mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-06-06 22:53:35 +00:00
Format: src/{common, utils, wire}
This commit is contained in:
parent
a351ce9618
commit
9d01c6c26d
@ -16,7 +16,11 @@
|
|||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
void HandleAssertionFailure(const char* file, const char* function, int line, const char* condition) {
|
void HandleAssertionFailure(const char* file,
|
||||||
std::cerr << "Assertion failure at " << file << ":" << line << " (" << function << "): " << condition << std::endl;
|
const char* function,
|
||||||
|
int line,
|
||||||
|
const char* condition) {
|
||||||
|
std::cerr << "Assertion failure at " << file << ":" << line << " (" << function
|
||||||
|
<< "): " << condition << std::endl;
|
||||||
NXT_BREAKPOINT();
|
NXT_BREAKPOINT();
|
||||||
}
|
}
|
||||||
|
@ -17,63 +17,64 @@
|
|||||||
|
|
||||||
#include "common/Compiler.h"
|
#include "common/Compiler.h"
|
||||||
|
|
||||||
void HandleAssertionFailure(const char* file, const char* function, int line, const char* condition);
|
// NXT asserts to be used instead of the regular C stdlib assert function (if you don't use assert
|
||||||
|
// yet, you should start now!). In debug ASSERT(condition) will trigger an error, otherwise in
|
||||||
|
// release it does nothing at runtime.
|
||||||
|
//
|
||||||
|
// In case of name clashes (with for example a testing library), you can define the
|
||||||
|
// NXT_SKIP_ASSERT_SHORTHANDS to only define the NXT_ prefixed macros.
|
||||||
|
//
|
||||||
|
// These asserts feature:
|
||||||
|
// - Logging of the error with file, line and function information.
|
||||||
|
// - Breaking in the debugger when an assert is triggered and a debugger is attached.
|
||||||
|
// - Use the assert information to help the compiler optimizer in release builds.
|
||||||
|
|
||||||
/*
|
// MSVC triggers a warning in /W4 for do {} while(0). SDL worked around this by using (0,0) and
|
||||||
* NXT asserts to be used instead of the regular C stdlib assert function (if you don't
|
// points out that it looks like an owl face.
|
||||||
* use assert yet, you should start now!). In debug ASSERT(condition) will trigger an error,
|
|
||||||
* otherwise in release it does nothing at runtime.
|
|
||||||
*
|
|
||||||
* In case of name clashes (with for example a testing library), you can define the
|
|
||||||
* NXT_SKIP_ASSERT_SHORTHANDS to only define the NXT_ prefixed macros.
|
|
||||||
*
|
|
||||||
* These asserts feature:
|
|
||||||
* - Logging of the error with file, line and function information.
|
|
||||||
* - Breaking in the debugger when an assert is triggered and a debugger is attached.
|
|
||||||
* - Use the assert information to help the compiler optimizer in release builds.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// MSVC triggers a warning in /W4 for do {} while(0). SDL worked around this by using
|
|
||||||
// // (0,0) and points out that it looks like an owl face.
|
|
||||||
#if defined(NXT_COMPILER_MSVC)
|
#if defined(NXT_COMPILER_MSVC)
|
||||||
#define NXT_ASSERT_LOOP_CONDITION (0,0)
|
# define NXT_ASSERT_LOOP_CONDITION (0, 0)
|
||||||
#else
|
#else
|
||||||
#define NXT_ASSERT_LOOP_CONDITION (0)
|
# define NXT_ASSERT_LOOP_CONDITION (0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// NXT_ASSERT_CALLSITE_HELPER generates the actual assert code. In Debug it does what you would
|
// NXT_ASSERT_CALLSITE_HELPER generates the actual assert code. In Debug it does what you would
|
||||||
// expect of an assert and in release it tries to give hints to make the compiler generate better code.
|
// expect of an assert and in release it tries to give hints to make the compiler generate better
|
||||||
|
// code.
|
||||||
#if defined(NXT_ENABLE_ASSERTS)
|
#if defined(NXT_ENABLE_ASSERTS)
|
||||||
#define NXT_ASSERT_CALLSITE_HELPER(file, func, line, condition) \
|
# define NXT_ASSERT_CALLSITE_HELPER(file, func, line, condition) \
|
||||||
do { \
|
do { \
|
||||||
if (!(condition)) { \
|
if (!(condition)) { \
|
||||||
HandleAssertionFailure(file, func, line, #condition); \
|
HandleAssertionFailure(file, func, line, #condition); \
|
||||||
} \
|
} \
|
||||||
} while(NXT_ASSERT_LOOP_CONDITION)
|
} while (NXT_ASSERT_LOOP_CONDITION)
|
||||||
#else
|
#else
|
||||||
#if defined(NXT_COMPILER_MSVC)
|
# if defined(NXT_COMPILER_MSVC)
|
||||||
#define NXT_ASSERT_CALLSITE_HELPER(file, func, line, condition) \
|
# define NXT_ASSERT_CALLSITE_HELPER(file, func, line, condition) __assume(condition)
|
||||||
__assume(condition)
|
# elif defined(NXT_COMPILER_CLANG) && defined(__builtin_assume)
|
||||||
#elif defined(NXT_COMPILER_CLANG) && defined(__builtin_assume)
|
# define NXT_ASSERT_CALLSITE_HELPER(file, func, line, condition) __builtin_assume(condition)
|
||||||
#define NXT_ASSERT_CALLSITE_HELPER(file, func, line, condition) \
|
# else
|
||||||
__builtin_assume(condition)
|
# define NXT_ASSERT_CALLSITE_HELPER(file, func, line, condition) \
|
||||||
#else
|
do { \
|
||||||
#define NXT_ASSERT_CALLSITE_HELPER(file, func, line, condition) \
|
(void)sizeof(condition); \
|
||||||
do { \
|
} while (NXT_ASSERT_LOOP_CONDITION)
|
||||||
(void) sizeof(condition); \
|
# endif
|
||||||
} while(NXT_ASSERT_LOOP_CONDITION)
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define NXT_ASSERT(condition) NXT_ASSERT_CALLSITE_HELPER(__FILE__, __func__, __LINE__, condition)
|
#define NXT_ASSERT(condition) NXT_ASSERT_CALLSITE_HELPER(__FILE__, __func__, __LINE__, condition)
|
||||||
#define NXT_UNREACHABLE() \
|
#define NXT_UNREACHABLE() \
|
||||||
do { \
|
do { \
|
||||||
NXT_ASSERT(NXT_ASSERT_LOOP_CONDITION && "Unreachable code hit"); NXT_BUILTIN_UNREACHABLE(); \
|
NXT_ASSERT(NXT_ASSERT_LOOP_CONDITION && "Unreachable code hit"); \
|
||||||
} while(NXT_ASSERT_LOOP_CONDITION)
|
NXT_BUILTIN_UNREACHABLE(); \
|
||||||
|
} while (NXT_ASSERT_LOOP_CONDITION)
|
||||||
|
|
||||||
#if !defined(NXT_SKIP_ASSERT_SHORTHANDS)
|
#if !defined(NXT_SKIP_ASSERT_SHORTHANDS)
|
||||||
#define ASSERT NXT_ASSERT
|
# define ASSERT NXT_ASSERT
|
||||||
#define UNREACHABLE NXT_UNREACHABLE
|
# define UNREACHABLE NXT_UNREACHABLE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif // COMMON_ASSERT_H_
|
void HandleAssertionFailure(const char* file,
|
||||||
|
const char* function,
|
||||||
|
int line,
|
||||||
|
const char* condition);
|
||||||
|
|
||||||
|
#endif // COMMON_ASSERT_H_
|
||||||
|
@ -21,7 +21,6 @@
|
|||||||
#include <bitset>
|
#include <bitset>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
|
||||||
|
|
||||||
// This is ANGLE's BitSetIterator class with a customizable return type
|
// This is ANGLE's BitSetIterator class with a customizable return type
|
||||||
// TODO(cwallez@chromium.org): it could be optimized, in particular when N <= 64
|
// TODO(cwallez@chromium.org): it could be optimized, in particular when N <= 64
|
||||||
|
|
||||||
@ -33,44 +32,48 @@ T roundUp(const T value, const T alignment) {
|
|||||||
|
|
||||||
template <size_t N, typename T>
|
template <size_t N, typename T>
|
||||||
class BitSetIterator final {
|
class BitSetIterator final {
|
||||||
public:
|
public:
|
||||||
BitSetIterator(const std::bitset<N>& bitset);
|
BitSetIterator(const std::bitset<N>& bitset);
|
||||||
BitSetIterator(const BitSetIterator& other);
|
BitSetIterator(const BitSetIterator& other);
|
||||||
BitSetIterator &operator=(const BitSetIterator& other);
|
BitSetIterator& operator=(const BitSetIterator& other);
|
||||||
|
|
||||||
class Iterator final {
|
class Iterator final {
|
||||||
public:
|
public:
|
||||||
Iterator(const std::bitset<N>& bits);
|
Iterator(const std::bitset<N>& bits);
|
||||||
Iterator& operator++();
|
Iterator& operator++();
|
||||||
|
|
||||||
bool operator==(const Iterator& other) const;
|
bool operator==(const Iterator& other) const;
|
||||||
bool operator!=(const Iterator& other) const;
|
bool operator!=(const Iterator& other) const;
|
||||||
T operator*() const { return static_cast<T>(mCurrentBit); }
|
T operator*() const {
|
||||||
|
return static_cast<T>(mCurrentBit);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
unsigned long getNextBit();
|
unsigned long getNextBit();
|
||||||
|
|
||||||
static const size_t BitsPerWord = sizeof(uint32_t) * 8;
|
static const size_t BitsPerWord = sizeof(uint32_t) * 8;
|
||||||
std::bitset<N> mBits;
|
std::bitset<N> mBits;
|
||||||
unsigned long mCurrentBit;
|
unsigned long mCurrentBit;
|
||||||
unsigned long mOffset;
|
unsigned long mOffset;
|
||||||
};
|
};
|
||||||
|
|
||||||
Iterator begin() const { return Iterator(mBits); }
|
Iterator begin() const {
|
||||||
Iterator end() const { return Iterator(std::bitset<N>(0)); }
|
return Iterator(mBits);
|
||||||
|
}
|
||||||
|
Iterator end() const {
|
||||||
|
return Iterator(std::bitset<N>(0));
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const std::bitset<N> mBits;
|
const std::bitset<N> mBits;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <size_t N, typename T>
|
template <size_t N, typename T>
|
||||||
BitSetIterator<N, T>::BitSetIterator(const std::bitset<N>& bitset)
|
BitSetIterator<N, T>::BitSetIterator(const std::bitset<N>& bitset) : mBits(bitset) {
|
||||||
: mBits(bitset) {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <size_t N, typename T>
|
template <size_t N, typename T>
|
||||||
BitSetIterator<N, T>::BitSetIterator(const BitSetIterator& other)
|
BitSetIterator<N, T>::BitSetIterator(const BitSetIterator& other) : mBits(other.mBits) {
|
||||||
: mBits(other.mBits) {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <size_t N, typename T>
|
template <size_t N, typename T>
|
||||||
|
@ -21,32 +21,32 @@
|
|||||||
// - NXT_BUILTIN_UNREACHABLE(): Hints the compiler that a code path is unreachable
|
// - NXT_BUILTIN_UNREACHABLE(): Hints the compiler that a code path is unreachable
|
||||||
|
|
||||||
// Clang and GCC
|
// Clang and GCC
|
||||||
#ifdef __GNUC__
|
#if defined(__GNUC__)
|
||||||
#if defined(__clang__)
|
# if defined(__clang__)
|
||||||
#define NXT_COMPILER_CLANG
|
# define NXT_COMPILER_CLANG
|
||||||
#else
|
# else
|
||||||
#define NXT_COMPILER_GCC
|
# define NXT_COMPILER_GCC
|
||||||
#endif
|
# endif
|
||||||
|
|
||||||
#if defined(__i386__) || defined(__x86_64__)
|
# if defined(__i386__) || defined(__x86_64__)
|
||||||
#define NXT_BREAKPOINT() __asm__ __volatile__("int $3\n\t")
|
# define NXT_BREAKPOINT() __asm__ __volatile__("int $3\n\t")
|
||||||
#else
|
# else
|
||||||
#error "Implement BREAKPOINT on your platform"
|
# error "Implement BREAKPOINT on your platform"
|
||||||
#endif
|
# endif
|
||||||
|
|
||||||
#define NXT_BUILTIN_UNREACHABLE() __builtin_unreachable()
|
# define NXT_BUILTIN_UNREACHABLE() __builtin_unreachable()
|
||||||
|
|
||||||
// MSVC
|
// MSVC
|
||||||
#elif defined(_MSC_VER)
|
#elif defined(_MSC_VER)
|
||||||
#define NXT_COMPILER_MSVC
|
# define NXT_COMPILER_MSVC
|
||||||
|
|
||||||
extern void __cdecl __debugbreak(void);
|
extern void __cdecl __debugbreak(void);
|
||||||
#define NXT_BREAKPOINT() __debugbreak()
|
# define NXT_BREAKPOINT() __debugbreak()
|
||||||
|
|
||||||
#define NXT_BUILTIN_UNREACHABLE() __assume(false)
|
# define NXT_BUILTIN_UNREACHABLE() __assume(false)
|
||||||
|
|
||||||
#else
|
#else
|
||||||
#error "Unsupported compiler"
|
# error "Unsupported compiler"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif // COMMON_COMPILER_H_
|
#endif // COMMON_COMPILER_H_
|
||||||
|
@ -19,11 +19,12 @@
|
|||||||
|
|
||||||
static constexpr uint32_t kMaxPushConstants = 32u;
|
static constexpr uint32_t kMaxPushConstants = 32u;
|
||||||
static constexpr uint32_t kMaxBindGroups = 4u;
|
static constexpr uint32_t kMaxBindGroups = 4u;
|
||||||
static constexpr uint32_t kMaxBindingsPerGroup = 16u; // TODO(cwallez@chromium.org): investigate bindgroup limits
|
// TODO(cwallez@chromium.org): investigate bindgroup limits
|
||||||
|
static constexpr uint32_t kMaxBindingsPerGroup = 16u;
|
||||||
static constexpr uint32_t kMaxVertexAttributes = 16u;
|
static constexpr uint32_t kMaxVertexAttributes = 16u;
|
||||||
static constexpr uint32_t kMaxVertexInputs = 16u;
|
static constexpr uint32_t kMaxVertexInputs = 16u;
|
||||||
static constexpr uint32_t kNumStages = 3;
|
static constexpr uint32_t kNumStages = 3;
|
||||||
static constexpr uint32_t kMaxColorAttachments = 4u;
|
static constexpr uint32_t kMaxColorAttachments = 4u;
|
||||||
static constexpr uint32_t kTextureRowPitchAlignment = 256u;
|
static constexpr uint32_t kTextureRowPitchAlignment = 256u;
|
||||||
|
|
||||||
#endif // COMMON_CONSTANTS_H_
|
#endif // COMMON_CONSTANTS_H_
|
||||||
|
@ -17,11 +17,11 @@
|
|||||||
#include "common/Platform.h"
|
#include "common/Platform.h"
|
||||||
|
|
||||||
#if NXT_PLATFORM_WINDOWS
|
#if NXT_PLATFORM_WINDOWS
|
||||||
#include <windows.h>
|
# include <windows.h>
|
||||||
#elif NXT_PLATFORM_POSIX
|
#elif NXT_PLATFORM_POSIX
|
||||||
#include <dlfcn.h>
|
# include <dlfcn.h>
|
||||||
#else
|
#else
|
||||||
#error "Unsupported platform for DynamicLib"
|
# error "Unsupported platform for DynamicLib"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
DynamicLib::~DynamicLib() {
|
DynamicLib::~DynamicLib() {
|
||||||
@ -42,21 +42,21 @@ bool DynamicLib::Valid() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool DynamicLib::Open(const std::string& filename, std::string* error) {
|
bool DynamicLib::Open(const std::string& filename, std::string* error) {
|
||||||
#if NXT_PLATFORM_WINDOWS
|
#if NXT_PLATFORM_WINDOWS
|
||||||
mHandle = LoadLibraryA(filename.c_str());
|
mHandle = LoadLibraryA(filename.c_str());
|
||||||
|
|
||||||
if (mHandle == nullptr && error != nullptr) {
|
if (mHandle == nullptr && error != nullptr) {
|
||||||
*error = "Windows Error: " + std::to_string(GetLastError());
|
*error = "Windows Error: " + std::to_string(GetLastError());
|
||||||
}
|
}
|
||||||
#elif NXT_PLATFORM_POSIX
|
#elif NXT_PLATFORM_POSIX
|
||||||
mHandle = dlopen(filename.c_str(), RTLD_NOW);
|
mHandle = dlopen(filename.c_str(), RTLD_NOW);
|
||||||
|
|
||||||
if (mHandle == nullptr && error != nullptr) {
|
if (mHandle == nullptr && error != nullptr) {
|
||||||
*error = dlerror();
|
*error = dlerror();
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
#error "Unsupported platform for DynamicLib"
|
# error "Unsupported platform for DynamicLib"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return mHandle != nullptr;
|
return mHandle != nullptr;
|
||||||
}
|
}
|
||||||
@ -66,13 +66,13 @@ void DynamicLib::Close() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if NXT_PLATFORM_WINDOWS
|
#if NXT_PLATFORM_WINDOWS
|
||||||
FreeLibrary(static_cast<HMODULE>(mHandle));
|
FreeLibrary(static_cast<HMODULE>(mHandle));
|
||||||
#elif NXT_PLATFORM_POSIX
|
#elif NXT_PLATFORM_POSIX
|
||||||
dlclose(mHandle);
|
dlclose(mHandle);
|
||||||
#else
|
#else
|
||||||
#error "Unsupported platform for DynamicLib"
|
# error "Unsupported platform for DynamicLib"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
mHandle = nullptr;
|
mHandle = nullptr;
|
||||||
}
|
}
|
||||||
@ -80,21 +80,21 @@ void DynamicLib::Close() {
|
|||||||
void* DynamicLib::GetProc(const std::string& procName, std::string* error) const {
|
void* DynamicLib::GetProc(const std::string& procName, std::string* error) const {
|
||||||
void* proc = nullptr;
|
void* proc = nullptr;
|
||||||
|
|
||||||
#if NXT_PLATFORM_WINDOWS
|
#if NXT_PLATFORM_WINDOWS
|
||||||
proc = reinterpret_cast<void*>(GetProcAddress(static_cast<HMODULE>(mHandle), procName.c_str()));
|
proc = reinterpret_cast<void*>(GetProcAddress(static_cast<HMODULE>(mHandle), procName.c_str()));
|
||||||
|
|
||||||
if (proc == nullptr && error != nullptr) {
|
if (proc == nullptr && error != nullptr) {
|
||||||
*error = "Windows Error: " + std::to_string(GetLastError());
|
*error = "Windows Error: " + std::to_string(GetLastError());
|
||||||
}
|
}
|
||||||
#elif NXT_PLATFORM_POSIX
|
#elif NXT_PLATFORM_POSIX
|
||||||
proc = reinterpret_cast<void*>(dlsym(mHandle, procName.c_str()));
|
proc = reinterpret_cast<void*>(dlsym(mHandle, procName.c_str()));
|
||||||
|
|
||||||
if (proc == nullptr && error != nullptr) {
|
if (proc == nullptr && error != nullptr) {
|
||||||
*error = dlerror();
|
*error = dlerror();
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
#error "Unsupported platform for DynamicLib"
|
# error "Unsupported platform for DynamicLib"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return proc;
|
return proc;
|
||||||
}
|
}
|
||||||
|
@ -21,34 +21,34 @@
|
|||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
class DynamicLib {
|
class DynamicLib {
|
||||||
public:
|
public:
|
||||||
DynamicLib() = default;
|
DynamicLib() = default;
|
||||||
~DynamicLib();
|
~DynamicLib();
|
||||||
|
|
||||||
DynamicLib(const DynamicLib&) = delete;
|
DynamicLib(const DynamicLib&) = delete;
|
||||||
DynamicLib& operator=(const DynamicLib&) = delete;
|
DynamicLib& operator=(const DynamicLib&) = delete;
|
||||||
|
|
||||||
DynamicLib(DynamicLib&& other);
|
DynamicLib(DynamicLib&& other);
|
||||||
DynamicLib& operator=(DynamicLib&& other);
|
DynamicLib& operator=(DynamicLib&& other);
|
||||||
|
|
||||||
bool Valid() const;
|
bool Valid() const;
|
||||||
|
|
||||||
bool Open(const std::string& filename, std::string* error = nullptr);
|
bool Open(const std::string& filename, std::string* error = nullptr);
|
||||||
void Close();
|
void Close();
|
||||||
|
|
||||||
void* GetProc(const std::string& procName, std::string* error = nullptr) const;
|
void* GetProc(const std::string& procName, std::string* error = nullptr) const;
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
bool GetProc(T** proc, const std::string& procName, std::string* error = nullptr) const {
|
bool GetProc(T** proc, const std::string& procName, std::string* error = nullptr) const {
|
||||||
ASSERT(proc != nullptr);
|
ASSERT(proc != nullptr);
|
||||||
static_assert(std::is_function<T>::value, "");
|
static_assert(std::is_function<T>::value, "");
|
||||||
|
|
||||||
*proc = reinterpret_cast<T*>(GetProc(procName, error));
|
*proc = reinterpret_cast<T*>(GetProc(procName, error));
|
||||||
return *proc != nullptr;
|
return *proc != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void* mHandle = nullptr;
|
void* mHandle = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // COMMON_DYNAMICLIB_H_
|
#endif // COMMON_DYNAMICLIB_H_
|
||||||
|
@ -17,31 +17,31 @@
|
|||||||
#include "common/Assert.h"
|
#include "common/Assert.h"
|
||||||
|
|
||||||
#if defined(NXT_COMPILER_MSVC)
|
#if defined(NXT_COMPILER_MSVC)
|
||||||
#include <intrin.h>
|
# include <intrin.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
uint32_t ScanForward(uint32_t bits) {
|
uint32_t ScanForward(uint32_t bits) {
|
||||||
ASSERT(bits != 0);
|
ASSERT(bits != 0);
|
||||||
#if defined(NXT_COMPILER_MSVC)
|
#if defined(NXT_COMPILER_MSVC)
|
||||||
unsigned long firstBitIndex = 0ul;
|
unsigned long firstBitIndex = 0ul;
|
||||||
unsigned char ret = _BitScanForward(&firstBitIndex, bits);
|
unsigned char ret = _BitScanForward(&firstBitIndex, bits);
|
||||||
ASSERT(ret != 0);
|
ASSERT(ret != 0);
|
||||||
return firstBitIndex;
|
return firstBitIndex;
|
||||||
#else
|
#else
|
||||||
return static_cast<uint32_t>(__builtin_ctz(bits));
|
return static_cast<uint32_t>(__builtin_ctz(bits));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t Log2(uint32_t value) {
|
uint32_t Log2(uint32_t value) {
|
||||||
ASSERT(value != 0);
|
ASSERT(value != 0);
|
||||||
#if defined(NXT_COMPILER_MSVC)
|
#if defined(NXT_COMPILER_MSVC)
|
||||||
unsigned long firstBitIndex = 0ul;
|
unsigned long firstBitIndex = 0ul;
|
||||||
unsigned char ret = _BitScanReverse(&firstBitIndex, value);
|
unsigned char ret = _BitScanReverse(&firstBitIndex, value);
|
||||||
ASSERT(ret != 0);
|
ASSERT(ret != 0);
|
||||||
return firstBitIndex;
|
return firstBitIndex;
|
||||||
#else
|
#else
|
||||||
return 31 - static_cast<uint32_t>(__builtin_clz(value));
|
return 31 - static_cast<uint32_t>(__builtin_clz(value));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsPowerOfTwo(size_t n) {
|
bool IsPowerOfTwo(size_t n) {
|
||||||
@ -58,7 +58,8 @@ bool IsPtrAligned(const void* ptr, size_t alignment) {
|
|||||||
void* AlignVoidPtr(void* ptr, size_t alignment) {
|
void* AlignVoidPtr(void* ptr, size_t alignment) {
|
||||||
ASSERT(IsPowerOfTwo(alignment));
|
ASSERT(IsPowerOfTwo(alignment));
|
||||||
ASSERT(alignment != 0);
|
ASSERT(alignment != 0);
|
||||||
return reinterpret_cast<void*>((reinterpret_cast<size_t>(ptr) + (alignment - 1)) & ~(alignment - 1));
|
return reinterpret_cast<void*>((reinterpret_cast<size_t>(ptr) + (alignment - 1)) &
|
||||||
|
~(alignment - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsAligned(uint32_t value, size_t alignment) {
|
bool IsAligned(uint32_t value, size_t alignment) {
|
||||||
|
@ -28,14 +28,14 @@ void* AlignVoidPtr(void* ptr, size_t alignment);
|
|||||||
bool IsAligned(uint32_t value, size_t alignment);
|
bool IsAligned(uint32_t value, size_t alignment);
|
||||||
uint32_t Align(uint32_t value, size_t alignment);
|
uint32_t Align(uint32_t value, size_t alignment);
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
T* AlignPtr(T* ptr, size_t alignment) {
|
T* AlignPtr(T* ptr, size_t alignment) {
|
||||||
return reinterpret_cast<T*>(AlignVoidPtr(ptr, alignment));
|
return reinterpret_cast<T*>(AlignVoidPtr(ptr, alignment));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
const T* AlignPtr(const T* ptr, size_t alignment) {
|
const T* AlignPtr(const T* ptr, size_t alignment) {
|
||||||
return reinterpret_cast<const T*>(AlignVoidPtr(const_cast<T*>(ptr), alignment));
|
return reinterpret_cast<const T*>(AlignVoidPtr(const_cast<T*>(ptr), alignment));
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // COMMON_MATH_H_
|
#endif // COMMON_MATH_H_
|
||||||
|
@ -16,15 +16,15 @@
|
|||||||
#define COMMON_PLATFORM_H_
|
#define COMMON_PLATFORM_H_
|
||||||
|
|
||||||
#if defined(_WIN32) || defined(_WIN64)
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
#define NXT_PLATFORM_WINDOWS 1
|
# define NXT_PLATFORM_WINDOWS 1
|
||||||
#elif defined(__linux__)
|
#elif defined(__linux__)
|
||||||
#define NXT_PLATFORM_LINUX 1
|
# define NXT_PLATFORM_LINUX 1
|
||||||
#define NXT_PLATFORM_POSIX 1
|
# define NXT_PLATFORM_POSIX 1
|
||||||
#elif defined(__APPLE__)
|
#elif defined(__APPLE__)
|
||||||
#define NXT_PLATFORM_APPLE 1
|
# define NXT_PLATFORM_APPLE 1
|
||||||
#define NXT_PLATFORM_POSIX 1
|
# define NXT_PLATFORM_POSIX 1
|
||||||
#else
|
#else
|
||||||
#error "Unsupported platform."
|
# error "Unsupported platform."
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif // COMMON_PLATFORM_H_
|
#endif // COMMON_PLATFORM_H_
|
||||||
|
@ -19,4 +19,4 @@
|
|||||||
|
|
||||||
using Serial = uint64_t;
|
using Serial = uint64_t;
|
||||||
|
|
||||||
#endif // COMMON_SERIAL_H_
|
#endif // COMMON_SERIAL_H_
|
||||||
|
@ -21,101 +21,101 @@
|
|||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
class SerialQueue {
|
class SerialQueue {
|
||||||
private:
|
private:
|
||||||
using SerialPair = std::pair<Serial, std::vector<T>>;
|
using SerialPair = std::pair<Serial, std::vector<T>>;
|
||||||
using Storage = std::vector<SerialPair>;
|
using Storage = std::vector<SerialPair>;
|
||||||
using StorageIterator = typename Storage::iterator;
|
using StorageIterator = typename Storage::iterator;
|
||||||
using ConstStorageIterator = typename Storage::const_iterator;
|
using ConstStorageIterator = typename Storage::const_iterator;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
class Iterator {
|
class Iterator {
|
||||||
public:
|
public:
|
||||||
Iterator(StorageIterator start);
|
Iterator(StorageIterator start);
|
||||||
Iterator& operator++();
|
Iterator& operator++();
|
||||||
|
|
||||||
bool operator==(const Iterator& other) const;
|
bool operator==(const Iterator& other) const;
|
||||||
bool operator!=(const Iterator& other) const;
|
bool operator!=(const Iterator& other) const;
|
||||||
T& operator*() const;
|
T& operator*() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
StorageIterator mStorageIterator;
|
StorageIterator mStorageIterator;
|
||||||
// Special case the mSerialIterator when it should be equal to mStorageIterator.begin()
|
// Special case the mSerialIterator when it should be equal to mStorageIterator.begin()
|
||||||
// otherwise we could ask mStorageIterator.begin() when mStorageIterator is mStorage.end()
|
// otherwise we could ask mStorageIterator.begin() when mStorageIterator is mStorage.end()
|
||||||
// which is invalid. mStorageIterator.begin() is tagged with a nullptr.
|
// which is invalid. mStorageIterator.begin() is tagged with a nullptr.
|
||||||
T* mSerialIterator;
|
T* mSerialIterator;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ConstIterator {
|
class ConstIterator {
|
||||||
public:
|
public:
|
||||||
ConstIterator(ConstStorageIterator start);
|
ConstIterator(ConstStorageIterator start);
|
||||||
ConstIterator& operator++();
|
ConstIterator& operator++();
|
||||||
|
|
||||||
bool operator==(const ConstIterator& other) const;
|
bool operator==(const ConstIterator& other) const;
|
||||||
bool operator!=(const ConstIterator& other) const;
|
bool operator!=(const ConstIterator& other) const;
|
||||||
const T& operator*() const;
|
const T& operator*() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ConstStorageIterator mStorageIterator;
|
ConstStorageIterator mStorageIterator;
|
||||||
const T* mSerialIterator;
|
const T* mSerialIterator;
|
||||||
};
|
};
|
||||||
|
|
||||||
class BeginEnd {
|
class BeginEnd {
|
||||||
public:
|
public:
|
||||||
BeginEnd(StorageIterator start, StorageIterator end);
|
BeginEnd(StorageIterator start, StorageIterator end);
|
||||||
|
|
||||||
Iterator begin() const;
|
Iterator begin() const;
|
||||||
Iterator end() const;
|
Iterator end() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
StorageIterator mStartIt;
|
StorageIterator mStartIt;
|
||||||
StorageIterator mEndIt;
|
StorageIterator mEndIt;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ConstBeginEnd {
|
class ConstBeginEnd {
|
||||||
public:
|
public:
|
||||||
ConstBeginEnd(ConstStorageIterator start, ConstStorageIterator end);
|
ConstBeginEnd(ConstStorageIterator start, ConstStorageIterator end);
|
||||||
|
|
||||||
ConstIterator begin() const;
|
ConstIterator begin() const;
|
||||||
ConstIterator end() const;
|
ConstIterator end() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ConstStorageIterator mStartIt;
|
ConstStorageIterator mStartIt;
|
||||||
ConstStorageIterator mEndIt;
|
ConstStorageIterator mEndIt;
|
||||||
};
|
};
|
||||||
|
|
||||||
// The serial must be given in (not strictly) increasing order.
|
// The serial must be given in (not strictly) increasing order.
|
||||||
void Enqueue(const T& value, Serial serial);
|
void Enqueue(const T& value, Serial serial);
|
||||||
void Enqueue(T&& value, Serial serial);
|
void Enqueue(T&& value, Serial serial);
|
||||||
void Enqueue(const std::vector<T>& values, Serial serial);
|
void Enqueue(const std::vector<T>& values, Serial serial);
|
||||||
void Enqueue(std::vector<T>&& values, Serial serial);
|
void Enqueue(std::vector<T>&& values, Serial serial);
|
||||||
|
|
||||||
bool Empty() const;
|
bool Empty() const;
|
||||||
|
|
||||||
// The UpTo variants of Iterate and Clear affect all values associated to a serial
|
// The UpTo variants of Iterate and Clear affect all values associated to a serial
|
||||||
// that is smaller OR EQUAL to the given serial. Iterating is done like so:
|
// that is smaller OR EQUAL to the given serial. Iterating is done like so:
|
||||||
// for (const T& value : queue.IterateAll()) { stuff(T); }
|
// for (const T& value : queue.IterateAll()) { stuff(T); }
|
||||||
ConstBeginEnd IterateAll() const;
|
ConstBeginEnd IterateAll() const;
|
||||||
ConstBeginEnd IterateUpTo(Serial serial) const;
|
ConstBeginEnd IterateUpTo(Serial serial) const;
|
||||||
BeginEnd IterateAll();
|
BeginEnd IterateAll();
|
||||||
BeginEnd IterateUpTo(Serial serial);
|
BeginEnd IterateUpTo(Serial serial);
|
||||||
|
|
||||||
void Clear();
|
void Clear();
|
||||||
void ClearUpTo(Serial serial);
|
void ClearUpTo(Serial serial);
|
||||||
|
|
||||||
Serial FirstSerial() const;
|
Serial FirstSerial() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Returns the first StorageIterator that a serial bigger than serial.
|
// Returns the first StorageIterator that a serial bigger than serial.
|
||||||
ConstStorageIterator FindUpTo(Serial serial) const;
|
ConstStorageIterator FindUpTo(Serial serial) const;
|
||||||
StorageIterator FindUpTo(Serial serial);
|
StorageIterator FindUpTo(Serial serial);
|
||||||
Storage mStorage;
|
Storage mStorage;
|
||||||
};
|
};
|
||||||
|
|
||||||
// SerialQueue
|
// SerialQueue
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
void SerialQueue<T>::Enqueue(const T& value, Serial serial) {
|
void SerialQueue<T>::Enqueue(const T& value, Serial serial) {
|
||||||
NXT_ASSERT(Empty() || mStorage.back().first <= serial);
|
NXT_ASSERT(Empty() || mStorage.back().first <= serial);
|
||||||
|
|
||||||
@ -125,7 +125,7 @@ void SerialQueue<T>::Enqueue(const T& value, Serial serial) {
|
|||||||
mStorage.back().second.emplace_back(value);
|
mStorage.back().second.emplace_back(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
void SerialQueue<T>::Enqueue(T&& value, Serial serial) {
|
void SerialQueue<T>::Enqueue(T&& value, Serial serial) {
|
||||||
NXT_ASSERT(Empty() || mStorage.back().first <= serial);
|
NXT_ASSERT(Empty() || mStorage.back().first <= serial);
|
||||||
|
|
||||||
@ -135,132 +135,133 @@ void SerialQueue<T>::Enqueue(T&& value, Serial serial) {
|
|||||||
mStorage.back().second.emplace_back(value);
|
mStorage.back().second.emplace_back(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
void SerialQueue<T>::Enqueue(const std::vector<T>& values, Serial serial) {
|
void SerialQueue<T>::Enqueue(const std::vector<T>& values, Serial serial) {
|
||||||
NXT_ASSERT(values.size() > 0);
|
NXT_ASSERT(values.size() > 0);
|
||||||
NXT_ASSERT(Empty() || mStorage.back().first <= serial);
|
NXT_ASSERT(Empty() || mStorage.back().first <= serial);
|
||||||
mStorage.emplace_back(SerialPair(serial, {values}));
|
mStorage.emplace_back(SerialPair(serial, {values}));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
void SerialQueue<T>::Enqueue(std::vector<T>&& values, Serial serial) {
|
void SerialQueue<T>::Enqueue(std::vector<T>&& values, Serial serial) {
|
||||||
NXT_ASSERT(values.size() > 0);
|
NXT_ASSERT(values.size() > 0);
|
||||||
NXT_ASSERT(Empty() || mStorage.back().first <= serial);
|
NXT_ASSERT(Empty() || mStorage.back().first <= serial);
|
||||||
mStorage.emplace_back(SerialPair(serial, {values}));
|
mStorage.emplace_back(SerialPair(serial, {values}));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
bool SerialQueue<T>::Empty() const {
|
bool SerialQueue<T>::Empty() const {
|
||||||
return mStorage.empty();
|
return mStorage.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
typename SerialQueue<T>::ConstBeginEnd SerialQueue<T>::IterateAll() const {
|
typename SerialQueue<T>::ConstBeginEnd SerialQueue<T>::IterateAll() const {
|
||||||
return {mStorage.begin(), mStorage.end()};
|
return {mStorage.begin(), mStorage.end()};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
typename SerialQueue<T>::ConstBeginEnd SerialQueue<T>::IterateUpTo(Serial serial) const {
|
typename SerialQueue<T>::ConstBeginEnd SerialQueue<T>::IterateUpTo(Serial serial) const {
|
||||||
return {mStorage.begin(), FindUpTo(serial)};
|
return {mStorage.begin(), FindUpTo(serial)};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
typename SerialQueue<T>::BeginEnd SerialQueue<T>::IterateAll() {
|
typename SerialQueue<T>::BeginEnd SerialQueue<T>::IterateAll() {
|
||||||
return {mStorage.begin(), mStorage.end()};
|
return {mStorage.begin(), mStorage.end()};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
typename SerialQueue<T>::BeginEnd SerialQueue<T>::IterateUpTo(Serial serial) {
|
typename SerialQueue<T>::BeginEnd SerialQueue<T>::IterateUpTo(Serial serial) {
|
||||||
return {mStorage.begin(), FindUpTo(serial)};
|
return {mStorage.begin(), FindUpTo(serial)};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
void SerialQueue<T>::Clear() {
|
void SerialQueue<T>::Clear() {
|
||||||
mStorage.clear();
|
mStorage.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
void SerialQueue<T>::ClearUpTo(Serial serial) {
|
void SerialQueue<T>::ClearUpTo(Serial serial) {
|
||||||
mStorage.erase(mStorage.begin(), FindUpTo(serial));
|
mStorage.erase(mStorage.begin(), FindUpTo(serial));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
Serial SerialQueue<T>::FirstSerial() const {
|
Serial SerialQueue<T>::FirstSerial() const {
|
||||||
NXT_ASSERT(!Empty());
|
NXT_ASSERT(!Empty());
|
||||||
return mStorage.front().first;
|
return mStorage.front().first;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
typename SerialQueue<T>::ConstStorageIterator SerialQueue<T>::FindUpTo(Serial serial) const {
|
typename SerialQueue<T>::ConstStorageIterator SerialQueue<T>::FindUpTo(Serial serial) const {
|
||||||
auto it = mStorage.begin();
|
auto it = mStorage.begin();
|
||||||
while (it != mStorage.end() && it->first <= serial) {
|
while (it != mStorage.end() && it->first <= serial) {
|
||||||
it ++;
|
it++;
|
||||||
}
|
}
|
||||||
return it;
|
return it;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
typename SerialQueue<T>::StorageIterator SerialQueue<T>::FindUpTo(Serial serial) {
|
typename SerialQueue<T>::StorageIterator SerialQueue<T>::FindUpTo(Serial serial) {
|
||||||
auto it = mStorage.begin();
|
auto it = mStorage.begin();
|
||||||
while (it != mStorage.end() && it->first <= serial) {
|
while (it != mStorage.end() && it->first <= serial) {
|
||||||
it ++;
|
it++;
|
||||||
}
|
}
|
||||||
return it;
|
return it;
|
||||||
}
|
}
|
||||||
|
|
||||||
// SerialQueue::BeginEnd
|
// SerialQueue::BeginEnd
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
SerialQueue<T>::BeginEnd::BeginEnd(typename SerialQueue<T>::StorageIterator start, typename SerialQueue<T>::StorageIterator end)
|
SerialQueue<T>::BeginEnd::BeginEnd(typename SerialQueue<T>::StorageIterator start,
|
||||||
|
typename SerialQueue<T>::StorageIterator end)
|
||||||
: mStartIt(start), mEndIt(end) {
|
: mStartIt(start), mEndIt(end) {
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
typename SerialQueue<T>::Iterator SerialQueue<T>::BeginEnd::begin() const {
|
typename SerialQueue<T>::Iterator SerialQueue<T>::BeginEnd::begin() const {
|
||||||
return {mStartIt};
|
return {mStartIt};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
typename SerialQueue<T>::Iterator SerialQueue<T>::BeginEnd::end() const {
|
typename SerialQueue<T>::Iterator SerialQueue<T>::BeginEnd::end() const {
|
||||||
return {mEndIt};
|
return {mEndIt};
|
||||||
}
|
}
|
||||||
|
|
||||||
// SerialQueue::Iterator
|
// SerialQueue::Iterator
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
SerialQueue<T>::Iterator::Iterator(typename SerialQueue<T>::StorageIterator start)
|
SerialQueue<T>::Iterator::Iterator(typename SerialQueue<T>::StorageIterator start)
|
||||||
: mStorageIterator(start), mSerialIterator(nullptr) {
|
: mStorageIterator(start), mSerialIterator(nullptr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
typename SerialQueue<T>::Iterator& SerialQueue<T>::Iterator::operator++() {
|
typename SerialQueue<T>::Iterator& SerialQueue<T>::Iterator::operator++() {
|
||||||
T* vectorData = mStorageIterator->second.data();
|
T* vectorData = mStorageIterator->second.data();
|
||||||
|
|
||||||
if (mSerialIterator == nullptr) {
|
if (mSerialIterator == nullptr) {
|
||||||
mSerialIterator = vectorData + 1;
|
mSerialIterator = vectorData + 1;
|
||||||
} else {
|
} else {
|
||||||
mSerialIterator ++;
|
mSerialIterator++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mSerialIterator >= vectorData + mStorageIterator->second.size()) {
|
if (mSerialIterator >= vectorData + mStorageIterator->second.size()) {
|
||||||
mSerialIterator = nullptr;
|
mSerialIterator = nullptr;
|
||||||
mStorageIterator ++;
|
mStorageIterator++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
bool SerialQueue<T>::Iterator::operator==(const typename SerialQueue<T>::Iterator& other) const {
|
bool SerialQueue<T>::Iterator::operator==(const typename SerialQueue<T>::Iterator& other) const {
|
||||||
return other.mStorageIterator == mStorageIterator && other.mSerialIterator == mSerialIterator;
|
return other.mStorageIterator == mStorageIterator && other.mSerialIterator == mSerialIterator;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
bool SerialQueue<T>::Iterator::operator!=(const typename SerialQueue<T>::Iterator& other) const {
|
bool SerialQueue<T>::Iterator::operator!=(const typename SerialQueue<T>::Iterator& other) const {
|
||||||
return !(*this == other);
|
return !(*this == other);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
T& SerialQueue<T>::Iterator::operator*() const {
|
T& SerialQueue<T>::Iterator::operator*() const {
|
||||||
if (mSerialIterator == nullptr) {
|
if (mSerialIterator == nullptr) {
|
||||||
return *mStorageIterator->second.begin();
|
return *mStorageIterator->second.begin();
|
||||||
@ -270,57 +271,60 @@ T& SerialQueue<T>::Iterator::operator*() const {
|
|||||||
|
|
||||||
// SerialQueue::ConstBeginEnd
|
// SerialQueue::ConstBeginEnd
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
SerialQueue<T>::ConstBeginEnd::ConstBeginEnd(typename SerialQueue<T>::ConstStorageIterator start, typename SerialQueue<T>::ConstStorageIterator end)
|
SerialQueue<T>::ConstBeginEnd::ConstBeginEnd(typename SerialQueue<T>::ConstStorageIterator start,
|
||||||
|
typename SerialQueue<T>::ConstStorageIterator end)
|
||||||
: mStartIt(start), mEndIt(end) {
|
: mStartIt(start), mEndIt(end) {
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
typename SerialQueue<T>::ConstIterator SerialQueue<T>::ConstBeginEnd::begin() const {
|
typename SerialQueue<T>::ConstIterator SerialQueue<T>::ConstBeginEnd::begin() const {
|
||||||
return {mStartIt};
|
return {mStartIt};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
typename SerialQueue<T>::ConstIterator SerialQueue<T>::ConstBeginEnd::end() const {
|
typename SerialQueue<T>::ConstIterator SerialQueue<T>::ConstBeginEnd::end() const {
|
||||||
return {mEndIt};
|
return {mEndIt};
|
||||||
}
|
}
|
||||||
|
|
||||||
// SerialQueue::ConstIterator
|
// SerialQueue::ConstIterator
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
SerialQueue<T>::ConstIterator::ConstIterator(typename SerialQueue<T>::ConstStorageIterator start)
|
SerialQueue<T>::ConstIterator::ConstIterator(typename SerialQueue<T>::ConstStorageIterator start)
|
||||||
: mStorageIterator(start), mSerialIterator(nullptr) {
|
: mStorageIterator(start), mSerialIterator(nullptr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
typename SerialQueue<T>::ConstIterator& SerialQueue<T>::ConstIterator::operator++() {
|
typename SerialQueue<T>::ConstIterator& SerialQueue<T>::ConstIterator::operator++() {
|
||||||
const T* vectorData = mStorageIterator->second.data();
|
const T* vectorData = mStorageIterator->second.data();
|
||||||
|
|
||||||
if (mSerialIterator == nullptr) {
|
if (mSerialIterator == nullptr) {
|
||||||
mSerialIterator = vectorData + 1;
|
mSerialIterator = vectorData + 1;
|
||||||
} else {
|
} else {
|
||||||
mSerialIterator ++;
|
mSerialIterator++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mSerialIterator >= vectorData + mStorageIterator->second.size()) {
|
if (mSerialIterator >= vectorData + mStorageIterator->second.size()) {
|
||||||
mSerialIterator = nullptr;
|
mSerialIterator = nullptr;
|
||||||
mStorageIterator ++;
|
mStorageIterator++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
bool SerialQueue<T>::ConstIterator::operator==(const typename SerialQueue<T>::ConstIterator& other) const {
|
bool SerialQueue<T>::ConstIterator::operator==(
|
||||||
|
const typename SerialQueue<T>::ConstIterator& other) const {
|
||||||
return other.mStorageIterator == mStorageIterator && other.mSerialIterator == mSerialIterator;
|
return other.mStorageIterator == mStorageIterator && other.mSerialIterator == mSerialIterator;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
bool SerialQueue<T>::ConstIterator::operator!=(const typename SerialQueue<T>::ConstIterator& other) const {
|
bool SerialQueue<T>::ConstIterator::operator!=(
|
||||||
|
const typename SerialQueue<T>::ConstIterator& other) const {
|
||||||
return !(*this == other);
|
return !(*this == other);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
const T& SerialQueue<T>::ConstIterator::operator*() const {
|
const T& SerialQueue<T>::ConstIterator::operator*() const {
|
||||||
if (mSerialIterator == nullptr) {
|
if (mSerialIterator == nullptr) {
|
||||||
return *mStorageIterator->second.begin();
|
return *mStorageIterator->second.begin();
|
||||||
@ -328,4 +332,4 @@ const T& SerialQueue<T>::ConstIterator::operator*() const {
|
|||||||
return *mSerialIterator;
|
return *mSerialIterator;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // COMMON_SERIALQUEUE_H_
|
#endif // COMMON_SERIALQUEUE_H_
|
||||||
|
@ -18,21 +18,21 @@
|
|||||||
|
|
||||||
namespace utils {
|
namespace utils {
|
||||||
|
|
||||||
#if defined(NXT_ENABLE_BACKEND_D3D12)
|
#if defined(NXT_ENABLE_BACKEND_D3D12)
|
||||||
BackendBinding* CreateD3D12Binding();
|
BackendBinding* CreateD3D12Binding();
|
||||||
#endif
|
#endif
|
||||||
#if defined(NXT_ENABLE_BACKEND_METAL)
|
#if defined(NXT_ENABLE_BACKEND_METAL)
|
||||||
BackendBinding* CreateMetalBinding();
|
BackendBinding* CreateMetalBinding();
|
||||||
#endif
|
#endif
|
||||||
#if defined(NXT_ENABLE_BACKEND_NULL)
|
#if defined(NXT_ENABLE_BACKEND_NULL)
|
||||||
BackendBinding* CreateNullBinding();
|
BackendBinding* CreateNullBinding();
|
||||||
#endif
|
#endif
|
||||||
#if defined(NXT_ENABLE_BACKEND_OPENGL)
|
#if defined(NXT_ENABLE_BACKEND_OPENGL)
|
||||||
BackendBinding* CreateOpenGLBinding();
|
BackendBinding* CreateOpenGLBinding();
|
||||||
#endif
|
#endif
|
||||||
#if defined(NXT_ENABLE_BACKEND_VULKAN)
|
#if defined(NXT_ENABLE_BACKEND_VULKAN)
|
||||||
BackendBinding* CreateVulkanBinding();
|
BackendBinding* CreateVulkanBinding();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void BackendBinding::SetWindow(GLFWwindow* window) {
|
void BackendBinding::SetWindow(GLFWwindow* window) {
|
||||||
mWindow = window;
|
mWindow = window;
|
||||||
@ -40,34 +40,34 @@ namespace utils {
|
|||||||
|
|
||||||
BackendBinding* CreateBinding(BackendType type) {
|
BackendBinding* CreateBinding(BackendType type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
#if defined(NXT_ENABLE_BACKEND_D3D12)
|
#if defined(NXT_ENABLE_BACKEND_D3D12)
|
||||||
case BackendType::D3D12:
|
case BackendType::D3D12:
|
||||||
return CreateD3D12Binding();
|
return CreateD3D12Binding();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(NXT_ENABLE_BACKEND_METAL)
|
#if defined(NXT_ENABLE_BACKEND_METAL)
|
||||||
case BackendType::Metal:
|
case BackendType::Metal:
|
||||||
return CreateMetalBinding();
|
return CreateMetalBinding();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(NXT_ENABLE_BACKEND_NULL)
|
#if defined(NXT_ENABLE_BACKEND_NULL)
|
||||||
case BackendType::Null:
|
case BackendType::Null:
|
||||||
return CreateNullBinding();
|
return CreateNullBinding();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(NXT_ENABLE_BACKEND_OPENGL)
|
#if defined(NXT_ENABLE_BACKEND_OPENGL)
|
||||||
case BackendType::OpenGL:
|
case BackendType::OpenGL:
|
||||||
return CreateOpenGLBinding();
|
return CreateOpenGLBinding();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(NXT_ENABLE_BACKEND_VULKAN)
|
#if defined(NXT_ENABLE_BACKEND_VULKAN)
|
||||||
case BackendType::Vulkan:
|
case BackendType::Vulkan:
|
||||||
return CreateVulkanBinding();
|
return CreateVulkanBinding();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} // namespace utils
|
||||||
|
@ -32,21 +32,22 @@ namespace utils {
|
|||||||
};
|
};
|
||||||
|
|
||||||
class BackendBinding {
|
class BackendBinding {
|
||||||
public:
|
public:
|
||||||
virtual ~BackendBinding() = default;
|
virtual ~BackendBinding() = default;
|
||||||
|
|
||||||
virtual void SetupGLFWWindowHints() = 0;
|
virtual void SetupGLFWWindowHints() = 0;
|
||||||
virtual void GetProcAndDevice(nxtProcTable* procs, nxtDevice* device) = 0;
|
virtual void GetProcAndDevice(nxtProcTable* procs, nxtDevice* device) = 0;
|
||||||
virtual uint64_t GetSwapChainImplementation() = 0;
|
virtual uint64_t GetSwapChainImplementation() = 0;
|
||||||
virtual nxtTextureFormat GetPreferredSwapChainTextureFormat() = 0;
|
virtual nxtTextureFormat GetPreferredSwapChainTextureFormat() = 0;
|
||||||
|
|
||||||
void SetWindow(GLFWwindow* window);
|
void SetWindow(GLFWwindow* window);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
GLFWwindow* mWindow = nullptr;
|
GLFWwindow* mWindow = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
BackendBinding* CreateBinding(BackendType type);
|
BackendBinding* CreateBinding(BackendType type);
|
||||||
}
|
|
||||||
|
|
||||||
#endif // UTILS_BACKENDBINDING_H_
|
} // namespace utils
|
||||||
|
|
||||||
|
#endif // UTILS_BACKENDBINDING_H_
|
||||||
|
@ -22,27 +22,26 @@
|
|||||||
#include "GLFW/glfw3.h"
|
#include "GLFW/glfw3.h"
|
||||||
#include "GLFW/glfw3native.h"
|
#include "GLFW/glfw3native.h"
|
||||||
|
|
||||||
#include <initializer_list>
|
|
||||||
#include <wrl.h>
|
|
||||||
#include <d3d12.h>
|
#include <d3d12.h>
|
||||||
#include <dxgi1_4.h>
|
#include <dxgi1_4.h>
|
||||||
|
#include <wrl.h>
|
||||||
|
#include <initializer_list>
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
#include <dxgidebug.h>
|
#include <dxgidebug.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
using Microsoft::WRL::ComPtr;
|
using Microsoft::WRL::ComPtr;
|
||||||
|
|
||||||
namespace backend {
|
namespace backend { namespace d3d12 {
|
||||||
namespace d3d12 {
|
|
||||||
void Init(ComPtr<ID3D12Device> d3d12Device, nxtProcTable* procs, nxtDevice* device);
|
void Init(ComPtr<ID3D12Device> d3d12Device, nxtProcTable* procs, nxtDevice* device);
|
||||||
ComPtr<ID3D12CommandQueue> GetCommandQueue(nxtDevice device);
|
ComPtr<ID3D12CommandQueue> GetCommandQueue(nxtDevice device);
|
||||||
uint64_t GetSerial(const nxtDevice device);
|
uint64_t GetSerial(const nxtDevice device);
|
||||||
void NextSerial(nxtDevice device);
|
void NextSerial(nxtDevice device);
|
||||||
void ExecuteCommandLists(nxtDevice device, std::initializer_list<ID3D12CommandList*> commandLists);
|
void ExecuteCommandLists(nxtDevice device,
|
||||||
|
std::initializer_list<ID3D12CommandList*> commandLists);
|
||||||
void WaitForSerial(nxtDevice device, uint64_t serial);
|
void WaitForSerial(nxtDevice device, uint64_t serial);
|
||||||
void OpenCommandList(nxtDevice device, ComPtr<ID3D12GraphicsCommandList>* commandList);
|
void OpenCommandList(nxtDevice device, ComPtr<ID3D12GraphicsCommandList>* commandList);
|
||||||
}
|
}} // namespace backend::d3d12
|
||||||
}
|
|
||||||
|
|
||||||
namespace utils {
|
namespace utils {
|
||||||
namespace {
|
namespace {
|
||||||
@ -56,7 +55,8 @@ namespace utils {
|
|||||||
uint32_t dxgiFactoryFlags = 0;
|
uint32_t dxgiFactoryFlags = 0;
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
// Enable the debug layer (requires the Graphics Tools "optional feature").
|
// Enable the debug layer (requires the Graphics Tools "optional feature").
|
||||||
// NOTE: Enabling the debug layer after device creation will invalidate the active device.
|
// NOTE: Enabling the debug layer after device creation will invalidate the active
|
||||||
|
// device.
|
||||||
{
|
{
|
||||||
ComPtr<ID3D12Debug> debugController;
|
ComPtr<ID3D12Debug> debugController;
|
||||||
if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(&debugController)))) {
|
if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(&debugController)))) {
|
||||||
@ -68,7 +68,8 @@ namespace utils {
|
|||||||
|
|
||||||
ComPtr<IDXGIDebug1> dxgiDebug;
|
ComPtr<IDXGIDebug1> dxgiDebug;
|
||||||
if (SUCCEEDED(DXGIGetDebugInterface1(0, IID_PPV_ARGS(&dxgiDebug)))) {
|
if (SUCCEEDED(DXGIGetDebugInterface1(0, IID_PPV_ARGS(&dxgiDebug)))) {
|
||||||
dxgiDebug->ReportLiveObjects(DXGI_DEBUG_ALL, DXGI_DEBUG_RLO_FLAGS(DXGI_DEBUG_RLO_ALL));
|
dxgiDebug->ReportLiveObjects(DXGI_DEBUG_ALL,
|
||||||
|
DXGI_DEBUG_RLO_FLAGS(DXGI_DEBUG_RLO_ALL));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -101,7 +102,8 @@ namespace utils {
|
|||||||
resourceState |= D3D12_RESOURCE_STATE_COPY_DEST;
|
resourceState |= D3D12_RESOURCE_STATE_COPY_DEST;
|
||||||
}
|
}
|
||||||
if (usage & NXT_TEXTURE_USAGE_BIT_SAMPLED) {
|
if (usage & NXT_TEXTURE_USAGE_BIT_SAMPLED) {
|
||||||
resourceState |= (D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE | D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE);
|
resourceState |= (D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE |
|
||||||
|
D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE);
|
||||||
}
|
}
|
||||||
if (usage & NXT_TEXTURE_USAGE_BIT_STORAGE) {
|
if (usage & NXT_TEXTURE_USAGE_BIT_STORAGE) {
|
||||||
resourceState |= D3D12_RESOURCE_STATE_UNORDERED_ACCESS;
|
resourceState |= D3D12_RESOURCE_STATE_UNORDERED_ACCESS;
|
||||||
@ -112,204 +114,205 @@ namespace utils {
|
|||||||
|
|
||||||
return resourceState;
|
return resourceState;
|
||||||
}
|
}
|
||||||
}
|
} // namespace
|
||||||
|
|
||||||
class SwapChainImplD3D12 : SwapChainImpl {
|
class SwapChainImplD3D12 : SwapChainImpl {
|
||||||
public:
|
public:
|
||||||
static nxtSwapChainImplementation Create(HWND window, const nxtProcTable& procs) {
|
static nxtSwapChainImplementation Create(HWND window, const nxtProcTable& procs) {
|
||||||
auto impl = GenerateSwapChainImplementation<SwapChainImplD3D12, nxtWSIContextD3D12>();
|
auto impl = GenerateSwapChainImplementation<SwapChainImplD3D12, nxtWSIContextD3D12>();
|
||||||
impl.userData = new SwapChainImplD3D12(window, procs);
|
impl.userData = new SwapChainImplD3D12(window, procs);
|
||||||
return impl;
|
return impl;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
nxtDevice mBackendDevice = nullptr;
|
||||||
|
nxtProcTable mProcs = {};
|
||||||
|
|
||||||
|
static constexpr unsigned int kFrameCount = 2;
|
||||||
|
|
||||||
|
HWND mWindow = 0;
|
||||||
|
ComPtr<IDXGIFactory4> mFactory = {};
|
||||||
|
ComPtr<ID3D12CommandQueue> mCommandQueue = {};
|
||||||
|
ComPtr<IDXGISwapChain3> mSwapChain = {};
|
||||||
|
ComPtr<ID3D12Resource> mRenderTargetResources[kFrameCount] = {};
|
||||||
|
|
||||||
|
// Frame synchronization. Updated every frame
|
||||||
|
uint32_t mRenderTargetIndex = 0;
|
||||||
|
uint32_t mPreviousRenderTargetIndex = 0;
|
||||||
|
uint64_t mLastSerialRenderTargetWasUsed[kFrameCount] = {};
|
||||||
|
|
||||||
|
D3D12_RESOURCE_STATES mRenderTargetResourceState;
|
||||||
|
|
||||||
|
SwapChainImplD3D12(HWND window, nxtProcTable procs)
|
||||||
|
: mWindow(window), mProcs(procs), mFactory(CreateFactory()) {
|
||||||
|
}
|
||||||
|
|
||||||
|
~SwapChainImplD3D12() {
|
||||||
|
}
|
||||||
|
|
||||||
|
// For GenerateSwapChainImplementation
|
||||||
|
friend class SwapChainImpl;
|
||||||
|
|
||||||
|
void Init(nxtWSIContextD3D12* ctx) {
|
||||||
|
mBackendDevice = ctx->device;
|
||||||
|
mCommandQueue = backend::d3d12::GetCommandQueue(mBackendDevice);
|
||||||
|
}
|
||||||
|
|
||||||
|
nxtSwapChainError Configure(nxtTextureFormat format,
|
||||||
|
nxtTextureUsageBit allowedUsage,
|
||||||
|
uint32_t width,
|
||||||
|
uint32_t height) {
|
||||||
|
if (format != NXT_TEXTURE_FORMAT_R8_G8_B8_A8_UNORM) {
|
||||||
|
return "unsupported format";
|
||||||
|
}
|
||||||
|
ASSERT(width > 0);
|
||||||
|
ASSERT(height > 0);
|
||||||
|
|
||||||
|
DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {};
|
||||||
|
swapChainDesc.Width = width;
|
||||||
|
swapChainDesc.Height = height;
|
||||||
|
swapChainDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||||
|
swapChainDesc.BufferUsage = D3D12SwapChainBufferUsage(allowedUsage);
|
||||||
|
swapChainDesc.BufferCount = kFrameCount;
|
||||||
|
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
|
||||||
|
swapChainDesc.SampleDesc.Count = 1;
|
||||||
|
swapChainDesc.SampleDesc.Quality = 0;
|
||||||
|
|
||||||
|
ComPtr<IDXGISwapChain1> swapChain1;
|
||||||
|
ASSERT_SUCCESS(mFactory->CreateSwapChainForHwnd(
|
||||||
|
mCommandQueue.Get(), mWindow, &swapChainDesc, nullptr, nullptr, &swapChain1));
|
||||||
|
ASSERT_SUCCESS(swapChain1.As(&mSwapChain));
|
||||||
|
|
||||||
|
for (uint32_t n = 0; n < kFrameCount; ++n) {
|
||||||
|
ASSERT_SUCCESS(mSwapChain->GetBuffer(n, IID_PPV_ARGS(&mRenderTargetResources[n])));
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
// Get the initial render target and arbitrarily choose a "previous" render target
|
||||||
nxtDevice mBackendDevice = nullptr;
|
// that's different
|
||||||
nxtProcTable mProcs = {};
|
mPreviousRenderTargetIndex = mRenderTargetIndex =
|
||||||
|
mSwapChain->GetCurrentBackBufferIndex();
|
||||||
|
mPreviousRenderTargetIndex = mRenderTargetIndex == 0 ? 1 : 0;
|
||||||
|
|
||||||
static constexpr unsigned int kFrameCount = 2;
|
// Initial the serial for all render targets
|
||||||
|
const uint64_t initialSerial = backend::d3d12::GetSerial(mBackendDevice);
|
||||||
HWND mWindow = 0;
|
for (uint32_t n = 0; n < kFrameCount; ++n) {
|
||||||
ComPtr<IDXGIFactory4> mFactory = {};
|
mLastSerialRenderTargetWasUsed[n] = initialSerial;
|
||||||
ComPtr<ID3D12CommandQueue> mCommandQueue = {};
|
|
||||||
ComPtr<IDXGISwapChain3> mSwapChain = {};
|
|
||||||
ComPtr<ID3D12Resource> mRenderTargetResources[kFrameCount] = {};
|
|
||||||
|
|
||||||
// Frame synchronization. Updated every frame
|
|
||||||
uint32_t mRenderTargetIndex = 0;
|
|
||||||
uint32_t mPreviousRenderTargetIndex = 0;
|
|
||||||
uint64_t mLastSerialRenderTargetWasUsed[kFrameCount] = {};
|
|
||||||
|
|
||||||
D3D12_RESOURCE_STATES mRenderTargetResourceState;
|
|
||||||
|
|
||||||
SwapChainImplD3D12(HWND window, nxtProcTable procs)
|
|
||||||
: mWindow(window), mProcs(procs), mFactory(CreateFactory()) {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
~SwapChainImplD3D12() {
|
return NXT_SWAP_CHAIN_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
nxtSwapChainError GetNextTexture(nxtSwapChainNextTexture* nextTexture) {
|
||||||
|
nextTexture->texture = mRenderTargetResources[mRenderTargetIndex].Get();
|
||||||
|
return NXT_SWAP_CHAIN_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
nxtSwapChainError Present() {
|
||||||
|
// Current frame already transitioned to Present by the application, but
|
||||||
|
// we need to flush the D3D12 backend's pending transitions.
|
||||||
|
mProcs.deviceTick(mBackendDevice);
|
||||||
|
|
||||||
|
ASSERT_SUCCESS(mSwapChain->Present(1, 0));
|
||||||
|
|
||||||
|
// Transition last frame's render target back to being a render target
|
||||||
|
if (mRenderTargetResourceState != D3D12_RESOURCE_STATE_PRESENT) {
|
||||||
|
ComPtr<ID3D12GraphicsCommandList> commandList = {};
|
||||||
|
backend::d3d12::OpenCommandList(mBackendDevice, &commandList);
|
||||||
|
|
||||||
|
D3D12_RESOURCE_BARRIER resourceBarrier;
|
||||||
|
resourceBarrier.Transition.pResource =
|
||||||
|
mRenderTargetResources[mPreviousRenderTargetIndex].Get();
|
||||||
|
resourceBarrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT;
|
||||||
|
resourceBarrier.Transition.StateAfter = mRenderTargetResourceState;
|
||||||
|
resourceBarrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
||||||
|
resourceBarrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
||||||
|
resourceBarrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
||||||
|
commandList->ResourceBarrier(1, &resourceBarrier);
|
||||||
|
ASSERT_SUCCESS(commandList->Close());
|
||||||
|
backend::d3d12::ExecuteCommandLists(mBackendDevice, {commandList.Get()});
|
||||||
}
|
}
|
||||||
|
|
||||||
// For GenerateSwapChainImplementation
|
backend::d3d12::NextSerial(mBackendDevice);
|
||||||
friend class SwapChainImpl;
|
|
||||||
|
|
||||||
void Init(nxtWSIContextD3D12* ctx) {
|
mPreviousRenderTargetIndex = mRenderTargetIndex;
|
||||||
mBackendDevice = ctx->device;
|
mRenderTargetIndex = mSwapChain->GetCurrentBackBufferIndex();
|
||||||
mCommandQueue = backend::d3d12::GetCommandQueue(mBackendDevice);
|
|
||||||
}
|
|
||||||
|
|
||||||
nxtSwapChainError Configure(nxtTextureFormat format, nxtTextureUsageBit allowedUsage,
|
// If the next render target is not ready to be rendered yet, wait until it is ready.
|
||||||
uint32_t width, uint32_t height) {
|
// If the last completed serial is less than the last requested serial for this render
|
||||||
if (format != NXT_TEXTURE_FORMAT_R8_G8_B8_A8_UNORM) {
|
// target, then the commands previously executed on this render target have not yet
|
||||||
return "unsupported format";
|
// completed
|
||||||
}
|
backend::d3d12::WaitForSerial(mBackendDevice,
|
||||||
ASSERT(width > 0);
|
mLastSerialRenderTargetWasUsed[mRenderTargetIndex]);
|
||||||
ASSERT(height > 0);
|
|
||||||
|
|
||||||
DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {};
|
mLastSerialRenderTargetWasUsed[mRenderTargetIndex] =
|
||||||
swapChainDesc.Width = width;
|
backend::d3d12::GetSerial(mBackendDevice);
|
||||||
swapChainDesc.Height = height;
|
|
||||||
swapChainDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
|
||||||
swapChainDesc.BufferUsage = D3D12SwapChainBufferUsage(allowedUsage);
|
|
||||||
swapChainDesc.BufferCount = kFrameCount;
|
|
||||||
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
|
|
||||||
swapChainDesc.SampleDesc.Count = 1;
|
|
||||||
swapChainDesc.SampleDesc.Quality = 0;
|
|
||||||
|
|
||||||
ComPtr<IDXGISwapChain1> swapChain1;
|
return NXT_SWAP_CHAIN_NO_ERROR;
|
||||||
ASSERT_SUCCESS(mFactory->CreateSwapChainForHwnd(
|
}
|
||||||
mCommandQueue.Get(),
|
|
||||||
mWindow,
|
|
||||||
&swapChainDesc,
|
|
||||||
nullptr,
|
|
||||||
nullptr,
|
|
||||||
&swapChain1
|
|
||||||
));
|
|
||||||
ASSERT_SUCCESS(swapChain1.As(&mSwapChain));
|
|
||||||
|
|
||||||
for (uint32_t n = 0; n < kFrameCount; ++n) {
|
|
||||||
ASSERT_SUCCESS(mSwapChain->GetBuffer(n, IID_PPV_ARGS(&mRenderTargetResources[n])));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the initial render target and arbitrarily choose a "previous" render target that's different
|
|
||||||
mPreviousRenderTargetIndex = mRenderTargetIndex = mSwapChain->GetCurrentBackBufferIndex();
|
|
||||||
mPreviousRenderTargetIndex = mRenderTargetIndex == 0 ? 1 : 0;
|
|
||||||
|
|
||||||
// Initial the serial for all render targets
|
|
||||||
const uint64_t initialSerial = backend::d3d12::GetSerial(mBackendDevice);
|
|
||||||
for (uint32_t n = 0; n < kFrameCount; ++n) {
|
|
||||||
mLastSerialRenderTargetWasUsed[n] = initialSerial;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NXT_SWAP_CHAIN_NO_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
nxtSwapChainError GetNextTexture(nxtSwapChainNextTexture* nextTexture) {
|
|
||||||
nextTexture->texture = mRenderTargetResources[mRenderTargetIndex].Get();
|
|
||||||
return NXT_SWAP_CHAIN_NO_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
nxtSwapChainError Present() {
|
|
||||||
// Current frame already transitioned to Present by the application, but
|
|
||||||
// we need to flush the D3D12 backend's pending transitions.
|
|
||||||
mProcs.deviceTick(mBackendDevice);
|
|
||||||
|
|
||||||
ASSERT_SUCCESS(mSwapChain->Present(1, 0));
|
|
||||||
|
|
||||||
// Transition last frame's render target back to being a render target
|
|
||||||
if (mRenderTargetResourceState != D3D12_RESOURCE_STATE_PRESENT) {
|
|
||||||
ComPtr<ID3D12GraphicsCommandList> commandList = {};
|
|
||||||
backend::d3d12::OpenCommandList(mBackendDevice, &commandList);
|
|
||||||
|
|
||||||
D3D12_RESOURCE_BARRIER resourceBarrier;
|
|
||||||
resourceBarrier.Transition.pResource = mRenderTargetResources[mPreviousRenderTargetIndex].Get();
|
|
||||||
resourceBarrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT;
|
|
||||||
resourceBarrier.Transition.StateAfter = mRenderTargetResourceState;
|
|
||||||
resourceBarrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
|
||||||
resourceBarrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
|
||||||
resourceBarrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
|
||||||
commandList->ResourceBarrier(1, &resourceBarrier);
|
|
||||||
ASSERT_SUCCESS(commandList->Close());
|
|
||||||
backend::d3d12::ExecuteCommandLists(mBackendDevice, { commandList.Get() });
|
|
||||||
}
|
|
||||||
|
|
||||||
backend::d3d12::NextSerial(mBackendDevice);
|
|
||||||
|
|
||||||
mPreviousRenderTargetIndex = mRenderTargetIndex;
|
|
||||||
mRenderTargetIndex = mSwapChain->GetCurrentBackBufferIndex();
|
|
||||||
|
|
||||||
// If the next render target is not ready to be rendered yet, wait until it is ready.
|
|
||||||
// If the last completed serial is less than the last requested serial for this render target,
|
|
||||||
// then the commands previously executed on this render target have not yet completed
|
|
||||||
backend::d3d12::WaitForSerial(mBackendDevice, mLastSerialRenderTargetWasUsed[mRenderTargetIndex]);
|
|
||||||
|
|
||||||
mLastSerialRenderTargetWasUsed[mRenderTargetIndex] = backend::d3d12::GetSerial(mBackendDevice);
|
|
||||||
|
|
||||||
return NXT_SWAP_CHAIN_NO_ERROR;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class D3D12Binding : public BackendBinding {
|
class D3D12Binding : public BackendBinding {
|
||||||
public:
|
public:
|
||||||
void SetupGLFWWindowHints() override {
|
void SetupGLFWWindowHints() override {
|
||||||
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetProcAndDevice(nxtProcTable* procs, nxtDevice* device) override {
|
||||||
|
mFactory = CreateFactory();
|
||||||
|
ASSERT(GetHardwareAdapter(mFactory.Get(), &mHardwareAdapter));
|
||||||
|
ASSERT_SUCCESS(D3D12CreateDevice(mHardwareAdapter.Get(), D3D_FEATURE_LEVEL_11_0,
|
||||||
|
IID_PPV_ARGS(&mD3d12Device)));
|
||||||
|
|
||||||
|
backend::d3d12::Init(mD3d12Device, procs, device);
|
||||||
|
mBackendDevice = *device;
|
||||||
|
mProcTable = *procs;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t GetSwapChainImplementation() override {
|
||||||
|
if (mSwapchainImpl.userData == nullptr) {
|
||||||
|
HWND win32Window = glfwGetWin32Window(mWindow);
|
||||||
|
mSwapchainImpl = SwapChainImplD3D12::Create(win32Window, mProcTable);
|
||||||
}
|
}
|
||||||
|
return reinterpret_cast<uint64_t>(&mSwapchainImpl);
|
||||||
|
}
|
||||||
|
|
||||||
void GetProcAndDevice(nxtProcTable* procs, nxtDevice* device) override {
|
nxtTextureFormat GetPreferredSwapChainTextureFormat() override {
|
||||||
mFactory = CreateFactory();
|
return NXT_TEXTURE_FORMAT_R8_G8_B8_A8_UNORM;
|
||||||
ASSERT(GetHardwareAdapter(mFactory.Get(), &mHardwareAdapter));
|
}
|
||||||
ASSERT_SUCCESS(D3D12CreateDevice(
|
|
||||||
mHardwareAdapter.Get(),
|
|
||||||
D3D_FEATURE_LEVEL_11_0,
|
|
||||||
IID_PPV_ARGS(&mD3d12Device)
|
|
||||||
));
|
|
||||||
|
|
||||||
backend::d3d12::Init(mD3d12Device, procs, device);
|
private:
|
||||||
mBackendDevice = *device;
|
nxtDevice mBackendDevice = nullptr;
|
||||||
mProcTable = *procs;
|
nxtSwapChainImplementation mSwapchainImpl = {};
|
||||||
}
|
nxtProcTable mProcTable = {};
|
||||||
|
|
||||||
uint64_t GetSwapChainImplementation() override {
|
// Initialization
|
||||||
if (mSwapchainImpl.userData == nullptr) {
|
ComPtr<IDXGIFactory4> mFactory;
|
||||||
HWND win32Window = glfwGetWin32Window(mWindow);
|
ComPtr<IDXGIAdapter1> mHardwareAdapter;
|
||||||
mSwapchainImpl = SwapChainImplD3D12::Create(win32Window, mProcTable);
|
ComPtr<ID3D12Device> mD3d12Device;
|
||||||
|
|
||||||
|
static bool GetHardwareAdapter(IDXGIFactory4* factory, IDXGIAdapter1** hardwareAdapter) {
|
||||||
|
*hardwareAdapter = nullptr;
|
||||||
|
for (uint32_t adapterIndex = 0;; ++adapterIndex) {
|
||||||
|
IDXGIAdapter1* adapter = nullptr;
|
||||||
|
if (factory->EnumAdapters1(adapterIndex, &adapter) == DXGI_ERROR_NOT_FOUND) {
|
||||||
|
break; // No more adapters to enumerate.
|
||||||
}
|
}
|
||||||
return reinterpret_cast<uint64_t>(&mSwapchainImpl);
|
|
||||||
}
|
|
||||||
|
|
||||||
nxtTextureFormat GetPreferredSwapChainTextureFormat() override {
|
// Check to see if the adapter supports Direct3D 12, but don't create the actual
|
||||||
return NXT_TEXTURE_FORMAT_R8_G8_B8_A8_UNORM;
|
// device yet.
|
||||||
}
|
if (SUCCEEDED(D3D12CreateDevice(adapter, D3D_FEATURE_LEVEL_11_0,
|
||||||
|
_uuidof(ID3D12Device), nullptr))) {
|
||||||
private:
|
*hardwareAdapter = adapter;
|
||||||
nxtDevice mBackendDevice = nullptr;
|
return true;
|
||||||
nxtSwapChainImplementation mSwapchainImpl = {};
|
|
||||||
nxtProcTable mProcTable = {};
|
|
||||||
|
|
||||||
// Initialization
|
|
||||||
ComPtr<IDXGIFactory4> mFactory;
|
|
||||||
ComPtr<IDXGIAdapter1> mHardwareAdapter;
|
|
||||||
ComPtr<ID3D12Device> mD3d12Device;
|
|
||||||
|
|
||||||
static bool GetHardwareAdapter(IDXGIFactory4* factory, IDXGIAdapter1** hardwareAdapter) {
|
|
||||||
*hardwareAdapter = nullptr;
|
|
||||||
for (uint32_t adapterIndex = 0; ; ++adapterIndex) {
|
|
||||||
IDXGIAdapter1* adapter = nullptr;
|
|
||||||
if (factory->EnumAdapters1(adapterIndex, &adapter) == DXGI_ERROR_NOT_FOUND) {
|
|
||||||
break; // No more adapters to enumerate.
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check to see if the adapter supports Direct3D 12, but don't create the actual device yet.
|
|
||||||
if (SUCCEEDED(D3D12CreateDevice(adapter, D3D_FEATURE_LEVEL_11_0, _uuidof(ID3D12Device), nullptr))) {
|
|
||||||
*hardwareAdapter = adapter;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
adapter->Release();
|
|
||||||
}
|
}
|
||||||
return false;
|
adapter->Release();
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
BackendBinding* CreateD3D12Binding() {
|
BackendBinding* CreateD3D12Binding() {
|
||||||
return new D3D12Binding;
|
return new D3D12Binding;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} // namespace utils
|
||||||
|
@ -22,132 +22,130 @@
|
|||||||
#include "GLFW/glfw3.h"
|
#include "GLFW/glfw3.h"
|
||||||
#include "GLFW/glfw3native.h"
|
#include "GLFW/glfw3native.h"
|
||||||
|
|
||||||
#import <QuartzCore/CAMetalLayer.h>
|
|
||||||
#import <Metal/Metal.h>
|
#import <Metal/Metal.h>
|
||||||
|
#import <QuartzCore/CAMetalLayer.h>
|
||||||
|
|
||||||
namespace backend {
|
namespace backend { namespace metal {
|
||||||
namespace metal {
|
|
||||||
void Init(id<MTLDevice> metalDevice, nxtProcTable* procs, nxtDevice* device);
|
void Init(id<MTLDevice> metalDevice, nxtProcTable* procs, nxtDevice* device);
|
||||||
void SetNextDrawable(nxtDevice device, id<CAMetalDrawable> drawable);
|
void SetNextDrawable(nxtDevice device, id<CAMetalDrawable> drawable);
|
||||||
void Present(nxtDevice device);
|
void Present(nxtDevice device);
|
||||||
}
|
}}
|
||||||
}
|
|
||||||
|
|
||||||
namespace utils {
|
namespace utils {
|
||||||
class SwapChainImplMTL : SwapChainImpl {
|
class SwapChainImplMTL : SwapChainImpl {
|
||||||
public:
|
public:
|
||||||
static nxtSwapChainImplementation Create(id nswindow) {
|
static nxtSwapChainImplementation Create(id nswindow) {
|
||||||
auto impl = GenerateSwapChainImplementation<SwapChainImplMTL, nxtWSIContextMetal>();
|
auto impl = GenerateSwapChainImplementation<SwapChainImplMTL, nxtWSIContextMetal>();
|
||||||
impl.userData = new SwapChainImplMTL(nswindow);
|
impl.userData = new SwapChainImplMTL(nswindow);
|
||||||
return impl;
|
return impl;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
id mNsWindow = nil;
|
||||||
|
id<MTLDevice> mMtlDevice = nil;
|
||||||
|
id<MTLCommandQueue> mCommandQueue = nil;
|
||||||
|
|
||||||
|
CAMetalLayer* mLayer = nullptr;
|
||||||
|
id<CAMetalDrawable> mCurrentDrawable = nil;
|
||||||
|
id<MTLTexture> mCurrentTexture = nil;
|
||||||
|
|
||||||
|
SwapChainImplMTL(id nsWindow) : mNsWindow(nsWindow) {
|
||||||
|
}
|
||||||
|
|
||||||
|
~SwapChainImplMTL() {
|
||||||
|
[mCurrentTexture release];
|
||||||
|
[mCurrentDrawable release];
|
||||||
|
}
|
||||||
|
|
||||||
|
// For GenerateSwapChainImplementation
|
||||||
|
friend class SwapChainImpl;
|
||||||
|
|
||||||
|
void Init(nxtWSIContextMetal* ctx) {
|
||||||
|
mMtlDevice = ctx->device;
|
||||||
|
mCommandQueue = [mMtlDevice newCommandQueue];
|
||||||
|
}
|
||||||
|
|
||||||
|
nxtSwapChainError Configure(nxtTextureFormat format,
|
||||||
|
nxtTextureUsageBit,
|
||||||
|
uint32_t width,
|
||||||
|
uint32_t height) {
|
||||||
|
if (format != NXT_TEXTURE_FORMAT_B8_G8_R8_A8_UNORM) {
|
||||||
|
return "unsupported format";
|
||||||
}
|
}
|
||||||
|
ASSERT(width > 0);
|
||||||
|
ASSERT(height > 0);
|
||||||
|
|
||||||
private:
|
NSView* contentView = [mNsWindow contentView];
|
||||||
id mNsWindow = nil;
|
[contentView setWantsLayer:YES];
|
||||||
id<MTLDevice> mMtlDevice = nil;
|
|
||||||
id<MTLCommandQueue> mCommandQueue = nil;
|
|
||||||
|
|
||||||
CAMetalLayer* mLayer = nullptr;
|
CGSize size = {};
|
||||||
id<CAMetalDrawable> mCurrentDrawable = nil;
|
size.width = width;
|
||||||
id<MTLTexture> mCurrentTexture = nil;
|
size.height = height;
|
||||||
|
|
||||||
SwapChainImplMTL(id nsWindow)
|
mLayer = [CAMetalLayer layer];
|
||||||
: mNsWindow(nsWindow) {
|
[mLayer setDevice:mMtlDevice];
|
||||||
}
|
[mLayer setPixelFormat:MTLPixelFormatBGRA8Unorm];
|
||||||
|
[mLayer setFramebufferOnly:YES];
|
||||||
|
[mLayer setDrawableSize:size];
|
||||||
|
|
||||||
~SwapChainImplMTL() {
|
[contentView setLayer:mLayer];
|
||||||
[mCurrentTexture release];
|
|
||||||
[mCurrentDrawable release];
|
|
||||||
}
|
|
||||||
|
|
||||||
// For GenerateSwapChainImplementation
|
return NXT_SWAP_CHAIN_NO_ERROR;
|
||||||
friend class SwapChainImpl;
|
}
|
||||||
|
|
||||||
void Init(nxtWSIContextMetal* ctx) {
|
nxtSwapChainError GetNextTexture(nxtSwapChainNextTexture* nextTexture) {
|
||||||
mMtlDevice = ctx->device;
|
[mCurrentDrawable release];
|
||||||
mCommandQueue = [mMtlDevice newCommandQueue];
|
mCurrentDrawable = [mLayer nextDrawable];
|
||||||
}
|
[mCurrentDrawable retain];
|
||||||
|
|
||||||
nxtSwapChainError Configure(nxtTextureFormat format, nxtTextureUsageBit,
|
[mCurrentTexture release];
|
||||||
uint32_t width, uint32_t height) {
|
mCurrentTexture = mCurrentDrawable.texture;
|
||||||
if (format != NXT_TEXTURE_FORMAT_B8_G8_R8_A8_UNORM) {
|
[mCurrentTexture retain];
|
||||||
return "unsupported format";
|
|
||||||
}
|
|
||||||
ASSERT(width > 0);
|
|
||||||
ASSERT(height > 0);
|
|
||||||
|
|
||||||
NSView* contentView = [mNsWindow contentView];
|
nextTexture->texture = reinterpret_cast<void*>(mCurrentTexture);
|
||||||
[contentView setWantsLayer: YES];
|
|
||||||
|
|
||||||
CGSize size = {};
|
return NXT_SWAP_CHAIN_NO_ERROR;
|
||||||
size.width = width;
|
}
|
||||||
size.height = height;
|
|
||||||
|
|
||||||
mLayer = [CAMetalLayer layer];
|
nxtSwapChainError Present() {
|
||||||
[mLayer setDevice: mMtlDevice];
|
id<MTLCommandBuffer> commandBuffer = [mCommandQueue commandBuffer];
|
||||||
[mLayer setPixelFormat: MTLPixelFormatBGRA8Unorm];
|
[commandBuffer presentDrawable:mCurrentDrawable];
|
||||||
[mLayer setFramebufferOnly: YES];
|
[commandBuffer commit];
|
||||||
[mLayer setDrawableSize: size];
|
|
||||||
|
|
||||||
[contentView setLayer: mLayer];
|
return NXT_SWAP_CHAIN_NO_ERROR;
|
||||||
|
}
|
||||||
return NXT_SWAP_CHAIN_NO_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
nxtSwapChainError GetNextTexture(nxtSwapChainNextTexture* nextTexture) {
|
|
||||||
[mCurrentDrawable release];
|
|
||||||
mCurrentDrawable = [mLayer nextDrawable];
|
|
||||||
[mCurrentDrawable retain];
|
|
||||||
|
|
||||||
[mCurrentTexture release];
|
|
||||||
mCurrentTexture = mCurrentDrawable.texture;
|
|
||||||
[mCurrentTexture retain];
|
|
||||||
|
|
||||||
nextTexture->texture = reinterpret_cast<void*>(mCurrentTexture);
|
|
||||||
|
|
||||||
return NXT_SWAP_CHAIN_NO_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
nxtSwapChainError Present() {
|
|
||||||
id<MTLCommandBuffer> commandBuffer = [mCommandQueue commandBuffer];
|
|
||||||
[commandBuffer presentDrawable: mCurrentDrawable];
|
|
||||||
[commandBuffer commit];
|
|
||||||
|
|
||||||
return NXT_SWAP_CHAIN_NO_ERROR;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class MetalBinding : public BackendBinding {
|
class MetalBinding : public BackendBinding {
|
||||||
public:
|
public:
|
||||||
void SetupGLFWWindowHints() override {
|
void SetupGLFWWindowHints() override {
|
||||||
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
||||||
}
|
}
|
||||||
void GetProcAndDevice(nxtProcTable* procs, nxtDevice* device) override {
|
void GetProcAndDevice(nxtProcTable* procs, nxtDevice* device) override {
|
||||||
mMetalDevice = MTLCreateSystemDefaultDevice();
|
mMetalDevice = MTLCreateSystemDefaultDevice();
|
||||||
|
|
||||||
backend::metal::Init(mMetalDevice, procs, device);
|
backend::metal::Init(mMetalDevice, procs, device);
|
||||||
mBackendDevice = *device;
|
mBackendDevice = *device;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t GetSwapChainImplementation() override {
|
uint64_t GetSwapChainImplementation() override {
|
||||||
if (mSwapchainImpl.userData == nullptr) {
|
if (mSwapchainImpl.userData == nullptr) {
|
||||||
mSwapchainImpl = SwapChainImplMTL::Create(glfwGetCocoaWindow(mWindow));
|
mSwapchainImpl = SwapChainImplMTL::Create(glfwGetCocoaWindow(mWindow));
|
||||||
}
|
|
||||||
return reinterpret_cast<uint64_t>(&mSwapchainImpl);
|
|
||||||
}
|
}
|
||||||
|
return reinterpret_cast<uint64_t>(&mSwapchainImpl);
|
||||||
|
}
|
||||||
|
|
||||||
nxtTextureFormat GetPreferredSwapChainTextureFormat() override {
|
nxtTextureFormat GetPreferredSwapChainTextureFormat() override {
|
||||||
return NXT_TEXTURE_FORMAT_B8_G8_R8_A8_UNORM;
|
return NXT_TEXTURE_FORMAT_B8_G8_R8_A8_UNORM;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
id<MTLDevice> mMetalDevice = nil;
|
id<MTLDevice> mMetalDevice = nil;
|
||||||
nxtDevice mBackendDevice = nullptr;
|
nxtDevice mBackendDevice = nullptr;
|
||||||
nxtSwapChainImplementation mSwapchainImpl = {};
|
nxtSwapChainImplementation mSwapchainImpl = {};
|
||||||
};
|
};
|
||||||
|
|
||||||
BackendBinding* CreateMetalBinding() {
|
BackendBinding* CreateMetalBinding() {
|
||||||
return new MetalBinding;
|
return new MetalBinding;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,9 @@
|
|||||||
|
|
||||||
namespace utils {
|
namespace utils {
|
||||||
|
|
||||||
void FillShaderModuleBuilder(const nxt::ShaderModuleBuilder& builder, nxt::ShaderStage stage, const char* source) {
|
void FillShaderModuleBuilder(const nxt::ShaderModuleBuilder& builder,
|
||||||
|
nxt::ShaderStage stage,
|
||||||
|
const char* source) {
|
||||||
shaderc::Compiler compiler;
|
shaderc::Compiler compiler;
|
||||||
shaderc::CompileOptions options;
|
shaderc::CompileOptions options;
|
||||||
|
|
||||||
@ -60,7 +62,8 @@ namespace utils {
|
|||||||
|
|
||||||
#ifdef DUMP_SPIRV_ASSEMBLY
|
#ifdef DUMP_SPIRV_ASSEMBLY
|
||||||
{
|
{
|
||||||
auto resultAsm = compiler.CompileGlslToSpvAssembly(source, strlen(source), kind, "myshader?", options);
|
auto resultAsm = compiler.CompileGlslToSpvAssembly(source, strlen(source), kind,
|
||||||
|
"myshader?", options);
|
||||||
size_t sizeAsm = (resultAsm.cend() - resultAsm.cbegin());
|
size_t sizeAsm = (resultAsm.cend() - resultAsm.cbegin());
|
||||||
|
|
||||||
char* buffer = reinterpret_cast<char*>(malloc(sizeAsm + 1));
|
char* buffer = reinterpret_cast<char*>(malloc(sizeAsm + 1));
|
||||||
@ -86,21 +89,26 @@ namespace utils {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
nxt::ShaderModule CreateShaderModule(const nxt::Device& device, nxt::ShaderStage stage, const char* source) {
|
nxt::ShaderModule CreateShaderModule(const nxt::Device& device,
|
||||||
|
nxt::ShaderStage stage,
|
||||||
|
const char* source) {
|
||||||
nxt::ShaderModuleBuilder builder = device.CreateShaderModuleBuilder();
|
nxt::ShaderModuleBuilder builder = device.CreateShaderModuleBuilder();
|
||||||
FillShaderModuleBuilder(builder, stage, source);
|
FillShaderModuleBuilder(builder, stage, source);
|
||||||
return builder.GetResult();
|
return builder.GetResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
nxt::Buffer CreateFrozenBufferFromData(const nxt::Device& device, const void* data, uint32_t size, nxt::BufferUsageBit usage) {
|
nxt::Buffer CreateFrozenBufferFromData(const nxt::Device& device,
|
||||||
|
const void* data,
|
||||||
|
uint32_t size,
|
||||||
|
nxt::BufferUsageBit usage) {
|
||||||
nxt::Buffer buffer = device.CreateBufferBuilder()
|
nxt::Buffer buffer = device.CreateBufferBuilder()
|
||||||
.SetAllowedUsage(nxt::BufferUsageBit::TransferDst | usage)
|
.SetAllowedUsage(nxt::BufferUsageBit::TransferDst | usage)
|
||||||
.SetInitialUsage(nxt::BufferUsageBit::TransferDst)
|
.SetInitialUsage(nxt::BufferUsageBit::TransferDst)
|
||||||
.SetSize(size)
|
.SetSize(size)
|
||||||
.GetResult();
|
.GetResult();
|
||||||
buffer.SetSubData(0, size / sizeof(uint32_t), reinterpret_cast<const uint32_t*>(data));
|
buffer.SetSubData(0, size / sizeof(uint32_t), reinterpret_cast<const uint32_t*>(data));
|
||||||
buffer.FreezeUsage(usage);
|
buffer.FreezeUsage(usage);
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} // namespace utils
|
||||||
|
@ -18,12 +18,23 @@
|
|||||||
|
|
||||||
namespace utils {
|
namespace utils {
|
||||||
|
|
||||||
void FillShaderModuleBuilder(const nxt::ShaderModuleBuilder& builder, nxt::ShaderStage stage, const char* source);
|
void FillShaderModuleBuilder(const nxt::ShaderModuleBuilder& builder,
|
||||||
nxt::ShaderModule CreateShaderModule(const nxt::Device& device, nxt::ShaderStage stage, const char* source);
|
nxt::ShaderStage stage,
|
||||||
nxt::Buffer CreateFrozenBufferFromData(const nxt::Device& device, const void* data, uint32_t size, nxt::BufferUsageBit usage);
|
const char* source);
|
||||||
|
nxt::ShaderModule CreateShaderModule(const nxt::Device& device,
|
||||||
|
nxt::ShaderStage stage,
|
||||||
|
const char* source);
|
||||||
|
nxt::Buffer CreateFrozenBufferFromData(const nxt::Device& device,
|
||||||
|
const void* data,
|
||||||
|
uint32_t size,
|
||||||
|
nxt::BufferUsageBit usage);
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
nxt::Buffer CreateFrozenBufferFromData(const nxt::Device& device, nxt::BufferUsageBit usage, std::initializer_list<T> data) {
|
nxt::Buffer CreateFrozenBufferFromData(const nxt::Device& device,
|
||||||
return CreateFrozenBufferFromData(device, data.begin(), uint32_t(sizeof(T) * data.size()), usage);
|
nxt::BufferUsageBit usage,
|
||||||
|
std::initializer_list<T> data) {
|
||||||
|
return CreateFrozenBufferFromData(device, data.begin(), uint32_t(sizeof(T) * data.size()),
|
||||||
|
usage);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
} // namespace utils
|
||||||
|
@ -14,32 +14,29 @@
|
|||||||
|
|
||||||
#include "utils/BackendBinding.h"
|
#include "utils/BackendBinding.h"
|
||||||
|
|
||||||
namespace backend {
|
namespace backend { namespace null {
|
||||||
namespace null {
|
void Init(nxtProcTable* procs, nxtDevice* device);
|
||||||
void Init(nxtProcTable* procs, nxtDevice* device);
|
}} // namespace backend::null
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace utils {
|
namespace utils {
|
||||||
|
|
||||||
class NullBinding : public BackendBinding {
|
class NullBinding : public BackendBinding {
|
||||||
public:
|
public:
|
||||||
void SetupGLFWWindowHints() override {
|
void SetupGLFWWindowHints() override {
|
||||||
}
|
}
|
||||||
void GetProcAndDevice(nxtProcTable* procs, nxtDevice* device) override {
|
void GetProcAndDevice(nxtProcTable* procs, nxtDevice* device) override {
|
||||||
backend::null::Init(procs, device);
|
backend::null::Init(procs, device);
|
||||||
}
|
}
|
||||||
uint64_t GetSwapChainImplementation() override {
|
uint64_t GetSwapChainImplementation() override {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
nxtTextureFormat GetPreferredSwapChainTextureFormat() override {
|
nxtTextureFormat GetPreferredSwapChainTextureFormat() override {
|
||||||
return NXT_TEXTURE_FORMAT_R8_G8_B8_A8_UNORM;
|
return NXT_TEXTURE_FORMAT_R8_G8_B8_A8_UNORM;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
BackendBinding* CreateNullBinding() {
|
BackendBinding* CreateNullBinding() {
|
||||||
return new NullBinding;
|
return new NullBinding;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} // namespace utils
|
||||||
|
@ -19,130 +19,131 @@
|
|||||||
#include "nxt/nxt_wsi.h"
|
#include "nxt/nxt_wsi.h"
|
||||||
#include "utils/SwapChainImpl.h"
|
#include "utils/SwapChainImpl.h"
|
||||||
|
|
||||||
#include <cstdio>
|
// Glad needs to be included before GLFW otherwise it complain that GL.h was already included
|
||||||
#include "glad/glad.h"
|
#include "glad/glad.h"
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
#include "GLFW/glfw3.h"
|
#include "GLFW/glfw3.h"
|
||||||
|
|
||||||
namespace backend {
|
namespace backend { namespace opengl {
|
||||||
namespace opengl {
|
void Init(void* (*getProc)(const char*), nxtProcTable* procs, nxtDevice* device);
|
||||||
void Init(void* (*getProc)(const char*), nxtProcTable* procs, nxtDevice* device);
|
}} // namespace backend::opengl
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace utils {
|
namespace utils {
|
||||||
class SwapChainImplGL : SwapChainImpl {
|
class SwapChainImplGL : SwapChainImpl {
|
||||||
public:
|
public:
|
||||||
static nxtSwapChainImplementation Create(GLFWwindow* window) {
|
static nxtSwapChainImplementation Create(GLFWwindow* window) {
|
||||||
auto impl = GenerateSwapChainImplementation<SwapChainImplGL, nxtWSIContextGL>();
|
auto impl = GenerateSwapChainImplementation<SwapChainImplGL, nxtWSIContextGL>();
|
||||||
impl.userData = new SwapChainImplGL(window);
|
impl.userData = new SwapChainImplGL(window);
|
||||||
return impl;
|
return impl;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
GLFWwindow* mWindow = nullptr;
|
||||||
|
uint32_t mWidth = 0;
|
||||||
|
uint32_t mHeight = 0;
|
||||||
|
GLuint mBackFBO = 0;
|
||||||
|
GLuint mBackTexture = 0;
|
||||||
|
|
||||||
|
SwapChainImplGL(GLFWwindow* window) : mWindow(window) {
|
||||||
|
}
|
||||||
|
|
||||||
|
~SwapChainImplGL() {
|
||||||
|
glDeleteTextures(1, &mBackTexture);
|
||||||
|
glDeleteFramebuffers(1, &mBackFBO);
|
||||||
|
}
|
||||||
|
|
||||||
|
// For GenerateSwapChainImplementation
|
||||||
|
friend class SwapChainImpl;
|
||||||
|
|
||||||
|
void Init(nxtWSIContextGL*) {
|
||||||
|
glGenTextures(1, &mBackTexture);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, mBackTexture);
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 0, 0, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
|
||||||
|
|
||||||
|
glGenFramebuffers(1, &mBackFBO);
|
||||||
|
glBindFramebuffer(GL_READ_FRAMEBUFFER, mBackFBO);
|
||||||
|
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
|
||||||
|
mBackTexture, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
nxtSwapChainError Configure(nxtTextureFormat format,
|
||||||
|
nxtTextureUsageBit,
|
||||||
|
uint32_t width,
|
||||||
|
uint32_t height) {
|
||||||
|
if (format != NXT_TEXTURE_FORMAT_R8_G8_B8_A8_UNORM) {
|
||||||
|
return "unsupported format";
|
||||||
}
|
}
|
||||||
|
ASSERT(width > 0);
|
||||||
|
ASSERT(height > 0);
|
||||||
|
mWidth = width;
|
||||||
|
mHeight = height;
|
||||||
|
|
||||||
private:
|
glBindTexture(GL_TEXTURE_2D, mBackTexture);
|
||||||
GLFWwindow* mWindow = nullptr;
|
// Reallocate the texture
|
||||||
uint32_t mWidth = 0;
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE,
|
||||||
uint32_t mHeight = 0;
|
nullptr);
|
||||||
GLuint mBackFBO = 0;
|
|
||||||
GLuint mBackTexture = 0;
|
|
||||||
|
|
||||||
SwapChainImplGL(GLFWwindow* window)
|
return NXT_SWAP_CHAIN_NO_ERROR;
|
||||||
: mWindow(window) {
|
}
|
||||||
}
|
|
||||||
|
|
||||||
~SwapChainImplGL() {
|
nxtSwapChainError GetNextTexture(nxtSwapChainNextTexture* nextTexture) {
|
||||||
glDeleteTextures(1, &mBackTexture);
|
nextTexture->texture = reinterpret_cast<void*>(static_cast<size_t>(mBackTexture));
|
||||||
glDeleteFramebuffers(1, &mBackFBO);
|
return NXT_SWAP_CHAIN_NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
// For GenerateSwapChainImplementation
|
nxtSwapChainError Present() {
|
||||||
friend class SwapChainImpl;
|
glBindFramebuffer(GL_READ_FRAMEBUFFER, mBackFBO);
|
||||||
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||||
|
glBlitFramebuffer(0, 0, mWidth, mHeight, 0, 0, mWidth, mHeight, GL_COLOR_BUFFER_BIT,
|
||||||
|
GL_NEAREST);
|
||||||
|
glfwSwapBuffers(mWindow);
|
||||||
|
|
||||||
void Init(nxtWSIContextGL*) {
|
return NXT_SWAP_CHAIN_NO_ERROR;
|
||||||
glGenTextures(1, &mBackTexture);
|
}
|
||||||
glBindTexture(GL_TEXTURE_2D, mBackTexture);
|
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 0, 0, 0,
|
|
||||||
GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
|
|
||||||
|
|
||||||
glGenFramebuffers(1, &mBackFBO);
|
|
||||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, mBackFBO);
|
|
||||||
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
|
||||||
GL_TEXTURE_2D, mBackTexture, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
nxtSwapChainError Configure(nxtTextureFormat format, nxtTextureUsageBit,
|
|
||||||
uint32_t width, uint32_t height) {
|
|
||||||
if (format != NXT_TEXTURE_FORMAT_R8_G8_B8_A8_UNORM) {
|
|
||||||
return "unsupported format";
|
|
||||||
}
|
|
||||||
ASSERT(width > 0);
|
|
||||||
ASSERT(height > 0);
|
|
||||||
mWidth = width;
|
|
||||||
mHeight = height;
|
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, mBackTexture);
|
|
||||||
// Reallocate the texture
|
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0,
|
|
||||||
GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
|
|
||||||
|
|
||||||
return NXT_SWAP_CHAIN_NO_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
nxtSwapChainError GetNextTexture(nxtSwapChainNextTexture* nextTexture) {
|
|
||||||
nextTexture->texture = reinterpret_cast<void*>(static_cast<size_t>(mBackTexture));
|
|
||||||
return NXT_SWAP_CHAIN_NO_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
nxtSwapChainError Present() {
|
|
||||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, mBackFBO);
|
|
||||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
|
||||||
glBlitFramebuffer(0, 0, mWidth, mHeight, 0, 0, mWidth, mHeight,
|
|
||||||
GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
|
||||||
glfwSwapBuffers(mWindow);
|
|
||||||
|
|
||||||
return NXT_SWAP_CHAIN_NO_ERROR;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class OpenGLBinding : public BackendBinding {
|
class OpenGLBinding : public BackendBinding {
|
||||||
public:
|
public:
|
||||||
void SetupGLFWWindowHints() override {
|
void SetupGLFWWindowHints() override {
|
||||||
#if defined(NXT_PLATFORM_APPLE)
|
#if defined(NXT_PLATFORM_APPLE)
|
||||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
|
||||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
|
||||||
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE);
|
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE);
|
||||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
||||||
#else
|
#else
|
||||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
|
||||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 4);
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 4);
|
||||||
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE);
|
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE);
|
||||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
void GetProcAndDevice(nxtProcTable* procs, nxtDevice* device) override {
|
void GetProcAndDevice(nxtProcTable* procs, nxtDevice* device) override {
|
||||||
glfwMakeContextCurrent(mWindow);
|
glfwMakeContextCurrent(mWindow);
|
||||||
backend::opengl::Init(reinterpret_cast<void*(*)(const char*)>(glfwGetProcAddress), procs, device);
|
backend::opengl::Init(reinterpret_cast<void* (*)(const char*)>(glfwGetProcAddress),
|
||||||
|
procs, device);
|
||||||
|
|
||||||
mBackendDevice = *device;
|
mBackendDevice = *device;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t GetSwapChainImplementation() override {
|
uint64_t GetSwapChainImplementation() override {
|
||||||
if (mSwapchainImpl.userData == nullptr) {
|
if (mSwapchainImpl.userData == nullptr) {
|
||||||
mSwapchainImpl = SwapChainImplGL::Create(mWindow);
|
mSwapchainImpl = SwapChainImplGL::Create(mWindow);
|
||||||
}
|
|
||||||
return reinterpret_cast<uint64_t>(&mSwapchainImpl);
|
|
||||||
}
|
}
|
||||||
|
return reinterpret_cast<uint64_t>(&mSwapchainImpl);
|
||||||
|
}
|
||||||
|
|
||||||
nxtTextureFormat GetPreferredSwapChainTextureFormat() override {
|
nxtTextureFormat GetPreferredSwapChainTextureFormat() override {
|
||||||
return NXT_TEXTURE_FORMAT_R8_G8_B8_A8_UNORM;
|
return NXT_TEXTURE_FORMAT_R8_G8_B8_A8_UNORM;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
nxtDevice mBackendDevice = nullptr;
|
nxtDevice mBackendDevice = nullptr;
|
||||||
nxtSwapChainImplementation mSwapchainImpl = {};
|
nxtSwapChainImplementation mSwapchainImpl = {};
|
||||||
};
|
};
|
||||||
|
|
||||||
BackendBinding* CreateOpenGLBinding() {
|
BackendBinding* CreateOpenGLBinding() {
|
||||||
return new OpenGLBinding;
|
return new OpenGLBinding;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} // namespace utils
|
||||||
|
@ -17,30 +17,29 @@
|
|||||||
|
|
||||||
namespace utils {
|
namespace utils {
|
||||||
class SwapChainImpl {
|
class SwapChainImpl {
|
||||||
protected:
|
protected:
|
||||||
template<class TImpl, typename TWSIContext>
|
template <class TImpl, typename TWSIContext>
|
||||||
static nxtSwapChainImplementation GenerateSwapChainImplementation() {
|
static nxtSwapChainImplementation GenerateSwapChainImplementation() {
|
||||||
nxtSwapChainImplementation impl = {};
|
nxtSwapChainImplementation impl = {};
|
||||||
impl.Init = [](void* userData, void* wsiContext) {
|
impl.Init = [](void* userData, void* wsiContext) {
|
||||||
auto* ctx = reinterpret_cast<TWSIContext*>(wsiContext);
|
auto* ctx = reinterpret_cast<TWSIContext*>(wsiContext);
|
||||||
reinterpret_cast<TImpl*>(userData)->Init(ctx);
|
reinterpret_cast<TImpl*>(userData)->Init(ctx);
|
||||||
};
|
};
|
||||||
impl.Destroy = [](void* userData) {
|
impl.Destroy = [](void* userData) { delete reinterpret_cast<TImpl*>(userData); };
|
||||||
delete reinterpret_cast<TImpl*>(userData);
|
impl.Configure = [](void* userData, nxtTextureFormat format,
|
||||||
};
|
nxtTextureUsageBit allowedUsage, uint32_t width, uint32_t height) {
|
||||||
impl.Configure = [](void* userData, nxtTextureFormat format, nxtTextureUsageBit allowedUsage, uint32_t width, uint32_t height) {
|
return reinterpret_cast<TImpl*>(userData)->Configure(format, allowedUsage, width,
|
||||||
return reinterpret_cast<TImpl*>(userData)->Configure(format, allowedUsage, width, height);
|
height);
|
||||||
};
|
};
|
||||||
impl.GetNextTexture = [](void* userData, nxtSwapChainNextTexture* nextTexture) {
|
impl.GetNextTexture = [](void* userData, nxtSwapChainNextTexture* nextTexture) {
|
||||||
return reinterpret_cast<TImpl*>(userData)->GetNextTexture(
|
return reinterpret_cast<TImpl*>(userData)->GetNextTexture(nextTexture);
|
||||||
nextTexture);
|
};
|
||||||
};
|
impl.Present = [](void* userData) {
|
||||||
impl.Present = [](void* userData) {
|
return reinterpret_cast<TImpl*>(userData)->Present();
|
||||||
return reinterpret_cast<TImpl*>(userData)->Present();
|
};
|
||||||
};
|
return impl;
|
||||||
return impl;
|
}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
} // namespace utils
|
||||||
|
|
||||||
#endif // UTILS_SWAPCHAINIMPL_H_
|
#endif // UTILS_SWAPCHAINIMPL_H_
|
||||||
|
@ -15,25 +15,25 @@
|
|||||||
#include "common/Platform.h"
|
#include "common/Platform.h"
|
||||||
|
|
||||||
#if defined(NXT_PLATFORM_WINDOWS)
|
#if defined(NXT_PLATFORM_WINDOWS)
|
||||||
#include <Windows.h>
|
# include <Windows.h>
|
||||||
#elif defined(NXT_PLATFORM_POSIX)
|
#elif defined(NXT_PLATFORM_POSIX)
|
||||||
#include <unistd.h>
|
# include <unistd.h>
|
||||||
#else
|
#else
|
||||||
#error "Unsupported platform."
|
# error "Unsupported platform."
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace utils {
|
namespace utils {
|
||||||
|
|
||||||
#if defined(NXT_PLATFORM_WINDOWS)
|
#if defined(NXT_PLATFORM_WINDOWS)
|
||||||
void USleep(unsigned int usecs) {
|
void USleep(unsigned int usecs) {
|
||||||
Sleep(static_cast<DWORD>(usecs / 1000));
|
Sleep(static_cast<DWORD>(usecs / 1000));
|
||||||
}
|
}
|
||||||
#elif defined(NXT_PLATFORM_POSIX)
|
#elif defined(NXT_PLATFORM_POSIX)
|
||||||
void USleep(unsigned int usecs) {
|
void USleep(unsigned int usecs) {
|
||||||
usleep(usecs);
|
usleep(usecs);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
#error "Implement USleep for your platform."
|
# error "Implement USleep for your platform."
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
} // namespace utils
|
||||||
|
@ -15,5 +15,4 @@
|
|||||||
namespace utils {
|
namespace utils {
|
||||||
|
|
||||||
void USleep(unsigned int usecs);
|
void USleep(unsigned int usecs);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -17,75 +17,71 @@
|
|||||||
#include "nxt/nxt_wsi.h"
|
#include "nxt/nxt_wsi.h"
|
||||||
#include "utils/SwapChainImpl.h"
|
#include "utils/SwapChainImpl.h"
|
||||||
|
|
||||||
namespace backend {
|
namespace backend { namespace vulkan {
|
||||||
namespace vulkan {
|
void Init(nxtProcTable* procs, nxtDevice* device);
|
||||||
void Init(nxtProcTable* procs, nxtDevice* device);
|
}} // namespace backend::vulkan
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace utils {
|
namespace utils {
|
||||||
|
|
||||||
class SwapChainImplVulkan : SwapChainImpl {
|
class SwapChainImplVulkan : SwapChainImpl {
|
||||||
public:
|
public:
|
||||||
static nxtSwapChainImplementation Create(GLFWwindow* window) {
|
static nxtSwapChainImplementation Create(GLFWwindow* window) {
|
||||||
auto impl = GenerateSwapChainImplementation<SwapChainImplVulkan, nxtWSIContextVulkan>();
|
auto impl = GenerateSwapChainImplementation<SwapChainImplVulkan, nxtWSIContextVulkan>();
|
||||||
impl.userData = new SwapChainImplVulkan(window);
|
impl.userData = new SwapChainImplVulkan(window);
|
||||||
return impl;
|
return impl;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
GLFWwindow* window = nullptr;
|
GLFWwindow* window = nullptr;
|
||||||
|
|
||||||
SwapChainImplVulkan(GLFWwindow* window)
|
SwapChainImplVulkan(GLFWwindow* window) : window(window) {
|
||||||
: window(window) {
|
}
|
||||||
}
|
|
||||||
|
|
||||||
~SwapChainImplVulkan() {
|
~SwapChainImplVulkan() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// For GenerateSwapChainImplementation
|
// For GenerateSwapChainImplementation
|
||||||
friend class SwapChainImpl;
|
friend class SwapChainImpl;
|
||||||
|
|
||||||
void Init(nxtWSIContextVulkan*) {
|
void Init(nxtWSIContextVulkan*) {
|
||||||
}
|
}
|
||||||
|
|
||||||
nxtSwapChainError Configure(nxtTextureFormat, nxtTextureUsageBit, uint32_t, uint32_t) {
|
nxtSwapChainError Configure(nxtTextureFormat, nxtTextureUsageBit, uint32_t, uint32_t) {
|
||||||
return NXT_SWAP_CHAIN_NO_ERROR;
|
return NXT_SWAP_CHAIN_NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
nxtSwapChainError GetNextTexture(nxtSwapChainNextTexture*) {
|
nxtSwapChainError GetNextTexture(nxtSwapChainNextTexture*) {
|
||||||
return NXT_SWAP_CHAIN_NO_ERROR;
|
return NXT_SWAP_CHAIN_NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
nxtSwapChainError Present() {
|
nxtSwapChainError Present() {
|
||||||
return NXT_SWAP_CHAIN_NO_ERROR;
|
return NXT_SWAP_CHAIN_NO_ERROR;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class VulkanBinding : public BackendBinding {
|
class VulkanBinding : public BackendBinding {
|
||||||
public:
|
public:
|
||||||
void SetupGLFWWindowHints() override {
|
void SetupGLFWWindowHints() override {
|
||||||
}
|
}
|
||||||
void GetProcAndDevice(nxtProcTable* procs, nxtDevice* device) override {
|
void GetProcAndDevice(nxtProcTable* procs, nxtDevice* device) override {
|
||||||
backend::vulkan::Init(procs, device);
|
backend::vulkan::Init(procs, device);
|
||||||
}
|
}
|
||||||
uint64_t GetSwapChainImplementation() override {
|
uint64_t GetSwapChainImplementation() override {
|
||||||
if (mSwapchainImpl.userData == nullptr) {
|
if (mSwapchainImpl.userData == nullptr) {
|
||||||
mSwapchainImpl = SwapChainImplVulkan::Create(mWindow);
|
mSwapchainImpl = SwapChainImplVulkan::Create(mWindow);
|
||||||
}
|
|
||||||
return reinterpret_cast<uint64_t>(&mSwapchainImpl);
|
|
||||||
}
|
|
||||||
nxtTextureFormat GetPreferredSwapChainTextureFormat() override {
|
|
||||||
return NXT_TEXTURE_FORMAT_R8_G8_B8_A8_UNORM;
|
|
||||||
}
|
}
|
||||||
|
return reinterpret_cast<uint64_t>(&mSwapchainImpl);
|
||||||
|
}
|
||||||
|
nxtTextureFormat GetPreferredSwapChainTextureFormat() override {
|
||||||
|
return NXT_TEXTURE_FORMAT_R8_G8_B8_A8_UNORM;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
nxtSwapChainImplementation mSwapchainImpl = {};
|
nxtSwapChainImplementation mSwapchainImpl = {};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
BackendBinding* CreateVulkanBinding() {
|
BackendBinding* CreateVulkanBinding() {
|
||||||
return new VulkanBinding;
|
return new VulkanBinding;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} // namespace utils
|
||||||
|
@ -14,8 +14,7 @@
|
|||||||
|
|
||||||
#include "wire/TerribleCommandBuffer.h"
|
#include "wire/TerribleCommandBuffer.h"
|
||||||
|
|
||||||
namespace nxt {
|
namespace nxt { namespace wire {
|
||||||
namespace wire {
|
|
||||||
|
|
||||||
TerribleCommandBuffer::TerribleCommandBuffer() {
|
TerribleCommandBuffer::TerribleCommandBuffer() {
|
||||||
}
|
}
|
||||||
@ -48,5 +47,4 @@ namespace wire {
|
|||||||
mOffset = 0;
|
mOffset = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}} // namespace nxt::wire
|
||||||
}
|
|
||||||
|
@ -19,11 +19,10 @@
|
|||||||
|
|
||||||
#include "wire/Wire.h"
|
#include "wire/Wire.h"
|
||||||
|
|
||||||
namespace nxt {
|
namespace nxt { namespace wire {
|
||||||
namespace wire {
|
|
||||||
|
|
||||||
class TerribleCommandBuffer : public CommandSerializer {
|
class TerribleCommandBuffer : public CommandSerializer {
|
||||||
public:
|
public:
|
||||||
TerribleCommandBuffer();
|
TerribleCommandBuffer();
|
||||||
TerribleCommandBuffer(CommandHandler* handler);
|
TerribleCommandBuffer(CommandHandler* handler);
|
||||||
|
|
||||||
@ -32,13 +31,12 @@ class TerribleCommandBuffer : public CommandSerializer {
|
|||||||
void* GetCmdSpace(size_t size) override;
|
void* GetCmdSpace(size_t size) override;
|
||||||
void Flush() override;
|
void Flush() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CommandHandler* mHandler = nullptr;
|
CommandHandler* mHandler = nullptr;
|
||||||
size_t mOffset = 0;
|
size_t mOffset = 0;
|
||||||
uint8_t mBuffer[10000000];
|
uint8_t mBuffer[10000000];
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}} // namespace nxt::wire
|
||||||
}
|
|
||||||
|
|
||||||
#endif // WIRE_TERRIBLE_COMMAND_BUFFER_H_
|
#endif // WIRE_TERRIBLE_COMMAND_BUFFER_H_
|
||||||
|
@ -19,26 +19,28 @@
|
|||||||
|
|
||||||
#include "nxt/nxt.h"
|
#include "nxt/nxt.h"
|
||||||
|
|
||||||
namespace nxt {
|
namespace nxt { namespace wire {
|
||||||
namespace wire {
|
|
||||||
|
|
||||||
class CommandSerializer {
|
class CommandSerializer {
|
||||||
public:
|
public:
|
||||||
virtual ~CommandSerializer() = default;
|
virtual ~CommandSerializer() = default;
|
||||||
virtual void* GetCmdSpace(size_t size) = 0;
|
virtual void* GetCmdSpace(size_t size) = 0;
|
||||||
virtual void Flush() = 0;
|
virtual void Flush() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CommandHandler {
|
class CommandHandler {
|
||||||
public:
|
public:
|
||||||
virtual ~CommandHandler() = default;
|
virtual ~CommandHandler() = default;
|
||||||
virtual const uint8_t* HandleCommands(const uint8_t* commands, size_t size) = 0;
|
virtual const uint8_t* HandleCommands(const uint8_t* commands, size_t size) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
CommandHandler* NewClientDevice(nxtProcTable* procs, nxtDevice* device, CommandSerializer* serializer);
|
CommandHandler* NewClientDevice(nxtProcTable* procs,
|
||||||
CommandHandler* NewServerCommandHandler(nxtDevice device, const nxtProcTable& procs, CommandSerializer* serializer);
|
nxtDevice* device,
|
||||||
|
CommandSerializer* serializer);
|
||||||
|
CommandHandler* NewServerCommandHandler(nxtDevice device,
|
||||||
|
const nxtProcTable& procs,
|
||||||
|
CommandSerializer* serializer);
|
||||||
|
|
||||||
}
|
}} // namespace nxt::wire
|
||||||
}
|
|
||||||
|
|
||||||
#endif // WIRE_WIRE_H_
|
#endif // WIRE_WIRE_H_
|
||||||
|
@ -14,8 +14,7 @@
|
|||||||
|
|
||||||
#include "wire/WireCmd.h"
|
#include "wire/WireCmd.h"
|
||||||
|
|
||||||
namespace nxt {
|
namespace nxt { namespace wire {
|
||||||
namespace wire {
|
|
||||||
|
|
||||||
size_t ReturnDeviceErrorCallbackCmd::GetRequiredSize() const {
|
size_t ReturnDeviceErrorCallbackCmd::GetRequiredSize() const {
|
||||||
return sizeof(*this) + messageStrlen + 1;
|
return sizeof(*this) + messageStrlen + 1;
|
||||||
@ -45,5 +44,4 @@ namespace wire {
|
|||||||
return this + 1;
|
return this + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}} // namespace nxt::wire
|
||||||
}
|
|
||||||
|
@ -17,8 +17,7 @@
|
|||||||
|
|
||||||
#include "wire/WireCmd_autogen.h"
|
#include "wire/WireCmd_autogen.h"
|
||||||
|
|
||||||
namespace nxt {
|
namespace nxt { namespace wire {
|
||||||
namespace wire {
|
|
||||||
|
|
||||||
struct ReturnDeviceErrorCallbackCmd {
|
struct ReturnDeviceErrorCallbackCmd {
|
||||||
wire::ReturnWireCmd commandId = ReturnWireCmd::DeviceErrorCallback;
|
wire::ReturnWireCmd commandId = ReturnWireCmd::DeviceErrorCallback;
|
||||||
@ -55,7 +54,6 @@ namespace wire {
|
|||||||
const void* GetData() const;
|
const void* GetData() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}} // namespace nxt::wire
|
||||||
}
|
|
||||||
|
|
||||||
#endif // WIRE_WIRECMD_H_
|
#endif // WIRE_WIRECMD_H_
|
||||||
|
Loading…
x
Reference in New Issue
Block a user