code:
#pragma once

#include <functional>
#include <ostream>

namespace dxvk {

  /**
   * \brief Pointer for reference-counted objects
   *
   * This only requires the given type to implement \c incRef
   * and \c decRef methods that adjust the reference count.
   * \tparam T Object type
   */
  template<typename T>
  class Rc {
    template<typename Tx>
    friend class Rc;
  public:

    Rc() { }
    Rc(std::nullptr_t) { }

    Rc(T* object)
    : m_object(object) {
      this->incRef();
    }

    Rc(const Rc& other)
    : m_object(other.m_object) {
      this->incRef();
    }

    template<typename Tx>
    Rc(const Rc<Tx>& other)
    : m_object(other.m_object) {
      this->incRef();
    }

    Rc(Rc&& other)
    : m_object(other.m_object) {
      other.m_object = nullptr;
    }

    template<typename Tx>
    Rc(Rc<Tx>&& other)
    : m_object(other.m_object) {
      other.m_object = nullptr;
    }

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

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

    template<typename Tx>
    Rc& operator = (const Rc<Tx>& other) {
      other.incRef();
      this->decRef();
      m_object = other.m_object;
      return *this;
    }

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

    template<typename Tx>
    Rc& operator = (Rc<Tx>&& other) {
      this->decRef();
      this->m_object = other.m_object;
      other.m_object = nullptr;
      return *this;
    }

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

    T& operator *  () const { return *m_object; }
    T* operator -> () const { return  m_object; }
    T* ptr() const { return m_object; }

    bool operator == (const Rc& other) const { return m_object == other.m_object; }
    bool operator != (const Rc& other) const { return m_object != other.m_object; }

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

  private:

    T* m_object = nullptr;

    void incRef() const {
      if (m_object != nullptr)
        m_object->incRef();
    }

    void decRef() const {
      if (m_object != nullptr) {
        if (m_object->decRef() == 0)
          delete m_object;
      }
    }

  };

}

template<typename T>
std::ostream& operator << (std::ostream& os, const dxvk::Rc<T>& rc) {
  return os << rc.ptr();
}


code:
/*	$OpenBSD: sha1.c,v 1.26 2015/09/11 09:18:27 guenther Exp $	*/

/*
 * SHA-1 in C
 * By Steve Reid <steve@edmweb.com>
 * 100% Public Domain
 *
 * Test Vectors (from FIPS PUB 180-1)
 * "abc"
 *   A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
 * "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
 *   84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
 * A million repetitions of "a"
 *   34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
 */

#include <stdint.h>
#include <string.h>
#include "sha1.h"

#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))

/*
 * blk0() and blk() perform the initial expand.
 * I got the idea of expanding during the round function from SSLeay
 */
# define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \
    |(rol(block->l[i],8)&0x00FF00FF))

#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
    ^block->l[(i+2)&15]^block->l[i&15],1))

/*
 * (R0+R1), R2, R3, R4 are the different operations (rounds) used in SHA1
 */
#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);

typedef union {
	uint8_t c[64];
	uint32_t l[16];
} CHAR64LONG16;

/*
 * Hash a single 512-bit block. This is the core of the algorithm.
 */
void
SHA1Transform(uint32_t state[5], const uint8_t* buffer)
{
	uint32_t a, b, c, d, e;
	uint8_t workspace[SHA1_BLOCK_LENGTH];
	CHAR64LONG16 *block = (CHAR64LONG16 *)workspace;

	(void)memcpy(block, buffer, SHA1_BLOCK_LENGTH);

	/* Copy context->state[] to working vars */
	a = state[0];
	b = state[1];
	c = state[2];
	d = state[3];
	e = state[4];

	/* 4 rounds of 20 operations each. Loop unrolled. */
	R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
	R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
	R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
	R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
	R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
	R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
	R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
	R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
	R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
	R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
	R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
	R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
	R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
	R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
	R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
	R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
	R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
	R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
	R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
	R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);

	/* Add the working vars back into context.state[] */
	state[0] += a;
	state[1] += b;
	state[2] += c;
	state[3] += d;
	state[4] += e;

	/* Wipe variables */
	a = b = c = d = e = 0;
}

/*
 * SHA1Init - Initialize new context
 */
void
SHA1Init(SHA1_CTX *context)
{

	/* SHA1 initialization constants */
	context->count = 0;
	context->state[0] = 0x67452301;
	context->state[1] = 0xEFCDAB89;
	context->state[2] = 0x98BADCFE;
	context->state[3] = 0x10325476;
	context->state[4] = 0xC3D2E1F0;
}

/*
 * Run your data through this.
 */
void
SHA1Update(SHA1_CTX *context, const uint8_t *data, size_t len)
{
	size_t i, j;

	j = (size_t)((context->count >> 3) & 63);
	context->count += (len << 3);
	if ((j + len) > 63) {
		(void)memcpy(&context->buffer[j], data, (i = 64-j));
		SHA1Transform(context->state, context->buffer);
		for ( ; i + 63 < len; i += 64)
			SHA1Transform(context->state, (uint8_t *)&data[i]);
		j = 0;
	} else {
		i = 0;
	}
	(void)memcpy(&context->buffer[j], &data[i], len - i);
}

/*
 * Add padding and return the message digest.
 */
void
SHA1Pad(SHA1_CTX *context)
{
	uint8_t finalcount[8];
	uint32_t i;

	for (i = 0; i < 8; i++) {
		finalcount[i] = (uint8_t)((context->count >>
		    ((7 - (i & 7)) * 8)) & 255);	/* Endian independent */
	}
	SHA1Update(context, (uint8_t *)"\200", 1);
	while ((context->count & 504) != 448)
		SHA1Update(context, (uint8_t *)"\0", 1);
	SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */
}

void
SHA1Final(uint8_t digest[SHA1_DIGEST_LENGTH], SHA1_CTX *context)
{
	uint32_t i;

	SHA1Pad(context);
	for (i = 0; i < SHA1_DIGEST_LENGTH; i++) {
		digest[i] = (uint8_t)
		   ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
	}
	memset(context, 0, sizeof(*context));
}

repo_name: orochi/dxvk


code:
/*	$OpenBSD: sha1.h,v 1.24 2012/12/05 23:19:57 deraadt Exp $	*/

/*
 * SHA-1 in C
 * By Steve Reid <steve@edmweb.com>
 * 100% Public Domain
 */

#ifndef _SHA1_H
#define _SHA1_H

#include <stddef.h>
#include <stdint.h>

#define	SHA1_BLOCK_LENGTH		64
#define	SHA1_DIGEST_LENGTH		20
#define	SHA1_DIGEST_STRING_LENGTH	(SHA1_DIGEST_LENGTH * 2 + 1)

#ifdef __cplusplus
extern "C" {
#endif

typedef struct _SHA1_CTX {
    uint32_t state[5];
    uint64_t count;
    uint8_t buffer[SHA1_BLOCK_LENGTH];
} SHA1_CTX;

void SHA1Init(SHA1_CTX *);
void SHA1Pad(SHA1_CTX *);
void SHA1Transform(uint32_t [5], const uint8_t*);
void SHA1Update(SHA1_CTX *, const uint8_t *, size_t);
void SHA1Final(uint8_t [SHA1_DIGEST_LENGTH], SHA1_CTX *);

#define HTONDIGEST(x) do {                                              \
        x[0] = htonl(x[0]);                                             \
        x[1] = htonl(x[1]);                                             \
        x[2] = htonl(x[2]);                                             \
        x[3] = htonl(x[3]);                                             \
        x[4] = htonl(x[4]); } while (0)

#define NTOHDIGEST(x) do {                                              \
        x[0] = ntohl(x[0]);                                             \
        x[1] = ntohl(x[1]);                                             \
        x[2] = ntohl(x[2]);                                             \
        x[3] = ntohl(x[3]);                                             \
        x[4] = ntohl(x[4]); } while (0)

#ifdef __cplusplus
}
#endif

#endif /* _SHA1_H */


code:
#include "sha1.h"
#include "sha1_util.h"

namespace dxvk {

  std::string Sha1Hash::toString() const {
    static const char nibbles[]
      = { '0', '1', '2', '3', '4', '5', '6', '7',
          '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };

    std::string result;
    result.resize(2 * m_digest.size());

    for (uint32_t i = 0; i < m_digest.size(); i++) {
      result.at(2 * i + 0) = nibbles[(m_digest[i] >> 4) & 0xF];
      result.at(2 * i + 1) = nibbles[(m_digest[i] >> 0) & 0xF];
    }

    return result;
  }

  Sha1Hash Sha1Hash::compute(
    const void*     data,
          size_t    size) {
    Sha1Data chunk = { data, size };
    return compute(1, &chunk);
  }

  Sha1Hash Sha1Hash::compute(
          size_t    numChunks,
    const Sha1Data* chunks) {
    Sha1Digest digest;

    SHA1_CTX ctx;
    SHA1Init(&ctx);

    for (size_t i = 0; i < numChunks; i++) {
      auto ptr = reinterpret_cast<const uint8_t*>(chunks[i].data);
      SHA1Update(&ctx, ptr, chunks[i].size);
    }

    SHA1Final(digest.data(), &ctx);
    return Sha1Hash(digest);
  }

}


code:
#pragma once

#include <array>
#include <cstring>
#include <string>

namespace dxvk {

  using Sha1Digest = std::array<uint8_t, 20>;

  struct Sha1Data {
    const void* data;
    size_t      size;
  };

  class Sha1Hash {

  public:

    Sha1Hash() { }
    Sha1Hash(const Sha1Digest& digest)
    : m_digest(digest) { }

    std::string toString() const;

    uint32_t dword(uint32_t id) const {
      return uint32_t(m_digest[4 * id + 0]) <<  0
           | uint32_t(m_digest[4 * id + 1]) <<  8
           | uint32_t(m_digest[4 * id + 2]) << 16
           | uint32_t(m_digest[4 * id + 3]) << 24;
    }

    bool operator == (const Sha1Hash& other) const {
      return !std::memcmp(
        this->m_digest.data(),
        other.m_digest.data(),
        other.m_digest.size());
    }

    bool operator != (const Sha1Hash& other) const {
      return !this->operator == (other);
    }

    static Sha1Hash compute(
      const void*     data,
            size_t    size);

    static Sha1Hash compute(
            size_t    numChunks,
      const Sha1Data* chunks);

    template<typename T>
    static Sha1Hash compute(const T& data) {
      return compute(&data, sizeof(T));
    }

  private:

    Sha1Digest m_digest;

  };

}


code:
#pragma once

#include <atomic>

namespace dxvk::sync {

  /**
   * \brief Lock-free single-linked list
   */
  template<typename T>
  class List {

    struct Entry {
      Entry(T&& data_)
      : data(std::move(data_)), next(nullptr) { }
      Entry(const T& data_)
      : data(data_), next(nullptr) { }
      template<typename... Args>
      Entry(Args... args)
      : data(std::forward<Args>(args)...), next(nullptr) { }

      T      data;
      Entry* next;
    };

  public:

    class Iterator {

    public:

      using iterator_category = std::forward_iterator_tag;
      using difference_type   = std::ptrdiff_t;
      using value_type        = T;
      using pointer           = T*;
      using reference         = T&;

      Iterator()
      : m_entry(nullptr) { }

      Iterator(Entry* e)
      : m_entry(e) { }

      reference operator * () const {
        return m_entry->data;
      }

      pointer operator -> () const {
        return &m_entry->data;
      }

      Iterator& operator ++ () {
        m_entry = m_entry->next;
        return *this;
      }

      Iterator operator ++ (int) {
        Iterator tmp(m_entry);
        m_entry = m_entry->next;
        return tmp;
      }

      bool operator == (const Iterator& other) const { return m_entry == other.m_entry; }
      bool operator != (const Iterator& other) const { return m_entry != other.m_entry; }

    private:

      Entry* m_entry;

    };

    using iterator = Iterator;

    List()
    : m_head(nullptr) { }
    List(List&& other)
    : m_head(other.m_head.exchange(nullptr)) { }

    List& operator = (List&& other) {
      freeList(m_head.exchange(other.m_head.exchange(nullptr)));
      return *this;
    }

    ~List() {
      freeList(m_head.load());
    }

    auto begin() const { return Iterator(m_head); }
    auto end() const { return Iterator(nullptr); }

