Format: src/backend

This commit is contained in:
Corentin Wallez 2017-11-24 13:59:42 -05:00 committed by Corentin Wallez
parent 9d01c6c26d
commit c1400f0d14
51 changed files with 1925 additions and 1760 deletions

View File

@ -26,7 +26,9 @@ namespace backend {
// BindGroup // BindGroup
BindGroupBase::BindGroupBase(BindGroupBuilder* builder) BindGroupBase::BindGroupBase(BindGroupBuilder* builder)
: mLayout(std::move(builder->mLayout)), mUsage(builder->mUsage), mBindings(std::move(builder->mBindings)) { : mLayout(std::move(builder->mLayout)),
mUsage(builder->mUsage),
mBindings(std::move(builder->mBindings)) {
} }
const BindGroupLayoutBase* BindGroupBase::GetLayout() const { const BindGroupLayoutBase* BindGroupBase::GetLayout() const {
@ -41,7 +43,7 @@ namespace backend {
ASSERT(binding < kMaxBindingsPerGroup); ASSERT(binding < kMaxBindingsPerGroup);
ASSERT(mLayout->GetBindingInfo().mask[binding]); ASSERT(mLayout->GetBindingInfo().mask[binding]);
ASSERT(mLayout->GetBindingInfo().types[binding] == nxt::BindingType::UniformBuffer || ASSERT(mLayout->GetBindingInfo().types[binding] == nxt::BindingType::UniformBuffer ||
mLayout->GetBindingInfo().types[binding] == nxt::BindingType::StorageBuffer); mLayout->GetBindingInfo().types[binding] == nxt::BindingType::StorageBuffer);
return reinterpret_cast<BufferViewBase*>(mBindings[binding].Get()); return reinterpret_cast<BufferViewBase*>(mBindings[binding].Get());
} }
@ -104,7 +106,9 @@ namespace backend {
mPropertiesSet |= BINDGROUP_PROPERTY_USAGE; mPropertiesSet |= BINDGROUP_PROPERTY_USAGE;
} }
void BindGroupBuilder::SetBufferViews(uint32_t start, uint32_t count, BufferViewBase* const * bufferViews) { void BindGroupBuilder::SetBufferViews(uint32_t start,
uint32_t count,
BufferViewBase* const* bufferViews) {
if (!SetBindingsValidationBase(start, count)) { if (!SetBindingsValidationBase(start, count)) {
return; return;
} }
@ -138,10 +142,12 @@ namespace backend {
} }
} }
SetBindingsBase(start, count, reinterpret_cast<RefCounted* const *>(bufferViews)); SetBindingsBase(start, count, reinterpret_cast<RefCounted* const*>(bufferViews));
} }
void BindGroupBuilder::SetSamplers(uint32_t start, uint32_t count, SamplerBase* const * samplers) { void BindGroupBuilder::SetSamplers(uint32_t start,
uint32_t count,
SamplerBase* const* samplers) {
if (!SetBindingsValidationBase(start, count)) { if (!SetBindingsValidationBase(start, count)) {
return; return;
} }
@ -154,10 +160,12 @@ namespace backend {
} }
} }
SetBindingsBase(start, count, reinterpret_cast<RefCounted* const *>(samplers)); SetBindingsBase(start, count, reinterpret_cast<RefCounted* const*>(samplers));
} }
void BindGroupBuilder::SetTextureViews(uint32_t start, uint32_t count, TextureViewBase* const * textureViews) { void BindGroupBuilder::SetTextureViews(uint32_t start,
uint32_t count,
TextureViewBase* const* textureViews) {
if (!SetBindingsValidationBase(start, count)) { if (!SetBindingsValidationBase(start, count)) {
return; return;
} }
@ -169,16 +177,19 @@ namespace backend {
return; return;
} }
if (!(textureViews[j]->GetTexture()->GetAllowedUsage() & nxt::TextureUsageBit::Sampled)) { if (!(textureViews[j]->GetTexture()->GetAllowedUsage() &
nxt::TextureUsageBit::Sampled)) {
HandleError("Texture needs to allow the sampled usage bit"); HandleError("Texture needs to allow the sampled usage bit");
return; return;
} }
} }
SetBindingsBase(start, count, reinterpret_cast<RefCounted* const *>(textureViews)); SetBindingsBase(start, count, reinterpret_cast<RefCounted* const*>(textureViews));
} }
void BindGroupBuilder::SetBindingsBase(uint32_t start, uint32_t count, RefCounted* const * objects) { void BindGroupBuilder::SetBindingsBase(uint32_t start,
uint32_t count,
RefCounted* const* objects) {
for (size_t i = start, j = 0; i < start + count; ++i, ++j) { for (size_t i = start, j = 0; i < start + count; ++i, ++j) {
mSetMask.set(i); mSetMask.set(i);
mBindings[i] = objects[j]; mBindings[i] = objects[j];
@ -211,4 +222,4 @@ namespace backend {
return true; return true;
} }
} } // namespace backend

View File

@ -29,65 +29,65 @@
namespace backend { namespace backend {
class BindGroupBase : public RefCounted { class BindGroupBase : public RefCounted {
public: public:
BindGroupBase(BindGroupBuilder* builder); BindGroupBase(BindGroupBuilder* builder);
const BindGroupLayoutBase* GetLayout() const; const BindGroupLayoutBase* GetLayout() const;
nxt::BindGroupUsage GetUsage() const; nxt::BindGroupUsage GetUsage() const;
BufferViewBase* GetBindingAsBufferView(size_t binding); BufferViewBase* GetBindingAsBufferView(size_t binding);
SamplerBase* GetBindingAsSampler(size_t binding); SamplerBase* GetBindingAsSampler(size_t binding);
TextureViewBase* GetBindingAsTextureView(size_t binding); TextureViewBase* GetBindingAsTextureView(size_t binding);
private: private:
Ref<BindGroupLayoutBase> mLayout; Ref<BindGroupLayoutBase> mLayout;
nxt::BindGroupUsage mUsage; nxt::BindGroupUsage mUsage;
std::array<Ref<RefCounted>, kMaxBindingsPerGroup> mBindings; std::array<Ref<RefCounted>, kMaxBindingsPerGroup> mBindings;
}; };
class BindGroupBuilder : public Builder<BindGroupBase> { class BindGroupBuilder : public Builder<BindGroupBase> {
public: public:
BindGroupBuilder(DeviceBase* device); BindGroupBuilder(DeviceBase* device);
// NXT API // NXT API
void SetLayout(BindGroupLayoutBase* layout); void SetLayout(BindGroupLayoutBase* layout);
void SetUsage(nxt::BindGroupUsage usage); void SetUsage(nxt::BindGroupUsage usage);
template<typename T> template <typename T>
void SetBufferViews(uint32_t start, uint32_t count, T* const* bufferViews) { void SetBufferViews(uint32_t start, uint32_t count, T* const* bufferViews) {
static_assert(std::is_base_of<BufferViewBase, T>::value, ""); static_assert(std::is_base_of<BufferViewBase, T>::value, "");
SetBufferViews(start, count, reinterpret_cast<BufferViewBase* const*>(bufferViews)); SetBufferViews(start, count, reinterpret_cast<BufferViewBase* const*>(bufferViews));
} }
void SetBufferViews(uint32_t start, uint32_t count, BufferViewBase* const * bufferViews); void SetBufferViews(uint32_t start, uint32_t count, BufferViewBase* const* bufferViews);
template<typename T> template <typename T>
void SetSamplers(uint32_t start, uint32_t count, T* const* samplers) { void SetSamplers(uint32_t start, uint32_t count, T* const* samplers) {
static_assert(std::is_base_of<SamplerBase, T>::value, ""); static_assert(std::is_base_of<SamplerBase, T>::value, "");
SetSamplers(start, count, reinterpret_cast<SamplerBase* const*>(samplers)); SetSamplers(start, count, reinterpret_cast<SamplerBase* const*>(samplers));
} }
void SetSamplers(uint32_t start, uint32_t count, SamplerBase* const * samplers); void SetSamplers(uint32_t start, uint32_t count, SamplerBase* const* samplers);
template<typename T> template <typename T>
void SetTextureViews(uint32_t start, uint32_t count, T* const* textureViews) { void SetTextureViews(uint32_t start, uint32_t count, T* const* textureViews) {
static_assert(std::is_base_of<TextureViewBase, T>::value, ""); static_assert(std::is_base_of<TextureViewBase, T>::value, "");
SetTextureViews(start, count, reinterpret_cast<TextureViewBase* const*>(textureViews)); SetTextureViews(start, count, reinterpret_cast<TextureViewBase* const*>(textureViews));
} }
void SetTextureViews(uint32_t start, uint32_t count, TextureViewBase* const * textureViews); void SetTextureViews(uint32_t start, uint32_t count, TextureViewBase* const* textureViews);
private: private:
friend class BindGroupBase; friend class BindGroupBase;
BindGroupBase* GetResultImpl() override; BindGroupBase* GetResultImpl() override;
void SetBindingsBase(uint32_t start, uint32_t count, RefCounted* const * objects); void SetBindingsBase(uint32_t start, uint32_t count, RefCounted* const* objects);
bool SetBindingsValidationBase(uint32_t start, uint32_t count); bool SetBindingsValidationBase(uint32_t start, uint32_t count);
std::bitset<kMaxBindingsPerGroup> mSetMask; std::bitset<kMaxBindingsPerGroup> mSetMask;
int mPropertiesSet = 0; int mPropertiesSet = 0;
Ref<BindGroupLayoutBase> mLayout; Ref<BindGroupLayoutBase> mLayout;
nxt::BindGroupUsage mUsage; nxt::BindGroupUsage mUsage;
std::array<Ref<RefCounted>, kMaxBindingsPerGroup> mBindings; std::array<Ref<RefCounted>, kMaxBindingsPerGroup> mBindings;
}; };
} } // namespace backend
#endif // BACKEND_BINDGROUP_H_ #endif // BACKEND_BINDGROUP_H_

View File

@ -23,13 +23,13 @@ namespace backend {
namespace { namespace {
// Workaround for Chrome's stdlib having a broken std::hash for enums and bitsets // Workaround for Chrome's stdlib having a broken std::hash for enums and bitsets
template<typename T> template <typename T>
typename std::enable_if<std::is_enum<T>::value, size_t>::type Hash(T value) { typename std::enable_if<std::is_enum<T>::value, size_t>::type Hash(T value) {
using Integral = typename nxt::UnderlyingType<T>::type; using Integral = typename nxt::UnderlyingType<T>::type;
return std::hash<Integral>()(static_cast<Integral>(value)); return std::hash<Integral>()(static_cast<Integral>(value));
} }
template<size_t N> template <size_t N>
size_t Hash(const std::bitset<N>& value) { size_t Hash(const std::bitset<N>& value) {
static_assert(N <= sizeof(unsigned long long) * 8, ""); static_assert(N <= sizeof(unsigned long long) * 8, "");
return std::hash<unsigned long long>()(value.to_ullong()); return std::hash<unsigned long long>()(value.to_ullong());
@ -54,7 +54,8 @@ namespace backend {
return hash; return hash;
} }
bool operator== (const BindGroupLayoutBase::LayoutBindingInfo& a, const BindGroupLayoutBase::LayoutBindingInfo& b) { bool operator==(const BindGroupLayoutBase::LayoutBindingInfo& a,
const BindGroupLayoutBase::LayoutBindingInfo& b) {
if (a.mask != b.mask) { if (a.mask != b.mask) {
return false; return false;
} }
@ -72,7 +73,7 @@ namespace backend {
return true; return true;
} }
} } // namespace
// BindGroupLayoutBase // BindGroupLayoutBase
@ -108,7 +109,10 @@ namespace backend {
return result; return result;
} }
void BindGroupLayoutBuilder::SetBindingsType(nxt::ShaderStageBit visibility, nxt::BindingType bindingType, uint32_t start, uint32_t count) { void BindGroupLayoutBuilder::SetBindingsType(nxt::ShaderStageBit visibility,
nxt::BindingType bindingType,
uint32_t start,
uint32_t count) {
if (start + count > kMaxBindingsPerGroup) { if (start + count > kMaxBindingsPerGroup) {
HandleError("Setting bindings type over maximum number of bindings"); HandleError("Setting bindings type over maximum number of bindings");
return; return;
@ -129,12 +133,13 @@ namespace backend {
// BindGroupLayoutCacheFuncs // BindGroupLayoutCacheFuncs
size_t BindGroupLayoutCacheFuncs::operator() (const BindGroupLayoutBase* bgl) const { size_t BindGroupLayoutCacheFuncs::operator()(const BindGroupLayoutBase* bgl) const {
return HashBindingInfo(bgl->GetBindingInfo()); return HashBindingInfo(bgl->GetBindingInfo());
} }
bool BindGroupLayoutCacheFuncs::operator() (const BindGroupLayoutBase* a, const BindGroupLayoutBase* b) const { bool BindGroupLayoutCacheFuncs::operator()(const BindGroupLayoutBase* a,
const BindGroupLayoutBase* b) const {
return a->GetBindingInfo() == b->GetBindingInfo(); return a->GetBindingInfo() == b->GetBindingInfo();
} }
} } // namespace backend

View File

@ -15,8 +15,8 @@
#ifndef BACKEND_BINDGROUPLAYOUT_H_ #ifndef BACKEND_BINDGROUPLAYOUT_H_
#define BACKEND_BINDGROUPLAYOUT_H_ #define BACKEND_BINDGROUPLAYOUT_H_
#include "backend/Forward.h"
#include "backend/Builder.h" #include "backend/Builder.h"
#include "backend/Forward.h"
#include "backend/RefCounted.h" #include "backend/RefCounted.h"
#include "common/Constants.h" #include "common/Constants.h"
@ -28,49 +28,52 @@
namespace backend { namespace backend {
class BindGroupLayoutBase : public RefCounted { class BindGroupLayoutBase : public RefCounted {
public: public:
BindGroupLayoutBase(BindGroupLayoutBuilder* builder, bool blueprint = false); BindGroupLayoutBase(BindGroupLayoutBuilder* builder, bool blueprint = false);
~BindGroupLayoutBase() override; ~BindGroupLayoutBase() override;
struct LayoutBindingInfo { struct LayoutBindingInfo {
std::array<nxt::ShaderStageBit, kMaxBindingsPerGroup> visibilities; std::array<nxt::ShaderStageBit, kMaxBindingsPerGroup> visibilities;
std::array<nxt::BindingType, kMaxBindingsPerGroup> types; std::array<nxt::BindingType, kMaxBindingsPerGroup> types;
std::bitset<kMaxBindingsPerGroup> mask; std::bitset<kMaxBindingsPerGroup> mask;
}; };
const LayoutBindingInfo& GetBindingInfo() const; const LayoutBindingInfo& GetBindingInfo() const;
private: private:
DeviceBase* mDevice; DeviceBase* mDevice;
LayoutBindingInfo mBindingInfo; LayoutBindingInfo mBindingInfo;
bool mIsBlueprint = false; bool mIsBlueprint = false;
}; };
class BindGroupLayoutBuilder : public Builder<BindGroupLayoutBase> { class BindGroupLayoutBuilder : public Builder<BindGroupLayoutBase> {
public: public:
BindGroupLayoutBuilder(DeviceBase* device); BindGroupLayoutBuilder(DeviceBase* device);
const BindGroupLayoutBase::LayoutBindingInfo& GetBindingInfo() const; const BindGroupLayoutBase::LayoutBindingInfo& GetBindingInfo() const;
// NXT API // NXT API
void SetBindingsType(nxt::ShaderStageBit visibility, nxt::BindingType bindingType, uint32_t start, uint32_t count); void SetBindingsType(nxt::ShaderStageBit visibility,
nxt::BindingType bindingType,
uint32_t start,
uint32_t count);
private: private:
friend class BindGroupLayoutBase; friend class BindGroupLayoutBase;
BindGroupLayoutBase* GetResultImpl() override; BindGroupLayoutBase* GetResultImpl() override;
BindGroupLayoutBase::LayoutBindingInfo mBindingInfo; BindGroupLayoutBase::LayoutBindingInfo mBindingInfo;
}; };
// Implements the functors necessary for the unordered_set<BGL*>-based cache. // Implements the functors necessary for the unordered_set<BGL*>-based cache.
struct BindGroupLayoutCacheFuncs { struct BindGroupLayoutCacheFuncs {
// The hash function // The hash function
size_t operator() (const BindGroupLayoutBase* bgl) const; size_t operator()(const BindGroupLayoutBase* bgl) const;
// The equality predicate // The equality predicate
bool operator() (const BindGroupLayoutBase* a, const BindGroupLayoutBase* b) const; bool operator()(const BindGroupLayoutBase* a, const BindGroupLayoutBase* b) const;
}; };
} } // namespace backend
#endif // BACKEND_BINDGROUPLAYOUT_H_ #endif // BACKEND_BINDGROUPLAYOUT_H_

View File

@ -54,7 +54,9 @@ namespace backend {
mBlendInfo.blendEnabled = blendEnabled; mBlendInfo.blendEnabled = blendEnabled;
} }
void BlendStateBuilder::SetAlphaBlend(nxt::BlendOperation blendOperation, nxt::BlendFactor srcFactor, nxt::BlendFactor dstFactor) { void BlendStateBuilder::SetAlphaBlend(nxt::BlendOperation blendOperation,
nxt::BlendFactor srcFactor,
nxt::BlendFactor dstFactor) {
if ((mPropertiesSet & BLEND_STATE_PROPERTY_ALPHA_BLEND) != 0) { if ((mPropertiesSet & BLEND_STATE_PROPERTY_ALPHA_BLEND) != 0) {
HandleError("Alpha blend property set multiple times"); HandleError("Alpha blend property set multiple times");
return; return;
@ -62,10 +64,12 @@ namespace backend {
mPropertiesSet |= BLEND_STATE_PROPERTY_ALPHA_BLEND; mPropertiesSet |= BLEND_STATE_PROPERTY_ALPHA_BLEND;
mBlendInfo.alphaBlend = { blendOperation, srcFactor, dstFactor }; mBlendInfo.alphaBlend = {blendOperation, srcFactor, dstFactor};
} }
void BlendStateBuilder::SetColorBlend(nxt::BlendOperation blendOperation, nxt::BlendFactor srcFactor, nxt::BlendFactor dstFactor) { void BlendStateBuilder::SetColorBlend(nxt::BlendOperation blendOperation,
nxt::BlendFactor srcFactor,
nxt::BlendFactor dstFactor) {
if ((mPropertiesSet & BLEND_STATE_PROPERTY_COLOR_BLEND) != 0) { if ((mPropertiesSet & BLEND_STATE_PROPERTY_COLOR_BLEND) != 0) {
HandleError("Color blend property set multiple times"); HandleError("Color blend property set multiple times");
return; return;
@ -73,7 +77,7 @@ namespace backend {
mPropertiesSet |= BLEND_STATE_PROPERTY_COLOR_BLEND; mPropertiesSet |= BLEND_STATE_PROPERTY_COLOR_BLEND;
mBlendInfo.colorBlend = { blendOperation, srcFactor, dstFactor }; mBlendInfo.colorBlend = {blendOperation, srcFactor, dstFactor};
} }
void BlendStateBuilder::SetColorWriteMask(nxt::ColorWriteMask colorWriteMask) { void BlendStateBuilder::SetColorWriteMask(nxt::ColorWriteMask colorWriteMask) {
@ -86,4 +90,4 @@ namespace backend {
mBlendInfo.colorWriteMask = colorWriteMask; mBlendInfo.colorWriteMask = colorWriteMask;
} }
} } // namespace backend

View File

@ -15,8 +15,8 @@
#ifndef BACKEND_BLENDSTATE_H_ #ifndef BACKEND_BLENDSTATE_H_
#define BACKEND_BLENDSTATE_H_ #define BACKEND_BLENDSTATE_H_
#include "backend/Forward.h"
#include "backend/Builder.h" #include "backend/Builder.h"
#include "backend/Forward.h"
#include "backend/RefCounted.h" #include "backend/RefCounted.h"
#include "nxt/nxtcpp.h" #include "nxt/nxtcpp.h"
@ -24,49 +24,52 @@
namespace backend { namespace backend {
class BlendStateBase : public RefCounted { class BlendStateBase : public RefCounted {
public: public:
BlendStateBase(BlendStateBuilder* builder); BlendStateBase(BlendStateBuilder* builder);
struct BlendInfo { struct BlendInfo {
struct BlendOpFactor { struct BlendOpFactor {
nxt::BlendOperation operation = nxt::BlendOperation::Add; nxt::BlendOperation operation = nxt::BlendOperation::Add;
nxt::BlendFactor srcFactor = nxt::BlendFactor::One; nxt::BlendFactor srcFactor = nxt::BlendFactor::One;
nxt::BlendFactor dstFactor = nxt::BlendFactor::Zero; nxt::BlendFactor dstFactor = nxt::BlendFactor::Zero;
};
bool blendEnabled = false;
BlendOpFactor alphaBlend;
BlendOpFactor colorBlend;
nxt::ColorWriteMask colorWriteMask = nxt::ColorWriteMask::All;
}; };
const BlendInfo& GetBlendInfo() const; bool blendEnabled = false;
BlendOpFactor alphaBlend;
BlendOpFactor colorBlend;
nxt::ColorWriteMask colorWriteMask = nxt::ColorWriteMask::All;
};
private: const BlendInfo& GetBlendInfo() const;
BlendInfo mBlendInfo;
private:
BlendInfo mBlendInfo;
}; };
class BlendStateBuilder : public Builder<BlendStateBase> { class BlendStateBuilder : public Builder<BlendStateBase> {
public: public:
BlendStateBuilder(DeviceBase* device); BlendStateBuilder(DeviceBase* device);
// NXT API // NXT API
void SetBlendEnabled(bool blendEnabled); void SetBlendEnabled(bool blendEnabled);
void SetAlphaBlend(nxt::BlendOperation blendOperation, nxt::BlendFactor srcFactor, nxt::BlendFactor dstFactor); void SetAlphaBlend(nxt::BlendOperation blendOperation,
void SetColorBlend(nxt::BlendOperation blendOperation, nxt::BlendFactor srcFactor, nxt::BlendFactor dstFactor); nxt::BlendFactor srcFactor,
void SetColorWriteMask(nxt::ColorWriteMask colorWriteMask); nxt::BlendFactor dstFactor);
void SetColorBlend(nxt::BlendOperation blendOperation,
nxt::BlendFactor srcFactor,
nxt::BlendFactor dstFactor);
void SetColorWriteMask(nxt::ColorWriteMask colorWriteMask);
private: private:
friend class BlendStateBase; friend class BlendStateBase;
BlendStateBase* GetResultImpl() override; BlendStateBase* GetResultImpl() override;
int mPropertiesSet = 0; int mPropertiesSet = 0;
BlendStateBase::BlendInfo mBlendInfo; BlendStateBase::BlendInfo mBlendInfo;
}; };
} } // namespace backend
#endif // BACKEND_BLENDSTATE_H_ #endif // BACKEND_BLENDSTATE_H_

View File

@ -17,8 +17,8 @@
#include "backend/Device.h" #include "backend/Device.h"
#include "common/Assert.h" #include "common/Assert.h"
#include <utility>
#include <cstdio> #include <cstdio>
#include <utility>
namespace backend { namespace backend {
@ -57,7 +57,9 @@ namespace backend {
return mCurrentUsage; return mCurrentUsage;
} }
void BufferBase::CallMapReadCallback(uint32_t serial, nxtBufferMapReadStatus status, const void* pointer) { void BufferBase::CallMapReadCallback(uint32_t serial,
nxtBufferMapReadStatus status,
const void* pointer) {
if (mMapReadCallback && serial == mMapReadSerial) { if (mMapReadCallback && serial == mMapReadSerial) {
mMapReadCallback(status, pointer, mMapReadUserdata); mMapReadCallback(status, pointer, mMapReadUserdata);
mMapReadCallback = nullptr; mMapReadCallback = nullptr;
@ -78,7 +80,10 @@ namespace backend {
SetSubDataImpl(start, count, data); SetSubDataImpl(start, count, data);
} }
void BufferBase::MapReadAsync(uint32_t start, uint32_t size, nxtBufferMapReadCallback callback, nxtCallbackUserdata userdata) { void BufferBase::MapReadAsync(uint32_t start,
uint32_t size,
nxtBufferMapReadCallback callback,
nxtCallbackUserdata userdata) {
if (start + size > GetSize()) { if (start + size > GetSize()) {
mDevice->HandleError("Buffer map read out of range"); mDevice->HandleError("Buffer map read out of range");
callback(NXT_BUFFER_MAP_READ_STATUS_ERROR, nullptr, userdata); callback(NXT_BUFFER_MAP_READ_STATUS_ERROR, nullptr, userdata);
@ -98,7 +103,7 @@ namespace backend {
} }
// TODO(cwallez@chromium.org): what to do on wraparound? Could cause crashes. // TODO(cwallez@chromium.org): what to do on wraparound? Could cause crashes.
mMapReadSerial ++; mMapReadSerial++;
mMapReadCallback = callback; mMapReadCallback = callback;
mMapReadUserdata = userdata; mMapReadUserdata = userdata;
MapReadAsyncImpl(mMapReadSerial, start, size); MapReadAsyncImpl(mMapReadSerial, start, size);
@ -128,11 +133,8 @@ namespace backend {
bool BufferBase::IsUsagePossible(nxt::BufferUsageBit allowedUsage, nxt::BufferUsageBit usage) { bool BufferBase::IsUsagePossible(nxt::BufferUsageBit allowedUsage, nxt::BufferUsageBit usage) {
const nxt::BufferUsageBit allReadBits = const nxt::BufferUsageBit allReadBits =
nxt::BufferUsageBit::MapRead | nxt::BufferUsageBit::MapRead | nxt::BufferUsageBit::TransferSrc |
nxt::BufferUsageBit::TransferSrc | nxt::BufferUsageBit::Index | nxt::BufferUsageBit::Vertex | nxt::BufferUsageBit::Uniform;
nxt::BufferUsageBit::Index |
nxt::BufferUsageBit::Vertex |
nxt::BufferUsageBit::Uniform;
bool allowed = (usage & allowedUsage) == usage; bool allowed = (usage & allowedUsage) == usage;
bool readOnly = (usage & allReadBits) == usage; bool readOnly = (usage & allReadBits) == usage;
bool singleUse = nxt::HasZeroOrOneBits(usage); bool singleUse = nxt::HasZeroOrOneBits(usage);
@ -189,14 +191,16 @@ namespace backend {
return nullptr; return nullptr;
} }
const nxt::BufferUsageBit kMapWriteAllowedUsages = nxt::BufferUsageBit::MapWrite | nxt::BufferUsageBit::TransferSrc; const nxt::BufferUsageBit kMapWriteAllowedUsages =
nxt::BufferUsageBit::MapWrite | nxt::BufferUsageBit::TransferSrc;
if (mAllowedUsage & nxt::BufferUsageBit::MapWrite && if (mAllowedUsage & nxt::BufferUsageBit::MapWrite &&
(mAllowedUsage & kMapWriteAllowedUsages) != mAllowedUsage) { (mAllowedUsage & kMapWriteAllowedUsages) != mAllowedUsage) {
HandleError("Only TransferSrc is allowed with MapWrite"); HandleError("Only TransferSrc is allowed with MapWrite");
return nullptr; return nullptr;
} }
const nxt::BufferUsageBit kMapReadAllowedUsages = nxt::BufferUsageBit::MapRead | nxt::BufferUsageBit::TransferDst; const nxt::BufferUsageBit kMapReadAllowedUsages =
nxt::BufferUsageBit::MapRead | nxt::BufferUsageBit::TransferDst;
if (mAllowedUsage & nxt::BufferUsageBit::MapRead && if (mAllowedUsage & nxt::BufferUsageBit::MapRead &&
(mAllowedUsage & kMapReadAllowedUsages) != mAllowedUsage) { (mAllowedUsage & kMapReadAllowedUsages) != mAllowedUsage) {
HandleError("Only TransferDst is allowed with MapRead"); HandleError("Only TransferDst is allowed with MapRead");
@ -296,4 +300,4 @@ namespace backend {
mPropertiesSet |= BUFFER_VIEW_PROPERTY_EXTENT; mPropertiesSet |= BUFFER_VIEW_PROPERTY_EXTENT;
} }
} } // namespace backend

View File

@ -15,8 +15,8 @@
#ifndef BACKEND_BUFFER_H_ #ifndef BACKEND_BUFFER_H_
#define BACKEND_BUFFER_H_ #define BACKEND_BUFFER_H_
#include "backend/Forward.h"
#include "backend/Builder.h" #include "backend/Builder.h"
#include "backend/Forward.h"
#include "backend/RefCounted.h" #include "backend/RefCounted.h"
#include "nxt/nxtcpp.h" #include "nxt/nxtcpp.h"
@ -24,103 +24,109 @@
namespace backend { namespace backend {
class BufferBase : public RefCounted { class BufferBase : public RefCounted {
public: public:
BufferBase(BufferBuilder* builder); BufferBase(BufferBuilder* builder);
~BufferBase(); ~BufferBase();
uint32_t GetSize() const; uint32_t GetSize() const;
nxt::BufferUsageBit GetAllowedUsage() const; nxt::BufferUsageBit GetAllowedUsage() const;
nxt::BufferUsageBit GetUsage() const; nxt::BufferUsageBit GetUsage() const;
static bool IsUsagePossible(nxt::BufferUsageBit allowedUsage, nxt::BufferUsageBit usage); static bool IsUsagePossible(nxt::BufferUsageBit allowedUsage, nxt::BufferUsageBit usage);
bool IsTransitionPossible(nxt::BufferUsageBit usage) const; bool IsTransitionPossible(nxt::BufferUsageBit usage) const;
bool IsFrozen() const; bool IsFrozen() const;
bool HasFrozenUsage(nxt::BufferUsageBit usage) const; bool HasFrozenUsage(nxt::BufferUsageBit usage) const;
void UpdateUsageInternal(nxt::BufferUsageBit usage); void UpdateUsageInternal(nxt::BufferUsageBit usage);
DeviceBase* GetDevice(); DeviceBase* GetDevice();
// NXT API // NXT API
BufferViewBuilder* CreateBufferViewBuilder(); BufferViewBuilder* CreateBufferViewBuilder();
void SetSubData(uint32_t start, uint32_t count, const uint32_t* data); void SetSubData(uint32_t start, uint32_t count, const uint32_t* data);
void MapReadAsync(uint32_t start, uint32_t size, nxtBufferMapReadCallback callback, nxtCallbackUserdata userdata); void MapReadAsync(uint32_t start,
void Unmap(); uint32_t size,
void TransitionUsage(nxt::BufferUsageBit usage); nxtBufferMapReadCallback callback,
void FreezeUsage(nxt::BufferUsageBit usage); nxtCallbackUserdata userdata);
void Unmap();
void TransitionUsage(nxt::BufferUsageBit usage);
void FreezeUsage(nxt::BufferUsageBit usage);
protected: protected:
void CallMapReadCallback(uint32_t serial, nxtBufferMapReadStatus status, const void* pointer); void CallMapReadCallback(uint32_t serial,
nxtBufferMapReadStatus status,
const void* pointer);
private: private:
virtual void SetSubDataImpl(uint32_t start, uint32_t count, const uint32_t* data) = 0; virtual void SetSubDataImpl(uint32_t start, uint32_t count, const uint32_t* data) = 0;
virtual void MapReadAsyncImpl(uint32_t serial, uint32_t start, uint32_t size) = 0; virtual void MapReadAsyncImpl(uint32_t serial, uint32_t start, uint32_t size) = 0;
virtual void UnmapImpl() = 0; virtual void UnmapImpl() = 0;
virtual void TransitionUsageImpl(nxt::BufferUsageBit currentUsage, nxt::BufferUsageBit targetUsage) = 0; virtual void TransitionUsageImpl(nxt::BufferUsageBit currentUsage,
nxt::BufferUsageBit targetUsage) = 0;
DeviceBase* mDevice; DeviceBase* mDevice;
uint32_t mSize; uint32_t mSize;
nxt::BufferUsageBit mAllowedUsage = nxt::BufferUsageBit::None; nxt::BufferUsageBit mAllowedUsage = nxt::BufferUsageBit::None;
nxt::BufferUsageBit mCurrentUsage = nxt::BufferUsageBit::None; nxt::BufferUsageBit mCurrentUsage = nxt::BufferUsageBit::None;
nxtBufferMapReadCallback mMapReadCallback = nullptr; nxtBufferMapReadCallback mMapReadCallback = nullptr;
nxtCallbackUserdata mMapReadUserdata = 0; nxtCallbackUserdata mMapReadUserdata = 0;
uint32_t mMapReadSerial = 0; uint32_t mMapReadSerial = 0;
bool mIsFrozen = false; bool mIsFrozen = false;
bool mIsMapped = false; bool mIsMapped = false;
}; };
class BufferBuilder : public Builder<BufferBase> { class BufferBuilder : public Builder<BufferBase> {
public: public:
BufferBuilder(DeviceBase* device); BufferBuilder(DeviceBase* device);
// NXT API // NXT API
void SetAllowedUsage(nxt::BufferUsageBit usage); void SetAllowedUsage(nxt::BufferUsageBit usage);
void SetInitialUsage(nxt::BufferUsageBit usage); void SetInitialUsage(nxt::BufferUsageBit usage);
void SetSize(uint32_t size); void SetSize(uint32_t size);
private: private:
friend class BufferBase; friend class BufferBase;
BufferBase* GetResultImpl() override; BufferBase* GetResultImpl() override;
uint32_t mSize; uint32_t mSize;
nxt::BufferUsageBit mAllowedUsage = nxt::BufferUsageBit::None; nxt::BufferUsageBit mAllowedUsage = nxt::BufferUsageBit::None;
nxt::BufferUsageBit mCurrentUsage = nxt::BufferUsageBit::None; nxt::BufferUsageBit mCurrentUsage = nxt::BufferUsageBit::None;
int mPropertiesSet = 0; int mPropertiesSet = 0;
}; };
class BufferViewBase : public RefCounted { class BufferViewBase : public RefCounted {
public: public:
BufferViewBase(BufferViewBuilder* builder); BufferViewBase(BufferViewBuilder* builder);
BufferBase* GetBuffer(); BufferBase* GetBuffer();
uint32_t GetSize() const; uint32_t GetSize() const;
uint32_t GetOffset() const; uint32_t GetOffset() const;
private: private:
Ref<BufferBase> mBuffer; Ref<BufferBase> mBuffer;
uint32_t mSize; uint32_t mSize;
uint32_t mOffset; uint32_t mOffset;
}; };
class BufferViewBuilder : public Builder<BufferViewBase> { class BufferViewBuilder : public Builder<BufferViewBase> {
public: public:
BufferViewBuilder(DeviceBase* device, BufferBase* buffer); BufferViewBuilder(DeviceBase* device, BufferBase* buffer);
// NXT API // NXT API
void SetExtent(uint32_t offset, uint32_t size); void SetExtent(uint32_t offset, uint32_t size);
private: private:
friend class BufferViewBase; friend class BufferViewBase;
BufferViewBase* GetResultImpl() override; BufferViewBase* GetResultImpl() override;
Ref<BufferBase> mBuffer; Ref<BufferBase> mBuffer;
uint32_t mOffset = 0; uint32_t mOffset = 0;
uint32_t mSize = 0; uint32_t mSize = 0;
int mPropertiesSet = 0; int mPropertiesSet = 0;
}; };
} } // namespace backend
#endif // BACKEND_BUFFER_H_ #endif // BACKEND_BUFFER_H_

View File

@ -32,8 +32,8 @@ namespace backend {
} }
void BuilderBase::SetErrorCallback(nxt::BuilderErrorCallback callback, void BuilderBase::SetErrorCallback(nxt::BuilderErrorCallback callback,
nxt::CallbackUserdata userdata1, nxt::CallbackUserdata userdata1,
nxt::CallbackUserdata userdata2) { nxt::CallbackUserdata userdata2) {
mCallback = callback; mCallback = callback;
mUserdata1 = userdata1; mUserdata1 = userdata1;
mUserdata2 = userdata2; mUserdata2 = userdata2;
@ -44,14 +44,15 @@ namespace backend {
BuilderBase::~BuilderBase() { BuilderBase::~BuilderBase() {
if (!mIsConsumed && mCallback != nullptr) { if (!mIsConsumed && mCallback != nullptr) {
mCallback(NXT_BUILDER_ERROR_STATUS_UNKNOWN, "Builder destroyed before GetResult", mUserdata1, mUserdata2); mCallback(NXT_BUILDER_ERROR_STATUS_UNKNOWN, "Builder destroyed before GetResult",
mUserdata1, mUserdata2);
} }
} }
void BuilderBase::SetStatus(nxt::BuilderErrorStatus status, const char* message) { void BuilderBase::SetStatus(nxt::BuilderErrorStatus status, const char* message) {
ASSERT(status != nxt::BuilderErrorStatus::Success); ASSERT(status != nxt::BuilderErrorStatus::Success);
ASSERT(status != nxt::BuilderErrorStatus::Unknown); ASSERT(status != nxt::BuilderErrorStatus::Unknown);
ASSERT(!mGotStatus); // This is not strictly necessary but something to strive for. ASSERT(!mGotStatus); // This is not strictly necessary but something to strive for.
mGotStatus = true; mGotStatus = true;
mStoredStatus = status; mStoredStatus = status;
@ -78,17 +79,19 @@ namespace backend {
} }
// Unhandled builder errors are promoted to device errors // Unhandled builder errors are promoted to device errors
if (!mCallback) mDevice->HandleError(("Unhandled builder error: " + mStoredMessage).c_str()); if (!mCallback)
mDevice->HandleError(("Unhandled builder error: " + mStoredMessage).c_str());
} else { } else {
ASSERT(mStoredStatus == nxt::BuilderErrorStatus::Success); ASSERT(mStoredStatus == nxt::BuilderErrorStatus::Success);
ASSERT(mStoredMessage.empty()); ASSERT(mStoredMessage.empty());
} }
if (mCallback != nullptr) { if (mCallback != nullptr) {
mCallback(static_cast<nxtBuilderErrorStatus>(mStoredStatus), mStoredMessage.c_str(), mUserdata1, mUserdata2); mCallback(static_cast<nxtBuilderErrorStatus>(mStoredStatus), mStoredMessage.c_str(),
mUserdata1, mUserdata2);
} }
return result != nullptr; return result != nullptr;
} }
} } // namespace backend

View File

@ -25,79 +25,76 @@
namespace backend { namespace backend {
// This class implements behavior shared by all builders: // This class implements behavior shared by all builders:
// - Tracking whether GetResult has been called already, needed by the // - Tracking whether GetResult has been called already, needed by the autogenerated code to
// autogenerated code to prevent operations on "consumed" builders. // prevent operations on "consumed" builders.
// - The error status callback of the API. The callback is guaranteed to be // - The error status callback of the API. The callback is guaranteed to be called exactly once
// called exactly once with an error, a success, or "unknown" if the // with an error, a success, or "unknown" if the builder is destroyed; also the builder
// builder is destroyed; also the builder callback cannot be called before // callback cannot be called before either the object is destroyed or GetResult is called.
// either the object is destroyed or GetResult is called.
// //
// It is possible for error to be generated before the error callback is // It is possible for error to be generated before the error callback is registered when a
// registered when a builder "set" function performance validation inline. // builder "set" function performance validation inline. Because of this we have to store the
// Because of this we have to store the status in the builder and defer // status in the builder and defer calling the callback to GetResult.
// calling the callback to GetResult.
class BuilderBase : public RefCounted { class BuilderBase : public RefCounted {
public: public:
// Used by the auto-generated validation to prevent usage of the builder // Used by the auto-generated validation to prevent usage of the builder
// after GetResult or an error. // after GetResult or an error.
bool CanBeUsed() const; bool CanBeUsed() const;
DeviceBase* GetDevice(); DeviceBase* GetDevice();
// Set the status of the builder to an error. // Set the status of the builder to an error.
void HandleError(const char* message); void HandleError(const char* message);
// Internal API, to be used by builder and BackendProcTable only. // Internal API, to be used by builder and BackendProcTable only.
// rReturns true for success cases, and calls the callback with appropriate status. // Returns true for success cases, and calls the callback with appropriate status.
bool HandleResult(RefCounted* result); bool HandleResult(RefCounted* result);
// NXT API // NXT API
void SetErrorCallback(nxt::BuilderErrorCallback callback, void SetErrorCallback(nxt::BuilderErrorCallback callback,
nxt::CallbackUserdata userdata1, nxt::CallbackUserdata userdata1,
nxt::CallbackUserdata userdata2); nxt::CallbackUserdata userdata2);
protected: protected:
BuilderBase(DeviceBase* device); BuilderBase(DeviceBase* device);
~BuilderBase(); ~BuilderBase();
DeviceBase* const mDevice; DeviceBase* const mDevice;
bool mGotStatus = false; bool mGotStatus = false;
private: private:
void SetStatus(nxt::BuilderErrorStatus status, const char* message); void SetStatus(nxt::BuilderErrorStatus status, const char* message);
nxt::BuilderErrorCallback mCallback = nullptr; nxt::BuilderErrorCallback mCallback = nullptr;
nxt::CallbackUserdata mUserdata1 = 0; nxt::CallbackUserdata mUserdata1 = 0;
nxt::CallbackUserdata mUserdata2 = 0; nxt::CallbackUserdata mUserdata2 = 0;
nxt::BuilderErrorStatus mStoredStatus = nxt::BuilderErrorStatus::Success; nxt::BuilderErrorStatus mStoredStatus = nxt::BuilderErrorStatus::Success;
std::string mStoredMessage; std::string mStoredMessage;
bool mIsConsumed = false; bool mIsConsumed = false;
}; };
// This builder base class is used to capture the calls to GetResult and make sure // This builder base class is used to capture the calls to GetResult and make sure that either:
// that either:
// - There was an error, callback is called with an error and nullptr is returned. // - There was an error, callback is called with an error and nullptr is returned.
// - There was no error, callback is called with success and a non-null T* is returned. // - There was no error, callback is called with success and a non-null T* is returned.
template<typename T> template <typename T>
class Builder : public BuilderBase { class Builder : public BuilderBase {
public: public:
// NXT API // NXT API
T* GetResult(); T* GetResult();
protected: protected:
using BuilderBase::BuilderBase; using BuilderBase::BuilderBase;
private: private:
virtual T* GetResultImpl() = 0; virtual T* GetResultImpl() = 0;
}; };
template<typename T> template <typename T>
T* Builder<T>::GetResult() { T* Builder<T>::GetResult() {
T* result = GetResultImpl(); T* result = GetResultImpl();
// An object can have been returned but failed its initialization, so if an error // An object can have been returned but failed its initialization, so if an error happened,
// happened, return nullptr instead of result. // return nullptr instead of result.
if (HandleResult(result)) { if (HandleResult(result)) {
return result; return result;
} else { } else {
@ -105,6 +102,6 @@ namespace backend {
} }
} }
} } // namespace backend
#endif // BACKEND_BUILDER_H_ #endif // BACKEND_BUILDER_H_

View File

@ -23,13 +23,12 @@
namespace backend { namespace backend {
constexpr uint32_t EndOfBlock = UINT_MAX;//std::numeric_limits<uint32_t>::max(); constexpr uint32_t EndOfBlock = UINT_MAX; // std::numeric_limits<uint32_t>::max();
constexpr uint32_t AdditionalData = UINT_MAX - 1;//std::numeric_limits<uint32_t>::max(); constexpr uint32_t AdditionalData = UINT_MAX - 1; // std::numeric_limits<uint32_t>::max() - 1;
// TODO(cwallez@chromium.org): figure out a way to have more type safety for the iterator // TODO(cwallez@chromium.org): figure out a way to have more type safety for the iterator
CommandIterator::CommandIterator() CommandIterator::CommandIterator() : mEndOfBlock(EndOfBlock) {
: mEndOfBlock(EndOfBlock) {
Reset(); Reset();
} }
@ -43,8 +42,7 @@ namespace backend {
} }
} }
CommandIterator::CommandIterator(CommandIterator&& other) CommandIterator::CommandIterator(CommandIterator&& other) : mEndOfBlock(EndOfBlock) {
: mEndOfBlock(EndOfBlock) {
if (!other.IsEmpty()) { if (!other.IsEmpty()) {
mBlocks = std::move(other.mBlocks); mBlocks = std::move(other.mBlocks);
other.Reset(); other.Reset();
@ -80,9 +78,8 @@ namespace backend {
mCurrentBlock = 0; mCurrentBlock = 0;
if (mBlocks.empty()) { if (mBlocks.empty()) {
// This will case the first NextCommandId call to try to move to the next // This will case the first NextCommandId call to try to move to the next block and stop
// block and stop the iteration immediately, without special casing the // the iteration immediately, without special casing the initialization.
// initialization.
mCurrentPtr = reinterpret_cast<uint8_t*>(&mEndOfBlock); mCurrentPtr = reinterpret_cast<uint8_t*>(&mEndOfBlock);
mBlocks.emplace_back(); mBlocks.emplace_back();
mBlocks[0].size = sizeof(mEndOfBlock); mBlocks[0].size = sizeof(mEndOfBlock);
@ -102,7 +99,8 @@ namespace backend {
bool CommandIterator::NextCommandId(uint32_t* commandId) { bool CommandIterator::NextCommandId(uint32_t* commandId) {
uint8_t* idPtr = AlignPtr(mCurrentPtr, alignof(uint32_t)); uint8_t* idPtr = AlignPtr(mCurrentPtr, alignof(uint32_t));
ASSERT(idPtr + sizeof(uint32_t) <= mBlocks[mCurrentBlock].block + mBlocks[mCurrentBlock].size); ASSERT(idPtr + sizeof(uint32_t) <=
mBlocks[mCurrentBlock].block + mBlocks[mCurrentBlock].size);
uint32_t id = *reinterpret_cast<uint32_t*>(idPtr); uint32_t id = *reinterpret_cast<uint32_t*>(idPtr);
@ -124,7 +122,8 @@ namespace backend {
void* CommandIterator::NextCommand(size_t commandSize, size_t commandAlignment) { void* CommandIterator::NextCommand(size_t commandSize, size_t commandAlignment) {
uint8_t* commandPtr = AlignPtr(mCurrentPtr, commandAlignment); uint8_t* commandPtr = AlignPtr(mCurrentPtr, commandAlignment);
ASSERT(commandPtr + sizeof(commandSize) <= mBlocks[mCurrentBlock].block + mBlocks[mCurrentBlock].size); ASSERT(commandPtr + sizeof(commandSize) <=
mBlocks[mCurrentBlock].block + mBlocks[mCurrentBlock].size);
mCurrentPtr = commandPtr + commandSize; mCurrentPtr = commandPtr + commandSize;
return commandPtr; return commandPtr;
@ -140,13 +139,18 @@ namespace backend {
} }
// Potential TODO(cwallez@chromium.org): // Potential TODO(cwallez@chromium.org):
// - Host the size and pointer to next block in the block itself to avoid having an allocation in the vector // - Host the size and pointer to next block in the block itself to avoid having an allocation
// - Assume T's alignof is, say 64bits, static assert it, and make commandAlignment a constant in Allocate // in the vector
// - Be able to optimize allocation to one block, for command buffers expected to live long to avoid cache misses // - Assume T's alignof is, say 64bits, static assert it, and make commandAlignment a constant
// - Better block allocation, maybe have NXT API to say command buffer is going to have size close to another // in Allocate
// - Be able to optimize allocation to one block, for command buffers expected to live long to
// avoid cache misses
// - Better block allocation, maybe have NXT API to say command buffer is going to have size
// close to another
CommandAllocator::CommandAllocator() CommandAllocator::CommandAllocator()
: mCurrentPtr(reinterpret_cast<uint8_t*>(&mDummyEnum[0])), mEndPtr(reinterpret_cast<uint8_t*>(&mDummyEnum[1])) { : mCurrentPtr(reinterpret_cast<uint8_t*>(&mDummyEnum[0])),
mEndPtr(reinterpret_cast<uint8_t*>(&mDummyEnum[1])) {
} }
CommandAllocator::~CommandAllocator() { CommandAllocator::~CommandAllocator() {
@ -164,7 +168,9 @@ namespace backend {
return std::move(mBlocks); return std::move(mBlocks);
} }
uint8_t* CommandAllocator::Allocate(uint32_t commandId, size_t commandSize, size_t commandAlignment) { uint8_t* CommandAllocator::Allocate(uint32_t commandId,
size_t commandSize,
size_t commandAlignment) {
ASSERT(mCurrentPtr != nullptr); ASSERT(mCurrentPtr != nullptr);
ASSERT(mEndPtr != nullptr); ASSERT(mEndPtr != nullptr);
ASSERT(commandId != EndOfBlock); ASSERT(commandId != EndOfBlock);
@ -180,15 +186,15 @@ namespace backend {
// When there is not enough space, we signal the EndOfBlock, so that the iterator nows to // When there is not enough space, we signal the EndOfBlock, so that the iterator nows to
// move to the next one. EndOfBlock on the last block means the end of the commands. // move to the next one. EndOfBlock on the last block means the end of the commands.
if (nextPtr + sizeof(uint32_t) > mEndPtr) { if (nextPtr + sizeof(uint32_t) > mEndPtr) {
// Even if we are not able to get another block, the list of commands will be
// Even if we are not able to get another block, the list of commands will be well-formed // well-formed and iterable as this block will be that last one.
// and iterable as this block will be that last one.
*idAlloc = EndOfBlock; *idAlloc = EndOfBlock;
// Make sure we have space for current allocation, plus end of block and alignment padding // Make sure we have space for current allocation, plus end of block and alignment
// for the first id. // padding for the first id.
ASSERT(nextPtr > mCurrentPtr); ASSERT(nextPtr > mCurrentPtr);
if (!GetNewBlock(static_cast<size_t>(nextPtr - mCurrentPtr) + sizeof(uint32_t) + alignof(uint32_t))) { if (!GetNewBlock(static_cast<size_t>(nextPtr - mCurrentPtr) + sizeof(uint32_t) +
alignof(uint32_t))) {
return nullptr; return nullptr;
} }
return Allocate(commandId, commandSize, commandAlignment); return Allocate(commandId, commandSize, commandAlignment);
@ -205,7 +211,8 @@ namespace backend {
bool CommandAllocator::GetNewBlock(size_t minimumSize) { bool CommandAllocator::GetNewBlock(size_t minimumSize) {
// Allocate blocks doubling sizes each time, to a maximum of 16k (or at least minimumSize). // Allocate blocks doubling sizes each time, to a maximum of 16k (or at least minimumSize).
mLastAllocationSize = std::max(minimumSize, std::min(mLastAllocationSize * 2, size_t(16384))); mLastAllocationSize =
std::max(minimumSize, std::min(mLastAllocationSize * 2, size_t(16384)));
uint8_t* block = reinterpret_cast<uint8_t*>(malloc(mLastAllocationSize)); uint8_t* block = reinterpret_cast<uint8_t*>(malloc(mLastAllocationSize));
if (block == nullptr) { if (block == nullptr) {
@ -218,4 +225,4 @@ namespace backend {
return true; return true;
} }
} } // namespace backend

View File

@ -15,8 +15,8 @@
#ifndef BACKEND_COMMAND_ALLOCATOR_H_ #ifndef BACKEND_COMMAND_ALLOCATOR_H_
#define BACKEND_COMMAND_ALLOCATOR_H_ #define BACKEND_COMMAND_ALLOCATOR_H_
#include <cstdint>
#include <cstddef> #include <cstddef>
#include <cstdint>
#include <vector> #include <vector>
namespace backend { namespace backend {
@ -61,90 +61,90 @@ namespace backend {
// TODO(cwallez@chromium.org): prevent copy for both iterator and allocator // TODO(cwallez@chromium.org): prevent copy for both iterator and allocator
class CommandIterator { class CommandIterator {
public: public:
CommandIterator(); CommandIterator();
~CommandIterator(); ~CommandIterator();
CommandIterator(CommandIterator&& other); CommandIterator(CommandIterator&& other);
CommandIterator& operator=(CommandIterator&& other); CommandIterator& operator=(CommandIterator&& other);
CommandIterator(CommandAllocator&& allocator); CommandIterator(CommandAllocator&& allocator);
CommandIterator& operator=(CommandAllocator&& allocator); CommandIterator& operator=(CommandAllocator&& allocator);
template<typename E> template <typename E>
bool NextCommandId(E* commandId) { bool NextCommandId(E* commandId) {
return NextCommandId(reinterpret_cast<uint32_t*>(commandId)); return NextCommandId(reinterpret_cast<uint32_t*>(commandId));
} }
template<typename T> template <typename T>
T* NextCommand() { T* NextCommand() {
return reinterpret_cast<T*>(NextCommand(sizeof(T), alignof(T))); return reinterpret_cast<T*>(NextCommand(sizeof(T), alignof(T)));
} }
template<typename T> template <typename T>
T* NextData(size_t count) { T* NextData(size_t count) {
return reinterpret_cast<T*>(NextData(sizeof(T) * count, alignof(T))); return reinterpret_cast<T*>(NextData(sizeof(T) * count, alignof(T)));
} }
// Needs to be called if iteration was stopped early. // Needs to be called if iteration was stopped early.
void Reset(); void Reset();
void DataWasDestroyed(); void DataWasDestroyed();
private: private:
bool IsEmpty() const; bool IsEmpty() const;
bool NextCommandId(uint32_t* commandId); bool NextCommandId(uint32_t* commandId);
void* NextCommand(size_t commandSize, size_t commandAlignment); void* NextCommand(size_t commandSize, size_t commandAlignment);
void* NextData(size_t dataSize, size_t dataAlignment); void* NextData(size_t dataSize, size_t dataAlignment);
CommandBlocks mBlocks; CommandBlocks mBlocks;
uint8_t* mCurrentPtr = nullptr; uint8_t* mCurrentPtr = nullptr;
size_t mCurrentBlock = 0; size_t mCurrentBlock = 0;
// Used to avoid a special case for empty iterators. // Used to avoid a special case for empty iterators.
uint32_t mEndOfBlock; uint32_t mEndOfBlock;
bool mDataWasDestroyed = false; bool mDataWasDestroyed = false;
}; };
class CommandAllocator { class CommandAllocator {
public: public:
CommandAllocator(); CommandAllocator();
~CommandAllocator(); ~CommandAllocator();
template<typename T, typename E> template <typename T, typename E>
T* Allocate(E commandId) { T* Allocate(E commandId) {
static_assert(sizeof(E) == sizeof(uint32_t), ""); static_assert(sizeof(E) == sizeof(uint32_t), "");
static_assert(alignof(E) == alignof(uint32_t), ""); static_assert(alignof(E) == alignof(uint32_t), "");
return reinterpret_cast<T*>(Allocate(static_cast<uint32_t>(commandId), sizeof(T), alignof(T))); return reinterpret_cast<T*>(
} Allocate(static_cast<uint32_t>(commandId), sizeof(T), alignof(T)));
}
template<typename T> template <typename T>
T* AllocateData(size_t count) { T* AllocateData(size_t count) {
return reinterpret_cast<T*>(AllocateData(sizeof(T) * count, alignof(T))); return reinterpret_cast<T*>(AllocateData(sizeof(T) * count, alignof(T)));
} }
private: private:
friend CommandIterator; friend CommandIterator;
CommandBlocks&& AcquireBlocks(); CommandBlocks&& AcquireBlocks();
uint8_t* Allocate(uint32_t commandId, size_t commandSize, size_t commandAlignment); uint8_t* Allocate(uint32_t commandId, size_t commandSize, size_t commandAlignment);
uint8_t* AllocateData(size_t dataSize, size_t dataAlignment); uint8_t* AllocateData(size_t dataSize, size_t dataAlignment);
bool GetNewBlock(size_t minimumSize); bool GetNewBlock(size_t minimumSize);
CommandBlocks mBlocks; CommandBlocks mBlocks;
size_t mLastAllocationSize = 2048; size_t mLastAllocationSize = 2048;
// Pointers to the current range of allocation in the block. Guaranteed to allow // Pointers to the current range of allocation in the block. Guaranteed to allow for at
// for at least one uint32_t is not nullptr, so that the special EndOfBlock command id // least one uint32_t is not nullptr, so that the special EndOfBlock command id can always
// can always be written. // be written. Nullptr iff the blocks were moved out.
// Nullptr iff the blocks were moved out. uint8_t* mCurrentPtr = nullptr;
uint8_t* mCurrentPtr = nullptr; uint8_t* mEndPtr = nullptr;
uint8_t* mEndPtr = nullptr;
// Data used for the block range at initialization so that the first call to Allocate // Data used for the block range at initialization so that the first call to Allocate sees
// sees there is not enough space and calls GetNewBlock. This avoids having to special // there is not enough space and calls GetNewBlock. This avoids having to special case the
// case the initialization in Allocate. // initialization in Allocate.
uint32_t mDummyEnum[1] = {0}; uint32_t mDummyEnum[1] = {0};
}; };
} } // namespace backend
#endif // BACKEND_COMMAND_ALLOCATOR_H_ #endif // BACKEND_COMMAND_ALLOCATOR_H_

File diff suppressed because it is too large Load Diff

View File

@ -17,8 +17,8 @@
#include "nxt/nxtcpp.h" #include "nxt/nxtcpp.h"
#include "backend/CommandAllocator.h"
#include "backend/Builder.h" #include "backend/Builder.h"
#include "backend/CommandAllocator.h"
#include "backend/RefCounted.h" #include "backend/RefCounted.h"
#include <memory> #include <memory>
@ -39,75 +39,111 @@ namespace backend {
class CommandBufferBuilder; class CommandBufferBuilder;
class CommandBufferBase : public RefCounted { class CommandBufferBase : public RefCounted {
public: public:
CommandBufferBase(CommandBufferBuilder* builder); CommandBufferBase(CommandBufferBuilder* builder);
bool ValidateResourceUsagesImmediate(); bool ValidateResourceUsagesImmediate();
DeviceBase* GetDevice(); DeviceBase* GetDevice();
private: private:
DeviceBase* mDevice; DeviceBase* mDevice;
std::set<BufferBase*> mBuffersTransitioned; std::set<BufferBase*> mBuffersTransitioned;
std::set<TextureBase*> mTexturesTransitioned; std::set<TextureBase*> mTexturesTransitioned;
}; };
class CommandBufferBuilder : public Builder<CommandBufferBase> { class CommandBufferBuilder : public Builder<CommandBufferBase> {
public: public:
CommandBufferBuilder(DeviceBase* device); CommandBufferBuilder(DeviceBase* device);
~CommandBufferBuilder(); ~CommandBufferBuilder();
bool ValidateGetResult(); bool ValidateGetResult();
CommandIterator AcquireCommands(); CommandIterator AcquireCommands();
// NXT API // NXT API
void BeginComputePass(); void BeginComputePass();
void BeginRenderPass(RenderPassBase* renderPass, FramebufferBase* framebuffer); void BeginRenderPass(RenderPassBase* renderPass, FramebufferBase* framebuffer);
void BeginRenderSubpass(); void BeginRenderSubpass();
void CopyBufferToBuffer(BufferBase* source, uint32_t sourceOffset, BufferBase* destination, uint32_t destinationOffset, uint32_t size); void CopyBufferToBuffer(BufferBase* source,
void CopyBufferToTexture(BufferBase* buffer, uint32_t bufferOffset, uint32_t rowPitch, uint32_t sourceOffset,
TextureBase* texture, uint32_t x, uint32_t y, uint32_t z, BufferBase* destination,
uint32_t width, uint32_t height, uint32_t depth, uint32_t level); uint32_t destinationOffset,
void CopyTextureToBuffer(TextureBase* texture, uint32_t x, uint32_t y, uint32_t z, uint32_t size);
uint32_t width, uint32_t height, uint32_t depth, uint32_t level, void CopyBufferToTexture(BufferBase* buffer,
BufferBase* buffer, uint32_t bufferOffset, uint32_t rowPitch); uint32_t bufferOffset,
void Dispatch(uint32_t x, uint32_t y, uint32_t z); uint32_t rowPitch,
void DrawArrays(uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance); TextureBase* texture,
void DrawElements(uint32_t vertexCount, uint32_t instanceCount, uint32_t firstIndex, uint32_t firstInstance); uint32_t x,
void EndComputePass(); uint32_t y,
void EndRenderPass(); uint32_t z,
void EndRenderSubpass(); uint32_t width,
void SetPushConstants(nxt::ShaderStageBit stages, uint32_t offset, uint32_t count, const void* data); uint32_t height,
void SetComputePipeline(ComputePipelineBase* pipeline); uint32_t depth,
void SetRenderPipeline(RenderPipelineBase* pipeline); uint32_t level);
void SetStencilReference(uint32_t reference); void CopyTextureToBuffer(TextureBase* texture,
void SetBlendColor(float r, float g, float b, float a); uint32_t x,
void SetBindGroup(uint32_t groupIndex, BindGroupBase* group); uint32_t y,
void SetIndexBuffer(BufferBase* buffer, uint32_t offset); uint32_t z,
uint32_t width,
uint32_t height,
uint32_t depth,
uint32_t level,
BufferBase* buffer,
uint32_t bufferOffset,
uint32_t rowPitch);
void Dispatch(uint32_t x, uint32_t y, uint32_t z);
void DrawArrays(uint32_t vertexCount,
uint32_t instanceCount,
uint32_t firstVertex,
uint32_t firstInstance);
void DrawElements(uint32_t vertexCount,
uint32_t instanceCount,
uint32_t firstIndex,
uint32_t firstInstance);
void EndComputePass();
void EndRenderPass();
void EndRenderSubpass();
void SetPushConstants(nxt::ShaderStageBit stages,
uint32_t offset,
uint32_t count,
const void* data);
void SetComputePipeline(ComputePipelineBase* pipeline);
void SetRenderPipeline(RenderPipelineBase* pipeline);
void SetStencilReference(uint32_t reference);
void SetBlendColor(float r, float g, float b, float a);
void SetBindGroup(uint32_t groupIndex, BindGroupBase* group);
void SetIndexBuffer(BufferBase* buffer, uint32_t offset);
template<typename T> template <typename T>
void SetVertexBuffers(uint32_t startSlot, uint32_t count, T* const* buffers, uint32_t const* offsets) { void SetVertexBuffers(uint32_t startSlot,
static_assert(std::is_base_of<BufferBase, T>::value, ""); uint32_t count,
SetVertexBuffers(startSlot, count, reinterpret_cast<BufferBase* const*>(buffers), offsets); T* const* buffers,
} uint32_t const* offsets) {
void SetVertexBuffers(uint32_t startSlot, uint32_t count, BufferBase* const* buffers, uint32_t const* offsets); static_assert(std::is_base_of<BufferBase, T>::value, "");
SetVertexBuffers(startSlot, count, reinterpret_cast<BufferBase* const*>(buffers),
offsets);
}
void SetVertexBuffers(uint32_t startSlot,
uint32_t count,
BufferBase* const* buffers,
uint32_t const* offsets);
void TransitionBufferUsage(BufferBase* buffer, nxt::BufferUsageBit usage); void TransitionBufferUsage(BufferBase* buffer, nxt::BufferUsageBit usage);
void TransitionTextureUsage(TextureBase* texture, nxt::TextureUsageBit usage); void TransitionTextureUsage(TextureBase* texture, nxt::TextureUsageBit usage);
private: private:
friend class CommandBufferBase; friend class CommandBufferBase;
CommandBufferBase* GetResultImpl() override; CommandBufferBase* GetResultImpl() override;
void MoveToIterator(); void MoveToIterator();
std::unique_ptr<CommandBufferStateTracker> mState; std::unique_ptr<CommandBufferStateTracker> mState;
CommandAllocator mAllocator; CommandAllocator mAllocator;
CommandIterator mIterator; CommandIterator mIterator;
bool mWasMovedToIterator = false; bool mWasMovedToIterator = false;
bool mWereCommandsAcquired = false; bool mWereCommandsAcquired = false;
}; };
} } // namespace backend
#endif // BACKEND_COMMANDBUFFER_H_ #endif // BACKEND_COMMANDBUFFER_H_

View File

@ -14,11 +14,11 @@
#include "backend/CommandBufferStateTracker.h" #include "backend/CommandBufferStateTracker.h"
#include "backend/Forward.h"
#include "backend/BindGroup.h" #include "backend/BindGroup.h"
#include "backend/BindGroupLayout.h" #include "backend/BindGroupLayout.h"
#include "backend/Buffer.h" #include "backend/Buffer.h"
#include "backend/ComputePipeline.h" #include "backend/ComputePipeline.h"
#include "backend/Forward.h"
#include "backend/Framebuffer.h" #include "backend/Framebuffer.h"
#include "backend/InputState.h" #include "backend/InputState.h"
#include "backend/PipelineLayout.h" #include "backend/PipelineLayout.h"
@ -49,7 +49,8 @@ namespace backend {
return true; return true;
} }
bool CommandBufferStateTracker::ValidateCanUseBufferAs(BufferBase* buffer, nxt::BufferUsageBit usage) const { bool CommandBufferStateTracker::ValidateCanUseBufferAs(BufferBase* buffer,
nxt::BufferUsageBit usage) const {
if (!BufferHasGuaranteedUsageBit(buffer, usage)) { if (!BufferHasGuaranteedUsageBit(buffer, usage)) {
mBuilder->HandleError("Buffer is not in the necessary usage"); mBuilder->HandleError("Buffer is not in the necessary usage");
return false; return false;
@ -57,7 +58,8 @@ namespace backend {
return true; return true;
} }
bool CommandBufferStateTracker::ValidateCanUseTextureAs(TextureBase* texture, nxt::TextureUsageBit usage) const { bool CommandBufferStateTracker::ValidateCanUseTextureAs(TextureBase* texture,
nxt::TextureUsageBit usage) const {
if (!TextureHasGuaranteedUsageBit(texture, usage)) { if (!TextureHasGuaranteedUsageBit(texture, usage)) {
mBuilder->HandleError("Texture is not in the necessary usage"); mBuilder->HandleError("Texture is not in the necessary usage");
return false; return false;
@ -67,7 +69,7 @@ namespace backend {
bool CommandBufferStateTracker::ValidateCanDispatch() { bool CommandBufferStateTracker::ValidateCanDispatch() {
constexpr ValidationAspects requiredAspects = constexpr ValidationAspects requiredAspects =
1 << VALIDATION_ASPECT_COMPUTE_PIPELINE | // implicitly requires COMPUTE_PASS 1 << VALIDATION_ASPECT_COMPUTE_PIPELINE | // implicitly requires COMPUTE_PASS
1 << VALIDATION_ASPECT_BIND_GROUPS; 1 << VALIDATION_ASPECT_BIND_GROUPS;
if ((requiredAspects & ~mAspects).none()) { if ((requiredAspects & ~mAspects).none()) {
// Fast return-true path if everything is good // Fast return-true path if everything is good
@ -89,9 +91,8 @@ namespace backend {
bool CommandBufferStateTracker::ValidateCanDrawArrays() { bool CommandBufferStateTracker::ValidateCanDrawArrays() {
// TODO(kainino@chromium.org): Check for a current render pass // TODO(kainino@chromium.org): Check for a current render pass
constexpr ValidationAspects requiredAspects = constexpr ValidationAspects requiredAspects =
1 << VALIDATION_ASPECT_RENDER_PIPELINE | // implicitly requires RENDER_SUBPASS 1 << VALIDATION_ASPECT_RENDER_PIPELINE | // implicitly requires RENDER_SUBPASS
1 << VALIDATION_ASPECT_BIND_GROUPS | 1 << VALIDATION_ASPECT_BIND_GROUPS | 1 << VALIDATION_ASPECT_VERTEX_BUFFERS;
1 << VALIDATION_ASPECT_VERTEX_BUFFERS;
if ((requiredAspects & ~mAspects).none()) { if ((requiredAspects & ~mAspects).none()) {
// Fast return-true path if everything is good // Fast return-true path if everything is good
return true; return true;
@ -103,10 +104,8 @@ namespace backend {
bool CommandBufferStateTracker::ValidateCanDrawElements() { bool CommandBufferStateTracker::ValidateCanDrawElements() {
// TODO(kainino@chromium.org): Check for a current render pass // TODO(kainino@chromium.org): Check for a current render pass
constexpr ValidationAspects requiredAspects = constexpr ValidationAspects requiredAspects =
1 << VALIDATION_ASPECT_RENDER_PIPELINE | 1 << VALIDATION_ASPECT_RENDER_PIPELINE | 1 << VALIDATION_ASPECT_BIND_GROUPS |
1 << VALIDATION_ASPECT_BIND_GROUPS | 1 << VALIDATION_ASPECT_VERTEX_BUFFERS | 1 << VALIDATION_ASPECT_INDEX_BUFFER;
1 << VALIDATION_ASPECT_VERTEX_BUFFERS |
1 << VALIDATION_ASPECT_INDEX_BUFFER;
if ((requiredAspects & ~mAspects).none()) { if ((requiredAspects & ~mAspects).none()) {
// Fast return-true path if everything is good // Fast return-true path if everything is good
return true; return true;
@ -134,16 +133,19 @@ namespace backend {
bool CommandBufferStateTracker::ValidateSetPushConstants(nxt::ShaderStageBit stages) { bool CommandBufferStateTracker::ValidateSetPushConstants(nxt::ShaderStageBit stages) {
if (mAspects[VALIDATION_ASPECT_COMPUTE_PASS]) { if (mAspects[VALIDATION_ASPECT_COMPUTE_PASS]) {
if (stages & ~nxt::ShaderStageBit::Compute) { if (stages & ~nxt::ShaderStageBit::Compute) {
mBuilder->HandleError("SetPushConstants stage must be compute or 0 in compute passes"); mBuilder->HandleError(
"SetPushConstants stage must be compute or 0 in compute passes");
return false; return false;
} }
} else if (mAspects[VALIDATION_ASPECT_RENDER_SUBPASS]) { } else if (mAspects[VALIDATION_ASPECT_RENDER_SUBPASS]) {
if (stages & ~(nxt::ShaderStageBit::Vertex | nxt::ShaderStageBit::Fragment)) { if (stages & ~(nxt::ShaderStageBit::Vertex | nxt::ShaderStageBit::Fragment)) {
mBuilder->HandleError("SetPushConstants stage must be a subset if (vertex|fragment) in subpasses"); mBuilder->HandleError(
"SetPushConstants stage must be a subset if (vertex|fragment) in subpasses");
return false; return false;
} }
} else { } else {
mBuilder->HandleError("PushConstants must be set in either compute passes or subpasses"); mBuilder->HandleError(
"PushConstants must be set in either compute passes or subpasses");
return false; return false;
} }
return true; return true;
@ -224,7 +226,8 @@ namespace backend {
return true; return true;
} }
bool CommandBufferStateTracker::BeginRenderPass(RenderPassBase* renderPass, FramebufferBase* framebuffer) { bool CommandBufferStateTracker::BeginRenderPass(RenderPassBase* renderPass,
FramebufferBase* framebuffer) {
if (mAspects[VALIDATION_ASPECT_COMPUTE_PASS]) { if (mAspects[VALIDATION_ASPECT_COMPUTE_PASS]) {
mBuilder->HandleError("Cannot begin a render pass while a compute pass is active"); mBuilder->HandleError("Cannot begin a render pass while a compute pass is active");
return false; return false;
@ -338,7 +341,8 @@ namespace backend {
return true; return true;
} }
bool CommandBufferStateTracker::TransitionBufferUsage(BufferBase* buffer, nxt::BufferUsageBit usage) { bool CommandBufferStateTracker::TransitionBufferUsage(BufferBase* buffer,
nxt::BufferUsageBit usage) {
if (!buffer->IsTransitionPossible(usage)) { if (!buffer->IsTransitionPossible(usage)) {
if (buffer->IsFrozen()) { if (buffer->IsFrozen()) {
mBuilder->HandleError("Buffer transition not possible (usage is frozen)"); mBuilder->HandleError("Buffer transition not possible (usage is frozen)");
@ -355,14 +359,17 @@ namespace backend {
return true; return true;
} }
bool CommandBufferStateTracker::TransitionTextureUsage(TextureBase* texture, nxt::TextureUsageBit usage) { bool CommandBufferStateTracker::TransitionTextureUsage(TextureBase* texture,
nxt::TextureUsageBit usage) {
if (!IsExplicitTextureTransitionPossible(texture, usage)) { if (!IsExplicitTextureTransitionPossible(texture, usage)) {
if (texture->IsFrozen()) { if (texture->IsFrozen()) {
mBuilder->HandleError("Texture transition not possible (usage is frozen)"); mBuilder->HandleError("Texture transition not possible (usage is frozen)");
} else if (!TextureBase::IsUsagePossible(texture->GetAllowedUsage(), usage)) { } else if (!TextureBase::IsUsagePossible(texture->GetAllowedUsage(), usage)) {
mBuilder->HandleError("Texture transition not possible (usage not allowed)"); mBuilder->HandleError("Texture transition not possible (usage not allowed)");
} else if (mTexturesAttached.find(texture) != mTexturesAttached.end()) { } else if (mTexturesAttached.find(texture) != mTexturesAttached.end()) {
mBuilder->HandleError("Texture transition not possible (texture is in use as a framebuffer attachment)"); mBuilder->HandleError(
"Texture transition not possible (texture is in use as a framebuffer "
"attachment)");
} else { } else {
mBuilder->HandleError("Texture transition not possible"); mBuilder->HandleError("Texture transition not possible");
} }
@ -374,7 +381,8 @@ namespace backend {
return true; return true;
} }
bool CommandBufferStateTracker::EnsureTextureUsage(TextureBase* texture, nxt::TextureUsageBit usage) { bool CommandBufferStateTracker::EnsureTextureUsage(TextureBase* texture,
nxt::TextureUsageBit usage) {
if (texture->HasFrozenUsage(usage)) { if (texture->HasFrozenUsage(usage)) {
return true; return true;
} }
@ -386,7 +394,8 @@ namespace backend {
return true; return true;
} }
bool CommandBufferStateTracker::BufferHasGuaranteedUsageBit(BufferBase* buffer, nxt::BufferUsageBit usage) const { bool CommandBufferStateTracker::BufferHasGuaranteedUsageBit(BufferBase* buffer,
nxt::BufferUsageBit usage) const {
ASSERT(usage != nxt::BufferUsageBit::None && nxt::HasZeroOrOneBits(usage)); ASSERT(usage != nxt::BufferUsageBit::None && nxt::HasZeroOrOneBits(usage));
if (buffer->HasFrozenUsage(usage)) { if (buffer->HasFrozenUsage(usage)) {
return true; return true;
@ -395,7 +404,8 @@ namespace backend {
return it != mMostRecentBufferUsages.end() && (it->second & usage); return it != mMostRecentBufferUsages.end() && (it->second & usage);
} }
bool CommandBufferStateTracker::TextureHasGuaranteedUsageBit(TextureBase* texture, nxt::TextureUsageBit usage) const { bool CommandBufferStateTracker::TextureHasGuaranteedUsageBit(TextureBase* texture,
nxt::TextureUsageBit usage) const {
ASSERT(usage != nxt::TextureUsageBit::None && nxt::HasZeroOrOneBits(usage)); ASSERT(usage != nxt::TextureUsageBit::None && nxt::HasZeroOrOneBits(usage));
if (texture->HasFrozenUsage(usage)) { if (texture->HasFrozenUsage(usage)) {
return true; return true;
@ -404,7 +414,9 @@ namespace backend {
return it != mMostRecentTextureUsages.end() && (it->second & usage); return it != mMostRecentTextureUsages.end() && (it->second & usage);
} }
bool CommandBufferStateTracker::IsInternalTextureTransitionPossible(TextureBase* texture, nxt::TextureUsageBit usage) const { bool CommandBufferStateTracker::IsInternalTextureTransitionPossible(
TextureBase* texture,
nxt::TextureUsageBit usage) const {
ASSERT(usage != nxt::TextureUsageBit::None && nxt::HasZeroOrOneBits(usage)); ASSERT(usage != nxt::TextureUsageBit::None && nxt::HasZeroOrOneBits(usage));
if (mTexturesAttached.find(texture) != mTexturesAttached.end()) { if (mTexturesAttached.find(texture) != mTexturesAttached.end()) {
return false; return false;
@ -412,9 +424,10 @@ namespace backend {
return texture->IsTransitionPossible(usage); return texture->IsTransitionPossible(usage);
} }
bool CommandBufferStateTracker::IsExplicitTextureTransitionPossible(TextureBase* texture, nxt::TextureUsageBit usage) const { bool CommandBufferStateTracker::IsExplicitTextureTransitionPossible(
const nxt::TextureUsageBit attachmentUsages = TextureBase* texture,
nxt::TextureUsageBit::OutputAttachment; nxt::TextureUsageBit usage) const {
const nxt::TextureUsageBit attachmentUsages = nxt::TextureUsageBit::OutputAttachment;
if (usage & attachmentUsages) { if (usage & attachmentUsages) {
return false; return false;
} }
@ -456,8 +469,7 @@ namespace backend {
bool CommandBufferStateTracker::HavePipeline() const { bool CommandBufferStateTracker::HavePipeline() const {
constexpr ValidationAspects pipelineAspects = constexpr ValidationAspects pipelineAspects =
1 << VALIDATION_ASPECT_COMPUTE_PIPELINE | 1 << VALIDATION_ASPECT_COMPUTE_PIPELINE | 1 << VALIDATION_ASPECT_RENDER_PIPELINE;
1 << VALIDATION_ASPECT_RENDER_PIPELINE;
return (mAspects & pipelineAspects).any(); return (mAspects & pipelineAspects).any();
} }
@ -471,40 +483,36 @@ namespace backend {
nxt::BindingType type = layoutInfo.types[i]; nxt::BindingType type = layoutInfo.types[i];
switch (type) { switch (type) {
case nxt::BindingType::UniformBuffer: case nxt::BindingType::UniformBuffer:
case nxt::BindingType::StorageBuffer: case nxt::BindingType::StorageBuffer: {
{ nxt::BufferUsageBit requiredUsage = nxt::BufferUsageBit::None;
nxt::BufferUsageBit requiredUsage = nxt::BufferUsageBit::None; switch (type) {
switch (type) { case nxt::BindingType::UniformBuffer:
case nxt::BindingType::UniformBuffer: requiredUsage = nxt::BufferUsageBit::Uniform;
requiredUsage = nxt::BufferUsageBit::Uniform; break;
break;
case nxt::BindingType::StorageBuffer: case nxt::BindingType::StorageBuffer:
requiredUsage = nxt::BufferUsageBit::Storage; requiredUsage = nxt::BufferUsageBit::Storage;
break; break;
default: default:
UNREACHABLE(); UNREACHABLE();
}
auto buffer = group->GetBindingAsBufferView(i)->GetBuffer();
if (!BufferHasGuaranteedUsageBit(buffer, requiredUsage)) {
mBuilder->HandleError("Can't guarantee buffer usage needed by bind group");
return false;
}
} }
break;
case nxt::BindingType::SampledTexture:
{
auto requiredUsage = nxt::TextureUsageBit::Sampled;
auto texture = group->GetBindingAsTextureView(i)->GetTexture(); auto buffer = group->GetBindingAsBufferView(i)->GetBuffer();
if (!TextureHasGuaranteedUsageBit(texture, requiredUsage)) { if (!BufferHasGuaranteedUsageBit(buffer, requiredUsage)) {
mBuilder->HandleError("Can't guarantee texture usage needed by bind group"); mBuilder->HandleError("Can't guarantee buffer usage needed by bind group");
return false; return false;
}
} }
break; } break;
case nxt::BindingType::SampledTexture: {
auto requiredUsage = nxt::TextureUsageBit::Sampled;
auto texture = group->GetBindingAsTextureView(i)->GetTexture();
if (!TextureHasGuaranteedUsageBit(texture, requiredUsage)) {
mBuilder->HandleError("Can't guarantee texture usage needed by bind group");
return false;
}
} break;
case nxt::BindingType::Sampler: case nxt::BindingType::Sampler:
continue; continue;
} }
@ -547,12 +555,10 @@ namespace backend {
void CommandBufferStateTracker::UnsetPipeline() { void CommandBufferStateTracker::UnsetPipeline() {
constexpr ValidationAspects pipelineDependentAspects = constexpr ValidationAspects pipelineDependentAspects =
1 << VALIDATION_ASPECT_RENDER_PIPELINE | 1 << VALIDATION_ASPECT_RENDER_PIPELINE | 1 << VALIDATION_ASPECT_COMPUTE_PIPELINE |
1 << VALIDATION_ASPECT_COMPUTE_PIPELINE | 1 << VALIDATION_ASPECT_BIND_GROUPS | 1 << VALIDATION_ASPECT_VERTEX_BUFFERS |
1 << VALIDATION_ASPECT_BIND_GROUPS |
1 << VALIDATION_ASPECT_VERTEX_BUFFERS |
1 << VALIDATION_ASPECT_INDEX_BUFFER; 1 << VALIDATION_ASPECT_INDEX_BUFFER;
mAspects &= ~pipelineDependentAspects; mAspects &= ~pipelineDependentAspects;
mBindgroups.fill(nullptr); mBindgroups.fill(nullptr);
} }
} } // namespace backend

View File

@ -25,92 +25,94 @@
namespace backend { namespace backend {
class CommandBufferStateTracker { class CommandBufferStateTracker {
public: public:
explicit CommandBufferStateTracker(CommandBufferBuilder* builder); explicit CommandBufferStateTracker(CommandBufferBuilder* builder);
// Non-state-modifying validation functions // Non-state-modifying validation functions
bool HaveRenderPass() const; bool HaveRenderPass() const;
bool HaveRenderSubpass() const; bool HaveRenderSubpass() const;
bool ValidateCanCopy() const; bool ValidateCanCopy() const;
bool ValidateCanUseBufferAs(BufferBase* buffer, nxt::BufferUsageBit usage) const; bool ValidateCanUseBufferAs(BufferBase* buffer, nxt::BufferUsageBit usage) const;
bool ValidateCanUseTextureAs(TextureBase* texture, nxt::TextureUsageBit usage) const; bool ValidateCanUseTextureAs(TextureBase* texture, nxt::TextureUsageBit usage) const;
bool ValidateCanDispatch(); bool ValidateCanDispatch();
bool ValidateCanDrawArrays(); bool ValidateCanDrawArrays();
bool ValidateCanDrawElements(); bool ValidateCanDrawElements();
bool ValidateEndCommandBuffer() const; bool ValidateEndCommandBuffer() const;
bool ValidateSetPushConstants(nxt::ShaderStageBit stages); bool ValidateSetPushConstants(nxt::ShaderStageBit stages);
// State-modifying methods // State-modifying methods
bool BeginComputePass(); bool BeginComputePass();
bool EndComputePass(); bool EndComputePass();
bool BeginSubpass(); bool BeginSubpass();
bool EndSubpass(); bool EndSubpass();
bool BeginRenderPass(RenderPassBase* renderPass, FramebufferBase* framebuffer); bool BeginRenderPass(RenderPassBase* renderPass, FramebufferBase* framebuffer);
bool EndRenderPass(); bool EndRenderPass();
bool SetComputePipeline(ComputePipelineBase* pipeline); bool SetComputePipeline(ComputePipelineBase* pipeline);
bool SetRenderPipeline(RenderPipelineBase* pipeline); bool SetRenderPipeline(RenderPipelineBase* pipeline);
bool SetBindGroup(uint32_t index, BindGroupBase* bindgroup); bool SetBindGroup(uint32_t index, BindGroupBase* bindgroup);
bool SetIndexBuffer(BufferBase* buffer); bool SetIndexBuffer(BufferBase* buffer);
bool SetVertexBuffer(uint32_t index, BufferBase* buffer); bool SetVertexBuffer(uint32_t index, BufferBase* buffer);
bool TransitionBufferUsage(BufferBase* buffer, nxt::BufferUsageBit usage); bool TransitionBufferUsage(BufferBase* buffer, nxt::BufferUsageBit usage);
bool TransitionTextureUsage(TextureBase* texture, nxt::TextureUsageBit usage); bool TransitionTextureUsage(TextureBase* texture, nxt::TextureUsageBit usage);
bool EnsureTextureUsage(TextureBase* texture, nxt::TextureUsageBit usage); bool EnsureTextureUsage(TextureBase* texture, nxt::TextureUsageBit usage);
// These collections are copied to the CommandBuffer at build time. // These collections are copied to the CommandBuffer at build time. These pointers will
// These pointers will remain valid since they are referenced by // remain valid since they are referenced by the bind groups which are referenced by this
// the bind groups which are referenced by this command buffer. // command buffer.
std::set<BufferBase*> mBuffersTransitioned; std::set<BufferBase*> mBuffersTransitioned;
std::set<TextureBase*> mTexturesTransitioned; std::set<TextureBase*> mTexturesTransitioned;
std::set<TextureBase*> mTexturesAttached; std::set<TextureBase*> mTexturesAttached;
private: private:
enum ValidationAspect { enum ValidationAspect {
VALIDATION_ASPECT_RENDER_PIPELINE, VALIDATION_ASPECT_RENDER_PIPELINE,
VALIDATION_ASPECT_COMPUTE_PIPELINE, VALIDATION_ASPECT_COMPUTE_PIPELINE,
VALIDATION_ASPECT_BIND_GROUPS, VALIDATION_ASPECT_BIND_GROUPS,
VALIDATION_ASPECT_VERTEX_BUFFERS, VALIDATION_ASPECT_VERTEX_BUFFERS,
VALIDATION_ASPECT_INDEX_BUFFER, VALIDATION_ASPECT_INDEX_BUFFER,
VALIDATION_ASPECT_RENDER_SUBPASS, VALIDATION_ASPECT_RENDER_SUBPASS,
VALIDATION_ASPECT_COMPUTE_PASS, VALIDATION_ASPECT_COMPUTE_PASS,
VALIDATION_ASPECT_COUNT VALIDATION_ASPECT_COUNT
}; };
using ValidationAspects = std::bitset<VALIDATION_ASPECT_COUNT>; using ValidationAspects = std::bitset<VALIDATION_ASPECT_COUNT>;
// Usage helper functions // Usage helper functions
bool BufferHasGuaranteedUsageBit(BufferBase* buffer, nxt::BufferUsageBit usage) const; bool BufferHasGuaranteedUsageBit(BufferBase* buffer, nxt::BufferUsageBit usage) const;
bool TextureHasGuaranteedUsageBit(TextureBase* texture, nxt::TextureUsageBit usage) const; bool TextureHasGuaranteedUsageBit(TextureBase* texture, nxt::TextureUsageBit usage) const;
bool IsInternalTextureTransitionPossible(TextureBase* texture, nxt::TextureUsageBit usage) const; bool IsInternalTextureTransitionPossible(TextureBase* texture,
bool IsExplicitTextureTransitionPossible(TextureBase* texture, nxt::TextureUsageBit usage) const; nxt::TextureUsageBit usage) const;
bool IsExplicitTextureTransitionPossible(TextureBase* texture,
nxt::TextureUsageBit usage) const;
// Queries for lazily evaluated aspects // Queries for lazily evaluated aspects
bool RecomputeHaveAspectBindGroups(); bool RecomputeHaveAspectBindGroups();
bool RecomputeHaveAspectVertexBuffers(); bool RecomputeHaveAspectVertexBuffers();
bool HavePipeline() const; bool HavePipeline() const;
bool ValidateBindGroupUsages(BindGroupBase* group) const; bool ValidateBindGroupUsages(BindGroupBase* group) const;
bool RevalidateCanDraw(); bool RevalidateCanDraw();
void SetPipelineCommon(PipelineBase* pipeline); void SetPipelineCommon(PipelineBase* pipeline);
void UnsetPipeline(); void UnsetPipeline();
CommandBufferBuilder* mBuilder; CommandBufferBuilder* mBuilder;
ValidationAspects mAspects; ValidationAspects mAspects;
std::bitset<kMaxBindGroups> mBindgroupsSet; std::bitset<kMaxBindGroups> mBindgroupsSet;
std::array<BindGroupBase*, kMaxBindGroups> mBindgroups = {}; std::array<BindGroupBase*, kMaxBindGroups> mBindgroups = {};
std::bitset<kMaxVertexInputs> mInputsSet; std::bitset<kMaxVertexInputs> mInputsSet;
PipelineBase* mLastPipeline = nullptr; PipelineBase* mLastPipeline = nullptr;
RenderPipelineBase* mLastRenderPipeline = nullptr; RenderPipelineBase* mLastRenderPipeline = nullptr;
std::map<BufferBase*, nxt::BufferUsageBit> mMostRecentBufferUsages; std::map<BufferBase*, nxt::BufferUsageBit> mMostRecentBufferUsages;
std::map<TextureBase*, nxt::TextureUsageBit> mMostRecentTextureUsages; std::map<TextureBase*, nxt::TextureUsageBit> mMostRecentTextureUsages;
RenderPassBase* mCurrentRenderPass = nullptr; RenderPassBase* mCurrentRenderPass = nullptr;
FramebufferBase* mCurrentFramebuffer = nullptr; FramebufferBase* mCurrentFramebuffer = nullptr;
uint32_t mCurrentSubpass = 0; uint32_t mCurrentSubpass = 0;
}; };
} } // namespace backend
#endif // BACKEND_COMMANDBUFFERSTATETRACKER_H #endif // BACKEND_COMMANDBUFFERSTATETRACKER_H

View File

@ -52,16 +52,14 @@ namespace backend {
TransitionTextureUsage, TransitionTextureUsage,
}; };
struct BeginComputePassCmd { struct BeginComputePassCmd {};
};
struct BeginRenderPassCmd { struct BeginRenderPassCmd {
Ref<RenderPassBase> renderPass; Ref<RenderPassBase> renderPass;
Ref<FramebufferBase> framebuffer; Ref<FramebufferBase> framebuffer;
}; };
struct BeginRenderSubpassCmd { struct BeginRenderSubpassCmd {};
};
struct BufferCopyLocation { struct BufferCopyLocation {
Ref<BufferBase> buffer; Ref<BufferBase> buffer;
@ -113,14 +111,11 @@ namespace backend {
uint32_t firstInstance; uint32_t firstInstance;
}; };
struct EndComputePassCmd { struct EndComputePassCmd {};
};
struct EndRenderPassCmd { struct EndRenderPassCmd {};
};
struct EndRenderSubpassCmd { struct EndRenderSubpassCmd {};
};
struct SetComputePipelineCmd { struct SetComputePipelineCmd {
Ref<ComputePipelineBase> pipeline; Ref<ComputePipelineBase> pipeline;
@ -176,6 +171,6 @@ namespace backend {
void FreeCommands(CommandIterator* commands); void FreeCommands(CommandIterator* commands);
void SkipCommand(CommandIterator* commands, Command type); void SkipCommand(CommandIterator* commands, Command type);
} } // namespace backend
#endif // BACKEND_COMMANDS_H_ #endif // BACKEND_COMMANDS_H_

View File

@ -38,4 +38,4 @@ namespace backend {
return mDevice->CreateComputePipeline(this); return mDevice->CreateComputePipeline(this);
} }
} } // namespace backend

View File

@ -20,19 +20,18 @@
namespace backend { namespace backend {
class ComputePipelineBase : public RefCounted, public PipelineBase { class ComputePipelineBase : public RefCounted, public PipelineBase {
public: public:
ComputePipelineBase(ComputePipelineBuilder* builder); ComputePipelineBase(ComputePipelineBuilder* builder);
}; };
class ComputePipelineBuilder : public Builder<ComputePipelineBase>, public PipelineBuilder { class ComputePipelineBuilder : public Builder<ComputePipelineBase>, public PipelineBuilder {
public: public:
ComputePipelineBuilder(DeviceBase* device); ComputePipelineBuilder(DeviceBase* device);
private: private:
ComputePipelineBase* GetResultImpl() override; ComputePipelineBase* GetResultImpl() override;
}; };
} } // namespace backend
#endif // BACKEND_COMPUTEPIPELINE_H_ #endif // BACKEND_COMPUTEPIPELINE_H_

View File

@ -26,13 +26,13 @@ namespace backend {
bool DepthStencilStateBase::StencilTestEnabled() const { bool DepthStencilStateBase::StencilTestEnabled() const {
return mStencilInfo.back.compareFunction != nxt::CompareFunction::Always || return mStencilInfo.back.compareFunction != nxt::CompareFunction::Always ||
mStencilInfo.back.stencilFail != nxt::StencilOperation::Keep || mStencilInfo.back.stencilFail != nxt::StencilOperation::Keep ||
mStencilInfo.back.depthFail != nxt::StencilOperation::Keep || mStencilInfo.back.depthFail != nxt::StencilOperation::Keep ||
mStencilInfo.back.depthStencilPass != nxt::StencilOperation::Keep || mStencilInfo.back.depthStencilPass != nxt::StencilOperation::Keep ||
mStencilInfo.front.compareFunction != nxt::CompareFunction::Always || mStencilInfo.front.compareFunction != nxt::CompareFunction::Always ||
mStencilInfo.front.stencilFail != nxt::StencilOperation::Keep || mStencilInfo.front.stencilFail != nxt::StencilOperation::Keep ||
mStencilInfo.front.depthFail != nxt::StencilOperation::Keep || mStencilInfo.front.depthFail != nxt::StencilOperation::Keep ||
mStencilInfo.front.depthStencilPass != nxt::StencilOperation::Keep; mStencilInfo.front.depthStencilPass != nxt::StencilOperation::Keep;
} }
const DepthStencilStateBase::DepthInfo& DepthStencilStateBase::GetDepth() const { const DepthStencilStateBase::DepthInfo& DepthStencilStateBase::GetDepth() const {
@ -60,7 +60,8 @@ namespace backend {
return mDevice->CreateDepthStencilState(this); return mDevice->CreateDepthStencilState(this);
} }
void DepthStencilStateBuilder::SetDepthCompareFunction(nxt::CompareFunction depthCompareFunction) { void DepthStencilStateBuilder::SetDepthCompareFunction(
nxt::CompareFunction depthCompareFunction) {
if ((mPropertiesSet & DEPTH_STENCIL_STATE_PROPERTY_DEPTH_COMPARE_FUNCTION) != 0) { if ((mPropertiesSet & DEPTH_STENCIL_STATE_PROPERTY_DEPTH_COMPARE_FUNCTION) != 0) {
HandleError("Depth compare property set multiple times"); HandleError("Depth compare property set multiple times");
return; return;
@ -82,8 +83,11 @@ namespace backend {
mDepthInfo.depthWriteEnabled = enabled; mDepthInfo.depthWriteEnabled = enabled;
} }
void DepthStencilStateBuilder::SetStencilFunction(nxt::Face face, nxt::CompareFunction stencilCompareFunction, void DepthStencilStateBuilder::SetStencilFunction(nxt::Face face,
nxt::StencilOperation stencilFail, nxt::StencilOperation depthFail, nxt::StencilOperation depthStencilPass) {\ nxt::CompareFunction stencilCompareFunction,
nxt::StencilOperation stencilFail,
nxt::StencilOperation depthFail,
nxt::StencilOperation depthStencilPass) {
if (face == nxt::Face::None) { if (face == nxt::Face::None) {
HandleError("Can't set stencil function of None face"); HandleError("Can't set stencil function of None face");
return; return;
@ -118,7 +122,7 @@ namespace backend {
} }
void DepthStencilStateBuilder::SetStencilMask(uint32_t readMask, uint32_t writeMask) { void DepthStencilStateBuilder::SetStencilMask(uint32_t readMask, uint32_t writeMask) {
if ((mPropertiesSet & DEPTH_STENCIL_STATE_PROPERTY_STENCIL_MASK) != 0) { if ((mPropertiesSet & DEPTH_STENCIL_STATE_PROPERTY_STENCIL_MASK) != 0) {
HandleError("Stencilmask property set multiple times"); HandleError("Stencilmask property set multiple times");
return; return;
} }
@ -128,4 +132,4 @@ namespace backend {
mStencilInfo.writeMask = writeMask; mStencilInfo.writeMask = writeMask;
} }
} } // namespace backend

View File

@ -15,69 +15,71 @@
#ifndef BACKEND_DEPTHSTENCILSTATE_H_ #ifndef BACKEND_DEPTHSTENCILSTATE_H_
#define BACKEND_DEPTHSTENCILSTATE_H_ #define BACKEND_DEPTHSTENCILSTATE_H_
#include "backend/Forward.h"
#include "backend/Builder.h" #include "backend/Builder.h"
#include "backend/Forward.h"
#include "backend/RefCounted.h" #include "backend/RefCounted.h"
#include "nxt/nxtcpp.h" #include "nxt/nxtcpp.h"
namespace backend { namespace backend {
class DepthStencilStateBase : public RefCounted { class DepthStencilStateBase : public RefCounted {
public: public:
DepthStencilStateBase(DepthStencilStateBuilder* builder); DepthStencilStateBase(DepthStencilStateBuilder* builder);
struct DepthInfo { struct DepthInfo {
nxt::CompareFunction compareFunction = nxt::CompareFunction::Always; nxt::CompareFunction compareFunction = nxt::CompareFunction::Always;
bool depthWriteEnabled = false; bool depthWriteEnabled = false;
}; };
struct StencilFaceInfo { struct StencilFaceInfo {
nxt::CompareFunction compareFunction = nxt::CompareFunction::Always; nxt::CompareFunction compareFunction = nxt::CompareFunction::Always;
nxt::StencilOperation stencilFail = nxt::StencilOperation::Keep; nxt::StencilOperation stencilFail = nxt::StencilOperation::Keep;
nxt::StencilOperation depthFail = nxt::StencilOperation::Keep; nxt::StencilOperation depthFail = nxt::StencilOperation::Keep;
nxt::StencilOperation depthStencilPass = nxt::StencilOperation::Keep; nxt::StencilOperation depthStencilPass = nxt::StencilOperation::Keep;
}; };
struct StencilInfo { struct StencilInfo {
StencilFaceInfo back; StencilFaceInfo back;
StencilFaceInfo front; StencilFaceInfo front;
uint32_t readMask = 0xff; uint32_t readMask = 0xff;
uint32_t writeMask = 0xff; uint32_t writeMask = 0xff;
}; };
bool StencilTestEnabled() const; bool StencilTestEnabled() const;
const DepthInfo& GetDepth() const; const DepthInfo& GetDepth() const;
const StencilInfo& GetStencil() const; const StencilInfo& GetStencil() const;
private: private:
DepthInfo mDepthInfo; DepthInfo mDepthInfo;
StencilInfo mStencilInfo; StencilInfo mStencilInfo;
}; };
class DepthStencilStateBuilder : public Builder<DepthStencilStateBase> { class DepthStencilStateBuilder : public Builder<DepthStencilStateBase> {
public: public:
DepthStencilStateBuilder(DeviceBase* device); DepthStencilStateBuilder(DeviceBase* device);
// NXT API // NXT API
void SetDepthCompareFunction(nxt::CompareFunction depthCompareFunction); void SetDepthCompareFunction(nxt::CompareFunction depthCompareFunction);
void SetDepthWriteEnabled(bool enabled); void SetDepthWriteEnabled(bool enabled);
void SetStencilFunction(nxt::Face face, nxt::CompareFunction stencilCompareFunction, void SetStencilFunction(nxt::Face face,
nxt::StencilOperation stencilFail, nxt::StencilOperation depthFail, nxt::StencilOperation depthStencilPass); nxt::CompareFunction stencilCompareFunction,
void SetStencilMask(uint32_t readMask, uint32_t writeMask); nxt::StencilOperation stencilFail,
nxt::StencilOperation depthFail,
nxt::StencilOperation depthStencilPass);
void SetStencilMask(uint32_t readMask, uint32_t writeMask);
private: private:
friend class DepthStencilStateBase; friend class DepthStencilStateBase;
DepthStencilStateBase* GetResultImpl() override; DepthStencilStateBase* GetResultImpl() override;
int mPropertiesSet = 0; int mPropertiesSet = 0;
DepthStencilStateBase::DepthInfo mDepthInfo; DepthStencilStateBase::DepthInfo mDepthInfo;
DepthStencilStateBase::StencilInfo mStencilInfo; DepthStencilStateBase::StencilInfo mStencilInfo;
}; };
} } // namespace backend
#endif // BACKEND_DEPTHSTENCILSTATE_H_ #endif // BACKEND_DEPTHSTENCILSTATE_H_

View File

@ -40,7 +40,8 @@ namespace backend {
// The caches are unordered_sets of pointers with special hash and compare functions // The caches are unordered_sets of pointers with special hash and compare functions
// to compare the value of the objects, instead of the pointers. // to compare the value of the objects, instead of the pointers.
using BindGroupLayoutCache = std::unordered_set<BindGroupLayoutBase*, BindGroupLayoutCacheFuncs, BindGroupLayoutCacheFuncs>; using BindGroupLayoutCache = std::
unordered_set<BindGroupLayoutBase*, BindGroupLayoutCacheFuncs, BindGroupLayoutCacheFuncs>;
struct DeviceBase::Caches { struct DeviceBase::Caches {
BindGroupLayoutCache bindGroupLayouts; BindGroupLayoutCache bindGroupLayouts;
@ -62,7 +63,8 @@ namespace backend {
} }
} }
void DeviceBase::SetErrorCallback(nxt::DeviceErrorCallback callback, nxt::CallbackUserdata userdata) { void DeviceBase::SetErrorCallback(nxt::DeviceErrorCallback callback,
nxt::CallbackUserdata userdata) {
mErrorCallback = callback; mErrorCallback = callback;
mErrorUserdata = userdata; mErrorUserdata = userdata;
} }
@ -71,7 +73,9 @@ namespace backend {
return this; return this;
} }
BindGroupLayoutBase* DeviceBase::GetOrCreateBindGroupLayout(const BindGroupLayoutBase* blueprint, BindGroupLayoutBuilder* builder) { BindGroupLayoutBase* DeviceBase::GetOrCreateBindGroupLayout(
const BindGroupLayoutBase* blueprint,
BindGroupLayoutBuilder* builder) {
// The blueprint is only used to search in the cache and is not modified. However cached // The blueprint is only used to search in the cache and is not modified. However cached
// objects can be modified, and unordered_set cannot search for a const pointer in a non // objects can be modified, and unordered_set cannot search for a const pointer in a non
// const pointer set. That's why we do a const_cast here, but the blueprint won't be // const pointer set. That's why we do a const_cast here, but the blueprint won't be
@ -159,4 +163,4 @@ namespace backend {
} }
} }
} } // namespace backend

View File

@ -25,89 +25,91 @@ namespace backend {
using ErrorCallback = void (*)(const char* errorMessage, void* userData); using ErrorCallback = void (*)(const char* errorMessage, void* userData);
class DeviceBase { class DeviceBase {
public: public:
DeviceBase(); DeviceBase();
virtual ~DeviceBase(); virtual ~DeviceBase();
void HandleError(const char* message); void HandleError(const char* message);
// Used by autogenerated code, returns itself // Used by autogenerated code, returns itself
DeviceBase* GetDevice(); DeviceBase* GetDevice();
virtual BindGroupBase* CreateBindGroup(BindGroupBuilder* builder) = 0; virtual BindGroupBase* CreateBindGroup(BindGroupBuilder* builder) = 0;
virtual BindGroupLayoutBase* CreateBindGroupLayout(BindGroupLayoutBuilder* builder) = 0; virtual BindGroupLayoutBase* CreateBindGroupLayout(BindGroupLayoutBuilder* builder) = 0;
virtual BlendStateBase* CreateBlendState(BlendStateBuilder* builder) = 0; virtual BlendStateBase* CreateBlendState(BlendStateBuilder* builder) = 0;
virtual BufferBase* CreateBuffer(BufferBuilder* builder) = 0; virtual BufferBase* CreateBuffer(BufferBuilder* builder) = 0;
virtual BufferViewBase* CreateBufferView(BufferViewBuilder* builder) = 0; virtual BufferViewBase* CreateBufferView(BufferViewBuilder* builder) = 0;
virtual CommandBufferBase* CreateCommandBuffer(CommandBufferBuilder* builder) = 0; virtual CommandBufferBase* CreateCommandBuffer(CommandBufferBuilder* builder) = 0;
virtual ComputePipelineBase* CreateComputePipeline(ComputePipelineBuilder* builder) = 0; virtual ComputePipelineBase* CreateComputePipeline(ComputePipelineBuilder* builder) = 0;
virtual DepthStencilStateBase* CreateDepthStencilState(DepthStencilStateBuilder* builder) = 0; virtual DepthStencilStateBase* CreateDepthStencilState(
virtual FramebufferBase* CreateFramebuffer(FramebufferBuilder* builder) = 0; DepthStencilStateBuilder* builder) = 0;
virtual InputStateBase* CreateInputState(InputStateBuilder* builder) = 0; virtual FramebufferBase* CreateFramebuffer(FramebufferBuilder* builder) = 0;
virtual PipelineLayoutBase* CreatePipelineLayout(PipelineLayoutBuilder* builder) = 0; virtual InputStateBase* CreateInputState(InputStateBuilder* builder) = 0;
virtual QueueBase* CreateQueue(QueueBuilder* builder) = 0; virtual PipelineLayoutBase* CreatePipelineLayout(PipelineLayoutBuilder* builder) = 0;
virtual RenderPassBase* CreateRenderPass(RenderPassBuilder* builder) = 0; virtual QueueBase* CreateQueue(QueueBuilder* builder) = 0;
virtual RenderPipelineBase* CreateRenderPipeline(RenderPipelineBuilder* builder) = 0; virtual RenderPassBase* CreateRenderPass(RenderPassBuilder* builder) = 0;
virtual SamplerBase* CreateSampler(SamplerBuilder* builder) = 0; virtual RenderPipelineBase* CreateRenderPipeline(RenderPipelineBuilder* builder) = 0;
virtual ShaderModuleBase* CreateShaderModule(ShaderModuleBuilder* builder) = 0; virtual SamplerBase* CreateSampler(SamplerBuilder* builder) = 0;
virtual SwapChainBase* CreateSwapChain(SwapChainBuilder* builder) = 0; virtual ShaderModuleBase* CreateShaderModule(ShaderModuleBuilder* builder) = 0;
virtual TextureBase* CreateTexture(TextureBuilder* builder) = 0; virtual SwapChainBase* CreateSwapChain(SwapChainBuilder* builder) = 0;
virtual TextureViewBase* CreateTextureView(TextureViewBuilder* builder) = 0; virtual TextureBase* CreateTexture(TextureBuilder* builder) = 0;
virtual TextureViewBase* CreateTextureView(TextureViewBuilder* builder) = 0;
virtual void TickImpl() = 0; virtual void TickImpl() = 0;
// Many NXT objects are completely immutable once created which means that if two // Many NXT objects are completely immutable once created which means that if two
// builders are given the same arguments, they can return the same object. Reusing // builders are given the same arguments, they can return the same object. Reusing
// objects will help make comparisons between objects by a single pointer comparison. // objects will help make comparisons between objects by a single pointer comparison.
// //
// Technically no object is immutable as they have a reference count, and an // Technically no object is immutable as they have a reference count, and an
// application with reference-counting issues could "see" that objects are reused. // application with reference-counting issues could "see" that objects are reused.
// This is solved by automatic-reference counting, and also the fact that when using // This is solved by automatic-reference counting, and also the fact that when using
// the client-server wire every creation will get a different proxy object, with a // the client-server wire every creation will get a different proxy object, with a
// different reference count. // different reference count.
// //
// When trying to create an object, we give both the builder and an example of what // When trying to create an object, we give both the builder and an example of what
// the built object will be, the "blueprint". The blueprint is just a FooBase object // the built object will be, the "blueprint". The blueprint is just a FooBase object
// instead of a backend Foo object. If the blueprint doesn't match an object in the // instead of a backend Foo object. If the blueprint doesn't match an object in the
// cache, then the builder is used to make a new object. // cache, then the builder is used to make a new object.
BindGroupLayoutBase* GetOrCreateBindGroupLayout(const BindGroupLayoutBase* blueprint, BindGroupLayoutBuilder* builder); BindGroupLayoutBase* GetOrCreateBindGroupLayout(const BindGroupLayoutBase* blueprint,
void UncacheBindGroupLayout(BindGroupLayoutBase* obj); BindGroupLayoutBuilder* builder);
void UncacheBindGroupLayout(BindGroupLayoutBase* obj);
// NXT API // NXT API
BindGroupBuilder* CreateBindGroupBuilder(); BindGroupBuilder* CreateBindGroupBuilder();
BindGroupLayoutBuilder* CreateBindGroupLayoutBuilder(); BindGroupLayoutBuilder* CreateBindGroupLayoutBuilder();
BlendStateBuilder* CreateBlendStateBuilder(); BlendStateBuilder* CreateBlendStateBuilder();
BufferBuilder* CreateBufferBuilder(); BufferBuilder* CreateBufferBuilder();
CommandBufferBuilder* CreateCommandBufferBuilder(); CommandBufferBuilder* CreateCommandBufferBuilder();
ComputePipelineBuilder* CreateComputePipelineBuilder(); ComputePipelineBuilder* CreateComputePipelineBuilder();
DepthStencilStateBuilder* CreateDepthStencilStateBuilder(); DepthStencilStateBuilder* CreateDepthStencilStateBuilder();
FramebufferBuilder* CreateFramebufferBuilder(); FramebufferBuilder* CreateFramebufferBuilder();
InputStateBuilder* CreateInputStateBuilder(); InputStateBuilder* CreateInputStateBuilder();
PipelineLayoutBuilder* CreatePipelineLayoutBuilder(); PipelineLayoutBuilder* CreatePipelineLayoutBuilder();
QueueBuilder* CreateQueueBuilder(); QueueBuilder* CreateQueueBuilder();
RenderPassBuilder* CreateRenderPassBuilder(); RenderPassBuilder* CreateRenderPassBuilder();
RenderPipelineBuilder* CreateRenderPipelineBuilder(); RenderPipelineBuilder* CreateRenderPipelineBuilder();
SamplerBuilder* CreateSamplerBuilder(); SamplerBuilder* CreateSamplerBuilder();
ShaderModuleBuilder* CreateShaderModuleBuilder(); ShaderModuleBuilder* CreateShaderModuleBuilder();
SwapChainBuilder* CreateSwapChainBuilder(); SwapChainBuilder* CreateSwapChainBuilder();
TextureBuilder* CreateTextureBuilder(); TextureBuilder* CreateTextureBuilder();
void Tick(); void Tick();
void SetErrorCallback(nxt::DeviceErrorCallback callback, nxt::CallbackUserdata userdata); void SetErrorCallback(nxt::DeviceErrorCallback callback, nxt::CallbackUserdata userdata);
void Reference(); void Reference();
void Release(); void Release();
private: private:
// The object caches aren't exposed in the header as they would require a lot of // The object caches aren't exposed in the header as they would require a lot of
// additional includes. // additional includes.
struct Caches; struct Caches;
Caches* mCaches = nullptr; Caches* mCaches = nullptr;
nxt::DeviceErrorCallback mErrorCallback = nullptr; nxt::DeviceErrorCallback mErrorCallback = nullptr;
nxt::CallbackUserdata mErrorUserdata = 0; nxt::CallbackUserdata mErrorUserdata = 0;
uint32_t mRefCount = 1; uint32_t mRefCount = 1;
}; };
} } // namespace backend
#endif // BACKEND_DEVICEBASE_H_ #endif // BACKEND_DEVICEBASE_H_

View File

@ -60,13 +60,13 @@ namespace backend {
class DeviceBase; class DeviceBase;
template<typename T> template <typename T>
class Ref; class Ref;
template<typename T> template <typename T>
class PerStage; class PerStage;
enum PushConstantType : uint8_t; enum PushConstantType : uint8_t;
} } // namespace backend
#endif // BACKEND_FORWARD_H_ #endif // BACKEND_FORWARD_H_

View File

@ -25,9 +25,13 @@ namespace backend {
// Framebuffer // Framebuffer
FramebufferBase::FramebufferBase(FramebufferBuilder* builder) FramebufferBase::FramebufferBase(FramebufferBuilder* builder)
: mDevice(builder->mDevice), mRenderPass(std::move(builder->mRenderPass)), : mDevice(builder->mDevice),
mWidth(builder->mWidth), mHeight(builder->mHeight), mTextureViews(std::move(builder->mTextureViews)), mRenderPass(std::move(builder->mRenderPass)),
mClearColors(mTextureViews.size()), mClearDepthStencils(mTextureViews.size()) { mWidth(builder->mWidth),
mHeight(builder->mHeight),
mTextureViews(std::move(builder->mTextureViews)),
mClearColors(mTextureViews.size()),
mClearDepthStencils(mTextureViews.size()) {
} }
DeviceBase* FramebufferBase::GetDevice() { DeviceBase* FramebufferBase::GetDevice() {
@ -48,7 +52,8 @@ namespace backend {
return mClearColors[attachmentSlot]; return mClearColors[attachmentSlot];
} }
FramebufferBase::ClearDepthStencil FramebufferBase::GetClearDepthStencil(uint32_t attachmentSlot) { FramebufferBase::ClearDepthStencil FramebufferBase::GetClearDepthStencil(
uint32_t attachmentSlot) {
ASSERT(attachmentSlot < mClearDepthStencils.size()); ASSERT(attachmentSlot < mClearDepthStencils.size());
return mClearDepthStencils[attachmentSlot]; return mClearDepthStencils[attachmentSlot];
} }
@ -61,7 +66,11 @@ namespace backend {
return mHeight; return mHeight;
} }
void FramebufferBase::AttachmentSetClearColor(uint32_t attachmentSlot, float clearR, float clearG, float clearB, float clearA) { void FramebufferBase::AttachmentSetClearColor(uint32_t attachmentSlot,
float clearR,
float clearG,
float clearB,
float clearA) {
if (attachmentSlot >= mRenderPass->GetAttachmentCount()) { if (attachmentSlot >= mRenderPass->GetAttachmentCount()) {
mDevice->HandleError("Framebuffer attachment out of bounds"); mDevice->HandleError("Framebuffer attachment out of bounds");
return; return;
@ -74,7 +83,9 @@ namespace backend {
c.color[3] = clearA; c.color[3] = clearA;
} }
void FramebufferBase::AttachmentSetClearDepthStencil(uint32_t attachmentSlot, float clearDepth, uint32_t clearStencil) { void FramebufferBase::AttachmentSetClearDepthStencil(uint32_t attachmentSlot,
float clearDepth,
uint32_t clearStencil) {
if (attachmentSlot >= mRenderPass->GetAttachmentCount()) { if (attachmentSlot >= mRenderPass->GetAttachmentCount()) {
mDevice->HandleError("Framebuffer attachment out of bounds"); mDevice->HandleError("Framebuffer attachment out of bounds");
return; return;
@ -92,12 +103,12 @@ namespace backend {
FRAMEBUFFER_PROPERTY_DIMENSIONS = 0x2, FRAMEBUFFER_PROPERTY_DIMENSIONS = 0x2,
}; };
FramebufferBuilder::FramebufferBuilder(DeviceBase* device) FramebufferBuilder::FramebufferBuilder(DeviceBase* device) : Builder(device) {
: Builder(device) {
} }
FramebufferBase* FramebufferBuilder::GetResultImpl() { FramebufferBase* FramebufferBuilder::GetResultImpl() {
constexpr int requiredProperties = FRAMEBUFFER_PROPERTY_RENDER_PASS | FRAMEBUFFER_PROPERTY_DIMENSIONS; constexpr int requiredProperties =
FRAMEBUFFER_PROPERTY_RENDER_PASS | FRAMEBUFFER_PROPERTY_DIMENSIONS;
if ((mPropertiesSet & requiredProperties) != requiredProperties) { if ((mPropertiesSet & requiredProperties) != requiredProperties) {
HandleError("Framebuffer missing properties"); HandleError("Framebuffer missing properties");
return nullptr; return nullptr;
@ -170,4 +181,4 @@ namespace backend {
mTextureViews[attachmentSlot] = textureView; mTextureViews[attachmentSlot] = textureView;
} }
} } // namespace backend

View File

@ -27,60 +27,66 @@
namespace backend { namespace backend {
class FramebufferBase : public RefCounted { class FramebufferBase : public RefCounted {
public: public:
struct ClearColor { struct ClearColor {
float color[4] = {}; float color[4] = {};
}; };
struct ClearDepthStencil { struct ClearDepthStencil {
float depth = 1.0f; float depth = 1.0f;
uint32_t stencil = 0; uint32_t stencil = 0;
}; };
FramebufferBase(FramebufferBuilder* builder); FramebufferBase(FramebufferBuilder* builder);
DeviceBase* GetDevice(); DeviceBase* GetDevice();
RenderPassBase* GetRenderPass(); RenderPassBase* GetRenderPass();
TextureViewBase* GetTextureView(uint32_t attachmentSlot); TextureViewBase* GetTextureView(uint32_t attachmentSlot);
ClearColor GetClearColor(uint32_t attachmentSlot); ClearColor GetClearColor(uint32_t attachmentSlot);
ClearDepthStencil GetClearDepthStencil(uint32_t attachmentSlot); ClearDepthStencil GetClearDepthStencil(uint32_t attachmentSlot);
uint32_t GetWidth() const; uint32_t GetWidth() const;
uint32_t GetHeight() const; uint32_t GetHeight() const;
// NXT API // NXT API
void AttachmentSetClearColor(uint32_t attachmentSlot, float clearR, float clearG, float clearB, float clearA); void AttachmentSetClearColor(uint32_t attachmentSlot,
void AttachmentSetClearDepthStencil(uint32_t attachmentSlot, float clearDepth, uint32_t clearStencil); float clearR,
float clearG,
float clearB,
float clearA);
void AttachmentSetClearDepthStencil(uint32_t attachmentSlot,
float clearDepth,
uint32_t clearStencil);
private: private:
DeviceBase* mDevice; DeviceBase* mDevice;
Ref<RenderPassBase> mRenderPass; Ref<RenderPassBase> mRenderPass;
uint32_t mWidth = 0; uint32_t mWidth = 0;
uint32_t mHeight = 0; uint32_t mHeight = 0;
std::vector<Ref<TextureViewBase>> mTextureViews; std::vector<Ref<TextureViewBase>> mTextureViews;
std::vector<ClearColor> mClearColors; std::vector<ClearColor> mClearColors;
std::vector<ClearDepthStencil> mClearDepthStencils; std::vector<ClearDepthStencil> mClearDepthStencils;
}; };
class FramebufferBuilder : public Builder<FramebufferBase> { class FramebufferBuilder : public Builder<FramebufferBase> {
public: public:
FramebufferBuilder(DeviceBase* device); FramebufferBuilder(DeviceBase* device);
// NXT API // NXT API
FramebufferBase* GetResultImpl() override; FramebufferBase* GetResultImpl() override;
void SetRenderPass(RenderPassBase* renderPass); void SetRenderPass(RenderPassBase* renderPass);
void SetDimensions(uint32_t width, uint32_t height); void SetDimensions(uint32_t width, uint32_t height);
void SetAttachment(uint32_t attachmentSlot, TextureViewBase* textureView); void SetAttachment(uint32_t attachmentSlot, TextureViewBase* textureView);
private: private:
friend class FramebufferBase; friend class FramebufferBase;
Ref<RenderPassBase> mRenderPass; Ref<RenderPassBase> mRenderPass;
uint32_t mWidth = 0; uint32_t mWidth = 0;
uint32_t mHeight = 0; uint32_t mHeight = 0;
std::vector<Ref<TextureViewBase>> mTextureViews; std::vector<Ref<TextureViewBase>> mTextureViews;
int mPropertiesSet = 0; int mPropertiesSet = 0;
}; };
} } // namespace backend
#endif // BACKEND_FRAMEBUFFER_H_ #endif // BACKEND_FRAMEBUFFER_H_

View File

@ -94,7 +94,7 @@ namespace backend {
InputStateBase* InputStateBuilder::GetResultImpl() { InputStateBase* InputStateBuilder::GetResultImpl() {
for (uint32_t location = 0; location < kMaxVertexAttributes; ++location) { for (uint32_t location = 0; location < kMaxVertexAttributes; ++location) {
if (mAttributesSetMask[location] && if (mAttributesSetMask[location] &&
!mInputsSetMask[mAttributeInfos[location].bindingSlot]) { !mInputsSetMask[mAttributeInfos[location].bindingSlot]) {
HandleError("Attribute uses unset input"); HandleError("Attribute uses unset input");
return nullptr; return nullptr;
} }
@ -104,7 +104,9 @@ namespace backend {
} }
void InputStateBuilder::SetAttribute(uint32_t shaderLocation, void InputStateBuilder::SetAttribute(uint32_t shaderLocation,
uint32_t bindingSlot, nxt::VertexFormat format, uint32_t offset) { uint32_t bindingSlot,
nxt::VertexFormat format,
uint32_t offset) {
if (shaderLocation >= kMaxVertexAttributes) { if (shaderLocation >= kMaxVertexAttributes) {
HandleError("Setting attribute out of bounds"); HandleError("Setting attribute out of bounds");
return; return;
@ -125,8 +127,9 @@ namespace backend {
info.offset = offset; info.offset = offset;
} }
void InputStateBuilder::SetInput(uint32_t bindingSlot, uint32_t stride, void InputStateBuilder::SetInput(uint32_t bindingSlot,
nxt::InputStepMode stepMode) { uint32_t stride,
nxt::InputStepMode stepMode) {
if (bindingSlot >= kMaxVertexInputs) { if (bindingSlot >= kMaxVertexInputs) {
HandleError("Setting input out of bounds"); HandleError("Setting input out of bounds");
return; return;
@ -142,4 +145,4 @@ namespace backend {
info.stepMode = stepMode; info.stepMode = stepMode;
} }
} } // namespace backend

View File

@ -15,8 +15,8 @@
#ifndef BACKEND_INPUTSTATE_H_ #ifndef BACKEND_INPUTSTATE_H_
#define BACKEND_INPUTSTATE_H_ #define BACKEND_INPUTSTATE_H_
#include "backend/Forward.h"
#include "backend/Builder.h" #include "backend/Builder.h"
#include "backend/Forward.h"
#include "backend/RefCounted.h" #include "backend/RefCounted.h"
#include "common/Constants.h" #include "common/Constants.h"
@ -32,53 +32,54 @@ namespace backend {
size_t VertexFormatSize(nxt::VertexFormat format); size_t VertexFormatSize(nxt::VertexFormat format);
class InputStateBase : public RefCounted { class InputStateBase : public RefCounted {
public: public:
InputStateBase(InputStateBuilder* builder); InputStateBase(InputStateBuilder* builder);
struct AttributeInfo { struct AttributeInfo {
uint32_t bindingSlot; uint32_t bindingSlot;
nxt::VertexFormat format; nxt::VertexFormat format;
uint32_t offset; uint32_t offset;
}; };
struct InputInfo { struct InputInfo {
uint32_t stride; uint32_t stride;
nxt::InputStepMode stepMode; nxt::InputStepMode stepMode;
}; };
const std::bitset<kMaxVertexAttributes>& GetAttributesSetMask() const; const std::bitset<kMaxVertexAttributes>& GetAttributesSetMask() const;
const AttributeInfo& GetAttribute(uint32_t location) const; const AttributeInfo& GetAttribute(uint32_t location) const;
const std::bitset<kMaxVertexInputs>& GetInputsSetMask() const; const std::bitset<kMaxVertexInputs>& GetInputsSetMask() const;
const InputInfo& GetInput(uint32_t slot) const; const InputInfo& GetInput(uint32_t slot) const;
private: private:
std::bitset<kMaxVertexAttributes> mAttributesSetMask; std::bitset<kMaxVertexAttributes> mAttributesSetMask;
std::array<AttributeInfo, kMaxVertexAttributes> mAttributeInfos; std::array<AttributeInfo, kMaxVertexAttributes> mAttributeInfos;
std::bitset<kMaxVertexInputs> mInputsSetMask; std::bitset<kMaxVertexInputs> mInputsSetMask;
std::array<InputInfo, kMaxVertexInputs> mInputInfos; std::array<InputInfo, kMaxVertexInputs> mInputInfos;
}; };
class InputStateBuilder : public Builder<InputStateBase> { class InputStateBuilder : public Builder<InputStateBase> {
public: public:
InputStateBuilder(DeviceBase* device); InputStateBuilder(DeviceBase* device);
// NXT API // NXT API
void SetAttribute(uint32_t shaderLocation, uint32_t bindingSlot, void SetAttribute(uint32_t shaderLocation,
nxt::VertexFormat format, uint32_t offset); uint32_t bindingSlot,
void SetInput(uint32_t bindingSlot, uint32_t stride, nxt::VertexFormat format,
nxt::InputStepMode stepMode); uint32_t offset);
void SetInput(uint32_t bindingSlot, uint32_t stride, nxt::InputStepMode stepMode);
private: private:
friend class InputStateBase; friend class InputStateBase;
InputStateBase* GetResultImpl() override; InputStateBase* GetResultImpl() override;
std::bitset<kMaxVertexAttributes> mAttributesSetMask; std::bitset<kMaxVertexAttributes> mAttributesSetMask;
std::array<InputStateBase::AttributeInfo, kMaxVertexAttributes> mAttributeInfos; std::array<InputStateBase::AttributeInfo, kMaxVertexAttributes> mAttributeInfos;
std::bitset<kMaxVertexInputs> mInputsSetMask; std::bitset<kMaxVertexInputs> mInputsSetMask;
std::array<InputStateBase::InputInfo, kMaxVertexInputs> mInputInfos; std::array<InputStateBase::InputInfo, kMaxVertexInputs> mInputInfos;
}; };
} } // namespace backend
#endif // BACKEND_INPUTSTATE_H_ #endif // BACKEND_INPUTSTATE_H_

View File

@ -26,4 +26,4 @@ namespace backend {
return static_cast<nxt::ShaderStageBit>(1 << static_cast<uint32_t>(stage)); return static_cast<nxt::ShaderStageBit>(1 << static_cast<uint32_t>(stage));
} }
} } // namespace backend

View File

@ -29,42 +29,49 @@ namespace backend {
static_assert(static_cast<uint32_t>(nxt::ShaderStage::Fragment) < kNumStages, ""); static_assert(static_cast<uint32_t>(nxt::ShaderStage::Fragment) < kNumStages, "");
static_assert(static_cast<uint32_t>(nxt::ShaderStage::Compute) < kNumStages, ""); static_assert(static_cast<uint32_t>(nxt::ShaderStage::Compute) < kNumStages, "");
static_assert(static_cast<uint32_t>(nxt::ShaderStageBit::Vertex) == (1 << static_cast<uint32_t>(nxt::ShaderStage::Vertex)), ""); static_assert(static_cast<uint32_t>(nxt::ShaderStageBit::Vertex) ==
static_assert(static_cast<uint32_t>(nxt::ShaderStageBit::Fragment) == (1 << static_cast<uint32_t>(nxt::ShaderStage::Fragment)), ""); (1 << static_cast<uint32_t>(nxt::ShaderStage::Vertex)),
static_assert(static_cast<uint32_t>(nxt::ShaderStageBit::Compute) == (1 << static_cast<uint32_t>(nxt::ShaderStage::Compute)), ""); "");
static_assert(static_cast<uint32_t>(nxt::ShaderStageBit::Fragment) ==
(1 << static_cast<uint32_t>(nxt::ShaderStage::Fragment)),
"");
static_assert(static_cast<uint32_t>(nxt::ShaderStageBit::Compute) ==
(1 << static_cast<uint32_t>(nxt::ShaderStage::Compute)),
"");
BitSetIterator<kNumStages, nxt::ShaderStage> IterateStages(nxt::ShaderStageBit stages); BitSetIterator<kNumStages, nxt::ShaderStage> IterateStages(nxt::ShaderStageBit stages);
nxt::ShaderStageBit StageBit(nxt::ShaderStage stage); nxt::ShaderStageBit StageBit(nxt::ShaderStage stage);
static constexpr nxt::ShaderStageBit kAllStages = static_cast<nxt::ShaderStageBit>((1 << kNumStages) - 1); static constexpr nxt::ShaderStageBit kAllStages =
static_cast<nxt::ShaderStageBit>((1 << kNumStages) - 1);
template<typename T> template <typename T>
class PerStage { class PerStage {
public: public:
T& operator[](nxt::ShaderStage stage) { T& operator[](nxt::ShaderStage stage) {
NXT_ASSERT(static_cast<uint32_t>(stage) < kNumStages); NXT_ASSERT(static_cast<uint32_t>(stage) < kNumStages);
return mData[static_cast<uint32_t>(stage)]; return mData[static_cast<uint32_t>(stage)];
} }
const T& operator[](nxt::ShaderStage stage) const { const T& operator[](nxt::ShaderStage stage) const {
NXT_ASSERT(static_cast<uint32_t>(stage) < kNumStages); NXT_ASSERT(static_cast<uint32_t>(stage) < kNumStages);
return mData[static_cast<uint32_t>(stage)]; return mData[static_cast<uint32_t>(stage)];
} }
T& operator[](nxt::ShaderStageBit stageBit) { T& operator[](nxt::ShaderStageBit stageBit) {
uint32_t bit = static_cast<uint32_t>(stageBit); uint32_t bit = static_cast<uint32_t>(stageBit);
NXT_ASSERT(bit != 0 && IsPowerOfTwo(bit) && bit <= (1 << kNumStages)); NXT_ASSERT(bit != 0 && IsPowerOfTwo(bit) && bit <= (1 << kNumStages));
return mData[Log2(bit)]; return mData[Log2(bit)];
} }
const T& operator[](nxt::ShaderStageBit stageBit) const { const T& operator[](nxt::ShaderStageBit stageBit) const {
uint32_t bit = static_cast<uint32_t>(stageBit); uint32_t bit = static_cast<uint32_t>(stageBit);
NXT_ASSERT(bit != 0 && IsPowerOfTwo(bit) && bit <= (1 << kNumStages)); NXT_ASSERT(bit != 0 && IsPowerOfTwo(bit) && bit <= (1 << kNumStages));
return mData[Log2(bit)]; return mData[Log2(bit)];
} }
private: private:
std::array<T, kNumStages> mData; std::array<T, kNumStages> mData;
}; };
} } // namespace backend
#endif // BACKEND_PERSTAGE_H_ #endif // BACKEND_PERSTAGE_H_

View File

@ -14,8 +14,8 @@
#include "backend/Pipeline.h" #include "backend/Pipeline.h"
#include "backend/Device.h"
#include "backend/DepthStencilState.h" #include "backend/DepthStencilState.h"
#include "backend/Device.h"
#include "backend/InputState.h" #include "backend/InputState.h"
#include "backend/PipelineLayout.h" #include "backend/PipelineLayout.h"
#include "backend/RenderPass.h" #include "backend/RenderPass.h"
@ -28,7 +28,10 @@ namespace backend {
PipelineBase::PipelineBase(PipelineBuilder* builder) PipelineBase::PipelineBase(PipelineBuilder* builder)
: mStageMask(builder->mStageMask), mLayout(std::move(builder->mLayout)) { : mStageMask(builder->mStageMask), mLayout(std::move(builder->mLayout)) {
if (!mLayout) { if (!mLayout) {
mLayout = builder->GetParentBuilder()->GetDevice()->CreatePipelineLayoutBuilder()->GetResult(); mLayout = builder->GetParentBuilder()
->GetDevice()
->CreatePipelineLayoutBuilder()
->GetResult();
} }
auto FillPushConstants = [](const ShaderModuleBase* module, PushConstantInfo* info) { auto FillPushConstants = [](const ShaderModuleBase* module, PushConstantInfo* info) {
@ -58,7 +61,8 @@ namespace backend {
} }
} }
const PipelineBase::PushConstantInfo& PipelineBase::GetPushConstants(nxt::ShaderStage stage) const { const PipelineBase::PushConstantInfo& PipelineBase::GetPushConstants(
nxt::ShaderStage stage) const {
return mPushConstants[stage]; return mPushConstants[stage];
} }
@ -89,7 +93,9 @@ namespace backend {
mLayout = layout; mLayout = layout;
} }
void PipelineBuilder::SetStage(nxt::ShaderStage stage, ShaderModuleBase* module, const char* entryPoint) { void PipelineBuilder::SetStage(nxt::ShaderStage stage,
ShaderModuleBase* module,
const char* entryPoint) {
if (entryPoint != std::string("main")) { if (entryPoint != std::string("main")) {
mParentBuilder->HandleError("Currently the entry point has to be main()"); mParentBuilder->HandleError("Currently the entry point has to be main()");
return; return;
@ -111,4 +117,4 @@ namespace backend {
mStages[stage].entryPoint = entryPoint; mStages[stage].entryPoint = entryPoint;
} }
} } // namespace backend

View File

@ -15,8 +15,8 @@
#ifndef BACKEND_PIPELINE_H_ #ifndef BACKEND_PIPELINE_H_
#define BACKEND_PIPELINE_H_ #define BACKEND_PIPELINE_H_
#include "backend/Forward.h"
#include "backend/Builder.h" #include "backend/Builder.h"
#include "backend/Forward.h"
#include "backend/PerStage.h" #include "backend/PerStage.h"
#include "backend/PipelineLayout.h" #include "backend/PipelineLayout.h"
#include "backend/RefCounted.h" #include "backend/RefCounted.h"
@ -38,48 +38,48 @@ namespace backend {
class PipelineBuilder; class PipelineBuilder;
class PipelineBase { class PipelineBase {
public: public:
PipelineBase(PipelineBuilder* builder); PipelineBase(PipelineBuilder* builder);
struct PushConstantInfo { struct PushConstantInfo {
std::bitset<kMaxPushConstants> mask; std::bitset<kMaxPushConstants> mask;
std::array<PushConstantType, kMaxPushConstants> types; std::array<PushConstantType, kMaxPushConstants> types;
}; };
const PushConstantInfo& GetPushConstants(nxt::ShaderStage stage) const; const PushConstantInfo& GetPushConstants(nxt::ShaderStage stage) const;
nxt::ShaderStageBit GetStageMask() const; nxt::ShaderStageBit GetStageMask() const;
PipelineLayoutBase* GetLayout(); PipelineLayoutBase* GetLayout();
private: private:
nxt::ShaderStageBit mStageMask; nxt::ShaderStageBit mStageMask;
Ref<PipelineLayoutBase> mLayout; Ref<PipelineLayoutBase> mLayout;
PerStage<PushConstantInfo> mPushConstants; PerStage<PushConstantInfo> mPushConstants;
}; };
class PipelineBuilder { class PipelineBuilder {
public: public:
PipelineBuilder(BuilderBase* parentBuilder); PipelineBuilder(BuilderBase* parentBuilder);
struct StageInfo { struct StageInfo {
std::string entryPoint; std::string entryPoint;
Ref<ShaderModuleBase> module; Ref<ShaderModuleBase> module;
}; };
const StageInfo& GetStageInfo(nxt::ShaderStage stage) const; const StageInfo& GetStageInfo(nxt::ShaderStage stage) const;
BuilderBase* GetParentBuilder() const; BuilderBase* GetParentBuilder() const;
// NXT API // NXT API
void SetLayout(PipelineLayoutBase* layout); void SetLayout(PipelineLayoutBase* layout);
void SetStage(nxt::ShaderStage stage, ShaderModuleBase* module, const char* entryPoint); void SetStage(nxt::ShaderStage stage, ShaderModuleBase* module, const char* entryPoint);
private: private:
friend class PipelineBase; friend class PipelineBase;
BuilderBase* mParentBuilder; BuilderBase* mParentBuilder;
Ref<PipelineLayoutBase> mLayout; Ref<PipelineLayoutBase> mLayout;
nxt::ShaderStageBit mStageMask; nxt::ShaderStageBit mStageMask;
PerStage<StageInfo> mStages; PerStage<StageInfo> mStages;
}; };
} } // namespace backend
#endif // BACKEND_PIPELINE_H_ #endif // BACKEND_PIPELINE_H_

View File

@ -35,8 +35,9 @@ namespace backend {
return mMask; return mMask;
} }
std::bitset<kMaxBindGroups> PipelineLayoutBase::InheritedGroupsMask(const PipelineLayoutBase* other) const { std::bitset<kMaxBindGroups> PipelineLayoutBase::InheritedGroupsMask(
return { GroupsInheritUpTo(other) - 1 }; const PipelineLayoutBase* other) const {
return {GroupsInheritUpTo(other) - 1};
} }
uint32_t PipelineLayoutBase::GroupsInheritUpTo(const PipelineLayoutBase* other) const { uint32_t PipelineLayoutBase::GroupsInheritUpTo(const PipelineLayoutBase* other) const {
@ -54,8 +55,8 @@ namespace backend {
} }
PipelineLayoutBase* PipelineLayoutBuilder::GetResultImpl() { PipelineLayoutBase* PipelineLayoutBuilder::GetResultImpl() {
// TODO(cwallez@chromium.org): this is a hack, have the null bind group layout somewhere in the device // TODO(cwallez@chromium.org): this is a hack, have the null bind group layout somewhere in
// once we have a cache of BGL // the device once we have a cache of BGL
for (size_t group = 0; group < kMaxBindGroups; ++group) { for (size_t group = 0; group < kMaxBindGroups; ++group) {
if (!mBindGroupLayouts[group]) { if (!mBindGroupLayouts[group]) {
mBindGroupLayouts[group] = mDevice->CreateBindGroupLayoutBuilder()->GetResult(); mBindGroupLayouts[group] = mDevice->CreateBindGroupLayoutBuilder()->GetResult();
@ -65,7 +66,8 @@ namespace backend {
return mDevice->CreatePipelineLayout(this); return mDevice->CreatePipelineLayout(this);
} }
void PipelineLayoutBuilder::SetBindGroupLayout(uint32_t groupIndex, BindGroupLayoutBase* layout) { void PipelineLayoutBuilder::SetBindGroupLayout(uint32_t groupIndex,
BindGroupLayoutBase* layout) {
if (groupIndex >= kMaxBindGroups) { if (groupIndex >= kMaxBindGroups) {
HandleError("groupIndex is over the maximum allowed"); HandleError("groupIndex is over the maximum allowed");
return; return;
@ -79,4 +81,4 @@ namespace backend {
mMask.set(groupIndex); mMask.set(groupIndex);
} }
} } // namespace backend

View File

@ -15,8 +15,8 @@
#ifndef BACKEND_PIPELINELAYOUT_H_ #ifndef BACKEND_PIPELINELAYOUT_H_
#define BACKEND_PIPELINELAYOUT_H_ #define BACKEND_PIPELINELAYOUT_H_
#include "backend/Forward.h"
#include "backend/Builder.h" #include "backend/Builder.h"
#include "backend/Forward.h"
#include "backend/RefCounted.h" #include "backend/RefCounted.h"
#include "common/Constants.h" #include "common/Constants.h"
@ -30,40 +30,41 @@ namespace backend {
using BindGroupLayoutArray = std::array<Ref<BindGroupLayoutBase>, kMaxBindGroups>; using BindGroupLayoutArray = std::array<Ref<BindGroupLayoutBase>, kMaxBindGroups>;
class PipelineLayoutBase : public RefCounted { class PipelineLayoutBase : public RefCounted {
public: public:
PipelineLayoutBase(PipelineLayoutBuilder* builder); PipelineLayoutBase(PipelineLayoutBuilder* builder);
const BindGroupLayoutBase* GetBindGroupLayout(size_t group) const; const BindGroupLayoutBase* GetBindGroupLayout(size_t group) const;
const std::bitset<kMaxBindGroups> GetBindGroupsLayoutMask() const; const std::bitset<kMaxBindGroups> GetBindGroupsLayoutMask() const;
// Utility functions to compute inherited bind groups. // Utility functions to compute inherited bind groups.
// Returns the inherited bind groups as a mask // Returns the inherited bind groups as a mask.
std::bitset<kMaxBindGroups> InheritedGroupsMask(const PipelineLayoutBase* other) const; std::bitset<kMaxBindGroups> InheritedGroupsMask(const PipelineLayoutBase* other) const;
// Returns the index of the first incompatible bind group (in the range [1, kMaxBindGroups + 1]) // Returns the index of the first incompatible bind group in the range
uint32_t GroupsInheritUpTo(const PipelineLayoutBase* other) const; // [1, kMaxBindGroups + 1]
uint32_t GroupsInheritUpTo(const PipelineLayoutBase* other) const;
protected: protected:
BindGroupLayoutArray mBindGroupLayouts; BindGroupLayoutArray mBindGroupLayouts;
std::bitset<kMaxBindGroups> mMask; std::bitset<kMaxBindGroups> mMask;
}; };
class PipelineLayoutBuilder : public Builder<PipelineLayoutBase> { class PipelineLayoutBuilder : public Builder<PipelineLayoutBase> {
public: public:
PipelineLayoutBuilder(DeviceBase* device); PipelineLayoutBuilder(DeviceBase* device);
// NXT API // NXT API
void SetBindGroupLayout(uint32_t groupIndex, BindGroupLayoutBase* layout); void SetBindGroupLayout(uint32_t groupIndex, BindGroupLayoutBase* layout);
private: private:
friend class PipelineLayoutBase; friend class PipelineLayoutBase;
PipelineLayoutBase* GetResultImpl() override; PipelineLayoutBase* GetResultImpl() override;
BindGroupLayoutArray mBindGroupLayouts; BindGroupLayoutArray mBindGroupLayouts;
std::bitset<kMaxBindGroups> mMask; std::bitset<kMaxBindGroups> mMask;
}; };
} } // namespace backend
#endif // BACKEND_PIPELINELAYOUT_H_ #endif // BACKEND_PIPELINELAYOUT_H_

View File

@ -14,8 +14,8 @@
#include "backend/Queue.h" #include "backend/Queue.h"
#include "backend/Device.h"
#include "backend/CommandBuffer.h" #include "backend/CommandBuffer.h"
#include "backend/Device.h"
namespace backend { namespace backend {
@ -41,4 +41,4 @@ namespace backend {
return mDevice->CreateQueue(this); return mDevice->CreateQueue(this);
} }
} } // namespace backend

View File

@ -15,8 +15,8 @@
#ifndef BACKEND_QUEUE_H_ #ifndef BACKEND_QUEUE_H_
#define BACKEND_QUEUE_H_ #define BACKEND_QUEUE_H_
#include "backend/Forward.h"
#include "backend/Builder.h" #include "backend/Builder.h"
#include "backend/Forward.h"
#include "backend/RefCounted.h" #include "backend/RefCounted.h"
#include "nxt/nxtcpp.h" #include "nxt/nxtcpp.h"
@ -24,38 +24,39 @@
namespace backend { namespace backend {
class QueueBase : public RefCounted { class QueueBase : public RefCounted {
public: public:
QueueBase(QueueBuilder* builder); QueueBase(QueueBuilder* builder);
DeviceBase* GetDevice(); DeviceBase* GetDevice();
template<typename T> template <typename T>
bool ValidateSubmit(uint32_t numCommands, T* const * commands) { bool ValidateSubmit(uint32_t numCommands, T* const* commands) {
static_assert(std::is_base_of<CommandBufferBase, T>::value, "invalid command buffer type"); static_assert(std::is_base_of<CommandBufferBase, T>::value,
"invalid command buffer type");
for (uint32_t i = 0; i < numCommands; ++i) { for (uint32_t i = 0; i < numCommands; ++i) {
if (!ValidateSubmitCommand(commands[i])) { if (!ValidateSubmitCommand(commands[i])) {
return false; return false;
}
} }
return true;
} }
return true;
}
private: private:
bool ValidateSubmitCommand(CommandBufferBase* command); bool ValidateSubmitCommand(CommandBufferBase* command);
DeviceBase* mDevice; DeviceBase* mDevice;
}; };
class QueueBuilder : public Builder<QueueBase> { class QueueBuilder : public Builder<QueueBase> {
public: public:
QueueBuilder(DeviceBase* device); QueueBuilder(DeviceBase* device);
private: private:
friend class QueueBase; friend class QueueBase;
QueueBase* GetResultImpl() override; QueueBase* GetResultImpl() override;
}; };
} } // namespace backend
#endif // BACKEND_QUEUE_H_ #endif // BACKEND_QUEUE_H_

View File

@ -27,12 +27,12 @@ namespace backend {
void RefCounted::ReferenceInternal() { void RefCounted::ReferenceInternal() {
ASSERT(mInternalRefs != 0); ASSERT(mInternalRefs != 0);
// TODO(cwallez@chromium.org): what to do on overflow? // TODO(cwallez@chromium.org): what to do on overflow?
mInternalRefs ++; mInternalRefs++;
} }
void RefCounted::ReleaseInternal() { void RefCounted::ReleaseInternal() {
ASSERT(mInternalRefs != 0); ASSERT(mInternalRefs != 0);
mInternalRefs --; mInternalRefs--;
if (mInternalRefs == 0) { if (mInternalRefs == 0) {
ASSERT(mExternalRefs == 0); ASSERT(mExternalRefs == 0);
// TODO(cwallez@chromium.org): would this work with custom allocators? // TODO(cwallez@chromium.org): would this work with custom allocators?
@ -51,15 +51,15 @@ namespace backend {
void RefCounted::Reference() { void RefCounted::Reference() {
ASSERT(mExternalRefs != 0); ASSERT(mExternalRefs != 0);
// TODO(cwallez@chromium.org): what to do on overflow? // TODO(cwallez@chromium.org): what to do on overflow?
mExternalRefs ++; mExternalRefs++;
} }
void RefCounted::Release() { void RefCounted::Release() {
ASSERT(mExternalRefs != 0); ASSERT(mExternalRefs != 0);
mExternalRefs --; mExternalRefs--;
if (mExternalRefs == 0) { if (mExternalRefs == 0) {
ReleaseInternal(); ReleaseInternal();
} }
} }
} } // namespace backend

View File

@ -20,107 +20,110 @@
namespace backend { namespace backend {
class RefCounted { class RefCounted {
public: public:
RefCounted(); RefCounted();
virtual ~RefCounted(); virtual ~RefCounted();
void ReferenceInternal(); void ReferenceInternal();
void ReleaseInternal(); void ReleaseInternal();
uint32_t GetExternalRefs() const; uint32_t GetExternalRefs() const;
uint32_t GetInternalRefs() const; uint32_t GetInternalRefs() const;
// NXT API // NXT API
void Reference(); void Reference();
void Release(); void Release();
protected: protected:
uint32_t mExternalRefs = 1; uint32_t mExternalRefs = 1;
uint32_t mInternalRefs = 1; uint32_t mInternalRefs = 1;
}; };
template<typename T> template <typename T>
class Ref { class Ref {
public: public:
Ref() {} Ref() {
}
Ref(T* p): mPointee(p) { Ref(T* p) : mPointee(p) {
Reference(); Reference();
} }
Ref(const Ref<T>& other): mPointee(other.mPointee) {
Reference();
}
Ref<T>& operator=(const Ref<T>& other) {
if (&other == this) return *this;
other.Reference();
Release();
mPointee = other.mPointee;
Ref(const Ref<T>& other) : mPointee(other.mPointee) {
Reference();
}
Ref<T>& operator=(const Ref<T>& other) {
if (&other == this)
return *this; return *this;
}
Ref(Ref<T>&& other) { other.Reference();
mPointee = other.mPointee; Release();
other.mPointee = nullptr; mPointee = other.mPointee;
}
Ref<T>& operator=(Ref<T>&& other) {
if (&other == this) return *this;
Release(); return *this;
mPointee = other.mPointee; }
other.mPointee = nullptr;
Ref(Ref<T>&& other) {
mPointee = other.mPointee;
other.mPointee = nullptr;
}
Ref<T>& operator=(Ref<T>&& other) {
if (&other == this)
return *this; return *this;
}
~Ref() { Release();
Release(); mPointee = other.mPointee;
mPointee = nullptr; other.mPointee = nullptr;
}
operator bool() { return *this;
return mPointee != nullptr; }
}
const T& operator*() const { ~Ref() {
return *mPointee; Release();
} mPointee = nullptr;
T& operator*() { }
return *mPointee;
}
const T* operator->() const { operator bool() {
return mPointee; return mPointee != nullptr;
} }
T* operator->() {
return mPointee;
}
const T* Get() const { const T& operator*() const {
return mPointee; return *mPointee;
} }
T* Get() { T& operator*() {
return mPointee; return *mPointee;
} }
private: const T* operator->() const {
void Reference() const { return mPointee;
if (mPointee != nullptr) { }
mPointee->ReferenceInternal(); T* operator->() {
} return mPointee;
} }
void Release() const {
if (mPointee != nullptr) {
mPointee->ReleaseInternal();
}
}
//static_assert(std::is_base_of<RefCounted, T>::value, ""); const T* Get() const {
T* mPointee = nullptr; return mPointee;
}
T* Get() {
return mPointee;
}
private:
void Reference() const {
if (mPointee != nullptr) {
mPointee->ReferenceInternal();
}
}
void Release() const {
if (mPointee != nullptr) {
mPointee->ReleaseInternal();
}
}
// static_assert(std::is_base_of<RefCounted, T>::value, "");
T* mPointee = nullptr;
}; };
} } // namespace backend
#endif // BACKEND_REFCOUNTED_H_ #endif // BACKEND_REFCOUNTED_H_

View File

@ -25,7 +25,8 @@ namespace backend {
// RenderPass // RenderPass
RenderPassBase::RenderPassBase(RenderPassBuilder* builder) RenderPassBase::RenderPassBase(RenderPassBuilder* builder)
: mAttachments(std::move(builder->mAttachments)), mSubpasses(std::move(builder->mSubpasses)) { : mAttachments(std::move(builder->mAttachments)),
mSubpasses(std::move(builder->mSubpasses)) {
for (uint32_t s = 0; s < GetSubpassCount(); ++s) { for (uint32_t s = 0; s < GetSubpassCount(); ++s) {
const auto& subpass = GetSubpassInfo(s); const auto& subpass = GetSubpassInfo(s);
for (auto location : IterateBitSet(subpass.colorAttachmentsSet)) { for (auto location : IterateBitSet(subpass.colorAttachmentsSet)) {
@ -49,7 +50,8 @@ namespace backend {
return static_cast<uint32_t>(mAttachments.size()); return static_cast<uint32_t>(mAttachments.size());
} }
const RenderPassBase::AttachmentInfo& RenderPassBase::GetAttachmentInfo(uint32_t attachment) const { const RenderPassBase::AttachmentInfo& RenderPassBase::GetAttachmentInfo(
uint32_t attachment) const {
ASSERT(attachment < mAttachments.size()); ASSERT(attachment < mAttachments.size());
return mAttachments[attachment]; return mAttachments[attachment];
} }
@ -76,12 +78,12 @@ namespace backend {
RENDERPASS_PROPERTY_SUBPASS_COUNT = 0x2, RENDERPASS_PROPERTY_SUBPASS_COUNT = 0x2,
}; };
RenderPassBuilder::RenderPassBuilder(DeviceBase* device) RenderPassBuilder::RenderPassBuilder(DeviceBase* device) : Builder(device), mSubpasses(1) {
: Builder(device), mSubpasses(1) {
} }
RenderPassBase* RenderPassBuilder::GetResultImpl() { RenderPassBase* RenderPassBuilder::GetResultImpl() {
constexpr int requiredProperties = RENDERPASS_PROPERTY_ATTACHMENT_COUNT | RENDERPASS_PROPERTY_SUBPASS_COUNT; constexpr int requiredProperties =
RENDERPASS_PROPERTY_ATTACHMENT_COUNT | RENDERPASS_PROPERTY_SUBPASS_COUNT;
if ((mPropertiesSet & requiredProperties) != requiredProperties) { if ((mPropertiesSet & requiredProperties) != requiredProperties) {
HandleError("Render pass missing properties"); HandleError("Render pass missing properties");
return nullptr; return nullptr;
@ -105,7 +107,8 @@ namespace backend {
if (subpass.depthStencilAttachmentSet) { if (subpass.depthStencilAttachmentSet) {
uint32_t slot = subpass.depthStencilAttachment; uint32_t slot = subpass.depthStencilAttachment;
if (!TextureFormatHasDepthOrStencil(mAttachments[slot].format)) { if (!TextureFormatHasDepthOrStencil(mAttachments[slot].format)) {
HandleError("Render pass depth/stencil attachment is not of a depth/stencil format"); HandleError(
"Render pass depth/stencil attachment is not of a depth/stencil format");
return nullptr; return nullptr;
} }
} }
@ -125,7 +128,8 @@ namespace backend {
mPropertiesSet |= RENDERPASS_PROPERTY_ATTACHMENT_COUNT; mPropertiesSet |= RENDERPASS_PROPERTY_ATTACHMENT_COUNT;
} }
void RenderPassBuilder::AttachmentSetFormat(uint32_t attachmentSlot, nxt::TextureFormat format) { void RenderPassBuilder::AttachmentSetFormat(uint32_t attachmentSlot,
nxt::TextureFormat format) {
if ((mPropertiesSet & RENDERPASS_PROPERTY_ATTACHMENT_COUNT) == 0) { if ((mPropertiesSet & RENDERPASS_PROPERTY_ATTACHMENT_COUNT) == 0) {
HandleError("Render pass attachment count not set yet"); HandleError("Render pass attachment count not set yet");
return; return;
@ -156,7 +160,9 @@ namespace backend {
mAttachments[attachmentSlot].colorLoadOp = op; mAttachments[attachmentSlot].colorLoadOp = op;
} }
void RenderPassBuilder::AttachmentSetDepthStencilLoadOps(uint32_t attachmentSlot, nxt::LoadOp depthOp, nxt::LoadOp stencilOp) { void RenderPassBuilder::AttachmentSetDepthStencilLoadOps(uint32_t attachmentSlot,
nxt::LoadOp depthOp,
nxt::LoadOp stencilOp) {
if ((mPropertiesSet & RENDERPASS_PROPERTY_ATTACHMENT_COUNT) == 0) { if ((mPropertiesSet & RENDERPASS_PROPERTY_ATTACHMENT_COUNT) == 0) {
HandleError("Render pass attachment count not set yet"); HandleError("Render pass attachment count not set yet");
return; return;
@ -170,7 +176,6 @@ namespace backend {
mAttachments[attachmentSlot].stencilLoadOp = stencilOp; mAttachments[attachmentSlot].stencilLoadOp = stencilOp;
} }
void RenderPassBuilder::SetSubpassCount(uint32_t subpassCount) { void RenderPassBuilder::SetSubpassCount(uint32_t subpassCount) {
if ((mPropertiesSet & RENDERPASS_PROPERTY_SUBPASS_COUNT) != 0) { if ((mPropertiesSet & RENDERPASS_PROPERTY_SUBPASS_COUNT) != 0) {
HandleError("Render pass subpass count property set multiple times"); HandleError("Render pass subpass count property set multiple times");
@ -185,7 +190,9 @@ namespace backend {
mPropertiesSet |= RENDERPASS_PROPERTY_SUBPASS_COUNT; mPropertiesSet |= RENDERPASS_PROPERTY_SUBPASS_COUNT;
} }
void RenderPassBuilder::SubpassSetColorAttachment(uint32_t subpass, uint32_t outputAttachmentLocation, uint32_t attachmentSlot) { void RenderPassBuilder::SubpassSetColorAttachment(uint32_t subpass,
uint32_t outputAttachmentLocation,
uint32_t attachmentSlot) {
if ((mPropertiesSet & RENDERPASS_PROPERTY_SUBPASS_COUNT) == 0) { if ((mPropertiesSet & RENDERPASS_PROPERTY_SUBPASS_COUNT) == 0) {
HandleError("Render pass subpass count not set yet"); HandleError("Render pass subpass count not set yet");
return; return;
@ -215,7 +222,8 @@ namespace backend {
mSubpasses[subpass].colorAttachments[outputAttachmentLocation] = attachmentSlot; mSubpasses[subpass].colorAttachments[outputAttachmentLocation] = attachmentSlot;
} }
void RenderPassBuilder::SubpassSetDepthStencilAttachment(uint32_t subpass, uint32_t attachmentSlot) { void RenderPassBuilder::SubpassSetDepthStencilAttachment(uint32_t subpass,
uint32_t attachmentSlot) {
if ((mPropertiesSet & RENDERPASS_PROPERTY_SUBPASS_COUNT) == 0) { if ((mPropertiesSet & RENDERPASS_PROPERTY_SUBPASS_COUNT) == 0) {
HandleError("Render pass subpass count not set yet"); HandleError("Render pass subpass count not set yet");
return; return;
@ -241,4 +249,4 @@ namespace backend {
mSubpasses[subpass].depthStencilAttachment = attachmentSlot; mSubpasses[subpass].depthStencilAttachment = attachmentSlot;
} }
} } // namespace backend

View File

@ -29,68 +29,68 @@
namespace backend { namespace backend {
class RenderPassBase : public RefCounted { class RenderPassBase : public RefCounted {
public: public:
RenderPassBase(RenderPassBuilder* builder); RenderPassBase(RenderPassBuilder* builder);
struct AttachmentInfo { struct AttachmentInfo {
nxt::TextureFormat format; nxt::TextureFormat format;
nxt::LoadOp colorLoadOp = nxt::LoadOp::Load; nxt::LoadOp colorLoadOp = nxt::LoadOp::Load;
nxt::LoadOp depthLoadOp = nxt::LoadOp::Load; nxt::LoadOp depthLoadOp = nxt::LoadOp::Load;
nxt::LoadOp stencilLoadOp = nxt::LoadOp::Load; nxt::LoadOp stencilLoadOp = nxt::LoadOp::Load;
// The first subpass that this attachment is used in. // The first subpass that this attachment is used in. This is used to determine, for
// This is used to determine, for each subpass, whether each // each subpass, whether each of its attachments is being used for the first time.
// of its attachments is being used for the first time. uint32_t firstSubpass = UINT32_MAX;
uint32_t firstSubpass = UINT32_MAX; };
};
struct SubpassInfo { struct SubpassInfo {
// Set of locations which are set // Set of locations which are set
std::bitset<kMaxColorAttachments> colorAttachmentsSet; std::bitset<kMaxColorAttachments> colorAttachmentsSet;
// Mapping from location to attachment slot // Mapping from location to attachment slot
std::array<uint32_t, kMaxColorAttachments> colorAttachments; std::array<uint32_t, kMaxColorAttachments> colorAttachments;
bool depthStencilAttachmentSet = false; bool depthStencilAttachmentSet = false;
uint32_t depthStencilAttachment = 0; uint32_t depthStencilAttachment = 0;
}; };
uint32_t GetAttachmentCount() const; uint32_t GetAttachmentCount() const;
const AttachmentInfo& GetAttachmentInfo(uint32_t attachment) const; const AttachmentInfo& GetAttachmentInfo(uint32_t attachment) const;
uint32_t GetSubpassCount() const; uint32_t GetSubpassCount() const;
const SubpassInfo& GetSubpassInfo(uint32_t subpass) const; const SubpassInfo& GetSubpassInfo(uint32_t subpass) const;
bool IsCompatibleWith(const RenderPassBase* other) const; bool IsCompatibleWith(const RenderPassBase* other) const;
private: private:
std::vector<AttachmentInfo> mAttachments; std::vector<AttachmentInfo> mAttachments;
std::vector<SubpassInfo> mSubpasses; std::vector<SubpassInfo> mSubpasses;
}; };
class RenderPassBuilder : public Builder<RenderPassBase> { class RenderPassBuilder : public Builder<RenderPassBase> {
public: public:
RenderPassBuilder(DeviceBase* device); RenderPassBuilder(DeviceBase* device);
// NXT API // NXT API
RenderPassBase* GetResultImpl() override; RenderPassBase* GetResultImpl() override;
void SetAttachmentCount(uint32_t attachmentCount); void SetAttachmentCount(uint32_t attachmentCount);
void AttachmentSetFormat(uint32_t attachmentSlot, nxt::TextureFormat format); void AttachmentSetFormat(uint32_t attachmentSlot, nxt::TextureFormat format);
void AttachmentSetColorLoadOp(uint32_t attachmentSlot, nxt::LoadOp op); void AttachmentSetColorLoadOp(uint32_t attachmentSlot, nxt::LoadOp op);
void AttachmentSetDepthStencilLoadOps(uint32_t attachmentSlot, nxt::LoadOp depthOp, nxt::LoadOp stencilOp); void AttachmentSetDepthStencilLoadOps(uint32_t attachmentSlot,
void SetSubpassCount(uint32_t subpassCount); nxt::LoadOp depthOp,
void SubpassSetColorAttachment(uint32_t subpass, uint32_t outputAttachmentLocation, uint32_t attachmentSlot); nxt::LoadOp stencilOp);
void SubpassSetDepthStencilAttachment(uint32_t subpass, uint32_t attachmentSlot); void SetSubpassCount(uint32_t subpassCount);
void SubpassSetColorAttachment(uint32_t subpass,
uint32_t outputAttachmentLocation,
uint32_t attachmentSlot);
void SubpassSetDepthStencilAttachment(uint32_t subpass, uint32_t attachmentSlot);
private: private:
friend class RenderPassBase; friend class RenderPassBase;
enum AttachmentProperty { enum AttachmentProperty { ATTACHMENT_PROPERTY_FORMAT, ATTACHMENT_PROPERTY_COUNT };
ATTACHMENT_PROPERTY_FORMAT,
ATTACHMENT_PROPERTY_COUNT
};
std::vector<std::bitset<ATTACHMENT_PROPERTY_COUNT>> mAttachmentProperties; std::vector<std::bitset<ATTACHMENT_PROPERTY_COUNT>> mAttachmentProperties;
std::vector<RenderPassBase::AttachmentInfo> mAttachments; std::vector<RenderPassBase::AttachmentInfo> mAttachments;
std::vector<RenderPassBase::SubpassInfo> mSubpasses; std::vector<RenderPassBase::SubpassInfo> mSubpasses;
int mPropertiesSet = 0; int mPropertiesSet = 0;
}; };
} } // namespace backend
#endif // BACKEND_RENDERPASS_H_ #endif // BACKEND_RENDERPASS_H_

View File

@ -15,8 +15,8 @@
#include "backend/RenderPipeline.h" #include "backend/RenderPipeline.h"
#include "backend/BlendState.h" #include "backend/BlendState.h"
#include "backend/Device.h"
#include "backend/DepthStencilState.h" #include "backend/DepthStencilState.h"
#include "backend/Device.h"
#include "backend/InputState.h" #include "backend/InputState.h"
#include "backend/RenderPass.h" #include "backend/RenderPass.h"
#include "common/BitSetIterator.h" #include "common/BitSetIterator.h"
@ -32,8 +32,8 @@ namespace backend {
mInputState(std::move(builder->mInputState)), mInputState(std::move(builder->mInputState)),
mPrimitiveTopology(builder->mPrimitiveTopology), mPrimitiveTopology(builder->mPrimitiveTopology),
mBlendStates(builder->mBlendStates), mBlendStates(builder->mBlendStates),
mRenderPass(std::move(builder->mRenderPass)), mSubpass(builder->mSubpass) { mRenderPass(std::move(builder->mRenderPass)),
mSubpass(builder->mSubpass) {
if (GetStageMask() != (nxt::ShaderStageBit::Vertex | nxt::ShaderStageBit::Fragment)) { if (GetStageMask() != (nxt::ShaderStageBit::Vertex | nxt::ShaderStageBit::Fragment)) {
builder->HandleError("Render pipeline should have exactly a vertex and fragment stage"); builder->HandleError("Render pipeline should have exactly a vertex and fragment stage");
return; return;
@ -41,7 +41,9 @@ namespace backend {
// TODO(kainino@chromium.org): Need to verify the pipeline against its render subpass. // TODO(kainino@chromium.org): Need to verify the pipeline against its render subpass.
if ((builder->GetStageInfo(nxt::ShaderStage::Vertex).module->GetUsedVertexAttributes() & ~mInputState->GetAttributesSetMask()).any()) { if ((builder->GetStageInfo(nxt::ShaderStage::Vertex).module->GetUsedVertexAttributes() &
~mInputState->GetAttributesSetMask())
.any()) {
builder->HandleError("Pipeline vertex stage uses inputs not in the input state"); builder->HandleError("Pipeline vertex stage uses inputs not in the input state");
return; return;
} }
@ -83,7 +85,8 @@ namespace backend {
} }
RenderPipelineBase* RenderPipelineBuilder::GetResultImpl() { RenderPipelineBase* RenderPipelineBuilder::GetResultImpl() {
// TODO(cwallez@chromium.org): the layout should be required, and put the default objects in the device // TODO(cwallez@chromium.org): the layout should be required, and put the default objects in
// the device
if (!mInputState) { if (!mInputState) {
mInputState = mDevice->CreateInputStateBuilder()->GetResult(); mInputState = mDevice->CreateInputStateBuilder()->GetResult();
} }
@ -95,21 +98,24 @@ namespace backend {
return nullptr; return nullptr;
} }
const auto& subpassInfo = mRenderPass->GetSubpassInfo(mSubpass); const auto& subpassInfo = mRenderPass->GetSubpassInfo(mSubpass);
if ((mBlendStatesSet | subpassInfo.colorAttachmentsSet) != subpassInfo.colorAttachmentsSet) { if ((mBlendStatesSet | subpassInfo.colorAttachmentsSet) !=
subpassInfo.colorAttachmentsSet) {
HandleError("Blend state set on unset color attachment"); HandleError("Blend state set on unset color attachment");
return nullptr; return nullptr;
} }
// Assign all color attachments without a blend state the default state // Assign all color attachments without a blend state the default state
// TODO(enga@google.com): Put the default objects in the device // TODO(enga@google.com): Put the default objects in the device
for (uint32_t attachmentSlot : IterateBitSet(subpassInfo.colorAttachmentsSet & ~mBlendStatesSet)) { for (uint32_t attachmentSlot :
IterateBitSet(subpassInfo.colorAttachmentsSet & ~mBlendStatesSet)) {
mBlendStates[attachmentSlot] = mDevice->CreateBlendStateBuilder()->GetResult(); mBlendStates[attachmentSlot] = mDevice->CreateBlendStateBuilder()->GetResult();
} }
return mDevice->CreateRenderPipeline(this); return mDevice->CreateRenderPipeline(this);
} }
void RenderPipelineBuilder::SetColorAttachmentBlendState(uint32_t attachmentSlot, BlendStateBase* blendState) { void RenderPipelineBuilder::SetColorAttachmentBlendState(uint32_t attachmentSlot,
BlendStateBase* blendState) {
if (attachmentSlot > mBlendStates.size()) { if (attachmentSlot > mBlendStates.size()) {
HandleError("Attachment index out of bounds"); HandleError("Attachment index out of bounds");
return; return;
@ -144,4 +150,4 @@ namespace backend {
mSubpass = subpass; mSubpass = subpass;
} }
} } // namespace backend

View File

@ -25,55 +25,56 @@
namespace backend { namespace backend {
class RenderPipelineBase : public RefCounted, public PipelineBase { class RenderPipelineBase : public RefCounted, public PipelineBase {
public: public:
RenderPipelineBase(RenderPipelineBuilder* builder); RenderPipelineBase(RenderPipelineBuilder* builder);
BlendStateBase* GetBlendState(uint32_t attachmentSlot); BlendStateBase* GetBlendState(uint32_t attachmentSlot);
DepthStencilStateBase* GetDepthStencilState(); DepthStencilStateBase* GetDepthStencilState();
nxt::IndexFormat GetIndexFormat() const; nxt::IndexFormat GetIndexFormat() const;
InputStateBase* GetInputState(); InputStateBase* GetInputState();
nxt::PrimitiveTopology GetPrimitiveTopology() const; nxt::PrimitiveTopology GetPrimitiveTopology() const;
RenderPassBase* GetRenderPass(); RenderPassBase* GetRenderPass();
uint32_t GetSubPass(); uint32_t GetSubPass();
private: private:
Ref<DepthStencilStateBase> mDepthStencilState; Ref<DepthStencilStateBase> mDepthStencilState;
nxt::IndexFormat mIndexFormat; nxt::IndexFormat mIndexFormat;
Ref<InputStateBase> mInputState; Ref<InputStateBase> mInputState;
nxt::PrimitiveTopology mPrimitiveTopology; nxt::PrimitiveTopology mPrimitiveTopology;
std::array<Ref<BlendStateBase>, kMaxColorAttachments> mBlendStates; std::array<Ref<BlendStateBase>, kMaxColorAttachments> mBlendStates;
Ref<RenderPassBase> mRenderPass; Ref<RenderPassBase> mRenderPass;
uint32_t mSubpass; uint32_t mSubpass;
}; };
class RenderPipelineBuilder : public Builder<RenderPipelineBase>, public PipelineBuilder { class RenderPipelineBuilder : public Builder<RenderPipelineBase>, public PipelineBuilder {
public: public:
RenderPipelineBuilder(DeviceBase* device); RenderPipelineBuilder(DeviceBase* device);
// NXT API // NXT API
void SetColorAttachmentBlendState(uint32_t attachmentSlot, BlendStateBase* blendState); void SetColorAttachmentBlendState(uint32_t attachmentSlot, BlendStateBase* blendState);
void SetDepthStencilState(DepthStencilStateBase* depthStencilState); void SetDepthStencilState(DepthStencilStateBase* depthStencilState);
void SetPrimitiveTopology(nxt::PrimitiveTopology primitiveTopology); void SetPrimitiveTopology(nxt::PrimitiveTopology primitiveTopology);
void SetIndexFormat(nxt::IndexFormat format); void SetIndexFormat(nxt::IndexFormat format);
void SetInputState(InputStateBase* inputState); void SetInputState(InputStateBase* inputState);
void SetSubpass(RenderPassBase* renderPass, uint32_t subpass); void SetSubpass(RenderPassBase* renderPass, uint32_t subpass);
private: private:
friend class RenderPipelineBase; friend class RenderPipelineBase;
RenderPipelineBase* GetResultImpl() override; RenderPipelineBase* GetResultImpl() override;
Ref<DepthStencilStateBase> mDepthStencilState; Ref<DepthStencilStateBase> mDepthStencilState;
Ref<InputStateBase> mInputState; Ref<InputStateBase> mInputState;
// TODO(enga@google.com): Remove default when we validate that all required properties are set // TODO(enga@google.com): Remove default when we validate that all required properties are
nxt::PrimitiveTopology mPrimitiveTopology = nxt::PrimitiveTopology::TriangleList; // set
nxt::IndexFormat mIndexFormat = nxt::IndexFormat::Uint32; nxt::PrimitiveTopology mPrimitiveTopology = nxt::PrimitiveTopology::TriangleList;
std::bitset<kMaxColorAttachments> mBlendStatesSet; nxt::IndexFormat mIndexFormat = nxt::IndexFormat::Uint32;
std::array<Ref<BlendStateBase>, kMaxColorAttachments> mBlendStates; std::bitset<kMaxColorAttachments> mBlendStatesSet;
Ref<RenderPassBase> mRenderPass; std::array<Ref<BlendStateBase>, kMaxColorAttachments> mBlendStates;
uint32_t mSubpass; Ref<RenderPassBase> mRenderPass;
uint32_t mSubpass;
}; };
} } // namespace backend
#endif // BACKEND_RENDERPIPELINE_H_ #endif // BACKEND_RENDERPIPELINE_H_

View File

@ -43,7 +43,9 @@ namespace backend {
return mMipMapFilter; return mMipMapFilter;
} }
void SamplerBuilder::SetFilterMode(nxt::FilterMode magFilter, nxt::FilterMode minFilter, nxt::FilterMode mipMapFilter) { void SamplerBuilder::SetFilterMode(nxt::FilterMode magFilter,
nxt::FilterMode minFilter,
nxt::FilterMode mipMapFilter) {
if ((mPropertiesSet & SAMPLER_PROPERTY_FILTER) != 0) { if ((mPropertiesSet & SAMPLER_PROPERTY_FILTER) != 0) {
HandleError("Sampler filter property set multiple times"); HandleError("Sampler filter property set multiple times");
return; return;
@ -59,4 +61,4 @@ namespace backend {
return mDevice->CreateSampler(this); return mDevice->CreateSampler(this);
} }
} } // namespace backend

View File

@ -15,8 +15,8 @@
#ifndef BACKEND_SAMPLER_H_ #ifndef BACKEND_SAMPLER_H_
#define BACKEND_SAMPLER_H_ #define BACKEND_SAMPLER_H_
#include "backend/Forward.h"
#include "backend/Buffer.h" #include "backend/Buffer.h"
#include "backend/Forward.h"
#include "backend/RefCounted.h" #include "backend/RefCounted.h"
#include "nxt/nxtcpp.h" #include "nxt/nxtcpp.h"
@ -24,33 +24,35 @@
namespace backend { namespace backend {
class SamplerBase : public RefCounted { class SamplerBase : public RefCounted {
public: public:
SamplerBase(SamplerBuilder* builder); SamplerBase(SamplerBuilder* builder);
}; };
class SamplerBuilder : public Builder<SamplerBase> { class SamplerBuilder : public Builder<SamplerBase> {
public: public:
SamplerBuilder(DeviceBase* device); SamplerBuilder(DeviceBase* device);
nxt::FilterMode GetMagFilter() const; nxt::FilterMode GetMagFilter() const;
nxt::FilterMode GetMinFilter() const; nxt::FilterMode GetMinFilter() const;
nxt::FilterMode GetMipMapFilter() const; nxt::FilterMode GetMipMapFilter() const;
// NXT API // NXT API
void SetFilterMode(nxt::FilterMode magFilter, nxt::FilterMode minFilter, nxt::FilterMode mipMapFilter); void SetFilterMode(nxt::FilterMode magFilter,
nxt::FilterMode minFilter,
nxt::FilterMode mipMapFilter);
private: private:
friend class SamplerBase; friend class SamplerBase;
SamplerBase* GetResultImpl() override; SamplerBase* GetResultImpl() override;
int mPropertiesSet = 0; int mPropertiesSet = 0;
nxt::FilterMode mMagFilter = nxt::FilterMode::Nearest; nxt::FilterMode mMagFilter = nxt::FilterMode::Nearest;
nxt::FilterMode mMinFilter = nxt::FilterMode::Nearest; nxt::FilterMode mMinFilter = nxt::FilterMode::Nearest;
nxt::FilterMode mMipMapFilter = nxt::FilterMode::Nearest; nxt::FilterMode mMipMapFilter = nxt::FilterMode::Nearest;
}; };
} } // namespace backend
#endif // BACKEND_SAMPLER_H_ #endif // BACKEND_SAMPLER_H_

View File

@ -23,8 +23,7 @@
namespace backend { namespace backend {
ShaderModuleBase::ShaderModuleBase(ShaderModuleBuilder* builder) ShaderModuleBase::ShaderModuleBase(ShaderModuleBuilder* builder) : mDevice(builder->mDevice) {
: mDevice(builder->mDevice) {
} }
DeviceBase* ShaderModuleBase::GetDevice() const { DeviceBase* ShaderModuleBase::GetDevice() const {
@ -62,8 +61,10 @@ namespace backend {
ASSERT(blockType.basetype == spirv_cross::SPIRType::Struct); ASSERT(blockType.basetype == spirv_cross::SPIRType::Struct);
for (uint32_t i = 0; i < blockType.member_types.size(); i++) { for (uint32_t i = 0; i < blockType.member_types.size(); i++) {
ASSERT(compiler.get_member_decoration_mask(blockType.self, i) & 1ull << spv::DecorationOffset); ASSERT(compiler.get_member_decoration_mask(blockType.self, i) &
uint32_t offset = compiler.get_member_decoration(blockType.self, i, spv::DecorationOffset); 1ull << spv::DecorationOffset);
uint32_t offset =
compiler.get_member_decoration(blockType.self, i, spv::DecorationOffset);
ASSERT(offset % 4 == 0); ASSERT(offset % 4 == 0);
offset /= 4; offset /= 4;
@ -78,8 +79,8 @@ namespace backend {
constantType = PushConstantType::Float; constantType = PushConstantType::Float;
} }
// TODO(cwallez@chromium.org): check for overflows and make the logic better take into account // TODO(cwallez@chromium.org): check for overflows and make the logic better take
// things like the array of types with padding. // into account things like the array of types with padding.
uint32_t size = memberType.vecsize * memberType.columns; uint32_t size = memberType.vecsize * memberType.columns;
// Handle unidimensional arrays // Handle unidimensional arrays
if (!memberType.array.empty()) { if (!memberType.array.empty()) {
@ -92,7 +93,8 @@ namespace backend {
} }
mPushConstants.mask.set(offset); mPushConstants.mask.set(offset);
mPushConstants.names[offset] = interfaceBlock.name + "." + compiler.get_member_name(blockType.self, i); mPushConstants.names[offset] =
interfaceBlock.name + "." + compiler.get_member_name(blockType.self, i);
mPushConstants.sizes[offset] = size; mPushConstants.sizes[offset] = size;
mPushConstants.types[offset] = constantType; mPushConstants.types[offset] = constantType;
} }
@ -100,11 +102,14 @@ namespace backend {
// Fill in bindingInfo with the SPIRV bindings // Fill in bindingInfo with the SPIRV bindings
auto ExtractResourcesBinding = [this](const std::vector<spirv_cross::Resource>& resources, auto ExtractResourcesBinding = [this](const std::vector<spirv_cross::Resource>& resources,
const spirv_cross::Compiler& compiler, nxt::BindingType bindingType) { const spirv_cross::Compiler& compiler,
constexpr uint64_t requiredBindingDecorationMask = (1ull << spv::DecorationBinding) | (1ull << spv::DecorationDescriptorSet); nxt::BindingType bindingType) {
constexpr uint64_t requiredBindingDecorationMask =
(1ull << spv::DecorationBinding) | (1ull << spv::DecorationDescriptorSet);
for (const auto& resource : resources) { for (const auto& resource : resources) {
ASSERT((compiler.get_decoration_mask(resource.id) & requiredBindingDecorationMask) == requiredBindingDecorationMask); ASSERT((compiler.get_decoration_mask(resource.id) &
requiredBindingDecorationMask) == requiredBindingDecorationMask);
uint32_t binding = compiler.get_decoration(resource.id, spv::DecorationBinding); uint32_t binding = compiler.get_decoration(resource.id, spv::DecorationBinding);
uint32_t set = compiler.get_decoration(resource.id, spv::DecorationDescriptorSet); uint32_t set = compiler.get_decoration(resource.id, spv::DecorationDescriptorSet);
@ -121,10 +126,13 @@ namespace backend {
} }
}; };
ExtractResourcesBinding(resources.uniform_buffers, compiler, nxt::BindingType::UniformBuffer); ExtractResourcesBinding(resources.uniform_buffers, compiler,
ExtractResourcesBinding(resources.separate_images, compiler, nxt::BindingType::SampledTexture); nxt::BindingType::UniformBuffer);
ExtractResourcesBinding(resources.separate_images, compiler,
nxt::BindingType::SampledTexture);
ExtractResourcesBinding(resources.separate_samplers, compiler, nxt::BindingType::Sampler); ExtractResourcesBinding(resources.separate_samplers, compiler, nxt::BindingType::Sampler);
ExtractResourcesBinding(resources.storage_buffers, compiler, nxt::BindingType::StorageBuffer); ExtractResourcesBinding(resources.storage_buffers, compiler,
nxt::BindingType::StorageBuffer);
// Extract the vertex attributes // Extract the vertex attributes
if (mExecutionModel == nxt::ShaderStage::Vertex) { if (mExecutionModel == nxt::ShaderStage::Vertex) {
@ -140,10 +148,11 @@ namespace backend {
mUsedVertexAttributes.set(location); mUsedVertexAttributes.set(location);
} }
// Without a location qualifier on vertex outputs, spirv_cross::CompilerMSL gives them all // Without a location qualifier on vertex outputs, spirv_cross::CompilerMSL gives them
// the location 0, causing a compile error. // all the location 0, causing a compile error.
for (const auto& attrib : resources.stage_outputs) { for (const auto& attrib : resources.stage_outputs) {
if (!(compiler.get_decoration_mask(attrib.id) & (1ull << spv::DecorationLocation))) { if (!(compiler.get_decoration_mask(attrib.id) &
(1ull << spv::DecorationLocation))) {
mDevice->HandleError("Need location qualifier on vertex output"); mDevice->HandleError("Need location qualifier on vertex output");
return; return;
} }
@ -151,10 +160,11 @@ namespace backend {
} }
if (mExecutionModel == nxt::ShaderStage::Fragment) { if (mExecutionModel == nxt::ShaderStage::Fragment) {
// Without a location qualifier on vertex inputs, spirv_cross::CompilerMSL gives them all // Without a location qualifier on vertex inputs, spirv_cross::CompilerMSL gives them
// the location 0, causing a compile error. // all the location 0, causing a compile error.
for (const auto& attrib : resources.stage_inputs) { for (const auto& attrib : resources.stage_inputs) {
if (!(compiler.get_decoration_mask(attrib.id) & (1ull << spv::DecorationLocation))) { if (!(compiler.get_decoration_mask(attrib.id) &
(1ull << spv::DecorationLocation))) {
mDevice->HandleError("Need location qualifier on fragment input"); mDevice->HandleError("Need location qualifier on fragment input");
return; return;
} }
@ -187,7 +197,8 @@ namespace backend {
return true; return true;
} }
bool ShaderModuleBase::IsCompatibleWithBindGroupLayout(size_t group, const BindGroupLayoutBase* layout) { bool ShaderModuleBase::IsCompatibleWithBindGroupLayout(size_t group,
const BindGroupLayoutBase* layout) {
const auto& layoutInfo = layout->GetBindingInfo(); const auto& layoutInfo = layout->GetBindingInfo();
for (size_t i = 0; i < kMaxBindingsPerGroup; ++i) { for (size_t i = 0; i < kMaxBindingsPerGroup; ++i) {
const auto& moduleInfo = mBindingInfo[group][i]; const auto& moduleInfo = mBindingInfo[group][i];
@ -227,4 +238,4 @@ namespace backend {
mSpirv.assign(code, code + codeSize); mSpirv.assign(code, code + codeSize);
} }
} } // namespace backend

View File

@ -15,8 +15,8 @@
#ifndef BACKEND_SHADERMODULE_H_ #ifndef BACKEND_SHADERMODULE_H_
#define BACKEND_SHADERMODULE_H_ #define BACKEND_SHADERMODULE_H_
#include "backend/Forward.h"
#include "backend/Builder.h" #include "backend/Builder.h"
#include "backend/Forward.h"
#include "backend/RefCounted.h" #include "backend/RefCounted.h"
#include "common/Constants.h" #include "common/Constants.h"
@ -33,64 +33,65 @@ namespace spirv_cross {
namespace backend { namespace backend {
class ShaderModuleBase : public RefCounted { class ShaderModuleBase : public RefCounted {
public: public:
ShaderModuleBase(ShaderModuleBuilder* builder); ShaderModuleBase(ShaderModuleBuilder* builder);
DeviceBase* GetDevice() const; DeviceBase* GetDevice() const;
void ExtractSpirvInfo(const spirv_cross::Compiler& compiler); void ExtractSpirvInfo(const spirv_cross::Compiler& compiler);
struct PushConstantInfo { struct PushConstantInfo {
std::bitset<kMaxPushConstants> mask; std::bitset<kMaxPushConstants> mask;
std::array<std::string, kMaxPushConstants> names; std::array<std::string, kMaxPushConstants> names;
std::array<uint32_t, kMaxPushConstants> sizes; std::array<uint32_t, kMaxPushConstants> sizes;
std::array<PushConstantType, kMaxPushConstants> types; std::array<PushConstantType, kMaxPushConstants> types;
}; };
struct BindingInfo { struct BindingInfo {
// The SPIRV ID of the resource. // The SPIRV ID of the resource.
uint32_t id; uint32_t id;
uint32_t base_type_id; uint32_t base_type_id;
nxt::BindingType type; nxt::BindingType type;
bool used = false; bool used = false;
}; };
using ModuleBindingInfo = std::array<std::array<BindingInfo, kMaxBindingsPerGroup>, kMaxBindGroups>; using ModuleBindingInfo =
std::array<std::array<BindingInfo, kMaxBindingsPerGroup>, kMaxBindGroups>;
const PushConstantInfo& GetPushConstants() const; const PushConstantInfo& GetPushConstants() const;
const ModuleBindingInfo& GetBindingInfo() const; const ModuleBindingInfo& GetBindingInfo() const;
const std::bitset<kMaxVertexAttributes>& GetUsedVertexAttributes() const; const std::bitset<kMaxVertexAttributes>& GetUsedVertexAttributes() const;
nxt::ShaderStage GetExecutionModel() const; nxt::ShaderStage GetExecutionModel() const;
bool IsCompatibleWithPipelineLayout(const PipelineLayoutBase* layout); bool IsCompatibleWithPipelineLayout(const PipelineLayoutBase* layout);
private: private:
bool IsCompatibleWithBindGroupLayout(size_t group, const BindGroupLayoutBase* layout); bool IsCompatibleWithBindGroupLayout(size_t group, const BindGroupLayoutBase* layout);
DeviceBase* mDevice; DeviceBase* mDevice;
PushConstantInfo mPushConstants = {}; PushConstantInfo mPushConstants = {};
ModuleBindingInfo mBindingInfo; ModuleBindingInfo mBindingInfo;
std::bitset<kMaxVertexAttributes> mUsedVertexAttributes; std::bitset<kMaxVertexAttributes> mUsedVertexAttributes;
nxt::ShaderStage mExecutionModel; nxt::ShaderStage mExecutionModel;
}; };
class ShaderModuleBuilder : public Builder<ShaderModuleBase> { class ShaderModuleBuilder : public Builder<ShaderModuleBase> {
public: public:
ShaderModuleBuilder(DeviceBase* device); ShaderModuleBuilder(DeviceBase* device);
std::vector<uint32_t> AcquireSpirv(); std::vector<uint32_t> AcquireSpirv();
// NXT API // NXT API
void SetSource(uint32_t codeSize, const uint32_t* code); void SetSource(uint32_t codeSize, const uint32_t* code);
private: private:
friend class ShaderModuleBase; friend class ShaderModuleBase;
ShaderModuleBase* GetResultImpl() override; ShaderModuleBase* GetResultImpl() override;
std::vector<uint32_t> mSpirv; std::vector<uint32_t> mSpirv;
}; };
} } // namespace backend
#endif // BACKEND_SHADERMODULE_H_ #endif // BACKEND_SHADERMODULE_H_

View File

@ -22,7 +22,7 @@ namespace backend {
// SwapChain // SwapChain
SwapChainBase::SwapChainBase(SwapChainBuilder* builder) SwapChainBase::SwapChainBase(SwapChainBuilder* builder)
: mDevice(builder->mDevice), mImplementation(builder->mImplementation) { : mDevice(builder->mDevice), mImplementation(builder->mImplementation) {
} }
SwapChainBase::~SwapChainBase() { SwapChainBase::~SwapChainBase() {
@ -34,7 +34,10 @@ namespace backend {
return mDevice; return mDevice;
} }
void SwapChainBase::Configure(nxt::TextureFormat format, nxt::TextureUsageBit allowedUsage, uint32_t width, uint32_t height) { void SwapChainBase::Configure(nxt::TextureFormat format,
nxt::TextureUsageBit allowedUsage,
uint32_t width,
uint32_t height) {
if (width == 0 || height == 0) { if (width == 0 || height == 0) {
mDevice->HandleError("Swap chain cannot be configured to zero size"); mDevice->HandleError("Swap chain cannot be configured to zero size");
return; return;
@ -45,8 +48,8 @@ namespace backend {
mAllowedUsage = allowedUsage; mAllowedUsage = allowedUsage;
mWidth = width; mWidth = width;
mHeight = height; mHeight = height;
mImplementation.Configure(mImplementation.userData, mImplementation.Configure(mImplementation.userData, static_cast<nxtTextureFormat>(format),
static_cast<nxtTextureFormat>(format), static_cast<nxtTextureUsageBit>(allowedUsage), width, height); static_cast<nxtTextureUsageBit>(allowedUsage), width, height);
} }
TextureBase* SwapChainBase::GetNextTexture() { TextureBase* SwapChainBase::GetNextTexture() {
@ -87,8 +90,7 @@ namespace backend {
// SwapChain Builder // SwapChain Builder
SwapChainBuilder::SwapChainBuilder(DeviceBase* device) SwapChainBuilder::SwapChainBuilder(DeviceBase* device) : Builder(device) {
: Builder(device) {
} }
SwapChainBase* SwapChainBuilder::GetResultImpl() { SwapChainBase* SwapChainBuilder::GetResultImpl() {
@ -105,14 +107,15 @@ namespace backend {
return; return;
} }
nxtSwapChainImplementation& impl = *reinterpret_cast<nxtSwapChainImplementation*>(implementation); nxtSwapChainImplementation& impl =
*reinterpret_cast<nxtSwapChainImplementation*>(implementation);
if (!impl.Init || !impl.Destroy || !impl.Configure || if (!impl.Init || !impl.Destroy || !impl.Configure || !impl.GetNextTexture ||
!impl.GetNextTexture || !impl.Present) { !impl.Present) {
HandleError("Implementation is incomplete"); HandleError("Implementation is incomplete");
return; return;
} }
mImplementation = impl; mImplementation = impl;
} }
} } // namespace backend

View File

@ -15,55 +15,58 @@
#ifndef BACKEND_SWAPCHAIN_H_ #ifndef BACKEND_SWAPCHAIN_H_
#define BACKEND_SWAPCHAIN_H_ #define BACKEND_SWAPCHAIN_H_
#include "backend/Forward.h"
#include "backend/Builder.h" #include "backend/Builder.h"
#include "backend/Forward.h"
#include "backend/RefCounted.h" #include "backend/RefCounted.h"
#include "nxt/nxtcpp.h"
#include "nxt/nxt_wsi.h" #include "nxt/nxt_wsi.h"
#include "nxt/nxtcpp.h"
namespace backend { namespace backend {
class SwapChainBase : public RefCounted { class SwapChainBase : public RefCounted {
public: public:
SwapChainBase(SwapChainBuilder* builder); SwapChainBase(SwapChainBuilder* builder);
~SwapChainBase(); ~SwapChainBase();
DeviceBase* GetDevice(); DeviceBase* GetDevice();
// NXT API // NXT API
void Configure(nxt::TextureFormat format, nxt::TextureUsageBit allowedUsage, uint32_t width, uint32_t height); void Configure(nxt::TextureFormat format,
TextureBase* GetNextTexture(); nxt::TextureUsageBit allowedUsage,
void Present(TextureBase* texture); uint32_t width,
uint32_t height);
TextureBase* GetNextTexture();
void Present(TextureBase* texture);
protected: protected:
const nxtSwapChainImplementation& GetImplementation(); const nxtSwapChainImplementation& GetImplementation();
virtual TextureBase* GetNextTextureImpl(TextureBuilder* builder) = 0; virtual TextureBase* GetNextTextureImpl(TextureBuilder* builder) = 0;
private: private:
DeviceBase* mDevice = nullptr; DeviceBase* mDevice = nullptr;
nxtSwapChainImplementation mImplementation = {}; nxtSwapChainImplementation mImplementation = {};
nxt::TextureFormat mFormat = {}; nxt::TextureFormat mFormat = {};
nxt::TextureUsageBit mAllowedUsage; nxt::TextureUsageBit mAllowedUsage;
uint32_t mWidth = 0; uint32_t mWidth = 0;
uint32_t mHeight = 0; uint32_t mHeight = 0;
TextureBase* mLastNextTexture = nullptr; TextureBase* mLastNextTexture = nullptr;
}; };
class SwapChainBuilder : public Builder<SwapChainBase> { class SwapChainBuilder : public Builder<SwapChainBase> {
public: public:
SwapChainBuilder(DeviceBase* device); SwapChainBuilder(DeviceBase* device);
// NXT API // NXT API
SwapChainBase* GetResultImpl() override; SwapChainBase* GetResultImpl() override;
void SetImplementation(uint64_t implementation); void SetImplementation(uint64_t implementation);
private: private:
friend class SwapChainBase; friend class SwapChainBase;
nxtSwapChainImplementation mImplementation = {}; nxtSwapChainImplementation mImplementation = {};
}; };
} } // namespace backend
#endif // BACKEND_SWAPCHAIN_H_ #endif // BACKEND_SWAPCHAIN_H_

View File

@ -71,13 +71,18 @@ namespace backend {
} }
} }
// TextureBase // TextureBase
TextureBase::TextureBase(TextureBuilder* builder) TextureBase::TextureBase(TextureBuilder* builder)
: mDevice(builder->mDevice), mDimension(builder->mDimension), mFormat(builder->mFormat), mWidth(builder->mWidth), : mDevice(builder->mDevice),
mHeight(builder->mHeight), mDepth(builder->mDepth), mNumMipLevels(builder->mNumMipLevels), mDimension(builder->mDimension),
mAllowedUsage(builder->mAllowedUsage), mCurrentUsage(builder->mCurrentUsage) { mFormat(builder->mFormat),
mWidth(builder->mWidth),
mHeight(builder->mHeight),
mDepth(builder->mDepth),
mNumMipLevels(builder->mNumMipLevels),
mAllowedUsage(builder->mAllowedUsage),
mCurrentUsage(builder->mCurrentUsage) {
} }
DeviceBase* TextureBase::GetDevice() { DeviceBase* TextureBase::GetDevice() {
@ -121,7 +126,8 @@ namespace backend {
return mIsFrozen && (usage & mAllowedUsage); return mIsFrozen && (usage & mAllowedUsage);
} }
bool TextureBase::IsUsagePossible(nxt::TextureUsageBit allowedUsage, nxt::TextureUsageBit usage) { bool TextureBase::IsUsagePossible(nxt::TextureUsageBit allowedUsage,
nxt::TextureUsageBit usage) {
bool allowed = (usage & allowedUsage) == usage; bool allowed = (usage & allowedUsage) == usage;
bool singleUse = nxt::HasZeroOrOneBits(usage); bool singleUse = nxt::HasZeroOrOneBits(usage);
return allowed && singleUse; return allowed && singleUse;
@ -173,13 +179,13 @@ namespace backend {
TEXTURE_PROPERTY_INITIAL_USAGE = 0x20, TEXTURE_PROPERTY_INITIAL_USAGE = 0x20,
}; };
TextureBuilder::TextureBuilder(DeviceBase* device) TextureBuilder::TextureBuilder(DeviceBase* device) : Builder(device) {
: Builder(device) {
} }
TextureBase* TextureBuilder::GetResultImpl() { TextureBase* TextureBuilder::GetResultImpl() {
constexpr int allProperties = TEXTURE_PROPERTY_DIMENSION | TEXTURE_PROPERTY_EXTENT | constexpr int allProperties = TEXTURE_PROPERTY_DIMENSION | TEXTURE_PROPERTY_EXTENT |
TEXTURE_PROPERTY_FORMAT | TEXTURE_PROPERTY_MIP_LEVELS | TEXTURE_PROPERTY_ALLOWED_USAGE; TEXTURE_PROPERTY_FORMAT | TEXTURE_PROPERTY_MIP_LEVELS |
TEXTURE_PROPERTY_ALLOWED_USAGE;
if ((mPropertiesSet & allProperties) != allProperties) { if ((mPropertiesSet & allProperties) != allProperties) {
HandleError("Texture missing properties"); HandleError("Texture missing properties");
return nullptr; return nullptr;
@ -264,8 +270,7 @@ namespace backend {
// TextureViewBase // TextureViewBase
TextureViewBase::TextureViewBase(TextureViewBuilder* builder) TextureViewBase::TextureViewBase(TextureViewBuilder* builder) : mTexture(builder->mTexture) {
: mTexture(builder->mTexture) {
} }
TextureBase* TextureViewBase::GetTexture() { TextureBase* TextureViewBase::GetTexture() {
@ -282,4 +287,4 @@ namespace backend {
return mDevice->CreateTextureView(this); return mDevice->CreateTextureView(this);
} }
} } // namespace backend

View File

@ -15,8 +15,8 @@
#ifndef BACKEND_TEXTURE_H_ #ifndef BACKEND_TEXTURE_H_
#define BACKEND_TEXTURE_H_ #define BACKEND_TEXTURE_H_
#include "backend/Forward.h"
#include "backend/Builder.h" #include "backend/Builder.h"
#include "backend/Forward.h"
#include "backend/RefCounted.h" #include "backend/RefCounted.h"
#include "nxt/nxtcpp.h" #include "nxt/nxtcpp.h"
@ -29,93 +29,94 @@ namespace backend {
bool TextureFormatHasDepthOrStencil(nxt::TextureFormat format); bool TextureFormatHasDepthOrStencil(nxt::TextureFormat format);
class TextureBase : public RefCounted { class TextureBase : public RefCounted {
public: public:
TextureBase(TextureBuilder* builder); TextureBase(TextureBuilder* builder);
nxt::TextureDimension GetDimension() const; nxt::TextureDimension GetDimension() const;
nxt::TextureFormat GetFormat() const; nxt::TextureFormat GetFormat() const;
uint32_t GetWidth() const; uint32_t GetWidth() const;
uint32_t GetHeight() const; uint32_t GetHeight() const;
uint32_t GetDepth() const; uint32_t GetDepth() const;
uint32_t GetNumMipLevels() const; uint32_t GetNumMipLevels() const;
nxt::TextureUsageBit GetAllowedUsage() const; nxt::TextureUsageBit GetAllowedUsage() const;
nxt::TextureUsageBit GetUsage() const; nxt::TextureUsageBit GetUsage() const;
bool IsFrozen() const; bool IsFrozen() const;
bool HasFrozenUsage(nxt::TextureUsageBit usage) const; bool HasFrozenUsage(nxt::TextureUsageBit usage) const;
static bool IsUsagePossible(nxt::TextureUsageBit allowedUsage, nxt::TextureUsageBit usage); static bool IsUsagePossible(nxt::TextureUsageBit allowedUsage, nxt::TextureUsageBit usage);
bool IsTransitionPossible(nxt::TextureUsageBit usage) const; bool IsTransitionPossible(nxt::TextureUsageBit usage) const;
void UpdateUsageInternal(nxt::TextureUsageBit usage); void UpdateUsageInternal(nxt::TextureUsageBit usage);
DeviceBase* GetDevice(); DeviceBase* GetDevice();
// NXT API // NXT API
TextureViewBuilder* CreateTextureViewBuilder(); TextureViewBuilder* CreateTextureViewBuilder();
void TransitionUsage(nxt::TextureUsageBit usage); void TransitionUsage(nxt::TextureUsageBit usage);
void FreezeUsage(nxt::TextureUsageBit usage); void FreezeUsage(nxt::TextureUsageBit usage);
virtual void TransitionUsageImpl(nxt::TextureUsageBit currentUsage, nxt::TextureUsageBit targetUsage) = 0; virtual void TransitionUsageImpl(nxt::TextureUsageBit currentUsage,
nxt::TextureUsageBit targetUsage) = 0;
private: private:
DeviceBase* mDevice; DeviceBase* mDevice;
nxt::TextureDimension mDimension; nxt::TextureDimension mDimension;
nxt::TextureFormat mFormat; nxt::TextureFormat mFormat;
uint32_t mWidth, mHeight, mDepth; uint32_t mWidth, mHeight, mDepth;
uint32_t mNumMipLevels; uint32_t mNumMipLevels;
nxt::TextureUsageBit mAllowedUsage = nxt::TextureUsageBit::None; nxt::TextureUsageBit mAllowedUsage = nxt::TextureUsageBit::None;
nxt::TextureUsageBit mCurrentUsage = nxt::TextureUsageBit::None; nxt::TextureUsageBit mCurrentUsage = nxt::TextureUsageBit::None;
bool mIsFrozen = false; bool mIsFrozen = false;
}; };
class TextureBuilder : public Builder<TextureBase> { class TextureBuilder : public Builder<TextureBase> {
public: public:
TextureBuilder(DeviceBase* device); TextureBuilder(DeviceBase* device);
// NXT API // NXT API
void SetDimension(nxt::TextureDimension dimension); void SetDimension(nxt::TextureDimension dimension);
void SetExtent(uint32_t width, uint32_t height, uint32_t depth); void SetExtent(uint32_t width, uint32_t height, uint32_t depth);
void SetFormat(nxt::TextureFormat format); void SetFormat(nxt::TextureFormat format);
void SetMipLevels(uint32_t numMipLevels); void SetMipLevels(uint32_t numMipLevels);
void SetAllowedUsage(nxt::TextureUsageBit usage); void SetAllowedUsage(nxt::TextureUsageBit usage);
void SetInitialUsage(nxt::TextureUsageBit usage); void SetInitialUsage(nxt::TextureUsageBit usage);
private: private:
friend class TextureBase; friend class TextureBase;
TextureBase* GetResultImpl() override; TextureBase* GetResultImpl() override;
int mPropertiesSet = 0; int mPropertiesSet = 0;
nxt::TextureDimension mDimension; nxt::TextureDimension mDimension;
uint32_t mWidth, mHeight, mDepth; uint32_t mWidth, mHeight, mDepth;
nxt::TextureFormat mFormat; nxt::TextureFormat mFormat;
uint32_t mNumMipLevels; uint32_t mNumMipLevels;
nxt::TextureUsageBit mAllowedUsage = nxt::TextureUsageBit::None; nxt::TextureUsageBit mAllowedUsage = nxt::TextureUsageBit::None;
nxt::TextureUsageBit mCurrentUsage = nxt::TextureUsageBit::None; nxt::TextureUsageBit mCurrentUsage = nxt::TextureUsageBit::None;
}; };
class TextureViewBase : public RefCounted { class TextureViewBase : public RefCounted {
public: public:
TextureViewBase(TextureViewBuilder* builder); TextureViewBase(TextureViewBuilder* builder);
TextureBase* GetTexture(); TextureBase* GetTexture();
private: private:
Ref<TextureBase> mTexture; Ref<TextureBase> mTexture;
}; };
class TextureViewBuilder : public Builder<TextureViewBase> { class TextureViewBuilder : public Builder<TextureViewBase> {
public: public:
TextureViewBuilder(DeviceBase* device, TextureBase* texture); TextureViewBuilder(DeviceBase* device, TextureBase* texture);
private: private:
friend class TextureViewBase; friend class TextureViewBase;
TextureViewBase* GetResultImpl() override; TextureViewBase* GetResultImpl() override;
Ref<TextureBase> mTexture; Ref<TextureBase> mTexture;
}; };
} } // namespace backend
#endif // BACKEND_TEXTURE_H_ #endif // BACKEND_TEXTURE_H_

View File

@ -20,105 +20,105 @@
namespace backend { namespace backend {
// ToBackendTraits implements the mapping from base type to member type of BackendTraits // ToBackendTraits implements the mapping from base type to member type of BackendTraits
template<typename T, typename BackendTraits> template <typename T, typename BackendTraits>
struct ToBackendTraits; struct ToBackendTraits;
template<typename BackendTraits> template <typename BackendTraits>
struct ToBackendTraits<BindGroupBase, BackendTraits> { struct ToBackendTraits<BindGroupBase, BackendTraits> {
using BackendType = typename BackendTraits::BindGroupType; using BackendType = typename BackendTraits::BindGroupType;
}; };
template<typename BackendTraits> template <typename BackendTraits>
struct ToBackendTraits<BindGroupLayoutBase, BackendTraits> { struct ToBackendTraits<BindGroupLayoutBase, BackendTraits> {
using BackendType = typename BackendTraits::BindGroupLayoutType; using BackendType = typename BackendTraits::BindGroupLayoutType;
}; };
template<typename BackendTraits> template <typename BackendTraits>
struct ToBackendTraits<BlendStateBase, BackendTraits> { struct ToBackendTraits<BlendStateBase, BackendTraits> {
using BackendType = typename BackendTraits::BlendStateType; using BackendType = typename BackendTraits::BlendStateType;
}; };
template<typename BackendTraits> template <typename BackendTraits>
struct ToBackendTraits<BufferBase, BackendTraits> { struct ToBackendTraits<BufferBase, BackendTraits> {
using BackendType = typename BackendTraits::BufferType; using BackendType = typename BackendTraits::BufferType;
}; };
template<typename BackendTraits> template <typename BackendTraits>
struct ToBackendTraits<BufferViewBase, BackendTraits> { struct ToBackendTraits<BufferViewBase, BackendTraits> {
using BackendType = typename BackendTraits::BufferViewType; using BackendType = typename BackendTraits::BufferViewType;
}; };
template<typename BackendTraits> template <typename BackendTraits>
struct ToBackendTraits<CommandBufferBase, BackendTraits> { struct ToBackendTraits<CommandBufferBase, BackendTraits> {
using BackendType = typename BackendTraits::CommandBufferType; using BackendType = typename BackendTraits::CommandBufferType;
}; };
template<typename BackendTraits> template <typename BackendTraits>
struct ToBackendTraits<ComputePipelineBase, BackendTraits> { struct ToBackendTraits<ComputePipelineBase, BackendTraits> {
using BackendType = typename BackendTraits::ComputePipelineType; using BackendType = typename BackendTraits::ComputePipelineType;
}; };
template<typename BackendTraits> template <typename BackendTraits>
struct ToBackendTraits<DepthStencilStateBase, BackendTraits> { struct ToBackendTraits<DepthStencilStateBase, BackendTraits> {
using BackendType = typename BackendTraits::DepthStencilStateType; using BackendType = typename BackendTraits::DepthStencilStateType;
}; };
template<typename BackendTraits> template <typename BackendTraits>
struct ToBackendTraits<DeviceBase, BackendTraits> { struct ToBackendTraits<DeviceBase, BackendTraits> {
using BackendType = typename BackendTraits::DeviceType; using BackendType = typename BackendTraits::DeviceType;
}; };
template<typename BackendTraits> template <typename BackendTraits>
struct ToBackendTraits<FramebufferBase, BackendTraits> { struct ToBackendTraits<FramebufferBase, BackendTraits> {
using BackendType = typename BackendTraits::FramebufferType; using BackendType = typename BackendTraits::FramebufferType;
}; };
template<typename BackendTraits> template <typename BackendTraits>
struct ToBackendTraits<InputStateBase, BackendTraits> { struct ToBackendTraits<InputStateBase, BackendTraits> {
using BackendType = typename BackendTraits::InputStateType; using BackendType = typename BackendTraits::InputStateType;
}; };
template<typename BackendTraits> template <typename BackendTraits>
struct ToBackendTraits<PipelineLayoutBase, BackendTraits> { struct ToBackendTraits<PipelineLayoutBase, BackendTraits> {
using BackendType = typename BackendTraits::PipelineLayoutType; using BackendType = typename BackendTraits::PipelineLayoutType;
}; };
template<typename BackendTraits> template <typename BackendTraits>
struct ToBackendTraits<QueueBase, BackendTraits> { struct ToBackendTraits<QueueBase, BackendTraits> {
using BackendType = typename BackendTraits::QueueType; using BackendType = typename BackendTraits::QueueType;
}; };
template<typename BackendTraits> template <typename BackendTraits>
struct ToBackendTraits<RenderPassBase, BackendTraits> { struct ToBackendTraits<RenderPassBase, BackendTraits> {
using BackendType = typename BackendTraits::RenderPassType; using BackendType = typename BackendTraits::RenderPassType;
}; };
template<typename BackendTraits> template <typename BackendTraits>
struct ToBackendTraits<RenderPipelineBase, BackendTraits> { struct ToBackendTraits<RenderPipelineBase, BackendTraits> {
using BackendType = typename BackendTraits::RenderPipelineType; using BackendType = typename BackendTraits::RenderPipelineType;
}; };
template<typename BackendTraits> template <typename BackendTraits>
struct ToBackendTraits<SamplerBase, BackendTraits> { struct ToBackendTraits<SamplerBase, BackendTraits> {
using BackendType = typename BackendTraits::SamplerType; using BackendType = typename BackendTraits::SamplerType;
}; };
template<typename BackendTraits> template <typename BackendTraits>
struct ToBackendTraits<ShaderModuleBase, BackendTraits> { struct ToBackendTraits<ShaderModuleBase, BackendTraits> {
using BackendType = typename BackendTraits::ShaderModuleType; using BackendType = typename BackendTraits::ShaderModuleType;
}; };
template<typename BackendTraits> template <typename BackendTraits>
struct ToBackendTraits<TextureBase, BackendTraits> { struct ToBackendTraits<TextureBase, BackendTraits> {
using BackendType = typename BackendTraits::TextureType; using BackendType = typename BackendTraits::TextureType;
}; };
template<typename BackendTraits> template <typename BackendTraits>
struct ToBackendTraits<SwapChainBase, BackendTraits> { struct ToBackendTraits<SwapChainBase, BackendTraits> {
using BackendType = typename BackendTraits::SwapChainType; using BackendType = typename BackendTraits::SwapChainType;
}; };
template<typename BackendTraits> template <typename BackendTraits>
struct ToBackendTraits<TextureViewBase, BackendTraits> { struct ToBackendTraits<TextureViewBase, BackendTraits> {
using BackendType = typename BackendTraits::TextureViewType; using BackendType = typename BackendTraits::TextureViewType;
}; };
@ -130,26 +130,30 @@ namespace backend {
// return ToBackendBase<MyBackendTraits>(common); // return ToBackendBase<MyBackendTraits>(common);
// } // }
template<typename BackendTraits, typename T> template <typename BackendTraits, typename T>
Ref<typename ToBackendTraits<T, BackendTraits>::BackendType>& ToBackendBase(Ref<T>& common) { Ref<typename ToBackendTraits<T, BackendTraits>::BackendType>& ToBackendBase(Ref<T>& common) {
return reinterpret_cast<Ref<typename ToBackendTraits<T, BackendTraits>::BackendType>&>(common); return reinterpret_cast<Ref<typename ToBackendTraits<T, BackendTraits>::BackendType>&>(
common);
} }
template<typename BackendTraits, typename T> template <typename BackendTraits, typename T>
const Ref<typename ToBackendTraits<T, BackendTraits>::BackendType>& ToBackendBase(const Ref<T>& common) { const Ref<typename ToBackendTraits<T, BackendTraits>::BackendType>& ToBackendBase(
return reinterpret_cast<const Ref<typename ToBackendTraits<T, BackendTraits>::BackendType>&>(common); const Ref<T>& common) {
return reinterpret_cast<
const Ref<typename ToBackendTraits<T, BackendTraits>::BackendType>&>(common);
} }
template<typename BackendTraits, typename T> template <typename BackendTraits, typename T>
typename ToBackendTraits<T, BackendTraits>::BackendType* ToBackendBase(T* common) { typename ToBackendTraits<T, BackendTraits>::BackendType* ToBackendBase(T* common) {
return reinterpret_cast<typename ToBackendTraits<T, BackendTraits>::BackendType*>(common); return reinterpret_cast<typename ToBackendTraits<T, BackendTraits>::BackendType*>(common);
} }
template<typename BackendTraits, typename T> template <typename BackendTraits, typename T>
const typename ToBackendTraits<T, BackendTraits>::BackendType* ToBackendBase(const T* common) { const typename ToBackendTraits<T, BackendTraits>::BackendType* ToBackendBase(const T* common) {
return reinterpret_cast<const typename ToBackendTraits<T, BackendTraits>::BackendType*>(common); return reinterpret_cast<const typename ToBackendTraits<T, BackendTraits>::BackendType*>(
common);
} }
} } // namespace backend
#endif // BACKEND_TOBACKEND_H_ #endif // BACKEND_TOBACKEND_H_