Format: src/{common, utils, wire}

This commit is contained in:
Corentin Wallez 2017-11-24 11:45:29 -05:00 committed by Corentin Wallez
parent a351ce9618
commit 9d01c6c26d
29 changed files with 897 additions and 876 deletions

View File

@ -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();
} }

View File

@ -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_

View File

@ -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>

View File

@ -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_

View File

@ -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_

View File

@ -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;
} }

View File

@ -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_

View File

@ -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) {

View File

@ -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_

View File

@ -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_

View File

@ -19,4 +19,4 @@
using Serial = uint64_t; using Serial = uint64_t;
#endif // COMMON_SERIAL_H_ #endif // COMMON_SERIAL_H_

View File

@ -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_

View File

@ -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

View File

@ -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_

View File

@ -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

View File

@ -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;
} }
} }

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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_

View File

@ -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

View File

@ -15,5 +15,4 @@
namespace utils { namespace utils {
void USleep(unsigned int usecs); void USleep(unsigned int usecs);
} }

View File

@ -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

View File

@ -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
}

View File

@ -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_

View File

@ -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_

View File

@ -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
}

View File

@ -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_