    Iterator insert(const T& data) {
      return insertEntry(new Entry(data));
    }

    Iterator insert(T&& data) {
      return insertEntry(new Entry(std::move(data)));
    }

    template<typename... Args>
    Iterator emplace(Args... args) {
      return insertEntry(new Entry(std::forward<Args>(args)...));
    }

  private:

    std::atomic<Entry*> m_head;

    Iterator insertEntry(Entry* e) {
      Entry* next = m_head.load(std::memory_order_acquire);

      do {
        e->next = next;
      } while (!m_head.compare_exchange_weak(next, e,
        std::memory_order_release,
        std::memory_order_acquire));

      return Iterator(e);
    }

    void freeList(Entry* e) {
      while (e) {
        Entry* next = e->next;;
        delete e;
        e = next;
      }
    }

  };

}


code:
#include "sync_recursive.h"
#include "sync_spinlock.h"

namespace dxvk::sync {

  void RecursiveSpinlock::lock() {
    spin(2000, [this] { return try_lock(); });
  }

  void RecursiveSpinlock::unlock() {
    if (likely(m_counter == 0))
      m_owner.store(0, std::memory_order_release);
    else
      m_counter -= 1;
  }

  bool RecursiveSpinlock::try_lock() {
    uint32_t threadId = dxvk::this_thread::get_id();
    uint32_t expected = 0;

    bool status = m_owner.compare_exchange_weak(
      expected, threadId, std::memory_order_acquire);

    if (status)
      return true;

    if (expected != threadId)
      return false;

    m_counter += 1;
    return true;
  }

}


code:
#pragma once

#include <atomic>

#include "../com/com_include.h"

namespace dxvk::sync {

  /**
   * \brief Recursive spinlock
   *
   * Implements a spinlock that can be acquired
   * by the same thread multiple times.
   */
  class RecursiveSpinlock {

  public:

    void lock();

    void unlock();

    bool try_lock();

  private:

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

  };

}


code:
#pragma once

#include <atomic>
#include <functional>
#include <list>

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

#include "../thread.h"

namespace dxvk::sync {

  /**
   * \brief Signal
   *
   * Interface for a CPU-side fence. Can be signaled
   * to a given value, and any thread waiting for a
   * lower value will be woken up.
   */
  class Signal : public RcObject {

  public:

    virtual ~Signal() { }

    /**
     * \brief Last signaled value
     * \returns Last signaled value
     */
    virtual uint64_t value() const = 0;

    /**
     * \brief Notifies signal
     *
     * Wakes up all threads currently waiting for
     * a value lower than \c value. Note that
     * \c value must monotonically increase.
     * \param [in] value Value to signal to
     */
    virtual void signal(uint64_t value) = 0;

    /**
     * \brief Waits for signal
     *
     * Blocks the calling thread until another
     * thread signals it with a value equal to
     * or greater than \c value.
     * \param [in] value The value to wait for
     */
    virtual void wait(uint64_t value) = 0;

  };

  /**
   * \brief Fence
   *
   * Simple CPU-side fence.
   */
  class Fence final : public Signal {

  public:

    Fence()
    : m_value(0ull) { }

    explicit Fence(uint64_t value)
    : m_value(value) { }

    uint64_t value() const {
      return m_value.load(std::memory_order_acquire);
    }

    void signal(uint64_t value) {
      std::unique_lock<dxvk::mutex> lock(m_mutex);
      m_value.store(value, std::memory_order_release);
      m_cond.notify_all();
    }

    void wait(uint64_t value) {
      std::unique_lock<dxvk::mutex> lock(m_mutex);
      m_cond.wait(lock, [this, value] {
        return value <= m_value.load(std::memory_order_acquire);
      });
    }

  private:

    std::atomic<uint64_t>    m_value;
    dxvk::mutex              m_mutex;
    dxvk::condition_variable m_cond;

  };

  /**
   * \brief Callback signal
   *
   * CPU-side fence with the ability to call a
   * function when signaled to a given value.
   */
  class CallbackFence final : public Signal {

  public:

    CallbackFence()
    : m_value(0ull) { }

    explicit CallbackFence(uint64_t value)
    : m_value(value) { }

    uint64_t value() const {
      return m_value.load(std::memory_order_acquire);
    }

    void signal(uint64_t value) {
      std::unique_lock<dxvk::mutex> lock(m_mutex);
      m_value.store(value, std::memory_order_release);
      m_cond.notify_all();

      for (auto i = m_callbacks.begin(); i != m_callbacks.end(); ) {
        if (value >= i->first) {
          i->second();
          i = m_callbacks.erase(i);
        } else {
          i++;
        }
      }
    }

    void wait(uint64_t value) {
      std::unique_lock<dxvk::mutex> lock(m_mutex);
      m_cond.wait(lock, [this, value] {
        return value <= m_value.load(std::memory_order_acquire);
      });
    }

    template<typename Fn>
    void setCallback(uint64_t value, Fn&& proc) {
      std::unique_lock<dxvk::mutex> lock(m_mutex);

      if (value > this->value())
        m_callbacks.emplace_back(std::piecewise_construct,
          std::make_tuple(value),
          std::make_tuple(proc));
      else
        proc();
    }

  private:

    std::atomic<uint64_t>    m_value;
    dxvk::mutex              m_mutex;
    dxvk::condition_variable m_cond;

    std::list<std::pair<uint64_t, std::function<void ()>>> m_callbacks;

  };

}


code:
#pragma once

#include <atomic>

#include "../thread.h"

#include "../util_bit.h"
#include "../util_likely.h"

namespace dxvk::sync {

  /**
   * \brief Generic spin function
   *
   * Blocks calling thread until a condition becomes
   * \c true, calling \c yield every few iterations.
   * \param [in] spinCount Number of probes between each yield
   * \param [in] fn Condition to test
   */
  template<typename Fn>
  void spin(uint32_t spinCount, const Fn& fn) {
    while (unlikely(!fn())) {
      for (uint32_t i = 1; i < spinCount; i++) {
        _mm_pause();
        if (fn())
          return;
      }

      dxvk::this_thread::yield();
    }
  }

  /**
   * \brief Spin lock
   *
   * A low-overhead spin lock which can be used to
   * protect data structures for a short duration
   * in case the structure is not likely contested.
   */
  class Spinlock {

  public:

    Spinlock() { }
    ~Spinlock() { }

    Spinlock             (const Spinlock&) = delete;
    Spinlock& operator = (const Spinlock&) = delete;

    void lock() {
      spin(200, [this] { return try_lock(); });
    }

    void unlock() {
      m_lock.store(0, std::memory_order_release);
    }

    bool try_lock() {
      return likely(!m_lock.load())
          && likely(!m_lock.exchange(1, std::memory_order_acquire));
    }

  private:

    std::atomic<uint32_t> m_lock = { 0 };

  };

}


code:
#pragma once

#include <atomic>

#include "../thread.h"

namespace dxvk::sync {

  /**
   * \brief Ticket spinlock
   *
   * A fair spinlock implementation that should
   * be preferred over \ref Spinlock when one of
   * the threads accessing the lock is likely to
   * starve another.
   */
  class TicketLock {

  public:

    void lock() {
      uint32_t ticket = m_counter.fetch_add(1);

      while (m_serving.load(std::memory_order_acquire) != ticket)
        continue;
    }

    void unlock() {
      uint32_t serveNext = m_serving.load() + 1;
      m_serving.store(serveNext, std::memory_order_release);
    }

  private:

    std::atomic<uint32_t> m_counter = { 0 };
    std::atomic<uint32_t> m_serving = { 0 };

  };

}


code:
#include "thread.h"
#include "util_likely.h"

#include <atomic>

#ifdef _WIN32

namespace dxvk::this_thread {

  bool isInModuleDetachment() {
    using PFN_RtlDllShutdownInProgress = BOOLEAN (WINAPI *)();

    static auto RtlDllShutdownInProgress = reinterpret_cast<PFN_RtlDllShutdownInProgress>(
      ::GetProcAddress(::GetModuleHandleW(L"ntdll.dll"), "RtlDllShutdownInProgress"));

    return RtlDllShutdownInProgress();
  }

}

#else

namespace dxvk::this_thread {

  static std::atomic<uint32_t> g_threadCtr = { 0u };
  static thread_local uint32_t g_threadId  = 0u;

  // This implementation returns thread ids unique to the current instance.
  // ie. if you use this across multiple .so's then you might get conflicting ids.
  //
  // This isn't an issue for us, as it is only used by the spinlock implementation,
  // but may be for you if you use this elsewhere.
  uint32_t get_id() {
    if (unlikely(!g_threadId))
      g_threadId = ++g_threadCtr;

    return g_threadId;
  }

}

#endif


code:
#pragma once

#include <chrono>
#include <condition_variable>
#include <functional>
#include <mutex>
#include <thread>

#include "util_error.h"

#include "./com/com_include.h"

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

namespace dxvk {

#ifdef _WIN32
  /**
   * \brief Thread priority
   */
  enum class ThreadPriority : int32_t {
    Lowest      = THREAD_PRIORITY_LOWEST,
    Low         = THREAD_PRIORITY_BELOW_NORMAL,
    Normal      = THREAD_PRIORITY_NORMAL,
    High        = THREAD_PRIORITY_ABOVE_NORMAL,
    Highest     = THREAD_PRIORITY_HIGHEST,
  };

  /**
   * \brief Thread helper class
   *
   * This is needed mostly  for winelib builds. Wine needs to setup each thread that
   * calls Windows APIs. It means that in winelib builds, we can't let standard C++
   * library create threads and need to use Wine for that instead. We use a thin wrapper
   * around Windows thread functions so that the rest of code just has to use
   * dxvk::thread class instead of std::thread.
   */
  class ThreadFn : public RcObject {
    using Proc = std::function<void()>;
  public:

    ThreadFn(Proc&& proc)
    : m_proc(std::move(proc)) {
      // Reference for the thread function
      this->incRef();

      m_handle = ::CreateThread(nullptr, 0x100000,
        ThreadFn::threadProc, this, STACK_SIZE_PARAM_IS_A_RESERVATION,
        nullptr);

      if (m_handle == nullptr)
        throw DxvkError("Failed to create thread");
    }

    ~ThreadFn() {
      if (this->joinable())
        std::terminate();
    }

    void detach() {
      ::CloseHandle(m_handle);
      m_handle = nullptr;
    }

    void join() {
      if(::WaitForSingleObjectEx(m_handle, INFINITE, FALSE) == WAIT_FAILED)
        throw DxvkError("Failed to join thread");
      this->detach();
    }

    bool joinable() const {
      return m_handle != nullptr;
    }

    void set_priority(ThreadPriority priority) {
      ::SetThreadPriority(m_handle, int32_t(priority));
    }

  private:

    Proc    m_proc;
    HANDLE  m_handle;

    static DWORD WINAPI threadProc(void *arg) {
      auto thread = reinterpret_cast<ThreadFn*>(arg);
      thread->m_proc();
      thread->decRef();
      return 0;
    }

  };

  /**
   * \brief RAII thread wrapper
   *
   * Wrapper for \c ThreadFn that can be used
   * as a drop-in replacement for \c std::thread.
   */
  class thread {

  public:

    thread() { }

    explicit thread(std::function<void()>&& func)
    : m_thread(new ThreadFn(std::move(func))) { }

    thread(thread&& other)
    : m_thread(std::move(other.m_thread)) { }

    thread& operator = (thread&& other) {
      m_thread = std::move(other.m_thread);
      return *this;
    }

    void detach() {
      m_thread->detach();
    }

    void join() {
      m_thread->join();
    }

    bool joinable() const {
      return m_thread != nullptr
          && m_thread->joinable();
    }

    void set_priority(ThreadPriority priority) {
      m_thread->set_priority(priority);
    }

    static uint32_t hardware_concurrency() {
      SYSTEM_INFO info = { };
      ::GetSystemInfo(&info);
      return info.dwNumberOfProcessors;
    }

  private:

    Rc<ThreadFn> m_thread;

  };

  namespace this_thread {
    inline void yield() {
      SwitchToThread();
    }

    inline uint32_t get_id() {
      return uint32_t(GetCurrentThreadId());
    }

    bool isInModuleDetachment();
  }

  /**
   * \brief SRW-based mutex implementation
   *
   * Drop-in replacement for \c std::mutex that uses Win32
   * SRW locks, which are implemented with \c futex in wine.
   */
  class mutex {

  public:

    using native_handle_type = PSRWLOCK;

    mutex() { }

    mutex(const mutex&) = delete;
    mutex& operator = (const mutex&) = delete;

    void lock() {
      AcquireSRWLockExclusive(&m_lock);
    }

    void unlock() {
      ReleaseSRWLockExclusive(&m_lock);
    }

    bool try_lock() {
      return TryAcquireSRWLockExclusive(&m_lock);
    }

    native_handle_type native_handle() {
      return &m_lock;
    }

  private:

    SRWLOCK m_lock = SRWLOCK_INIT;

  };

  /**
   * \brief Recursive mutex implementation
   *
   * Drop-in replacement for \c std::recursive_mutex that
   * uses Win32 critical sections.
   */
  class recursive_mutex {

  public:

    using native_handle_type = PCRITICAL_SECTION;

    recursive_mutex() {
      InitializeCriticalSection(&m_lock);
    }

    ~recursive_mutex() {
      DeleteCriticalSection(&m_lock);
    }

    recursive_mutex(const recursive_mutex&) = delete;
    recursive_mutex& operator = (const recursive_mutex&) = delete;

    void lock() {
      EnterCriticalSection(&m_lock);
    }

    void unlock() {
      LeaveCriticalSection(&m_lock);
    }

    bool try_lock() {
      return TryEnterCriticalSection(&m_lock);
    }

    native_handle_type native_handle() {
      return &m_lock;
    }

  private:

    CRITICAL_SECTION m_lock;

  };

  /**
   * \brief SRW-based condition variable implementation
   *
   * Drop-in replacement for \c std::condition_variable that
   * uses Win32 condition variables on SRW locks.
   */
  class condition_variable {

  public:

    using native_handle_type = PCONDITION_VARIABLE;

    condition_variable() {
      InitializeConditionVariable(&m_cond);
    }

    condition_variable(condition_variable&) = delete;

    condition_variable& operator = (condition_variable&) = delete;

    void notify_one() {
      WakeConditionVariable(&m_cond);
    }

    void notify_all() {
      WakeAllConditionVariable(&m_cond);
    }

    void wait(std::unique_lock<dxvk::mutex>& lock) {
      auto srw = lock.mutex()->native_handle();
      SleepConditionVariableSRW(&m_cond, srw, INFINITE, 0);
    }

    template<typename Predicate>
    void wait(std::unique_lock<dxvk::mutex>& lock, Predicate pred) {
      while (!pred())
        wait(lock);
    }

    template<typename Clock, typename Duration>
    std::cv_status wait_until(std::unique_lock<dxvk::mutex>& lock, const std::chrono::time_point<Clock, Duration>& time) {
      auto now = Clock::now();

      return (now < time)
        ? wait_for(lock, now - time)
        : std::cv_status::timeout;
    }

    template<typename Clock, typename Duration, typename Predicate>
    bool wait_until(std::unique_lock<dxvk::mutex>& lock, const std::chrono::time_point<Clock, Duration>& time, Predicate pred) {
      if (pred())
        return true;

      auto now = Clock::now();
      return now < time && wait_for(lock, now - time, pred);
    }

    template<typename Rep, typename Period>
    std::cv_status wait_for(std::unique_lock<dxvk::mutex>& lock, const std::chrono::duration<Rep, Period>& timeout) {
      auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(timeout);
      auto srw = lock.mutex()->native_handle();

      return SleepConditionVariableSRW(&m_cond, srw, ms.count(), 0)
        ? std::cv_status::no_timeout
        : std::cv_status::timeout;
    }

    template<typename Rep, typename Period, typename Predicate>
    bool wait_for(std::unique_lock<dxvk::mutex>& lock, const std::chrono::duration<Rep, Period>& timeout, Predicate pred) {
      bool result = pred();

      if (!result && wait_for(lock, timeout) == std::cv_status::no_timeout)
        result = pred();

      return result;
    }

    native_handle_type native_handle() {
      return &m_cond;
    }

  private:

    CONDITION_VARIABLE m_cond;

  };

#else
  using mutex              = std::mutex;
  using thread             = std::thread;
  using recursive_mutex    = std::recursive_mutex;
  using condition_variable = std::condition_variable;

  namespace this_thread {
    inline void yield() {
      std::this_thread::yield();
    }

    uint32_t get_id();

    inline bool isInModuleDetachment() {
      return false;
    }
  }
#endif

}


code:
#pragma once

#ifndef _MSC_VER
#if defined(__WINE__) && defined(__clang__)
#pragma push_macro("_WIN32")
#undef _WIN32
#endif
#include <x86intrin.h>
#if defined(__WINE__) && defined(__clang__)
#pragma pop_macro("_WIN32")
#endif
#else
#include <intrin.h>
#endif

#include "util_likely.h"
#include "util_math.h"

#include <cstring>
#include <iterator>
#include <type_traits>

namespace dxvk::bit {

  template<typename T, typename J>
  T cast(const J& src) {
    static_assert(sizeof(T) == sizeof(J));
    static_assert(std::is_trivially_copyable<J>::value && std::is_trivial<T>::value);

    T dst;
    std::memcpy(&dst, &src, sizeof(T));
    return dst;
  }

  template<typename T>
  T extract(T value, uint32_t fst, uint32_t lst) {
    return (value >> fst) & ~(~T(0) << (lst - fst + 1));
  }

  inline uint32_t popcntStep(uint32_t n, uint32_t mask, uint32_t shift) {
    return (n & mask) + ((n & ~mask) >> shift);
  }

  inline uint32_t popcnt(uint32_t n) {
    n = popcntStep(n, 0x55555555, 1);
    n = popcntStep(n, 0x33333333, 2);
    n = popcntStep(n, 0x0F0F0F0F, 4);
    n = popcntStep(n, 0x00FF00FF, 8);
    n = popcntStep(n, 0x0000FFFF, 16);
    return n;
  }

  inline uint32_t tzcnt(uint32_t n) {
    #if defined(_MSC_VER) && !defined(__clang__)
    return _tzcnt_u32(n);
    #elif defined(__BMI__)
    return __tzcnt_u32(n);
    #elif defined(__GNUC__) || defined(__clang__)
    uint32_t res;
    uint32_t tmp;
    asm (
      "mov  $32, %1;"
      "bsf   %2, %0;"
      "cmovz %1, %0;"
      : "=&r" (res), "=&r" (tmp)
      : "r" (n));
    return res;
    #else
    uint32_t r = 31;
    n &= -n;
    r -= (n & 0x0000FFFF) ? 16 : 0;
    r -= (n & 0x00FF00FF) ?  8 : 0;
    r -= (n & 0x0F0F0F0F) ?  4 : 0;
    r -= (n & 0x33333333) ?  2 : 0;
    r -= (n & 0x55555555) ?  1 : 0;
    return n != 0 ? r : 32;
    #endif
  }

  inline uint32_t bsf(uint32_t n) {
    #if defined(_MSC_VER) && !defined(__clang__)
    unsigned long index;
    _BitScanForward(&index, n);
    return uint32_t(index);
    #elif defined(__GNUC__) || defined(__clang__)
    return __builtin_ctz(n);
    #else
    uint32_t r = 31;
    n &= -n;
    r -= (n & 0x0000FFFF) ? 16 : 0;
    r -= (n & 0x00FF00FF) ?  8 : 0;
    r -= (n & 0x0F0F0F0F) ?  4 : 0;
    r -= (n & 0x33333333) ?  2 : 0;
    r -= (n & 0x55555555) ?  1 : 0;
    return r;
    #endif
  }

  inline uint32_t lzcnt(uint32_t n) {
    #if (defined(_MSC_VER) && !defined(__clang__)) || defined(__LZCNT__)
    return _lzcnt_u32(n);
    #elif defined(__GNUC__) || defined(__clang__)
    return n != 0 ? __builtin_clz(n) : 32;
    #else
    uint32_t r = 0;

    if (n == 0)	return 32;

    if (n <= 0x0000FFFF) { r += 16; n <<= 16; }
    if (n <= 0x00FFFFFF) { r += 8;  n <<= 8; }
    if (n <= 0x0FFFFFFF) { r += 4;  n <<= 4; }
    if (n <= 0x3FFFFFFF) { r += 2;  n <<= 2; }
    if (n <= 0x7FFFFFFF) { r += 1;  n <<= 1; }

    return r;
    #endif
  }

  template<typename T>
  uint32_t pack(T& dst, uint32_t& shift, T src, uint32_t count) {
    constexpr uint32_t Bits = 8 * sizeof(T);
    if (likely(shift < Bits))
      dst |= src << shift;
    shift += count;
    return shift > Bits ? shift - Bits : 0;
  }

  template<typename T>
  uint32_t unpack(T& dst, T src, uint32_t& shift, uint32_t count) {
    constexpr uint32_t Bits = 8 * sizeof(T);
    if (likely(shift < Bits))
      dst = (src >> shift) & ((T(1) << count) - 1);
    shift += count;
    return shift > Bits ? shift - Bits : 0;
  }

  /**
   * \brief Compares two aligned structs bit by bit
   *
   * \param [in] a First struct
   * \param [in] b Second struct
   * \returns \c true if the structs are equal
   */
  template<typename T>
  bool bcmpeq(const T* a, const T* b) {
    static_assert(alignof(T) >= 16);
    #if defined(__GNUC__) || defined(__clang__) || defined(_MSC_VER)
    auto ai = reinterpret_cast<const __m128i*>(a);
    auto bi = reinterpret_cast<const __m128i*>(b);

    size_t i = 0;

    #if defined(__clang__)
    #pragma nounroll
    #elif defined(__GNUC__)
    #pragma GCC unroll 0
    #endif

    for ( ; i < 2 * (sizeof(T) / 32); i += 2) {
      __m128i eq0 = _mm_cmpeq_epi8(
        _mm_load_si128(ai + i),
        _mm_load_si128(bi + i));
      __m128i eq1 = _mm_cmpeq_epi8(
        _mm_load_si128(ai + i + 1),
        _mm_load_si128(bi + i + 1));
      __m128i eq = _mm_and_si128(eq0, eq1);

      int mask = _mm_movemask_epi8(eq);
      if (mask != 0xFFFF)
        return false;
    }

    for ( ; i < sizeof(T) / 16; i++) {
      __m128i eq = _mm_cmpeq_epi8(
        _mm_load_si128(ai + i),
        _mm_load_si128(bi + i));

      int mask = _mm_movemask_epi8(eq);
      if (mask != 0xFFFF)
        return false;
    }

    return true;
    #else
    return !std::memcmp(a, b, sizeof(T));
    #endif
  }

  template <size_t Bits>
  class bitset {
    static constexpr size_t Dwords = align(Bits, 32) / 32;
  public:

    constexpr bitset()
      : m_dwords() {

    }

    constexpr bool get(uint32_t idx) const {
      uint32_t dword = 0;
      uint32_t bit   = idx;

      // Compiler doesn't remove this otherwise.
      if constexpr (Dwords > 1) {
        dword = idx / 32;
        bit   = idx % 32;
      }

      return m_dwords[dword] & (1u << bit);
    }

    constexpr void set(uint32_t idx, bool value) {
      uint32_t dword = 0;
      uint32_t bit   = idx;

      // Compiler doesn't remove this otherwise.
      if constexpr (Dwords > 1) {
        dword = idx / 32;
        bit   = idx % 32;
      }

      if (value)
        m_dwords[dword] |= 1u << bit;
      else
        m_dwords[dword] &= ~(1u << bit);
    }

    constexpr bool exchange(uint32_t idx, bool value) {
      bool oldValue = get(idx);
      set(idx, value);
      return oldValue;
    }

    constexpr void flip(uint32_t idx) {
      uint32_t dword = 0;
      uint32_t bit   = idx;

      // Compiler doesn't remove this otherwise.
      if constexpr (Dwords > 1) {
        dword = idx / 32;
        bit   = idx % 32;
      }

      m_dwords[dword] ^= 1u << bit;
    }

    constexpr void setAll() {
      if constexpr (Bits % 32 == 0) {
        for (size_t i = 0; i < Dwords; i++)
          m_dwords[i] = std::numeric_limits<uint32_t>::max();
      }
      else {
        for (size_t i = 0; i < Dwords - 1; i++)
          m_dwords[i] = std::numeric_limits<uint32_t>::max();

        m_dwords[Dwords - 1] = (1u << (Bits % 32)) - 1;
      }
    }

    constexpr void clearAll() {
      for (size_t i = 0; i < Dwords; i++)
        m_dwords[i] = 0;
    }

    constexpr bool any() const {
      for (size_t i = 0; i < Dwords; i++) {
        if (m_dwords[i] != 0)
          return true;
      }

      return false;
    }

    constexpr uint32_t& dword(uint32_t idx) {
      return m_dwords[idx];
    }

    constexpr size_t bitCount() {
      return Bits;
    }

    constexpr size_t dwordCount() {
      return Dwords;
    }

    constexpr bool operator [] (uint32_t idx) const {
      return get(idx);
    }

  private:

    uint32_t m_dwords[Dwords];

  };

  class BitMask {

  public:

    class iterator {
    public:
      using iterator_category = std::input_iterator_tag;
      using value_type = uint32_t;
      using difference_type = uint32_t;
      using pointer = const uint32_t*;
      using reference = uint32_t;

      explicit iterator(uint32_t flags)
        : m_mask(flags) { }

      iterator& operator ++ () {
        m_mask &= m_mask - 1;
        return *this;
      }

      iterator operator ++ (int) {
        iterator retval = *this;
        m_mask &= m_mask - 1;
        return retval;
      }

      uint32_t operator * () const {
        return bsf(m_mask);
      }

      bool operator == (iterator other) const { return m_mask == other.m_mask; }
      bool operator != (iterator other) const { return m_mask != other.m_mask; }

    private:

      uint32_t m_mask;

    };

    BitMask() { }

    BitMask(uint32_t n)
      : m_mask(n) { }

    iterator begin() {
      return iterator(m_mask);
    }

    iterator end() {
      return iterator(0);
    }

  private:

    uint32_t m_mask;

  };
}


code:
#pragma once

#define ENUM_NAME(name) \
  case name: return os << #name

#define ENUM_DEFAULT(name) \
  default: return os << static_cast<int32_t>(e)


code:
#include <array>
#include <cstdlib>
#include <filesystem>
#include <numeric>

#ifdef __linux__
#include <unistd.h>
#include <limits.h>
#endif

#include "util_env.h"

#include "./com/com_include.h"

namespace dxvk::env {

  std::string getEnvVar(const char* name) {
#ifdef _WIN32
    std::vector<WCHAR> result;
    result.resize(MAX_PATH + 1);

    DWORD len = ::GetEnvironmentVariableW(str::tows(name).c_str(), result.data(), MAX_PATH);
    result.resize(len);

    return str::fromws(result.data());
#else
    const char* result = std::getenv(name);
    return result ? result : "";
#endif
  }

  size_t matchFileExtension(const std::string& name, const char* ext) {
    auto pos = name.find_last_of('.');

    if (pos == std::string::npos)
      return pos;

    bool matches = std::accumulate(name.begin() + pos + 1, name.end(), true,
      [&ext] (bool current, char a) {
        if (a >= 'A' && a <= 'Z')
          a += 'a' - 'A';
        return current && *ext && a == *(ext++);
      });

    return matches ? pos : std::string::npos;
  }

  std::string getExeName() {
    std::string fullPath = getExePath();
    auto n = fullPath.find_last_of(env::PlatformDirSlash);

    return (n != std::string::npos)
      ? fullPath.substr(n + 1)
      : fullPath;
  }

  std::string getExeBaseName() {
    auto exeName = getExeName();
#ifdef _WIN32
    auto extp = matchFileExtension(exeName, "exe");

    if (extp != std::string::npos)
      exeName.erase(extp);
#endif

    return exeName;
  }

  std::string getExePath() {
#if defined(_WIN32)
    std::vector<WCHAR> exePath;
    exePath.resize(MAX_PATH + 1);

    DWORD len = ::GetModuleFileNameW(NULL, exePath.data(), MAX_PATH);
    exePath.resize(len);

    return str::fromws(exePath.data());
#elif defined(__linux__)
    std::array<char, PATH_MAX> exePath = {};

    size_t count = readlink("/proc/self/exe", exePath.data(), exePath.size());

    return std::string(exePath.begin(), exePath.begin() + count);
#endif
  }

  void setThreadName(const std::string& name) {
#ifdef _WIN32
    using SetThreadDescriptionProc = HRESULT (WINAPI *) (HANDLE, PCWSTR);

    static auto proc = reinterpret_cast<SetThreadDescriptionProc>(
      ::GetProcAddress(::GetModuleHandleW(L"kernel32.dll"), "SetThreadDescription"));

    if (proc != nullptr) {
      auto wideName = std::vector<WCHAR>(name.length() + 1);
      str::tows(name.c_str(), wideName.data(), wideName.size());
      (*proc)(::GetCurrentThread(), wideName.data());
    }
#else
    std::array<char, 16> posixName = {};
    dxvk::str::strlcpy(posixName.data(), name.c_str(), 16);
    ::pthread_setname_np(pthread_self(), posixName.data());
#endif
  }

  bool createDirectory(const std::string& path) {
#ifdef _WIN32
    WCHAR widePath[MAX_PATH];
    str::tows(path.c_str(), widePath);
    return !!CreateDirectoryW(widePath, nullptr);
#else
    return std::filesystem::create_directories(path);
#endif
  }

}


code:
#pragma once

#include "util_string.h"

namespace dxvk::env {

#ifdef _WIN32
  constexpr char PlatformDirSlash = '\\';
#else
  constexpr char PlatformDirSlash = '/';
#endif

  /**
   * \brief Checks whether the host platform is 32-bit
   */
  constexpr bool is32BitHostPlatform() {
    return sizeof(void*) == 4;
  }

  /**
   * \brief Gets environment variable
   *
   * If the variable is not defined, this will return
   * an empty string. Note that environment variables
   * may be defined with an empty value.
   * \param [in] name Name of the variable
   * \returns Value of the variable
   */
  std::string getEnvVar(const char* name);

  /**
   * \brief Checks whether a file name has a given extension
   *
   * \param [in] name File name
   * \param [in] ext Extension to match, in lowercase letters
   * \returns Position of the extension within the file name, or
   *    \c std::string::npos if the file has a different extension
   */
  size_t matchFileExtension(const std::string& name, const char* ext);

  /**
   * \brief Gets the executable name
   *
   * Returns the base name (not the full path) of the
   * program executable, including the file extension.
   * This function should be used to identify programs.
   * \returns Executable name
   */
  std::string getExeName();

  /**
   * \brief Gets the executable name without extension
   *
   * Same as \ref getExeName but without the file extension.
   * \returns Executable name
   */
  std::string getExeBaseName();

  /**
   * \brief Gets full path to executable
   * \returns Path to executable
   */
  std::string getExePath();

  /**
   * \brief Sets name of the calling thread
   * \param [in] name Thread name
   */
  void setThreadName(const std::string& name);

  /**
   * \brief Creates a directory
   *
   * \param [in] path Path to directory
   * \returns \c true on success
   */
  bool createDirectory(const std::string& path);

}


code:
#pragma once

#include <string>

namespace dxvk {

  /**
   * \brief DXVK error
   *
   * A generic exception class that stores a
   * message. Exceptions should be logged.
   */
  class DxvkError {

  public:

    DxvkError() { }
    DxvkError(std::string&& message)
    : m_message(std::move(message)) { }

    const std::string& message() const {
      return m_message;
    }

  private:

    std::string m_message;

  };

}


code:
#pragma once

#include <type_traits>

#include "util_bit.h"

namespace dxvk {

  template<typename T>
  class Flags {

  public:

    using IntType = std::underlying_type_t<T>;

    Flags() { }

    Flags(IntType t)
    : m_bits(t) { }

    template<typename... Tx>
    Flags(T f, Tx... fx) {
      this->set(f, fx...);
    }

    template<typename... Tx>
    void set(Tx... fx) {
      m_bits |= bits(fx...);
    }

    void set(Flags flags) {
      m_bits |= flags.m_bits;
    }

    template<typename... Tx>
    void clr(Tx... fx) {
      m_bits &= ~bits(fx...);
    }

    void clr(Flags flags) {
      m_bits &= ~flags.m_bits;
    }

    template<typename... Tx>
    bool any(Tx... fx) const {
      return (m_bits & bits(fx...)) != 0;
    }

    template<typename... Tx>
    bool all(Tx... fx) const {
      const IntType mask = bits(fx...);
      return (m_bits & mask) == mask;
    }

    bool test(T f) const {
      return this->any(f);
    }

    bool isClear() const {
      return m_bits == 0;
    }

    void clrAll() {
      m_bits = 0;
    }

    IntType raw() const {
      return m_bits;
    }

    Flags operator & (const Flags& other) const {
      return Flags(m_bits & other.m_bits);
    }

    Flags operator | (const Flags& other) const {
      return Flags(m_bits | other.m_bits);
    }

    Flags operator ^ (const Flags& other) const {
      return Flags(m_bits ^ other.m_bits);
    }

    bool operator == (const Flags& other) const {
      return m_bits == other.m_bits;
    }

    bool operator != (const Flags& other) const {
      return m_bits != other.m_bits;
    }

  private:

    IntType m_bits = 0;

    static IntType bit(T f) {
      return IntType(1) << static_cast<IntType>(f);
    }

    template<typename... Tx>
    static IntType bits(T f, Tx... fx) {
      return bit(f) | bits(fx...);
    }

    static IntType bits() {
      return 0;
    }

  };

}


code:
#include <thread>

#include "thread.h"
#include "util_env.h"
#include "util_fps_limiter.h"
#include "util_string.h"

#include "./log/log.h"

namespace dxvk {

  FpsLimiter::FpsLimiter() {
    std::string env = env::getEnvVar("DXVK_FRAME_RATE");

    if (!env.empty()) {
      try {
        setTargetFrameRate(std::stod(env));
        m_envOverride = true;
      } catch (const std::invalid_argument&) {
        // no-op
      }
    }
  }

  FpsLimiter::~FpsLimiter() {

  }

  void FpsLimiter::setTargetFrameRate(double frameRate) {
    std::lock_guard<dxvk::mutex> lock(m_mutex);

    if (!m_envOverride) {
      m_targetInterval = frameRate > 0.0
        ? NtTimerDuration(int64_t(double(NtTimerDuration::period::den) / frameRate))
        : NtTimerDuration::zero();

      if (isEnabled() && !m_initialized)
        initialize();
    }
  }

  void FpsLimiter::delay(bool vsyncEnabled) {
    std::lock_guard<dxvk::mutex> lock(m_mutex);

    if (!isEnabled())
      return;

    auto t0 = m_lastFrame;
    auto t1 = dxvk::high_resolution_clock::now();

    auto frameTime = std::chrono::duration_cast<NtTimerDuration>(t1 - t0);

    if (frameTime * 100 > m_targetInterval * 103 - m_deviation * 100) {
      // If we have a slow frame, reset the deviation since we
      // do not want to compensate for low performance later on
      m_deviation = NtTimerDuration::zero();
    } else {
      // Don't call sleep if the amount of time to sleep is shorter
      // than the time the function calls are likely going to take
      NtTimerDuration sleepDuration = m_targetInterval - m_deviation - frameTime;
      t1 = sleep(t1, sleepDuration);

      // Compensate for any sleep inaccuracies in the next frame, and
      // limit cumulative deviation in order to avoid stutter in case we
      // have a number of slow frames immediately followed by a fast one.
      frameTime = std::chrono::duration_cast<NtTimerDuration>(t1 - t0);
      m_deviation += frameTime - m_targetInterval;
      m_deviation = std::min(m_deviation, m_targetInterval / 16);
    }

    m_lastFrame = t1;
  }

  FpsLimiter::TimePoint FpsLimiter::sleep(TimePoint t0, NtTimerDuration duration) {
    if (duration <= NtTimerDuration::zero())
      return t0;

    // On wine, we can rely on NtDelayExecution waiting for more or
    // less exactly the desired amount of time, and we want to avoid
    // spamming QueryPerformanceCounter for performance reasons.
    // On Windows, we busy-wait for the last couple of milliseconds
    // since sleeping is highly inaccurate and inconsistent.
    NtTimerDuration sleepThreshold = m_sleepThreshold;

    if (m_sleepGranularity != NtTimerDuration::zero())
      sleepThreshold += duration / 6;

    NtTimerDuration remaining = duration;
    TimePoint t1 = t0;

    while (remaining > sleepThreshold) {
      NtTimerDuration sleepDuration = remaining - sleepThreshold;

      if (NtDelayExecution) {
        LARGE_INTEGER ticks;
        ticks.QuadPart = -sleepDuration.count();

        NtDelayExecution(FALSE, &ticks);
      } else {
        std::this_thread::sleep_for(sleepDuration);
      }

      t1 = dxvk::high_resolution_clock::now();
      remaining -= std::chrono::duration_cast<NtTimerDuration>(t1 - t0);
      t0 = t1;
    }

    // Busy-wait until we have slept long enough
    while (remaining > NtTimerDuration::zero()) {
      t1 = dxvk::high_resolution_clock::now();
      remaining -= std::chrono::duration_cast<NtTimerDuration>(t1 - t0);
      t0 = t1;
    }

    return t1;
  }

  void FpsLimiter::initialize() {
    HMODULE ntdll = ::GetModuleHandleW(L"ntdll.dll");

    if (ntdll) {
      NtDelayExecution = reinterpret_cast<NtDelayExecutionProc>(
        ::GetProcAddress(ntdll, "NtDelayExecution"));
      auto NtQueryTimerResolution = reinterpret_cast<NtQueryTimerResolutionProc>(
        ::GetProcAddress(ntdll, "NtQueryTimerResolution"));
      auto NtSetTimerResolution = reinterpret_cast<NtSetTimerResolutionProc>(
        ::GetProcAddress(ntdll, "NtSetTimerResolution"));

      ULONG min, max, cur;

      // Wine's implementation of these functions is a stub as of 6.10, which is fine
      // since it uses select() in NtDelayExecution. This is only relevant for Windows.
      if (NtQueryTimerResolution && !NtQueryTimerResolution(&min, &max, &cur)) {
        m_sleepGranularity = NtTimerDuration(cur);

        if (NtSetTimerResolution && !NtSetTimerResolution(max, TRUE, &cur)) {
          Logger::info(str::format("Setting timer interval to ", (double(max) / 10.0), " us"));
          m_sleepGranularity = NtTimerDuration(max);
        }
      }
    } else {
      // Assume 1ms sleep granularity by default
      m_sleepGranularity = NtTimerDuration(10000);
    }

    m_sleepThreshold = 4 * m_sleepGranularity;
    m_lastFrame = dxvk::high_resolution_clock::now();
    m_initialized = true;
  }

}


code:
#pragma once

#include "thread.h"
#include "util_time.h"

namespace dxvk {

  /**
   * \brief Frame rate limiter
   *
   * Provides functionality to stall an application
   * thread in order to maintain a given frame rate.
   */
  class FpsLimiter {

  public:

    /**
     * \brief Creates frame rate limiter
     */
    FpsLimiter();

    ~FpsLimiter();

    /**
     * \brief Sets target frame rate
     * \param [in] frameRate Target frame rate
     */
    void setTargetFrameRate(double frameRate);

    /**
     * \brief Stalls calling thread as necessary
     *
     * Blocks the calling thread if the limiter is enabled
     * and the time since the last call to \ref delay is
     * shorter than the target interval.
     * \param [in] vsyncEnabled \c true if vsync is enabled
     */
    void delay(bool vsyncEnabled);

    /**
     * \brief Checks whether the frame rate limiter is enabled
     * \returns \c true if the target frame rate is non-zero.
     */
    bool isEnabled() const {
      return m_targetInterval != NtTimerDuration::zero();
    }

  private:

    using TimePoint = dxvk::high_resolution_clock::time_point;

    using NtTimerDuration = std::chrono::duration<int64_t, std::ratio<1, 10000000>>;
    using NtQueryTimerResolutionProc = UINT (WINAPI *) (ULONG*, ULONG*, ULONG*);
    using NtSetTimerResolutionProc = UINT (WINAPI *) (ULONG, BOOL, ULONG*);
    using NtDelayExecutionProc = UINT (WINAPI *) (BOOL, LARGE_INTEGER*);

    dxvk::mutex     m_mutex;

    NtTimerDuration m_targetInterval  = NtTimerDuration::zero();
    NtTimerDuration m_deviation       = NtTimerDuration::zero();
    TimePoint       m_lastFrame;

    bool            m_initialized     = false;
    bool            m_envOverride     = false;

    NtTimerDuration m_sleepGranularity = NtTimerDuration::zero();
    NtTimerDuration m_sleepThreshold   = NtTimerDuration::zero();

    NtDelayExecutionProc NtDelayExecution = nullptr;

    TimePoint sleep(TimePoint t0, NtTimerDuration duration);

    void initialize();

  };

}


code:
#include "util_gdi.h"
#include "log/log.h"

namespace dxvk {

  HMODULE GetGDIModule() {
    static HMODULE module = LoadLibraryA("gdi32.dll");
    return module;
  }

  NTSTATUS D3DKMTCreateDCFromMemory(D3DKMT_CREATEDCFROMMEMORY* Arg1) {
    static auto func = (D3DKMTCreateDCFromMemoryType)
      GetProcAddress(GetGDIModule(), "D3DKMTCreateDCFromMemory");

    if (func != nullptr)
      return func(Arg1);

    Logger::warn("D3DKMTCreateDCFromMemory: Unable to query proc address.");
    return -1;
  }

  NTSTATUS D3DKMTDestroyDCFromMemory(D3DKMT_DESTROYDCFROMMEMORY* Arg1) {
    static auto func = (D3DKMTDestroyDCFromMemoryType)
      GetProcAddress(GetGDIModule(), "D3DKMTDestroyDCFromMemory");

    if (func != nullptr)
      return func(Arg1);

    Logger::warn("D3DKMTDestroyDCFromMemory: Unable to query proc address.");
    return -1;
  }

}


code:
#pragma once

#include <d3d9.h>

namespace dxvk {
  using NTSTATUS = LONG;

  // Slightly modified definitions...
  struct D3DKMT_CREATEDCFROMMEMORY {
    void*         pMemory;
    D3DFORMAT     Format;
    UINT          Width;
    UINT          Height;
    UINT          Pitch;
    HDC           hDeviceDc;
    PALETTEENTRY* pColorTable;
    HDC           hDc;
    HANDLE        hBitmap;
  };

  struct D3DKMT_DESTROYDCFROMMEMORY {
    HDC    hDC     = nullptr;
    HANDLE hBitmap = nullptr;
  };

  using D3DKMTCreateDCFromMemoryType  = NTSTATUS(STDMETHODCALLTYPE*) (D3DKMT_CREATEDCFROMMEMORY*);
  NTSTATUS D3DKMTCreateDCFromMemory (D3DKMT_CREATEDCFROMMEMORY*  Arg1);

  using D3DKMTDestroyDCFromMemoryType = NTSTATUS(STDMETHODCALLTYPE*) (D3DKMT_DESTROYDCFROMMEMORY*);
  NTSTATUS D3DKMTDestroyDCFromMemory(D3DKMT_DESTROYDCFROMMEMORY* Arg1);

}


code:
#pragma once

#include <mutex>

namespace dxvk {

  /**
   * \brief Lazy-initialized object
   *
   * Creates an object on demand with
   * the given constructor arguments.
   */
  template<typename T>
  class Lazy {

  public:

    template<typename... Args>
    T& get(Args... args) {
      if (m_object)
        return *m_object;

      std::lock_guard lock(m_mutex);

      if (!m_object) {
        m_object = std::make_unique<T>(
          std::forward<Args>(args)...);
      }

      return *m_object;
    }

  private:

    dxvk::mutex        m_mutex;
    std::unique_ptr<T> m_object;

  };

}


code:
#pragma once

#ifdef __GNUC__
#define likely(x)   __builtin_expect((x),1)
#define unlikely(x) __builtin_expect((x),0)
#else
#define likely(x)   (x)
#define unlikely(x) (x)
#endif


code:
#include "util_luid.h"
#include "util_string.h"

#include "./log/log.h"

#include <mutex>
#include <vector>

namespace dxvk {

  LUID GetAdapterLUID(UINT Adapter) {
    static dxvk::mutex       s_mutex;
    static std::vector<LUID> s_luids;

    std::lock_guard<dxvk::mutex> lock(s_mutex);
    uint32_t newLuidCount = Adapter + 1;

    while (s_luids.size() < newLuidCount) {
      LUID luid = { 0, 0 };

      if (!::AllocateLocallyUniqueId(&luid))
        Logger::err("Failed to allocate LUID");

      Logger::info(str::format("Adapter LUID ", s_luids.size(), ": ",
        std::hex, luid.HighPart, ":", luid.LowPart, std::dec));

      s_luids.push_back(luid);
    }

    return s_luids[Adapter];
  }

}


code:
#include "./com/com_include.h"

namespace dxvk {

  /**
   * \brief Retrieves an adapter LUID
   *
   * Note that this only works reliably within the
   * module that this function was compiled into.
   * \param [in] Adapter The adapter index
   * \returns LUID An LUID for that adapter
   */
  LUID GetAdapterLUID(UINT Adapter);

}


code:
#pragma once

#include <cmath>

namespace dxvk {

  constexpr size_t CACHE_LINE_SIZE = 64;

  template<typename T>
  constexpr T clamp(T n, T lo, T hi) {
    if (n < lo) return lo;
    if (n > hi) return hi;
    return n;
  }

  template<typename T, typename U = T>
  constexpr T align(T what, U to) {
    return (what + to - 1) & ~(to - 1);
  }

  template<typename T, typename U = T>
  constexpr T alignDown(T what, U to) {
    return (what / to) * to;
  }

  // Equivalent of std::clamp for use with floating point numbers
  // Handles (-){INFINITY,NAN} cases.
  // Will return min in cases of NAN, etc.
  inline float fclamp(float value, float min, float max) {
    return std::fmin(
      std::fmax(value, min), max);
  }

  template<typename T>
  inline T divCeil(T dividend, T divisor) {
    return (dividend + divisor - 1) / divisor;
  }

}


code:
#include "util_matrix.h"

namespace dxvk {

        Vector4& Matrix4::operator[](size_t index)       { return data[index]; }
  const Vector4& Matrix4::operator[](size_t index) const { return data[index]; }

  bool Matrix4::operator==(const Matrix4& m2) const {
    const Matrix4& m1 = *this;
    for (uint32_t i = 0; i < 4; i++) {
      if (m1[i] != m2[i])
        return false;
    }
    return true;
  }

  bool Matrix4::operator!=(const Matrix4& m2) const { return !operator==(m2); }

  Matrix4 Matrix4::operator+(const Matrix4& other) const {
    Matrix4 mat;
    for (uint32_t i = 0; i < 4; i++)
      mat[i] = data[i] + other.data[i];
    return mat;
  }

  Matrix4 Matrix4::operator-(const Matrix4& other) const {
    Matrix4 mat;
    for (uint32_t i = 0; i < 4; i++)
      mat[i] = data[i] - other.data[i];
    return mat;
  }

  Matrix4 Matrix4::operator*(const Matrix4& m2) const {
    const Matrix4& m1 = *this;

    const Vector4 srcA0 = { m1[0] };
    const Vector4 srcA1 = { m1[1] };
    const Vector4 srcA2 = { m1[2] };
    const Vector4 srcA3 = { m1[3] };

    const Vector4 srcB0 = { m2[0] };
    const Vector4 srcB1 = { m2[1] };
    const Vector4 srcB2 = { m2[2] };
    const Vector4 srcB3 = { m2[3] };

    Matrix4 result;
    result[0] = srcA0 * srcB0[0] + srcA1 * srcB0[1] + srcA2 * srcB0[2] + srcA3 * srcB0[3];
    result[1] = srcA0 * srcB1[0] + srcA1 * srcB1[1] + srcA2 * srcB1[2] + srcA3 * srcB1[3];
    result[2] = srcA0 * srcB2[0] + srcA1 * srcB2[1] + srcA2 * srcB2[2] + srcA3 * srcB2[3];
    result[3] = srcA0 * srcB3[0] + srcA1 * srcB3[1] + srcA2 * srcB3[2] + srcA3 * srcB3[3];
    return result;
  }

  Vector4 Matrix4::operator*(const Vector4& v) const {
    const Matrix4& m = *this;

    const Vector4 mul0 = { m[0] * v[0] };
    const Vector4 mul1 = { m[1] * v[1] };
    const Vector4 mul2 = { m[2] * v[2] };
    const Vector4 mul3 = { m[3] * v[3] };

    const Vector4 add0 = { mul0 + mul1 };
    const Vector4 add1 = { mul2 + mul3 };

    return add0 + add1;
  }

  Matrix4 Matrix4::operator*(float scalar) const {
    Matrix4 mat;
    for (uint32_t i = 0; i < 4; i++)
      mat[i] = data[i] * scalar;
    return mat;
  }

  Matrix4 Matrix4::operator/(float scalar) const {
    Matrix4 mat;
    for (uint32_t i = 0; i < 4; i++)
      mat[i] = data[i] / scalar;
    return mat;
  }

  Matrix4& Matrix4::operator+=(const Matrix4& other) {
    for (uint32_t i = 0; i < 4; i++)
      data[i] += other.data[i];
    return *this;
  }

  Matrix4& Matrix4::operator-=(const Matrix4& other) {
    for (uint32_t i = 0; i < 4; i++)
      data[i] -= other.data[i];
    return *this;
  }

  Matrix4& Matrix4::operator*=(const Matrix4& other) {
    return (*this = (*this) * other);
  }

  Matrix4 transpose(const Matrix4& m) {
    Matrix4 result;

    for (uint32_t i = 0; i < 4; i++) {
      for (uint32_t j = 0; j < 4; j++)
        result[i][j] = m.data[j][i];
    }
    return result;
  }

  float determinant(const Matrix4& m) {
    float coef00    =  m[2][2] * m[3][3] - m[3][2] * m[2][3];
    float coef02    =  m[1][2] * m[3][3] - m[3][2] * m[1][3];
    float coef03    =  m[1][2] * m[2][3] - m[2][2] * m[1][3];

    float coef04    =  m[2][1] * m[3][3] - m[3][1] * m[2][3];
    float coef06    =  m[1][1] * m[3][3] - m[3][1] * m[1][3];
    float coef07    =  m[1][1] * m[2][3] - m[2][1] * m[1][3];

    float coef08    =  m[2][1] * m[3][2] - m[3][1] * m[2][2];
    float coef10    =  m[1][1] * m[3][2] - m[3][1] * m[1][2];
    float coef11    =  m[1][1] * m[2][2] - m[2][1] * m[1][2];

    float coef12    =  m[2][0] * m[3][3] - m[3][0] * m[2][3];
    float coef14    =  m[1][0] * m[3][3] - m[3][0] * m[1][3];
    float coef15    =  m[1][0] * m[2][3] - m[2][0] * m[1][3];

    float coef16    =  m[2][0] * m[3][2] - m[3][0] * m[2][2];
    float coef18    =  m[1][0] * m[3][2] - m[3][0] * m[1][2];
    float coef19    =  m[1][0] * m[2][2] - m[2][0] * m[1][2];

    float coef20    =  m[2][0] * m[3][1] - m[3][0] * m[2][1];
    float coef22    =  m[1][0] * m[3][1] - m[3][0] * m[1][1];
    float coef23    =  m[1][0] * m[2][1] - m[2][0] * m[1][1];

    Vector4 fac0    = { coef00, coef00, coef02, coef03 };
    Vector4 fac1    = { coef04, coef04, coef06, coef07 };
    Vector4 fac2    = { coef08, coef08, coef10, coef11 };
    Vector4 fac3    = { coef12, coef12, coef14, coef15 };
    Vector4 fac4    = { coef16, coef16, coef18, coef19 };
    Vector4 fac5    = { coef20, coef20, coef22, coef23 };

    Vector4 vec0    = { m[1][0], m[0][0], m[0][0], m[0][0] };
    Vector4 vec1    = { m[1][1], m[0][1], m[0][1], m[0][1] };
    Vector4 vec2    = { m[1][2], m[0][2], m[0][2], m[0][2] };
    Vector4 vec3    = { m[1][3], m[0][3], m[0][3], m[0][3] };

    Vector4 inv0    = { vec1 * fac0 - vec2 * fac1 + vec3 * fac2 };
    Vector4 inv1    = { vec0 * fac0 - vec2 * fac3 + vec3 * fac4 };
    Vector4 inv2    = { vec0 * fac1 - vec1 * fac3 + vec3 * fac5 };
    Vector4 inv3    = { vec0 * fac2 - vec1 * fac4 + vec2 * fac5 };

    Vector4 signA   = { +1, -1, +1, -1 };
    Vector4 signB   = { -1, +1, -1, +1 };
    Matrix4 inverse = { inv0 * signA, inv1 * signB, inv2 * signA, inv3 * signB };

    Vector4 row0    = { inverse[0][0], inverse[1][0], inverse[2][0], inverse[3][0] };

    Vector4 dot0    = { m[0] * row0 };

    return (dot0.x + dot0.y) + (dot0.z + dot0.w);
  }

  Matrix4 inverse(const Matrix4& m)
  {
    float coef00    = m[2][2] * m[3][3] - m[3][2] * m[2][3];
    float coef02    = m[1][2] * m[3][3] - m[3][2] * m[1][3];
    float coef03    = m[1][2] * m[2][3] - m[2][2] * m[1][3];
    float coef04    = m[2][1] * m[3][3] - m[3][1] * m[2][3];
    float coef06    = m[1][1] * m[3][3] - m[3][1] * m[1][3];
    float coef07    = m[1][1] * m[2][3] - m[2][1] * m[1][3];
    float coef08    = m[2][1] * m[3][2] - m[3][1] * m[2][2];
    float coef10    = m[1][1] * m[3][2] - m[3][1] * m[1][2];
    float coef11    = m[1][1] * m[2][2] - m[2][1] * m[1][2];
    float coef12    = m[2][0] * m[3][3] - m[3][0] * m[2][3];
    float coef14    = m[1][0] * m[3][3] - m[3][0] * m[1][3];
    float coef15    = m[1][0] * m[2][3] - m[2][0] * m[1][3];
    float coef16    = m[2][0] * m[3][2] - m[3][0] * m[2][2];
    float coef18    = m[1][0] * m[3][2] - m[3][0] * m[1][2];
    float coef19    = m[1][0] * m[2][2] - m[2][0] * m[1][2];
    float coef20    = m[2][0] * m[3][1] - m[3][0] * m[2][1];
    float coef22    = m[1][0] * m[3][1] - m[3][0] * m[1][1];
    float coef23    = m[1][0] * m[2][1] - m[2][0] * m[1][1];

    Vector4 fac0    = { coef00, coef00, coef02, coef03 };
    Vector4 fac1    = { coef04, coef04, coef06, coef07 };
    Vector4 fac2    = { coef08, coef08, coef10, coef11 };
    Vector4 fac3    = { coef12, coef12, coef14, coef15 };
    Vector4 fac4    = { coef16, coef16, coef18, coef19 };
    Vector4 fac5    = { coef20, coef20, coef22, coef23 };

    Vector4 vec0    = { m[1][0], m[0][0], m[0][0], m[0][0] };
    Vector4 vec1    = { m[1][1], m[0][1], m[0][1], m[0][1] };
    Vector4 vec2    = { m[1][2], m[0][2], m[0][2], m[0][2] };
    Vector4 vec3    = { m[1][3], m[0][3], m[0][3], m[0][3] };

    Vector4 inv0    = { vec1 * fac0 - vec2 * fac1 + vec3 * fac2 };
    Vector4 inv1    = { vec0 * fac0 - vec2 * fac3 + vec3 * fac4 };
    Vector4 inv2    = { vec0 * fac1 - vec1 * fac3 + vec3 * fac5 };
    Vector4 inv3    = { vec0 * fac2 - vec1 * fac4 + vec2 * fac5 };

    Vector4 signA   = { +1, -1, +1, -1 };
    Vector4 signB   = { -1, +1, -1, +1 };
    Matrix4 inverse = { inv0 * signA, inv1 * signB, inv2 * signA, inv3 * signB };

    Vector4 row0    = { inverse[0][0], inverse[1][0], inverse[2][0], inverse[3][0] };

    Vector4 dot0    = { m[0] * row0 };
    float dot1      = (dot0.x + dot0.y) + (dot0.z + dot0.w);

    return inverse * (1.0f / dot1);
  }

  Matrix4 hadamardProduct(const Matrix4& a, const Matrix4& b) {
    Matrix4 result;

    for (uint32_t i = 0; i < 4; i++)
      result[i] = a[i] * b[i];

    return result;
  }

  std::ostream& operator<<(std::ostream& os, const Matrix4& m) {
    os << "Matrix4(";
    for (uint32_t i = 0; i < 4; i++) {
      os << "\n\t" << m[i];
      if (i < 3)
        os << ", ";
    }
    os << "\n)";

    return os;
  }

}


code:
#pragma once

#include "util_vector.h"

namespace dxvk {

  class Matrix4 {

    public:

    // Identity
    inline Matrix4() {
      data[0] = { 1, 0, 0, 0 };
      data[1] = { 0, 1, 0, 0 };
      data[2] = { 0, 0, 1, 0 };
      data[3] = { 0, 0, 0, 1 };
    }

    // Produces a scalar matrix, x * Identity
    inline explicit Matrix4(float x) {
      data[0] = { x, 0, 0, 0 };
      data[1] = { 0, x, 0, 0 };
      data[2] = { 0, 0, x, 0 };
      data[3] = { 0, 0, 0, x };
    }

    inline Matrix4(
      const Vector4& v0,
      const Vector4& v1,
      const Vector4& v2,
      const Vector4& v3) {
      data[0] = v0;
      data[1] = v1;
      data[2] = v2;
      data[3] = v3;
    }

    inline Matrix4(const float matrix[4][4]) {
      data[0] = Vector4(matrix[0]);
      data[1] = Vector4(matrix[1]);
      data[2] = Vector4(matrix[2]);
      data[3] = Vector4(matrix[3]);
    }

    Matrix4(const Matrix4& other) = default;

    Vector4& operator[](size_t index);
    const Vector4& operator[](size_t index) const;

    bool operator==(const Matrix4& m2) const;
    bool operator!=(const Matrix4& m2) const;

    Matrix4 operator+(const Matrix4& other) const;
    Matrix4 operator-(const Matrix4& other) const;

    Matrix4 operator*(const Matrix4& m2) const;
    Vector4 operator*(const Vector4& v) const;
    Matrix4 operator*(float scalar) const;

    Matrix4 operator/(float scalar) const;

    Matrix4& operator+=(const Matrix4& other);
    Matrix4& operator-=(const Matrix4& other);

    Matrix4& operator*=(const Matrix4& other);

    Vector4 data[4];

  };

  static_assert(sizeof(Matrix4) == sizeof(Vector4) * 4);

  inline Matrix4 operator*(float scalar, const Matrix4& m) { return m * scalar; }

  Matrix4 transpose(const Matrix4& m);

  float determinant(const Matrix4& m);

  Matrix4 inverse(const Matrix4& m);

  Matrix4 hadamardProduct(const Matrix4& a, const Matrix4& b);

  std::ostream& operator<<(std::ostream& os, const Matrix4& m);

}


code:
#pragma once

#include <d3d9types.h>

namespace dxvk {

  inline void DecodeD3DCOLOR(D3DCOLOR color, float* rgba) {
    // Encoded in D3DCOLOR as argb
    rgba[3] = (float)((color & 0xff000000) >> 24) / 255.0f;
    rgba[0] = (float)((color & 0x00ff0000) >> 16) / 255.0f;
    rgba[1] = (float)((color & 0x0000ff00) >> 8)  / 255.0f;
    rgba[2] = (float)((color & 0x000000ff))       / 255.0f;
  }

}


code:
#include "util_monitor.h"
#include "util_string.h"

#include "./log/log.h"

namespace dxvk {

  HMONITOR GetDefaultMonitor() {
    return ::MonitorFromPoint({ 0, 0 }, MONITOR_DEFAULTTOPRIMARY);
  }

  BOOL SetMonitorDisplayMode(
          HMONITOR                hMonitor,
          DEVMODEW*               pMode) {
    ::MONITORINFOEXW monInfo;
    monInfo.cbSize = sizeof(monInfo);

    if (!::GetMonitorInfoW(hMonitor, reinterpret_cast<MONITORINFO*>(&monInfo))) {
      Logger::err("Failed to query monitor info");
      return E_FAIL;
    }

    Logger::info(str::format("Setting display mode: ",
      pMode->dmPelsWidth, "x", pMode->dmPelsHeight, "@",
      pMode->dmDisplayFrequency));

    DEVMODEW curMode = { };
    curMode.dmSize = sizeof(curMode);

    if (GetMonitorDisplayMode(hMonitor, ENUM_CURRENT_SETTINGS, &curMode)) {
      bool eq = curMode.dmPelsWidth  == pMode->dmPelsWidth
             && curMode.dmPelsHeight == pMode->dmPelsHeight
             && curMode.dmBitsPerPel == pMode->dmBitsPerPel;

      if (pMode->dmFields & DM_DISPLAYFREQUENCY)
        eq &= curMode.dmDisplayFrequency == pMode->dmDisplayFrequency;

      if (eq)
        return true;
    }

    LONG status = ::ChangeDisplaySettingsExW(monInfo.szDevice,
      pMode, nullptr, CDS_FULLSCREEN, nullptr);

    if (status != DISP_CHANGE_SUCCESSFUL) {
      pMode->dmFields &= ~DM_DISPLAYFREQUENCY;

      status = ::ChangeDisplaySettingsExW(monInfo.szDevice,
        pMode, nullptr, CDS_FULLSCREEN, nullptr);
    }

    return status == DISP_CHANGE_SUCCESSFUL;
  }

  BOOL GetMonitorDisplayMode(
          HMONITOR                hMonitor,
          DWORD                   modeNum,
          DEVMODEW*               pMode) {
    ::MONITORINFOEXW monInfo;
    monInfo.cbSize = sizeof(monInfo);

    if (!::GetMonitorInfoW(hMonitor, reinterpret_cast<MONITORINFO*>(&monInfo))) {
      Logger::err("Failed to query monitor info");
      return false;
    }

    return ::EnumDisplaySettingsW(monInfo.szDevice, modeNum, pMode);
  }

  BOOL CALLBACK RestoreMonitorDisplayModeCallback(
          HMONITOR                hMonitor,
          HDC                     hDC,
          LPRECT                  pRect,
          LPARAM                  pUserdata) {
    auto success = reinterpret_cast<bool*>(pUserdata);

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

    if (!GetMonitorDisplayMode(hMonitor, ENUM_REGISTRY_SETTINGS, &devMode)) {
      *success = false;
      return false;
    }

    Logger::info(str::format("Restoring display mode: ",
      devMode.dmPelsWidth, "x", devMode.dmPelsHeight, "@",
      devMode.dmDisplayFrequency));

    if (!SetMonitorDisplayMode(hMonitor, &devMode)) {
      *success = false;
      return false;
    }

    return true;
  }

  BOOL RestoreMonitorDisplayMode() {
    bool success = true;
    bool result = ::EnumDisplayMonitors(nullptr, nullptr,
      &RestoreMonitorDisplayModeCallback,
      reinterpret_cast<LPARAM>(&success));

    return result && success;
  }

  void GetWindowClientSize(
          HWND                    hWnd,
          UINT*                   pWidth,
          UINT*                   pHeight) {
    RECT rect = { };
    ::GetClientRect(hWnd, &rect);

    if (pWidth)
      *pWidth = rect.right - rect.left;

    if (pHeight)
      *pHeight = rect.bottom - rect.top;
  }

  void GetMonitorClientSize(
          HMONITOR                hMonitor,
          UINT*                   pWidth,
          UINT*                   pHeight) {
    ::MONITORINFOEXW monInfo;
    monInfo.cbSize = sizeof(monInfo);

    if (!::GetMonitorInfoW(hMonitor, reinterpret_cast<MONITORINFO*>(&monInfo))) {
      Logger::err("Failed to query monitor info");
      return;
    }

    auto rect = monInfo.rcMonitor;

    if (pWidth)
      *pWidth = rect.right - rect.left;

    if (pHeight)
      *pHeight = rect.bottom - rect.top;
  }

  void GetMonitorRect(
          HMONITOR                hMonitor,
          RECT*                   pRect) {
    ::MONITORINFOEXW monInfo;
    monInfo.cbSize = sizeof(monInfo);

    if (!::GetMonitorInfoW(hMonitor, reinterpret_cast<MONITORINFO*>(&monInfo))) {
      Logger::err("Failed to query monitor info");
      return;
    }

    *pRect = monInfo.rcMonitor;
  }

}


code:
#pragma once

#include "./com/com_include.h"

namespace dxvk {

  /**
   * \brief Retrieves primary monitor
   * \returns The primary monitor
   */
  HMONITOR GetDefaultMonitor();

  /**
   * \brief Sets monitor display mode
   *
   * Note that \c pMode may be altered by this function.
   * \param [in] hMonitor The monitor to change
   * \param [in] pMode The desired display mode
   * \returns \c true on success
   */
  BOOL SetMonitorDisplayMode(
          HMONITOR                hMonitor,
          DEVMODEW*               pMode);

  /**
   * \brief Enumerates monitor display modes
   *
   * \param [in] hMonitor The monitor to query
   * \param [in] modeNum Mode number or enum
   * \param [in] pMode The display mode
   * \returns \c true on success
   */
  BOOL GetMonitorDisplayMode(
          HMONITOR                hMonitor,
          DWORD                   modeNum,
          DEVMODEW*               pMode);

  /**
   * \brief Change display modes to registry settings
   * \returns \c true on success
   */
  BOOL RestoreMonitorDisplayMode();

  /**
   * \brief Queries window client size
   *
   * \param [in] hWnd Window to query
   * \param [out] pWidth Client width
   * \param [out] pHeight Client height
   */
  void GetWindowClientSize(
          HWND                    hWnd,
          UINT*                   pWidth,
          UINT*                   pHeight);

  /**
   * \brief Queries monitor size
   *
   * \param [in] hMonitor Monitor to query
   * \param [out] pWidth Client width
   * \param [out] pHeight Client height
   */
  void GetMonitorClientSize(
          HMONITOR                hMonitor,
          UINT*                   pWidth,
          UINT*                   pHeight);

  /**
   * \brief Queries monitor rect
   *
   * \param [in] hMonitor Monitor to query
   * \param [out] pRect The rect to return
   */
  void GetMonitorRect(
          HMONITOR                hMonitor,
          RECT*                   pRect);

}


code:
#include <numeric>
#include <algorithm>
#include <cstdint>
#include <string>
#include <charconv>

namespace dxvk {

  /**
   * \brief Simplest ratio helper
   */
  template <typename T>
  class Ratio {

  public:

    Ratio(T num, T denom) {
      set(num, denom);
    }

    Ratio(std::string_view view) {
      set(0, 0);

      size_t colon = view.find(":");

      if (colon == std::string_view::npos)
        return;

      std::string_view numStr   = view.substr(0, colon);
      std::string_view denomStr = view.substr(colon + 1);

      T num = 0, denom = 0;
      std::from_chars(numStr.data(),   numStr.data()   + numStr.size(),   num);
      std::from_chars(denomStr.data(), denomStr.data() + denomStr.size(), denom);

      set(num, denom);
    }

    inline T num()    const { return m_num; }
    inline T denom() const { return m_denom; }

    inline bool undefined() const { return m_denom == 0; }

    inline void set(T num, T denom) {
      const T gcd = std::gcd(num, denom);

      if (gcd == 0) {
        m_num   = 0;
        m_denom = 0;

        return;
      }

      m_num = num / gcd;
      m_denom = denom / gcd;
    }

    inline bool operator == (const Ratio& other) const {
      return num() == other.num() && denom() == other.denom();
    }

    inline bool operator != (const Ratio& other) const {
      return !(*this == other);
    }

    inline bool operator >= (const Ratio& other) const {
      return num() * other.denom() >= other.num() * denom();
    }

    inline bool operator > (const Ratio& other) const {
      return num() * other.denom() > other.num() * denom();
    }

    inline bool operator < (const Ratio& other) const {
      return  !(*this >= other);
    }

    inline bool operator <= (const Ratio& other) const {
      return  !(*this > other);
    }

  private:

    T m_num, m_denom;

  };

}


code:
#include "util_shared_res.h"

#include "winioctl.h"

namespace dxvk {

  #define IOCTL_SHARED_GPU_RESOURCE_OPEN             CTL_CODE(FILE_DEVICE_VIDEO, 1, METHOD_BUFFERED, FILE_WRITE_ACCESS)

  HANDLE openKmtHandle(HANDLE kmt_handle) {
    HANDLE handle = ::CreateFileA("\\\\.\\SharedGpuResource", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    if (handle == INVALID_HANDLE_VALUE)
      return handle;

    struct
    {
        unsigned int kmt_handle;
        WCHAR name[1];
    } shared_resource_open = {0};
    shared_resource_open.kmt_handle = reinterpret_cast<uintptr_t>(kmt_handle);

    bool succeed = ::DeviceIoControl(handle, IOCTL_SHARED_GPU_RESOURCE_OPEN, &shared_resource_open, sizeof(shared_resource_open), NULL, 0, NULL, NULL);
    if (!succeed) {
      ::CloseHandle(handle);
      return INVALID_HANDLE_VALUE;
    }
    return handle;
  }

  #define IOCTL_SHARED_GPU_RESOURCE_SET_METADATA           CTL_CODE(FILE_DEVICE_VIDEO, 4, METHOD_BUFFERED, FILE_WRITE_ACCESS)

  bool setSharedMetadata(HANDLE handle, void *buf, uint32_t bufSize) {
    DWORD retSize;
    return ::DeviceIoControl(handle, IOCTL_SHARED_GPU_RESOURCE_SET_METADATA, buf, bufSize, NULL, 0, &retSize, NULL);
  }

  #define IOCTL_SHARED_GPU_RESOURCE_GET_METADATA           CTL_CODE(FILE_DEVICE_VIDEO, 5, METHOD_BUFFERED, FILE_READ_ACCESS)

  bool getSharedMetadata(HANDLE handle, void *buf, uint32_t bufSize, uint32_t *metadataSize) {
    DWORD retSize;
    bool ret = ::DeviceIoControl(handle, IOCTL_SHARED_GPU_RESOURCE_GET_METADATA, NULL, 0, buf, bufSize, &retSize, NULL);
    if (metadataSize)
      *metadataSize = retSize;
    return ret;
  }

}


code:
#pragma once

#include <cstdint>

#include "./com/com_include.h"

#include <d3d11_4.h>

namespace dxvk {

    HANDLE openKmtHandle(HANDLE kmt_handle);

    bool setSharedMetadata(HANDLE handle, void *buf, uint32_t bufSize);
    bool getSharedMetadata(HANDLE handle, void *buf, uint32_t bufSize, uint32_t *metadataSize);

    struct DxvkSharedTextureMetadata {
      UINT             Width;
      UINT             Height;
      UINT             MipLevels;
      UINT             ArraySize;
      DXGI_FORMAT      Format;
      DXGI_SAMPLE_DESC SampleDesc;
      D3D11_USAGE      Usage;
      UINT             BindFlags;
      UINT             CPUAccessFlags;
      UINT             MiscFlags;
      D3D11_TEXTURE_LAYOUT TextureLayout;
    };

}


code:
#pragma once

#include <type_traits>

namespace dxvk {

  template<typename T, size_t N>
  class small_vector {
    using storage = std::aligned_storage_t<sizeof(T), alignof(T)>;
  public:

    small_vector() { }

    small_vector             (const small_vector&) = delete;
    small_vector& operator = (const small_vector&) = delete;

    ~small_vector() {
      for (size_t i = 0; i < m_size; i++)
        ptr(i)->~T();

      if (m_capacity > N)
        delete[] u.m_ptr;
    }

    size_t size() const {
      return m_size;
    }

    void reserve(size_t n) {
      n = pick_capacity(n);

      if (n <= m_capacity)
        return;

      storage* data = new storage[n];

      for (size_t i = 0; i < m_size; i++) {
        new (&data[i]) T(std::move(*ptr(i)));
        ptr(i)->~T();
      }

      if (m_capacity > N)
        delete[] u.m_ptr;

      m_capacity = n;
      u.m_ptr = data;
    }

    const T* data() const { return ptr(0); }
          T* data()       { return ptr(0); }

    void resize(size_t n) {
      reserve(n);

      for (size_t i = n; i < m_size; i++)
        ptr(i)->~T();

      for (size_t i = m_size; i < n; i++)
        new (ptr(i)) T();
    }

    void push_back(const T& object) {
      reserve(m_size + 1);
      new (ptr(m_size++)) T(object);
    }

    void push_back(T&& object) {
      reserve(m_size + 1);
      new (ptr(m_size++)) T(std::move(object));
    }

    template<typename... Args>
    void emplace_back(Args... args) {
      reserve(m_size + 1);
      new (ptr(m_size++)) T(std::forward<Args>(args)...);
    }

    void erase(size_t idx) {
      ptr(idx)->~T();

      for (size_t i = idx; i < m_size - 1; i++) {
        new (ptr(i)) T(std::move(*ptr(i + 1)));
        ptr(i + 1)->~T();
      }
    }

    void pop_back() {
      ptr(--m_size)->~T();
    }

          T& operator [] (size_t idx)       { return *ptr(idx); }
    const T& operator [] (size_t idx) const { return *ptr(idx); }

          T& front()       { return *ptr(0); }
    const T& front() const { return *ptr(0); }

          T& back()       { return *ptr(m_size - 1); }
    const T& back() const { return *ptr(m_size - 1); }

  private:

    size_t m_capacity = N;
    size_t m_size     = 0;

    union {
      storage* m_ptr;
      storage  m_data[sizeof(T) * N];
    } u;

    size_t pick_capacity(size_t n) {
      size_t capacity = m_capacity;

      while (capacity < n)
        capacity *= 2;

      return capacity;
    }

    T* ptr(size_t idx) {
      return m_capacity == N
        ? reinterpret_cast<T*>(&u.m_data[idx])
        : reinterpret_cast<T*>(&u.m_ptr[idx]);
    }

    const T* ptr(size_t idx) const {
      return m_capacity == N
        ? reinterpret_cast<const T*>(&u.m_data[idx])
        : reinterpret_cast<const T*>(&u.m_ptr[idx]);
    }

  };

}


code:
#include "util_string.h"

namespace dxvk::str {
  std::string fromws(const WCHAR *ws) {
    size_t len = ::WideCharToMultiByte(CP_UTF8,
      0, ws, -1, nullptr, 0, nullptr, nullptr);

    if (len <= 1)
      return "";

    len -= 1;

    std::string result;
    result.resize(len);
    ::WideCharToMultiByte(CP_UTF8, 0, ws, -1,
      &result.at(0), len, nullptr, nullptr);
    return result;
  }

  void tows(const char* mbs, WCHAR* wcs, size_t wcsLen) {
    ::MultiByteToWideChar(
      CP_UTF8, 0, mbs, -1,
      wcs, wcsLen);
  }

  std::wstring tows(const char* mbs) {
    size_t len = ::MultiByteToWideChar(CP_UTF8,
      0, mbs, -1, nullptr, 0);

    if (len <= 1)
      return L"";

    len -= 1;

    std::wstring result;
    result.resize(len);
    ::MultiByteToWideChar(CP_UTF8, 0, mbs, -1,
      &result.at(0), len);
    return result;
  }

}


code:
#pragma once

#include <cstring>
#include <string>
#include <sstream>
#include <vector>

#include "./com/com_include.h"

namespace dxvk::str {

  std::string fromws(const WCHAR *ws);

  void tows(const char* mbs, WCHAR* wcs, size_t wcsLen);

  template <size_t N>
  void tows(const char* mbs, WCHAR (&wcs)[N]) {
    return tows(mbs, wcs, N);
  }

  std::wstring tows(const char* mbs);

  inline void format1(std::stringstream&) { }

  template<typename... Tx>
  void format1(std::stringstream& str, const WCHAR *arg, const Tx&... args) {
    str << fromws(arg);
    format1(str, args...);
  }

  template<typename T, typename... Tx>
  void format1(std::stringstream& str, const T& arg, const Tx&... args) {
    str << arg;
    format1(str, args...);
  }

  template<typename... Args>
  std::string format(const Args&... args) {
    std::stringstream stream;
    format1(stream, args...);
    return stream.str();
  }

  inline void strlcpy(char* dst, const char* src, size_t count) {
    std::strncpy(dst, src, count);
    if (count > 0)
      dst[count - 1] = '\0';
  }

}


code:
#pragma once

#include <chrono>
#include <cstdint>

#if defined(_WIN32) && !defined(__WINE__)
#include <windows.h>
#endif

namespace dxvk {

#if defined(_WIN32) && !defined(__WINE__)
  struct high_resolution_clock {
    static constexpr bool is_steady = true;

    using rep        = int64_t;
    using period     = std::nano;
    using duration   = std::chrono::nanoseconds;
    using time_point = std::chrono::time_point<high_resolution_clock>;

    static inline time_point now() noexcept {
      // Keep the frequency static, this doesn't change at all.
      static const int64_t freq = getFrequency();
      const int64_t counter     = getCounter();

      const int64_t whole = (counter / freq) * period::den;
      const int64_t part  = (counter % freq) * period::den / freq;

      return time_point(duration(whole + part));
    }

    static inline int64_t getFrequency() {
      LARGE_INTEGER freq;
      QueryPerformanceFrequency(&freq);

      return freq.QuadPart;
    }

    static inline int64_t getCounter() {
      LARGE_INTEGER count;
      QueryPerformanceCounter(&count);

      return count.QuadPart;
    }
  };
#else
  using high_resolution_clock = std::chrono::high_resolution_clock;
#endif

}


code:
#pragma once

#include <iostream>

#include "util_bit.h"
#include "util_math.h"

namespace dxvk {

  template <typename T>
  struct Vector4Base {
    Vector4Base()
      : x{ }, y{ }, z{ }, w{ } { }

    Vector4Base(T splat)
      : x(splat), y(splat), z(splat), w(splat) { }

    Vector4Base(T x, T y, T z, T w)
      : x(x), y(y), z(z), w(w) { }

    Vector4Base(const T xyzw[4])
      : x(xyzw[0]), y(xyzw[1]), z(xyzw[2]), w(xyzw[3]) { }

    Vector4Base(const Vector4Base<T>& other) = default;

    inline       T& operator[](size_t index)       { return data[index]; }
    inline const T& operator[](size_t index) const { return data[index]; }

    bool operator==(const Vector4Base<T>& other) const {
      for (uint32_t i = 0; i < 4; i++) {
        if (data[i] != other.data[i])
        return false;
      }

      return true;
    }

    bool operator!=(const Vector4Base<T>& other) const {
      return !operator==(other);
    }

    Vector4Base operator-() const { return {-x, -y, -z, -w}; }

    Vector4Base operator+(const Vector4Base<T>& other) const {
      return {x + other.x, y + other.y, z + other.z, w + other.w};
    }

    Vector4Base operator-(const Vector4Base<T>& other) const {
      return {x - other.x, y - other.y, z - other.z, w - other.w};
    }

    Vector4Base operator*(T scalar) const {
      return {scalar * x, scalar * y, scalar * z, scalar * w};
    }

    Vector4Base operator*(const Vector4Base<T>& other) const {
      Vector4Base result;
      for (uint32_t i = 0; i < 4; i++)
        result[i] = data[i] * other.data[i];
      return result;
    }

    Vector4Base operator/(const Vector4Base<T>& other) const {
      Vector4Base result;
      for (uint32_t i = 0; i < 4; i++)
        result[i] = data[i] / other.data[i];
      return result;
    }

    Vector4Base operator/(T scalar) const {
      return {x / scalar, y / scalar, z / scalar, w / scalar};
    }

    Vector4Base& operator+=(const Vector4Base<T>& other) {
      x += other.x;
      y += other.y;
      z += other.z;
      w += other.w;

      return *this;
    }

    Vector4Base& operator-=(const Vector4Base<T>& other) {
      x -= other.x;
      y -= other.y;
      z -= other.z;
      w -= other.w;

      return *this;
    }

    Vector4Base& operator*=(T scalar) {
      x *= scalar;
      y *= scalar;
      z *= scalar;
      w *= scalar;

      return *this;
    }

    Vector4Base& operator/=(T scalar) {
      x /= scalar;
      y /= scalar;
      z /= scalar;
      w /= scalar;

      return *this;
    }

    union {
      T data[4];
      struct {
        T x, y, z, w;
      };
      struct {
        T r, g, b, a;
      };
    };

  };

  template <typename T>
  inline Vector4Base<T> operator*(T scalar, const Vector4Base<T>& vector) {
    return vector * scalar;
  }

  template <typename T>
  float dot(const Vector4Base<T>& a, const Vector4Base<T>& b) {
    return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w;
  }

  template <typename T>
  T lengthSqr(const Vector4Base<T>& a) { return dot(a, a); }

  template <typename T>
  float length(const Vector4Base<T>& a) { return std::sqrt(float(lengthSqr(a))); }

  template <typename T>
  Vector4Base<T> normalize(const Vector4Base<T>& a) { return a * T(1.0f / length(a)); }

  template <typename T>
  std::ostream& operator<<(std::ostream& os, const Vector4Base<T>& v) {
    return os << "Vector4(" << v[0] << ", " << v[1] << ", " << v[2] << ", " << v[3] << ")";
  }

  using Vector4  = Vector4Base<float>;
  using Vector4i = Vector4Base<int>;

  static_assert(sizeof(Vector4)  == sizeof(float) * 4);
  static_assert(sizeof(Vector4i) == sizeof(int)   * 4);

  inline Vector4 replaceNaN(Vector4 a) {
    Vector4 result;
    __m128 value = _mm_load_ps(a.data);
    __m128 mask  = _mm_cmpeq_ps(value, value);
           value = _mm_and_ps(value, mask);
    _mm_store_ps(result.data, value);
    return result;
  }

}


code:
vkcommon_src = files([
  'vulkan_loader.cpp',
  'vulkan_names.cpp',
  'vulkan_presenter.cpp',
])

thread_dep = dependency('threads')

vkcommon_lib = static_library('vkcommon', vkcommon_src,
  dependencies        : [ thread_dep, lib_vulkan ],
  include_directories : [ dxvk_include_path ],
)

vkcommon_dep = declare_dependency(
  link_with           : [ vkcommon_lib ],
  include_directories : [ dxvk_include_path ],
)


code:
#include "vulkan_loader.h"

namespace dxvk::vk {

  static const PFN_vkGetInstanceProcAddr GetInstanceProcAddr = vkGetInstanceProcAddr;

  PFN_vkVoidFunction LibraryLoader::sym(const char* name) const {
    return dxvk::vk::GetInstanceProcAddr(nullptr, name);
  }

  InstanceLoader::InstanceLoader(bool owned, VkInstance instance)
  : m_instance(instance), m_owned(owned) { }

  PFN_vkVoidFunction InstanceLoader::sym(const char* name) const {
    return dxvk::vk::GetInstanceProcAddr(m_instance, name);
  }

  DeviceLoader::DeviceLoader(bool owned, VkInstance instance, VkDevice device)
  : m_getDeviceProcAddr(reinterpret_cast<PFN_vkGetDeviceProcAddr>(
      dxvk::vk::GetInstanceProcAddr(instance, "vkGetDeviceProcAddr"))),
    m_device(device), m_owned(owned) { }

  PFN_vkVoidFunction DeviceLoader::sym(const char* name) const {
    return m_getDeviceProcAddr(m_device, name);
  }

  LibraryFn::LibraryFn() { }
  LibraryFn::~LibraryFn() { }

  InstanceFn::InstanceFn(bool owned, VkInstance instance)
  : InstanceLoader(owned, instance) { }
  InstanceFn::~InstanceFn() {
    if (m_owned)
      this->vkDestroyInstance(m_instance, nullptr);
  }

  DeviceFn::DeviceFn(bool owned, VkInstance instance, VkDevice device)
  : DeviceLoader(owned, instance, device) { }
  DeviceFn::~DeviceFn() {
    if (m_owned)
      this->vkDestroyDevice(m_device, nullptr);
  }

}