diff options
Diffstat (limited to 'chromium/third_party/dawn/src/dawn_native')
181 files changed, 6353 insertions, 1906 deletions
diff --git a/chromium/third_party/dawn/src/dawn_native/Adapter.cpp b/chromium/third_party/dawn/src/dawn_native/Adapter.cpp index 6e51f17f593..362b540c0bd 100644 --- a/chromium/third_party/dawn/src/dawn_native/Adapter.cpp +++ b/chromium/third_party/dawn/src/dawn_native/Adapter.cpp @@ -38,6 +38,24 @@ namespace dawn_native { return mInstance; } + ExtensionsSet AdapterBase::GetSupportedExtensions() const { + return mSupportedExtensions; + } + + bool AdapterBase::SupportsAllRequestedExtensions( + const std::vector<const char*>& requestedExtensions) const { + for (const char* extensionStr : requestedExtensions) { + Extension extensionEnum = mInstance->ExtensionNameToEnum(extensionStr); + if (extensionEnum == Extension::InvalidEnum) { + return false; + } + if (!mSupportedExtensions.IsEnabled(extensionEnum)) { + return false; + } + } + return true; + } + DeviceBase* AdapterBase::CreateDevice(const DeviceDescriptor* descriptor) { DeviceBase* result = nullptr; @@ -50,6 +68,12 @@ namespace dawn_native { MaybeError AdapterBase::CreateDeviceInternal(DeviceBase** result, const DeviceDescriptor* descriptor) { + if (descriptor != nullptr) { + if (!SupportsAllRequestedExtensions(descriptor->requiredExtensions)) { + return DAWN_VALIDATION_ERROR("One or more requested extensions are not supported"); + } + } + // TODO(cwallez@chromium.org): This will eventually have validation that the device // descriptor is valid and is a subset what's allowed on this adapter. DAWN_TRY_ASSIGN(*result, CreateDeviceImpl(descriptor)); diff --git a/chromium/third_party/dawn/src/dawn_native/Adapter.h b/chromium/third_party/dawn/src/dawn_native/Adapter.h index 6c9d3f16947..f4cb28ae6ef 100644 --- a/chromium/third_party/dawn/src/dawn_native/Adapter.h +++ b/chromium/third_party/dawn/src/dawn_native/Adapter.h @@ -18,6 +18,7 @@ #include "dawn_native/DawnNative.h" #include "dawn_native/Error.h" +#include "dawn_native/Extensions.h" namespace dawn_native { @@ -35,9 +36,14 @@ namespace dawn_native { DeviceBase* CreateDevice(const DeviceDescriptor* descriptor = nullptr); + ExtensionsSet GetSupportedExtensions() const; + bool SupportsAllRequestedExtensions( + const std::vector<const char*>& requestedExtensions) const; + protected: PCIInfo mPCIInfo = {}; DeviceType mDeviceType = DeviceType::Unknown; + ExtensionsSet mSupportedExtensions; private: virtual ResultOrError<DeviceBase*> CreateDeviceImpl(const DeviceDescriptor* descriptor) = 0; diff --git a/chromium/third_party/dawn/src/dawn_native/AttachmentState.cpp b/chromium/third_party/dawn/src/dawn_native/AttachmentState.cpp new file mode 100644 index 00000000000..d21b01885f9 --- /dev/null +++ b/chromium/third_party/dawn/src/dawn_native/AttachmentState.cpp @@ -0,0 +1,149 @@ +// Copyright 2019 The Dawn Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "dawn_native/AttachmentState.h" + +#include "common/BitSetIterator.h" +#include "common/HashUtils.h" +#include "dawn_native/Device.h" +#include "dawn_native/Texture.h" + +namespace dawn_native { + + AttachmentStateBlueprint::AttachmentStateBlueprint( + const RenderBundleEncoderDescriptor* descriptor) + : mSampleCount(descriptor->sampleCount) { + for (uint32_t i = 0; i < descriptor->colorFormatsCount; ++i) { + mColorAttachmentsSet.set(i); + mColorFormats[i] = descriptor->colorFormats[i]; + } + mDepthStencilFormat = descriptor->depthStencilFormat; + } + + AttachmentStateBlueprint::AttachmentStateBlueprint(const RenderPipelineDescriptor* descriptor) + : mSampleCount(descriptor->sampleCount) { + for (uint32_t i = 0; i < descriptor->colorStateCount; ++i) { + ASSERT(descriptor->colorStates[i] != nullptr); + mColorAttachmentsSet.set(i); + mColorFormats[i] = descriptor->colorStates[i]->format; + } + if (descriptor->depthStencilState != nullptr) { + mDepthStencilFormat = descriptor->depthStencilState->format; + } + } + + AttachmentStateBlueprint::AttachmentStateBlueprint(const RenderPassDescriptor* descriptor) { + for (uint32_t i = 0; i < descriptor->colorAttachmentCount; ++i) { + TextureViewBase* attachment = descriptor->colorAttachments[i]->attachment; + mColorAttachmentsSet.set(i); + mColorFormats[i] = attachment->GetFormat().format; + if (mSampleCount == 0) { + mSampleCount = attachment->GetTexture()->GetSampleCount(); + } else { + ASSERT(mSampleCount == attachment->GetTexture()->GetSampleCount()); + } + } + if (descriptor->depthStencilAttachment != nullptr) { + TextureViewBase* attachment = descriptor->depthStencilAttachment->attachment; + mDepthStencilFormat = attachment->GetFormat().format; + if (mSampleCount == 0) { + mSampleCount = attachment->GetTexture()->GetSampleCount(); + } else { + ASSERT(mSampleCount == attachment->GetTexture()->GetSampleCount()); + } + } + ASSERT(mSampleCount > 0); + } + + AttachmentStateBlueprint::AttachmentStateBlueprint(const AttachmentStateBlueprint& rhs) = + default; + + size_t AttachmentStateBlueprint::HashFunc::operator()( + const AttachmentStateBlueprint* attachmentState) const { + size_t hash = 0; + + // Hash color formats + HashCombine(&hash, attachmentState->mColorAttachmentsSet); + for (uint32_t i : IterateBitSet(attachmentState->mColorAttachmentsSet)) { + HashCombine(&hash, attachmentState->mColorFormats[i]); + } + + // Hash depth stencil attachment + HashCombine(&hash, attachmentState->mDepthStencilFormat); + + // Hash sample count + HashCombine(&hash, attachmentState->mSampleCount); + + return hash; + } + + bool AttachmentStateBlueprint::EqualityFunc::operator()( + const AttachmentStateBlueprint* a, + const AttachmentStateBlueprint* b) const { + // Check set attachments + if (a->mColorAttachmentsSet != b->mColorAttachmentsSet) { + return false; + } + + // Check color formats + for (uint32_t i : IterateBitSet(a->mColorAttachmentsSet)) { + if (a->mColorFormats[i] != b->mColorFormats[i]) { + return false; + } + } + + // Check depth stencil format + if (a->mDepthStencilFormat != b->mDepthStencilFormat) { + return false; + } + + // Check sample count + if (a->mSampleCount != b->mSampleCount) { + return false; + } + + return true; + } + + AttachmentState::AttachmentState(DeviceBase* device, const AttachmentStateBlueprint& blueprint) + : AttachmentStateBlueprint(blueprint), RefCounted(), mDevice(device) { + } + + AttachmentState::~AttachmentState() { + mDevice->UncacheAttachmentState(this); + } + + std::bitset<kMaxColorAttachments> AttachmentState::GetColorAttachmentsMask() const { + return mColorAttachmentsSet; + } + + dawn::TextureFormat AttachmentState::GetColorAttachmentFormat(uint32_t index) const { + ASSERT(mColorAttachmentsSet[index]); + return mColorFormats[index]; + } + + bool AttachmentState::HasDepthStencilAttachment() const { + return mDepthStencilFormat != dawn::TextureFormat::Undefined; + } + + dawn::TextureFormat AttachmentState::GetDepthStencilFormat() const { + ASSERT(HasDepthStencilAttachment()); + return mDepthStencilFormat; + } + + uint32_t AttachmentState::GetSampleCount() const { + return mSampleCount; + } + +} // namespace dawn_native diff --git a/chromium/third_party/dawn/src/dawn_native/AttachmentState.h b/chromium/third_party/dawn/src/dawn_native/AttachmentState.h new file mode 100644 index 00000000000..7a2001a35e5 --- /dev/null +++ b/chromium/third_party/dawn/src/dawn_native/AttachmentState.h @@ -0,0 +1,76 @@ +// Copyright 2019 The Dawn Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef DAWNNATIVE_ATTACHMENTSTATE_H_ +#define DAWNNATIVE_ATTACHMENTSTATE_H_ + +#include "common/Constants.h" +#include "dawn_native/RefCounted.h" + +#include "dawn_native/dawn_platform.h" + +#include <array> +#include <bitset> + +namespace dawn_native { + + class DeviceBase; + + // AttachmentStateBlueprint and AttachmentState are separated so the AttachmentState + // can be constructed by copying the blueprint state instead of traversing descriptors. + // Also, AttachmentStateBlueprint does not need a refcount like AttachmentState. + class AttachmentStateBlueprint { + public: + // Note: Descriptors must be validated before the AttachmentState is constructed. + explicit AttachmentStateBlueprint(const RenderBundleEncoderDescriptor* descriptor); + explicit AttachmentStateBlueprint(const RenderPipelineDescriptor* descriptor); + explicit AttachmentStateBlueprint(const RenderPassDescriptor* descriptor); + + AttachmentStateBlueprint(const AttachmentStateBlueprint& rhs); + + // Functors necessary for the unordered_set<AttachmentState*>-based cache. + struct HashFunc { + size_t operator()(const AttachmentStateBlueprint* attachmentState) const; + }; + struct EqualityFunc { + bool operator()(const AttachmentStateBlueprint* a, + const AttachmentStateBlueprint* b) const; + }; + + protected: + std::bitset<kMaxColorAttachments> mColorAttachmentsSet; + std::array<dawn::TextureFormat, kMaxColorAttachments> mColorFormats; + // Default (texture format Undefined) indicates there is no depth stencil attachment. + dawn::TextureFormat mDepthStencilFormat = dawn::TextureFormat::Undefined; + uint32_t mSampleCount = 0; + }; + + class AttachmentState : public AttachmentStateBlueprint, public RefCounted { + public: + AttachmentState(DeviceBase* device, const AttachmentStateBlueprint& blueprint); + ~AttachmentState() override; + + std::bitset<kMaxColorAttachments> GetColorAttachmentsMask() const; + dawn::TextureFormat GetColorAttachmentFormat(uint32_t index) const; + bool HasDepthStencilAttachment() const; + dawn::TextureFormat GetDepthStencilFormat() const; + uint32_t GetSampleCount() const; + + private: + DeviceBase* mDevice; + }; + +} // namespace dawn_native + +#endif // DAWNNATIVE_ATTACHMENTSTATE_H_ diff --git a/chromium/third_party/dawn/src/dawn_native/BindGroup.cpp b/chromium/third_party/dawn/src/dawn_native/BindGroup.cpp index da018e1230c..15c971f5357 100644 --- a/chromium/third_party/dawn/src/dawn_native/BindGroup.cpp +++ b/chromium/third_party/dawn/src/dawn_native/BindGroup.cpp @@ -30,7 +30,7 @@ namespace dawn_native { MaybeError ValidateBufferBinding(const DeviceBase* device, const BindGroupBinding& binding, - dawn::BufferUsageBit requiredUsage) { + dawn::BufferUsage requiredUsage) { if (binding.buffer == nullptr || binding.sampler != nullptr || binding.textureView != nullptr) { return DAWN_VALIDATION_ERROR("expected buffer binding"); @@ -63,17 +63,29 @@ namespace dawn_native { MaybeError ValidateTextureBinding(const DeviceBase* device, const BindGroupBinding& binding, - dawn::TextureUsageBit requiredUsage) { + dawn::TextureUsage requiredUsage, + bool multisampledBinding, + dawn::TextureComponentType requiredComponentType) { if (binding.textureView == nullptr || binding.sampler != nullptr || binding.buffer != nullptr) { return DAWN_VALIDATION_ERROR("expected texture binding"); } DAWN_TRY(device->ValidateObject(binding.textureView)); - if (!(binding.textureView->GetTexture()->GetUsage() & requiredUsage)) { + TextureBase* texture = binding.textureView->GetTexture(); + + if (!(texture->GetUsage() & requiredUsage)) { return DAWN_VALIDATION_ERROR("texture binding usage mismatch"); } + if (texture->IsMultisampledTexture() != multisampledBinding) { + return DAWN_VALIDATION_ERROR("texture multisampling mismatch"); + } + + if (!texture->GetFormat().HasComponentType(requiredComponentType)) { + return DAWN_VALIDATION_ERROR("texture component type usage mismatch"); + } + return {}; } @@ -127,14 +139,16 @@ namespace dawn_native { // Perform binding-type specific validation. switch (layoutInfo.types[bindingIndex]) { case dawn::BindingType::UniformBuffer: - DAWN_TRY(ValidateBufferBinding(device, binding, dawn::BufferUsageBit::Uniform)); + DAWN_TRY(ValidateBufferBinding(device, binding, dawn::BufferUsage::Uniform)); break; case dawn::BindingType::StorageBuffer: - DAWN_TRY(ValidateBufferBinding(device, binding, dawn::BufferUsageBit::Storage)); + DAWN_TRY(ValidateBufferBinding(device, binding, dawn::BufferUsage::Storage)); break; case dawn::BindingType::SampledTexture: DAWN_TRY( - ValidateTextureBinding(device, binding, dawn::TextureUsageBit::Sampled)); + ValidateTextureBinding(device, binding, dawn::TextureUsage::Sampled, + layoutInfo.multisampled[bindingIndex], + layoutInfo.textureComponentTypes[bindingIndex])); break; case dawn::BindingType::Sampler: DAWN_TRY(ValidateSamplerBinding(device, binding)); diff --git a/chromium/third_party/dawn/src/dawn_native/BindGroupLayout.cpp b/chromium/third_party/dawn/src/dawn_native/BindGroupLayout.cpp index 90cdb06021d..57bc2ecf033 100644 --- a/chromium/third_party/dawn/src/dawn_native/BindGroupLayout.cpp +++ b/chromium/third_party/dawn/src/dawn_native/BindGroupLayout.cpp @@ -30,10 +30,13 @@ namespace dawn_native { } std::bitset<kMaxBindingsPerGroup> bindingsSet; + uint32_t dynamicUniformBufferCount = 0; + uint32_t dynamicStorageBufferCount = 0; for (uint32_t i = 0; i < descriptor->bindingCount; ++i) { const BindGroupLayoutBinding& binding = descriptor->bindings[i]; - DAWN_TRY(ValidateShaderStageBit(binding.visibility)); + DAWN_TRY(ValidateShaderStage(binding.visibility)); DAWN_TRY(ValidateBindingType(binding.type)); + DAWN_TRY(ValidateTextureComponentType(binding.textureComponentType)); if (binding.binding >= kMaxBindingsPerGroup) { return DAWN_VALIDATION_ERROR("some binding index exceeds the maximum value"); @@ -42,9 +45,20 @@ namespace dawn_native { return DAWN_VALIDATION_ERROR("some binding index was specified more than once"); } + if (binding.visibility == dawn::ShaderStage::None) { + return DAWN_VALIDATION_ERROR("Visibility of bindings can't be None"); + } + switch (binding.type) { case dawn::BindingType::UniformBuffer: + if (binding.dynamic) { + ++dynamicUniformBufferCount; + } + break; case dawn::BindingType::StorageBuffer: + if (binding.dynamic) { + ++dynamicStorageBufferCount; + } break; case dawn::BindingType::SampledTexture: case dawn::BindingType::Sampler: @@ -65,6 +79,17 @@ namespace dawn_native { bindingsSet.set(binding.binding); } + + if (dynamicUniformBufferCount > kMaxDynamicUniformBufferCount) { + return DAWN_VALIDATION_ERROR( + "The number of dynamic uniform buffer exceeds the maximum value"); + } + + if (dynamicStorageBufferCount > kMaxDynamicStorageBufferCount) { + return DAWN_VALIDATION_ERROR( + "The number of dynamic storage buffer exceeds the maximum value"); + } + return {}; } @@ -74,7 +99,8 @@ namespace dawn_native { HashCombine(&hash, info.dynamic, info.multisampled); for (uint32_t binding : IterateBitSet(info.mask)) { - HashCombine(&hash, info.visibilities[binding], info.types[binding]); + HashCombine(&hash, info.visibilities[binding], info.types[binding], + info.textureComponentTypes[binding]); } return hash; @@ -88,7 +114,8 @@ namespace dawn_native { for (uint32_t binding : IterateBitSet(a.mask)) { if ((a.visibilities[binding] != b.visibilities[binding]) || - (a.types[binding] != b.types[binding])) { + (a.types[binding] != b.types[binding]) || + (a.textureComponentTypes[binding] != b.textureComponentTypes[binding])) { return false; } } @@ -109,10 +136,24 @@ namespace dawn_native { uint32_t index = binding.binding; mBindingInfo.visibilities[index] = binding.visibility; mBindingInfo.types[index] = binding.type; + mBindingInfo.textureComponentTypes[index] = binding.textureComponentType; if (binding.dynamic) { mBindingInfo.dynamic.set(index); - mDynamicBufferCount++; + switch (binding.type) { + case dawn::BindingType::UniformBuffer: + ++mDynamicUniformBufferCount; + break; + case dawn::BindingType::StorageBuffer: + ++mDynamicStorageBufferCount; + break; + case dawn::BindingType::SampledTexture: + case dawn::BindingType::Sampler: + case dawn::BindingType::ReadonlyStorageBuffer: + case dawn::BindingType::StorageTexture: + UNREACHABLE(); + break; + } } mBindingInfo.multisampled.set(index, binding.multisampled); @@ -153,7 +194,15 @@ namespace dawn_native { } uint32_t BindGroupLayoutBase::GetDynamicBufferCount() const { - return mDynamicBufferCount; + return mDynamicStorageBufferCount + mDynamicUniformBufferCount; + } + + uint32_t BindGroupLayoutBase::GetDynamicUniformBufferCount() const { + return mDynamicUniformBufferCount; + } + + uint32_t BindGroupLayoutBase::GetDynamicStorageBufferCount() const { + return mDynamicStorageBufferCount; } } // namespace dawn_native diff --git a/chromium/third_party/dawn/src/dawn_native/BindGroupLayout.h b/chromium/third_party/dawn/src/dawn_native/BindGroupLayout.h index 4607c3718fa..1bb747184e0 100644 --- a/chromium/third_party/dawn/src/dawn_native/BindGroupLayout.h +++ b/chromium/third_party/dawn/src/dawn_native/BindGroupLayout.h @@ -40,8 +40,9 @@ namespace dawn_native { static BindGroupLayoutBase* MakeError(DeviceBase* device); struct LayoutBindingInfo { - std::array<dawn::ShaderStageBit, kMaxBindingsPerGroup> visibilities; + std::array<dawn::ShaderStage, kMaxBindingsPerGroup> visibilities; std::array<dawn::BindingType, kMaxBindingsPerGroup> types; + std::array<dawn::TextureComponentType, kMaxBindingsPerGroup> textureComponentTypes; std::bitset<kMaxBindingsPerGroup> dynamic; std::bitset<kMaxBindingsPerGroup> multisampled; std::bitset<kMaxBindingsPerGroup> mask; @@ -57,13 +58,16 @@ namespace dawn_native { }; uint32_t GetDynamicBufferCount() const; + uint32_t GetDynamicUniformBufferCount() const; + uint32_t GetDynamicStorageBufferCount() const; private: BindGroupLayoutBase(DeviceBase* device, ObjectBase::ErrorTag tag); LayoutBindingInfo mBindingInfo; bool mIsBlueprint = false; - uint32_t mDynamicBufferCount = 0; + uint32_t mDynamicUniformBufferCount = 0; + uint32_t mDynamicStorageBufferCount = 0; }; } // namespace dawn_native diff --git a/chromium/third_party/dawn/src/dawn_native/BuddyAllocator.cpp b/chromium/third_party/dawn/src/dawn_native/BuddyAllocator.cpp new file mode 100644 index 00000000000..a96dd883181 --- /dev/null +++ b/chromium/third_party/dawn/src/dawn_native/BuddyAllocator.cpp @@ -0,0 +1,267 @@ +// Copyright 2019 The Dawn Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "dawn_native/BuddyAllocator.h" + +#include "common/Assert.h" +#include "common/Math.h" + +namespace dawn_native { + + BuddyAllocator::BuddyAllocator(uint64_t maxSize) : mMaxBlockSize(maxSize) { + ASSERT(IsPowerOfTwo(maxSize)); + + mFreeLists.resize(Log2(mMaxBlockSize) + 1); + + // Insert the level0 free block. + mRoot = new BuddyBlock(maxSize, /*offset*/ 0); + mFreeLists[0] = {mRoot}; + } + + BuddyAllocator::~BuddyAllocator() { + if (mRoot) { + DeleteBlock(mRoot); + } + } + + uint64_t BuddyAllocator::ComputeTotalNumOfFreeBlocksForTesting() const { + return ComputeNumOfFreeBlocks(mRoot); + } + + uint64_t BuddyAllocator::ComputeNumOfFreeBlocks(BuddyBlock* block) const { + if (block->mState == BlockState::Free) { + return 1; + } else if (block->mState == BlockState::Split) { + return ComputeNumOfFreeBlocks(block->split.pLeft) + + ComputeNumOfFreeBlocks(block->split.pLeft->pBuddy); + } + return 0; + } + + uint32_t BuddyAllocator::ComputeLevelFromBlockSize(uint64_t blockSize) const { + // Every level in the buddy system can be indexed by order-n where n = log2(blockSize). + // However, mFreeList zero-indexed by level. + // For example, blockSize=4 is Level1 if MAX_BLOCK is 8. + return Log2(mMaxBlockSize) - Log2(blockSize); + } + + uint64_t BuddyAllocator::GetNextFreeAlignedBlock(size_t allocationBlockLevel, + uint64_t alignment) const { + ASSERT(IsPowerOfTwo(alignment)); + // The current level is the level that corresponds to the allocation size. The free list may + // not contain a block at that level until a larger one gets allocated (and splits). + // Continue to go up the tree until such a larger block exists. + // + // Even if the block exists at the level, it cannot be used if it's offset is unaligned. + // When the alignment is also a power-of-two, we simply use the next free block whose size + // is greater than or equal to the alignment value. + // + // After one 8-byte allocation: + // + // Level -------------------------------- + // 0 32 | S | + // -------------------------------- + // 1 16 | S | F2 | S - split + // -------------------------------- F - free + // 2 8 | Aa | F1 | | A - allocated + // -------------------------------- + // + // Allocate(size=8, alignment=8) will be satisfied by using F1. + // Allocate(size=8, alignment=4) will be satified by using F1. + // Allocate(size=8, alignment=16) will be satisified by using F2. + // + for (size_t currLevel = allocationBlockLevel; currLevel >= 0; currLevel--) { + BuddyBlock* freeBlock = mFreeLists[currLevel].head; + if (freeBlock && (freeBlock->mOffset % alignment == 0)) { + return currLevel; + } + + if (currLevel == 0) { + break; + } + } + return INVALID_OFFSET; // No free block exists at any level. + } + + // Inserts existing free block into the free-list. + // Called by allocate upon splitting to insert a child block into a free-list. + // Note: Always insert into the head of the free-list. As when a larger free block at a lower + // level was split, there were no smaller free blocks at a higher level to allocate. + void BuddyAllocator::InsertFreeBlock(BuddyBlock* block, size_t level) { + ASSERT(block->mState == BlockState::Free); + + // Inserted block is now the front (no prev). + block->free.pPrev = nullptr; + + // Old head is now the inserted block's next. + block->free.pNext = mFreeLists[level].head; + + // Block already in HEAD position (ex. right child was inserted first). + if (mFreeLists[level].head != nullptr) { + // Old head's previous is the inserted block. + mFreeLists[level].head->free.pPrev = block; + } + + mFreeLists[level].head = block; + } + + void BuddyAllocator::RemoveFreeBlock(BuddyBlock* block, size_t level) { + ASSERT(block->mState == BlockState::Free); + + if (mFreeLists[level].head == block) { + // Block is in HEAD position. + mFreeLists[level].head = mFreeLists[level].head->free.pNext; + } else { + // Block is after HEAD position. + BuddyBlock* pPrev = block->free.pPrev; + BuddyBlock* pNext = block->free.pNext; + + ASSERT(pPrev != nullptr); + ASSERT(pPrev->mState == BlockState::Free); + + pPrev->free.pNext = pNext; + + if (pNext != nullptr) { + ASSERT(pNext->mState == BlockState::Free); + pNext->free.pPrev = pPrev; + } + } + } + + uint64_t BuddyAllocator::Allocate(uint64_t allocationSize, uint64_t alignment) { + if (allocationSize == 0 || allocationSize > mMaxBlockSize) { + return INVALID_OFFSET; + } + + // Compute the level + const uint32_t allocationSizeToLevel = ComputeLevelFromBlockSize(allocationSize); + + ASSERT(allocationSizeToLevel < mFreeLists.size()); + + uint64_t currBlockLevel = GetNextFreeAlignedBlock(allocationSizeToLevel, alignment); + + // Error when no free blocks exist (allocator is full) + if (currBlockLevel == INVALID_OFFSET) { + return INVALID_OFFSET; + } + + // Split free blocks level-by-level. + // Terminate when the current block level is equal to the computed level of the requested + // allocation. + BuddyBlock* currBlock = mFreeLists[currBlockLevel].head; + + for (; currBlockLevel < allocationSizeToLevel; currBlockLevel++) { + ASSERT(currBlock->mState == BlockState::Free); + + // Remove curr block (about to be split). + RemoveFreeBlock(currBlock, currBlockLevel); + + // Create two free child blocks (the buddies). + const uint64_t nextLevelSize = currBlock->mSize / 2; + BuddyBlock* leftChildBlock = new BuddyBlock(nextLevelSize, currBlock->mOffset); + BuddyBlock* rightChildBlock = + new BuddyBlock(nextLevelSize, currBlock->mOffset + nextLevelSize); + + // Remember the parent to merge these back upon de-allocation. + rightChildBlock->pParent = currBlock; + leftChildBlock->pParent = currBlock; + + // Make them buddies. + leftChildBlock->pBuddy = rightChildBlock; + rightChildBlock->pBuddy = leftChildBlock; + + // Insert the children back into the free list into the next level. + // The free list does not require a specific order. However, an order is specified as + // it's ideal to allocate lower addresses first by having the leftmost child in HEAD. + InsertFreeBlock(rightChildBlock, currBlockLevel + 1); + InsertFreeBlock(leftChildBlock, currBlockLevel + 1); + + // Curr block is now split. + currBlock->mState = BlockState::Split; + currBlock->split.pLeft = leftChildBlock; + + // Decend down into the next level. + currBlock = leftChildBlock; + } + + // Remove curr block from free-list (now allocated). + RemoveFreeBlock(currBlock, currBlockLevel); + currBlock->mState = BlockState::Allocated; + + return currBlock->mOffset; + } + + void BuddyAllocator::Deallocate(uint64_t offset) { + BuddyBlock* curr = mRoot; + + // TODO(bryan.bernhart@intel.com): Optimize de-allocation. + // Passing allocationSize directly will avoid the following level-by-level search; + // however, it requires the size information to be stored outside the allocator. + + // Search for the free block node that corresponds to the block offset. + size_t currBlockLevel = 0; + while (curr->mState == BlockState::Split) { + if (offset < curr->split.pLeft->pBuddy->mOffset) { + curr = curr->split.pLeft; + } else { + curr = curr->split.pLeft->pBuddy; + } + + currBlockLevel++; + } + + ASSERT(curr->mState == BlockState::Allocated); + + // Ensure the block is at the correct level + ASSERT(currBlockLevel == ComputeLevelFromBlockSize(curr->mSize)); + + // Mark curr free so we can merge. + curr->mState = BlockState::Free; + + // Merge the buddies (LevelN-to-Level0). + while (currBlockLevel > 0 && curr->pBuddy->mState == BlockState::Free) { + // Remove the buddy. + RemoveFreeBlock(curr->pBuddy, currBlockLevel); + + BuddyBlock* parent = curr->pParent; + + // The buddies were inserted in a specific order but + // could be deleted in any order. + DeleteBlock(curr->pBuddy); + DeleteBlock(curr); + + // Parent is now free. + parent->mState = BlockState::Free; + + // Ascend up to the next level (parent block). + curr = parent; + currBlockLevel--; + } + + InsertFreeBlock(curr, currBlockLevel); + } + + // Helper which deletes a block in the tree recursively (post-order). + void BuddyAllocator::DeleteBlock(BuddyBlock* block) { + ASSERT(block != nullptr); + + if (block->mState == BlockState::Split) { + // Delete the pair in same order we inserted. + DeleteBlock(block->split.pLeft->pBuddy); + DeleteBlock(block->split.pLeft); + } + delete block; + } + +} // namespace dawn_native
\ No newline at end of file diff --git a/chromium/third_party/dawn/src/dawn_native/BuddyAllocator.h b/chromium/third_party/dawn/src/dawn_native/BuddyAllocator.h new file mode 100644 index 00000000000..df689f3b3db --- /dev/null +++ b/chromium/third_party/dawn/src/dawn_native/BuddyAllocator.h @@ -0,0 +1,111 @@ +// Copyright 2019 The Dawn Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef DAWNNATIVE_BUDDYALLOCATOR_H_ +#define DAWNNATIVE_BUDDYALLOCATOR_H_ + +#include <cstddef> +#include <vector> + +namespace dawn_native { + + static constexpr uint64_t INVALID_OFFSET = std::numeric_limits<uint64_t>::max(); + + // Buddy allocator uses the buddy memory allocation technique to satisify an allocation request. + // Memory is split into halves until just large enough to fit to the request. This + // requires the allocation size to be a power-of-two value. The allocator "allocates" a block by + // returning the starting offset whose size is guaranteed to be greater than or equal to the + // allocation size. To deallocate, the same offset is used to find the corresponding block. + // + // Internally, it manages a free list to track free blocks in a full binary tree. + // Every index in the free list corresponds to a level in the tree. That level also determines + // the size of the block to be used to satisfy the request. The first level (index=0) represents + // the root whose size is also called the max block size. + // + class BuddyAllocator { + public: + BuddyAllocator(uint64_t maxSize); + ~BuddyAllocator(); + + // Required methods. + uint64_t Allocate(uint64_t allocationSize, uint64_t alignment = 1); + void Deallocate(uint64_t offset); + + // For testing purposes only. + uint64_t ComputeTotalNumOfFreeBlocksForTesting() const; + + private: + uint32_t ComputeLevelFromBlockSize(uint64_t blockSize) const; + uint64_t GetNextFreeAlignedBlock(size_t allocationBlockLevel, uint64_t alignment) const; + + enum class BlockState { Free, Split, Allocated }; + + struct BuddyBlock { + BuddyBlock(uint64_t size, uint64_t offset) + : mOffset(offset), mSize(size), mState(BlockState::Free) { + free.pPrev = nullptr; + free.pNext = nullptr; + } + + uint64_t mOffset; + uint64_t mSize; + + // Pointer to this block's buddy, iff parent is split. + // Used to quickly merge buddy blocks upon de-allocate. + BuddyBlock* pBuddy = nullptr; + BuddyBlock* pParent = nullptr; + + // Track whether this block has been split or not. + BlockState mState; + + union { + // Used upon allocation. + // Avoids searching for the next free block. + struct { + BuddyBlock* pPrev; + BuddyBlock* pNext; + } free; + + // Used upon de-allocation. + // Had this block split upon allocation, it and it's buddy is to be deleted. + struct { + BuddyBlock* pLeft; + } split; + }; + }; + + void InsertFreeBlock(BuddyBlock* block, size_t level); + void RemoveFreeBlock(BuddyBlock* block, size_t level); + void DeleteBlock(BuddyBlock* block); + + uint64_t ComputeNumOfFreeBlocks(BuddyBlock* block) const; + + // Keep track the head and tail (for faster insertion/removal). + struct BlockList { + BuddyBlock* head = nullptr; // First free block in level. + // TODO(bryan.bernhart@intel.com): Track the tail. + }; + + BuddyBlock* mRoot = nullptr; // Used to deallocate non-free blocks. + + uint64_t mMaxBlockSize = 0; + + // List of linked-lists of free blocks where the index is a level that + // corresponds to a power-of-two sized block. + std::vector<BlockList> mFreeLists; + }; + +} // namespace dawn_native + +#endif // DAWNNATIVE_BUDDYALLOCATOR_H_
\ No newline at end of file diff --git a/chromium/third_party/dawn/src/dawn_native/Buffer.cpp b/chromium/third_party/dawn/src/dawn_native/Buffer.cpp index a88ebabfe69..bd5b2fb1615 100644 --- a/chromium/third_party/dawn/src/dawn_native/Buffer.cpp +++ b/chromium/third_party/dawn/src/dawn_native/Buffer.cpp @@ -89,19 +89,19 @@ namespace dawn_native { return DAWN_VALIDATION_ERROR("nextInChain must be nullptr"); } - DAWN_TRY(ValidateBufferUsageBit(descriptor->usage)); + DAWN_TRY(ValidateBufferUsage(descriptor->usage)); - dawn::BufferUsageBit usage = descriptor->usage; + dawn::BufferUsage usage = descriptor->usage; - const dawn::BufferUsageBit kMapWriteAllowedUsages = - dawn::BufferUsageBit::MapWrite | dawn::BufferUsageBit::CopySrc; - if (usage & dawn::BufferUsageBit::MapWrite && (usage & kMapWriteAllowedUsages) != usage) { + const dawn::BufferUsage kMapWriteAllowedUsages = + dawn::BufferUsage::MapWrite | dawn::BufferUsage::CopySrc; + if (usage & dawn::BufferUsage::MapWrite && (usage & kMapWriteAllowedUsages) != usage) { return DAWN_VALIDATION_ERROR("Only CopySrc is allowed with MapWrite"); } - const dawn::BufferUsageBit kMapReadAllowedUsages = - dawn::BufferUsageBit::MapRead | dawn::BufferUsageBit::CopyDst; - if (usage & dawn::BufferUsageBit::MapRead && (usage & kMapReadAllowedUsages) != usage) { + const dawn::BufferUsage kMapReadAllowedUsages = + dawn::BufferUsage::MapRead | dawn::BufferUsage::CopyDst; + if (usage & dawn::BufferUsage::MapRead && (usage & kMapReadAllowedUsages) != usage) { return DAWN_VALIDATION_ERROR("Only CopyDst is allowed with MapRead"); } @@ -146,7 +146,7 @@ namespace dawn_native { return mSize; } - dawn::BufferUsageBit BufferBase::GetUsage() const { + dawn::BufferUsage BufferBase::GetUsage() const { ASSERT(!IsError()); return mUsage; } @@ -232,7 +232,7 @@ namespace dawn_native { } void BufferBase::MapReadAsync(DawnBufferMapReadCallback callback, void* userdata) { - if (GetDevice()->ConsumedError(ValidateMap(dawn::BufferUsageBit::MapRead))) { + if (GetDevice()->ConsumedError(ValidateMap(dawn::BufferUsage::MapRead))) { callback(DAWN_BUFFER_MAP_ASYNC_STATUS_ERROR, nullptr, 0, userdata); return; } @@ -255,12 +255,8 @@ namespace dawn_native { DynamicUploader* uploader = nullptr; DAWN_TRY_ASSIGN(uploader, GetDevice()->GetDynamicUploader()); - // TODO(bryan.bernhart@intel.com): Remove once alignment constraint is added to validation - // (dawn:73). D3D12 does not specify so we assume 4-byte alignment to be safe. - static constexpr size_t kDefaultAlignment = 4; - UploadHandle uploadHandle; - DAWN_TRY_ASSIGN(uploadHandle, uploader->Allocate(count, kDefaultAlignment)); + DAWN_TRY_ASSIGN(uploadHandle, uploader->Allocate(count)); ASSERT(uploadHandle.mappedBuffer != nullptr); memcpy(uploadHandle.mappedBuffer, data, count); @@ -272,7 +268,7 @@ namespace dawn_native { } void BufferBase::MapWriteAsync(DawnBufferMapWriteCallback callback, void* userdata) { - if (GetDevice()->ConsumedError(ValidateMap(dawn::BufferUsageBit::MapWrite))) { + if (GetDevice()->ConsumedError(ValidateMap(dawn::BufferUsage::MapWrite))) { callback(DAWN_BUFFER_MAP_ASYNC_STATUS_ERROR, nullptr, 0, userdata); return; } @@ -381,14 +377,14 @@ namespace dawn_native { return DAWN_VALIDATION_ERROR("Buffer subdata out of range"); } - if (!(mUsage & dawn::BufferUsageBit::CopyDst)) { + if (!(mUsage & dawn::BufferUsage::CopyDst)) { return DAWN_VALIDATION_ERROR("Buffer needs the CopyDst usage bit"); } return {}; } - MaybeError BufferBase::ValidateMap(dawn::BufferUsageBit requiredUsage) const { + MaybeError BufferBase::ValidateMap(dawn::BufferUsage requiredUsage) const { DAWN_TRY(GetDevice()->ValidateObject(this)); switch (mState) { @@ -416,8 +412,7 @@ namespace dawn_native { // even if it did not have a mappable usage. return {}; case BufferState::Unmapped: - if ((mUsage & (dawn::BufferUsageBit::MapRead | dawn::BufferUsageBit::MapWrite)) == - 0) { + if ((mUsage & (dawn::BufferUsage::MapRead | dawn::BufferUsage::MapWrite)) == 0) { return DAWN_VALIDATION_ERROR("Buffer does not have map usage"); } return {}; diff --git a/chromium/third_party/dawn/src/dawn_native/Buffer.h b/chromium/third_party/dawn/src/dawn_native/Buffer.h index e656c25c4cb..9549c50e825 100644 --- a/chromium/third_party/dawn/src/dawn_native/Buffer.h +++ b/chromium/third_party/dawn/src/dawn_native/Buffer.h @@ -27,13 +27,12 @@ namespace dawn_native { MaybeError ValidateBufferDescriptor(DeviceBase* device, const BufferDescriptor* descriptor); - static constexpr dawn::BufferUsageBit kReadOnlyBufferUsages = - dawn::BufferUsageBit::MapRead | dawn::BufferUsageBit::CopySrc | - dawn::BufferUsageBit::Index | dawn::BufferUsageBit::Vertex | dawn::BufferUsageBit::Uniform; + static constexpr dawn::BufferUsage kReadOnlyBufferUsages = + dawn::BufferUsage::MapRead | dawn::BufferUsage::CopySrc | dawn::BufferUsage::Index | + dawn::BufferUsage::Vertex | dawn::BufferUsage::Uniform; - static constexpr dawn::BufferUsageBit kWritableBufferUsages = dawn::BufferUsageBit::MapWrite | - dawn::BufferUsageBit::CopyDst | - dawn::BufferUsageBit::Storage; + static constexpr dawn::BufferUsage kWritableBufferUsages = + dawn::BufferUsage::MapWrite | dawn::BufferUsage::CopyDst | dawn::BufferUsage::Storage; class BufferBase : public ObjectBase { enum class BufferState { @@ -52,7 +51,7 @@ namespace dawn_native { uint8_t** mappedPointer); uint64_t GetSize() const; - dawn::BufferUsageBit GetUsage() const; + dawn::BufferUsage GetUsage() const; MaybeError MapAtCreation(uint8_t** mappedPointer); @@ -91,12 +90,12 @@ namespace dawn_native { MaybeError CopyFromStagingBuffer(); MaybeError ValidateSetSubData(uint32_t start, uint32_t count) const; - MaybeError ValidateMap(dawn::BufferUsageBit requiredUsage) const; + MaybeError ValidateMap(dawn::BufferUsage requiredUsage) const; MaybeError ValidateUnmap() const; MaybeError ValidateDestroy() const; uint64_t mSize = 0; - dawn::BufferUsageBit mUsage = dawn::BufferUsageBit::None; + dawn::BufferUsage mUsage = dawn::BufferUsage::None; DawnBufferMapReadCallback mMapReadCallback = nullptr; DawnBufferMapWriteCallback mMapWriteCallback = nullptr; diff --git a/chromium/third_party/dawn/src/dawn_native/CommandEncoder.cpp b/chromium/third_party/dawn/src/dawn_native/CommandEncoder.cpp index c5c351a3667..832d27a667e 100644 --- a/chromium/third_party/dawn/src/dawn_native/CommandEncoder.cpp +++ b/chromium/third_party/dawn/src/dawn_native/CommandEncoder.cpp @@ -19,12 +19,15 @@ #include "dawn_native/Buffer.h" #include "dawn_native/CommandBuffer.h" #include "dawn_native/CommandBufferStateTracker.h" +#include "dawn_native/CommandValidation.h" #include "dawn_native/Commands.h" #include "dawn_native/ComputePassEncoder.h" #include "dawn_native/Device.h" #include "dawn_native/ErrorData.h" +#include "dawn_native/PassResourceUsageTracker.h" #include "dawn_native/RenderPassEncoder.h" #include "dawn_native/RenderPipeline.h" +#include "dawn_platform/tracing/TraceEvent.h" #include <map> @@ -120,29 +123,6 @@ namespace dawn_native { return {}; } - inline MaybeError PushDebugMarkerStack(unsigned int* counter) { - *counter += 1; - return {}; - } - - inline MaybeError PopDebugMarkerStack(unsigned int* counter) { - if (*counter == 0) { - return DAWN_VALIDATION_ERROR("Pop must be balanced by a corresponding Push."); - } else { - *counter -= 1; - } - - return {}; - } - - inline MaybeError ValidateDebugGroups(const unsigned int counter) { - if (counter != 0) { - return DAWN_VALIDATION_ERROR("Each Push must be balanced by a corresponding Pop."); - } - - return {}; - } - MaybeError ValidateTextureSampleCountInCopyCommands(const TextureBase* texture) { if (texture->GetSampleCount() > 1) { return DAWN_VALIDATION_ERROR("The sample count of textures must be 1"); @@ -262,7 +242,7 @@ namespace dawn_native { return {}; } - MaybeError ValidateCanUseAs(BufferBase* buffer, dawn::BufferUsageBit usage) { + MaybeError ValidateCanUseAs(BufferBase* buffer, dawn::BufferUsage usage) { ASSERT(HasZeroOrOneBits(usage)); if (!(buffer->GetUsage() & usage)) { return DAWN_VALIDATION_ERROR("buffer doesn't have the required usage."); @@ -271,7 +251,7 @@ namespace dawn_native { return {}; } - MaybeError ValidateCanUseAs(TextureBase* texture, dawn::TextureUsageBit usage) { + MaybeError ValidateCanUseAs(TextureBase* texture, dawn::TextureUsage usage) { ASSERT(HasZeroOrOneBits(usage)); if (!(texture->GetUsage() & usage)) { return DAWN_VALIDATION_ERROR("texture doesn't have the required usage."); @@ -475,150 +455,6 @@ namespace dawn_native { return {}; } - enum class PassType { - Render, - Compute, - }; - - // Helper class to encapsulate the logic of tracking per-resource usage during the - // validation of command buffer passes. It is used both to know if there are validation - // errors, and to get a list of resources used per pass for backends that need the - // information. - class PassResourceUsageTracker { - public: - void BufferUsedAs(BufferBase* buffer, dawn::BufferUsageBit usage) { - // std::map's operator[] will create the key and return 0 if the key didn't exist - // before. - dawn::BufferUsageBit& storedUsage = mBufferUsages[buffer]; - - if (usage == dawn::BufferUsageBit::Storage && - storedUsage & dawn::BufferUsageBit::Storage) { - mStorageUsedMultipleTimes = true; - } - - storedUsage |= usage; - } - - void TextureUsedAs(TextureBase* texture, dawn::TextureUsageBit usage) { - // std::map's operator[] will create the key and return 0 if the key didn't exist - // before. - dawn::TextureUsageBit& storedUsage = mTextureUsages[texture]; - - if (usage == dawn::TextureUsageBit::Storage && - storedUsage & dawn::TextureUsageBit::Storage) { - mStorageUsedMultipleTimes = true; - } - - storedUsage |= usage; - } - - // Performs the per-pass usage validation checks - MaybeError ValidateUsages(PassType pass) const { - // Storage resources cannot be used twice in the same compute pass - if (pass == PassType::Compute && mStorageUsedMultipleTimes) { - return DAWN_VALIDATION_ERROR( - "Storage resource used multiple times in compute pass"); - } - - // Buffers can only be used as single-write or multiple read. - for (auto& it : mBufferUsages) { - BufferBase* buffer = it.first; - dawn::BufferUsageBit usage = it.second; - - if (usage & ~buffer->GetUsage()) { - return DAWN_VALIDATION_ERROR("Buffer missing usage for the pass"); - } - - bool readOnly = (usage & kReadOnlyBufferUsages) == usage; - bool singleUse = dawn::HasZeroOrOneBits(usage); - - if (!readOnly && !singleUse) { - return DAWN_VALIDATION_ERROR( - "Buffer used as writable usage and another usage in pass"); - } - } - - // Textures can only be used as single-write or multiple read. - // TODO(cwallez@chromium.org): implement per-subresource tracking - for (auto& it : mTextureUsages) { - TextureBase* texture = it.first; - dawn::TextureUsageBit usage = it.second; - - if (usage & ~texture->GetUsage()) { - return DAWN_VALIDATION_ERROR("Texture missing usage for the pass"); - } - - // For textures the only read-only usage in a pass is Sampled, so checking the - // usage constraint simplifies to checking a single usage bit is set. - if (!dawn::HasZeroOrOneBits(it.second)) { - return DAWN_VALIDATION_ERROR( - "Texture used with more than one usage in pass"); - } - } - - return {}; - } - - // Returns the per-pass usage for use by backends for APIs with explicit barriers. - PassResourceUsage AcquireResourceUsage() { - PassResourceUsage result; - result.buffers.reserve(mBufferUsages.size()); - result.bufferUsages.reserve(mBufferUsages.size()); - result.textures.reserve(mTextureUsages.size()); - result.textureUsages.reserve(mTextureUsages.size()); - - for (auto& it : mBufferUsages) { - result.buffers.push_back(it.first); - result.bufferUsages.push_back(it.second); - } - - for (auto& it : mTextureUsages) { - result.textures.push_back(it.first); - result.textureUsages.push_back(it.second); - } - - return result; - } - - private: - std::map<BufferBase*, dawn::BufferUsageBit> mBufferUsages; - std::map<TextureBase*, dawn::TextureUsageBit> mTextureUsages; - bool mStorageUsedMultipleTimes = false; - }; - - void TrackBindGroupResourceUsage(BindGroupBase* group, PassResourceUsageTracker* tracker) { - const auto& layoutInfo = group->GetLayout()->GetBindingInfo(); - - for (uint32_t i : IterateBitSet(layoutInfo.mask)) { - dawn::BindingType type = layoutInfo.types[i]; - - switch (type) { - case dawn::BindingType::UniformBuffer: { - BufferBase* buffer = group->GetBindingAsBufferBinding(i).buffer; - tracker->BufferUsedAs(buffer, dawn::BufferUsageBit::Uniform); - } break; - - case dawn::BindingType::StorageBuffer: { - BufferBase* buffer = group->GetBindingAsBufferBinding(i).buffer; - tracker->BufferUsedAs(buffer, dawn::BufferUsageBit::Storage); - } break; - - case dawn::BindingType::SampledTexture: { - TextureBase* texture = group->GetBindingAsTextureView(i)->GetTexture(); - tracker->TextureUsedAs(texture, dawn::TextureUsageBit::Sampled); - } break; - - case dawn::BindingType::Sampler: - break; - - case dawn::BindingType::StorageTexture: - case dawn::BindingType::ReadonlyStorageBuffer: - UNREACHABLE(); - break; - } - } - } - } // namespace CommandEncoderBase::CommandEncoderBase(DeviceBase* device, const CommandEncoderDescriptor*) @@ -678,22 +514,19 @@ namespace dawn_native { BeginRenderPassCmd* cmd = allocator->Allocate<BeginRenderPassCmd>(Command::BeginRenderPass); - for (uint32_t i = 0; i < descriptor->colorAttachmentCount; ++i) { - if (descriptor->colorAttachments[i] != nullptr) { - cmd->colorAttachmentsSet.set(i); - cmd->colorAttachments[i].view = descriptor->colorAttachments[i]->attachment; - cmd->colorAttachments[i].resolveTarget = - descriptor->colorAttachments[i]->resolveTarget; - cmd->colorAttachments[i].loadOp = descriptor->colorAttachments[i]->loadOp; - cmd->colorAttachments[i].storeOp = descriptor->colorAttachments[i]->storeOp; - cmd->colorAttachments[i].clearColor = - descriptor->colorAttachments[i]->clearColor; - } + cmd->attachmentState = device->GetOrCreateAttachmentState(descriptor); + + for (uint32_t i : IterateBitSet(cmd->attachmentState->GetColorAttachmentsMask())) { + cmd->colorAttachments[i].view = descriptor->colorAttachments[i]->attachment; + cmd->colorAttachments[i].resolveTarget = + descriptor->colorAttachments[i]->resolveTarget; + cmd->colorAttachments[i].loadOp = descriptor->colorAttachments[i]->loadOp; + cmd->colorAttachments[i].storeOp = descriptor->colorAttachments[i]->storeOp; + cmd->colorAttachments[i].clearColor = + descriptor->colorAttachments[i]->clearColor; } - cmd->hasDepthStencilAttachment = descriptor->depthStencilAttachment != nullptr; - if (cmd->hasDepthStencilAttachment) { - cmd->hasDepthStencilAttachment = true; + if (cmd->attachmentState->HasDepthStencilAttachment()) { cmd->depthStencilAttachment.view = descriptor->depthStencilAttachment->attachment; cmd->depthStencilAttachment.clearDepth = @@ -712,7 +545,6 @@ namespace dawn_native { cmd->width = width; cmd->height = height; - cmd->sampleCount = sampleCount; return {}; }); @@ -836,6 +668,8 @@ namespace dawn_native { } CommandBufferBase* CommandEncoderBase::Finish(const CommandBufferDescriptor* descriptor) { + TRACE_EVENT0(GetDevice()->GetPlatform(), TRACE_DISABLED_BY_DEFAULT("gpu.dawn"), + "CommandEncoderBase::Finish"); if (GetDevice()->ConsumedError(ValidateFinish(descriptor))) { // Even if finish validation fails, it is now invalid to call any encoding commands on // this object, so we set its state to finished. @@ -863,12 +697,12 @@ namespace dawn_native { switch (type) { case Command::BeginComputePass: { commands->NextCommand<BeginComputePassCmd>(); - DAWN_TRY(ValidateComputePass(commands)); + DAWN_TRY(ValidateComputePass(commands, &mResourceUsages.perPass)); } break; case Command::BeginRenderPass: { BeginRenderPassCmd* cmd = commands->NextCommand<BeginRenderPassCmd>(); - DAWN_TRY(ValidateRenderPass(commands, cmd)); + DAWN_TRY(ValidateRenderPass(commands, cmd, &mResourceUsages.perPass)); } break; case Command::CopyBufferToBuffer: { @@ -881,9 +715,8 @@ namespace dawn_native { DAWN_TRY(ValidateB2BCopySizeAlignment(copy->size, copy->sourceOffset, copy->destinationOffset)); - DAWN_TRY(ValidateCanUseAs(copy->source.Get(), dawn::BufferUsageBit::CopySrc)); - DAWN_TRY( - ValidateCanUseAs(copy->destination.Get(), dawn::BufferUsageBit::CopyDst)); + DAWN_TRY(ValidateCanUseAs(copy->source.Get(), dawn::BufferUsage::CopySrc)); + DAWN_TRY(ValidateCanUseAs(copy->destination.Get(), dawn::BufferUsage::CopyDst)); mResourceUsages.topLevelBuffers.insert(copy->source.Get()); mResourceUsages.topLevelBuffers.insert(copy->destination.Get()); @@ -916,9 +749,9 @@ namespace dawn_native { copy->destination.texture->GetFormat())); DAWN_TRY( - ValidateCanUseAs(copy->source.buffer.Get(), dawn::BufferUsageBit::CopySrc)); + ValidateCanUseAs(copy->source.buffer.Get(), dawn::BufferUsage::CopySrc)); DAWN_TRY(ValidateCanUseAs(copy->destination.texture.Get(), - dawn::TextureUsageBit::CopyDst)); + dawn::TextureUsage::CopyDst)); mResourceUsages.topLevelBuffers.insert(copy->source.buffer.Get()); mResourceUsages.topLevelTextures.insert(copy->destination.texture.Get()); @@ -950,10 +783,10 @@ namespace dawn_native { DAWN_TRY(ValidateTexelBufferOffset(copy->destination, copy->source.texture->GetFormat())); - DAWN_TRY(ValidateCanUseAs(copy->source.texture.Get(), - dawn::TextureUsageBit::CopySrc)); + DAWN_TRY( + ValidateCanUseAs(copy->source.texture.Get(), dawn::TextureUsage::CopySrc)); DAWN_TRY(ValidateCanUseAs(copy->destination.buffer.Get(), - dawn::BufferUsageBit::CopyDst)); + dawn::BufferUsage::CopyDst)); mResourceUsages.topLevelTextures.insert(copy->source.texture.Get()); mResourceUsages.topLevelBuffers.insert(copy->destination.buffer.Get()); @@ -978,10 +811,10 @@ namespace dawn_native { DAWN_TRY(ValidateCopySizeFitsInTexture(copy->source, copy->copySize)); DAWN_TRY(ValidateCopySizeFitsInTexture(copy->destination, copy->copySize)); - DAWN_TRY(ValidateCanUseAs(copy->source.texture.Get(), - dawn::TextureUsageBit::CopySrc)); + DAWN_TRY( + ValidateCanUseAs(copy->source.texture.Get(), dawn::TextureUsage::CopySrc)); DAWN_TRY(ValidateCanUseAs(copy->destination.texture.Get(), - dawn::TextureUsageBit::CopyDst)); + dawn::TextureUsage::CopyDst)); mResourceUsages.topLevelTextures.insert(copy->source.texture.Get()); mResourceUsages.topLevelTextures.insert(copy->destination.texture.Get()); @@ -995,211 +828,4 @@ namespace dawn_native { return {}; } - MaybeError CommandEncoderBase::ValidateComputePass(CommandIterator* commands) { - PassResourceUsageTracker usageTracker; - CommandBufferStateTracker persistentState; - - Command type; - while (commands->NextCommandId(&type)) { - switch (type) { - case Command::EndComputePass: { - commands->NextCommand<EndComputePassCmd>(); - - DAWN_TRY(ValidateDebugGroups(mDebugGroupStackSize)); - - DAWN_TRY(usageTracker.ValidateUsages(PassType::Compute)); - mResourceUsages.perPass.push_back(usageTracker.AcquireResourceUsage()); - return {}; - } break; - - case Command::Dispatch: { - commands->NextCommand<DispatchCmd>(); - DAWN_TRY(persistentState.ValidateCanDispatch()); - } break; - - case Command::DispatchIndirect: { - DispatchIndirectCmd* cmd = commands->NextCommand<DispatchIndirectCmd>(); - DAWN_TRY(persistentState.ValidateCanDispatch()); - usageTracker.BufferUsedAs(cmd->indirectBuffer.Get(), - dawn::BufferUsageBit::Indirect); - } break; - - case Command::InsertDebugMarker: { - InsertDebugMarkerCmd* cmd = commands->NextCommand<InsertDebugMarkerCmd>(); - commands->NextData<char>(cmd->length + 1); - } break; - - case Command::PopDebugGroup: { - commands->NextCommand<PopDebugGroupCmd>(); - DAWN_TRY(PopDebugMarkerStack(&mDebugGroupStackSize)); - } break; - - case Command::PushDebugGroup: { - PushDebugGroupCmd* cmd = commands->NextCommand<PushDebugGroupCmd>(); - commands->NextData<char>(cmd->length + 1); - DAWN_TRY(PushDebugMarkerStack(&mDebugGroupStackSize)); - } break; - - case Command::SetComputePipeline: { - SetComputePipelineCmd* cmd = commands->NextCommand<SetComputePipelineCmd>(); - ComputePipelineBase* pipeline = cmd->pipeline.Get(); - persistentState.SetComputePipeline(pipeline); - } break; - - case Command::SetBindGroup: { - SetBindGroupCmd* cmd = commands->NextCommand<SetBindGroupCmd>(); - if (cmd->dynamicOffsetCount > 0) { - commands->NextData<uint64_t>(cmd->dynamicOffsetCount); - } - - TrackBindGroupResourceUsage(cmd->group.Get(), &usageTracker); - persistentState.SetBindGroup(cmd->index, cmd->group.Get()); - } break; - - default: - return DAWN_VALIDATION_ERROR("Command disallowed inside a compute pass"); - } - } - - UNREACHABLE(); - return DAWN_VALIDATION_ERROR("Unfinished compute pass"); - } - - MaybeError CommandEncoderBase::ValidateRenderPass(CommandIterator* commands, - BeginRenderPassCmd* renderPass) { - PassResourceUsageTracker usageTracker; - CommandBufferStateTracker persistentState; - - // Track usage of the render pass attachments - for (uint32_t i : IterateBitSet(renderPass->colorAttachmentsSet)) { - RenderPassColorAttachmentInfo* colorAttachment = &renderPass->colorAttachments[i]; - TextureBase* texture = colorAttachment->view->GetTexture(); - usageTracker.TextureUsedAs(texture, dawn::TextureUsageBit::OutputAttachment); - - TextureViewBase* resolveTarget = colorAttachment->resolveTarget.Get(); - if (resolveTarget != nullptr) { - usageTracker.TextureUsedAs(resolveTarget->GetTexture(), - dawn::TextureUsageBit::OutputAttachment); - } - } - - if (renderPass->hasDepthStencilAttachment) { - TextureBase* texture = renderPass->depthStencilAttachment.view->GetTexture(); - usageTracker.TextureUsedAs(texture, dawn::TextureUsageBit::OutputAttachment); - } - - Command type; - while (commands->NextCommandId(&type)) { - switch (type) { - case Command::EndRenderPass: { - commands->NextCommand<EndRenderPassCmd>(); - - DAWN_TRY(ValidateDebugGroups(mDebugGroupStackSize)); - - DAWN_TRY(usageTracker.ValidateUsages(PassType::Render)); - mResourceUsages.perPass.push_back(usageTracker.AcquireResourceUsage()); - return {}; - } break; - - case Command::Draw: { - commands->NextCommand<DrawCmd>(); - DAWN_TRY(persistentState.ValidateCanDraw()); - } break; - - case Command::DrawIndexed: { - commands->NextCommand<DrawIndexedCmd>(); - DAWN_TRY(persistentState.ValidateCanDrawIndexed()); - } break; - - case Command::DrawIndirect: { - DrawIndirectCmd* cmd = commands->NextCommand<DrawIndirectCmd>(); - DAWN_TRY(persistentState.ValidateCanDraw()); - usageTracker.BufferUsedAs(cmd->indirectBuffer.Get(), - dawn::BufferUsageBit::Indirect); - } break; - - case Command::DrawIndexedIndirect: { - DrawIndexedIndirectCmd* cmd = commands->NextCommand<DrawIndexedIndirectCmd>(); - DAWN_TRY(persistentState.ValidateCanDrawIndexed()); - usageTracker.BufferUsedAs(cmd->indirectBuffer.Get(), - dawn::BufferUsageBit::Indirect); - } break; - - case Command::InsertDebugMarker: { - InsertDebugMarkerCmd* cmd = commands->NextCommand<InsertDebugMarkerCmd>(); - commands->NextData<char>(cmd->length + 1); - } break; - - case Command::PopDebugGroup: { - commands->NextCommand<PopDebugGroupCmd>(); - DAWN_TRY(PopDebugMarkerStack(&mDebugGroupStackSize)); - } break; - - case Command::PushDebugGroup: { - PushDebugGroupCmd* cmd = commands->NextCommand<PushDebugGroupCmd>(); - commands->NextData<char>(cmd->length + 1); - DAWN_TRY(PushDebugMarkerStack(&mDebugGroupStackSize)); - } break; - - case Command::SetRenderPipeline: { - SetRenderPipelineCmd* cmd = commands->NextCommand<SetRenderPipelineCmd>(); - RenderPipelineBase* pipeline = cmd->pipeline.Get(); - - DAWN_TRY(pipeline->ValidateCompatibleWith(renderPass)); - persistentState.SetRenderPipeline(pipeline); - } break; - - case Command::SetStencilReference: { - commands->NextCommand<SetStencilReferenceCmd>(); - } break; - - case Command::SetBlendColor: { - commands->NextCommand<SetBlendColorCmd>(); - } break; - - case Command::SetViewport: { - commands->NextCommand<SetViewportCmd>(); - } break; - - case Command::SetScissorRect: { - commands->NextCommand<SetScissorRectCmd>(); - } break; - - case Command::SetBindGroup: { - SetBindGroupCmd* cmd = commands->NextCommand<SetBindGroupCmd>(); - if (cmd->dynamicOffsetCount > 0) { - commands->NextData<uint64_t>(cmd->dynamicOffsetCount); - } - - TrackBindGroupResourceUsage(cmd->group.Get(), &usageTracker); - persistentState.SetBindGroup(cmd->index, cmd->group.Get()); - } break; - - case Command::SetIndexBuffer: { - SetIndexBufferCmd* cmd = commands->NextCommand<SetIndexBufferCmd>(); - - usageTracker.BufferUsedAs(cmd->buffer.Get(), dawn::BufferUsageBit::Index); - persistentState.SetIndexBuffer(); - } break; - - case Command::SetVertexBuffers: { - SetVertexBuffersCmd* cmd = commands->NextCommand<SetVertexBuffersCmd>(); - auto buffers = commands->NextData<Ref<BufferBase>>(cmd->count); - commands->NextData<uint64_t>(cmd->count); - - for (uint32_t i = 0; i < cmd->count; ++i) { - usageTracker.BufferUsedAs(buffers[i].Get(), dawn::BufferUsageBit::Vertex); - } - persistentState.SetVertexBuffer(cmd->startSlot, cmd->count); - } break; - - default: - return DAWN_VALIDATION_ERROR("Command disallowed inside a render pass"); - } - } - - UNREACHABLE(); - return DAWN_VALIDATION_ERROR("Unfinished render pass"); - } - } // namespace dawn_native diff --git a/chromium/third_party/dawn/src/dawn_native/CommandEncoder.h b/chromium/third_party/dawn/src/dawn_native/CommandEncoder.h index 3a59e8e1887..bcb11370141 100644 --- a/chromium/third_party/dawn/src/dawn_native/CommandEncoder.h +++ b/chromium/third_party/dawn/src/dawn_native/CommandEncoder.h @@ -56,15 +56,11 @@ namespace dawn_native { private: MaybeError ValidateFinish(const CommandBufferDescriptor* descriptor); - MaybeError ValidateComputePass(CommandIterator* commands); - MaybeError ValidateRenderPass(CommandIterator* commands, BeginRenderPassCmd* renderPass); EncodingContext mEncodingContext; bool mWereResourceUsagesAcquired = false; CommandBufferResourceUsage mResourceUsages; - - unsigned int mDebugGroupStackSize = 0; }; } // namespace dawn_native diff --git a/chromium/third_party/dawn/src/dawn_native/CommandValidation.cpp b/chromium/third_party/dawn/src/dawn_native/CommandValidation.cpp new file mode 100644 index 00000000000..2aa73234923 --- /dev/null +++ b/chromium/third_party/dawn/src/dawn_native/CommandValidation.cpp @@ -0,0 +1,371 @@ +// Copyright 2019 The Dawn Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "dawn_native/CommandValidation.h" + +#include "common/BitSetIterator.h" +#include "dawn_native/BindGroup.h" +#include "dawn_native/CommandBufferStateTracker.h" +#include "dawn_native/Commands.h" +#include "dawn_native/PassResourceUsageTracker.h" +#include "dawn_native/RenderBundle.h" +#include "dawn_native/RenderPipeline.h" + +namespace dawn_native { + + namespace { + + inline MaybeError PushDebugMarkerStack(unsigned int* counter) { + *counter += 1; + return {}; + } + + inline MaybeError PopDebugMarkerStack(unsigned int* counter) { + if (*counter == 0) { + return DAWN_VALIDATION_ERROR("Pop must be balanced by a corresponding Push."); + } else { + *counter -= 1; + } + + return {}; + } + + inline MaybeError ValidateDebugGroups(const unsigned int counter) { + if (counter != 0) { + return DAWN_VALIDATION_ERROR("Each Push must be balanced by a corresponding Pop."); + } + + return {}; + } + + void TrackBindGroupResourceUsage(BindGroupBase* group, + PassResourceUsageTracker* usageTracker) { + const auto& layoutInfo = group->GetLayout()->GetBindingInfo(); + + for (uint32_t i : IterateBitSet(layoutInfo.mask)) { + dawn::BindingType type = layoutInfo.types[i]; + + switch (type) { + case dawn::BindingType::UniformBuffer: { + BufferBase* buffer = group->GetBindingAsBufferBinding(i).buffer; + usageTracker->BufferUsedAs(buffer, dawn::BufferUsage::Uniform); + } break; + + case dawn::BindingType::StorageBuffer: { + BufferBase* buffer = group->GetBindingAsBufferBinding(i).buffer; + usageTracker->BufferUsedAs(buffer, dawn::BufferUsage::Storage); + } break; + + case dawn::BindingType::SampledTexture: { + TextureBase* texture = group->GetBindingAsTextureView(i)->GetTexture(); + usageTracker->TextureUsedAs(texture, dawn::TextureUsage::Sampled); + } break; + + case dawn::BindingType::Sampler: + break; + + case dawn::BindingType::StorageTexture: + case dawn::BindingType::ReadonlyStorageBuffer: + UNREACHABLE(); + break; + } + } + } + + inline MaybeError ValidateRenderBundleCommand(CommandIterator* commands, + Command type, + PassResourceUsageTracker* usageTracker, + CommandBufferStateTracker* commandBufferState, + const AttachmentState* attachmentState, + unsigned int* debugGroupStackSize, + const char* disallowedMessage) { + switch (type) { + case Command::Draw: { + commands->NextCommand<DrawCmd>(); + DAWN_TRY(commandBufferState->ValidateCanDraw()); + } break; + + case Command::DrawIndexed: { + commands->NextCommand<DrawIndexedCmd>(); + DAWN_TRY(commandBufferState->ValidateCanDrawIndexed()); + } break; + + case Command::DrawIndirect: { + DrawIndirectCmd* cmd = commands->NextCommand<DrawIndirectCmd>(); + DAWN_TRY(commandBufferState->ValidateCanDraw()); + usageTracker->BufferUsedAs(cmd->indirectBuffer.Get(), + dawn::BufferUsage::Indirect); + } break; + + case Command::DrawIndexedIndirect: { + DrawIndexedIndirectCmd* cmd = commands->NextCommand<DrawIndexedIndirectCmd>(); + DAWN_TRY(commandBufferState->ValidateCanDrawIndexed()); + usageTracker->BufferUsedAs(cmd->indirectBuffer.Get(), + dawn::BufferUsage::Indirect); + } break; + + case Command::InsertDebugMarker: { + InsertDebugMarkerCmd* cmd = commands->NextCommand<InsertDebugMarkerCmd>(); + commands->NextData<char>(cmd->length + 1); + } break; + + case Command::PopDebugGroup: { + commands->NextCommand<PopDebugGroupCmd>(); + DAWN_TRY(PopDebugMarkerStack(debugGroupStackSize)); + } break; + + case Command::PushDebugGroup: { + PushDebugGroupCmd* cmd = commands->NextCommand<PushDebugGroupCmd>(); + commands->NextData<char>(cmd->length + 1); + DAWN_TRY(PushDebugMarkerStack(debugGroupStackSize)); + } break; + + case Command::SetRenderPipeline: { + SetRenderPipelineCmd* cmd = commands->NextCommand<SetRenderPipelineCmd>(); + RenderPipelineBase* pipeline = cmd->pipeline.Get(); + + if (DAWN_UNLIKELY(pipeline->GetAttachmentState() != attachmentState)) { + return DAWN_VALIDATION_ERROR("Pipeline attachment state is not compatible"); + } + commandBufferState->SetRenderPipeline(pipeline); + } break; + + case Command::SetBindGroup: { + SetBindGroupCmd* cmd = commands->NextCommand<SetBindGroupCmd>(); + if (cmd->dynamicOffsetCount > 0) { + commands->NextData<uint64_t>(cmd->dynamicOffsetCount); + } + + TrackBindGroupResourceUsage(cmd->group.Get(), usageTracker); + commandBufferState->SetBindGroup(cmd->index, cmd->group.Get()); + } break; + + case Command::SetIndexBuffer: { + SetIndexBufferCmd* cmd = commands->NextCommand<SetIndexBufferCmd>(); + + usageTracker->BufferUsedAs(cmd->buffer.Get(), dawn::BufferUsage::Index); + commandBufferState->SetIndexBuffer(); + } break; + + case Command::SetVertexBuffers: { + SetVertexBuffersCmd* cmd = commands->NextCommand<SetVertexBuffersCmd>(); + auto buffers = commands->NextData<Ref<BufferBase>>(cmd->count); + commands->NextData<uint64_t>(cmd->count); + + for (uint32_t i = 0; i < cmd->count; ++i) { + usageTracker->BufferUsedAs(buffers[i].Get(), dawn::BufferUsage::Vertex); + } + commandBufferState->SetVertexBuffer(cmd->startSlot, cmd->count); + } break; + + default: + return DAWN_VALIDATION_ERROR(disallowedMessage); + } + + return {}; + } + + } // namespace + + MaybeError ValidateRenderBundle(CommandIterator* commands, + const AttachmentState* attachmentState, + PassResourceUsage* resourceUsage) { + PassResourceUsageTracker usageTracker; + CommandBufferStateTracker commandBufferState; + unsigned int debugGroupStackSize = 0; + + Command type; + while (commands->NextCommandId(&type)) { + DAWN_TRY(ValidateRenderBundleCommand(commands, type, &usageTracker, &commandBufferState, + attachmentState, &debugGroupStackSize, + "Command disallowed inside a render bundle")); + } + + DAWN_TRY(ValidateDebugGroups(debugGroupStackSize)); + DAWN_TRY(usageTracker.ValidateRenderPassUsages()); + ASSERT(resourceUsage != nullptr); + *resourceUsage = usageTracker.AcquireResourceUsage(); + + return {}; + } + + MaybeError ValidateRenderPass(CommandIterator* commands, + BeginRenderPassCmd* renderPass, + std::vector<PassResourceUsage>* perPassResourceUsages) { + PassResourceUsageTracker usageTracker; + CommandBufferStateTracker commandBufferState; + unsigned int debugGroupStackSize = 0; + + // Track usage of the render pass attachments + for (uint32_t i : IterateBitSet(renderPass->attachmentState->GetColorAttachmentsMask())) { + RenderPassColorAttachmentInfo* colorAttachment = &renderPass->colorAttachments[i]; + TextureBase* texture = colorAttachment->view->GetTexture(); + usageTracker.TextureUsedAs(texture, dawn::TextureUsage::OutputAttachment); + + TextureViewBase* resolveTarget = colorAttachment->resolveTarget.Get(); + if (resolveTarget != nullptr) { + usageTracker.TextureUsedAs(resolveTarget->GetTexture(), + dawn::TextureUsage::OutputAttachment); + } + } + + if (renderPass->attachmentState->HasDepthStencilAttachment()) { + TextureBase* texture = renderPass->depthStencilAttachment.view->GetTexture(); + usageTracker.TextureUsedAs(texture, dawn::TextureUsage::OutputAttachment); + } + + Command type; + while (commands->NextCommandId(&type)) { + switch (type) { + case Command::EndRenderPass: { + commands->NextCommand<EndRenderPassCmd>(); + + DAWN_TRY(ValidateDebugGroups(debugGroupStackSize)); + + DAWN_TRY(usageTracker.ValidateRenderPassUsages()); + ASSERT(perPassResourceUsages != nullptr); + perPassResourceUsages->push_back(usageTracker.AcquireResourceUsage()); + + return {}; + } break; + + case Command::ExecuteBundles: { + ExecuteBundlesCmd* cmd = commands->NextCommand<ExecuteBundlesCmd>(); + auto bundles = commands->NextData<Ref<RenderBundleBase>>(cmd->count); + for (uint32_t i = 0; i < cmd->count; ++i) { + if (DAWN_UNLIKELY(renderPass->attachmentState.Get() != + bundles[i]->GetAttachmentState())) { + return DAWN_VALIDATION_ERROR( + "Render bundle is not compatible with render pass"); + } + + const PassResourceUsage& usages = bundles[i]->GetResourceUsage(); + for (uint32_t i = 0; i < usages.buffers.size(); ++i) { + usageTracker.BufferUsedAs(usages.buffers[i], usages.bufferUsages[i]); + } + + for (uint32_t i = 0; i < usages.textures.size(); ++i) { + usageTracker.TextureUsedAs(usages.textures[i], usages.textureUsages[i]); + } + } + + if (cmd->count > 0) { + // Reset state. It is invalidated after render bundle execution. + commandBufferState = CommandBufferStateTracker{}; + } + + } break; + + case Command::SetStencilReference: { + commands->NextCommand<SetStencilReferenceCmd>(); + } break; + + case Command::SetBlendColor: { + commands->NextCommand<SetBlendColorCmd>(); + } break; + + case Command::SetViewport: { + commands->NextCommand<SetViewportCmd>(); + } break; + + case Command::SetScissorRect: { + commands->NextCommand<SetScissorRectCmd>(); + } break; + + default: + DAWN_TRY(ValidateRenderBundleCommand( + commands, type, &usageTracker, &commandBufferState, + renderPass->attachmentState.Get(), &debugGroupStackSize, + "Command disallowed inside a render pass")); + } + } + + UNREACHABLE(); + return DAWN_VALIDATION_ERROR("Unfinished render pass"); + } + + MaybeError ValidateComputePass(CommandIterator* commands, + std::vector<PassResourceUsage>* perPassResourceUsages) { + PassResourceUsageTracker usageTracker; + CommandBufferStateTracker commandBufferState; + unsigned int debugGroupStackSize = 0; + + Command type; + while (commands->NextCommandId(&type)) { + switch (type) { + case Command::EndComputePass: { + commands->NextCommand<EndComputePassCmd>(); + + DAWN_TRY(ValidateDebugGroups(debugGroupStackSize)); + + DAWN_TRY(usageTracker.ValidateComputePassUsages()); + ASSERT(perPassResourceUsages != nullptr); + perPassResourceUsages->push_back(usageTracker.AcquireResourceUsage()); + return {}; + } break; + + case Command::Dispatch: { + commands->NextCommand<DispatchCmd>(); + DAWN_TRY(commandBufferState.ValidateCanDispatch()); + } break; + + case Command::DispatchIndirect: { + DispatchIndirectCmd* cmd = commands->NextCommand<DispatchIndirectCmd>(); + DAWN_TRY(commandBufferState.ValidateCanDispatch()); + usageTracker.BufferUsedAs(cmd->indirectBuffer.Get(), + dawn::BufferUsage::Indirect); + } break; + + case Command::InsertDebugMarker: { + InsertDebugMarkerCmd* cmd = commands->NextCommand<InsertDebugMarkerCmd>(); + commands->NextData<char>(cmd->length + 1); + } break; + + case Command::PopDebugGroup: { + commands->NextCommand<PopDebugGroupCmd>(); + DAWN_TRY(PopDebugMarkerStack(&debugGroupStackSize)); + } break; + + case Command::PushDebugGroup: { + PushDebugGroupCmd* cmd = commands->NextCommand<PushDebugGroupCmd>(); + commands->NextData<char>(cmd->length + 1); + DAWN_TRY(PushDebugMarkerStack(&debugGroupStackSize)); + } break; + + case Command::SetComputePipeline: { + SetComputePipelineCmd* cmd = commands->NextCommand<SetComputePipelineCmd>(); + ComputePipelineBase* pipeline = cmd->pipeline.Get(); + commandBufferState.SetComputePipeline(pipeline); + } break; + + case Command::SetBindGroup: { + SetBindGroupCmd* cmd = commands->NextCommand<SetBindGroupCmd>(); + if (cmd->dynamicOffsetCount > 0) { + commands->NextData<uint64_t>(cmd->dynamicOffsetCount); + } + + TrackBindGroupResourceUsage(cmd->group.Get(), &usageTracker); + commandBufferState.SetBindGroup(cmd->index, cmd->group.Get()); + } break; + + default: + return DAWN_VALIDATION_ERROR("Command disallowed inside a compute pass"); + } + } + + UNREACHABLE(); + return DAWN_VALIDATION_ERROR("Unfinished compute pass"); + } + +} // namespace dawn_native diff --git a/chromium/third_party/dawn/src/dawn_native/CommandValidation.h b/chromium/third_party/dawn/src/dawn_native/CommandValidation.h new file mode 100644 index 00000000000..c90343c4cdb --- /dev/null +++ b/chromium/third_party/dawn/src/dawn_native/CommandValidation.h @@ -0,0 +1,40 @@ +// Copyright 2019 The Dawn Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef DAWNNATIVE_COMMANDVALIDATION_H_ +#define DAWNNATIVE_COMMANDVALIDATION_H_ + +#include "dawn_native/CommandAllocator.h" +#include "dawn_native/Error.h" + +#include <vector> + +namespace dawn_native { + + class AttachmentState; + struct BeginRenderPassCmd; + struct PassResourceUsage; + + MaybeError ValidateRenderBundle(CommandIterator* commands, + const AttachmentState* attachmentState, + PassResourceUsage* resourceUsage); + MaybeError ValidateRenderPass(CommandIterator* commands, + BeginRenderPassCmd* renderPass, + std::vector<PassResourceUsage>* perPassResourceUsages); + MaybeError ValidateComputePass(CommandIterator* commands, + std::vector<PassResourceUsage>* perPassResourceUsages); + +} // namespace dawn_native + +#endif // DAWNNATIVE_COMMANDVALIDATION_H_ diff --git a/chromium/third_party/dawn/src/dawn_native/Commands.cpp b/chromium/third_party/dawn/src/dawn_native/Commands.cpp index fbc9172153a..eb1179103df 100644 --- a/chromium/third_party/dawn/src/dawn_native/Commands.cpp +++ b/chromium/third_party/dawn/src/dawn_native/Commands.cpp @@ -18,6 +18,7 @@ #include "dawn_native/Buffer.h" #include "dawn_native/CommandAllocator.h" #include "dawn_native/ComputePipeline.h" +#include "dawn_native/RenderBundle.h" #include "dawn_native/RenderPipeline.h" #include "dawn_native/Texture.h" @@ -86,6 +87,14 @@ namespace dawn_native { EndRenderPassCmd* cmd = commands->NextCommand<EndRenderPassCmd>(); cmd->~EndRenderPassCmd(); } break; + case Command::ExecuteBundles: { + ExecuteBundlesCmd* cmd = commands->NextCommand<ExecuteBundlesCmd>(); + auto bundles = commands->NextData<Ref<RenderBundleBase>>(cmd->count); + for (size_t i = 0; i < cmd->count; ++i) { + (&bundles[i])->~Ref<RenderBundleBase>(); + } + cmd->~ExecuteBundlesCmd(); + } break; case Command::InsertDebugMarker: { InsertDebugMarkerCmd* cmd = commands->NextCommand<InsertDebugMarkerCmd>(); commands->NextData<char>(cmd->length + 1); @@ -207,6 +216,11 @@ namespace dawn_native { commands->NextCommand<EndRenderPassCmd>(); break; + case Command::ExecuteBundles: { + auto* cmd = commands->NextCommand<ExecuteBundlesCmd>(); + commands->NextData<Ref<RenderBundleBase>>(cmd->count); + } break; + case Command::InsertDebugMarker: { InsertDebugMarkerCmd* cmd = commands->NextCommand<InsertDebugMarkerCmd>(); commands->NextData<char>(cmd->length + 1); diff --git a/chromium/third_party/dawn/src/dawn_native/Commands.h b/chromium/third_party/dawn/src/dawn_native/Commands.h index 24e4e115434..18d834d72b3 100644 --- a/chromium/third_party/dawn/src/dawn_native/Commands.h +++ b/chromium/third_party/dawn/src/dawn_native/Commands.h @@ -17,6 +17,7 @@ #include "common/Constants.h" +#include "dawn_native/AttachmentState.h" #include "dawn_native/Texture.h" #include "dawn_native/dawn_platform.h" @@ -45,6 +46,7 @@ namespace dawn_native { DrawIndexedIndirect, EndComputePass, EndRenderPass, + ExecuteBundles, InsertDebugMarker, PopDebugGroup, PushDebugGroup, @@ -80,15 +82,13 @@ namespace dawn_native { }; struct BeginRenderPassCmd { - std::bitset<kMaxColorAttachments> colorAttachmentsSet; + Ref<AttachmentState> attachmentState; RenderPassColorAttachmentInfo colorAttachments[kMaxColorAttachments]; - bool hasDepthStencilAttachment; RenderPassDepthStencilAttachmentInfo depthStencilAttachment; - // Cache the width, height and sample count of all attachments for convenience + // Cache the width and height of all attachments for convenience uint32_t width; uint32_t height; - uint32_t sampleCount; }; struct BufferCopy { @@ -171,6 +171,10 @@ namespace dawn_native { struct EndRenderPassCmd {}; + struct ExecuteBundlesCmd { + uint32_t count; + }; + struct InsertDebugMarkerCmd { uint32_t length; }; diff --git a/chromium/third_party/dawn/src/dawn_native/ComputePipeline.cpp b/chromium/third_party/dawn/src/dawn_native/ComputePipeline.cpp index 295e9000192..a1e941b9c3c 100644 --- a/chromium/third_party/dawn/src/dawn_native/ComputePipeline.cpp +++ b/chromium/third_party/dawn/src/dawn_native/ComputePipeline.cpp @@ -26,8 +26,8 @@ namespace dawn_native { } DAWN_TRY(device->ValidateObject(descriptor->layout)); - DAWN_TRY(ValidatePipelineStageDescriptor(device, descriptor->computeStage, - descriptor->layout, ShaderStage::Compute)); + DAWN_TRY(ValidatePipelineStageDescriptor(device, &descriptor->computeStage, + descriptor->layout, SingleShaderStage::Compute)); return {}; } @@ -36,9 +36,9 @@ namespace dawn_native { ComputePipelineBase::ComputePipelineBase(DeviceBase* device, const ComputePipelineDescriptor* descriptor, bool blueprint) - : PipelineBase(device, descriptor->layout, dawn::ShaderStageBit::Compute), - mModule(descriptor->computeStage->module), - mEntryPoint(descriptor->computeStage->entryPoint), + : PipelineBase(device, descriptor->layout, dawn::ShaderStage::Compute), + mModule(descriptor->computeStage.module), + mEntryPoint(descriptor->computeStage.entryPoint), mIsBlueprint(blueprint) { } diff --git a/chromium/third_party/dawn/src/dawn_native/DawnNative.cpp b/chromium/third_party/dawn/src/dawn_native/DawnNative.cpp index 08c9587f0ad..f0c3bc4a41f 100644 --- a/chromium/third_party/dawn/src/dawn_native/DawnNative.cpp +++ b/chromium/third_party/dawn/src/dawn_native/DawnNative.cpp @@ -15,6 +15,7 @@ #include "dawn_native/DawnNative.h" #include "dawn_native/Device.h" #include "dawn_native/Instance.h" +#include "dawn_platform/DawnPlatform.h" // Contains the entry-points into dawn_native @@ -55,6 +56,11 @@ namespace dawn_native { return mImpl->GetPCIInfo(); } + std::vector<const char*> Adapter::GetSupportedExtensions() const { + ExtensionsSet supportedExtensionsSet = mImpl->GetSupportedExtensions(); + return supportedExtensionsSet.GetEnabledExtensionNames(); + } + Adapter::operator bool() const { return mImpl != nullptr; } @@ -115,4 +121,17 @@ namespace dawn_native { return mImpl->IsBeginCaptureOnStartupEnabled(); } + void Instance::SetPlatform(dawn_platform::Platform* platform) { + mImpl->SetPlatform(platform); + } + + dawn_platform::Platform* Instance::GetPlatform() const { + return mImpl->GetPlatform(); + } + + size_t GetLazyClearCountForTesting(DawnDevice device) { + dawn_native::DeviceBase* deviceBase = reinterpret_cast<dawn_native::DeviceBase*>(device); + return deviceBase->GetLazyClearCountForTesting(); + } + } // namespace dawn_native diff --git a/chromium/third_party/dawn/src/dawn_native/Device.cpp b/chromium/third_party/dawn/src/dawn_native/Device.cpp index 8be70b0283d..e667c12477b 100644 --- a/chromium/third_party/dawn/src/dawn_native/Device.cpp +++ b/chromium/third_party/dawn/src/dawn_native/Device.cpp @@ -15,6 +15,7 @@ #include "dawn_native/Device.h" #include "dawn_native/Adapter.h" +#include "dawn_native/AttachmentState.h" #include "dawn_native/BindGroup.h" #include "dawn_native/BindGroupLayout.h" #include "dawn_native/Buffer.h" @@ -28,6 +29,7 @@ #include "dawn_native/Instance.h" #include "dawn_native/PipelineLayout.h" #include "dawn_native/Queue.h" +#include "dawn_native/RenderBundleEncoder.h" #include "dawn_native/RenderPipeline.h" #include "dawn_native/Sampler.h" #include "dawn_native/ShaderModule.h" @@ -47,6 +49,7 @@ namespace dawn_native { std::unordered_set<Object*, typename Object::HashFunc, typename Object::EqualityFunc>; struct DeviceBase::Caches { + ContentLessObjectCache<AttachmentStateBlueprint> attachmentStates; ContentLessObjectCache<BindGroupLayoutBase> bindGroupLayouts; ContentLessObjectCache<ComputePipelineBase> computePipelines; ContentLessObjectCache<PipelineLayoutBase> pipelineLayouts; @@ -64,6 +67,10 @@ namespace dawn_native { mDynamicUploader = std::make_unique<DynamicUploader>(this); SetDefaultToggles(); + if (descriptor != nullptr) { + ApplyExtensions(descriptor); + } + mFormatTable = BuildFormatTable(this); } @@ -71,19 +78,38 @@ namespace dawn_native { // Devices must explicitly free the uploader ASSERT(mDynamicUploader == nullptr); ASSERT(mDeferredCreateBufferMappedAsyncResults.empty()); + + ASSERT(mCaches->attachmentStates.empty()); + ASSERT(mCaches->bindGroupLayouts.empty()); + ASSERT(mCaches->computePipelines.empty()); + ASSERT(mCaches->pipelineLayouts.empty()); + ASSERT(mCaches->renderPipelines.empty()); + ASSERT(mCaches->samplers.empty()); + ASSERT(mCaches->shaderModules.empty()); } - void DeviceBase::HandleError(const char* message) { + void DeviceBase::HandleError(dawn::ErrorType type, const char* message) { if (mErrorCallback) { - mErrorCallback(message, mErrorUserdata); + mErrorCallback(static_cast<DawnErrorType>(type), message, mErrorUserdata); } } - void DeviceBase::SetErrorCallback(dawn::DeviceErrorCallback callback, void* userdata) { + void DeviceBase::SetUncapturedErrorCallback(dawn::ErrorCallback callback, void* userdata) { mErrorCallback = callback; mErrorUserdata = userdata; } + void DeviceBase::PushErrorScope(dawn::ErrorFilter filter) { + // TODO(crbug.com/dawn/153): Implement error scopes. + HandleError(dawn::ErrorType::Validation, "Error scopes not implemented"); + } + + bool DeviceBase::PopErrorScope(dawn::ErrorCallback callback, void* userdata) { + // TODO(crbug.com/dawn/153): Implement error scopes. + HandleError(dawn::ErrorType::Validation, "Error scopes not implemented"); + return false; + } + MaybeError DeviceBase::ValidateObject(const ObjectBase* object) const { if (DAWN_UNLIKELY(object->GetDevice() != this)) { return DAWN_VALIDATION_ERROR("Object from a different device."); @@ -98,6 +124,10 @@ namespace dawn_native { return mAdapter; } + dawn_platform::Platform* DeviceBase::GetPlatform() const { + return GetAdapter()->GetInstance()->GetPlatform(); + } + FenceSignalTracker* DeviceBase::GetFenceSignalTracker() const { return mFenceSignalTracker.get(); } @@ -249,6 +279,42 @@ namespace dawn_native { ASSERT(removedCount == 1); } + Ref<AttachmentState> DeviceBase::GetOrCreateAttachmentState( + AttachmentStateBlueprint* blueprint) { + auto iter = mCaches->attachmentStates.find(blueprint); + if (iter != mCaches->attachmentStates.end()) { + return static_cast<AttachmentState*>(*iter); + } + + Ref<AttachmentState> attachmentState = new AttachmentState(this, *blueprint); + attachmentState->Release(); + mCaches->attachmentStates.insert(attachmentState.Get()); + return attachmentState; + } + + Ref<AttachmentState> DeviceBase::GetOrCreateAttachmentState( + const RenderBundleEncoderDescriptor* descriptor) { + AttachmentStateBlueprint blueprint(descriptor); + return GetOrCreateAttachmentState(&blueprint); + } + + Ref<AttachmentState> DeviceBase::GetOrCreateAttachmentState( + const RenderPipelineDescriptor* descriptor) { + AttachmentStateBlueprint blueprint(descriptor); + return GetOrCreateAttachmentState(&blueprint); + } + + Ref<AttachmentState> DeviceBase::GetOrCreateAttachmentState( + const RenderPassDescriptor* descriptor) { + AttachmentStateBlueprint blueprint(descriptor); + return GetOrCreateAttachmentState(&blueprint); + } + + void DeviceBase::UncacheAttachmentState(AttachmentState* obj) { + size_t removedCount = mCaches->attachmentStates.erase(obj); + ASSERT(removedCount == 1); + } + // Object creation API methods BindGroupBase* DeviceBase::CreateBindGroup(const BindGroupDescriptor* descriptor) { @@ -375,6 +441,16 @@ namespace dawn_native { return result; } + RenderBundleEncoderBase* DeviceBase::CreateRenderBundleEncoder( + const RenderBundleEncoderDescriptor* descriptor) { + RenderBundleEncoderBase* result = nullptr; + + if (ConsumedError(CreateRenderBundleEncoderInternal(&result, descriptor))) { + return RenderBundleEncoderBase::MakeError(this); + } + + return result; + } RenderPipelineBase* DeviceBase::CreateRenderPipeline( const RenderPipelineDescriptor* descriptor) { RenderPipelineBase* result = nullptr; @@ -466,24 +542,38 @@ namespace dawn_native { } } - std::vector<const char*> DeviceBase::GetTogglesUsed() const { - std::vector<const char*> togglesNameInUse(mTogglesSet.toggleBitset.count()); + void DeviceBase::ApplyExtensions(const DeviceDescriptor* deviceDescriptor) { + ASSERT(deviceDescriptor); + ASSERT(GetAdapter()->SupportsAllRequestedExtensions(deviceDescriptor->requiredExtensions)); - uint32_t index = 0; - for (uint32_t i : IterateBitSet(mTogglesSet.toggleBitset)) { - const char* toggleName = - GetAdapter()->GetInstance()->ToggleEnumToName(static_cast<Toggle>(i)); - togglesNameInUse[index] = toggleName; - ++index; - } + mEnabledExtensions = GetAdapter()->GetInstance()->ExtensionNamesToExtensionsSet( + deviceDescriptor->requiredExtensions); + } + + std::vector<const char*> DeviceBase::GetEnabledExtensions() const { + return mEnabledExtensions.GetEnabledExtensionNames(); + } + + std::vector<const char*> DeviceBase::GetTogglesUsed() const { + return mTogglesSet.GetEnabledToggleNames(); + } - return togglesNameInUse; + bool DeviceBase::IsExtensionEnabled(Extension extension) const { + return mEnabledExtensions.IsEnabled(extension); } bool DeviceBase::IsToggleEnabled(Toggle toggle) const { return mTogglesSet.IsEnabled(toggle); } + size_t DeviceBase::GetLazyClearCountForTesting() { + return mLazyClearCountForTesting; + } + + void DeviceBase::IncrementLazyClearCountForTesting() { + ++mLazyClearCountForTesting; + } + void DeviceBase::SetDefaultToggles() { // Sets the default-enabled toggles mTogglesSet.SetToggle(Toggle::LazyClearResourceOnFirstUse, true); @@ -534,6 +624,14 @@ namespace dawn_native { return {}; } + MaybeError DeviceBase::CreateRenderBundleEncoderInternal( + RenderBundleEncoderBase** result, + const RenderBundleEncoderDescriptor* descriptor) { + DAWN_TRY(ValidateRenderBundleEncoderDescriptor(this, descriptor)); + *result = new RenderBundleEncoderBase(this, descriptor); + return {}; + } + MaybeError DeviceBase::CreateRenderPipelineInternal( RenderPipelineBase** result, const RenderPipelineDescriptor* descriptor) { @@ -573,8 +671,10 @@ namespace dawn_native { MaybeError DeviceBase::CreateTextureViewInternal(TextureViewBase** result, TextureBase* texture, const TextureViewDescriptor* descriptor) { - DAWN_TRY(ValidateTextureViewDescriptor(this, texture, descriptor)); - DAWN_TRY_ASSIGN(*result, CreateTextureViewImpl(texture, descriptor)); + DAWN_TRY(ValidateObject(texture)); + TextureViewDescriptor desc = GetTextureViewDescriptorWithDefaults(texture, descriptor); + DAWN_TRY(ValidateTextureViewDescriptor(texture, &desc)); + DAWN_TRY_ASSIGN(*result, CreateTextureViewImpl(texture, &desc)); return {}; } @@ -582,7 +682,7 @@ namespace dawn_native { void DeviceBase::ConsumeError(ErrorData* error) { ASSERT(error != nullptr); - HandleError(error->GetMessage().c_str()); + HandleError(error->GetType(), error->GetMessage().c_str()); delete error; } diff --git a/chromium/third_party/dawn/src/dawn_native/Device.h b/chromium/third_party/dawn/src/dawn_native/Device.h index d99f0f985cf..60cdbba9026 100644 --- a/chromium/third_party/dawn/src/dawn_native/Device.h +++ b/chromium/third_party/dawn/src/dawn_native/Device.h @@ -17,6 +17,7 @@ #include "common/Serial.h" #include "dawn_native/Error.h" +#include "dawn_native/Extensions.h" #include "dawn_native/Format.h" #include "dawn_native/Forward.h" #include "dawn_native/ObjectBase.h" @@ -32,6 +33,8 @@ namespace dawn_native { using ErrorCallback = void (*)(const char* errorMessage, void* userData); class AdapterBase; + class AttachmentState; + class AttachmentStateBlueprint; class FenceSignalTracker; class DynamicUploader; class StagingBufferBase; @@ -41,7 +44,7 @@ namespace dawn_native { DeviceBase(AdapterBase* adapter, const DeviceDescriptor* descriptor); virtual ~DeviceBase(); - void HandleError(const char* message); + void HandleError(dawn::ErrorType type, const char* message); bool ConsumedError(MaybeError maybeError) { if (DAWN_UNLIKELY(maybeError.IsError())) { @@ -54,6 +57,7 @@ namespace dawn_native { MaybeError ValidateObject(const ObjectBase* object) const; AdapterBase* GetAdapter() const; + dawn_platform::Platform* GetPlatform() const; FenceSignalTracker* GetFenceSignalTracker() const; @@ -113,6 +117,13 @@ namespace dawn_native { const ShaderModuleDescriptor* descriptor); void UncacheShaderModule(ShaderModuleBase* obj); + Ref<AttachmentState> GetOrCreateAttachmentState(AttachmentStateBlueprint* blueprint); + Ref<AttachmentState> GetOrCreateAttachmentState( + const RenderBundleEncoderDescriptor* descriptor); + Ref<AttachmentState> GetOrCreateAttachmentState(const RenderPipelineDescriptor* descriptor); + Ref<AttachmentState> GetOrCreateAttachmentState(const RenderPassDescriptor* descriptor); + void UncacheAttachmentState(AttachmentState* obj); + // Dawn API BindGroupBase* CreateBindGroup(const BindGroupDescriptor* descriptor); BindGroupLayoutBase* CreateBindGroupLayout(const BindGroupLayoutDescriptor* descriptor); @@ -125,6 +136,8 @@ namespace dawn_native { ComputePipelineBase* CreateComputePipeline(const ComputePipelineDescriptor* descriptor); PipelineLayoutBase* CreatePipelineLayout(const PipelineLayoutDescriptor* descriptor); QueueBase* CreateQueue(); + RenderBundleEncoderBase* CreateRenderBundleEncoder( + const RenderBundleEncoderDescriptor* descriptor); RenderPipelineBase* CreateRenderPipeline(const RenderPipelineDescriptor* descriptor); SamplerBase* CreateSampler(const SamplerDescriptor* descriptor); ShaderModuleBase* CreateShaderModule(const ShaderModuleDescriptor* descriptor); @@ -135,7 +148,10 @@ namespace dawn_native { void Tick(); - void SetErrorCallback(dawn::DeviceErrorCallback callback, void* userdata); + void SetUncapturedErrorCallback(dawn::ErrorCallback callback, void* userdata); + void PushErrorScope(dawn::ErrorFilter filter); + bool PopErrorScope(dawn::ErrorCallback callback, void* userdata); + void Reference(); void Release(); @@ -149,8 +165,12 @@ namespace dawn_native { ResultOrError<DynamicUploader*> GetDynamicUploader() const; + std::vector<const char*> GetEnabledExtensions() const; std::vector<const char*> GetTogglesUsed() const; + bool IsExtensionEnabled(Extension extension) const; bool IsToggleEnabled(Toggle toggle) const; + size_t GetLazyClearCountForTesting(); + void IncrementLazyClearCountForTesting(); protected: void SetToggle(Toggle toggle, bool isEnabled); @@ -193,6 +213,9 @@ namespace dawn_native { MaybeError CreatePipelineLayoutInternal(PipelineLayoutBase** result, const PipelineLayoutDescriptor* descriptor); MaybeError CreateQueueInternal(QueueBase** result); + MaybeError CreateRenderBundleEncoderInternal( + RenderBundleEncoderBase** result, + const RenderBundleEncoderDescriptor* descriptor); MaybeError CreateRenderPipelineInternal(RenderPipelineBase** result, const RenderPipelineDescriptor* descriptor); MaybeError CreateSamplerInternal(SamplerBase** result, const SamplerDescriptor* descriptor); @@ -205,6 +228,8 @@ namespace dawn_native { TextureBase* texture, const TextureViewDescriptor* descriptor); + void ApplyExtensions(const DeviceDescriptor* deviceDescriptor); + void ConsumeError(ErrorData* error); void SetDefaultToggles(); @@ -225,13 +250,16 @@ namespace dawn_native { std::unique_ptr<FenceSignalTracker> mFenceSignalTracker; std::vector<DeferredCreateBufferMappedAsync> mDeferredCreateBufferMappedAsyncResults; - dawn::DeviceErrorCallback mErrorCallback = nullptr; + dawn::ErrorCallback mErrorCallback = nullptr; void* mErrorUserdata = 0; uint32_t mRefCount = 1; FormatTable mFormatTable; TogglesSet mTogglesSet; + size_t mLazyClearCountForTesting = 0; + + ExtensionsSet mEnabledExtensions; }; } // namespace dawn_native diff --git a/chromium/third_party/dawn/src/dawn_native/DynamicUploader.cpp b/chromium/third_party/dawn/src/dawn_native/DynamicUploader.cpp index 344214b1dc6..c7163324290 100644 --- a/chromium/third_party/dawn/src/dawn_native/DynamicUploader.cpp +++ b/chromium/third_party/dawn/src/dawn_native/DynamicUploader.cpp @@ -41,31 +41,41 @@ namespace dawn_native { return {}; } - ResultOrError<UploadHandle> DynamicUploader::Allocate(uint32_t size, uint32_t alignment) { - ASSERT(IsPowerOfTwo(alignment)); - - // Align the requested allocation size - const size_t alignedSize = Align(size, alignment); + ResultOrError<UploadHandle> DynamicUploader::Allocate(uint32_t size) { + // Note: Validation ensures size is already aligned. + // First-fit: find next smallest buffer large enough to satisfy the allocation request. + RingBuffer* targetRingBuffer = GetLargestBuffer(); + for (auto& ringBuffer : mRingBuffers) { + // Prevent overflow. + ASSERT(ringBuffer->GetSize() >= ringBuffer->GetUsedSize()); + const size_t remainingSize = ringBuffer->GetSize() - ringBuffer->GetUsedSize(); + if (size <= remainingSize) { + targetRingBuffer = ringBuffer.get(); + break; + } + } - RingBuffer* largestRingBuffer = GetLargestBuffer(); - UploadHandle uploadHandle = largestRingBuffer->SubAllocate(alignedSize); + UploadHandle uploadHandle = UploadHandle{}; + if (targetRingBuffer != nullptr) { + uploadHandle = targetRingBuffer->SubAllocate(size); + } // Upon failure, append a newly created (and much larger) ring buffer to fulfill the // request. if (uploadHandle.mappedBuffer == nullptr) { // Compute the new max size (in powers of two to preserve alignment). - size_t newMaxSize = largestRingBuffer->GetSize(); + size_t newMaxSize = targetRingBuffer->GetSize() * 2; while (newMaxSize < size) { newMaxSize *= 2; } // TODO(bryan.bernhart@intel.com): Fall-back to no sub-allocations should this fail. DAWN_TRY(CreateAndAppendBuffer(newMaxSize)); - largestRingBuffer = GetLargestBuffer(); - uploadHandle = largestRingBuffer->SubAllocate(alignedSize); + targetRingBuffer = GetLargestBuffer(); + uploadHandle = targetRingBuffer->SubAllocate(size); } - uploadHandle.stagingBuffer = largestRingBuffer->GetStagingBuffer(); + uploadHandle.stagingBuffer = targetRingBuffer->GetStagingBuffer(); return uploadHandle; } diff --git a/chromium/third_party/dawn/src/dawn_native/DynamicUploader.h b/chromium/third_party/dawn/src/dawn_native/DynamicUploader.h index 5e4d0796023..0caecb9919d 100644 --- a/chromium/third_party/dawn/src/dawn_native/DynamicUploader.h +++ b/chromium/third_party/dawn/src/dawn_native/DynamicUploader.h @@ -29,12 +29,12 @@ namespace dawn_native { // We add functions to Create/Release StagingBuffers to the DynamicUploader as there's // currently no place to track the allocated staging buffers such that they're freed after - // pending coommands are finished. This should be changed when better resource allocation is + // pending commands are finished. This should be changed when better resource allocation is // implemented. ResultOrError<std::unique_ptr<StagingBufferBase>> CreateStagingBuffer(size_t size); void ReleaseStagingBuffer(std::unique_ptr<StagingBufferBase> stagingBuffer); - ResultOrError<UploadHandle> Allocate(uint32_t requiredSize, uint32_t alignment); + ResultOrError<UploadHandle> Allocate(uint32_t size); void Tick(Serial lastCompletedSerial); RingBuffer* GetLargestBuffer(); diff --git a/chromium/third_party/dawn/src/dawn_native/EncodingContext.cpp b/chromium/third_party/dawn/src/dawn_native/EncodingContext.cpp index d2c8a751a98..121a890992d 100644 --- a/chromium/third_party/dawn/src/dawn_native/EncodingContext.cpp +++ b/chromium/third_party/dawn/src/dawn_native/EncodingContext.cpp @@ -45,7 +45,7 @@ namespace dawn_native { return &mIterator; } - void EncodingContext::HandleError(const char* message) { + void EncodingContext::HandleError(dawn::ErrorType type, const char* message) { if (!IsFinished()) { // If the encoding context is not finished, errors are deferred until // Finish() is called. @@ -54,7 +54,7 @@ namespace dawn_native { mErrorMessage = message; } } else { - mDevice->HandleError(message); + mDevice->HandleError(type, message); } } @@ -76,6 +76,10 @@ namespace dawn_native { } MaybeError EncodingContext::Finish() { + if (IsFinished()) { + return DAWN_VALIDATION_ERROR("Command encoding already finished"); + } + const void* currentEncoder = mCurrentEncoder; const void* topLevelEncoder = mTopLevelEncoder; diff --git a/chromium/third_party/dawn/src/dawn_native/EncodingContext.h b/chromium/third_party/dawn/src/dawn_native/EncodingContext.h index a810f501ef3..831db7dcc24 100644 --- a/chromium/third_party/dawn/src/dawn_native/EncodingContext.h +++ b/chromium/third_party/dawn/src/dawn_native/EncodingContext.h @@ -18,6 +18,7 @@ #include "dawn_native/CommandAllocator.h" #include "dawn_native/Error.h" #include "dawn_native/ErrorData.h" +#include "dawn_native/dawn_platform.h" #include <string> @@ -37,10 +38,10 @@ namespace dawn_native { CommandIterator* GetIterator(); // Functions to handle encoder errors - void HandleError(const char* message); + void HandleError(dawn::ErrorType type, const char* message); inline void ConsumeError(ErrorData* error) { - HandleError(error->GetMessage().c_str()); + HandleError(error->GetType(), error->GetMessage().c_str()); delete error; } @@ -57,9 +58,11 @@ namespace dawn_native { if (DAWN_UNLIKELY(encoder != mCurrentEncoder)) { if (mCurrentEncoder != mTopLevelEncoder) { // The top level encoder was used when a pass encoder was current. - HandleError("Command cannot be recorded inside a pass"); + HandleError(dawn::ErrorType::Validation, + "Command cannot be recorded inside a pass"); } else { - HandleError("Recording in an error or already ended pass encoder"); + HandleError(dawn::ErrorType::Validation, + "Recording in an error or already ended pass encoder"); } return false; } diff --git a/chromium/third_party/dawn/src/dawn_native/Error.cpp b/chromium/third_party/dawn/src/dawn_native/Error.cpp index 2e09931574e..195afb2e024 100644 --- a/chromium/third_party/dawn/src/dawn_native/Error.cpp +++ b/chromium/third_party/dawn/src/dawn_native/Error.cpp @@ -18,7 +18,7 @@ namespace dawn_native { - ErrorData* MakeError(ErrorType type, + ErrorData* MakeError(InternalErrorType type, std::string message, const char* file, const char* function, diff --git a/chromium/third_party/dawn/src/dawn_native/Error.h b/chromium/third_party/dawn/src/dawn_native/Error.h index 9e073c27b2e..172263e0ac2 100644 --- a/chromium/third_party/dawn/src/dawn_native/Error.h +++ b/chromium/third_party/dawn/src/dawn_native/Error.h @@ -25,7 +25,7 @@ namespace dawn_native { // file to avoid having all files including headers like <string> and <vector> class ErrorData; - enum class ErrorType : uint32_t { Validation, ContextLost, Unimplemented }; + enum class InternalErrorType : uint32_t { Validation, DeviceLost, Unimplemented, OutOfMemory }; // MaybeError and ResultOrError are meant to be used as return value for function that are not // expected to, but might fail. The handling of error is potentially much slower than successes. @@ -45,9 +45,10 @@ namespace dawn_native { // return DAWN_VALIDATION_ERROR("My error message"); #define DAWN_MAKE_ERROR(TYPE, MESSAGE) \ ::dawn_native::MakeError(TYPE, MESSAGE, __FILE__, __func__, __LINE__) -#define DAWN_VALIDATION_ERROR(MESSAGE) DAWN_MAKE_ERROR(ErrorType::Validation, MESSAGE) -#define DAWN_CONTEXT_LOST_ERROR(MESSAGE) DAWN_MAKE_ERROR(ErrorType::ContextLost, MESSAGE) -#define DAWN_UNIMPLEMENTED_ERROR(MESSAGE) DAWN_MAKE_ERROR(ErrorType::Unimplemented, MESSAGE) +#define DAWN_VALIDATION_ERROR(MESSAGE) DAWN_MAKE_ERROR(InternalErrorType::Validation, MESSAGE) +#define DAWN_DEVICE_LOST_ERROR(MESSAGE) DAWN_MAKE_ERROR(InternalErrorType::DeviceLost, MESSAGE) +#define DAWN_UNIMPLEMENTED_ERROR(MESSAGE) DAWN_MAKE_ERROR(InternalErrorType::Unimplemented, MESSAGE) +#define DAWN_OUT_OF_MEMORY_ERROR(MESSAGE) DAWN_MAKE_ERROR(InternalErrorType::OutOfMemory, MESSAGE) #define DAWN_CONCAT1(x, y) x##y #define DAWN_CONCAT2(x, y) DAWN_CONCAT1(x, y) @@ -87,7 +88,7 @@ namespace dawn_native { void AppendBacktrace(ErrorData* error, const char* file, const char* function, int line); // Implementation detail of DAWN_MAKE_ERROR - ErrorData* MakeError(ErrorType type, + ErrorData* MakeError(InternalErrorType type, std::string message, const char* file, const char* function, diff --git a/chromium/third_party/dawn/src/dawn_native/ErrorData.cpp b/chromium/third_party/dawn/src/dawn_native/ErrorData.cpp index 77a0e3f9dc1..06be01e9899 100644 --- a/chromium/third_party/dawn/src/dawn_native/ErrorData.cpp +++ b/chromium/third_party/dawn/src/dawn_native/ErrorData.cpp @@ -14,11 +14,14 @@ #include "dawn_native/ErrorData.h" +#include "dawn_native/Error.h" +#include "dawn_native/dawn_platform.h" + namespace dawn_native { ErrorData::ErrorData() = default; - ErrorData::ErrorData(ErrorType type, std::string message) + ErrorData::ErrorData(InternalErrorType type, std::string message) : mType(type), mMessage(std::move(message)) { } @@ -31,10 +34,23 @@ namespace dawn_native { mBacktrace.push_back(std::move(record)); } - ErrorType ErrorData::GetType() const { + InternalErrorType ErrorData::GetInternalType() const { return mType; } + dawn::ErrorType ErrorData::GetType() const { + switch (mType) { + case InternalErrorType::Validation: + return dawn::ErrorType::Validation; + case InternalErrorType::OutOfMemory: + return dawn::ErrorType::OutOfMemory; + case InternalErrorType::DeviceLost: + return dawn::ErrorType::DeviceLost; + default: + return dawn::ErrorType::Unknown; + } + } + const std::string& ErrorData::GetMessage() const { return mMessage; } diff --git a/chromium/third_party/dawn/src/dawn_native/ErrorData.h b/chromium/third_party/dawn/src/dawn_native/ErrorData.h index 01520034838..8c56b7ab5a5 100644 --- a/chromium/third_party/dawn/src/dawn_native/ErrorData.h +++ b/chromium/third_party/dawn/src/dawn_native/ErrorData.h @@ -19,14 +19,18 @@ #include <string> #include <vector> +namespace dawn { + enum class ErrorType : uint32_t; +} + namespace dawn_native { - enum class ErrorType : uint32_t; + enum class InternalErrorType : uint32_t; class ErrorData { public: ErrorData(); - ErrorData(ErrorType type, std::string message); + ErrorData(InternalErrorType type, std::string message); struct BacktraceRecord { const char* file; @@ -35,12 +39,13 @@ namespace dawn_native { }; void AppendBacktrace(const char* file, const char* function, int line); - ErrorType GetType() const; + InternalErrorType GetInternalType() const; + dawn::ErrorType GetType() const; const std::string& GetMessage() const; const std::vector<BacktraceRecord>& GetBacktrace() const; private: - ErrorType mType; + InternalErrorType mType; std::string mMessage; std::vector<BacktraceRecord> mBacktrace; }; diff --git a/chromium/third_party/dawn/src/dawn_native/Extensions.cpp b/chromium/third_party/dawn/src/dawn_native/Extensions.cpp new file mode 100644 index 00000000000..2de7a8511d7 --- /dev/null +++ b/chromium/third_party/dawn/src/dawn_native/Extensions.cpp @@ -0,0 +1,113 @@ +// Copyright 2019 The Dawn Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include <array> + +#include "common/Assert.h" +#include "common/BitSetIterator.h" +#include "dawn_native/Extensions.h" + +namespace dawn_native { + namespace { + + struct ExtensionEnumAndInfo { + Extension extension; + ExtensionInfo info; + }; + + using ExtensionEnumAndInfoList = + std::array<ExtensionEnumAndInfo, static_cast<size_t>(Extension::EnumCount)>; + + static constexpr ExtensionEnumAndInfoList kExtensionNameAndInfoList = { + {{Extension::TextureCompressionBC, + {"texture_compression_bc", "Support Block Compressed (BC) texture formats", + "https://bugs.chromium.org/p/dawn/issues/detail?id=42"}}}}; + + } // anonymous namespace + + void ExtensionsSet::EnableExtension(Extension extension) { + ASSERT(extension != Extension::InvalidEnum); + const size_t extensionIndex = static_cast<size_t>(extension); + extensionsBitSet.set(extensionIndex); + } + + bool ExtensionsSet::IsEnabled(Extension extension) const { + ASSERT(extension != Extension::InvalidEnum); + const size_t extensionIndex = static_cast<size_t>(extension); + return extensionsBitSet[extensionIndex]; + } + + std::vector<const char*> ExtensionsSet::GetEnabledExtensionNames() const { + std::vector<const char*> enabledExtensionNames(extensionsBitSet.count()); + + uint32_t index = 0; + for (uint32_t i : IterateBitSet(extensionsBitSet)) { + const char* extensionName = ExtensionEnumToName(static_cast<Extension>(i)); + enabledExtensionNames[index] = extensionName; + ++index; + } + return enabledExtensionNames; + } + + const char* ExtensionEnumToName(Extension extension) { + ASSERT(extension != Extension::InvalidEnum); + + const ExtensionEnumAndInfo& extensionNameAndInfo = + kExtensionNameAndInfoList[static_cast<size_t>(extension)]; + ASSERT(extensionNameAndInfo.extension == extension); + return extensionNameAndInfo.info.name; + } + + ExtensionsInfo::ExtensionsInfo() { + for (size_t index = 0; index < kExtensionNameAndInfoList.size(); ++index) { + const ExtensionEnumAndInfo& extensionNameAndInfo = kExtensionNameAndInfoList[index]; + ASSERT(index == static_cast<size_t>(extensionNameAndInfo.extension)); + mExtensionNameToEnumMap[extensionNameAndInfo.info.name] = + extensionNameAndInfo.extension; + } + } + + const ExtensionInfo* ExtensionsInfo::GetExtensionInfo(const char* extensionName) const { + ASSERT(extensionName); + + const auto& iter = mExtensionNameToEnumMap.find(extensionName); + if (iter != mExtensionNameToEnumMap.cend()) { + return &kExtensionNameAndInfoList[static_cast<size_t>(iter->second)].info; + } + return nullptr; + } + + Extension ExtensionsInfo::ExtensionNameToEnum(const char* extensionName) const { + ASSERT(extensionName); + + const auto& iter = mExtensionNameToEnumMap.find(extensionName); + if (iter != mExtensionNameToEnumMap.cend()) { + return kExtensionNameAndInfoList[static_cast<size_t>(iter->second)].extension; + } + return Extension::InvalidEnum; + } + + ExtensionsSet ExtensionsInfo::ExtensionNamesToExtensionsSet( + const std::vector<const char*>& requiredExtensions) const { + ExtensionsSet extensionsSet; + + for (const char* extensionName : requiredExtensions) { + Extension extensionEnum = ExtensionNameToEnum(extensionName); + ASSERT(extensionEnum != Extension::InvalidEnum); + extensionsSet.EnableExtension(extensionEnum); + } + return extensionsSet; + } + +} // namespace dawn_native diff --git a/chromium/third_party/dawn/src/dawn_native/Extensions.h b/chromium/third_party/dawn/src/dawn_native/Extensions.h new file mode 100644 index 00000000000..274096fe3ea --- /dev/null +++ b/chromium/third_party/dawn/src/dawn_native/Extensions.h @@ -0,0 +1,63 @@ +// Copyright 2019 The Dawn Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef DAWNNATIVE_EXTENSIONS_H_ +#define DAWNNATIVE_EXTENSIONS_H_ + +#include <bitset> +#include <unordered_map> +#include <vector> + +#include "dawn_native/DawnNative.h" + +namespace dawn_native { + + enum class Extension { + TextureCompressionBC, + + EnumCount, + InvalidEnum = EnumCount, + ExtensionMin = TextureCompressionBC, + }; + + // A wrapper of the bitset to store if an extension is enabled or not. This wrapper provides the + // convenience to convert the enums of enum class Extension to the indices of a bitset. + struct ExtensionsSet { + std::bitset<static_cast<size_t>(Extension::EnumCount)> extensionsBitSet; + + void EnableExtension(Extension extension); + bool IsEnabled(Extension extension) const; + std::vector<const char*> GetEnabledExtensionNames() const; + }; + + const char* ExtensionEnumToName(Extension extension); + + class ExtensionsInfo { + public: + ExtensionsInfo(); + + // Used to query the details of an extension. Return nullptr if extensionName is not a valid + // name of an extension supported in Dawn + const ExtensionInfo* GetExtensionInfo(const char* extensionName) const; + Extension ExtensionNameToEnum(const char* extensionName) const; + ExtensionsSet ExtensionNamesToExtensionsSet( + const std::vector<const char*>& requiredExtensions) const; + + private: + std::unordered_map<std::string, Extension> mExtensionNameToEnumMap; + }; + +} // namespace dawn_native + +#endif // DAWNNATIVE_EXTENSIONS_H_
\ No newline at end of file diff --git a/chromium/third_party/dawn/src/dawn_native/Format.cpp b/chromium/third_party/dawn/src/dawn_native/Format.cpp index da2946aae46..c604a87d9c8 100644 --- a/chromium/third_party/dawn/src/dawn_native/Format.cpp +++ b/chromium/third_party/dawn/src/dawn_native/Format.cpp @@ -13,6 +13,8 @@ // limitations under the License. #include "dawn_native/Format.h" +#include "dawn_native/Device.h" +#include "dawn_native/Extensions.h" #include <bitset> @@ -36,6 +38,25 @@ namespace dawn_native { return aspect != Color; } + bool Format::HasComponentType(dawn::TextureComponentType componentType) const { + // Depth stencil textures need to be special cased but we don't support sampling them yet. + if (aspect != Color) { + return false; + } + + // Check that Type is correctly mirrors TextureComponentType except for "Other". + static_assert(static_cast<dawn::TextureComponentType>(Type::Float) == + dawn::TextureComponentType::Float, + ""); + static_assert( + static_cast<dawn::TextureComponentType>(Type::Sint) == dawn::TextureComponentType::Sint, + ""); + static_assert( + static_cast<dawn::TextureComponentType>(Type::Uint) == dawn::TextureComponentType::Uint, + ""); + return static_cast<dawn::TextureComponentType>(type) == componentType; + } + size_t Format::GetIndex() const { return ComputeFormatIndex(format); } @@ -43,15 +64,22 @@ namespace dawn_native { // Implementation details of the format table of the DeviceBase // For the enum for formats are packed but this might change when we have a broader extension - // mechanism for webgpu.h + // mechanism for webgpu.h. Formats start at 1 because 0 is the undefined format. size_t ComputeFormatIndex(dawn::TextureFormat format) { - return static_cast<size_t>(static_cast<uint32_t>(format)); + // This takes advantage of overflows to make the index of TextureFormat::Undefined outside + // of the range of the FormatTable. + static_assert(static_cast<uint32_t>(dawn::TextureFormat::Undefined) - 1 > kKnownFormatCount, + ""); + return static_cast<size_t>(static_cast<uint32_t>(format) - 1); } - FormatTable BuildFormatTable(const DeviceBase*) { + FormatTable BuildFormatTable(const DeviceBase* device) { FormatTable table; std::bitset<kKnownFormatCount> formatsSet; + using Type = Format::Type; + using Aspect = Format::Aspect; + auto AddFormat = [&table, &formatsSet](Format format) { size_t index = ComputeFormatIndex(format.format); ASSERT(index < table.size()); @@ -65,13 +93,14 @@ namespace dawn_native { }; auto AddColorFormat = [&AddFormat](dawn::TextureFormat format, bool renderable, - uint32_t byteSize) { + uint32_t byteSize, Type type) { Format internalFormat; internalFormat.format = format; internalFormat.isRenderable = renderable; internalFormat.isCompressed = false; internalFormat.isSupported = true; - internalFormat.aspect = Format::Aspect::Color; + internalFormat.aspect = Aspect::Color; + internalFormat.type = type; internalFormat.blockByteSize = byteSize; internalFormat.blockWidth = 1; internalFormat.blockHeight = 1; @@ -86,6 +115,7 @@ namespace dawn_native { internalFormat.isCompressed = false; internalFormat.isSupported = true; internalFormat.aspect = aspect; + internalFormat.type = Type::Other; internalFormat.blockByteSize = byteSize; internalFormat.blockWidth = 1; internalFormat.blockHeight = 1; @@ -93,13 +123,14 @@ namespace dawn_native { }; auto AddCompressedFormat = [&AddFormat](dawn::TextureFormat format, uint32_t byteSize, - uint32_t width, uint32_t height) { + uint32_t width, uint32_t height, bool isSupported) { Format internalFormat; internalFormat.format = format; internalFormat.isRenderable = false; internalFormat.isCompressed = true; - internalFormat.isSupported = true; - internalFormat.aspect = Format::Aspect::Color; + internalFormat.isSupported = isSupported; + internalFormat.aspect = Aspect::Color; + internalFormat.type = Type::Float; internalFormat.blockByteSize = byteSize; internalFormat.blockWidth = width; internalFormat.blockHeight = height; @@ -109,79 +140,74 @@ namespace dawn_native { // clang-format off // 1 byte color formats - AddColorFormat(dawn::TextureFormat::R8Unorm, true, 1); - AddColorFormat(dawn::TextureFormat::R8Snorm, true, 1); - AddColorFormat(dawn::TextureFormat::R8Uint, true, 1); - AddColorFormat(dawn::TextureFormat::R8Sint, true, 1); + AddColorFormat(dawn::TextureFormat::R8Unorm, true, 1, Type::Float); + AddColorFormat(dawn::TextureFormat::R8Snorm, false, 1, Type::Float); + AddColorFormat(dawn::TextureFormat::R8Uint, true, 1, Type::Uint); + AddColorFormat(dawn::TextureFormat::R8Sint, true, 1, Type::Sint); // 2 bytes color formats - AddColorFormat(dawn::TextureFormat::R16Unorm, true, 2); - AddColorFormat(dawn::TextureFormat::R16Snorm, true, 2); - AddColorFormat(dawn::TextureFormat::R16Uint, true, 2); - AddColorFormat(dawn::TextureFormat::R16Sint, true, 2); - AddColorFormat(dawn::TextureFormat::R16Float, true, 2); - AddColorFormat(dawn::TextureFormat::RG8Unorm, true, 2); - AddColorFormat(dawn::TextureFormat::RG8Snorm, true, 2); - AddColorFormat(dawn::TextureFormat::RG8Uint, true, 2); - AddColorFormat(dawn::TextureFormat::RG8Sint, true, 2); + AddColorFormat(dawn::TextureFormat::R16Uint, true, 2, Type::Uint); + AddColorFormat(dawn::TextureFormat::R16Sint, true, 2, Type::Sint); + AddColorFormat(dawn::TextureFormat::R16Float, true, 2, Type::Float); + AddColorFormat(dawn::TextureFormat::RG8Unorm, true, 2, Type::Float); + AddColorFormat(dawn::TextureFormat::RG8Snorm, false, 2, Type::Float); + AddColorFormat(dawn::TextureFormat::RG8Uint, true, 2, Type::Uint); + AddColorFormat(dawn::TextureFormat::RG8Sint, true, 2, Type::Sint); // 4 bytes color formats - AddColorFormat(dawn::TextureFormat::R32Uint, true, 4); - AddColorFormat(dawn::TextureFormat::R32Sint, true, 4); - AddColorFormat(dawn::TextureFormat::R32Float, true, 4); - AddColorFormat(dawn::TextureFormat::RG16Unorm, true, 4); - AddColorFormat(dawn::TextureFormat::RG16Snorm, true, 4); - AddColorFormat(dawn::TextureFormat::RG16Uint, true, 4); - AddColorFormat(dawn::TextureFormat::RG16Sint, true, 4); - AddColorFormat(dawn::TextureFormat::RG16Float, true, 4); - AddColorFormat(dawn::TextureFormat::RGBA8Unorm, true, 4); - AddColorFormat(dawn::TextureFormat::RGBA8UnormSrgb, true, 4); - AddColorFormat(dawn::TextureFormat::RGBA8Snorm, true, 4); - AddColorFormat(dawn::TextureFormat::RGBA8Uint, true, 4); - AddColorFormat(dawn::TextureFormat::RGBA8Sint, true, 4); - AddColorFormat(dawn::TextureFormat::BGRA8Unorm, true, 4); - AddColorFormat(dawn::TextureFormat::BGRA8UnormSrgb, true, 4); - AddColorFormat(dawn::TextureFormat::RGB10A2Unorm, true, 4); - - AddColorFormat(dawn::TextureFormat::RG11B10Float, false, 4); + AddColorFormat(dawn::TextureFormat::R32Uint, true, 4, Type::Uint); + AddColorFormat(dawn::TextureFormat::R32Sint, true, 4, Type::Sint); + AddColorFormat(dawn::TextureFormat::R32Float, true, 4, Type::Float); + AddColorFormat(dawn::TextureFormat::RG16Uint, true, 4, Type::Uint); + AddColorFormat(dawn::TextureFormat::RG16Sint, true, 4, Type::Sint); + AddColorFormat(dawn::TextureFormat::RG16Float, true, 4, Type::Float); + AddColorFormat(dawn::TextureFormat::RGBA8Unorm, true, 4, Type::Float); + AddColorFormat(dawn::TextureFormat::RGBA8UnormSrgb, true, 4, Type::Float); + AddColorFormat(dawn::TextureFormat::RGBA8Snorm, false, 4, Type::Float); + AddColorFormat(dawn::TextureFormat::RGBA8Uint, true, 4, Type::Uint); + AddColorFormat(dawn::TextureFormat::RGBA8Sint, true, 4, Type::Sint); + AddColorFormat(dawn::TextureFormat::BGRA8Unorm, true, 4, Type::Float); + AddColorFormat(dawn::TextureFormat::BGRA8UnormSrgb, true, 4, Type::Float); + AddColorFormat(dawn::TextureFormat::RGB10A2Unorm, true, 4, Type::Float); + + AddColorFormat(dawn::TextureFormat::RG11B10Float, false, 4, Type::Float); // 8 bytes color formats - AddColorFormat(dawn::TextureFormat::RG32Uint, true, 8); - AddColorFormat(dawn::TextureFormat::RG32Sint, true, 8); - AddColorFormat(dawn::TextureFormat::RG32Float, true, 8); - AddColorFormat(dawn::TextureFormat::RGBA16Unorm, true, 8); - AddColorFormat(dawn::TextureFormat::RGBA16Snorm, true, 8); - AddColorFormat(dawn::TextureFormat::RGBA16Uint, true, 8); - AddColorFormat(dawn::TextureFormat::RGBA16Sint, true, 8); - AddColorFormat(dawn::TextureFormat::RGBA16Float, true, 8); + AddColorFormat(dawn::TextureFormat::RG32Uint, true, 8, Type::Uint); + AddColorFormat(dawn::TextureFormat::RG32Sint, true, 8, Type::Sint); + AddColorFormat(dawn::TextureFormat::RG32Float, true, 8, Type::Float); + AddColorFormat(dawn::TextureFormat::RGBA16Uint, true, 8, Type::Uint); + AddColorFormat(dawn::TextureFormat::RGBA16Sint, true, 8, Type::Sint); + AddColorFormat(dawn::TextureFormat::RGBA16Float, true, 8, Type::Float); // 16 bytes color formats - AddColorFormat(dawn::TextureFormat::RGBA32Uint, true, 16); - AddColorFormat(dawn::TextureFormat::RGBA32Sint, true, 16); - AddColorFormat(dawn::TextureFormat::RGBA32Float, true, 16); + AddColorFormat(dawn::TextureFormat::RGBA32Uint, true, 16, Type::Uint); + AddColorFormat(dawn::TextureFormat::RGBA32Sint, true, 16, Type::Sint); + AddColorFormat(dawn::TextureFormat::RGBA32Float, true, 16, Type::Float); // Depth stencil formats - AddDepthStencilFormat(dawn::TextureFormat::Depth32Float, Format::Aspect::Depth, 4); - AddDepthStencilFormat(dawn::TextureFormat::Depth24Plus, Format::Aspect::Depth, 4); + AddDepthStencilFormat(dawn::TextureFormat::Depth32Float, Aspect::Depth, 4); + AddDepthStencilFormat(dawn::TextureFormat::Depth24Plus, Aspect::Depth, 4); // TODO(cwallez@chromium.org): It isn't clear if this format should be copyable // because its size isn't well defined, is it 4, 5 or 8? - AddDepthStencilFormat(dawn::TextureFormat::Depth24PlusStencil8, Format::Aspect::DepthStencil, 4); + AddDepthStencilFormat(dawn::TextureFormat::Depth24PlusStencil8, Aspect::DepthStencil, 4); // BC compressed formats - AddCompressedFormat(dawn::TextureFormat::BC1RGBAUnorm, 8, 4, 4); - AddCompressedFormat(dawn::TextureFormat::BC1RGBAUnormSrgb, 8, 4, 4); - AddCompressedFormat(dawn::TextureFormat::BC4RSnorm, 8, 4, 4); - AddCompressedFormat(dawn::TextureFormat::BC4RUnorm, 8, 4, 4); - AddCompressedFormat(dawn::TextureFormat::BC2RGBAUnorm, 16, 4, 4); - AddCompressedFormat(dawn::TextureFormat::BC2RGBAUnormSrgb, 16, 4, 4); - AddCompressedFormat(dawn::TextureFormat::BC3RGBAUnorm, 16, 4, 4); - AddCompressedFormat(dawn::TextureFormat::BC3RGBAUnormSrgb, 16, 4, 4); - AddCompressedFormat(dawn::TextureFormat::BC5RGSnorm, 16, 4, 4); - AddCompressedFormat(dawn::TextureFormat::BC5RGUnorm, 16, 4, 4); - AddCompressedFormat(dawn::TextureFormat::BC6HRGBSfloat, 16, 4, 4); - AddCompressedFormat(dawn::TextureFormat::BC6HRGBUfloat, 16, 4, 4); - AddCompressedFormat(dawn::TextureFormat::BC7RGBAUnorm, 16, 4, 4); - AddCompressedFormat(dawn::TextureFormat::BC7RGBAUnormSrgb, 16, 4, 4); + bool isBCFormatSupported = device->IsExtensionEnabled(Extension::TextureCompressionBC); + AddCompressedFormat(dawn::TextureFormat::BC1RGBAUnorm, 8, 4, 4, isBCFormatSupported); + AddCompressedFormat(dawn::TextureFormat::BC1RGBAUnormSrgb, 8, 4, 4, isBCFormatSupported); + AddCompressedFormat(dawn::TextureFormat::BC4RSnorm, 8, 4, 4, isBCFormatSupported); + AddCompressedFormat(dawn::TextureFormat::BC4RUnorm, 8, 4, 4, isBCFormatSupported); + AddCompressedFormat(dawn::TextureFormat::BC2RGBAUnorm, 16, 4, 4, isBCFormatSupported); + AddCompressedFormat(dawn::TextureFormat::BC2RGBAUnormSrgb, 16, 4, 4, isBCFormatSupported); + AddCompressedFormat(dawn::TextureFormat::BC3RGBAUnorm, 16, 4, 4, isBCFormatSupported); + AddCompressedFormat(dawn::TextureFormat::BC3RGBAUnormSrgb, 16, 4, 4, isBCFormatSupported); + AddCompressedFormat(dawn::TextureFormat::BC5RGSnorm, 16, 4, 4, isBCFormatSupported); + AddCompressedFormat(dawn::TextureFormat::BC5RGUnorm, 16, 4, 4, isBCFormatSupported); + AddCompressedFormat(dawn::TextureFormat::BC6HRGBSfloat, 16, 4, 4, isBCFormatSupported); + AddCompressedFormat(dawn::TextureFormat::BC6HRGBUfloat, 16, 4, 4, isBCFormatSupported); + AddCompressedFormat(dawn::TextureFormat::BC7RGBAUnorm, 16, 4, 4, isBCFormatSupported); + AddCompressedFormat(dawn::TextureFormat::BC7RGBAUnormSrgb, 16, 4, 4, isBCFormatSupported); // clang-format on diff --git a/chromium/third_party/dawn/src/dawn_native/Format.h b/chromium/third_party/dawn/src/dawn_native/Format.h index 334198cb98e..4ec19b8b918 100644 --- a/chromium/third_party/dawn/src/dawn_native/Format.h +++ b/chromium/third_party/dawn/src/dawn_native/Format.h @@ -27,7 +27,7 @@ namespace dawn_native { // The number of formats Dawn knows about. Asserts in BuildFormatTable ensure that this is the // exact number of known format. - static constexpr size_t kKnownFormatCount = 58; + static constexpr size_t kKnownFormatCount = 52; // A dawn::TextureFormat along with all the information about it necessary for validation. struct Format { @@ -38,12 +38,20 @@ namespace dawn_native { DepthStencil, }; + enum Type { + Float, + Sint, + Uint, + Other, + }; + dawn::TextureFormat format; bool isRenderable; bool isCompressed; // A format can be known but not supported because it is part of a disabled extension. bool isSupported; Aspect aspect; + Type type; uint32_t blockByteSize; uint32_t blockWidth; @@ -53,6 +61,7 @@ namespace dawn_native { bool HasDepth() const; bool HasStencil() const; bool HasDepthOrStencil() const; + bool HasComponentType(dawn::TextureComponentType componentType) const; // The index of the format in the list of all known formats: a unique number for each format // in [0, kKnownFormatCount) diff --git a/chromium/third_party/dawn/src/dawn_native/Forward.h b/chromium/third_party/dawn/src/dawn_native/Forward.h index b4c3e837bea..ad73beffac3 100644 --- a/chromium/third_party/dawn/src/dawn_native/Forward.h +++ b/chromium/third_party/dawn/src/dawn_native/Forward.h @@ -32,8 +32,11 @@ namespace dawn_native { class PipelineBase; class PipelineLayoutBase; class QueueBase; + class RenderBundleBase; + class RenderBundleEncoderBase; class RenderPassEncoderBase; class RenderPipelineBase; + class ResourceHeapBase; class SamplerBase; class ShaderModuleBase; class StagingBufferBase; diff --git a/chromium/third_party/dawn/src/dawn_native/Instance.cpp b/chromium/third_party/dawn/src/dawn_native/Instance.cpp index f686a069be0..3fc7ae889bd 100644 --- a/chromium/third_party/dawn/src/dawn_native/Instance.cpp +++ b/chromium/third_party/dawn/src/dawn_native/Instance.cpp @@ -49,47 +49,6 @@ namespace dawn_native { } #endif // defined(DAWN_ENABLE_BACKEND_VULKAN) - namespace { - - struct ToggleEnumAndInfo { - Toggle toggle; - ToggleInfo info; - }; - - using ToggleEnumAndInfoList = - std::array<ToggleEnumAndInfo, static_cast<size_t>(Toggle::EnumCount)>; - - static constexpr ToggleEnumAndInfoList kToggleNameAndInfoList = { - {{Toggle::EmulateStoreAndMSAAResolve, - {"emulate_store_and_msaa_resolve", - "Emulate storing into multisampled color attachments and doing MSAA resolve " - "simultaneously. This workaround is enabled by default on the Metal drivers that do " - "not support MTLStoreActionStoreAndMultisampleResolve. To support StoreOp::Store on " - "those platforms, we should do MSAA resolve in another render pass after ending the " - "previous one.", - "https://bugs.chromium.org/p/dawn/issues/detail?id=56"}}, - {Toggle::NonzeroClearResourcesOnCreationForTesting, - {"nonzero_clear_resources_on_creation_for_testing", - "Clears texture to full 1 bits as soon as they are created, but doesn't update " - "the tracking state of the texture. This way we can test the logic of clearing " - "textures that use recycled memory.", - "https://bugs.chromium.org/p/dawn/issues/detail?id=145"}}, - {Toggle::AlwaysResolveIntoZeroLevelAndLayer, - {"always_resolve_into_zero_level_and_layer", - "When the resolve target is a texture view that is created on the non-zero level or " - "layer of a texture, we first resolve into a temporarily 2D texture with only one " - "mipmap level and one array layer, and copy the result of MSAA resolve into the " - "true resolve target. This workaround is enabled by default on the Metal drivers " - "that have bugs when setting non-zero resolveLevel or resolveSlice.", - "https://bugs.chromium.org/p/dawn/issues/detail?id=56"}}, - {Toggle::LazyClearResourceOnFirstUse, - {"lazy_clear_resource_on_first_use", - "Clears resource to zero on first usage. This initializes the resource " - "so that no dirty bits from recycled memory is present in the new resource.", - "https://bugs.chromium.org/p/dawn/issues/detail?id=145"}}}}; - - } // anonymous namespace - // InstanceBase void InstanceBase::DiscoverDefaultAdapters() { @@ -119,51 +78,25 @@ namespace dawn_native { return !ConsumedError(DiscoverAdaptersInternal(options)); } - const char* InstanceBase::ToggleEnumToName(Toggle toggle) { - ASSERT(toggle != Toggle::InvalidEnum); - - const ToggleEnumAndInfo& toggleNameAndInfo = - kToggleNameAndInfoList[static_cast<size_t>(toggle)]; - ASSERT(toggleNameAndInfo.toggle == toggle); - return toggleNameAndInfo.info.name; - } - const ToggleInfo* InstanceBase::GetToggleInfo(const char* toggleName) { - ASSERT(toggleName); - - EnsureToggleNameToEnumMapInitialized(); - - const auto& iter = mToggleNameToEnumMap.find(toggleName); - if (iter != mToggleNameToEnumMap.cend()) { - return &kToggleNameAndInfoList[static_cast<size_t>(iter->second)].info; - } - return nullptr; + return mTogglesInfo.GetToggleInfo(toggleName); } Toggle InstanceBase::ToggleNameToEnum(const char* toggleName) { - ASSERT(toggleName); - - EnsureToggleNameToEnumMapInitialized(); - - const auto& iter = mToggleNameToEnumMap.find(toggleName); - if (iter != mToggleNameToEnumMap.cend()) { - return kToggleNameAndInfoList[static_cast<size_t>(iter->second)].toggle; - } - return Toggle::InvalidEnum; + return mTogglesInfo.ToggleNameToEnum(toggleName); } - void InstanceBase::EnsureToggleNameToEnumMapInitialized() { - if (mToggleNameToEnumMapInitialized) { - return; - } + const ExtensionInfo* InstanceBase::GetExtensionInfo(const char* extensionName) { + return mExtensionsInfo.GetExtensionInfo(extensionName); + } - for (size_t index = 0; index < kToggleNameAndInfoList.size(); ++index) { - const ToggleEnumAndInfo& toggleNameAndInfo = kToggleNameAndInfoList[index]; - ASSERT(index == static_cast<size_t>(toggleNameAndInfo.toggle)); - mToggleNameToEnumMap[toggleNameAndInfo.info.name] = toggleNameAndInfo.toggle; - } + Extension InstanceBase::ExtensionNameToEnum(const char* extensionName) { + return mExtensionsInfo.ExtensionNameToEnum(extensionName); + } - mToggleNameToEnumMapInitialized = true; + ExtensionsSet InstanceBase::ExtensionNamesToExtensionsSet( + const std::vector<const char*>& requiredExtensions) { + return mExtensionsInfo.ExtensionNamesToExtensionsSet(requiredExtensions); } const std::vector<std::unique_ptr<AdapterBase>>& InstanceBase::GetAdapters() const { @@ -259,4 +192,12 @@ namespace dawn_native { return mBeginCaptureOnStartup; } + void InstanceBase::SetPlatform(dawn_platform::Platform* platform) { + mPlatform = platform; + } + + dawn_platform::Platform* InstanceBase::GetPlatform() const { + return mPlatform; + } + } // namespace dawn_native diff --git a/chromium/third_party/dawn/src/dawn_native/Instance.h b/chromium/third_party/dawn/src/dawn_native/Instance.h index 3743dd81f93..1e704e093e0 100644 --- a/chromium/third_party/dawn/src/dawn_native/Instance.h +++ b/chromium/third_party/dawn/src/dawn_native/Instance.h @@ -17,6 +17,7 @@ #include "dawn_native/Adapter.h" #include "dawn_native/BackendConnection.h" +#include "dawn_native/Extensions.h" #include "dawn_native/Toggles.h" #include <array> @@ -47,9 +48,14 @@ namespace dawn_native { // Used to query the details of a toggle. Return nullptr if toggleName is not a valid name // of a toggle supported in Dawn. const ToggleInfo* GetToggleInfo(const char* toggleName); - Toggle ToggleNameToEnum(const char* toggleName); - const char* ToggleEnumToName(Toggle toggle); + + // Used to query the details of an extension. Return nullptr if extensionName is not a valid + // name of an extension supported in Dawn. + const ExtensionInfo* GetExtensionInfo(const char* extensionName); + Extension ExtensionNameToEnum(const char* extensionName); + ExtensionsSet ExtensionNamesToExtensionsSet( + const std::vector<const char*>& requiredExtensions); void EnableBackendValidation(bool enableBackendValidation); bool IsBackendValidationEnabled() const; @@ -57,6 +63,9 @@ namespace dawn_native { void EnableBeginCaptureOnStartup(bool beginCaptureOnStartup); bool IsBeginCaptureOnStartupEnabled() const; + void SetPlatform(dawn_platform::Platform* platform); + dawn_platform::Platform* GetPlatform() const; + private: // Lazily creates connections to all backends that have been compiled. void EnsureBackendConnections(); @@ -66,19 +75,19 @@ namespace dawn_native { MaybeError DiscoverAdaptersInternal(const AdapterDiscoveryOptionsBase* options); - void EnsureToggleNameToEnumMapInitialized(); - bool mBackendsConnected = false; bool mDiscoveredDefaultAdapters = false; - bool mToggleNameToEnumMapInitialized = false; bool mEnableBackendValidation = false; bool mBeginCaptureOnStartup = false; + dawn_platform::Platform* mPlatform = nullptr; + std::vector<std::unique_ptr<BackendConnection>> mBackends; std::vector<std::unique_ptr<AdapterBase>> mAdapters; - std::unordered_map<std::string, Toggle> mToggleNameToEnumMap; + ExtensionsInfo mExtensionsInfo; + TogglesInfo mTogglesInfo; }; } // namespace dawn_native diff --git a/chromium/third_party/dawn/src/dawn_native/PassResourceUsage.h b/chromium/third_party/dawn/src/dawn_native/PassResourceUsage.h index 9a8c2b07db4..eebeda6db1f 100644 --- a/chromium/third_party/dawn/src/dawn_native/PassResourceUsage.h +++ b/chromium/third_party/dawn/src/dawn_native/PassResourceUsage.h @@ -30,10 +30,10 @@ namespace dawn_native { // re-compute it. struct PassResourceUsage { std::vector<BufferBase*> buffers; - std::vector<dawn::BufferUsageBit> bufferUsages; + std::vector<dawn::BufferUsage> bufferUsages; std::vector<TextureBase*> textures; - std::vector<dawn::TextureUsageBit> textureUsages; + std::vector<dawn::TextureUsage> textureUsages; }; struct CommandBufferResourceUsage { diff --git a/chromium/third_party/dawn/src/dawn_native/PassResourceUsageTracker.cpp b/chromium/third_party/dawn/src/dawn_native/PassResourceUsageTracker.cpp new file mode 100644 index 00000000000..8ae4edfdb5e --- /dev/null +++ b/chromium/third_party/dawn/src/dawn_native/PassResourceUsageTracker.cpp @@ -0,0 +1,119 @@ +// Copyright 2019 The Dawn Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "dawn_native/PassResourceUsageTracker.h" + +#include "dawn_native/Buffer.h" +#include "dawn_native/Texture.h" + +namespace dawn_native { + + void PassResourceUsageTracker::BufferUsedAs(BufferBase* buffer, dawn::BufferUsage usage) { + // std::map's operator[] will create the key and return 0 if the key didn't exist + // before. + dawn::BufferUsage& storedUsage = mBufferUsages[buffer]; + + if (usage == dawn::BufferUsage::Storage && storedUsage & dawn::BufferUsage::Storage) { + mStorageUsedMultipleTimes = true; + } + + storedUsage |= usage; + } + + void PassResourceUsageTracker::TextureUsedAs(TextureBase* texture, dawn::TextureUsage usage) { + // std::map's operator[] will create the key and return 0 if the key didn't exist + // before. + dawn::TextureUsage& storedUsage = mTextureUsages[texture]; + + if (usage == dawn::TextureUsage::Storage && storedUsage & dawn::TextureUsage::Storage) { + mStorageUsedMultipleTimes = true; + } + + storedUsage |= usage; + } + + MaybeError PassResourceUsageTracker::ValidateComputePassUsages() const { + // Storage resources cannot be used twice in the same compute pass + if (mStorageUsedMultipleTimes) { + return DAWN_VALIDATION_ERROR("Storage resource used multiple times in compute pass"); + } + return ValidateUsages(); + } + + MaybeError PassResourceUsageTracker::ValidateRenderPassUsages() const { + return ValidateUsages(); + } + + // Performs the per-pass usage validation checks + MaybeError PassResourceUsageTracker::ValidateUsages() const { + // Buffers can only be used as single-write or multiple read. + for (auto& it : mBufferUsages) { + BufferBase* buffer = it.first; + dawn::BufferUsage usage = it.second; + + if (usage & ~buffer->GetUsage()) { + return DAWN_VALIDATION_ERROR("Buffer missing usage for the pass"); + } + + bool readOnly = (usage & kReadOnlyBufferUsages) == usage; + bool singleUse = dawn::HasZeroOrOneBits(usage); + + if (!readOnly && !singleUse) { + return DAWN_VALIDATION_ERROR( + "Buffer used as writable usage and another usage in pass"); + } + } + + // Textures can only be used as single-write or multiple read. + // TODO(cwallez@chromium.org): implement per-subresource tracking + for (auto& it : mTextureUsages) { + TextureBase* texture = it.first; + dawn::TextureUsage usage = it.second; + + if (usage & ~texture->GetUsage()) { + return DAWN_VALIDATION_ERROR("Texture missing usage for the pass"); + } + + // For textures the only read-only usage in a pass is Sampled, so checking the + // usage constraint simplifies to checking a single usage bit is set. + if (!dawn::HasZeroOrOneBits(it.second)) { + return DAWN_VALIDATION_ERROR("Texture used with more than one usage in pass"); + } + } + + return {}; + } + + // Returns the per-pass usage for use by backends for APIs with explicit barriers. + PassResourceUsage PassResourceUsageTracker::AcquireResourceUsage() { + PassResourceUsage result; + result.buffers.reserve(mBufferUsages.size()); + result.bufferUsages.reserve(mBufferUsages.size()); + result.textures.reserve(mTextureUsages.size()); + result.textureUsages.reserve(mTextureUsages.size()); + + for (auto& it : mBufferUsages) { + result.buffers.push_back(it.first); + result.bufferUsages.push_back(it.second); + } + + for (auto& it : mTextureUsages) { + result.textures.push_back(it.first); + result.textureUsages.push_back(it.second); + } + + return result; + } + +} // namespace dawn_native diff --git a/chromium/third_party/dawn/src/dawn_native/PassResourceUsageTracker.h b/chromium/third_party/dawn/src/dawn_native/PassResourceUsageTracker.h new file mode 100644 index 00000000000..8f3662f14b0 --- /dev/null +++ b/chromium/third_party/dawn/src/dawn_native/PassResourceUsageTracker.h @@ -0,0 +1,56 @@ +// Copyright 2019 The Dawn Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef DAWNNATIVE_PASSRESOURCEUSAGETRACKER_H_ +#define DAWNNATIVE_PASSRESOURCEUSAGETRACKER_H_ + +#include "dawn_native/Error.h" +#include "dawn_native/PassResourceUsage.h" + +#include "dawn_native/dawn_platform.h" + +#include <map> + +namespace dawn_native { + + class BufferBase; + class TextureBase; + + // Helper class to encapsulate the logic of tracking per-resource usage during the + // validation of command buffer passes. It is used both to know if there are validation + // errors, and to get a list of resources used per pass for backends that need the + // information. + class PassResourceUsageTracker { + public: + void BufferUsedAs(BufferBase* buffer, dawn::BufferUsage usage); + void TextureUsedAs(TextureBase* texture, dawn::TextureUsage usage); + + MaybeError ValidateComputePassUsages() const; + MaybeError ValidateRenderPassUsages() const; + + // Returns the per-pass usage for use by backends for APIs with explicit barriers. + PassResourceUsage AcquireResourceUsage(); + + private: + // Performs the per-pass usage validation checks + MaybeError ValidateUsages() const; + + std::map<BufferBase*, dawn::BufferUsage> mBufferUsages; + std::map<TextureBase*, dawn::TextureUsage> mTextureUsages; + bool mStorageUsedMultipleTimes = false; + }; + +} // namespace dawn_native + +#endif // DAWNNATIVE_PASSRESOURCEUSAGETRACKER_H_ diff --git a/chromium/third_party/dawn/src/dawn_native/PerStage.cpp b/chromium/third_party/dawn/src/dawn_native/PerStage.cpp index 1153c425d1d..c4837c7b5fb 100644 --- a/chromium/third_party/dawn/src/dawn_native/PerStage.cpp +++ b/chromium/third_party/dawn/src/dawn_native/PerStage.cpp @@ -16,14 +16,14 @@ namespace dawn_native { - BitSetIterator<kNumStages, ShaderStage> IterateStages(dawn::ShaderStageBit stages) { + BitSetIterator<kNumStages, SingleShaderStage> IterateStages(dawn::ShaderStage stages) { std::bitset<kNumStages> bits(static_cast<uint32_t>(stages)); - return BitSetIterator<kNumStages, ShaderStage>(bits); + return BitSetIterator<kNumStages, SingleShaderStage>(bits); } - dawn::ShaderStageBit StageBit(ShaderStage stage) { + dawn::ShaderStage StageBit(SingleShaderStage stage) { ASSERT(static_cast<uint32_t>(stage) < kNumStages); - return static_cast<dawn::ShaderStageBit>(1 << static_cast<uint32_t>(stage)); + return static_cast<dawn::ShaderStage>(1 << static_cast<uint32_t>(stage)); } } // namespace dawn_native diff --git a/chromium/third_party/dawn/src/dawn_native/PerStage.h b/chromium/third_party/dawn/src/dawn_native/PerStage.h index b7be5881fe9..ac92b5b78db 100644 --- a/chromium/third_party/dawn/src/dawn_native/PerStage.h +++ b/chromium/third_party/dawn/src/dawn_native/PerStage.h @@ -25,27 +25,27 @@ namespace dawn_native { - enum class ShaderStage { Vertex, Fragment, Compute }; + enum class SingleShaderStage { Vertex, Fragment, Compute }; - static_assert(static_cast<uint32_t>(ShaderStage::Vertex) < kNumStages, ""); - static_assert(static_cast<uint32_t>(ShaderStage::Fragment) < kNumStages, ""); - static_assert(static_cast<uint32_t>(ShaderStage::Compute) < kNumStages, ""); + static_assert(static_cast<uint32_t>(SingleShaderStage::Vertex) < kNumStages, ""); + static_assert(static_cast<uint32_t>(SingleShaderStage::Fragment) < kNumStages, ""); + static_assert(static_cast<uint32_t>(SingleShaderStage::Compute) < kNumStages, ""); - static_assert(static_cast<uint32_t>(dawn::ShaderStageBit::Vertex) == - (1 << static_cast<uint32_t>(ShaderStage::Vertex)), + static_assert(static_cast<uint32_t>(dawn::ShaderStage::Vertex) == + (1 << static_cast<uint32_t>(SingleShaderStage::Vertex)), ""); - static_assert(static_cast<uint32_t>(dawn::ShaderStageBit::Fragment) == - (1 << static_cast<uint32_t>(ShaderStage::Fragment)), + static_assert(static_cast<uint32_t>(dawn::ShaderStage::Fragment) == + (1 << static_cast<uint32_t>(SingleShaderStage::Fragment)), ""); - static_assert(static_cast<uint32_t>(dawn::ShaderStageBit::Compute) == - (1 << static_cast<uint32_t>(ShaderStage::Compute)), + static_assert(static_cast<uint32_t>(dawn::ShaderStage::Compute) == + (1 << static_cast<uint32_t>(SingleShaderStage::Compute)), ""); - BitSetIterator<kNumStages, ShaderStage> IterateStages(dawn::ShaderStageBit stages); - dawn::ShaderStageBit StageBit(ShaderStage stage); + BitSetIterator<kNumStages, SingleShaderStage> IterateStages(dawn::ShaderStage stages); + dawn::ShaderStage StageBit(SingleShaderStage stage); - static constexpr dawn::ShaderStageBit kAllStages = - static_cast<dawn::ShaderStageBit>((1 << kNumStages) - 1); + static constexpr dawn::ShaderStage kAllStages = + static_cast<dawn::ShaderStage>((1 << kNumStages) - 1); template <typename T> class PerStage { @@ -55,21 +55,21 @@ namespace dawn_native { mData.fill(initialValue); } - T& operator[](ShaderStage stage) { + T& operator[](SingleShaderStage stage) { DAWN_ASSERT(static_cast<uint32_t>(stage) < kNumStages); return mData[static_cast<uint32_t>(stage)]; } - const T& operator[](ShaderStage stage) const { + const T& operator[](SingleShaderStage stage) const { DAWN_ASSERT(static_cast<uint32_t>(stage) < kNumStages); return mData[static_cast<uint32_t>(stage)]; } - T& operator[](dawn::ShaderStageBit stageBit) { + T& operator[](dawn::ShaderStage stageBit) { uint32_t bit = static_cast<uint32_t>(stageBit); DAWN_ASSERT(bit != 0 && IsPowerOfTwo(bit) && bit <= (1 << kNumStages)); return mData[Log2(bit)]; } - const T& operator[](dawn::ShaderStageBit stageBit) const { + const T& operator[](dawn::ShaderStage stageBit) const { uint32_t bit = static_cast<uint32_t>(stageBit); DAWN_ASSERT(bit != 0 && IsPowerOfTwo(bit) && bit <= (1 << kNumStages)); return mData[Log2(bit)]; diff --git a/chromium/third_party/dawn/src/dawn_native/Pipeline.cpp b/chromium/third_party/dawn/src/dawn_native/Pipeline.cpp index 6551e178c4a..91b2ed090bd 100644 --- a/chromium/third_party/dawn/src/dawn_native/Pipeline.cpp +++ b/chromium/third_party/dawn/src/dawn_native/Pipeline.cpp @@ -23,7 +23,7 @@ namespace dawn_native { MaybeError ValidatePipelineStageDescriptor(const DeviceBase* device, const PipelineStageDescriptor* descriptor, const PipelineLayoutBase* layout, - ShaderStage stage) { + SingleShaderStage stage) { DAWN_TRY(device->ValidateObject(descriptor->module)); if (descriptor->entryPoint != std::string("main")) { @@ -42,7 +42,7 @@ namespace dawn_native { PipelineBase::PipelineBase(DeviceBase* device, PipelineLayoutBase* layout, - dawn::ShaderStageBit stages) + dawn::ShaderStage stages) : ObjectBase(device), mStageMask(stages), mLayout(layout) { } @@ -50,7 +50,7 @@ namespace dawn_native { : ObjectBase(device, tag) { } - dawn::ShaderStageBit PipelineBase::GetStageMask() const { + dawn::ShaderStage PipelineBase::GetStageMask() const { ASSERT(!IsError()); return mStageMask; } diff --git a/chromium/third_party/dawn/src/dawn_native/Pipeline.h b/chromium/third_party/dawn/src/dawn_native/Pipeline.h index 209fadecb10..ea989ed7330 100644 --- a/chromium/third_party/dawn/src/dawn_native/Pipeline.h +++ b/chromium/third_party/dawn/src/dawn_native/Pipeline.h @@ -31,20 +31,20 @@ namespace dawn_native { MaybeError ValidatePipelineStageDescriptor(const DeviceBase* device, const PipelineStageDescriptor* descriptor, const PipelineLayoutBase* layout, - ShaderStage stage); + SingleShaderStage stage); class PipelineBase : public ObjectBase { public: - dawn::ShaderStageBit GetStageMask() const; + dawn::ShaderStage GetStageMask() const; PipelineLayoutBase* GetLayout(); const PipelineLayoutBase* GetLayout() const; protected: - PipelineBase(DeviceBase* device, PipelineLayoutBase* layout, dawn::ShaderStageBit stages); + PipelineBase(DeviceBase* device, PipelineLayoutBase* layout, dawn::ShaderStage stages); PipelineBase(DeviceBase* device, ObjectBase::ErrorTag tag); private: - dawn::ShaderStageBit mStageMask; + dawn::ShaderStage mStageMask; Ref<PipelineLayoutBase> mLayout; }; diff --git a/chromium/third_party/dawn/src/dawn_native/PipelineLayout.cpp b/chromium/third_party/dawn/src/dawn_native/PipelineLayout.cpp index ee3b89ae26b..8c2a4296a26 100644 --- a/chromium/third_party/dawn/src/dawn_native/PipelineLayout.cpp +++ b/chromium/third_party/dawn/src/dawn_native/PipelineLayout.cpp @@ -32,9 +32,24 @@ namespace dawn_native { return DAWN_VALIDATION_ERROR("too many bind group layouts"); } + uint32_t totalDynamicUniformBufferCount = 0; + uint32_t totalDynamicStorageBufferCount = 0; for (uint32_t i = 0; i < descriptor->bindGroupLayoutCount; ++i) { DAWN_TRY(device->ValidateObject(descriptor->bindGroupLayouts[i])); + totalDynamicUniformBufferCount += + descriptor->bindGroupLayouts[i]->GetDynamicUniformBufferCount(); + totalDynamicStorageBufferCount += + descriptor->bindGroupLayouts[i]->GetDynamicStorageBufferCount(); } + + if (totalDynamicUniformBufferCount > kMaxDynamicUniformBufferCount) { + return DAWN_VALIDATION_ERROR("too many dynamic uniform buffers in pipeline layout"); + } + + if (totalDynamicStorageBufferCount > kMaxDynamicStorageBufferCount) { + return DAWN_VALIDATION_ERROR("too many dynamic storage buffers in pipeline layout"); + } + return {}; } diff --git a/chromium/third_party/dawn/src/dawn_native/ProgrammablePassEncoder.cpp b/chromium/third_party/dawn/src/dawn_native/ProgrammablePassEncoder.cpp index 4210a13d723..e59eab8ec3e 100644 --- a/chromium/third_party/dawn/src/dawn_native/ProgrammablePassEncoder.cpp +++ b/chromium/third_party/dawn/src/dawn_native/ProgrammablePassEncoder.cpp @@ -75,8 +75,6 @@ namespace dawn_native { uint32_t dynamicOffsetCount, const uint64_t* dynamicOffsets) { mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError { - const BindGroupLayoutBase* layout = group->GetLayout(); - DAWN_TRY(GetDevice()->ValidateObject(group)); if (groupIndex >= kMaxBindGroups) { @@ -84,6 +82,7 @@ namespace dawn_native { } // Dynamic offsets count must match the number required by the layout perfectly. + const BindGroupLayoutBase* layout = group->GetLayout(); if (layout->GetDynamicBufferCount() != dynamicOffsetCount) { return DAWN_VALIDATION_ERROR("dynamicOffset count mismatch"); } diff --git a/chromium/third_party/dawn/src/dawn_native/Queue.cpp b/chromium/third_party/dawn/src/dawn_native/Queue.cpp index 23cc91277f9..46ead116368 100644 --- a/chromium/third_party/dawn/src/dawn_native/Queue.cpp +++ b/chromium/third_party/dawn/src/dawn_native/Queue.cpp @@ -20,6 +20,7 @@ #include "dawn_native/Fence.h" #include "dawn_native/FenceSignalTracker.h" #include "dawn_native/Texture.h" +#include "dawn_platform/tracing/TraceEvent.h" namespace dawn_native { @@ -29,6 +30,8 @@ namespace dawn_native { } void QueueBase::Submit(uint32_t commandCount, CommandBufferBase* const* commands) { + TRACE_EVENT0(GetDevice()->GetPlatform(), TRACE_DISABLED_BY_DEFAULT("gpu.dawn"), + "Queue::Submit"); if (GetDevice()->ConsumedError(ValidateSubmit(commandCount, commands))) { return; } diff --git a/chromium/third_party/dawn/src/dawn_native/RenderBundle.cpp b/chromium/third_party/dawn/src/dawn_native/RenderBundle.cpp new file mode 100644 index 00000000000..9cd08ea0e61 --- /dev/null +++ b/chromium/third_party/dawn/src/dawn_native/RenderBundle.cpp @@ -0,0 +1,61 @@ +// Copyright 2019 The Dawn Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "dawn_native/RenderBundle.h" + +#include "common/BitSetIterator.h" +#include "dawn_native/Commands.h" +#include "dawn_native/Device.h" +#include "dawn_native/RenderBundleEncoder.h" + +namespace dawn_native { + + RenderBundleBase::RenderBundleBase(RenderBundleEncoderBase* encoder, + const RenderBundleDescriptor* descriptor, + AttachmentState* attachmentState, + PassResourceUsage resourceUsage) + : ObjectBase(encoder->GetDevice()), + mCommands(encoder->AcquireCommands()), + mAttachmentState(attachmentState), + mResourceUsage(std::move(resourceUsage)) { + } + + RenderBundleBase::~RenderBundleBase() { + FreeCommands(&mCommands); + } + + // static + RenderBundleBase* RenderBundleBase::MakeError(DeviceBase* device) { + return new RenderBundleBase(device, ObjectBase::kError); + } + + RenderBundleBase::RenderBundleBase(DeviceBase* device, ErrorTag errorTag) + : ObjectBase(device, errorTag) { + } + + CommandIterator* RenderBundleBase::GetCommands() { + return &mCommands; + } + + const AttachmentState* RenderBundleBase::GetAttachmentState() const { + ASSERT(!IsError()); + return mAttachmentState.Get(); + } + + const PassResourceUsage& RenderBundleBase::GetResourceUsage() const { + ASSERT(!IsError()); + return mResourceUsage; + } + +} // namespace dawn_native diff --git a/chromium/third_party/dawn/src/dawn_native/RenderBundle.h b/chromium/third_party/dawn/src/dawn_native/RenderBundle.h new file mode 100644 index 00000000000..26db850e2a7 --- /dev/null +++ b/chromium/third_party/dawn/src/dawn_native/RenderBundle.h @@ -0,0 +1,60 @@ +// Copyright 2019 The Dawn Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef DAWNNATIVE_RENDERBUNDLE_H_ +#define DAWNNATIVE_RENDERBUNDLE_H_ + +#include "common/Constants.h" +#include "dawn_native/AttachmentState.h" +#include "dawn_native/CommandAllocator.h" +#include "dawn_native/Error.h" +#include "dawn_native/ObjectBase.h" +#include "dawn_native/PassResourceUsage.h" + +#include "dawn_native/dawn_platform.h" + +#include <bitset> + +namespace dawn_native { + + struct BeginRenderPassCmd; + struct RenderBundleDescriptor; + class RenderBundleEncoderBase; + + class RenderBundleBase : public ObjectBase { + public: + RenderBundleBase(RenderBundleEncoderBase* encoder, + const RenderBundleDescriptor* descriptor, + AttachmentState* attachmentState, + PassResourceUsage resourceUsage); + ~RenderBundleBase() override; + + static RenderBundleBase* MakeError(DeviceBase* device); + + CommandIterator* GetCommands(); + + const AttachmentState* GetAttachmentState() const; + const PassResourceUsage& GetResourceUsage() const; + + private: + RenderBundleBase(DeviceBase* device, ErrorTag errorTag); + + CommandIterator mCommands; + Ref<AttachmentState> mAttachmentState; + PassResourceUsage mResourceUsage; + }; + +} // namespace dawn_native + +#endif // DAWNNATIVE_RENDERBUNDLE_H_ diff --git a/chromium/third_party/dawn/src/dawn_native/RenderBundleEncoder.cpp b/chromium/third_party/dawn/src/dawn_native/RenderBundleEncoder.cpp new file mode 100644 index 00000000000..8a7e99a58dc --- /dev/null +++ b/chromium/third_party/dawn/src/dawn_native/RenderBundleEncoder.cpp @@ -0,0 +1,126 @@ +// Copyright 2019 The Dawn Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "dawn_native/RenderBundleEncoder.h" + +#include "dawn_native/CommandValidation.h" +#include "dawn_native/Commands.h" +#include "dawn_native/Device.h" +#include "dawn_native/Format.h" +#include "dawn_native/RenderPipeline.h" +#include "dawn_native/ValidationUtils_autogen.h" + +namespace dawn_native { + + MaybeError ValidateColorAttachmentFormat(const DeviceBase* device, + dawn::TextureFormat textureFormat) { + DAWN_TRY(ValidateTextureFormat(textureFormat)); + const Format* format = nullptr; + DAWN_TRY_ASSIGN(format, device->GetInternalFormat(textureFormat)); + if (!format->IsColor() || !format->isRenderable) { + return DAWN_VALIDATION_ERROR( + "The color attachment texture format is not color renderable"); + } + return {}; + } + + MaybeError ValidateDepthStencilAttachmentFormat(const DeviceBase* device, + dawn::TextureFormat textureFormat) { + DAWN_TRY(ValidateTextureFormat(textureFormat)); + const Format* format = nullptr; + DAWN_TRY_ASSIGN(format, device->GetInternalFormat(textureFormat)); + if (!format->HasDepthOrStencil() || !format->isRenderable) { + return DAWN_VALIDATION_ERROR( + "The depth stencil attachment texture format is not a renderable depth/stencil " + "format"); + } + return {}; + } + + MaybeError ValidateRenderBundleEncoderDescriptor( + const DeviceBase* device, + const RenderBundleEncoderDescriptor* descriptor) { + if (!IsValidSampleCount(descriptor->sampleCount)) { + return DAWN_VALIDATION_ERROR("Sample count is not supported"); + } + + if (descriptor->colorFormatsCount > kMaxColorAttachments) { + return DAWN_VALIDATION_ERROR("Color formats count exceeds maximum"); + } + + if (descriptor->colorFormatsCount == 0 && + descriptor->depthStencilFormat == dawn::TextureFormat::Undefined) { + return DAWN_VALIDATION_ERROR("Should have at least one attachment format"); + } + + for (uint32_t i = 0; i < descriptor->colorFormatsCount; ++i) { + DAWN_TRY(ValidateColorAttachmentFormat(device, descriptor->colorFormats[i])); + } + + if (descriptor->depthStencilFormat != dawn::TextureFormat::Undefined) { + DAWN_TRY(ValidateDepthStencilAttachmentFormat(device, descriptor->depthStencilFormat)); + } + + return {}; + } + + RenderBundleEncoderBase::RenderBundleEncoderBase( + DeviceBase* device, + const RenderBundleEncoderDescriptor* descriptor) + : RenderEncoderBase(device, &mEncodingContext), + mEncodingContext(device, this), + mAttachmentState(device->GetOrCreateAttachmentState(descriptor)) { + } + + RenderBundleEncoderBase::RenderBundleEncoderBase(DeviceBase* device, ErrorTag errorTag) + : RenderEncoderBase(device, &mEncodingContext, errorTag), mEncodingContext(device, this) { + } + + // static + RenderBundleEncoderBase* RenderBundleEncoderBase::MakeError(DeviceBase* device) { + return new RenderBundleEncoderBase(device, ObjectBase::kError); + } + + const AttachmentState* RenderBundleEncoderBase::GetAttachmentState() const { + return mAttachmentState.Get(); + } + + CommandIterator RenderBundleEncoderBase::AcquireCommands() { + return mEncodingContext.AcquireCommands(); + } + + RenderBundleBase* RenderBundleEncoderBase::Finish(const RenderBundleDescriptor* descriptor) { + if (GetDevice()->ConsumedError(ValidateFinish(descriptor))) { + return RenderBundleBase::MakeError(GetDevice()); + } + ASSERT(!IsError()); + + return new RenderBundleBase(this, descriptor, mAttachmentState.Get(), + std::move(mResourceUsage)); + } + + MaybeError RenderBundleEncoderBase::ValidateFinish(const RenderBundleDescriptor* descriptor) { + DAWN_TRY(GetDevice()->ValidateObject(this)); + + // Even if Finish() validation fails, calling it will mutate the internal state of the + // encoding context. Subsequent calls to encode commands will generate errors. + DAWN_TRY(mEncodingContext.Finish()); + + CommandIterator* commands = mEncodingContext.GetIterator(); + + DAWN_TRY(ValidateRenderBundle(commands, mAttachmentState.Get(), &mResourceUsage)); + return {}; + } + +} // namespace dawn_native diff --git a/chromium/third_party/dawn/src/dawn_native/RenderBundleEncoder.h b/chromium/third_party/dawn/src/dawn_native/RenderBundleEncoder.h new file mode 100644 index 00000000000..aa322011c4a --- /dev/null +++ b/chromium/third_party/dawn/src/dawn_native/RenderBundleEncoder.h @@ -0,0 +1,53 @@ +// Copyright 2019 The Dawn Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef DAWNNATIVE_RENDERBUNDLEENCODER_H_ +#define DAWNNATIVE_RENDERBUNDLEENCODER_H_ + +#include "dawn_native/AttachmentState.h" +#include "dawn_native/EncodingContext.h" +#include "dawn_native/Error.h" +#include "dawn_native/RenderBundle.h" +#include "dawn_native/RenderEncoderBase.h" + +namespace dawn_native { + + MaybeError ValidateRenderBundleEncoderDescriptor( + const DeviceBase* device, + const RenderBundleEncoderDescriptor* descriptor); + class RenderBundleEncoderBase : public RenderEncoderBase { + public: + RenderBundleEncoderBase(DeviceBase* device, + const RenderBundleEncoderDescriptor* descriptor); + + static RenderBundleEncoderBase* MakeError(DeviceBase* device); + + const AttachmentState* GetAttachmentState() const; + + RenderBundleBase* Finish(const RenderBundleDescriptor* descriptor); + + CommandIterator AcquireCommands(); + + private: + RenderBundleEncoderBase(DeviceBase* device, ErrorTag errorTag); + + MaybeError ValidateFinish(const RenderBundleDescriptor* descriptor); + + EncodingContext mEncodingContext; + Ref<AttachmentState> mAttachmentState; + PassResourceUsage mResourceUsage; + }; +} // namespace dawn_native + +#endif // DAWNNATIVE_RENDERBUNDLEENCODER_H_ diff --git a/chromium/third_party/dawn/src/dawn_native/RenderPassEncoder.cpp b/chromium/third_party/dawn/src/dawn_native/RenderPassEncoder.cpp index 54d5db5f548..27f5df33260 100644 --- a/chromium/third_party/dawn/src/dawn_native/RenderPassEncoder.cpp +++ b/chromium/third_party/dawn/src/dawn_native/RenderPassEncoder.cpp @@ -19,6 +19,7 @@ #include "dawn_native/CommandEncoder.h" #include "dawn_native/Commands.h" #include "dawn_native/Device.h" +#include "dawn_native/RenderBundle.h" #include "dawn_native/RenderPipeline.h" #include <math.h> @@ -130,4 +131,24 @@ namespace dawn_native { }); } + void RenderPassEncoderBase::ExecuteBundles(uint32_t count, + RenderBundleBase* const* renderBundles) { + mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError { + for (uint32_t i = 0; i < count; ++i) { + DAWN_TRY(GetDevice()->ValidateObject(renderBundles[i])); + } + + ExecuteBundlesCmd* cmd = + allocator->Allocate<ExecuteBundlesCmd>(Command::ExecuteBundles); + cmd->count = count; + + Ref<RenderBundleBase>* bundles = allocator->AllocateData<Ref<RenderBundleBase>>(count); + for (uint32_t i = 0; i < count; ++i) { + bundles[i] = renderBundles[i]; + } + + return {}; + }); + } + } // namespace dawn_native diff --git a/chromium/third_party/dawn/src/dawn_native/RenderPassEncoder.h b/chromium/third_party/dawn/src/dawn_native/RenderPassEncoder.h index b9610793dc1..4b7c06db76f 100644 --- a/chromium/third_party/dawn/src/dawn_native/RenderPassEncoder.h +++ b/chromium/third_party/dawn/src/dawn_native/RenderPassEncoder.h @@ -20,10 +20,12 @@ namespace dawn_native { + class RenderBundleBase; + // This is called RenderPassEncoderBase to match the code generator expectations. Note that it // is a pure frontend type to record in its parent CommandEncoder and never has a backend // implementation. - // TODO(cwallez@chromium.org): Remove that generator limitation and rename to ComputePassEncoder + // TODO(cwallez@chromium.org): Remove that generator limitation and rename to RenderPassEncoder class RenderPassEncoderBase : public RenderEncoderBase { public: RenderPassEncoderBase(DeviceBase* device, @@ -45,6 +47,7 @@ namespace dawn_native { float minDepth, float maxDepth); void SetScissorRect(uint32_t x, uint32_t y, uint32_t width, uint32_t height); + void ExecuteBundles(uint32_t count, RenderBundleBase* const* renderBundles); protected: RenderPassEncoderBase(DeviceBase* device, diff --git a/chromium/third_party/dawn/src/dawn_native/RenderPipeline.cpp b/chromium/third_party/dawn/src/dawn_native/RenderPipeline.cpp index 421abf2a45b..1550a26a46b 100644 --- a/chromium/third_party/dawn/src/dawn_native/RenderPipeline.cpp +++ b/chromium/third_party/dawn/src/dawn_native/RenderPipeline.cpp @@ -65,6 +65,11 @@ namespace dawn_native { return DAWN_VALIDATION_ERROR("Setting input stride out of bounds"); } + if (buffer->stride % 4 != 0) { + return DAWN_VALIDATION_ERROR( + "Stride of Vertex buffer needs to be multiple of 4 bytes"); + } + for (uint32_t i = 0; i < buffer->attributeCount; ++i) { DAWN_TRY(ValidateVertexAttributeDescriptor(&buffer->attributes[i], buffer->stride, attributesSetMask)); @@ -267,23 +272,27 @@ namespace dawn_native { DAWN_TRY(device->ValidateObject(descriptor->layout)); - if (descriptor->vertexInput == nullptr) { - return DAWN_VALIDATION_ERROR("Input state must not be null"); + // TODO(crbug.com/dawn/136): Support vertex-only pipelines. + if (descriptor->fragmentStage == nullptr) { + return DAWN_VALIDATION_ERROR("Null fragment stage is not supported (yet)"); } std::bitset<kMaxVertexAttributes> attributesSetMask; - DAWN_TRY(ValidateVertexInputDescriptor(descriptor->vertexInput, &attributesSetMask)); + if (descriptor->vertexInput) { + DAWN_TRY(ValidateVertexInputDescriptor(descriptor->vertexInput, &attributesSetMask)); + } + DAWN_TRY(ValidatePrimitiveTopology(descriptor->primitiveTopology)); - DAWN_TRY(ValidatePipelineStageDescriptor(device, descriptor->vertexStage, - descriptor->layout, ShaderStage::Vertex)); + DAWN_TRY(ValidatePipelineStageDescriptor(device, &descriptor->vertexStage, + descriptor->layout, SingleShaderStage::Vertex)); DAWN_TRY(ValidatePipelineStageDescriptor(device, descriptor->fragmentStage, - descriptor->layout, ShaderStage::Fragment)); + descriptor->layout, SingleShaderStage::Fragment)); if (descriptor->rasterizationState) { DAWN_TRY(ValidateRasterizationStateDescriptor(descriptor->rasterizationState)); } - if ((descriptor->vertexStage->module->GetUsedVertexAttributes() & ~attributesSetMask) + if ((descriptor->vertexStage.module->GetUsedVertexAttributes() & ~attributesSetMask) .any()) { return DAWN_VALIDATION_ERROR( "Pipeline vertex stage uses inputs not in the input state"); @@ -347,18 +356,22 @@ namespace dawn_native { bool blueprint) : PipelineBase(device, descriptor->layout, - dawn::ShaderStageBit::Vertex | dawn::ShaderStageBit::Fragment), - mVertexInput(*descriptor->vertexInput), - mHasDepthStencilAttachment(descriptor->depthStencilState != nullptr), + dawn::ShaderStage::Vertex | dawn::ShaderStage::Fragment), + mAttachmentState(device->GetOrCreateAttachmentState(descriptor)), mPrimitiveTopology(descriptor->primitiveTopology), - mSampleCount(descriptor->sampleCount), mSampleMask(descriptor->sampleMask), mAlphaToCoverageEnabled(descriptor->alphaToCoverageEnabled), - mVertexModule(descriptor->vertexStage->module), - mVertexEntryPoint(descriptor->vertexStage->entryPoint), + mVertexModule(descriptor->vertexStage.module), + mVertexEntryPoint(descriptor->vertexStage.entryPoint), mFragmentModule(descriptor->fragmentStage->module), mFragmentEntryPoint(descriptor->fragmentStage->entryPoint), mIsBlueprint(blueprint) { + if (descriptor->vertexInput != nullptr) { + mVertexInput = *descriptor->vertexInput; + } else { + mVertexInput = VertexInputDescriptor(); + } + for (uint32_t slot = 0; slot < mVertexInput.bufferCount; ++slot) { if (mVertexInput.buffers[slot].attributeCount == 0) { continue; @@ -385,7 +398,7 @@ namespace dawn_native { mRasterizationState = RasterizationStateDescriptor(); } - if (mHasDepthStencilAttachment) { + if (mAttachmentState->HasDepthStencilAttachment()) { mDepthStencilState = *descriptor->depthStencilState; } else { // These default values below are useful for backends to fill information. @@ -406,8 +419,7 @@ namespace dawn_native { mDepthStencilState.stencilWriteMask = 0xff; } - for (uint32_t i = 0; i < descriptor->colorStateCount; ++i) { - mColorAttachmentsSet.set(i); + for (uint32_t i : IterateBitSet(mAttachmentState->GetColorAttachmentsMask())) { mColorStates[i] = *descriptor->colorStates[i]; } @@ -487,12 +499,12 @@ namespace dawn_native { std::bitset<kMaxColorAttachments> RenderPipelineBase::GetColorAttachmentsMask() const { ASSERT(!IsError()); - return mColorAttachmentsSet; + return mAttachmentState->GetColorAttachmentsMask(); } bool RenderPipelineBase::HasDepthStencilAttachment() const { ASSERT(!IsError()); - return mHasDepthStencilAttachment; + return mAttachmentState->HasDepthStencilAttachment(); } dawn::TextureFormat RenderPipelineBase::GetColorAttachmentFormat(uint32_t attachment) const { @@ -502,52 +514,19 @@ namespace dawn_native { dawn::TextureFormat RenderPipelineBase::GetDepthStencilFormat() const { ASSERT(!IsError()); - ASSERT(mHasDepthStencilAttachment); + ASSERT(mAttachmentState->HasDepthStencilAttachment()); return mDepthStencilState.format; } uint32_t RenderPipelineBase::GetSampleCount() const { ASSERT(!IsError()); - return mSampleCount; + return mAttachmentState->GetSampleCount(); } - MaybeError RenderPipelineBase::ValidateCompatibleWith( - const BeginRenderPassCmd* renderPass) const { + const AttachmentState* RenderPipelineBase::GetAttachmentState() const { ASSERT(!IsError()); - // TODO(cwallez@chromium.org): This is called on every SetPipeline command. Optimize it for - // example by caching some "attachment compatibility" object that would make the - // compatibility check a single pointer comparison. - - if (renderPass->colorAttachmentsSet != mColorAttachmentsSet) { - return DAWN_VALIDATION_ERROR( - "Pipeline doesn't have same color attachments set as renderPass"); - } - - for (uint32_t i : IterateBitSet(mColorAttachmentsSet)) { - if (renderPass->colorAttachments[i].view->GetFormat().format != - mColorStates[i].format) { - return DAWN_VALIDATION_ERROR( - "Pipeline color attachment format doesn't match renderPass"); - } - } - if (renderPass->hasDepthStencilAttachment != mHasDepthStencilAttachment) { - return DAWN_VALIDATION_ERROR( - "Pipeline depth stencil attachment doesn't match renderPass"); - } - - if (mHasDepthStencilAttachment && - (renderPass->depthStencilAttachment.view->GetFormat().format != - mDepthStencilState.format)) { - return DAWN_VALIDATION_ERROR( - "Pipeline depth stencil attachment format doesn't match renderPass"); - } - - if (renderPass->sampleCount != mSampleCount) { - return DAWN_VALIDATION_ERROR("Pipeline sample count doesn't match renderPass"); - } - - return {}; + return mAttachmentState.Get(); } std::bitset<kMaxVertexAttributes> RenderPipelineBase::GetAttributesUsingInput( @@ -564,20 +543,23 @@ namespace dawn_native { HashCombine(&hash, pipeline->mVertexModule.Get(), pipeline->mFragmentEntryPoint); HashCombine(&hash, pipeline->mFragmentModule.Get(), pipeline->mFragmentEntryPoint); + // Hierarchically hash the attachment state. + // It contains the attachments set, texture formats, and sample count. + HashCombine(&hash, pipeline->mAttachmentState.Get()); + // Hash attachments - HashCombine(&hash, pipeline->mColorAttachmentsSet); - for (uint32_t i : IterateBitSet(pipeline->mColorAttachmentsSet)) { + for (uint32_t i : IterateBitSet(pipeline->mAttachmentState->GetColorAttachmentsMask())) { const ColorStateDescriptor& desc = *pipeline->GetColorStateDescriptor(i); - HashCombine(&hash, desc.format, desc.writeMask); + HashCombine(&hash, desc.writeMask); HashCombine(&hash, desc.colorBlend.operation, desc.colorBlend.srcFactor, desc.colorBlend.dstFactor); HashCombine(&hash, desc.alphaBlend.operation, desc.alphaBlend.srcFactor, desc.alphaBlend.dstFactor); } - if (pipeline->mHasDepthStencilAttachment) { + if (pipeline->mAttachmentState->HasDepthStencilAttachment()) { const DepthStencilStateDescriptor& desc = pipeline->mDepthStencilState; - HashCombine(&hash, desc.format, desc.depthWriteEnabled, desc.depthCompare); + HashCombine(&hash, desc.depthWriteEnabled, desc.depthCompare); HashCombine(&hash, desc.stencilReadMask, desc.stencilWriteMask); HashCombine(&hash, desc.stencilFront.compare, desc.stencilFront.failOp, desc.stencilFront.depthFailOp, desc.stencilFront.passOp); @@ -608,8 +590,8 @@ namespace dawn_native { } // Hash other state - HashCombine(&hash, pipeline->mSampleCount, pipeline->mPrimitiveTopology, - pipeline->mSampleMask, pipeline->mAlphaToCoverageEnabled); + HashCombine(&hash, pipeline->mPrimitiveTopology, pipeline->mSampleMask, + pipeline->mAlphaToCoverageEnabled); return hash; } @@ -624,16 +606,16 @@ namespace dawn_native { return false; } - // Check attachments - if (a->mColorAttachmentsSet != b->mColorAttachmentsSet || - a->mHasDepthStencilAttachment != b->mHasDepthStencilAttachment) { + // Check the attachment state. + // It contains the attachments set, texture formats, and sample count. + if (a->mAttachmentState.Get() != b->mAttachmentState.Get()) { return false; } - for (uint32_t i : IterateBitSet(a->mColorAttachmentsSet)) { + for (uint32_t i : IterateBitSet(a->mAttachmentState->GetColorAttachmentsMask())) { const ColorStateDescriptor& descA = *a->GetColorStateDescriptor(i); const ColorStateDescriptor& descB = *b->GetColorStateDescriptor(i); - if (descA.format != descB.format || descA.writeMask != descB.writeMask) { + if (descA.writeMask != descB.writeMask) { return false; } if (descA.colorBlend.operation != descB.colorBlend.operation || @@ -648,11 +630,10 @@ namespace dawn_native { } } - if (a->mHasDepthStencilAttachment) { + if (a->mAttachmentState->HasDepthStencilAttachment()) { const DepthStencilStateDescriptor& descA = a->mDepthStencilState; const DepthStencilStateDescriptor& descB = b->mDepthStencilState; - if (descA.format != descB.format || - descA.depthWriteEnabled != descB.depthWriteEnabled || + if (descA.depthWriteEnabled != descB.depthWriteEnabled || descA.depthCompare != descB.depthCompare) { return false; } @@ -720,8 +701,7 @@ namespace dawn_native { } // Check other state - if (a->mSampleCount != b->mSampleCount || a->mPrimitiveTopology != b->mPrimitiveTopology || - a->mSampleMask != b->mSampleMask || + if (a->mPrimitiveTopology != b->mPrimitiveTopology || a->mSampleMask != b->mSampleMask || a->mAlphaToCoverageEnabled != b->mAlphaToCoverageEnabled) { return false; } diff --git a/chromium/third_party/dawn/src/dawn_native/RenderPipeline.h b/chromium/third_party/dawn/src/dawn_native/RenderPipeline.h index dfc46f75ab7..490d178563d 100644 --- a/chromium/third_party/dawn/src/dawn_native/RenderPipeline.h +++ b/chromium/third_party/dawn/src/dawn_native/RenderPipeline.h @@ -15,6 +15,7 @@ #ifndef DAWNNATIVE_RENDERPIPELINE_H_ #define DAWNNATIVE_RENDERPIPELINE_H_ +#include "dawn_native/AttachmentState.h" #include "dawn_native/Pipeline.h" #include "dawn_native/dawn_platform.h" @@ -27,6 +28,7 @@ namespace dawn_native { struct BeginRenderPassCmd; class DeviceBase; + class RenderBundleEncoderBase; MaybeError ValidateRenderPipelineDescriptor(const DeviceBase* device, const RenderPipelineDescriptor* descriptor); @@ -77,9 +79,8 @@ namespace dawn_native { dawn::TextureFormat GetDepthStencilFormat() const; uint32_t GetSampleCount() const; - // A pipeline can be used in a render pass if its attachment info matches the actual - // attachments in the render pass. This returns whether it is the case. - MaybeError ValidateCompatibleWith(const BeginRenderPassCmd* renderPassCmd) const; + const AttachmentState* GetAttachmentState() const; + std::bitset<kMaxVertexAttributes> GetAttributesUsingInput(uint32_t slot) const; std::array<std::bitset<kMaxVertexAttributes>, kMaxVertexBuffers> attributesUsingInput; @@ -102,15 +103,13 @@ namespace dawn_native { std::array<VertexBufferInfo, kMaxVertexBuffers> mInputInfos; // Attachments - bool mHasDepthStencilAttachment = false; + Ref<AttachmentState> mAttachmentState; DepthStencilStateDescriptor mDepthStencilState; - std::bitset<kMaxColorAttachments> mColorAttachmentsSet; std::array<ColorStateDescriptor, kMaxColorAttachments> mColorStates; // Other state dawn::PrimitiveTopology mPrimitiveTopology; RasterizationStateDescriptor mRasterizationState; - uint32_t mSampleCount; uint32_t mSampleMask; bool mAlphaToCoverageEnabled; diff --git a/chromium/third_party/dawn/src/dawn_native/ResourceHeap.h b/chromium/third_party/dawn/src/dawn_native/ResourceHeap.h new file mode 100644 index 00000000000..c4d67070329 --- /dev/null +++ b/chromium/third_party/dawn/src/dawn_native/ResourceHeap.h @@ -0,0 +1,31 @@ +// Copyright 2019 The Dawn Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef DAWNNATIVE_RESOURCEHEAP_H_ +#define DAWNNATIVE_RESOURCEHEAP_H_ + +#include "dawn_native/Error.h" + +namespace dawn_native { + + // Wrapper for a resource backed by a heap. + class ResourceHeapBase { + protected: + ResourceHeapBase() = default; + virtual ~ResourceHeapBase() = default; + }; + +} // namespace dawn_native + +#endif // DAWNNATIVE_RESOURCEHEAP_H_
\ No newline at end of file diff --git a/chromium/third_party/dawn/src/dawn_native/ResourceMemoryAllocation.cpp b/chromium/third_party/dawn/src/dawn_native/ResourceMemoryAllocation.cpp new file mode 100644 index 00000000000..1ace4d48fac --- /dev/null +++ b/chromium/third_party/dawn/src/dawn_native/ResourceMemoryAllocation.cpp @@ -0,0 +1,53 @@ +// Copyright 2019 The Dawn Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "dawn_native/ResourceMemoryAllocation.h" +#include "common/Assert.h" + +#include <limits> + +namespace dawn_native { + + static constexpr uint64_t INVALID_OFFSET = std::numeric_limits<uint64_t>::max(); + + ResourceMemoryAllocation::ResourceMemoryAllocation() + : mMethod(AllocationMethod::kInvalid), mOffset(INVALID_OFFSET), mResourceHeap(nullptr) { + } + + ResourceMemoryAllocation::ResourceMemoryAllocation(uint64_t offset, + ResourceHeapBase* resourceHeap, + AllocationMethod method) + : mMethod(method), mOffset(offset), mResourceHeap(resourceHeap) { + } + + ResourceHeapBase* ResourceMemoryAllocation::GetResourceHeap() const { + ASSERT(mMethod != AllocationMethod::kInvalid); + return mResourceHeap; + } + + uint64_t ResourceMemoryAllocation::GetOffset() const { + ASSERT(mMethod != AllocationMethod::kInvalid); + return mOffset; + } + + AllocationMethod ResourceMemoryAllocation::GetAllocationMethod() const { + ASSERT(mMethod != AllocationMethod::kInvalid); + return mMethod; + } + + void ResourceMemoryAllocation::Invalidate() { + mResourceHeap = nullptr; + mMethod = AllocationMethod::kInvalid; + } +} // namespace dawn_native
\ No newline at end of file diff --git a/chromium/third_party/dawn/src/dawn_native/ResourceMemoryAllocation.h b/chromium/third_party/dawn/src/dawn_native/ResourceMemoryAllocation.h new file mode 100644 index 00000000000..4e69a2290ef --- /dev/null +++ b/chromium/third_party/dawn/src/dawn_native/ResourceMemoryAllocation.h @@ -0,0 +1,60 @@ +// Copyright 2018 The Dawn Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef DAWNNATIVE_RESOURCEMEMORYALLOCATION_H_ +#define DAWNNATIVE_RESOURCEMEMORYALLOCATION_H_ + +#include <cstdint> + +namespace dawn_native { + + class ResourceHeapBase; + + // Allocation method determines how memory was sub-divided. + // Used by the device to get the allocator that was responsible for the allocation. + enum class AllocationMethod { + + // Memory not sub-divided. + kDirect, + + // Memory sub-divided using one or more blocks of various sizes. + kSubAllocated, + + // Memory not allocated or freed. + kInvalid + }; + + // Handle into a resource heap pool. + class ResourceMemoryAllocation { + public: + ResourceMemoryAllocation(); + ResourceMemoryAllocation(uint64_t offset, + ResourceHeapBase* resourceHeap, + AllocationMethod method); + ~ResourceMemoryAllocation() = default; + + ResourceHeapBase* GetResourceHeap() const; + uint64_t GetOffset() const; + AllocationMethod GetAllocationMethod() const; + + void Invalidate(); + + private: + AllocationMethod mMethod; + uint64_t mOffset; + ResourceHeapBase* mResourceHeap; + }; +} // namespace dawn_native + +#endif // DAWNNATIVE_RESOURCEMEMORYALLOCATION_H_
\ No newline at end of file diff --git a/chromium/third_party/dawn/src/dawn_native/ShaderModule.cpp b/chromium/third_party/dawn/src/dawn_native/ShaderModule.cpp index 2ce8f92e62a..ccb6e32a7b5 100644 --- a/chromium/third_party/dawn/src/dawn_native/ShaderModule.cpp +++ b/chromium/third_party/dawn/src/dawn_native/ShaderModule.cpp @@ -20,8 +20,8 @@ #include "dawn_native/Pipeline.h" #include "dawn_native/PipelineLayout.h" -#include <spirv-cross/spirv_cross.hpp> #include <spirv-tools/libspirv.hpp> +#include <spirv_cross.hpp> #include <sstream> @@ -102,20 +102,21 @@ namespace dawn_native { switch (compiler.get_execution_model()) { case spv::ExecutionModelVertex: - mExecutionModel = ShaderStage::Vertex; + mExecutionModel = SingleShaderStage::Vertex; break; case spv::ExecutionModelFragment: - mExecutionModel = ShaderStage::Fragment; + mExecutionModel = SingleShaderStage::Fragment; break; case spv::ExecutionModelGLCompute: - mExecutionModel = ShaderStage::Compute; + mExecutionModel = SingleShaderStage::Compute; break; default: UNREACHABLE(); } if (resources.push_constant_buffers.size() > 0) { - GetDevice()->HandleError("Push constants aren't supported."); + GetDevice()->HandleError(dawn::ErrorType::Validation, + "Push constants aren't supported."); } // Fill in bindingInfo with the SPIRV bindings @@ -132,7 +133,8 @@ namespace dawn_native { uint32_t set = compiler.get_decoration(resource.id, spv::DecorationDescriptorSet); if (binding >= kMaxBindingsPerGroup || set >= kMaxBindGroups) { - GetDevice()->HandleError("Binding over limits in the SPIRV"); + GetDevice()->HandleError(dawn::ErrorType::Validation, + "Binding over limits in the SPIRV"); continue; } @@ -153,13 +155,14 @@ namespace dawn_native { dawn::BindingType::StorageBuffer); // Extract the vertex attributes - if (mExecutionModel == ShaderStage::Vertex) { + if (mExecutionModel == SingleShaderStage::Vertex) { for (const auto& attrib : resources.stage_inputs) { ASSERT(compiler.get_decoration_bitset(attrib.id).get(spv::DecorationLocation)); uint32_t location = compiler.get_decoration(attrib.id, spv::DecorationLocation); if (location >= kMaxVertexAttributes) { - device->HandleError("Attribute location over limits in the SPIRV"); + device->HandleError(dawn::ErrorType::Validation, + "Attribute location over limits in the SPIRV"); return; } @@ -170,18 +173,20 @@ namespace dawn_native { // all the location 0, causing a compile error. for (const auto& attrib : resources.stage_outputs) { if (!compiler.get_decoration_bitset(attrib.id).get(spv::DecorationLocation)) { - device->HandleError("Need location qualifier on vertex output"); + device->HandleError(dawn::ErrorType::Validation, + "Need location qualifier on vertex output"); return; } } } - if (mExecutionModel == ShaderStage::Fragment) { + if (mExecutionModel == SingleShaderStage::Fragment) { // Without a location qualifier on vertex inputs, spirv_cross::CompilerMSL gives them // all the location 0, causing a compile error. for (const auto& attrib : resources.stage_inputs) { if (!compiler.get_decoration_bitset(attrib.id).get(spv::DecorationLocation)) { - device->HandleError("Need location qualifier on fragment input"); + device->HandleError(dawn::ErrorType::Validation, + "Need location qualifier on fragment input"); return; } } @@ -198,7 +203,7 @@ namespace dawn_native { return mUsedVertexAttributes; } - ShaderStage ShaderModuleBase::GetExecutionModel() const { + SingleShaderStage ShaderModuleBase::GetExecutionModel() const { ASSERT(!IsError()); return mExecutionModel; } diff --git a/chromium/third_party/dawn/src/dawn_native/ShaderModule.h b/chromium/third_party/dawn/src/dawn_native/ShaderModule.h index 6bc53db91e8..35c90207c44 100644 --- a/chromium/third_party/dawn/src/dawn_native/ShaderModule.h +++ b/chromium/third_party/dawn/src/dawn_native/ShaderModule.h @@ -59,7 +59,7 @@ namespace dawn_native { const ModuleBindingInfo& GetBindingInfo() const; const std::bitset<kMaxVertexAttributes>& GetUsedVertexAttributes() const; - ShaderStage GetExecutionModel() const; + SingleShaderStage GetExecutionModel() const; bool IsCompatibleWithPipelineLayout(const PipelineLayoutBase* layout); @@ -83,7 +83,7 @@ namespace dawn_native { ModuleBindingInfo mBindingInfo; std::bitset<kMaxVertexAttributes> mUsedVertexAttributes; - ShaderStage mExecutionModel; + SingleShaderStage mExecutionModel; }; } // namespace dawn_native diff --git a/chromium/third_party/dawn/src/dawn_native/SwapChain.cpp b/chromium/third_party/dawn/src/dawn_native/SwapChain.cpp index 3151c98de34..d5f685a948d 100644 --- a/chromium/third_party/dawn/src/dawn_native/SwapChain.cpp +++ b/chromium/third_party/dawn/src/dawn_native/SwapChain.cpp @@ -81,7 +81,7 @@ namespace dawn_native { } void SwapChainBase::Configure(dawn::TextureFormat format, - dawn::TextureUsageBit allowedUsage, + dawn::TextureUsage allowedUsage, uint32_t width, uint32_t height) { if (GetDevice()->ConsumedError(ValidateConfigure(format, allowedUsage, width, height))) { @@ -89,14 +89,14 @@ namespace dawn_native { } ASSERT(!IsError()); - allowedUsage |= dawn::TextureUsageBit::Present; + allowedUsage |= dawn::TextureUsage::Present; mFormat = format; mAllowedUsage = allowedUsage; mWidth = width; mHeight = height; mImplementation.Configure(mImplementation.userData, static_cast<DawnTextureFormat>(format), - static_cast<DawnTextureUsageBit>(allowedUsage), width, height); + static_cast<DawnTextureUsage>(allowedUsage), width, height); } TextureBase* SwapChainBase::GetNextTexture() { @@ -138,12 +138,12 @@ namespace dawn_native { } MaybeError SwapChainBase::ValidateConfigure(dawn::TextureFormat format, - dawn::TextureUsageBit allowedUsage, + dawn::TextureUsage allowedUsage, uint32_t width, uint32_t height) const { DAWN_TRY(GetDevice()->ValidateObject(this)); - DAWN_TRY(ValidateTextureUsageBit(allowedUsage)); + DAWN_TRY(ValidateTextureUsage(allowedUsage)); DAWN_TRY(ValidateTextureFormat(format)); if (width == 0 || height == 0) { diff --git a/chromium/third_party/dawn/src/dawn_native/SwapChain.h b/chromium/third_party/dawn/src/dawn_native/SwapChain.h index c8479c6a157..8b0e9fdb5ab 100644 --- a/chromium/third_party/dawn/src/dawn_native/SwapChain.h +++ b/chromium/third_party/dawn/src/dawn_native/SwapChain.h @@ -36,7 +36,7 @@ namespace dawn_native { // Dawn API void Configure(dawn::TextureFormat format, - dawn::TextureUsageBit allowedUsage, + dawn::TextureUsage allowedUsage, uint32_t width, uint32_t height); TextureBase* GetNextTexture(); @@ -51,7 +51,7 @@ namespace dawn_native { private: MaybeError ValidateConfigure(dawn::TextureFormat format, - dawn::TextureUsageBit allowedUsage, + dawn::TextureUsage allowedUsage, uint32_t width, uint32_t height) const; MaybeError ValidateGetNextTexture() const; @@ -59,7 +59,7 @@ namespace dawn_native { DawnSwapChainImplementation mImplementation = {}; dawn::TextureFormat mFormat = {}; - dawn::TextureUsageBit mAllowedUsage; + dawn::TextureUsage mAllowedUsage; uint32_t mWidth = 0; uint32_t mHeight = 0; TextureBase* mLastNextTexture = nullptr; diff --git a/chromium/third_party/dawn/src/dawn_native/Texture.cpp b/chromium/third_party/dawn/src/dawn_native/Texture.cpp index 224a10db344..f6370a86832 100644 --- a/chromium/third_party/dawn/src/dawn_native/Texture.cpp +++ b/chromium/third_party/dawn/src/dawn_native/Texture.cpp @@ -139,30 +139,6 @@ namespace dawn_native { return {}; } - TextureViewDescriptor MakeDefaultTextureViewDescriptor(const TextureBase* texture) { - TextureViewDescriptor descriptor; - descriptor.format = texture->GetFormat().format; - descriptor.baseArrayLayer = 0; - descriptor.arrayLayerCount = texture->GetArrayLayers(); - descriptor.baseMipLevel = 0; - descriptor.mipLevelCount = texture->GetNumMipLevels(); - - // TODO(jiawei.shao@intel.com): support all texture dimensions. - switch (texture->GetDimension()) { - case dawn::TextureDimension::e2D: - if (texture->GetArrayLayers() == 1u) { - descriptor.dimension = dawn::TextureViewDimension::e2D; - } else { - descriptor.dimension = dawn::TextureViewDimension::e2DArray; - } - break; - default: - UNREACHABLE(); - } - - return descriptor; - } - MaybeError ValidateTextureSize(const TextureDescriptor* descriptor, const Format* format) { ASSERT(descriptor->size.width != 0 && descriptor->size.height != 0); @@ -181,23 +157,23 @@ namespace dawn_native { } MaybeError ValidateTextureUsage(const TextureDescriptor* descriptor, const Format* format) { - DAWN_TRY(ValidateTextureUsageBit(descriptor->usage)); + DAWN_TRY(dawn_native::ValidateTextureUsage(descriptor->usage)); - constexpr dawn::TextureUsageBit kValidCompressedUsages = - dawn::TextureUsageBit::Sampled | dawn::TextureUsageBit::CopySrc | - dawn::TextureUsageBit::CopyDst; + constexpr dawn::TextureUsage kValidCompressedUsages = dawn::TextureUsage::Sampled | + dawn::TextureUsage::CopySrc | + dawn::TextureUsage::CopyDst; if (format->isCompressed && (descriptor->usage & (~kValidCompressedUsages))) { return DAWN_VALIDATION_ERROR( "Compressed texture format is incompatible with the texture usage"); } if (!format->isRenderable && - (descriptor->usage & dawn::TextureUsageBit::OutputAttachment)) { + (descriptor->usage & dawn::TextureUsage::OutputAttachment)) { return DAWN_VALIDATION_ERROR( "Non-renderable format used with OutputAttachment usage"); } - if (descriptor->usage & dawn::TextureUsageBit::Storage) { + if (descriptor->usage & dawn::TextureUsage::Storage) { return DAWN_VALIDATION_ERROR("storage textures aren't supported (yet)"); } @@ -208,6 +184,9 @@ namespace dawn_native { MaybeError ValidateTextureDescriptor(const DeviceBase* device, const TextureDescriptor* descriptor) { + if (descriptor == nullptr) { + return DAWN_VALIDATION_ERROR("Texture descriptor is nullptr"); + } if (descriptor->nextInChain != nullptr) { return DAWN_VALIDATION_ERROR("nextInChain must be nullptr"); } @@ -235,14 +214,15 @@ namespace dawn_native { return {}; } - MaybeError ValidateTextureViewDescriptor(const DeviceBase* device, - const TextureBase* texture, + MaybeError ValidateTextureViewDescriptor(const TextureBase* texture, const TextureViewDescriptor* descriptor) { if (descriptor->nextInChain != nullptr) { return DAWN_VALIDATION_ERROR("nextInChain must be nullptr"); } - DAWN_TRY(device->ValidateObject(texture)); + // Parent texture should have been already validated. + ASSERT(texture); + ASSERT(!texture->IsError()); if (texture->GetTextureState() == TextureBase::TextureState::Destroyed) { return DAWN_VALIDATION_ERROR("Destroyed texture used to create texture view"); } @@ -276,6 +256,53 @@ namespace dawn_native { return {}; } + TextureViewDescriptor GetTextureViewDescriptorWithDefaults( + const TextureBase* texture, + const TextureViewDescriptor* descriptor) { + ASSERT(texture); + + TextureViewDescriptor desc = {}; + if (descriptor) { + desc = *descriptor; + } + + // The default value for the view dimension depends on the texture's dimension with a + // special case for 2DArray being chosen automatically if arrayLayerCount is unspecified. + if (desc.dimension == dawn::TextureViewDimension::Undefined) { + switch (texture->GetDimension()) { + case dawn::TextureDimension::e1D: + desc.dimension = dawn::TextureViewDimension::e1D; + break; + + case dawn::TextureDimension::e2D: + if (texture->GetArrayLayers() > 1u && desc.arrayLayerCount == 0) { + desc.dimension = dawn::TextureViewDimension::e2DArray; + } else { + desc.dimension = dawn::TextureViewDimension::e2D; + } + break; + + case dawn::TextureDimension::e3D: + desc.dimension = dawn::TextureViewDimension::e3D; + break; + + default: + UNREACHABLE(); + } + } + + if (desc.format == dawn::TextureFormat::Undefined) { + desc.format = texture->GetFormat().format; + } + if (desc.arrayLayerCount == 0) { + desc.arrayLayerCount = texture->GetArrayLayers() - desc.baseArrayLayer; + } + if (desc.mipLevelCount == 0) { + desc.mipLevelCount = texture->GetNumMipLevels() - desc.baseMipLevel; + } + return desc; + } + bool IsValidSampleCount(uint32_t sampleCount) { switch (sampleCount) { case 1: @@ -343,7 +370,7 @@ namespace dawn_native { ASSERT(!IsError()); return mSampleCount; } - dawn::TextureUsageBit TextureBase::GetUsage() const { + dawn::TextureUsage TextureBase::GetUsage() const { ASSERT(!IsError()); return mUsage; } @@ -432,16 +459,6 @@ namespace dawn_native { return extent; } - TextureViewBase* TextureBase::CreateDefaultView() { - TextureViewDescriptor descriptor = {}; - - if (!IsError()) { - descriptor = MakeDefaultTextureViewDescriptor(this); - } - - return GetDevice()->CreateTextureView(this, &descriptor); - } - TextureViewBase* TextureBase::CreateView(const TextureViewDescriptor* descriptor) { return GetDevice()->CreateTextureView(this, descriptor); } diff --git a/chromium/third_party/dawn/src/dawn_native/Texture.h b/chromium/third_party/dawn/src/dawn_native/Texture.h index 066a7d739c1..6e26f997c83 100644 --- a/chromium/third_party/dawn/src/dawn_native/Texture.h +++ b/chromium/third_party/dawn/src/dawn_native/Texture.h @@ -26,24 +26,25 @@ namespace dawn_native { MaybeError ValidateTextureDescriptor(const DeviceBase* device, const TextureDescriptor* descriptor); - MaybeError ValidateTextureViewDescriptor(const DeviceBase* device, - const TextureBase* texture, + MaybeError ValidateTextureViewDescriptor(const TextureBase* texture, const TextureViewDescriptor* descriptor); + TextureViewDescriptor GetTextureViewDescriptorWithDefaults( + const TextureBase* texture, + const TextureViewDescriptor* descriptor); bool IsValidSampleCount(uint32_t sampleCount); - static constexpr dawn::TextureUsageBit kReadOnlyTextureUsages = dawn::TextureUsageBit::CopySrc | - dawn::TextureUsageBit::Sampled | - dawn::TextureUsageBit::Present; + static constexpr dawn::TextureUsage kReadOnlyTextureUsages = + dawn::TextureUsage::CopySrc | dawn::TextureUsage::Sampled | dawn::TextureUsage::Present; - static constexpr dawn::TextureUsageBit kWritableTextureUsages = - dawn::TextureUsageBit::CopyDst | dawn::TextureUsageBit::Storage | - dawn::TextureUsageBit::OutputAttachment; + static constexpr dawn::TextureUsage kWritableTextureUsages = + dawn::TextureUsage::CopyDst | dawn::TextureUsage::Storage | + dawn::TextureUsage::OutputAttachment; class TextureBase : public ObjectBase { public: enum class TextureState { OwnedInternal, OwnedExternal, Destroyed }; - + enum class ClearValue { Zero, NonZero }; TextureBase(DeviceBase* device, const TextureDescriptor* descriptor, TextureState state); static TextureBase* MakeError(DeviceBase* device); @@ -54,7 +55,7 @@ namespace dawn_native { uint32_t GetArrayLayers() const; uint32_t GetNumMipLevels() const; uint32_t GetSampleCount() const; - dawn::TextureUsageBit GetUsage() const; + dawn::TextureUsage GetUsage() const; TextureState GetTextureState() const; uint32_t GetSubresourceIndex(uint32_t mipLevel, uint32_t arraySlice) const; bool IsSubresourceContentInitialized(uint32_t baseMipLevel, @@ -79,7 +80,6 @@ namespace dawn_native { Extent3D GetMipLevelVirtualSize(uint32_t level) const; // Dawn API - TextureViewBase* CreateDefaultView(); TextureViewBase* CreateView(const TextureViewDescriptor* descriptor); void Destroy(); @@ -98,7 +98,7 @@ namespace dawn_native { uint32_t mArrayLayerCount; uint32_t mMipLevelCount; uint32_t mSampleCount; - dawn::TextureUsageBit mUsage = dawn::TextureUsageBit::None; + dawn::TextureUsage mUsage = dawn::TextureUsage::None; TextureState mState; // TODO(natlee@microsoft.com): Use a more optimized data structure to save space diff --git a/chromium/third_party/dawn/src/dawn_native/ToBackend.h b/chromium/third_party/dawn/src/dawn_native/ToBackend.h index 4f11fd45ae1..b9940aba2b6 100644 --- a/chromium/third_party/dawn/src/dawn_native/ToBackend.h +++ b/chromium/third_party/dawn/src/dawn_native/ToBackend.h @@ -74,6 +74,11 @@ namespace dawn_native { }; template <typename BackendTraits> + struct ToBackendTraits<ResourceHeapBase, BackendTraits> { + using BackendType = typename BackendTraits::ResourceHeapType; + }; + + template <typename BackendTraits> struct ToBackendTraits<SamplerBase, BackendTraits> { using BackendType = typename BackendTraits::SamplerType; }; diff --git a/chromium/third_party/dawn/src/dawn_native/Toggles.cpp b/chromium/third_party/dawn/src/dawn_native/Toggles.cpp new file mode 100644 index 00000000000..bbb69a328a7 --- /dev/null +++ b/chromium/third_party/dawn/src/dawn_native/Toggles.cpp @@ -0,0 +1,144 @@ +// Copyright 2019 The Dawn Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include <array> + +#include "common/Assert.h" +#include "common/BitSetIterator.h" +#include "dawn_native/Toggles.h" + +namespace dawn_native { + namespace { + + struct ToggleEnumAndInfo { + Toggle toggle; + ToggleInfo info; + }; + + using ToggleEnumAndInfoList = + std::array<ToggleEnumAndInfo, static_cast<size_t>(Toggle::EnumCount)>; + + static constexpr ToggleEnumAndInfoList kToggleNameAndInfoList = { + {{Toggle::EmulateStoreAndMSAAResolve, + {"emulate_store_and_msaa_resolve", + "Emulate storing into multisampled color attachments and doing MSAA resolve " + "simultaneously. This workaround is enabled by default on the Metal drivers that do " + "not support MTLStoreActionStoreAndMultisampleResolve. To support StoreOp::Store on " + "those platforms, we should do MSAA resolve in another render pass after ending the " + "previous one.", + "https://bugs.chromium.org/p/dawn/issues/detail?id=56"}}, + {Toggle::NonzeroClearResourcesOnCreationForTesting, + {"nonzero_clear_resources_on_creation_for_testing", + "Clears texture to full 1 bits as soon as they are created, but doesn't update " + "the tracking state of the texture. This way we can test the logic of clearing " + "textures that use recycled memory.", + "https://bugs.chromium.org/p/dawn/issues/detail?id=145"}}, + {Toggle::AlwaysResolveIntoZeroLevelAndLayer, + {"always_resolve_into_zero_level_and_layer", + "When the resolve target is a texture view that is created on the non-zero level or " + "layer of a texture, we first resolve into a temporarily 2D texture with only one " + "mipmap level and one array layer, and copy the result of MSAA resolve into the " + "true resolve target. This workaround is enabled by default on the Metal drivers " + "that have bugs when setting non-zero resolveLevel or resolveSlice.", + "https://bugs.chromium.org/p/dawn/issues/detail?id=56"}}, + {Toggle::LazyClearResourceOnFirstUse, + {"lazy_clear_resource_on_first_use", + "Clears resource to zero on first usage. This initializes the resource " + "so that no dirty bits from recycled memory is present in the new resource.", + "https://bugs.chromium.org/p/dawn/issues/detail?id=145"}}, + {Toggle::UseTemporaryBufferInCompressedTextureToTextureCopy, + {"use_temporary_buffer_in_texture_to_texture_copy", + "Split texture-to-texture copy into two copies: copy from source texture into a " + "temporary buffer, and copy from the temporary buffer into the destination texture " + "when copying between compressed textures that don't have block-aligned sizes. This " + "workaround is enabled by default on all Vulkan drivers to solve an issue in the " + "Vulkan SPEC about the texture-to-texture copies with compressed formats. See #1005 " + "(https://github.com/KhronosGroup/Vulkan-Docs/issues/1005) for more details.", + "https://bugs.chromium.org/p/dawn/issues/detail?id=42"}}}}; + + } // anonymous namespace + + void TogglesSet::SetToggle(Toggle toggle, bool enabled) { + ASSERT(toggle != Toggle::InvalidEnum); + const size_t toggleIndex = static_cast<size_t>(toggle); + toggleBitset.set(toggleIndex, enabled); + } + + bool TogglesSet::IsEnabled(Toggle toggle) const { + ASSERT(toggle != Toggle::InvalidEnum); + const size_t toggleIndex = static_cast<size_t>(toggle); + return toggleBitset.test(toggleIndex); + } + + std::vector<const char*> TogglesSet::GetEnabledToggleNames() const { + std::vector<const char*> togglesNameInUse(toggleBitset.count()); + + uint32_t index = 0; + for (uint32_t i : IterateBitSet(toggleBitset)) { + const char* toggleName = ToggleEnumToName(static_cast<Toggle>(i)); + togglesNameInUse[index] = toggleName; + ++index; + } + + return togglesNameInUse; + } + + const char* ToggleEnumToName(Toggle toggle) { + ASSERT(toggle != Toggle::InvalidEnum); + + const ToggleEnumAndInfo& toggleNameAndInfo = + kToggleNameAndInfoList[static_cast<size_t>(toggle)]; + ASSERT(toggleNameAndInfo.toggle == toggle); + return toggleNameAndInfo.info.name; + } + + const ToggleInfo* TogglesInfo::GetToggleInfo(const char* toggleName) { + ASSERT(toggleName); + + EnsureToggleNameToEnumMapInitialized(); + + const auto& iter = mToggleNameToEnumMap.find(toggleName); + if (iter != mToggleNameToEnumMap.cend()) { + return &kToggleNameAndInfoList[static_cast<size_t>(iter->second)].info; + } + return nullptr; + } + + Toggle TogglesInfo::ToggleNameToEnum(const char* toggleName) { + ASSERT(toggleName); + + EnsureToggleNameToEnumMapInitialized(); + + const auto& iter = mToggleNameToEnumMap.find(toggleName); + if (iter != mToggleNameToEnumMap.cend()) { + return kToggleNameAndInfoList[static_cast<size_t>(iter->second)].toggle; + } + return Toggle::InvalidEnum; + } + + void TogglesInfo::EnsureToggleNameToEnumMapInitialized() { + if (mToggleNameToEnumMapInitialized) { + return; + } + + for (size_t index = 0; index < kToggleNameAndInfoList.size(); ++index) { + const ToggleEnumAndInfo& toggleNameAndInfo = kToggleNameAndInfoList[index]; + ASSERT(index == static_cast<size_t>(toggleNameAndInfo.toggle)); + mToggleNameToEnumMap[toggleNameAndInfo.info.name] = toggleNameAndInfo.toggle; + } + + mToggleNameToEnumMapInitialized = true; + } + +} // namespace dawn_native diff --git a/chromium/third_party/dawn/src/dawn_native/Toggles.h b/chromium/third_party/dawn/src/dawn_native/Toggles.h index ac8b3dc1abf..73da01eacd5 100644 --- a/chromium/third_party/dawn/src/dawn_native/Toggles.h +++ b/chromium/third_party/dawn/src/dawn_native/Toggles.h @@ -16,6 +16,8 @@ #define DAWNNATIVE_TOGGLES_H_ #include <bitset> +#include <unordered_map> +#include <vector> #include "dawn_native/DawnNative.h" @@ -26,6 +28,7 @@ namespace dawn_native { NonzeroClearResourcesOnCreationForTesting, AlwaysResolveIntoZeroLevelAndLayer, LazyClearResourceOnFirstUse, + UseTemporaryBufferInCompressedTextureToTextureCopy, EnumCount, InvalidEnum = EnumCount, @@ -36,17 +39,25 @@ namespace dawn_native { struct TogglesSet { std::bitset<static_cast<size_t>(Toggle::EnumCount)> toggleBitset; - void SetToggle(Toggle toggle, bool enabled) { - ASSERT(toggle != Toggle::InvalidEnum); - const size_t toggleIndex = static_cast<size_t>(toggle); - toggleBitset.set(toggleIndex, enabled); - } - - bool IsEnabled(Toggle toggle) const { - ASSERT(toggle != Toggle::InvalidEnum); - const size_t toggleIndex = static_cast<size_t>(toggle); - return toggleBitset.test(toggleIndex); - } + void SetToggle(Toggle toggle, bool enabled); + bool IsEnabled(Toggle toggle) const; + std::vector<const char*> GetEnabledToggleNames() const; + }; + + const char* ToggleEnumToName(Toggle toggle); + + class TogglesInfo { + public: + // Used to query the details of a toggle. Return nullptr if toggleName is not a valid name + // of a toggle supported in Dawn. + const ToggleInfo* GetToggleInfo(const char* toggleName); + Toggle ToggleNameToEnum(const char* toggleName); + + private: + void EnsureToggleNameToEnumMapInitialized(); + + bool mToggleNameToEnumMapInitialized = false; + std::unordered_map<std::string, Toggle> mToggleNameToEnumMap; }; } // namespace dawn_native diff --git a/chromium/third_party/dawn/src/dawn_native/d3d12/AdapterD3D12.cpp b/chromium/third_party/dawn/src/dawn_native/d3d12/AdapterD3D12.cpp index e2c92ccf147..c39791a8767 100644 --- a/chromium/third_party/dawn/src/dawn_native/d3d12/AdapterD3D12.cpp +++ b/chromium/third_party/dawn/src/dawn_native/d3d12/AdapterD3D12.cpp @@ -63,7 +63,7 @@ namespace dawn_native { namespace d3d12 { const PlatformFunctions* functions = GetBackend()->GetFunctions(); if (FAILED(functions->d3d12CreateDevice(GetHardwareAdapter(), D3D_FEATURE_LEVEL_11_0, _uuidof(ID3D12Device), &mD3d12Device))) { - return DAWN_CONTEXT_LOST_ERROR("D3D12CreateDevice failed"); + return DAWN_DEVICE_LOST_ERROR("D3D12CreateDevice failed"); } DAWN_TRY_ASSIGN(mDeviceInfo, GatherDeviceInfo(*this)); @@ -84,9 +84,15 @@ namespace dawn_native { namespace d3d12 { "Error converting"); mPCIInfo.name = converter.to_bytes(adapterDesc.Description); + InitializeSupportedExtensions(); + return {}; } + void Adapter::InitializeSupportedExtensions() { + mSupportedExtensions.EnableExtension(Extension::TextureCompressionBC); + } + ResultOrError<DeviceBase*> Adapter::CreateDeviceImpl(const DeviceDescriptor* descriptor) { std::unique_ptr<Device> device = std::make_unique<Device>(this, descriptor); DAWN_TRY(device->Initialize()); diff --git a/chromium/third_party/dawn/src/dawn_native/d3d12/AdapterD3D12.h b/chromium/third_party/dawn/src/dawn_native/d3d12/AdapterD3D12.h index b5a726b88ab..6c085f03ddd 100644 --- a/chromium/third_party/dawn/src/dawn_native/d3d12/AdapterD3D12.h +++ b/chromium/third_party/dawn/src/dawn_native/d3d12/AdapterD3D12.h @@ -38,6 +38,7 @@ namespace dawn_native { namespace d3d12 { private: ResultOrError<DeviceBase*> CreateDeviceImpl(const DeviceDescriptor* descriptor) override; + void InitializeSupportedExtensions(); ComPtr<IDXGIAdapter1> mHardwareAdapter; ComPtr<ID3D12Device> mD3d12Device; diff --git a/chromium/third_party/dawn/src/dawn_native/d3d12/BackendD3D12.cpp b/chromium/third_party/dawn/src/dawn_native/d3d12/BackendD3D12.cpp index 473eedbb6a6..71beb6c5be6 100644 --- a/chromium/third_party/dawn/src/dawn_native/d3d12/BackendD3D12.cpp +++ b/chromium/third_party/dawn/src/dawn_native/d3d12/BackendD3D12.cpp @@ -61,7 +61,7 @@ namespace dawn_native { namespace d3d12 { } if (FAILED(functions->createDxgiFactory2(dxgiFactoryFlags, IID_PPV_ARGS(&factory)))) { - return DAWN_CONTEXT_LOST_ERROR("Failed to create a DXGI factory"); + return DAWN_DEVICE_LOST_ERROR("Failed to create a DXGI factory"); } ASSERT(factory != nullptr); diff --git a/chromium/third_party/dawn/src/dawn_native/d3d12/BindGroupD3D12.cpp b/chromium/third_party/dawn/src/dawn_native/d3d12/BindGroupD3D12.cpp index bfd0cd0aeda..275f1ce3faa 100644 --- a/chromium/third_party/dawn/src/dawn_native/d3d12/BindGroupD3D12.cpp +++ b/chromium/third_party/dawn/src/dawn_native/d3d12/BindGroupD3D12.cpp @@ -42,6 +42,12 @@ namespace dawn_native { namespace d3d12 { auto d3d12Device = ToBackend(GetDevice())->GetD3D12Device(); for (uint32_t bindingIndex : IterateBitSet(layout.mask)) { + // It's not necessary to create descriptors in descriptor heap for dynamic resources. + // So skip allocating descriptors in descriptor heaps for dynamic buffers. + if (layout.dynamic[bindingIndex]) { + continue; + } + switch (layout.types[bindingIndex]) { case dawn::BindingType::UniformBuffer: { BufferBinding binding = GetBindingAsBufferBinding(bindingIndex); diff --git a/chromium/third_party/dawn/src/dawn_native/d3d12/BindGroupLayoutD3D12.cpp b/chromium/third_party/dawn/src/dawn_native/d3d12/BindGroupLayoutD3D12.cpp index 2634464439c..ec81ad6d0ca 100644 --- a/chromium/third_party/dawn/src/dawn_native/d3d12/BindGroupLayoutD3D12.cpp +++ b/chromium/third_party/dawn/src/dawn_native/d3d12/BindGroupLayoutD3D12.cpp @@ -24,6 +24,13 @@ namespace dawn_native { namespace d3d12 { const auto& groupInfo = GetBindingInfo(); for (uint32_t binding : IterateBitSet(groupInfo.mask)) { + // For dynamic resources, Dawn uses root descriptor in D3D12 backend. + // So there is no need to allocate the descriptor from descriptor heap. Skip counting + // dynamic resources for calculating size of descriptor heap. + if (groupInfo.dynamic[binding]) { + continue; + } + switch (groupInfo.types[binding]) { case dawn::BindingType::UniformBuffer: mBindingOffsets[binding] = mDescriptorCounts[CBV]++; @@ -42,8 +49,6 @@ namespace dawn_native { namespace d3d12 { case dawn::BindingType::ReadonlyStorageBuffer: UNREACHABLE(); break; - - // TODO(shaobo.yan@intel.com): Implement dynamic buffer offset. } } @@ -89,6 +94,25 @@ namespace dawn_native { namespace d3d12 { descriptorOffsets[Sampler] = 0; for (uint32_t binding : IterateBitSet(groupInfo.mask)) { + if (groupInfo.dynamic[binding]) { + // Dawn is using values in mBindingOffsets to decide register number in HLSL. + // Root descriptor needs to set this value to set correct register number in + // generated HLSL shader. + switch (groupInfo.types[binding]) { + case dawn::BindingType::UniformBuffer: + case dawn::BindingType::StorageBuffer: + mBindingOffsets[binding] = baseRegister++; + break; + case dawn::BindingType::SampledTexture: + case dawn::BindingType::Sampler: + case dawn::BindingType::StorageTexture: + case dawn::BindingType::ReadonlyStorageBuffer: + UNREACHABLE(); + break; + } + continue; + } + switch (groupInfo.types[binding]) { case dawn::BindingType::UniformBuffer: mBindingOffsets[binding] += descriptorOffsets[CBV]; diff --git a/chromium/third_party/dawn/src/dawn_native/d3d12/BufferD3D12.cpp b/chromium/third_party/dawn/src/dawn_native/d3d12/BufferD3D12.cpp index 77f2a77f66b..148a7408a35 100644 --- a/chromium/third_party/dawn/src/dawn_native/d3d12/BufferD3D12.cpp +++ b/chromium/third_party/dawn/src/dawn_native/d3d12/BufferD3D12.cpp @@ -18,50 +18,50 @@ #include "common/Constants.h" #include "common/Math.h" #include "dawn_native/d3d12/DeviceD3D12.h" -#include "dawn_native/d3d12/ResourceAllocator.h" +#include "dawn_native/d3d12/ResourceHeapD3D12.h" namespace dawn_native { namespace d3d12 { namespace { - D3D12_RESOURCE_FLAGS D3D12ResourceFlags(dawn::BufferUsageBit usage) { + D3D12_RESOURCE_FLAGS D3D12ResourceFlags(dawn::BufferUsage usage) { D3D12_RESOURCE_FLAGS flags = D3D12_RESOURCE_FLAG_NONE; - if (usage & dawn::BufferUsageBit::Storage) { + if (usage & dawn::BufferUsage::Storage) { flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; } return flags; } - D3D12_RESOURCE_STATES D3D12BufferUsage(dawn::BufferUsageBit usage) { + D3D12_RESOURCE_STATES D3D12BufferUsage(dawn::BufferUsage usage) { D3D12_RESOURCE_STATES resourceState = D3D12_RESOURCE_STATE_COMMON; - if (usage & dawn::BufferUsageBit::CopySrc) { + if (usage & dawn::BufferUsage::CopySrc) { resourceState |= D3D12_RESOURCE_STATE_COPY_SOURCE; } - if (usage & dawn::BufferUsageBit::CopyDst) { + if (usage & dawn::BufferUsage::CopyDst) { resourceState |= D3D12_RESOURCE_STATE_COPY_DEST; } - if (usage & (dawn::BufferUsageBit::Vertex | dawn::BufferUsageBit::Uniform)) { + if (usage & (dawn::BufferUsage::Vertex | dawn::BufferUsage::Uniform)) { resourceState |= D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER; } - if (usage & dawn::BufferUsageBit::Index) { + if (usage & dawn::BufferUsage::Index) { resourceState |= D3D12_RESOURCE_STATE_INDEX_BUFFER; } - if (usage & dawn::BufferUsageBit::Storage) { + if (usage & dawn::BufferUsage::Storage) { resourceState |= D3D12_RESOURCE_STATE_UNORDERED_ACCESS; } - if (usage & dawn::BufferUsageBit::Indirect) { + if (usage & dawn::BufferUsage::Indirect) { resourceState |= D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT; } return resourceState; } - D3D12_HEAP_TYPE D3D12HeapType(dawn::BufferUsageBit allowedUsage) { - if (allowedUsage & dawn::BufferUsageBit::MapRead) { + D3D12_HEAP_TYPE D3D12HeapType(dawn::BufferUsage allowedUsage) { + if (allowedUsage & dawn::BufferUsage::MapRead) { return D3D12_HEAP_TYPE_READBACK; - } else if (allowedUsage & dawn::BufferUsageBit::MapWrite) { + } else if (allowedUsage & dawn::BufferUsage::MapWrite) { return D3D12_HEAP_TYPE_UPLOAD; } else { return D3D12_HEAP_TYPE_DEFAULT; @@ -71,6 +71,9 @@ namespace dawn_native { namespace d3d12 { Buffer::Buffer(Device* device, const BufferDescriptor* descriptor) : BufferBase(device, descriptor) { + } + + MaybeError Buffer::Initialize() { D3D12_RESOURCE_DESC resourceDescriptor; resourceDescriptor.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; resourceDescriptor.Alignment = 0; @@ -84,7 +87,7 @@ namespace dawn_native { namespace d3d12 { resourceDescriptor.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; // Add CopyDst for non-mappable buffer initialization in CreateBufferMapped // and robust resource initialization. - resourceDescriptor.Flags = D3D12ResourceFlags(GetUsage() | dawn::BufferUsageBit::CopyDst); + resourceDescriptor.Flags = D3D12ResourceFlags(GetUsage() | dawn::BufferUsage::CopyDst); auto heapType = D3D12HeapType(GetUsage()); auto bufferUsage = D3D12_RESOURCE_STATE_COMMON; @@ -94,7 +97,7 @@ namespace dawn_native { namespace d3d12 { if (heapType == D3D12_HEAP_TYPE_READBACK) { bufferUsage |= D3D12_RESOURCE_STATE_COPY_DEST; mFixedResourceState = true; - mLastUsage = dawn::BufferUsageBit::CopyDst; + mLastUsage = dawn::BufferUsage::CopyDst; } // D3D12 requires buffers on the UPLOAD heap to have the D3D12_RESOURCE_STATE_GENERIC_READ @@ -102,11 +105,14 @@ namespace dawn_native { namespace d3d12 { if (heapType == D3D12_HEAP_TYPE_UPLOAD) { bufferUsage |= D3D12_RESOURCE_STATE_GENERIC_READ; mFixedResourceState = true; - mLastUsage = dawn::BufferUsageBit::CopySrc; + mLastUsage = dawn::BufferUsage::CopySrc; } - mResource = - device->GetResourceAllocator()->Allocate(heapType, resourceDescriptor, bufferUsage); + DAWN_TRY_ASSIGN( + mResourceAllocation, + ToBackend(GetDevice()) + ->AllocateMemory(heapType, resourceDescriptor, bufferUsage, D3D12_HEAP_FLAG_NONE)); + return {}; } Buffer::~Buffer() { @@ -118,15 +124,15 @@ namespace dawn_native { namespace d3d12 { return Align(GetSize(), 256); } - ComPtr<ID3D12Resource> Buffer::GetD3D12Resource() { - return mResource; + ComPtr<ID3D12Resource> Buffer::GetD3D12Resource() const { + return ToBackend(mResourceAllocation.GetResourceHeap())->GetD3D12Resource(); } // When true is returned, a D3D12_RESOURCE_BARRIER has been created and must be used in a // ResourceBarrier call. Failing to do so will cause the tracked state to become invalid and can // cause subsequent errors. bool Buffer::TransitionUsageAndGetResourceBarrier(D3D12_RESOURCE_BARRIER* barrier, - dawn::BufferUsageBit newUsage) { + dawn::BufferUsage newUsage) { // Resources in upload and readback heaps must be kept in the COPY_SOURCE/DEST state if (mFixedResourceState) { ASSERT(mLastUsage == newUsage); @@ -174,7 +180,7 @@ namespace dawn_native { namespace d3d12 { barrier->Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; barrier->Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; - barrier->Transition.pResource = mResource.Get(); + barrier->Transition.pResource = GetD3D12Resource().Get(); barrier->Transition.StateBefore = lastState; barrier->Transition.StateAfter = newState; barrier->Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; @@ -183,7 +189,7 @@ namespace dawn_native { namespace d3d12 { } void Buffer::TransitionUsageNow(ComPtr<ID3D12GraphicsCommandList> commandList, - dawn::BufferUsageBit usage) { + dawn::BufferUsage usage) { D3D12_RESOURCE_BARRIER barrier; if (TransitionUsageAndGetResourceBarrier(&barrier, usage)) { @@ -192,7 +198,7 @@ namespace dawn_native { namespace d3d12 { } D3D12_GPU_VIRTUAL_ADDRESS Buffer::GetVA() const { - return mResource->GetGPUVirtualAddress(); + return ToBackend(mResourceAllocation.GetResourceHeap())->GetGPUPointer(); } void Buffer::OnMapCommandSerialFinished(uint32_t mapSerial, void* data, bool isWrite) { @@ -205,13 +211,13 @@ namespace dawn_native { namespace d3d12 { bool Buffer::IsMapWritable() const { // TODO(enga): Handle CPU-visible memory on UMA - return (GetUsage() & (dawn::BufferUsageBit::MapRead | dawn::BufferUsageBit::MapWrite)) != 0; + return (GetUsage() & (dawn::BufferUsage::MapRead | dawn::BufferUsage::MapWrite)) != 0; } MaybeError Buffer::MapAtCreationImpl(uint8_t** mappedPointer) { mWrittenMappedRange = {0, GetSize()}; - ASSERT_SUCCESS( - mResource->Map(0, &mWrittenMappedRange, reinterpret_cast<void**>(mappedPointer))); + ASSERT_SUCCESS(GetD3D12Resource()->Map(0, &mWrittenMappedRange, + reinterpret_cast<void**>(mappedPointer))); return {}; } @@ -219,8 +225,7 @@ namespace dawn_native { namespace d3d12 { mWrittenMappedRange = {}; D3D12_RANGE readRange = {0, GetSize()}; char* data = nullptr; - ASSERT_SUCCESS(mResource->Map(0, &readRange, reinterpret_cast<void**>(&data))); - + ASSERT_SUCCESS(GetD3D12Resource()->Map(0, &readRange, reinterpret_cast<void**>(&data))); // There is no need to transition the resource to a new state: D3D12 seems to make the GPU // writes available when the fence is passed. MapRequestTracker* tracker = ToBackend(GetDevice())->GetMapRequestTracker(); @@ -231,8 +236,8 @@ namespace dawn_native { namespace d3d12 { MaybeError Buffer::MapWriteAsyncImpl(uint32_t serial) { mWrittenMappedRange = {0, GetSize()}; char* data = nullptr; - ASSERT_SUCCESS(mResource->Map(0, &mWrittenMappedRange, reinterpret_cast<void**>(&data))); - + ASSERT_SUCCESS( + GetD3D12Resource()->Map(0, &mWrittenMappedRange, reinterpret_cast<void**>(&data))); // There is no need to transition the resource to a new state: D3D12 seems to make the CPU // writes available on queue submission. MapRequestTracker* tracker = ToBackend(GetDevice())->GetMapRequestTracker(); @@ -241,14 +246,12 @@ namespace dawn_native { namespace d3d12 { } void Buffer::UnmapImpl() { - mResource->Unmap(0, &mWrittenMappedRange); - ToBackend(GetDevice())->GetResourceAllocator()->Release(mResource); + GetD3D12Resource()->Unmap(0, &mWrittenMappedRange); mWrittenMappedRange = {}; } void Buffer::DestroyImpl() { - ToBackend(GetDevice())->GetResourceAllocator()->Release(mResource); - mResource = nullptr; + ToBackend(GetDevice())->DeallocateMemory(mResourceAllocation); } MapRequestTracker::MapRequestTracker(Device* device) : mDevice(device) { diff --git a/chromium/third_party/dawn/src/dawn_native/d3d12/BufferD3D12.h b/chromium/third_party/dawn/src/dawn_native/d3d12/BufferD3D12.h index 811fe19103f..7a9b433091d 100644 --- a/chromium/third_party/dawn/src/dawn_native/d3d12/BufferD3D12.h +++ b/chromium/third_party/dawn/src/dawn_native/d3d12/BufferD3D12.h @@ -18,6 +18,7 @@ #include "common/SerialQueue.h" #include "dawn_native/Buffer.h" +#include "dawn_native/ResourceMemoryAllocation.h" #include "dawn_native/d3d12/d3d12_platform.h" namespace dawn_native { namespace d3d12 { @@ -29,14 +30,16 @@ namespace dawn_native { namespace d3d12 { Buffer(Device* device, const BufferDescriptor* descriptor); ~Buffer(); + MaybeError Initialize(); + uint32_t GetD3D12Size() const; - ComPtr<ID3D12Resource> GetD3D12Resource(); + ComPtr<ID3D12Resource> GetD3D12Resource() const; D3D12_GPU_VIRTUAL_ADDRESS GetVA() const; void OnMapCommandSerialFinished(uint32_t mapSerial, void* data, bool isWrite); bool TransitionUsageAndGetResourceBarrier(D3D12_RESOURCE_BARRIER* barrier, - dawn::BufferUsageBit newUsage); + dawn::BufferUsage newUsage); void TransitionUsageNow(ComPtr<ID3D12GraphicsCommandList> commandList, - dawn::BufferUsageBit usage); + dawn::BufferUsage usage); private: // Dawn API @@ -48,9 +51,9 @@ namespace dawn_native { namespace d3d12 { bool IsMapWritable() const override; virtual MaybeError MapAtCreationImpl(uint8_t** mappedPointer) override; - ComPtr<ID3D12Resource> mResource; + ResourceMemoryAllocation mResourceAllocation; bool mFixedResourceState = false; - dawn::BufferUsageBit mLastUsage = dawn::BufferUsageBit::None; + dawn::BufferUsage mLastUsage = dawn::BufferUsage::None; Serial mLastUsedSerial = UINT64_MAX; D3D12_RANGE mWrittenMappedRange; }; diff --git a/chromium/third_party/dawn/src/dawn_native/d3d12/CommandBufferD3D12.cpp b/chromium/third_party/dawn/src/dawn_native/d3d12/CommandBufferD3D12.cpp index 3e201e8ee46..7ea4e4095ab 100644 --- a/chromium/third_party/dawn/src/dawn_native/d3d12/CommandBufferD3D12.cpp +++ b/chromium/third_party/dawn/src/dawn_native/d3d12/CommandBufferD3D12.cpp @@ -17,6 +17,7 @@ #include "common/Assert.h" #include "dawn_native/CommandEncoder.h" #include "dawn_native/Commands.h" +#include "dawn_native/RenderBundle.h" #include "dawn_native/d3d12/BindGroupD3D12.h" #include "dawn_native/d3d12/BindGroupLayoutD3D12.h" #include "dawn_native/d3d12/BufferD3D12.h" @@ -30,6 +31,7 @@ #include "dawn_native/d3d12/SamplerD3D12.h" #include "dawn_native/d3d12/TextureCopySplitter.h" #include "dawn_native/d3d12/TextureD3D12.h" +#include "dawn_native/d3d12/UtilsD3D12.h" #include <deque> @@ -47,17 +49,6 @@ namespace dawn_native { namespace d3d12 { } } - D3D12_TEXTURE_COPY_LOCATION CreateTextureCopyLocationForTexture(const Texture& texture, - uint32_t level, - uint32_t slice) { - D3D12_TEXTURE_COPY_LOCATION copyLocation; - copyLocation.pResource = texture.GetD3D12Resource(); - copyLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; - copyLocation.SubresourceIndex = texture.GetSubresourceIndex(level, slice); - - return copyLocation; - } - bool CanUseCopyResource(const uint32_t sourceNumMipLevels, const Extent3D& srcSize, const Extent3D& dstSize, @@ -151,10 +142,65 @@ namespace dawn_native { namespace d3d12 { PipelineLayout* pipelineLayout, BindGroup* group, uint32_t index, + uint32_t dynamicOffsetCount, + uint64_t* dynamicOffsets, bool force = false) { + // Usually, the application won't set the same offsets many times, + // so always try to apply dynamic offsets even if the offsets stay the same + if (dynamicOffsetCount) { + // Update dynamic offsets + const BindGroupLayout::LayoutBindingInfo& layout = + group->GetLayout()->GetBindingInfo(); + uint32_t currentDynamicBufferIndex = 0; + + for (uint32_t bindingIndex : IterateBitSet(layout.dynamic)) { + ASSERT(dynamicOffsetCount > 0); + uint32_t parameterIndex = + pipelineLayout->GetDynamicRootParameterIndex(index, bindingIndex); + BufferBinding binding = group->GetBindingAsBufferBinding(bindingIndex); + + // Calculate buffer locations that root descriptors links to. The location + // is (base buffer location + initial offset + dynamic offset) + uint64_t dynamicOffset = dynamicOffsets[currentDynamicBufferIndex]; + uint64_t offset = binding.offset + dynamicOffset; + D3D12_GPU_VIRTUAL_ADDRESS bufferLocation = + ToBackend(binding.buffer)->GetVA() + offset; + + switch (layout.types[bindingIndex]) { + case dawn::BindingType::UniformBuffer: + if (mInCompute) { + commandList->SetComputeRootConstantBufferView(parameterIndex, + bufferLocation); + } else { + commandList->SetGraphicsRootConstantBufferView(parameterIndex, + bufferLocation); + } + break; + case dawn::BindingType::StorageBuffer: + if (mInCompute) { + commandList->SetComputeRootUnorderedAccessView(parameterIndex, + bufferLocation); + } else { + commandList->SetGraphicsRootUnorderedAccessView(parameterIndex, + bufferLocation); + } + break; + case dawn::BindingType::SampledTexture: + case dawn::BindingType::Sampler: + case dawn::BindingType::StorageTexture: + case dawn::BindingType::ReadonlyStorageBuffer: + UNREACHABLE(); + break; + } + + // Record current dynamic offsets for inheriting + mLastDynamicOffsets[index][currentDynamicBufferIndex] = dynamicOffset; + ++currentDynamicBufferIndex; + } + } + if (mBindGroups[index] != group || force) { mBindGroups[index] = group; - uint32_t cbvUavSrvCount = ToBackend(group->GetLayout())->GetCbvUavSrvDescriptorCount(); uint32_t samplerCount = ToBackend(group->GetLayout())->GetSamplerDescriptorCount(); @@ -198,7 +244,16 @@ namespace dawn_native { namespace d3d12 { uint32_t inheritUntil = oldLayout->GroupsInheritUpTo(newLayout); for (uint32_t i = 0; i < inheritUntil; ++i) { - SetBindGroup(commandList, newLayout, mBindGroups[i], i, true); + const BindGroupLayout* layout = ToBackend(mBindGroups[i]->GetLayout()); + const uint32_t dynamicBufferCount = layout->GetDynamicBufferCount(); + + // Inherit dynamic offsets + if (dynamicBufferCount > 0) { + SetBindGroup(commandList, newLayout, mBindGroups[i], i, dynamicBufferCount, + mLastDynamicOffsets[i].data(), true); + } else { + SetBindGroup(commandList, newLayout, mBindGroups[i], i, 0, nullptr, true); + } } } @@ -226,6 +281,8 @@ namespace dawn_native { namespace d3d12 { uint32_t mSamplerDescriptorHeapSize = 0; std::array<BindGroup*, kMaxBindGroups> mBindGroups = {}; std::deque<BindGroup*> mBindGroupsList = {}; + std::array<std::array<uint64_t, kMaxDynamicBufferCount>, kMaxBindGroups> + mLastDynamicOffsets; bool mInCompute = false; DescriptorHeapHandle mCbvSrvUavGPUDescriptorHeap = {}; @@ -249,8 +306,9 @@ namespace dawn_native { namespace d3d12 { void TrackRenderPass(const BeginRenderPassCmd* renderPass) { DAWN_ASSERT(mRTVHeap.Get() == nullptr && mDSVHeap.Get() == nullptr); - mNumRTVs += static_cast<uint32_t>(renderPass->colorAttachmentsSet.count()); - if (renderPass->hasDepthStencilAttachment) { + mNumRTVs += static_cast<uint32_t>( + renderPass->attachmentState->GetColorAttachmentsMask().count()); + if (renderPass->attachmentState->HasDepthStencilAttachment()) { ++mNumDSVs; } } @@ -273,9 +331,11 @@ namespace dawn_native { namespace d3d12 { OMSetRenderTargetArgs args = {}; unsigned int rtvIndex = 0; - uint32_t rtvCount = static_cast<uint32_t>(renderPass->colorAttachmentsSet.count()); + uint32_t rtvCount = static_cast<uint32_t>( + renderPass->attachmentState->GetColorAttachmentsMask().count()); DAWN_ASSERT(mAllocatedRTVs + rtvCount <= mNumRTVs); - for (uint32_t i : IterateBitSet(renderPass->colorAttachmentsSet)) { + for (uint32_t i : + IterateBitSet(renderPass->attachmentState->GetColorAttachmentsMask())) { TextureView* view = ToBackend(renderPass->colorAttachments[i].view).Get(); D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = mRTVHeap.GetCPUHandle(mAllocatedRTVs); D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = view->GetRTVDescriptor(); @@ -288,7 +348,7 @@ namespace dawn_native { namespace d3d12 { } args.numRTVs = rtvIndex; - if (renderPass->hasDepthStencilAttachment) { + if (renderPass->attachmentState->HasDepthStencilAttachment()) { DAWN_ASSERT(mAllocatedDSVs < mNumDSVs); TextureView* view = ToBackend(renderPass->depthStencilAttachment.view).Get(); D3D12_CPU_DESCRIPTOR_HANDLE dsvHandle = mDSVHeap.GetCPUHandle(mAllocatedDSVs); @@ -329,7 +389,7 @@ namespace dawn_native { namespace d3d12 { Command type; PipelineLayout* lastLayout = nullptr; - while (commands->NextCommandId(&type)) { + auto HandleCommand = [&](CommandIterator* commands, Command type) { switch (type) { case Command::SetComputePipeline: { SetComputePipelineCmd* cmd = @@ -350,6 +410,9 @@ namespace dawn_native { namespace d3d12 { case Command::SetBindGroup: { SetBindGroupCmd* cmd = commands->NextCommand<SetBindGroupCmd>(); BindGroup* group = ToBackend(cmd->group.Get()); + if (cmd->dynamicOffsetCount) { + commands->NextData<uint64_t>(cmd->dynamicOffsetCount); + } bindingTracker->TrackSetBindGroup(group, cmd->index, indexInSubmit); } break; case Command::BeginRenderPass: { @@ -359,6 +422,26 @@ namespace dawn_native { namespace d3d12 { default: SkipCommand(commands, type); } + }; + + while (commands->NextCommandId(&type)) { + switch (type) { + case Command::ExecuteBundles: { + ExecuteBundlesCmd* cmd = commands->NextCommand<ExecuteBundlesCmd>(); + auto bundles = commands->NextData<Ref<RenderBundleBase>>(cmd->count); + + for (uint32_t i = 0; i < cmd->count; ++i) { + CommandIterator* commands = bundles[i]->GetCommands(); + commands->Reset(); + while (commands->NextCommandId(&type)) { + HandleCommand(commands, type); + } + } + } break; + default: + HandleCommand(commands, type); + break; + } } commands->Reset(); @@ -372,7 +455,8 @@ namespace dawn_native { namespace d3d12 { BeginRenderPassCmd* renderPass) { ASSERT(renderPass != nullptr); - for (uint32_t i : IterateBitSet(renderPass->colorAttachmentsSet)) { + for (uint32_t i : + IterateBitSet(renderPass->attachmentState->GetColorAttachmentsMask())) { TextureViewBase* resolveTarget = renderPass->colorAttachments[i].resolveTarget.Get(); if (resolveTarget == nullptr) { @@ -442,10 +526,13 @@ namespace dawn_native { namespace d3d12 { for (size_t i = 0; i < usages.textures.size(); ++i) { Texture* texture = ToBackend(usages.textures[i]); - // TODO(natlee@microsoft.com): Update clearing here when subresource tracking is - // implemented - texture->EnsureSubresourceContentInitialized( - commandList, 0, texture->GetNumMipLevels(), 0, texture->GetArrayLayers()); + // Clear textures that are not output attachments. Output attachments will be + // cleared during record render pass if the texture subresource has not been + // initialized before the render pass. + if (!(usages.textureUsages[i] & dawn::TextureUsage::OutputAttachment)) { + texture->EnsureSubresourceContentInitialized( + commandList, 0, texture->GetNumMipLevels(), 0, texture->GetArrayLayers()); + } } for (size_t i = 0; i < usages.textures.size(); ++i) { @@ -494,8 +581,8 @@ namespace dawn_native { namespace d3d12 { Buffer* srcBuffer = ToBackend(copy->source.Get()); Buffer* dstBuffer = ToBackend(copy->destination.Get()); - srcBuffer->TransitionUsageNow(commandList, dawn::BufferUsageBit::CopySrc); - dstBuffer->TransitionUsageNow(commandList, dawn::BufferUsageBit::CopyDst); + srcBuffer->TransitionUsageNow(commandList, dawn::BufferUsage::CopySrc); + dstBuffer->TransitionUsageNow(commandList, dawn::BufferUsage::CopyDst); commandList->CopyBufferRegion( dstBuffer->GetD3D12Resource().Get(), copy->destinationOffset, @@ -517,37 +604,26 @@ namespace dawn_native { namespace d3d12 { copy->destination.arrayLayer, 1); } - buffer->TransitionUsageNow(commandList, dawn::BufferUsageBit::CopySrc); - texture->TransitionUsageNow(commandList, dawn::TextureUsageBit::CopyDst); + buffer->TransitionUsageNow(commandList, dawn::BufferUsage::CopySrc); + texture->TransitionUsageNow(commandList, dawn::TextureUsage::CopyDst); auto copySplit = ComputeTextureCopySplit( copy->destination.origin, copy->copySize, texture->GetFormat(), copy->source.offset, copy->source.rowPitch, copy->source.imageHeight); D3D12_TEXTURE_COPY_LOCATION textureLocation = - CreateTextureCopyLocationForTexture(*texture, copy->destination.mipLevel, - copy->destination.arrayLayer); + ComputeTextureCopyLocationForTexture(texture, copy->destination.mipLevel, + copy->destination.arrayLayer); for (uint32_t i = 0; i < copySplit.count; ++i) { - auto& info = copySplit.copies[i]; - - D3D12_TEXTURE_COPY_LOCATION bufferLocation; - bufferLocation.pResource = buffer->GetD3D12Resource().Get(); - bufferLocation.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; - bufferLocation.PlacedFootprint.Offset = copySplit.offset; - bufferLocation.PlacedFootprint.Footprint.Format = texture->GetD3D12Format(); - bufferLocation.PlacedFootprint.Footprint.Width = info.bufferSize.width; - bufferLocation.PlacedFootprint.Footprint.Height = info.bufferSize.height; - bufferLocation.PlacedFootprint.Footprint.Depth = info.bufferSize.depth; - bufferLocation.PlacedFootprint.Footprint.RowPitch = copy->source.rowPitch; - - D3D12_BOX sourceRegion; - sourceRegion.left = info.bufferOffset.x; - sourceRegion.top = info.bufferOffset.y; - sourceRegion.front = info.bufferOffset.z; - sourceRegion.right = info.bufferOffset.x + info.copySize.width; - sourceRegion.bottom = info.bufferOffset.y + info.copySize.height; - sourceRegion.back = info.bufferOffset.z + info.copySize.depth; + TextureCopySplit::CopyInfo& info = copySplit.copies[i]; + + D3D12_TEXTURE_COPY_LOCATION bufferLocation = + ComputeBufferLocationForCopyTextureRegion( + texture, buffer->GetD3D12Resource().Get(), info.bufferSize, + copySplit.offset, copy->source.rowPitch); + D3D12_BOX sourceRegion = + ComputeD3D12BoxFromOffsetAndSize(info.bufferOffset, info.copySize); commandList->CopyTextureRegion(&textureLocation, info.textureOffset.x, info.textureOffset.y, info.textureOffset.z, @@ -563,39 +639,28 @@ namespace dawn_native { namespace d3d12 { texture->EnsureSubresourceContentInitialized(commandList, copy->source.mipLevel, 1, copy->source.arrayLayer, 1); - texture->TransitionUsageNow(commandList, dawn::TextureUsageBit::CopySrc); - buffer->TransitionUsageNow(commandList, dawn::BufferUsageBit::CopyDst); + texture->TransitionUsageNow(commandList, dawn::TextureUsage::CopySrc); + buffer->TransitionUsageNow(commandList, dawn::BufferUsage::CopyDst); - auto copySplit = ComputeTextureCopySplit( + TextureCopySplit copySplit = ComputeTextureCopySplit( copy->source.origin, copy->copySize, texture->GetFormat(), copy->destination.offset, copy->destination.rowPitch, copy->destination.imageHeight); D3D12_TEXTURE_COPY_LOCATION textureLocation = - CreateTextureCopyLocationForTexture(*texture, copy->source.mipLevel, - copy->source.arrayLayer); + ComputeTextureCopyLocationForTexture(texture, copy->source.mipLevel, + copy->source.arrayLayer); for (uint32_t i = 0; i < copySplit.count; ++i) { - auto& info = copySplit.copies[i]; - - D3D12_TEXTURE_COPY_LOCATION bufferLocation; - bufferLocation.pResource = buffer->GetD3D12Resource().Get(); - bufferLocation.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; - bufferLocation.PlacedFootprint.Offset = copySplit.offset; - bufferLocation.PlacedFootprint.Footprint.Format = texture->GetD3D12Format(); - bufferLocation.PlacedFootprint.Footprint.Width = info.bufferSize.width; - bufferLocation.PlacedFootprint.Footprint.Height = info.bufferSize.height; - bufferLocation.PlacedFootprint.Footprint.Depth = info.bufferSize.depth; - bufferLocation.PlacedFootprint.Footprint.RowPitch = - copy->destination.rowPitch; - - D3D12_BOX sourceRegion; - sourceRegion.left = info.textureOffset.x; - sourceRegion.top = info.textureOffset.y; - sourceRegion.front = info.textureOffset.z; - sourceRegion.right = info.textureOffset.x + info.copySize.width; - sourceRegion.bottom = info.textureOffset.y + info.copySize.height; - sourceRegion.back = info.textureOffset.z + info.copySize.depth; + TextureCopySplit::CopyInfo& info = copySplit.copies[i]; + + D3D12_TEXTURE_COPY_LOCATION bufferLocation = + ComputeBufferLocationForCopyTextureRegion( + texture, buffer->GetD3D12Resource().Get(), info.bufferSize, + copySplit.offset, copy->destination.rowPitch); + + D3D12_BOX sourceRegion = + ComputeD3D12BoxFromOffsetAndSize(info.textureOffset, info.copySize); commandList->CopyTextureRegion(&bufferLocation, info.bufferOffset.x, info.bufferOffset.y, info.bufferOffset.z, @@ -621,8 +686,8 @@ namespace dawn_native { namespace d3d12 { commandList, copy->destination.mipLevel, 1, copy->destination.arrayLayer, 1); } - source->TransitionUsageNow(commandList, dawn::TextureUsageBit::CopySrc); - destination->TransitionUsageNow(commandList, dawn::TextureUsageBit::CopyDst); + source->TransitionUsageNow(commandList, dawn::TextureUsage::CopySrc); + destination->TransitionUsageNow(commandList, dawn::TextureUsage::CopyDst); if (CanUseCopyResource(source->GetNumMipLevels(), source->GetSize(), destination->GetSize(), copy->copySize)) { @@ -630,21 +695,16 @@ namespace dawn_native { namespace d3d12 { source->GetD3D12Resource()); } else { D3D12_TEXTURE_COPY_LOCATION srcLocation = - CreateTextureCopyLocationForTexture(*source, copy->source.mipLevel, - copy->source.arrayLayer); + ComputeTextureCopyLocationForTexture(source, copy->source.mipLevel, + copy->source.arrayLayer); D3D12_TEXTURE_COPY_LOCATION dstLocation = - CreateTextureCopyLocationForTexture(*destination, - copy->destination.mipLevel, - copy->destination.arrayLayer); - - D3D12_BOX sourceRegion; - sourceRegion.left = copy->source.origin.x; - sourceRegion.top = copy->source.origin.y; - sourceRegion.front = copy->source.origin.z; - sourceRegion.right = copy->source.origin.x + copy->copySize.width; - sourceRegion.bottom = copy->source.origin.y + copy->copySize.height; - sourceRegion.back = copy->source.origin.z + copy->copySize.depth; + ComputeTextureCopyLocationForTexture(destination, + copy->destination.mipLevel, + copy->destination.arrayLayer); + + D3D12_BOX sourceRegion = + ComputeD3D12BoxFromOffsetAndSize(copy->source.origin, copy->copySize); commandList->CopyTextureRegion( &dstLocation, copy->destination.origin.x, copy->destination.origin.y, @@ -743,7 +803,50 @@ namespace dawn_native { namespace d3d12 { case Command::SetBindGroup: { SetBindGroupCmd* cmd = mCommands.NextCommand<SetBindGroupCmd>(); BindGroup* group = ToBackend(cmd->group.Get()); - bindingTracker->SetBindGroup(commandList, lastLayout, group, cmd->index); + uint64_t* dynamicOffsets = nullptr; + + if (cmd->dynamicOffsetCount > 0) { + dynamicOffsets = mCommands.NextData<uint64_t>(cmd->dynamicOffsetCount); + } + + bindingTracker->SetBindGroup(commandList, lastLayout, group, cmd->index, + cmd->dynamicOffsetCount, dynamicOffsets); + } break; + + case Command::InsertDebugMarker: { + InsertDebugMarkerCmd* cmd = mCommands.NextCommand<InsertDebugMarkerCmd>(); + const char* label = mCommands.NextData<char>(cmd->length + 1); + + if (ToBackend(GetDevice())->GetFunctions()->IsPIXEventRuntimeLoaded()) { + // PIX color is 1 byte per channel in ARGB format + constexpr uint64_t kPIXBlackColor = 0xff000000; + ToBackend(GetDevice()) + ->GetFunctions() + ->pixSetMarkerOnCommandList(commandList.Get(), kPIXBlackColor, label); + } + } break; + + case Command::PopDebugGroup: { + mCommands.NextCommand<PopDebugGroupCmd>(); + + if (ToBackend(GetDevice())->GetFunctions()->IsPIXEventRuntimeLoaded()) { + ToBackend(GetDevice()) + ->GetFunctions() + ->pixEndEventOnCommandList(commandList.Get()); + } + } break; + + case Command::PushDebugGroup: { + PushDebugGroupCmd* cmd = mCommands.NextCommand<PushDebugGroupCmd>(); + const char* label = mCommands.NextData<char>(cmd->length + 1); + + if (ToBackend(GetDevice())->GetFunctions()->IsPIXEventRuntimeLoaded()) { + // PIX color is 1 byte per channel in ARGB format + constexpr uint64_t kPIXBlackColor = 0xff000000; + ToBackend(GetDevice()) + ->GetFunctions() + ->pixBeginEventOnCommandList(commandList.Get(), kPIXBlackColor, label); + } } break; default: { UNREACHABLE(); } break; @@ -759,22 +862,34 @@ namespace dawn_native { namespace d3d12 { // Clear framebuffer attachments as needed and transition to render target { - for (uint32_t i : IterateBitSet(renderPass->colorAttachmentsSet)) { + for (uint32_t i : + IterateBitSet(renderPass->attachmentState->GetColorAttachmentsMask())) { auto& attachmentInfo = renderPass->colorAttachments[i]; TextureView* view = ToBackend(attachmentInfo.view.Get()); // Load op - color ASSERT(view->GetLevelCount() == 1); ASSERT(view->GetLayerCount() == 1); - if (attachmentInfo.loadOp == dawn::LoadOp::Clear) { + if (attachmentInfo.loadOp == dawn::LoadOp::Clear || + (attachmentInfo.loadOp == dawn::LoadOp::Load && + !view->GetTexture()->IsSubresourceContentInitialized( + view->GetBaseMipLevel(), 1, view->GetBaseArrayLayer(), 1))) { D3D12_CPU_DESCRIPTOR_HANDLE handle = args.RTVs[i]; commandList->ClearRenderTargetView(handle, &attachmentInfo.clearColor.r, 0, nullptr); - } else if (attachmentInfo.loadOp == dawn::LoadOp::Load && view->GetTexture()) { - ToBackend(view->GetTexture()) - ->EnsureSubresourceContentInitialized(commandList, view->GetBaseMipLevel(), - 1, view->GetBaseArrayLayer(), 1); } + + TextureView* resolveView = ToBackend(attachmentInfo.resolveTarget.Get()); + if (resolveView != nullptr) { + // We need to set the resolve target to initialized so that it does not get + // cleared later in the pipeline. The texture will be resolved from the source + // color attachment, which will be correctly initialized. + ToBackend(resolveView->GetTexture()) + ->SetIsSubresourceContentInitialized( + resolveView->GetBaseMipLevel(), resolveView->GetLevelCount(), + resolveView->GetBaseArrayLayer(), resolveView->GetLayerCount()); + } + switch (attachmentInfo.storeOp) { case dawn::StoreOp::Store: { view->GetTexture()->SetIsSubresourceContentInitialized( @@ -785,7 +900,7 @@ namespace dawn_native { namespace d3d12 { } } - if (renderPass->hasDepthStencilAttachment) { + if (renderPass->attachmentState->HasDepthStencilAttachment()) { auto& attachmentInfo = renderPass->depthStencilAttachment; Texture* texture = ToBackend(renderPass->depthStencilAttachment.view->GetTexture()); if ((texture->GetFormat().HasDepth() && @@ -856,22 +971,10 @@ namespace dawn_native { namespace d3d12 { PipelineLayout* lastLayout = nullptr; VertexBuffersInfo vertexBuffersInfo = {}; - Command type; - while (mCommands.NextCommandId(&type)) { + auto EncodeRenderBundleCommand = [&](CommandIterator* iter, Command type) { switch (type) { - case Command::EndRenderPass: { - mCommands.NextCommand<EndRenderPassCmd>(); - - // TODO(brandon1.jones@intel.com): avoid calling this function and enable MSAA - // resolve in D3D12 render pass on the platforms that support this feature. - if (renderPass->sampleCount > 1) { - ResolveMultisampledRenderPass(commandList, renderPass); - } - return; - } break; - case Command::Draw: { - DrawCmd* draw = mCommands.NextCommand<DrawCmd>(); + DrawCmd* draw = iter->NextCommand<DrawCmd>(); FlushSetVertexBuffers(commandList, &vertexBuffersInfo, lastPipeline); commandList->DrawInstanced(draw->vertexCount, draw->instanceCount, @@ -879,7 +982,7 @@ namespace dawn_native { namespace d3d12 { } break; case Command::DrawIndexed: { - DrawIndexedCmd* draw = mCommands.NextCommand<DrawIndexedCmd>(); + DrawIndexedCmd* draw = iter->NextCommand<DrawIndexedCmd>(); FlushSetVertexBuffers(commandList, &vertexBuffersInfo, lastPipeline); commandList->DrawIndexedInstanced(draw->indexCount, draw->instanceCount, @@ -888,7 +991,7 @@ namespace dawn_native { namespace d3d12 { } break; case Command::DrawIndirect: { - DrawIndirectCmd* draw = mCommands.NextCommand<DrawIndirectCmd>(); + DrawIndirectCmd* draw = iter->NextCommand<DrawIndirectCmd>(); FlushSetVertexBuffers(commandList, &vertexBuffersInfo, lastPipeline); Buffer* buffer = ToBackend(draw->indirectBuffer.Get()); @@ -900,7 +1003,7 @@ namespace dawn_native { namespace d3d12 { } break; case Command::DrawIndexedIndirect: { - DrawIndexedIndirectCmd* draw = mCommands.NextCommand<DrawIndexedIndirectCmd>(); + DrawIndexedIndirectCmd* draw = iter->NextCommand<DrawIndexedIndirectCmd>(); FlushSetVertexBuffers(commandList, &vertexBuffersInfo, lastPipeline); Buffer* buffer = ToBackend(draw->indirectBuffer.Get()); @@ -912,10 +1015,10 @@ namespace dawn_native { namespace d3d12 { } break; case Command::InsertDebugMarker: { - InsertDebugMarkerCmd* cmd = mCommands.NextCommand<InsertDebugMarkerCmd>(); - const char* label = mCommands.NextData<char>(cmd->length + 1); + InsertDebugMarkerCmd* cmd = iter->NextCommand<InsertDebugMarkerCmd>(); + const char* label = iter->NextData<char>(cmd->length + 1); - if (ToBackend(GetDevice())->GetFunctions()->isPIXEventRuntimeLoaded()) { + if (ToBackend(GetDevice())->GetFunctions()->IsPIXEventRuntimeLoaded()) { // PIX color is 1 byte per channel in ARGB format constexpr uint64_t kPIXBlackColor = 0xff000000; ToBackend(GetDevice()) @@ -925,9 +1028,9 @@ namespace dawn_native { namespace d3d12 { } break; case Command::PopDebugGroup: { - mCommands.NextCommand<PopDebugGroupCmd>(); + iter->NextCommand<PopDebugGroupCmd>(); - if (ToBackend(GetDevice())->GetFunctions()->isPIXEventRuntimeLoaded()) { + if (ToBackend(GetDevice())->GetFunctions()->IsPIXEventRuntimeLoaded()) { ToBackend(GetDevice()) ->GetFunctions() ->pixEndEventOnCommandList(commandList.Get()); @@ -935,10 +1038,10 @@ namespace dawn_native { namespace d3d12 { } break; case Command::PushDebugGroup: { - PushDebugGroupCmd* cmd = mCommands.NextCommand<PushDebugGroupCmd>(); - const char* label = mCommands.NextData<char>(cmd->length + 1); + PushDebugGroupCmd* cmd = iter->NextCommand<PushDebugGroupCmd>(); + const char* label = iter->NextData<char>(cmd->length + 1); - if (ToBackend(GetDevice())->GetFunctions()->isPIXEventRuntimeLoaded()) { + if (ToBackend(GetDevice())->GetFunctions()->IsPIXEventRuntimeLoaded()) { // PIX color is 1 byte per channel in ARGB format constexpr uint64_t kPIXBlackColor = 0xff000000; ToBackend(GetDevice()) @@ -948,7 +1051,7 @@ namespace dawn_native { namespace d3d12 { } break; case Command::SetRenderPipeline: { - SetRenderPipelineCmd* cmd = mCommands.NextCommand<SetRenderPipelineCmd>(); + SetRenderPipelineCmd* cmd = iter->NextCommand<SetRenderPipelineCmd>(); RenderPipeline* pipeline = ToBackend(cmd->pipeline).Get(); PipelineLayout* layout = ToBackend(pipeline->GetLayout()); @@ -962,6 +1065,75 @@ namespace dawn_native { namespace d3d12 { lastLayout = layout; } break; + case Command::SetBindGroup: { + SetBindGroupCmd* cmd = iter->NextCommand<SetBindGroupCmd>(); + BindGroup* group = ToBackend(cmd->group.Get()); + uint64_t* dynamicOffsets = nullptr; + + if (cmd->dynamicOffsetCount > 0) { + dynamicOffsets = iter->NextData<uint64_t>(cmd->dynamicOffsetCount); + } + + bindingTracker->SetBindGroup(commandList, lastLayout, group, cmd->index, + cmd->dynamicOffsetCount, dynamicOffsets); + } break; + + case Command::SetIndexBuffer: { + SetIndexBufferCmd* cmd = iter->NextCommand<SetIndexBufferCmd>(); + + Buffer* buffer = ToBackend(cmd->buffer.Get()); + D3D12_INDEX_BUFFER_VIEW bufferView; + bufferView.BufferLocation = buffer->GetVA() + cmd->offset; + bufferView.SizeInBytes = buffer->GetSize() - cmd->offset; + // TODO(cwallez@chromium.org): Make index buffers lazily applied, right now + // this will break if the pipeline is changed for one with a different index + // format after SetIndexBuffer + bufferView.Format = + DXGIIndexFormat(lastPipeline->GetVertexInputDescriptor()->indexFormat); + + commandList->IASetIndexBuffer(&bufferView); + } break; + + case Command::SetVertexBuffers: { + SetVertexBuffersCmd* cmd = iter->NextCommand<SetVertexBuffersCmd>(); + auto buffers = iter->NextData<Ref<BufferBase>>(cmd->count); + auto offsets = iter->NextData<uint64_t>(cmd->count); + + vertexBuffersInfo.startSlot = + std::min(vertexBuffersInfo.startSlot, cmd->startSlot); + vertexBuffersInfo.endSlot = + std::max(vertexBuffersInfo.endSlot, cmd->startSlot + cmd->count); + + for (uint32_t i = 0; i < cmd->count; ++i) { + Buffer* buffer = ToBackend(buffers[i].Get()); + auto* d3d12BufferView = + &vertexBuffersInfo.d3d12BufferViews[cmd->startSlot + i]; + d3d12BufferView->BufferLocation = buffer->GetVA() + offsets[i]; + d3d12BufferView->SizeInBytes = buffer->GetSize() - offsets[i]; + // The bufferView stride is set based on the input state before a draw. + } + } break; + + default: + UNREACHABLE(); + break; + } + }; + + Command type; + while (mCommands.NextCommandId(&type)) { + switch (type) { + case Command::EndRenderPass: { + mCommands.NextCommand<EndRenderPassCmd>(); + + // TODO(brandon1.jones@intel.com): avoid calling this function and enable MSAA + // resolve in D3D12 render pass on the platforms that support this feature. + if (renderPass->attachmentState->GetSampleCount() > 1) { + ResolveMultisampledRenderPass(commandList, renderPass); + } + return; + } break; + case Command::SetStencilReference: { SetStencilReferenceCmd* cmd = mCommands.NextCommand<SetStencilReferenceCmd>(); @@ -997,49 +1169,20 @@ namespace dawn_native { namespace d3d12 { commandList->OMSetBlendFactor(static_cast<const FLOAT*>(&cmd->color.r)); } break; - case Command::SetBindGroup: { - SetBindGroupCmd* cmd = mCommands.NextCommand<SetBindGroupCmd>(); - BindGroup* group = ToBackend(cmd->group.Get()); - bindingTracker->SetBindGroup(commandList, lastLayout, group, cmd->index); - } break; - - case Command::SetIndexBuffer: { - SetIndexBufferCmd* cmd = mCommands.NextCommand<SetIndexBufferCmd>(); - - Buffer* buffer = ToBackend(cmd->buffer.Get()); - D3D12_INDEX_BUFFER_VIEW bufferView; - bufferView.BufferLocation = buffer->GetVA() + cmd->offset; - bufferView.SizeInBytes = buffer->GetSize() - cmd->offset; - // TODO(cwallez@chromium.org): Make index buffers lazily applied, right now - // this will break if the pipeline is changed for one with a different index - // format after SetIndexBuffer - bufferView.Format = - DXGIIndexFormat(lastPipeline->GetVertexInputDescriptor()->indexFormat); - - commandList->IASetIndexBuffer(&bufferView); - } break; - - case Command::SetVertexBuffers: { - SetVertexBuffersCmd* cmd = mCommands.NextCommand<SetVertexBuffersCmd>(); - auto buffers = mCommands.NextData<Ref<BufferBase>>(cmd->count); - auto offsets = mCommands.NextData<uint64_t>(cmd->count); - - vertexBuffersInfo.startSlot = - std::min(vertexBuffersInfo.startSlot, cmd->startSlot); - vertexBuffersInfo.endSlot = - std::max(vertexBuffersInfo.endSlot, cmd->startSlot + cmd->count); + case Command::ExecuteBundles: { + ExecuteBundlesCmd* cmd = mCommands.NextCommand<ExecuteBundlesCmd>(); + auto bundles = mCommands.NextData<Ref<RenderBundleBase>>(cmd->count); for (uint32_t i = 0; i < cmd->count; ++i) { - Buffer* buffer = ToBackend(buffers[i].Get()); - auto* d3d12BufferView = - &vertexBuffersInfo.d3d12BufferViews[cmd->startSlot + i]; - d3d12BufferView->BufferLocation = buffer->GetVA() + offsets[i]; - d3d12BufferView->SizeInBytes = buffer->GetSize() - offsets[i]; - // The bufferView stride is set based on the input state before a draw. + CommandIterator* iter = bundles[i]->GetCommands(); + iter->Reset(); + while (iter->NextCommandId(&type)) { + EncodeRenderBundleCommand(iter, type); + } } } break; - default: { UNREACHABLE(); } break; + default: { EncodeRenderBundleCommand(&mCommands, type); } break; } } } diff --git a/chromium/third_party/dawn/src/dawn_native/d3d12/CommittedResourceAllocatorD3D12.cpp b/chromium/third_party/dawn/src/dawn_native/d3d12/CommittedResourceAllocatorD3D12.cpp new file mode 100644 index 00000000000..772f5d21f4c --- /dev/null +++ b/chromium/third_party/dawn/src/dawn_native/d3d12/CommittedResourceAllocatorD3D12.cpp @@ -0,0 +1,52 @@ +// Copyright 2019 The Dawn Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "dawn_native/d3d12/CommittedResourceAllocatorD3D12.h" +#include "dawn_native/d3d12/DeviceD3D12.h" +#include "dawn_native/d3d12/ResourceHeapD3D12.h" + +namespace dawn_native { namespace d3d12 { + + CommittedResourceAllocator::CommittedResourceAllocator(Device* device, D3D12_HEAP_TYPE heapType) + : mDevice(device), mHeapType(heapType) { + } + + ResultOrError<ResourceMemoryAllocation> CommittedResourceAllocator::Allocate( + const D3D12_RESOURCE_DESC& resourceDescriptor, + D3D12_RESOURCE_STATES initialUsage, + D3D12_HEAP_FLAGS heapFlags) { + D3D12_HEAP_PROPERTIES heapProperties; + heapProperties.Type = mHeapType; + heapProperties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; + heapProperties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; + heapProperties.CreationNodeMask = 0; + heapProperties.VisibleNodeMask = 0; + + ComPtr<ID3D12Resource> committedResource; + if (FAILED(mDevice->GetD3D12Device()->CreateCommittedResource( + &heapProperties, heapFlags, &resourceDescriptor, initialUsage, nullptr, + IID_PPV_ARGS(&committedResource)))) { + return DAWN_OUT_OF_MEMORY_ERROR("Unable to allocate resource"); + } + + return ResourceMemoryAllocation( + /*offset*/ 0, new ResourceHeap(std::move(committedResource)), + AllocationMethod::kDirect); + } + + void CommittedResourceAllocator::Deallocate(ResourceMemoryAllocation& allocation) { + std::unique_ptr<ResourceHeap> resourceHeap(ToBackend(allocation.GetResourceHeap())); + mDevice->ReferenceUntilUnused(resourceHeap->GetD3D12Resource()); + } +}} // namespace dawn_native::d3d12 diff --git a/chromium/third_party/dawn/src/dawn_native/d3d12/CommittedResourceAllocatorD3D12.h b/chromium/third_party/dawn/src/dawn_native/d3d12/CommittedResourceAllocatorD3D12.h new file mode 100644 index 00000000000..419d1c6cbd9 --- /dev/null +++ b/chromium/third_party/dawn/src/dawn_native/d3d12/CommittedResourceAllocatorD3D12.h @@ -0,0 +1,47 @@ +// Copyright 2019 The Dawn Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef DAWNNATIVE_D3D12_COMMITTEDRESOURCEALLOCATORD3D12_H_ +#define DAWNNATIVE_D3D12_COMMITTEDRESOURCEALLOCATORD3D12_H_ + +#include "common/SerialQueue.h" +#include "dawn_native/Error.h" +#include "dawn_native/ResourceMemoryAllocation.h" +#include "dawn_native/d3d12/d3d12_platform.h" + +namespace dawn_native { namespace d3d12 { + + class Device; + + // Wrapper to allocate D3D12 committed resource. + // Committed resources are implicitly backed by a D3D12 heap. + class CommittedResourceAllocator { + public: + CommittedResourceAllocator(Device* device, D3D12_HEAP_TYPE heapType); + ~CommittedResourceAllocator() = default; + + ResultOrError<ResourceMemoryAllocation> Allocate( + const D3D12_RESOURCE_DESC& resourceDescriptor, + D3D12_RESOURCE_STATES initialUsage, + D3D12_HEAP_FLAGS heapFlags); + void Deallocate(ResourceMemoryAllocation& allocation); + + private: + Device* mDevice; + D3D12_HEAP_TYPE mHeapType; + }; + +}} // namespace dawn_native::d3d12 + +#endif // DAWNNATIVE_D3D12_COMMITTEDRESOURCEALLOCATORD3D12_H_ diff --git a/chromium/third_party/dawn/src/dawn_native/d3d12/ComputePipelineD3D12.cpp b/chromium/third_party/dawn/src/dawn_native/d3d12/ComputePipelineD3D12.cpp index d70846ea099..893b5654378 100644 --- a/chromium/third_party/dawn/src/dawn_native/d3d12/ComputePipelineD3D12.cpp +++ b/chromium/third_party/dawn/src/dawn_native/d3d12/ComputePipelineD3D12.cpp @@ -32,7 +32,7 @@ namespace dawn_native { namespace d3d12 { // SPRIV-cross does matrix multiplication expecting row major matrices compileFlags |= D3DCOMPILE_PACK_MATRIX_ROW_MAJOR; - const ShaderModule* module = ToBackend(descriptor->computeStage->module); + const ShaderModule* module = ToBackend(descriptor->computeStage.module); const std::string& hlslSource = module->GetHLSLSource(ToBackend(GetLayout())); ComPtr<ID3DBlob> compiledShader; @@ -40,7 +40,7 @@ namespace dawn_native { namespace d3d12 { const PlatformFunctions* functions = device->GetFunctions(); if (FAILED(functions->d3dCompile(hlslSource.c_str(), hlslSource.length(), nullptr, nullptr, - nullptr, descriptor->computeStage->entryPoint, "cs_5_1", + nullptr, descriptor->computeStage.entryPoint, "cs_5_1", compileFlags, 0, &compiledShader, &errors))) { printf("%s\n", reinterpret_cast<char*>(errors->GetBufferPointer())); ASSERT(false); diff --git a/chromium/third_party/dawn/src/dawn_native/d3d12/D3D12Backend.cpp b/chromium/third_party/dawn/src/dawn_native/d3d12/D3D12Backend.cpp index 36e766151dc..5d96593d81a 100644 --- a/chromium/third_party/dawn/src/dawn_native/d3d12/D3D12Backend.cpp +++ b/chromium/third_party/dawn/src/dawn_native/d3d12/D3D12Backend.cpp @@ -23,12 +23,18 @@ namespace dawn_native { namespace d3d12 { + ComPtr<ID3D12Device> GetD3D12Device(DawnDevice device) { + Device* backendDevice = reinterpret_cast<Device*>(device); + + return backendDevice->GetD3D12Device(); + } + DawnSwapChainImplementation CreateNativeSwapChainImpl(DawnDevice device, HWND window) { Device* backendDevice = reinterpret_cast<Device*>(device); DawnSwapChainImplementation impl; impl = CreateSwapChainImplementation(new NativeSwapChainImpl(backendDevice, window)); - impl.textureUsage = DAWN_TEXTURE_USAGE_BIT_PRESENT; + impl.textureUsage = DAWN_TEXTURE_USAGE_PRESENT; return impl; } @@ -39,4 +45,13 @@ namespace dawn_native { namespace d3d12 { return static_cast<DawnTextureFormat>(impl->GetPreferredFormat()); } + DawnTexture WrapSharedHandle(DawnDevice device, + const DawnTextureDescriptor* descriptor, + HANDLE sharedHandle) { + Device* backendDevice = reinterpret_cast<Device*>(device); + const TextureDescriptor* backendDescriptor = + reinterpret_cast<const TextureDescriptor*>(descriptor); + TextureBase* texture = backendDevice->WrapSharedHandle(backendDescriptor, sharedHandle); + return reinterpret_cast<DawnTexture>(texture); + } }} // namespace dawn_native::d3d12 diff --git a/chromium/third_party/dawn/src/dawn_native/d3d12/D3D12Info.cpp b/chromium/third_party/dawn/src/dawn_native/d3d12/D3D12Info.cpp index 3b2b57d823f..1431b34c400 100644 --- a/chromium/third_party/dawn/src/dawn_native/d3d12/D3D12Info.cpp +++ b/chromium/third_party/dawn/src/dawn_native/d3d12/D3D12Info.cpp @@ -33,7 +33,7 @@ namespace dawn_native { namespace d3d12 { D3D12_FEATURE_DATA_ARCHITECTURE arch = {}; if (FAILED(adapter.GetDevice()->CheckFeatureSupport(D3D12_FEATURE_ARCHITECTURE, &arch, sizeof(arch)))) { - return DAWN_CONTEXT_LOST_ERROR("CheckFeatureSupport failed"); + return DAWN_DEVICE_LOST_ERROR("CheckFeatureSupport failed"); } info.isUMA = arch.UMA; diff --git a/chromium/third_party/dawn/src/dawn_native/d3d12/DeviceD3D12.cpp b/chromium/third_party/dawn/src/dawn_native/d3d12/DeviceD3D12.cpp index f49d843c99e..e925a771b7f 100644 --- a/chromium/third_party/dawn/src/dawn_native/d3d12/DeviceD3D12.cpp +++ b/chromium/third_party/dawn/src/dawn_native/d3d12/DeviceD3D12.cpp @@ -31,6 +31,7 @@ #include "dawn_native/d3d12/QueueD3D12.h" #include "dawn_native/d3d12/RenderPipelineD3D12.h" #include "dawn_native/d3d12/ResourceAllocator.h" +#include "dawn_native/d3d12/ResourceHeapD3D12.h" #include "dawn_native/d3d12/SamplerD3D12.h" #include "dawn_native/d3d12/ShaderModuleD3D12.h" #include "dawn_native/d3d12/StagingBufferD3D12.h" @@ -110,16 +111,27 @@ namespace dawn_native { namespace d3d12 { } NextSerial(); WaitForSerial(mLastSubmittedSerial); // Wait for all in-flight commands to finish executing - TickImpl(); // Call tick one last time so resources are cleaned up + TickImpl(); // Call tick one last time so resources are cleaned up // Free services explicitly so that they can free D3D12 resources before destruction of the // device. mDynamicUploader = nullptr; + // GPU is no longer executing commands. Existing objects do not get freed until the device + // is destroyed. To ensure objects are always released, force the completed serial to be + // MAX. + mCompletedSerial = std::numeric_limits<Serial>::max(); + // Releasing the uploader enqueues buffers to be released. // Call Tick() again to clear them before releasing the allocator. mResourceAllocator->Tick(mCompletedSerial); + if (mFenceEvent != nullptr) { + ::CloseHandle(mFenceEvent); + } + + mUsedComObjectRefs.ClearUpTo(mCompletedSerial); + ASSERT(mUsedComObjectRefs.Empty()); ASSERT(mPendingCommands.commandList == nullptr); } @@ -260,7 +272,9 @@ namespace dawn_native { namespace d3d12 { return new BindGroupLayout(this, descriptor); } ResultOrError<BufferBase*> Device::CreateBufferImpl(const BufferDescriptor* descriptor) { - return new Buffer(this, descriptor); + std::unique_ptr<Buffer> buffer = std::make_unique<Buffer>(this, descriptor); + DAWN_TRY(buffer->Initialize()); + return buffer.release(); } CommandBufferBase* Device::CreateCommandBuffer(CommandEncoderBase* encoder, const CommandBufferDescriptor* descriptor) { @@ -313,7 +327,7 @@ namespace dawn_native { namespace d3d12 { uint64_t destinationOffset, uint64_t size) { ToBackend(destination) - ->TransitionUsageNow(GetPendingCommandList(), dawn::BufferUsageBit::CopyDst); + ->TransitionUsageNow(GetPendingCommandList(), dawn::BufferUsage::CopyDst); GetPendingCommandList()->CopyBufferRegion( ToBackend(destination)->GetD3D12Resource().Get(), destinationOffset, @@ -322,4 +336,72 @@ namespace dawn_native { namespace d3d12 { return {}; } + size_t Device::GetD3D12HeapTypeToIndex(D3D12_HEAP_TYPE heapType) const { + ASSERT(heapType > 0); + ASSERT(static_cast<uint32_t>(heapType) <= kNumHeapTypes); + return heapType - 1; + } + + void Device::DeallocateMemory(ResourceMemoryAllocation& allocation) { + CommittedResourceAllocator* allocator = nullptr; + D3D12_HEAP_PROPERTIES heapProp; + ToBackend(allocation.GetResourceHeap()) + ->GetD3D12Resource() + ->GetHeapProperties(&heapProp, nullptr); + const size_t heapTypeIndex = GetD3D12HeapTypeToIndex(heapProp.Type); + ASSERT(heapTypeIndex < kNumHeapTypes); + allocator = mDirectResourceAllocators[heapTypeIndex].get(); + allocator->Deallocate(allocation); + + // Invalidate the underlying resource heap in case the client accidentally + // calls DeallocateMemory again using the same allocation. + allocation.Invalidate(); + } + + ResultOrError<ResourceMemoryAllocation> Device::AllocateMemory( + D3D12_HEAP_TYPE heapType, + const D3D12_RESOURCE_DESC& resourceDescriptor, + D3D12_RESOURCE_STATES initialUsage, + D3D12_HEAP_FLAGS heapFlags) { + const size_t heapTypeIndex = GetD3D12HeapTypeToIndex(heapType); + ASSERT(heapTypeIndex < kNumHeapTypes); + + // Get the direct allocator using a tightly sized heap (aka CreateCommittedResource). + CommittedResourceAllocator* allocator = mDirectResourceAllocators[heapTypeIndex].get(); + if (allocator == nullptr) { + mDirectResourceAllocators[heapTypeIndex] = + std::make_unique<CommittedResourceAllocator>(this, heapType); + allocator = mDirectResourceAllocators[heapTypeIndex].get(); + } + + ResourceMemoryAllocation allocation; + DAWN_TRY_ASSIGN(allocation, + allocator->Allocate(resourceDescriptor, initialUsage, heapFlags)); + + return allocation; + } + + TextureBase* Device::WrapSharedHandle(const TextureDescriptor* descriptor, + HANDLE sharedHandle) { + if (ConsumedError(ValidateTextureDescriptor(this, descriptor))) { + return nullptr; + } + + if (ConsumedError(ValidateTextureDescriptorCanBeWrapped(descriptor))) { + return nullptr; + } + + ComPtr<ID3D12Resource> d3d12Resource; + const HRESULT hr = + mD3d12Device->OpenSharedHandle(sharedHandle, IID_PPV_ARGS(&d3d12Resource)); + if (FAILED(hr)) { + return nullptr; + } + + if (ConsumedError(ValidateD3D12TextureCanBeWrapped(d3d12Resource.Get(), descriptor))) { + return nullptr; + } + + return new Texture(this, descriptor, d3d12Resource.Get()); + } }} // namespace dawn_native::d3d12 diff --git a/chromium/third_party/dawn/src/dawn_native/d3d12/DeviceD3D12.h b/chromium/third_party/dawn/src/dawn_native/d3d12/DeviceD3D12.h index 6af417accb4..237c8b4b4e7 100644 --- a/chromium/third_party/dawn/src/dawn_native/d3d12/DeviceD3D12.h +++ b/chromium/third_party/dawn/src/dawn_native/d3d12/DeviceD3D12.h @@ -19,6 +19,7 @@ #include "common/SerialQueue.h" #include "dawn_native/Device.h" +#include "dawn_native/d3d12/CommittedResourceAllocatorD3D12.h" #include "dawn_native/d3d12/Forward.h" #include "dawn_native/d3d12/d3d12_platform.h" @@ -81,6 +82,16 @@ namespace dawn_native { namespace d3d12 { uint64_t destinationOffset, uint64_t size) override; + ResultOrError<ResourceMemoryAllocation> AllocateMemory( + D3D12_HEAP_TYPE heapType, + const D3D12_RESOURCE_DESC& resourceDescriptor, + D3D12_RESOURCE_STATES initialUsage, + D3D12_HEAP_FLAGS heapFlags); + + void DeallocateMemory(ResourceMemoryAllocation& allocation); + + TextureBase* WrapSharedHandle(const TextureDescriptor* descriptor, HANDLE sharedHandle); + private: ResultOrError<BindGroupBase*> CreateBindGroupImpl( const BindGroupDescriptor* descriptor) override; @@ -104,10 +115,12 @@ namespace dawn_native { namespace d3d12 { TextureBase* texture, const TextureViewDescriptor* descriptor) override; + size_t GetD3D12HeapTypeToIndex(D3D12_HEAP_TYPE heapType) const; + Serial mCompletedSerial = 0; Serial mLastSubmittedSerial = 0; ComPtr<ID3D12Fence> mFence; - HANDLE mFenceEvent; + HANDLE mFenceEvent = nullptr; ComPtr<ID3D12Device> mD3d12Device; // Device is owned by adapter and will not be outlived. ComPtr<ID3D12CommandQueue> mCommandQueue; @@ -128,6 +141,20 @@ namespace dawn_native { namespace d3d12 { std::unique_ptr<MapRequestTracker> mMapRequestTracker; std::unique_ptr<ResourceAllocator> mResourceAllocator; + static constexpr uint32_t kNumHeapTypes = 4u; // Number of D3D12_HEAP_TYPE + + static_assert(D3D12_HEAP_TYPE_READBACK <= kNumHeapTypes, + "Readback heap type enum exceeds max heap types"); + static_assert(D3D12_HEAP_TYPE_UPLOAD <= kNumHeapTypes, + "Upload heap type enum exceeds max heap types"); + static_assert(D3D12_HEAP_TYPE_DEFAULT <= kNumHeapTypes, + "Default heap type enum exceeds max heap types"); + static_assert(D3D12_HEAP_TYPE_CUSTOM <= kNumHeapTypes, + "Custom heap type enum exceeds max heap types"); + + std::array<std::unique_ptr<CommittedResourceAllocator>, kNumHeapTypes> + mDirectResourceAllocators; + dawn_native::PCIInfo mPCIInfo; }; diff --git a/chromium/third_party/dawn/src/dawn_native/d3d12/Forward.h b/chromium/third_party/dawn/src/dawn_native/d3d12/Forward.h index ade12e3ac86..f42f82430f4 100644 --- a/chromium/third_party/dawn/src/dawn_native/d3d12/Forward.h +++ b/chromium/third_party/dawn/src/dawn_native/d3d12/Forward.h @@ -29,6 +29,7 @@ namespace dawn_native { namespace d3d12 { class PipelineLayout; class Queue; class RenderPipeline; + class ResourceHeap; class Sampler; class ShaderModule; class StagingBuffer; @@ -47,6 +48,7 @@ namespace dawn_native { namespace d3d12 { using PipelineLayoutType = PipelineLayout; using QueueType = Queue; using RenderPipelineType = RenderPipeline; + using ResourceHeapType = ResourceHeap; using SamplerType = Sampler; using ShaderModuleType = ShaderModule; using StagingBufferType = StagingBuffer; diff --git a/chromium/third_party/dawn/src/dawn_native/d3d12/NativeSwapChainImplD3D12.cpp b/chromium/third_party/dawn/src/dawn_native/d3d12/NativeSwapChainImplD3D12.cpp index 6934679757e..2ec24b59ab6 100644 --- a/chromium/third_party/dawn/src/dawn_native/d3d12/NativeSwapChainImplD3D12.cpp +++ b/chromium/third_party/dawn/src/dawn_native/d3d12/NativeSwapChainImplD3D12.cpp @@ -21,15 +21,15 @@ namespace dawn_native { namespace d3d12 { namespace { - DXGI_USAGE D3D12SwapChainBufferUsage(DawnTextureUsageBit allowedUsages) { + DXGI_USAGE D3D12SwapChainBufferUsage(DawnTextureUsage allowedUsages) { DXGI_USAGE usage = DXGI_CPU_ACCESS_NONE; - if (allowedUsages & DAWN_TEXTURE_USAGE_BIT_SAMPLED) { + if (allowedUsages & DAWN_TEXTURE_USAGE_SAMPLED) { usage |= DXGI_USAGE_SHADER_INPUT; } - if (allowedUsages & DAWN_TEXTURE_USAGE_BIT_STORAGE) { + if (allowedUsages & DAWN_TEXTURE_USAGE_STORAGE) { usage |= DXGI_USAGE_UNORDERED_ACCESS; } - if (allowedUsages & DAWN_TEXTURE_USAGE_BIT_OUTPUT_ATTACHMENT) { + if (allowedUsages & DAWN_TEXTURE_USAGE_OUTPUT_ATTACHMENT) { usage |= DXGI_USAGE_RENDER_TARGET_OUTPUT; } return usage; @@ -49,7 +49,7 @@ namespace dawn_native { namespace d3d12 { } DawnSwapChainError NativeSwapChainImpl::Configure(DawnTextureFormat format, - DawnTextureUsageBit usage, + DawnTextureUsage usage, uint32_t width, uint32_t height) { ASSERT(width > 0); diff --git a/chromium/third_party/dawn/src/dawn_native/d3d12/NativeSwapChainImplD3D12.h b/chromium/third_party/dawn/src/dawn_native/d3d12/NativeSwapChainImplD3D12.h index f2fa847b97f..223f5ef6b90 100644 --- a/chromium/third_party/dawn/src/dawn_native/d3d12/NativeSwapChainImplD3D12.h +++ b/chromium/third_party/dawn/src/dawn_native/d3d12/NativeSwapChainImplD3D12.h @@ -35,7 +35,7 @@ namespace dawn_native { namespace d3d12 { void Init(DawnWSIContextD3D12* context); DawnSwapChainError Configure(DawnTextureFormat format, - DawnTextureUsageBit, + DawnTextureUsage, uint32_t width, uint32_t height); DawnSwapChainError GetNextTexture(DawnSwapChainNextTexture* nextTexture); diff --git a/chromium/third_party/dawn/src/dawn_native/d3d12/PipelineLayoutD3D12.cpp b/chromium/third_party/dawn/src/dawn_native/d3d12/PipelineLayoutD3D12.cpp index e63d9eaeacb..08b0e257c81 100644 --- a/chromium/third_party/dawn/src/dawn_native/d3d12/PipelineLayoutD3D12.cpp +++ b/chromium/third_party/dawn/src/dawn_native/d3d12/PipelineLayoutD3D12.cpp @@ -23,10 +23,40 @@ using Microsoft::WRL::ComPtr; namespace dawn_native { namespace d3d12 { + namespace { + D3D12_SHADER_VISIBILITY ShaderVisibilityType(dawn::ShaderStage visibility) { + ASSERT(visibility != dawn::ShaderStage::None); + + if (visibility == dawn::ShaderStage::Vertex) { + return D3D12_SHADER_VISIBILITY_VERTEX; + } + + if (visibility == dawn::ShaderStage::Fragment) { + return D3D12_SHADER_VISIBILITY_PIXEL; + } + + // For compute or any two combination of stages, visibility must be ALL + return D3D12_SHADER_VISIBILITY_ALL; + } + + D3D12_ROOT_PARAMETER_TYPE RootParameterType(dawn::BindingType type) { + switch (type) { + case dawn::BindingType::UniformBuffer: + return D3D12_ROOT_PARAMETER_TYPE_CBV; + case dawn::BindingType::StorageBuffer: + return D3D12_ROOT_PARAMETER_TYPE_UAV; + case dawn::BindingType::SampledTexture: + case dawn::BindingType::Sampler: + case dawn::BindingType::StorageTexture: + case dawn::BindingType::ReadonlyStorageBuffer: + UNREACHABLE(); + } + } + } // anonymous namespace PipelineLayout::PipelineLayout(Device* device, const PipelineLayoutDescriptor* descriptor) : PipelineLayoutBase(device, descriptor) { - D3D12_ROOT_PARAMETER rootParameters[kMaxBindGroups * 2]; + D3D12_ROOT_PARAMETER rootParameters[kMaxBindGroups * 2 + kMaxDynamicBufferCount]; // A root parameter is one of these types union { @@ -46,6 +76,7 @@ namespace dawn_native { namespace d3d12 { for (uint32_t group : IterateBitSet(GetBindGroupLayoutsMask())) { const BindGroupLayout* bindGroupLayout = ToBackend(GetBindGroupLayout(group)); + const BindGroupLayout::LayoutBindingInfo& groupInfo = bindGroupLayout->GetBindingInfo(); // Set the root descriptor table parameter and copy ranges. Ranges are offset by the // bind group index Returns whether or not the parameter was set. A root parameter is @@ -81,6 +112,30 @@ namespace dawn_native { namespace d3d12 { bindGroupLayout->GetSamplerDescriptorRanges())) { mSamplerRootParameterInfo[group] = parameterIndex++; } + + // Get calculated shader register for root descriptors + const auto& shaderRegisters = bindGroupLayout->GetBindingOffsets(); + + // Init root descriptors in root signatures. + for (uint32_t dynamicBinding : IterateBitSet(groupInfo.dynamic)) { + D3D12_ROOT_PARAMETER* rootParameter = &rootParameters[parameterIndex]; + + // Setup root descriptor. + D3D12_ROOT_DESCRIPTOR rootDescriptor; + rootDescriptor.ShaderRegister = shaderRegisters[dynamicBinding]; + rootDescriptor.RegisterSpace = group; + + // Set root descriptors in root signatures. + rootParameter->Descriptor = rootDescriptor; + mDynamicRootParameterIndices[group][dynamicBinding] = parameterIndex++; + + // Set parameter types according to bind group layout descriptor. + rootParameter->ParameterType = RootParameterType(groupInfo.types[dynamicBinding]); + + // Set visibilities according to bind group layout descriptor. + rootParameter->ShaderVisibility = + ShaderVisibilityType(groupInfo.visibilities[dynamicBinding]); + } } D3D12_ROOT_SIGNATURE_DESC rootSignatureDescriptor; @@ -110,7 +165,14 @@ namespace dawn_native { namespace d3d12 { return mSamplerRootParameterInfo[group]; } - ComPtr<ID3D12RootSignature> PipelineLayout::GetRootSignature() { + ComPtr<ID3D12RootSignature> PipelineLayout::GetRootSignature() const { return mRootSignature; } + + uint32_t PipelineLayout::GetDynamicRootParameterIndex(uint32_t group, uint32_t binding) const { + ASSERT(group < kMaxBindGroups); + ASSERT(binding < kMaxBindingsPerGroup); + ASSERT(GetBindGroupLayout(group)->GetBindingInfo().dynamic[binding]); + return mDynamicRootParameterIndices[group][binding]; + } }} // namespace dawn_native::d3d12 diff --git a/chromium/third_party/dawn/src/dawn_native/d3d12/PipelineLayoutD3D12.h b/chromium/third_party/dawn/src/dawn_native/d3d12/PipelineLayoutD3D12.h index 90c1802a4cc..b2ee9e6bbdb 100644 --- a/chromium/third_party/dawn/src/dawn_native/d3d12/PipelineLayoutD3D12.h +++ b/chromium/third_party/dawn/src/dawn_native/d3d12/PipelineLayoutD3D12.h @@ -30,12 +30,16 @@ namespace dawn_native { namespace d3d12 { uint32_t GetCbvUavSrvRootParameterIndex(uint32_t group) const; uint32_t GetSamplerRootParameterIndex(uint32_t group) const; - ComPtr<ID3D12RootSignature> GetRootSignature(); + // Returns the index of the root parameter reserved for a dynamic buffer binding + uint32_t GetDynamicRootParameterIndex(uint32_t group, uint32_t binding) const; + + ComPtr<ID3D12RootSignature> GetRootSignature() const; private: std::array<uint32_t, kMaxBindGroups> mCbvUavSrvRootParameterInfo; std::array<uint32_t, kMaxBindGroups> mSamplerRootParameterInfo; - + std::array<std::array<uint32_t, kMaxBindingsPerGroup>, kMaxBindGroups> + mDynamicRootParameterIndices; ComPtr<ID3D12RootSignature> mRootSignature; }; diff --git a/chromium/third_party/dawn/src/dawn_native/d3d12/PlatformFunctions.cpp b/chromium/third_party/dawn/src/dawn_native/d3d12/PlatformFunctions.cpp index d9137365f6a..747cb68dbfa 100644 --- a/chromium/third_party/dawn/src/dawn_native/d3d12/PlatformFunctions.cpp +++ b/chromium/third_party/dawn/src/dawn_native/d3d12/PlatformFunctions.cpp @@ -44,7 +44,7 @@ namespace dawn_native { namespace d3d12 { "D3D12SerializeVersionedRootSignature", &error) || !mD3D12Lib.GetProc(&d3d12CreateVersionedRootSignatureDeserializer, "D3D12CreateVersionedRootSignatureDeserializer", &error)) { - return DAWN_CONTEXT_LOST_ERROR(error.c_str()); + return DAWN_DEVICE_LOST_ERROR(error.c_str()); } return {}; @@ -55,7 +55,7 @@ namespace dawn_native { namespace d3d12 { if (!mDXGILib.Open("dxgi.dll", &error) || !mDXGILib.GetProc(&dxgiGetDebugInterface1, "DXGIGetDebugInterface1", &error) || !mDXGILib.GetProc(&createDxgiFactory2, "CreateDXGIFactory2", &error)) { - return DAWN_CONTEXT_LOST_ERROR(error.c_str()); + return DAWN_DEVICE_LOST_ERROR(error.c_str()); } return {}; @@ -65,13 +65,13 @@ namespace dawn_native { namespace d3d12 { std::string error; if (!mD3DCompilerLib.Open("d3dcompiler_47.dll", &error) || !mD3DCompilerLib.GetProc(&d3dCompile, "D3DCompile", &error)) { - return DAWN_CONTEXT_LOST_ERROR(error.c_str()); + return DAWN_DEVICE_LOST_ERROR(error.c_str()); } return {}; } - bool PlatformFunctions::isPIXEventRuntimeLoaded() const { + bool PlatformFunctions::IsPIXEventRuntimeLoaded() const { return mPIXEventRuntimeLib.Valid(); } diff --git a/chromium/third_party/dawn/src/dawn_native/d3d12/PlatformFunctions.h b/chromium/third_party/dawn/src/dawn_native/d3d12/PlatformFunctions.h index ec51ba18c5c..f367bfce81d 100644 --- a/chromium/third_party/dawn/src/dawn_native/d3d12/PlatformFunctions.h +++ b/chromium/third_party/dawn/src/dawn_native/d3d12/PlatformFunctions.h @@ -35,7 +35,7 @@ namespace dawn_native { namespace d3d12 { ~PlatformFunctions(); MaybeError LoadFunctions(); - bool isPIXEventRuntimeLoaded() const; + bool IsPIXEventRuntimeLoaded() const; // Functions from d3d12.dll PFN_D3D12_CREATE_DEVICE d3d12CreateDevice = nullptr; diff --git a/chromium/third_party/dawn/src/dawn_native/d3d12/RenderPipelineD3D12.cpp b/chromium/third_party/dawn/src/dawn_native/d3d12/RenderPipelineD3D12.cpp index f06fd0ef753..92c286535af 100644 --- a/chromium/third_party/dawn/src/dawn_native/d3d12/RenderPipelineD3D12.cpp +++ b/chromium/third_party/dawn/src/dawn_native/d3d12/RenderPipelineD3D12.cpp @@ -304,21 +304,20 @@ namespace dawn_native { namespace d3d12 { PerStage<ComPtr<ID3DBlob>> compiledShader; ComPtr<ID3DBlob> errors; - dawn::ShaderStageBit renderStages = - dawn::ShaderStageBit::Vertex | dawn::ShaderStageBit::Fragment; + dawn::ShaderStage renderStages = dawn::ShaderStage::Vertex | dawn::ShaderStage::Fragment; for (auto stage : IterateStages(renderStages)) { const ShaderModule* module = nullptr; const char* entryPoint = nullptr; const char* compileTarget = nullptr; D3D12_SHADER_BYTECODE* shader = nullptr; switch (stage) { - case ShaderStage::Vertex: - module = ToBackend(descriptor->vertexStage->module); - entryPoint = descriptor->vertexStage->entryPoint; + case SingleShaderStage::Vertex: + module = ToBackend(descriptor->vertexStage.module); + entryPoint = descriptor->vertexStage.entryPoint; shader = &descriptorD3D12.VS; compileTarget = "vs_5_1"; break; - case ShaderStage::Fragment: + case SingleShaderStage::Fragment: module = ToBackend(descriptor->fragmentStage->module); entryPoint = descriptor->fragmentStage->entryPoint; shader = &descriptorD3D12.PS; diff --git a/chromium/third_party/dawn/src/dawn_native/d3d12/ResourceHeapD3D12.cpp b/chromium/third_party/dawn/src/dawn_native/d3d12/ResourceHeapD3D12.cpp new file mode 100644 index 00000000000..5aec4b3256b --- /dev/null +++ b/chromium/third_party/dawn/src/dawn_native/d3d12/ResourceHeapD3D12.cpp @@ -0,0 +1,30 @@ +// Copyright 2019 The Dawn Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "dawn_native/d3d12/ResourceHeapD3D12.h" +#include "dawn_native/d3d12/DeviceD3D12.h" + +namespace dawn_native { namespace d3d12 { + + ResourceHeap::ResourceHeap(ComPtr<ID3D12Resource> resource) : mResource(resource) { + } + + ComPtr<ID3D12Resource> ResourceHeap::GetD3D12Resource() const { + return mResource; + } + + D3D12_GPU_VIRTUAL_ADDRESS ResourceHeap::GetGPUPointer() const { + return mResource->GetGPUVirtualAddress(); + } +}} // namespace dawn_native::d3d12
\ No newline at end of file diff --git a/chromium/third_party/dawn/src/dawn_native/d3d12/ResourceHeapD3D12.h b/chromium/third_party/dawn/src/dawn_native/d3d12/ResourceHeapD3D12.h new file mode 100644 index 00000000000..18b342a691d --- /dev/null +++ b/chromium/third_party/dawn/src/dawn_native/d3d12/ResourceHeapD3D12.h @@ -0,0 +1,38 @@ +// Copyright 2019 The Dawn Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef DAWNNATIVE_D3D12_RESOURCEHEAPD3D12_H_ +#define DAWNNATIVE_D3D12_RESOURCEHEAPD3D12_H_ + +#include "dawn_native/ResourceHeap.h" +#include "dawn_native/d3d12/d3d12_platform.h" + +namespace dawn_native { namespace d3d12 { + + // Wrapper for physical memory used with or without a resource object. + class ResourceHeap : public ResourceHeapBase { + public: + ResourceHeap(ComPtr<ID3D12Resource> resource); + + ~ResourceHeap() = default; + + ComPtr<ID3D12Resource> GetD3D12Resource() const; + D3D12_GPU_VIRTUAL_ADDRESS GetGPUPointer() const; + + private: + ComPtr<ID3D12Resource> mResource; + }; +}} // namespace dawn_native::d3d12 + +#endif // DAWNNATIVE_D3D12_RESOURCEHEAPD3D12_H_
\ No newline at end of file diff --git a/chromium/third_party/dawn/src/dawn_native/d3d12/ShaderModuleD3D12.cpp b/chromium/third_party/dawn/src/dawn_native/d3d12/ShaderModuleD3D12.cpp index a01294c2006..4698459b3a4 100644 --- a/chromium/third_party/dawn/src/dawn_native/d3d12/ShaderModuleD3D12.cpp +++ b/chromium/third_party/dawn/src/dawn_native/d3d12/ShaderModuleD3D12.cpp @@ -20,7 +20,7 @@ #include "dawn_native/d3d12/DeviceD3D12.h" #include "dawn_native/d3d12/PipelineLayoutD3D12.h" -#include <spirv-cross/spirv_hlsl.hpp> +#include <spirv_hlsl.hpp> namespace dawn_native { namespace d3d12 { diff --git a/chromium/third_party/dawn/src/dawn_native/d3d12/StagingBufferD3D12.cpp b/chromium/third_party/dawn/src/dawn_native/d3d12/StagingBufferD3D12.cpp index da5db485394..cab3a18413e 100644 --- a/chromium/third_party/dawn/src/dawn_native/d3d12/StagingBufferD3D12.cpp +++ b/chromium/third_party/dawn/src/dawn_native/d3d12/StagingBufferD3D12.cpp @@ -14,7 +14,7 @@ #include "dawn_native/d3d12/StagingBufferD3D12.h" #include "dawn_native/d3d12/DeviceD3D12.h" -#include "dawn_native/d3d12/ResourceAllocator.h" +#include "dawn_native/d3d12/ResourceHeapD3D12.h" namespace dawn_native { namespace d3d12 { @@ -36,13 +36,12 @@ namespace dawn_native { namespace d3d12 { resourceDescriptor.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; resourceDescriptor.Flags = D3D12_RESOURCE_FLAG_NONE; - mUploadHeap = mDevice->GetResourceAllocator()->Allocate( - D3D12_HEAP_TYPE_UPLOAD, resourceDescriptor, D3D12_RESOURCE_STATE_GENERIC_READ); + DAWN_TRY_ASSIGN(mUploadHeap, mDevice->AllocateMemory( + D3D12_HEAP_TYPE_UPLOAD, resourceDescriptor, + D3D12_RESOURCE_STATE_GENERIC_READ, D3D12_HEAP_FLAG_NONE)); - // TODO(bryan.bernhart@intel.com): Record the GPU pointer for generic non-upload usage. - - if (FAILED(mUploadHeap->Map(0, nullptr, &mMappedPointer))) { - return DAWN_CONTEXT_LOST_ERROR("Unable to map staging buffer."); + if (FAILED(GetResource()->Map(0, nullptr, &mMappedPointer))) { + return DAWN_DEVICE_LOST_ERROR("Unable to map staging buffer."); } return {}; @@ -50,14 +49,14 @@ namespace dawn_native { namespace d3d12 { StagingBuffer::~StagingBuffer() { // Invalidate the CPU virtual address & flush cache (if needed). - mUploadHeap->Unmap(0, nullptr); + GetResource()->Unmap(0, nullptr); mMappedPointer = nullptr; - mDevice->GetResourceAllocator()->Release(mUploadHeap); + mDevice->DeallocateMemory(mUploadHeap); } ID3D12Resource* StagingBuffer::GetResource() const { - return mUploadHeap.Get(); + return ToBackend(mUploadHeap.GetResourceHeap())->GetD3D12Resource().Get(); } -}} // namespace dawn_native::d3d12
\ No newline at end of file +}} // namespace dawn_native::d3d12 diff --git a/chromium/third_party/dawn/src/dawn_native/d3d12/StagingBufferD3D12.h b/chromium/third_party/dawn/src/dawn_native/d3d12/StagingBufferD3D12.h index b689df4a956..633be53c32f 100644 --- a/chromium/third_party/dawn/src/dawn_native/d3d12/StagingBufferD3D12.h +++ b/chromium/third_party/dawn/src/dawn_native/d3d12/StagingBufferD3D12.h @@ -15,6 +15,7 @@ #ifndef DAWNNATIVE_STAGINGBUFFERD3D12_H_ #define DAWNNATIVE_STAGINGBUFFERD3D12_H_ +#include "dawn_native/ResourceMemoryAllocation.h" #include "dawn_native/StagingBuffer.h" #include "dawn_native/d3d12/d3d12_platform.h" @@ -33,7 +34,7 @@ namespace dawn_native { namespace d3d12 { private: Device* mDevice; - ComPtr<ID3D12Resource> mUploadHeap; + ResourceMemoryAllocation mUploadHeap; }; }} // namespace dawn_native::d3d12 diff --git a/chromium/third_party/dawn/src/dawn_native/d3d12/SwapChainD3D12.cpp b/chromium/third_party/dawn/src/dawn_native/d3d12/SwapChainD3D12.cpp index f02a79e30f1..0dffc29481f 100644 --- a/chromium/third_party/dawn/src/dawn_native/d3d12/SwapChainD3D12.cpp +++ b/chromium/third_party/dawn/src/dawn_native/d3d12/SwapChainD3D12.cpp @@ -28,8 +28,8 @@ namespace dawn_native { namespace d3d12 { wsiContext.device = reinterpret_cast<DawnDevice>(GetDevice()); im.Init(im.userData, &wsiContext); - ASSERT(im.textureUsage != DAWN_TEXTURE_USAGE_BIT_NONE); - mTextureUsage = static_cast<dawn::TextureUsageBit>(im.textureUsage); + ASSERT(im.textureUsage != DAWN_TEXTURE_USAGE_NONE); + mTextureUsage = static_cast<dawn::TextureUsage>(im.textureUsage); } SwapChain::~SwapChain() { @@ -40,7 +40,7 @@ namespace dawn_native { namespace d3d12 { DawnSwapChainNextTexture next = {}; DawnSwapChainError error = im.GetNextTexture(im.userData, &next); if (error) { - GetDevice()->HandleError(error); + GetDevice()->HandleError(dawn::ErrorType::Unknown, error); return nullptr; } diff --git a/chromium/third_party/dawn/src/dawn_native/d3d12/SwapChainD3D12.h b/chromium/third_party/dawn/src/dawn_native/d3d12/SwapChainD3D12.h index 1ca8ded3f3f..833ba48b81c 100644 --- a/chromium/third_party/dawn/src/dawn_native/d3d12/SwapChainD3D12.h +++ b/chromium/third_party/dawn/src/dawn_native/d3d12/SwapChainD3D12.h @@ -30,7 +30,7 @@ namespace dawn_native { namespace d3d12 { TextureBase* GetNextTextureImpl(const TextureDescriptor* descriptor) override; void OnBeforePresent(TextureBase* texture) override; - dawn::TextureUsageBit mTextureUsage; + dawn::TextureUsage mTextureUsage; }; }} // namespace dawn_native::d3d12 diff --git a/chromium/third_party/dawn/src/dawn_native/d3d12/TextureD3D12.cpp b/chromium/third_party/dawn/src/dawn_native/d3d12/TextureD3D12.cpp index afe10f35778..dbc88642ab3 100644 --- a/chromium/third_party/dawn/src/dawn_native/d3d12/TextureD3D12.cpp +++ b/chromium/third_party/dawn/src/dawn_native/d3d12/TextureD3D12.cpp @@ -14,35 +14,43 @@ #include "dawn_native/d3d12/TextureD3D12.h" +#include "common/Constants.h" +#include "common/Math.h" +#include "dawn_native/DynamicUploader.h" +#include "dawn_native/Error.h" +#include "dawn_native/d3d12/BufferD3D12.h" #include "dawn_native/d3d12/DescriptorHeapAllocator.h" #include "dawn_native/d3d12/DeviceD3D12.h" #include "dawn_native/d3d12/ResourceAllocator.h" +#include "dawn_native/d3d12/StagingBufferD3D12.h" +#include "dawn_native/d3d12/TextureCopySplitter.h" +#include "dawn_native/d3d12/UtilsD3D12.h" namespace dawn_native { namespace d3d12 { namespace { - D3D12_RESOURCE_STATES D3D12TextureUsage(dawn::TextureUsageBit usage, const Format& format) { + D3D12_RESOURCE_STATES D3D12TextureUsage(dawn::TextureUsage usage, const Format& format) { D3D12_RESOURCE_STATES resourceState = D3D12_RESOURCE_STATE_COMMON; // Present is an exclusive flag. - if (usage & dawn::TextureUsageBit::Present) { + if (usage & dawn::TextureUsage::Present) { return D3D12_RESOURCE_STATE_PRESENT; } - if (usage & dawn::TextureUsageBit::CopySrc) { + if (usage & dawn::TextureUsage::CopySrc) { resourceState |= D3D12_RESOURCE_STATE_COPY_SOURCE; } - if (usage & dawn::TextureUsageBit::CopyDst) { + if (usage & dawn::TextureUsage::CopyDst) { resourceState |= D3D12_RESOURCE_STATE_COPY_DEST; } - if (usage & dawn::TextureUsageBit::Sampled) { + if (usage & dawn::TextureUsage::Sampled) { resourceState |= (D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE | D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE); } - if (usage & dawn::TextureUsageBit::Storage) { + if (usage & dawn::TextureUsage::Storage) { resourceState |= D3D12_RESOURCE_STATE_UNORDERED_ACCESS; } - if (usage & dawn::TextureUsageBit::OutputAttachment) { + if (usage & dawn::TextureUsage::OutputAttachment) { if (format.HasDepthOrStencil()) { resourceState |= D3D12_RESOURCE_STATE_DEPTH_WRITE; } else { @@ -53,12 +61,12 @@ namespace dawn_native { namespace d3d12 { return resourceState; } - D3D12_RESOURCE_FLAGS D3D12ResourceFlags(dawn::TextureUsageBit usage, + D3D12_RESOURCE_FLAGS D3D12ResourceFlags(dawn::TextureUsage usage, const Format& format, bool isMultisampledTexture) { D3D12_RESOURCE_FLAGS flags = D3D12_RESOURCE_FLAG_NONE; - if (usage & dawn::TextureUsageBit::Storage) { + if (usage & dawn::TextureUsage::Storage) { flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; } @@ -70,7 +78,7 @@ namespace dawn_native { namespace d3d12 { // flag is invalid. // TODO(natlee@microsoft.com, jiawei.shao@intel.com): do not require render target for // lazy clearing. - if ((usage & dawn::TextureUsageBit::OutputAttachment) || isMultisampledTexture || + if ((usage & dawn::TextureUsage::OutputAttachment) || isMultisampledTexture || !format.isCompressed) { if (format.HasDepthOrStencil()) { flags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL; @@ -92,7 +100,6 @@ namespace dawn_native { namespace d3d12 { UNREACHABLE(); } } - } // namespace DXGI_FORMAT D3D12TextureFormat(dawn::TextureFormat format) { @@ -106,10 +113,6 @@ namespace dawn_native { namespace d3d12 { case dawn::TextureFormat::R8Sint: return DXGI_FORMAT_R8_SINT; - case dawn::TextureFormat::R16Unorm: - return DXGI_FORMAT_R16_UNORM; - case dawn::TextureFormat::R16Snorm: - return DXGI_FORMAT_R16_SNORM; case dawn::TextureFormat::R16Uint: return DXGI_FORMAT_R16_UINT; case dawn::TextureFormat::R16Sint: @@ -131,10 +134,6 @@ namespace dawn_native { namespace d3d12 { return DXGI_FORMAT_R32_SINT; case dawn::TextureFormat::R32Float: return DXGI_FORMAT_R32_FLOAT; - case dawn::TextureFormat::RG16Unorm: - return DXGI_FORMAT_R16G16_UNORM; - case dawn::TextureFormat::RG16Snorm: - return DXGI_FORMAT_R16G16_SNORM; case dawn::TextureFormat::RG16Uint: return DXGI_FORMAT_R16G16_UINT; case dawn::TextureFormat::RG16Sint: @@ -166,10 +165,6 @@ namespace dawn_native { namespace d3d12 { return DXGI_FORMAT_R32G32_SINT; case dawn::TextureFormat::RG32Float: return DXGI_FORMAT_R32G32_FLOAT; - case dawn::TextureFormat::RGBA16Unorm: - return DXGI_FORMAT_R16G16B16A16_UNORM; - case dawn::TextureFormat::RGBA16Snorm: - return DXGI_FORMAT_R16G16B16A16_SNORM; case dawn::TextureFormat::RGBA16Uint: return DXGI_FORMAT_R16G16B16A16_UINT; case dawn::TextureFormat::RGBA16Sint: @@ -225,6 +220,56 @@ namespace dawn_native { namespace d3d12 { } } + MaybeError ValidateTextureDescriptorCanBeWrapped(const TextureDescriptor* descriptor) { + if (descriptor->dimension != dawn::TextureDimension::e2D) { + return DAWN_VALIDATION_ERROR("Texture must be 2D"); + } + + if (descriptor->mipLevelCount != 1) { + return DAWN_VALIDATION_ERROR("Mip level count must be 1"); + } + + if (descriptor->arrayLayerCount != 1) { + return DAWN_VALIDATION_ERROR("Array layer count must be 1"); + } + + if (descriptor->sampleCount != 1) { + return DAWN_VALIDATION_ERROR("Sample count must be 1"); + } + + return {}; + } + + MaybeError ValidateD3D12TextureCanBeWrapped(ID3D12Resource* d3d12Resource, + const TextureDescriptor* dawnDescriptor) { + const D3D12_RESOURCE_DESC d3dDescriptor = d3d12Resource->GetDesc(); + if ((dawnDescriptor->size.width != d3dDescriptor.Width) || + (dawnDescriptor->size.height != d3dDescriptor.Height) || + (dawnDescriptor->size.depth != 1)) { + return DAWN_VALIDATION_ERROR("D3D12 texture size doesn't match descriptor"); + } + + const DXGI_FORMAT dxgiFormatFromDescriptor = D3D12TextureFormat(dawnDescriptor->format); + if (dxgiFormatFromDescriptor != d3dDescriptor.Format) { + return DAWN_VALIDATION_ERROR( + "D3D12 texture format must be compatible with descriptor format."); + } + + if (d3dDescriptor.MipLevels != 1) { + return DAWN_VALIDATION_ERROR("D3D12 texture number of miplevels must be 1."); + } + + if (d3dDescriptor.DepthOrArraySize != 1) { + return DAWN_VALIDATION_ERROR("D3D12 texture array size must be 1."); + } + + // Shared textures cannot be multi-sample so no need to check those. + ASSERT(d3dDescriptor.SampleDesc.Count == 1); + ASSERT(d3dDescriptor.SampleDesc.Quality == 0); + + return {}; + } + Texture::Texture(Device* device, const TextureDescriptor* descriptor) : TextureBase(device, descriptor, TextureState::OwnedInternal) { D3D12_RESOURCE_DESC resourceDescriptor; @@ -251,45 +296,9 @@ namespace dawn_native { namespace d3d12 { D3D12_RESOURCE_STATE_COMMON); if (device->IsToggleEnabled(Toggle::NonzeroClearResourcesOnCreationForTesting)) { - DescriptorHeapAllocator* descriptorHeapAllocator = device->GetDescriptorHeapAllocator(); - if (GetFormat().HasDepthOrStencil()) { - TransitionUsageNow(device->GetPendingCommandList(), - D3D12_RESOURCE_STATE_DEPTH_WRITE); - DescriptorHeapHandle dsvHeap = - descriptorHeapAllocator->AllocateCPUHeap(D3D12_DESCRIPTOR_HEAP_TYPE_DSV, 1); - D3D12_CPU_DESCRIPTOR_HANDLE dsvHandle = dsvHeap.GetCPUHandle(0); - D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = GetDSVDescriptor(0); - device->GetD3D12Device()->CreateDepthStencilView(mResource.Get(), &dsvDesc, - dsvHandle); - - D3D12_CLEAR_FLAGS clearFlags = {}; - if (GetFormat().HasDepth()) { - clearFlags |= D3D12_CLEAR_FLAG_DEPTH; - } - if (GetFormat().HasStencil()) { - clearFlags |= D3D12_CLEAR_FLAG_STENCIL; - } - - device->GetPendingCommandList()->ClearDepthStencilView(dsvHandle, clearFlags, 1.0f, - 1u, 0, nullptr); - } else { - TransitionUsageNow(device->GetPendingCommandList(), - D3D12_RESOURCE_STATE_RENDER_TARGET); - DescriptorHeapHandle rtvHeap = - descriptorHeapAllocator->AllocateCPUHeap(D3D12_DESCRIPTOR_HEAP_TYPE_RTV, 1); - D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = rtvHeap.GetCPUHandle(0); - - const float clearColor[4] = {1.0f, 1.0f, 1.0f, 1.0f}; - // TODO(natlee@microsoft.com): clear all array layers for 2D array textures - for (int i = 0; i < resourceDescriptor.MipLevels; i++) { - D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = - GetRTVDescriptor(i, 0, GetArrayLayers()); - device->GetD3D12Device()->CreateRenderTargetView(mResource.Get(), &rtvDesc, - rtvHandle); - device->GetPendingCommandList()->ClearRenderTargetView(rtvHandle, clearColor, 0, - nullptr); - } - } + device->ConsumedError(ClearTexture(device->GetPendingCommandList(), 0, + GetNumMipLevels(), 0, GetArrayLayers(), + TextureBase::ClearValue::NonZero)); } } @@ -298,6 +307,8 @@ namespace dawn_native { namespace d3d12 { const TextureDescriptor* descriptor, ID3D12Resource* nativeTexture) : TextureBase(device, descriptor, TextureState::OwnedExternal), mResource(nativeTexture) { + SetIsSubresourceContentInitialized(0, descriptor->mipLevelCount, 0, + descriptor->arrayLayerCount); } Texture::~Texture() { @@ -331,7 +342,7 @@ namespace dawn_native { namespace d3d12 { // ResourceBarrier call. Failing to do so will cause the tracked state to become invalid and can // cause subsequent errors. bool Texture::TransitionUsageAndGetResourceBarrier(D3D12_RESOURCE_BARRIER* barrier, - dawn::TextureUsageBit newUsage) { + dawn::TextureUsage newUsage) { return TransitionUsageAndGetResourceBarrier(barrier, D3D12TextureUsage(newUsage, GetFormat())); } @@ -407,7 +418,7 @@ namespace dawn_native { namespace d3d12 { } void Texture::TransitionUsageNow(ComPtr<ID3D12GraphicsCommandList> commandList, - dawn::TextureUsageBit usage) { + dawn::TextureUsage usage) { TransitionUsageNow(commandList, D3D12TextureUsage(usage, GetFormat())); } @@ -464,55 +475,107 @@ namespace dawn_native { namespace d3d12 { return dsvDesc; } - void Texture::ClearTexture(ComPtr<ID3D12GraphicsCommandList> commandList, - uint32_t baseMipLevel, - uint32_t levelCount, - uint32_t baseArrayLayer, - uint32_t layerCount) { + MaybeError Texture::ClearTexture(ComPtr<ID3D12GraphicsCommandList> commandList, + uint32_t baseMipLevel, + uint32_t levelCount, + uint32_t baseArrayLayer, + uint32_t layerCount, + TextureBase::ClearValue clearValue) { // TODO(jiawei.shao@intel.com): initialize the textures in compressed formats with copies. if (GetFormat().isCompressed) { SetIsSubresourceContentInitialized(baseMipLevel, levelCount, baseArrayLayer, layerCount); - return; + return {}; } Device* device = ToBackend(GetDevice()); DescriptorHeapAllocator* descriptorHeapAllocator = device->GetDescriptorHeapAllocator(); + uint8_t clearColor = (clearValue == TextureBase::ClearValue::Zero) ? 0 : 1; + if (GetFormat().isRenderable) { + if (GetFormat().HasDepthOrStencil()) { + TransitionUsageNow(commandList, D3D12_RESOURCE_STATE_DEPTH_WRITE); + DescriptorHeapHandle dsvHeap = + descriptorHeapAllocator->AllocateCPUHeap(D3D12_DESCRIPTOR_HEAP_TYPE_DSV, 1); + D3D12_CPU_DESCRIPTOR_HANDLE dsvHandle = dsvHeap.GetCPUHandle(0); + D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = GetDSVDescriptor(baseMipLevel); + device->GetD3D12Device()->CreateDepthStencilView(mResource.Get(), &dsvDesc, + dsvHandle); - if (GetFormat().HasDepthOrStencil()) { - TransitionUsageNow(commandList, D3D12_RESOURCE_STATE_DEPTH_WRITE); - DescriptorHeapHandle dsvHeap = - descriptorHeapAllocator->AllocateCPUHeap(D3D12_DESCRIPTOR_HEAP_TYPE_DSV, 1); - D3D12_CPU_DESCRIPTOR_HANDLE dsvHandle = dsvHeap.GetCPUHandle(0); - D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = GetDSVDescriptor(baseMipLevel); - device->GetD3D12Device()->CreateDepthStencilView(mResource.Get(), &dsvDesc, dsvHandle); - - D3D12_CLEAR_FLAGS clearFlags = {}; - if (GetFormat().HasDepth()) { - clearFlags |= D3D12_CLEAR_FLAG_DEPTH; - } - if (GetFormat().HasStencil()) { - clearFlags |= D3D12_CLEAR_FLAG_STENCIL; - } + D3D12_CLEAR_FLAGS clearFlags = {}; + if (GetFormat().HasDepth()) { + clearFlags |= D3D12_CLEAR_FLAG_DEPTH; + } + if (GetFormat().HasStencil()) { + clearFlags |= D3D12_CLEAR_FLAG_STENCIL; + } + + commandList->ClearDepthStencilView(dsvHandle, clearFlags, clearColor, clearColor, 0, + nullptr); + } else { + TransitionUsageNow(commandList, D3D12_RESOURCE_STATE_RENDER_TARGET); + DescriptorHeapHandle rtvHeap = + descriptorHeapAllocator->AllocateCPUHeap(D3D12_DESCRIPTOR_HEAP_TYPE_RTV, 1); + D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = rtvHeap.GetCPUHandle(0); + const float clearColorRGBA[4] = {clearColor, clearColor, clearColor, clearColor}; - commandList->ClearDepthStencilView(dsvHandle, clearFlags, 0.0f, 0u, 0, nullptr); + // TODO(natlee@microsoft.com): clear all array layers for 2D array textures + for (uint32_t i = baseMipLevel; i < baseMipLevel + levelCount; i++) { + D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = + GetRTVDescriptor(i, baseArrayLayer, layerCount); + device->GetD3D12Device()->CreateRenderTargetView(mResource.Get(), &rtvDesc, + rtvHandle); + commandList->ClearRenderTargetView(rtvHandle, clearColorRGBA, 0, nullptr); + } + } } else { - TransitionUsageNow(commandList, D3D12_RESOURCE_STATE_RENDER_TARGET); - DescriptorHeapHandle rtvHeap = - descriptorHeapAllocator->AllocateCPUHeap(D3D12_DESCRIPTOR_HEAP_TYPE_RTV, 1); - D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = rtvHeap.GetCPUHandle(0); - const float clearColor[4] = {0.0f, 0.0f, 0.0f, 0.0f}; - - // TODO(natlee@microsoft.com): clear all array layers for 2D array textures - for (uint32_t i = baseMipLevel; i < baseMipLevel + levelCount; i++) { - D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = - GetRTVDescriptor(i, baseArrayLayer, layerCount); - device->GetD3D12Device()->CreateRenderTargetView(mResource.Get(), &rtvDesc, - rtvHandle); - commandList->ClearRenderTargetView(rtvHandle, clearColor, 0, nullptr); + // TODO(natlee@microsoft.com): test compressed textures are cleared + // create temp buffer with clear color to copy to the texture image + uint32_t rowPitch = + Align((GetSize().width / GetFormat().blockWidth) * GetFormat().blockByteSize, + kTextureRowPitchAlignment); + uint64_t bufferSize64 = rowPitch * (GetSize().height / GetFormat().blockHeight); + if (bufferSize64 > std::numeric_limits<uint32_t>::max()) { + return DAWN_OUT_OF_MEMORY_ERROR("Unable to allocate buffer."); } + uint32_t bufferSize = static_cast<uint32_t>(bufferSize64); + DynamicUploader* uploader = nullptr; + DAWN_TRY_ASSIGN(uploader, device->GetDynamicUploader()); + UploadHandle uploadHandle; + DAWN_TRY_ASSIGN(uploadHandle, uploader->Allocate(bufferSize)); + std::fill(reinterpret_cast<uint32_t*>(uploadHandle.mappedBuffer), + reinterpret_cast<uint32_t*>(uploadHandle.mappedBuffer + bufferSize), + clearColor); + + TransitionUsageNow(commandList, D3D12_RESOURCE_STATE_COPY_DEST); + + // compute d3d12 texture copy locations for texture and buffer + Extent3D copySize = {GetSize().width, GetSize().height, 1}; + TextureCopySplit copySplit = ComputeTextureCopySplit( + {0, 0, 0}, copySize, GetFormat(), uploadHandle.startOffset, rowPitch, 0); + D3D12_TEXTURE_COPY_LOCATION textureLocation = + ComputeTextureCopyLocationForTexture(this, baseMipLevel, baseArrayLayer); + for (uint32_t i = 0; i < copySplit.count; ++i) { + TextureCopySplit::CopyInfo& info = copySplit.copies[i]; + + D3D12_TEXTURE_COPY_LOCATION bufferLocation = + ComputeBufferLocationForCopyTextureRegion( + this, ToBackend(uploadHandle.stagingBuffer)->GetResource(), info.bufferSize, + copySplit.offset, rowPitch); + D3D12_BOX sourceRegion = + ComputeD3D12BoxFromOffsetAndSize(info.bufferOffset, info.copySize); + + // copy the buffer filled with clear color to the texture + commandList->CopyTextureRegion(&textureLocation, info.textureOffset.x, + info.textureOffset.y, info.textureOffset.z, + &bufferLocation, &sourceRegion); + } + } + if (clearValue == TextureBase::ClearValue::Zero) { + SetIsSubresourceContentInitialized(baseMipLevel, levelCount, baseArrayLayer, + layerCount); + GetDevice()->IncrementLazyClearCountForTesting(); } - SetIsSubresourceContentInitialized(baseMipLevel, levelCount, baseArrayLayer, layerCount); + return {}; } void Texture::EnsureSubresourceContentInitialized(ComPtr<ID3D12GraphicsCommandList> commandList, @@ -527,7 +590,9 @@ namespace dawn_native { namespace d3d12 { layerCount)) { // If subresource has not been initialized, clear it to black as it could contain // dirty bits from recycled memory - ClearTexture(commandList, baseMipLevel, levelCount, baseArrayLayer, layerCount); + GetDevice()->ConsumedError(ClearTexture(commandList, baseMipLevel, levelCount, + baseArrayLayer, layerCount, + TextureBase::ClearValue::Zero)); } } diff --git a/chromium/third_party/dawn/src/dawn_native/d3d12/TextureD3D12.h b/chromium/third_party/dawn/src/dawn_native/d3d12/TextureD3D12.h index 787c5b19c64..af32dd3cf84 100644 --- a/chromium/third_party/dawn/src/dawn_native/d3d12/TextureD3D12.h +++ b/chromium/third_party/dawn/src/dawn_native/d3d12/TextureD3D12.h @@ -25,6 +25,9 @@ namespace dawn_native { namespace d3d12 { class Device; DXGI_FORMAT D3D12TextureFormat(dawn::TextureFormat format); + MaybeError ValidateD3D12TextureCanBeWrapped(ID3D12Resource* d3d12Resource, + const TextureDescriptor* descriptor); + MaybeError ValidateTextureDescriptorCanBeWrapped(const TextureDescriptor* descriptor); class Texture : public TextureBase { public: @@ -35,9 +38,9 @@ namespace dawn_native { namespace d3d12 { DXGI_FORMAT GetD3D12Format() const; ID3D12Resource* GetD3D12Resource() const; bool TransitionUsageAndGetResourceBarrier(D3D12_RESOURCE_BARRIER* barrier, - dawn::TextureUsageBit newUsage); + dawn::TextureUsage newUsage); void TransitionUsageNow(ComPtr<ID3D12GraphicsCommandList> commandList, - dawn::TextureUsageBit usage); + dawn::TextureUsage usage); void TransitionUsageNow(ComPtr<ID3D12GraphicsCommandList> commandList, D3D12_RESOURCE_STATES newState); @@ -54,11 +57,12 @@ namespace dawn_native { namespace d3d12 { private: // Dawn API void DestroyImpl() override; - void ClearTexture(ComPtr<ID3D12GraphicsCommandList> commandList, - uint32_t baseMipLevel, - uint32_t levelCount, - uint32_t baseArrayLayer, - uint32_t layerCount); + MaybeError ClearTexture(ComPtr<ID3D12GraphicsCommandList> commandList, + uint32_t baseMipLevel, + uint32_t levelCount, + uint32_t baseArrayLayer, + uint32_t layerCount, + TextureBase::ClearValue clearValue); UINT16 GetDepthOrArraySize(); diff --git a/chromium/third_party/dawn/src/dawn_native/d3d12/UtilsD3D12.cpp b/chromium/third_party/dawn/src/dawn_native/d3d12/UtilsD3D12.cpp index 864605c871e..5db58905547 100644 --- a/chromium/third_party/dawn/src/dawn_native/d3d12/UtilsD3D12.cpp +++ b/chromium/third_party/dawn/src/dawn_native/d3d12/UtilsD3D12.cpp @@ -41,4 +41,44 @@ namespace dawn_native { namespace d3d12 { } } + D3D12_TEXTURE_COPY_LOCATION ComputeTextureCopyLocationForTexture(const Texture* texture, + uint32_t level, + uint32_t slice) { + D3D12_TEXTURE_COPY_LOCATION copyLocation; + copyLocation.pResource = texture->GetD3D12Resource(); + copyLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; + copyLocation.SubresourceIndex = texture->GetSubresourceIndex(level, slice); + + return copyLocation; + } + + D3D12_TEXTURE_COPY_LOCATION ComputeBufferLocationForCopyTextureRegion( + const Texture* texture, + ID3D12Resource* bufferResource, + const Extent3D& bufferSize, + const uint64_t offset, + const uint32_t rowPitch) { + D3D12_TEXTURE_COPY_LOCATION bufferLocation; + bufferLocation.pResource = bufferResource; + bufferLocation.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; + bufferLocation.PlacedFootprint.Offset = offset; + bufferLocation.PlacedFootprint.Footprint.Format = texture->GetD3D12Format(); + bufferLocation.PlacedFootprint.Footprint.Width = bufferSize.width; + bufferLocation.PlacedFootprint.Footprint.Height = bufferSize.height; + bufferLocation.PlacedFootprint.Footprint.Depth = bufferSize.depth; + bufferLocation.PlacedFootprint.Footprint.RowPitch = rowPitch; + return bufferLocation; + } + + D3D12_BOX ComputeD3D12BoxFromOffsetAndSize(const Origin3D& offset, const Extent3D& copySize) { + D3D12_BOX sourceRegion; + sourceRegion.left = offset.x; + sourceRegion.top = offset.y; + sourceRegion.front = offset.z; + sourceRegion.right = offset.x + copySize.width; + sourceRegion.bottom = offset.y + copySize.height; + sourceRegion.back = offset.z + copySize.depth; + return sourceRegion; + } + }} // namespace dawn_native::d3d12 diff --git a/chromium/third_party/dawn/src/dawn_native/d3d12/UtilsD3D12.h b/chromium/third_party/dawn/src/dawn_native/d3d12/UtilsD3D12.h index f47a360fc45..2566a42d9b1 100644 --- a/chromium/third_party/dawn/src/dawn_native/d3d12/UtilsD3D12.h +++ b/chromium/third_party/dawn/src/dawn_native/d3d12/UtilsD3D12.h @@ -15,6 +15,9 @@ #ifndef DAWNNATIVE_D3D12_UTILSD3D12_H_ #define DAWNNATIVE_D3D12_UTILSD3D12_H_ +#include "dawn_native/d3d12/BufferD3D12.h" +#include "dawn_native/d3d12/TextureCopySplitter.h" +#include "dawn_native/d3d12/TextureD3D12.h" #include "dawn_native/d3d12/d3d12_platform.h" #include "dawn_native/dawn_platform.h" @@ -22,6 +25,18 @@ namespace dawn_native { namespace d3d12 { D3D12_COMPARISON_FUNC ToD3D12ComparisonFunc(dawn::CompareFunction func); + D3D12_TEXTURE_COPY_LOCATION ComputeTextureCopyLocationForTexture(const Texture* texture, + uint32_t level, + uint32_t slice); + + D3D12_TEXTURE_COPY_LOCATION ComputeBufferLocationForCopyTextureRegion( + const Texture* texture, + ID3D12Resource* bufferResource, + const Extent3D& bufferSize, + const uint64_t offset, + const uint32_t rowPitch); + D3D12_BOX ComputeD3D12BoxFromOffsetAndSize(const Origin3D& offset, const Extent3D& copySize); + }} // namespace dawn_native::d3d12 #endif // DAWNNATIVE_D3D12_UTILSD3D12_H_ diff --git a/chromium/third_party/dawn/src/dawn_native/dawn_platform.h b/chromium/third_party/dawn/src/dawn_native/dawn_platform.h index d456d326db7..795c371225c 100644 --- a/chromium/third_party/dawn/src/dawn_native/dawn_platform.h +++ b/chromium/third_party/dawn/src/dawn_native/dawn_platform.h @@ -15,7 +15,7 @@ #ifndef DAWNNATIVE_DAWNPLATFORM_H_ #define DAWNNATIVE_DAWNPLATFORM_H_ -// Use cawncpp to have the enum and bitfield definitions +// Use dawncpp to have the enum and bitfield definitions #include <dawn/dawncpp.h> // Use our autogenerated version of the dawn structures that point to dawn_native object types diff --git a/chromium/third_party/dawn/src/dawn_native/metal/BackendMTL.mm b/chromium/third_party/dawn/src/dawn_native/metal/BackendMTL.mm index e09976d5588..80287ddbb34 100644 --- a/chromium/third_party/dawn/src/dawn_native/metal/BackendMTL.mm +++ b/chromium/third_party/dawn/src/dawn_native/metal/BackendMTL.mm @@ -52,7 +52,7 @@ namespace dawn_native { namespace metal { } if (vendorId == 0) { - return DAWN_CONTEXT_LOST_ERROR("Failed to find vendor id with the device"); + return DAWN_DEVICE_LOST_ERROR("Failed to find vendor id with the device"); } // Set vendor id with 0 @@ -102,7 +102,7 @@ namespace dawn_native { namespace metal { // Get a matching dictionary for the IOGraphicsAccelerator2 CFMutableDictionaryRef matchingDict = IORegistryEntryIDMatching([device registryID]); if (matchingDict == nullptr) { - return DAWN_CONTEXT_LOST_ERROR("Failed to create the matching dict for the device"); + return DAWN_DEVICE_LOST_ERROR("Failed to create the matching dict for the device"); } // IOServiceGetMatchingService will consume the reference on the matching dictionary, @@ -110,7 +110,7 @@ namespace dawn_native { namespace metal { io_registry_entry_t acceleratorEntry = IOServiceGetMatchingService(kIOMasterPortDefault, matchingDict); if (acceleratorEntry == IO_OBJECT_NULL) { - return DAWN_CONTEXT_LOST_ERROR( + return DAWN_DEVICE_LOST_ERROR( "Failed to get the IO registry entry for the accelerator"); } @@ -119,8 +119,7 @@ namespace dawn_native { namespace metal { if (IORegistryEntryGetParentEntry(acceleratorEntry, kIOServicePlane, &deviceEntry) != kIOReturnSuccess) { IOObjectRelease(acceleratorEntry); - return DAWN_CONTEXT_LOST_ERROR( - "Failed to get the IO registry entry for the device"); + return DAWN_DEVICE_LOST_ERROR("Failed to get the IO registry entry for the device"); } ASSERT(deviceEntry != IO_OBJECT_NULL); @@ -172,6 +171,8 @@ namespace dawn_native { namespace metal { } else { mDeviceType = DeviceType::DiscreteGPU; } + + InitializeSupportedExtensions(); } ~Adapter() override { @@ -182,6 +183,11 @@ namespace dawn_native { namespace metal { ResultOrError<DeviceBase*> CreateDeviceImpl(const DeviceDescriptor* descriptor) override { return {new Device(this, mDevice, descriptor)}; } + void InitializeSupportedExtensions() { + if ([mDevice supportsFeatureSet:MTLFeatureSet_macOS_GPUFamily1_v1]) { + mSupportedExtensions.EnableExtension(Extension::TextureCompressionBC); + } + } id<MTLDevice> mDevice = nil; }; diff --git a/chromium/third_party/dawn/src/dawn_native/metal/BufferMTL.h b/chromium/third_party/dawn/src/dawn_native/metal/BufferMTL.h index c4395b2d40c..f05f38e7515 100644 --- a/chromium/third_party/dawn/src/dawn_native/metal/BufferMTL.h +++ b/chromium/third_party/dawn/src/dawn_native/metal/BufferMTL.h @@ -29,7 +29,7 @@ namespace dawn_native { namespace metal { Buffer(Device* device, const BufferDescriptor* descriptor); ~Buffer(); - id<MTLBuffer> GetMTLBuffer(); + id<MTLBuffer> GetMTLBuffer() const; void OnMapCommandSerialFinished(uint32_t mapSerial, bool isWrite); diff --git a/chromium/third_party/dawn/src/dawn_native/metal/BufferMTL.mm b/chromium/third_party/dawn/src/dawn_native/metal/BufferMTL.mm index d4cb82f1f1e..dfe96f3e90a 100644 --- a/chromium/third_party/dawn/src/dawn_native/metal/BufferMTL.mm +++ b/chromium/third_party/dawn/src/dawn_native/metal/BufferMTL.mm @@ -21,7 +21,7 @@ namespace dawn_native { namespace metal { Buffer::Buffer(Device* device, const BufferDescriptor* descriptor) : BufferBase(device, descriptor) { MTLResourceOptions storageMode; - if (GetUsage() & (dawn::BufferUsageBit::MapRead | dawn::BufferUsageBit::MapWrite)) { + if (GetUsage() & (dawn::BufferUsage::MapRead | dawn::BufferUsage::MapWrite)) { storageMode = MTLResourceStorageModeShared; } else { storageMode = MTLResourceStorageModePrivate; @@ -34,7 +34,7 @@ namespace dawn_native { namespace metal { DestroyInternal(); } - id<MTLBuffer> Buffer::GetMTLBuffer() { + id<MTLBuffer> Buffer::GetMTLBuffer() const { return mMtlBuffer; } @@ -49,7 +49,7 @@ namespace dawn_native { namespace metal { bool Buffer::IsMapWritable() const { // TODO(enga): Handle CPU-visible memory on UMA - return (GetUsage() & (dawn::BufferUsageBit::MapRead | dawn::BufferUsageBit::MapWrite)) != 0; + return (GetUsage() & (dawn::BufferUsage::MapRead | dawn::BufferUsage::MapWrite)) != 0; } MaybeError Buffer::MapAtCreationImpl(uint8_t** mappedPointer) { diff --git a/chromium/third_party/dawn/src/dawn_native/metal/CommandBufferMTL.mm b/chromium/third_party/dawn/src/dawn_native/metal/CommandBufferMTL.mm index c6c440ac8c7..ef89ff2342a 100644 --- a/chromium/third_party/dawn/src/dawn_native/metal/CommandBufferMTL.mm +++ b/chromium/third_party/dawn/src/dawn_native/metal/CommandBufferMTL.mm @@ -17,6 +17,7 @@ #include "dawn_native/BindGroup.h" #include "dawn_native/CommandEncoder.h" #include "dawn_native/Commands.h" +#include "dawn_native/RenderBundle.h" #include "dawn_native/metal/BufferMTL.h" #include "dawn_native/metal/ComputePipelineMTL.h" #include "dawn_native/metal/DeviceMTL.h" @@ -50,7 +51,8 @@ namespace dawn_native { namespace metal { MTLRenderPassDescriptor* CreateMTLRenderPassDescriptor(BeginRenderPassCmd* renderPass) { MTLRenderPassDescriptor* descriptor = [MTLRenderPassDescriptor renderPassDescriptor]; - for (uint32_t i : IterateBitSet(renderPass->colorAttachmentsSet)) { + for (uint32_t i : + IterateBitSet(renderPass->attachmentState->GetColorAttachmentsMask())) { auto& attachmentInfo = renderPass->colorAttachments[i]; if (attachmentInfo.loadOp == dawn::LoadOp::Clear) { @@ -83,7 +85,7 @@ namespace dawn_native { namespace metal { } } - if (renderPass->hasDepthStencilAttachment) { + if (renderPass->attachmentState->HasDepthStencilAttachment()) { auto& attachmentInfo = renderPass->depthStencilAttachment; // TODO(jiawei.shao@intel.com): support rendering into a layer of a texture. @@ -190,6 +192,67 @@ namespace dawn_native { namespace metal { destinationOrigin:MTLOriginMake(0, 0, 0)]; } + // Metal uses a physical addressing mode which means buffers in the shading language are + // just pointers to the virtual address of their start. This means there is no way to know + // the length of a buffer to compute the length() of unsized arrays at the end of storage + // buffers. SPIRV-Cross implements the length() of unsized arrays by requiring an extra + // buffer that contains the length of other buffers. This structure that keeps track of the + // length of storage buffers and can apply them to the reserved "buffer length buffer" when + // needed for a draw or a dispatch. + struct StorageBufferLengthTracker { + dawn::ShaderStage dirtyStages = dawn::ShaderStage::None; + + // The lengths of buffers are stored as 32bit integers because that is the width the + // MSL code generated by SPIRV-Cross expects. + PerStage<std::array<uint32_t, kGenericMetalBufferSlots>> data; + + void Apply(RenderPipeline* pipeline, id<MTLRenderCommandEncoder> render) { + dawn::ShaderStage stagesToApply = + dirtyStages & pipeline->GetStagesRequiringStorageBufferLength(); + + if (stagesToApply == dawn::ShaderStage::None) { + return; + } + + if (stagesToApply & dawn::ShaderStage::Vertex) { + uint32_t bufferCount = ToBackend(pipeline->GetLayout()) + ->GetBufferBindingCount(SingleShaderStage::Vertex); + [render setVertexBytes:data[SingleShaderStage::Vertex].data() + length:sizeof(uint32_t) * bufferCount + atIndex:kBufferLengthBufferSlot]; + } + + if (stagesToApply & dawn::ShaderStage::Fragment) { + uint32_t bufferCount = ToBackend(pipeline->GetLayout()) + ->GetBufferBindingCount(SingleShaderStage::Fragment); + [render setFragmentBytes:data[SingleShaderStage::Fragment].data() + length:sizeof(uint32_t) * bufferCount + atIndex:kBufferLengthBufferSlot]; + } + + // Only mark clean stages that were actually applied. + dirtyStages ^= stagesToApply; + } + + void Apply(ComputePipeline* pipeline, id<MTLComputeCommandEncoder> compute) { + if (!(dirtyStages & dawn::ShaderStage::Compute)) { + return; + } + + if (!pipeline->RequiresStorageBufferLength()) { + return; + } + + uint32_t bufferCount = ToBackend(pipeline->GetLayout()) + ->GetBufferBindingCount(SingleShaderStage::Compute); + [compute setBytes:data[SingleShaderStage::Compute].data() + length:sizeof(uint32_t) * bufferCount + atIndex:kBufferLengthBufferSlot]; + + dirtyStages ^= dawn::ShaderStage::Compute; + } + }; + // Handles a call to SetBindGroup, directing the commands to the correct encoder. // There is a single function that takes both encoders to factor code. Other approaches like // templates wouldn't work because the name of methods are different between the two encoder @@ -199,6 +262,7 @@ namespace dawn_native { namespace metal { uint32_t dynamicOffsetCount, uint64_t* dynamicOffsets, PipelineLayout* pipelineLayout, + StorageBufferLengthTracker* lengthTracker, id<MTLRenderCommandEncoder> render, id<MTLComputeCommandEncoder> compute) { const auto& layout = group->GetLayout()->GetBindingInfo(); @@ -209,9 +273,9 @@ namespace dawn_native { namespace metal { // call here. for (uint32_t bindingIndex : IterateBitSet(layout.mask)) { auto stage = layout.visibilities[bindingIndex]; - bool hasVertStage = stage & dawn::ShaderStageBit::Vertex && render != nil; - bool hasFragStage = stage & dawn::ShaderStageBit::Fragment && render != nil; - bool hasComputeStage = stage & dawn::ShaderStageBit::Compute && compute != nil; + bool hasVertStage = stage & dawn::ShaderStage::Vertex && render != nil; + bool hasFragStage = stage & dawn::ShaderStage::Fragment && render != nil; + bool hasComputeStage = stage & dawn::ShaderStage::Compute && compute != nil; uint32_t vertIndex = 0; uint32_t fragIndex = 0; @@ -219,21 +283,22 @@ namespace dawn_native { namespace metal { if (hasVertStage) { vertIndex = pipelineLayout->GetBindingIndexInfo( - ShaderStage::Vertex)[index][bindingIndex]; + SingleShaderStage::Vertex)[index][bindingIndex]; } if (hasFragStage) { fragIndex = pipelineLayout->GetBindingIndexInfo( - ShaderStage::Fragment)[index][bindingIndex]; + SingleShaderStage::Fragment)[index][bindingIndex]; } if (hasComputeStage) { computeIndex = pipelineLayout->GetBindingIndexInfo( - ShaderStage::Compute)[index][bindingIndex]; + SingleShaderStage::Compute)[index][bindingIndex]; } switch (layout.types[bindingIndex]) { case dawn::BindingType::UniformBuffer: case dawn::BindingType::StorageBuffer: { - BufferBinding binding = group->GetBindingAsBufferBinding(bindingIndex); + const BufferBinding& binding = + group->GetBindingAsBufferBinding(bindingIndex); const id<MTLBuffer> buffer = ToBackend(binding.buffer)->GetMTLBuffer(); NSUInteger offset = binding.offset; @@ -245,16 +310,25 @@ namespace dawn_native { namespace metal { } if (hasVertStage) { + lengthTracker->data[SingleShaderStage::Vertex][vertIndex] = + binding.size; + lengthTracker->dirtyStages |= dawn::ShaderStage::Vertex; [render setVertexBuffers:&buffer offsets:&offset withRange:NSMakeRange(vertIndex, 1)]; } if (hasFragStage) { + lengthTracker->data[SingleShaderStage::Fragment][fragIndex] = + binding.size; + lengthTracker->dirtyStages |= dawn::ShaderStage::Fragment; [render setFragmentBuffers:&buffer offsets:&offset withRange:NSMakeRange(fragIndex, 1)]; } if (hasComputeStage) { + lengthTracker->data[SingleShaderStage::Compute][computeIndex] = + binding.size; + lengthTracker->dirtyStages |= dawn::ShaderStage::Compute; [compute setBuffers:&buffer offsets:&offset withRange:NSMakeRange(computeIndex, 1)]; @@ -436,6 +510,55 @@ namespace dawn_native { namespace metal { return copy; } + + // Keeps track of the dirty vertex buffer values so they can be lazily applied when we know + // all the relevant state. + class VertexInputBufferTracker { + public: + void OnSetVertexBuffers(uint32_t startSlot, + uint32_t count, + const Ref<BufferBase>* buffers, + const uint64_t* offsets) { + for (uint32_t i = 0; i < count; ++i) { + uint32_t slot = startSlot + i; + mVertexBuffers[slot] = ToBackend(buffers[i].Get())->GetMTLBuffer(); + mVertexBufferOffsets[slot] = offsets[i]; + } + + // Use 64 bit masks and make sure there are no shift UB + static_assert(kMaxVertexBuffers <= 8 * sizeof(unsigned long long) - 1, ""); + mDirtyVertexBuffers |= ((1ull << count) - 1ull) << startSlot; + } + + void OnSetPipeline(RenderPipeline* lastPipeline, RenderPipeline* pipeline) { + // When a new pipeline is bound we must set all the vertex buffers again because + // they might have been offset by the pipeline layout, and they might be packed + // differently from the previous pipeline. + mDirtyVertexBuffers |= pipeline->GetInputsSetMask(); + } + + void Apply(id<MTLRenderCommandEncoder> encoder, RenderPipeline* pipeline) { + std::bitset<kMaxVertexBuffers> vertexBuffersToApply = + mDirtyVertexBuffers & pipeline->GetInputsSetMask(); + + for (uint32_t dawnIndex : IterateBitSet(vertexBuffersToApply)) { + uint32_t metalIndex = pipeline->GetMtlVertexBufferIndex(dawnIndex); + + [encoder setVertexBuffers:&mVertexBuffers[dawnIndex] + offsets:&mVertexBufferOffsets[dawnIndex] + withRange:NSMakeRange(metalIndex, 1)]; + } + + mDirtyVertexBuffers.reset(); + } + + private: + // All the indices in these arrays are Dawn vertex buffer indices + std::bitset<kMaxVertexBuffers> mDirtyVertexBuffers; + std::array<id<MTLBuffer>, kMaxVertexBuffers> mVertexBuffers; + std::array<NSUInteger, kMaxVertexBuffers> mVertexBufferOffsets; + }; + } // anonymous namespace CommandBuffer::CommandBuffer(CommandEncoderBase* encoder, @@ -561,6 +684,7 @@ namespace dawn_native { namespace metal { void CommandBuffer::EncodeComputePass(id<MTLCommandBuffer> commandBuffer) { ComputePipeline* lastPipeline = nullptr; + StorageBufferLengthTracker storageBufferLengths = {}; // Will be autoreleased id<MTLComputeCommandEncoder> encoder = [commandBuffer computeCommandEncoder]; @@ -576,12 +700,15 @@ namespace dawn_native { namespace metal { case Command::Dispatch: { DispatchCmd* dispatch = mCommands.NextCommand<DispatchCmd>(); + storageBufferLengths.Apply(lastPipeline, encoder); + [encoder dispatchThreadgroups:MTLSizeMake(dispatch->x, dispatch->y, dispatch->z) threadsPerThreadgroup:lastPipeline->GetLocalWorkGroupSize()]; } break; case Command::DispatchIndirect: { DispatchIndirectCmd* dispatch = mCommands.NextCommand<DispatchIndirectCmd>(); + storageBufferLengths.Apply(lastPipeline, encoder); Buffer* buffer = ToBackend(dispatch->indirectBuffer.Get()); id<MTLBuffer> indirectBuffer = buffer->GetMTLBuffer(); @@ -606,8 +733,32 @@ namespace dawn_native { namespace metal { } ApplyBindGroup(cmd->index, ToBackend(cmd->group.Get()), cmd->dynamicOffsetCount, - dynamicOffsets, ToBackend(lastPipeline->GetLayout()), nil, - encoder); + dynamicOffsets, ToBackend(lastPipeline->GetLayout()), + &storageBufferLengths, nil, encoder); + } break; + + case Command::InsertDebugMarker: { + InsertDebugMarkerCmd* cmd = mCommands.NextCommand<InsertDebugMarkerCmd>(); + char* label = mCommands.NextData<char>(cmd->length + 1); + NSString* mtlLabel = [[NSString alloc] initWithUTF8String:label]; + + [encoder insertDebugSignpost:mtlLabel]; + [mtlLabel release]; + } break; + + case Command::PopDebugGroup: { + mCommands.NextCommand<PopDebugGroupCmd>(); + + [encoder popDebugGroup]; + } break; + + case Command::PushDebugGroup: { + PushDebugGroupCmd* cmd = mCommands.NextCommand<PushDebugGroupCmd>(); + char* label = mCommands.NextData<char>(cmd->length + 1); + NSString* mtlLabel = [[NSString alloc] initWithUTF8String:label]; + + [encoder pushDebugGroup:mtlLabel]; + [mtlLabel release]; } break; default: { UNREACHABLE(); } break; @@ -717,22 +868,20 @@ namespace dawn_native { namespace metal { RenderPipeline* lastPipeline = nullptr; id<MTLBuffer> indexBuffer = nil; uint32_t indexBufferBaseOffset = 0; + VertexInputBufferTracker vertexInputBuffers; + StorageBufferLengthTracker storageBufferLengths = {}; // This will be autoreleased id<MTLRenderCommandEncoder> encoder = [commandBuffer renderCommandEncoderWithDescriptor:mtlRenderPass]; - Command type; - while (mCommands.NextCommandId(&type)) { + auto EncodeRenderBundleCommand = [&](CommandIterator* iter, Command type) { switch (type) { - case Command::EndRenderPass: { - mCommands.NextCommand<EndRenderPassCmd>(); - [encoder endEncoding]; - return; - } break; - case Command::Draw: { - DrawCmd* draw = mCommands.NextCommand<DrawCmd>(); + DrawCmd* draw = iter->NextCommand<DrawCmd>(); + + vertexInputBuffers.Apply(encoder, lastPipeline); + storageBufferLengths.Apply(lastPipeline, encoder); // The instance count must be non-zero, otherwise no-op if (draw->instanceCount != 0) { @@ -745,10 +894,13 @@ namespace dawn_native { namespace metal { } break; case Command::DrawIndexed: { - DrawIndexedCmd* draw = mCommands.NextCommand<DrawIndexedCmd>(); + DrawIndexedCmd* draw = iter->NextCommand<DrawIndexedCmd>(); size_t formatSize = IndexFormatSize(lastPipeline->GetVertexInputDescriptor()->indexFormat); + vertexInputBuffers.Apply(encoder, lastPipeline); + storageBufferLengths.Apply(lastPipeline, encoder); + // The index and instance count must be non-zero, otherwise no-op if (draw->indexCount != 0 && draw->instanceCount != 0) { [encoder drawIndexedPrimitives:lastPipeline->GetMTLPrimitiveTopology() @@ -764,7 +916,10 @@ namespace dawn_native { namespace metal { } break; case Command::DrawIndirect: { - DrawIndirectCmd* draw = mCommands.NextCommand<DrawIndirectCmd>(); + DrawIndirectCmd* draw = iter->NextCommand<DrawIndirectCmd>(); + + vertexInputBuffers.Apply(encoder, lastPipeline); + storageBufferLengths.Apply(lastPipeline, encoder); Buffer* buffer = ToBackend(draw->indirectBuffer.Get()); id<MTLBuffer> indirectBuffer = buffer->GetMTLBuffer(); @@ -774,7 +929,10 @@ namespace dawn_native { namespace metal { } break; case Command::DrawIndexedIndirect: { - DrawIndirectCmd* draw = mCommands.NextCommand<DrawIndirectCmd>(); + DrawIndirectCmd* draw = iter->NextCommand<DrawIndirectCmd>(); + + vertexInputBuffers.Apply(encoder, lastPipeline); + storageBufferLengths.Apply(lastPipeline, encoder); Buffer* buffer = ToBackend(draw->indirectBuffer.Get()); id<MTLBuffer> indirectBuffer = buffer->GetMTLBuffer(); @@ -787,8 +945,8 @@ namespace dawn_native { namespace metal { } break; case Command::InsertDebugMarker: { - InsertDebugMarkerCmd* cmd = mCommands.NextCommand<InsertDebugMarkerCmd>(); - auto label = mCommands.NextData<char>(cmd->length + 1); + InsertDebugMarkerCmd* cmd = iter->NextCommand<InsertDebugMarkerCmd>(); + char* label = iter->NextData<char>(cmd->length + 1); NSString* mtlLabel = [[NSString alloc] initWithUTF8String:label]; [encoder insertDebugSignpost:mtlLabel]; @@ -796,14 +954,14 @@ namespace dawn_native { namespace metal { } break; case Command::PopDebugGroup: { - mCommands.NextCommand<PopDebugGroupCmd>(); + iter->NextCommand<PopDebugGroupCmd>(); [encoder popDebugGroup]; } break; case Command::PushDebugGroup: { - PushDebugGroupCmd* cmd = mCommands.NextCommand<PushDebugGroupCmd>(); - auto label = mCommands.NextData<char>(cmd->length + 1); + PushDebugGroupCmd* cmd = iter->NextCommand<PushDebugGroupCmd>(); + char* label = iter->NextData<char>(cmd->length + 1); NSString* mtlLabel = [[NSString alloc] initWithUTF8String:label]; [encoder pushDebugGroup:mtlLabel]; @@ -811,13 +969,59 @@ namespace dawn_native { namespace metal { } break; case Command::SetRenderPipeline: { - SetRenderPipelineCmd* cmd = mCommands.NextCommand<SetRenderPipelineCmd>(); - lastPipeline = ToBackend(cmd->pipeline).Get(); + SetRenderPipelineCmd* cmd = iter->NextCommand<SetRenderPipelineCmd>(); + RenderPipeline* newPipeline = ToBackend(cmd->pipeline).Get(); - [encoder setDepthStencilState:lastPipeline->GetMTLDepthStencilState()]; - [encoder setFrontFacingWinding:lastPipeline->GetMTLFrontFace()]; - [encoder setCullMode:lastPipeline->GetMTLCullMode()]; - lastPipeline->Encode(encoder); + vertexInputBuffers.OnSetPipeline(lastPipeline, newPipeline); + [encoder setDepthStencilState:newPipeline->GetMTLDepthStencilState()]; + [encoder setFrontFacingWinding:newPipeline->GetMTLFrontFace()]; + [encoder setCullMode:newPipeline->GetMTLCullMode()]; + newPipeline->Encode(encoder); + + lastPipeline = newPipeline; + } break; + + case Command::SetBindGroup: { + SetBindGroupCmd* cmd = iter->NextCommand<SetBindGroupCmd>(); + uint64_t* dynamicOffsets = nullptr; + if (cmd->dynamicOffsetCount > 0) { + dynamicOffsets = iter->NextData<uint64_t>(cmd->dynamicOffsetCount); + } + + ApplyBindGroup(cmd->index, ToBackend(cmd->group.Get()), cmd->dynamicOffsetCount, + dynamicOffsets, ToBackend(lastPipeline->GetLayout()), + &storageBufferLengths, encoder, nil); + } break; + + case Command::SetIndexBuffer: { + SetIndexBufferCmd* cmd = iter->NextCommand<SetIndexBufferCmd>(); + auto b = ToBackend(cmd->buffer.Get()); + indexBuffer = b->GetMTLBuffer(); + indexBufferBaseOffset = cmd->offset; + } break; + + case Command::SetVertexBuffers: { + SetVertexBuffersCmd* cmd = iter->NextCommand<SetVertexBuffersCmd>(); + const Ref<BufferBase>* buffers = iter->NextData<Ref<BufferBase>>(cmd->count); + const uint64_t* offsets = iter->NextData<uint64_t>(cmd->count); + + vertexInputBuffers.OnSetVertexBuffers(cmd->startSlot, cmd->count, buffers, + offsets); + } break; + + default: + UNREACHABLE(); + break; + } + }; + + Command type; + while (mCommands.NextCommandId(&type)) { + switch (type) { + case Command::EndRenderPass: { + mCommands.NextCommand<EndRenderPassCmd>(); + [encoder endEncoding]; + return; } break; case Command::SetStencilReference: { @@ -866,48 +1070,20 @@ namespace dawn_native { namespace metal { alpha:cmd->color.a]; } break; - case Command::SetBindGroup: { - SetBindGroupCmd* cmd = mCommands.NextCommand<SetBindGroupCmd>(); - uint64_t* dynamicOffsets = nullptr; - if (cmd->dynamicOffsetCount > 0) { - dynamicOffsets = mCommands.NextData<uint64_t>(cmd->dynamicOffsetCount); - } + case Command::ExecuteBundles: { + ExecuteBundlesCmd* cmd = mCommands.NextCommand<ExecuteBundlesCmd>(); + auto bundles = mCommands.NextData<Ref<RenderBundleBase>>(cmd->count); - ApplyBindGroup(cmd->index, ToBackend(cmd->group.Get()), cmd->dynamicOffsetCount, - dynamicOffsets, ToBackend(lastPipeline->GetLayout()), encoder, - nil); - } break; - - case Command::SetIndexBuffer: { - SetIndexBufferCmd* cmd = mCommands.NextCommand<SetIndexBufferCmd>(); - auto b = ToBackend(cmd->buffer.Get()); - indexBuffer = b->GetMTLBuffer(); - indexBufferBaseOffset = cmd->offset; - } break; - - case Command::SetVertexBuffers: { - SetVertexBuffersCmd* cmd = mCommands.NextCommand<SetVertexBuffersCmd>(); - auto buffers = mCommands.NextData<Ref<BufferBase>>(cmd->count); - auto offsets = mCommands.NextData<uint64_t>(cmd->count); - - std::array<id<MTLBuffer>, kMaxVertexBuffers> mtlBuffers; - std::array<NSUInteger, kMaxVertexBuffers> mtlOffsets; - - // Perhaps an "array of vertex buffers(+offsets?)" should be - // a Dawn API primitive to avoid reconstructing this array? for (uint32_t i = 0; i < cmd->count; ++i) { - Buffer* buffer = ToBackend(buffers[i].Get()); - mtlBuffers[i] = buffer->GetMTLBuffer(); - mtlOffsets[i] = offsets[i]; + CommandIterator* iter = bundles[i]->GetCommands(); + iter->Reset(); + while (iter->NextCommandId(&type)) { + EncodeRenderBundleCommand(iter, type); + } } - - [encoder setVertexBuffers:mtlBuffers.data() - offsets:mtlOffsets.data() - withRange:NSMakeRange(kMaxBindingsPerGroup + cmd->startSlot, - cmd->count)]; } break; - default: { UNREACHABLE(); } break; + default: { EncodeRenderBundleCommand(&mCommands, type); } break; } } diff --git a/chromium/third_party/dawn/src/dawn_native/metal/ComputePipelineMTL.h b/chromium/third_party/dawn/src/dawn_native/metal/ComputePipelineMTL.h index 6f3aca9a5c7..71b5ba36bcf 100644 --- a/chromium/third_party/dawn/src/dawn_native/metal/ComputePipelineMTL.h +++ b/chromium/third_party/dawn/src/dawn_native/metal/ComputePipelineMTL.h @@ -30,10 +30,12 @@ namespace dawn_native { namespace metal { void Encode(id<MTLComputeCommandEncoder> encoder); MTLSize GetLocalWorkGroupSize() const; + bool RequiresStorageBufferLength() const; private: id<MTLComputePipelineState> mMtlComputePipelineState = nil; MTLSize mLocalWorkgroupSize; + bool mRequiresStorageBufferLength; }; }} // namespace dawn_native::metal diff --git a/chromium/third_party/dawn/src/dawn_native/metal/ComputePipelineMTL.mm b/chromium/third_party/dawn/src/dawn_native/metal/ComputePipelineMTL.mm index 66f6da8765b..f62412a3104 100644 --- a/chromium/third_party/dawn/src/dawn_native/metal/ComputePipelineMTL.mm +++ b/chromium/third_party/dawn/src/dawn_native/metal/ComputePipelineMTL.mm @@ -23,22 +23,23 @@ namespace dawn_native { namespace metal { : ComputePipelineBase(device, descriptor) { auto mtlDevice = ToBackend(GetDevice())->GetMTLDevice(); - const ShaderModule* computeModule = ToBackend(descriptor->computeStage->module); - const char* computeEntryPoint = descriptor->computeStage->entryPoint; + const ShaderModule* computeModule = ToBackend(descriptor->computeStage.module); + const char* computeEntryPoint = descriptor->computeStage.entryPoint; ShaderModule::MetalFunctionData computeData = computeModule->GetFunction( - computeEntryPoint, ShaderStage::Compute, ToBackend(GetLayout())); + computeEntryPoint, SingleShaderStage::Compute, ToBackend(GetLayout())); NSError* error = nil; mMtlComputePipelineState = [mtlDevice newComputePipelineStateWithFunction:computeData.function error:&error]; if (error != nil) { NSLog(@" error => %@", error); - GetDevice()->HandleError("Error creating pipeline state"); + GetDevice()->HandleError(dawn::ErrorType::DeviceLost, "Error creating pipeline state"); return; } // Copy over the local workgroup size as it is passed to dispatch explicitly in Metal mLocalWorkgroupSize = computeData.localWorkgroupSize; + mRequiresStorageBufferLength = computeData.needsStorageBufferLength; } ComputePipeline::~ComputePipeline() { @@ -53,4 +54,8 @@ namespace dawn_native { namespace metal { return mLocalWorkgroupSize; } + bool ComputePipeline::RequiresStorageBufferLength() const { + return mRequiresStorageBufferLength; + } + }} // namespace dawn_native::metal diff --git a/chromium/third_party/dawn/src/dawn_native/metal/DeviceMTL.mm b/chromium/third_party/dawn/src/dawn_native/metal/DeviceMTL.mm index 811a43cc821..dda06915bee 100644 --- a/chromium/third_party/dawn/src/dawn_native/metal/DeviceMTL.mm +++ b/chromium/third_party/dawn/src/dawn_native/metal/DeviceMTL.mm @@ -29,6 +29,7 @@ #include "dawn_native/metal/StagingBufferMTL.h" #include "dawn_native/metal/SwapChainMTL.h" #include "dawn_native/metal/TextureMTL.h" +#include "dawn_platform/tracing/TraceEvent.h" #include <type_traits> @@ -168,6 +169,8 @@ namespace dawn_native { namespace metal { } id<MTLCommandBuffer> Device::GetPendingCommandBuffer() { + TRACE_EVENT0(GetPlatform(), TRACE_DISABLED_BY_DEFAULT("gpu.dawn"), + "DeviceMTL::GetPendingCommandBuffer"); if (mPendingCommands == nil) { mPendingCommands = [mCommandQueue commandBuffer]; [mPendingCommands retain]; @@ -214,10 +217,14 @@ namespace dawn_native { namespace metal { // mLastSubmittedSerial so it is captured by value. Serial pendingSerial = mLastSubmittedSerial; [mPendingCommands addCompletedHandler:^(id<MTLCommandBuffer>) { + TRACE_EVENT_ASYNC_END0(GetPlatform(), TRACE_DISABLED_BY_DEFAULT("gpu.dawn"), + "DeviceMTL::SubmitPendingCommandBuffer", pendingSerial); ASSERT(pendingSerial > mCompletedSerial.load()); this->mCompletedSerial = pendingSerial; }]; + TRACE_EVENT_ASYNC_BEGIN0(GetPlatform(), TRACE_DISABLED_BY_DEFAULT("gpu.dawn"), + "DeviceMTL::SubmitPendingCommandBuffer", pendingSerial); [mPendingCommands commit]; mPendingCommands = nil; } diff --git a/chromium/third_party/dawn/src/dawn_native/metal/PipelineLayoutMTL.h b/chromium/third_party/dawn/src/dawn_native/metal/PipelineLayoutMTL.h index 77610a5f4a3..e66a852a676 100644 --- a/chromium/third_party/dawn/src/dawn_native/metal/PipelineLayoutMTL.h +++ b/chromium/third_party/dawn/src/dawn_native/metal/PipelineLayoutMTL.h @@ -29,16 +29,27 @@ namespace dawn_native { namespace metal { class Device; + // The number of Metal buffers usable by applications in general + static constexpr size_t kMetalBufferTableSize = 31; + // The Metal buffer slot that Dawn reserves for its own use to pass more data to shaders + static constexpr size_t kBufferLengthBufferSlot = kMetalBufferTableSize - 1; + // The number of Metal buffers Dawn can use in a generic way (i.e. that aren't reserved) + static constexpr size_t kGenericMetalBufferSlots = kMetalBufferTableSize - 1; + class PipelineLayout : public PipelineLayoutBase { public: PipelineLayout(Device* device, const PipelineLayoutDescriptor* descriptor); using BindingIndexInfo = std::array<std::array<uint32_t, kMaxBindingsPerGroup>, kMaxBindGroups>; - const BindingIndexInfo& GetBindingIndexInfo(ShaderStage stage) const; + const BindingIndexInfo& GetBindingIndexInfo(SingleShaderStage stage) const; + + // The number of Metal vertex stage buffers used for the whole pipeline layout. + uint32_t GetBufferBindingCount(SingleShaderStage stage); private: PerStage<BindingIndexInfo> mIndexInfo; + PerStage<uint32_t> mBufferBindingCount; }; }} // namespace dawn_native::metal diff --git a/chromium/third_party/dawn/src/dawn_native/metal/PipelineLayoutMTL.mm b/chromium/third_party/dawn/src/dawn_native/metal/PipelineLayoutMTL.mm index 282559fdbf4..2469371d7e2 100644 --- a/chromium/third_party/dawn/src/dawn_native/metal/PipelineLayoutMTL.mm +++ b/chromium/third_party/dawn/src/dawn_native/metal/PipelineLayoutMTL.mm @@ -60,12 +60,18 @@ namespace dawn_native { namespace metal { } } } + + mBufferBindingCount[stage] = bufferIndex; } } const PipelineLayout::BindingIndexInfo& PipelineLayout::GetBindingIndexInfo( - ShaderStage stage) const { + SingleShaderStage stage) const { return mIndexInfo[stage]; } + uint32_t PipelineLayout::GetBufferBindingCount(SingleShaderStage stage) { + return mBufferBindingCount[stage]; + } + }} // namespace dawn_native::metal diff --git a/chromium/third_party/dawn/src/dawn_native/metal/QueueMTL.mm b/chromium/third_party/dawn/src/dawn_native/metal/QueueMTL.mm index ffd82924ed4..084c9ef05bb 100644 --- a/chromium/third_party/dawn/src/dawn_native/metal/QueueMTL.mm +++ b/chromium/third_party/dawn/src/dawn_native/metal/QueueMTL.mm @@ -16,6 +16,7 @@ #include "dawn_native/metal/CommandBufferMTL.h" #include "dawn_native/metal/DeviceMTL.h" +#include "dawn_platform/tracing/TraceEvent.h" namespace dawn_native { namespace metal { @@ -27,9 +28,13 @@ namespace dawn_native { namespace metal { device->Tick(); id<MTLCommandBuffer> commandBuffer = device->GetPendingCommandBuffer(); + TRACE_EVENT_BEGIN0(GetDevice()->GetPlatform(), TRACE_DISABLED_BY_DEFAULT("gpu.dawn"), + "CommandBufferMTL::FillCommands"); for (uint32_t i = 0; i < commandCount; ++i) { ToBackend(commands[i])->FillCommands(commandBuffer); } + TRACE_EVENT_END0(GetDevice()->GetPlatform(), TRACE_DISABLED_BY_DEFAULT("gpu.dawn"), + "CommandBufferMTL::FillCommands"); device->SubmitPendingCommandBuffer(); } diff --git a/chromium/third_party/dawn/src/dawn_native/metal/RenderPipelineMTL.h b/chromium/third_party/dawn/src/dawn_native/metal/RenderPipelineMTL.h index a027ffc8062..1b764ddae5a 100644 --- a/chromium/third_party/dawn/src/dawn_native/metal/RenderPipelineMTL.h +++ b/chromium/third_party/dawn/src/dawn_native/metal/RenderPipelineMTL.h @@ -37,6 +37,12 @@ namespace dawn_native { namespace metal { id<MTLDepthStencilState> GetMTLDepthStencilState(); + // For each Dawn vertex buffer, give the index in which it will be positioned in the Metal + // vertex buffer table. + uint32_t GetMtlVertexBufferIndex(uint32_t dawnIndex) const; + + dawn::ShaderStage GetStagesRequiringStorageBufferLength() const; + private: MTLVertexDescriptor* MakeVertexDesc(); @@ -46,6 +52,9 @@ namespace dawn_native { namespace metal { MTLCullMode mMtlCullMode; id<MTLRenderPipelineState> mMtlRenderPipelineState = nil; id<MTLDepthStencilState> mMtlDepthStencilState = nil; + std::array<uint32_t, kMaxVertexBuffers> mMtlVertexBufferIndices; + + dawn::ShaderStage mStagesRequiringStorageBufferLength = dawn::ShaderStage::None; }; }} // namespace dawn_native::metal diff --git a/chromium/third_party/dawn/src/dawn_native/metal/RenderPipelineMTL.mm b/chromium/third_party/dawn/src/dawn_native/metal/RenderPipelineMTL.mm index 0bb3a55d73e..c00d488cace 100644 --- a/chromium/third_party/dawn/src/dawn_native/metal/RenderPipelineMTL.mm +++ b/chromium/third_party/dawn/src/dawn_native/metal/RenderPipelineMTL.mm @@ -314,17 +314,23 @@ namespace dawn_native { namespace metal { MTLRenderPipelineDescriptor* descriptorMTL = [MTLRenderPipelineDescriptor new]; - const ShaderModule* vertexModule = ToBackend(descriptor->vertexStage->module); - const char* vertexEntryPoint = descriptor->vertexStage->entryPoint; + const ShaderModule* vertexModule = ToBackend(descriptor->vertexStage.module); + const char* vertexEntryPoint = descriptor->vertexStage.entryPoint; ShaderModule::MetalFunctionData vertexData = vertexModule->GetFunction( - vertexEntryPoint, ShaderStage::Vertex, ToBackend(GetLayout())); + vertexEntryPoint, SingleShaderStage::Vertex, ToBackend(GetLayout())); descriptorMTL.vertexFunction = vertexData.function; + if (vertexData.needsStorageBufferLength) { + mStagesRequiringStorageBufferLength |= dawn::ShaderStage::Vertex; + } const ShaderModule* fragmentModule = ToBackend(descriptor->fragmentStage->module); const char* fragmentEntryPoint = descriptor->fragmentStage->entryPoint; ShaderModule::MetalFunctionData fragmentData = fragmentModule->GetFunction( - fragmentEntryPoint, ShaderStage::Fragment, ToBackend(GetLayout())); + fragmentEntryPoint, SingleShaderStage::Fragment, ToBackend(GetLayout())); descriptorMTL.fragmentFunction = fragmentData.function; + if (fragmentData.needsStorageBufferLength) { + mStagesRequiringStorageBufferLength |= dawn::ShaderStage::Fragment; + } if (HasDepthStencilAttachment()) { // TODO(kainino@chromium.org): Handle depth-only and stencil-only formats. @@ -357,7 +363,8 @@ namespace dawn_native { namespace metal { [descriptorMTL release]; if (error != nil) { NSLog(@" error => %@", error); - device->HandleError("Error creating rendering pipeline state"); + device->HandleError(dawn::ErrorType::DeviceLost, + "Error creating rendering pipeline state"); return; } } @@ -400,24 +407,26 @@ namespace dawn_native { namespace metal { return mMtlDepthStencilState; } + uint32_t RenderPipeline::GetMtlVertexBufferIndex(uint32_t dawnIndex) const { + ASSERT(dawnIndex < kMaxVertexBuffers); + return mMtlVertexBufferIndices[dawnIndex]; + } + + dawn::ShaderStage RenderPipeline::GetStagesRequiringStorageBufferLength() const { + return mStagesRequiringStorageBufferLength; + } + MTLVertexDescriptor* RenderPipeline::MakeVertexDesc() { MTLVertexDescriptor* mtlVertexDescriptor = [MTLVertexDescriptor new]; - for (uint32_t i : IterateBitSet(GetAttributesSetMask())) { - const VertexAttributeInfo& info = GetAttribute(i); - - auto attribDesc = [MTLVertexAttributeDescriptor new]; - attribDesc.format = VertexFormatType(info.format); - attribDesc.offset = info.offset; - attribDesc.bufferIndex = kMaxBindingsPerGroup + info.inputSlot; - mtlVertexDescriptor.attributes[i] = attribDesc; - [attribDesc release]; - } + // Vertex buffers are packed after all the buffers for the bind groups. + uint32_t mtlVertexBufferIndex = + ToBackend(GetLayout())->GetBufferBindingCount(SingleShaderStage::Vertex); - for (uint32_t vbInputSlot : IterateBitSet(GetInputsSetMask())) { - const VertexBufferInfo& info = GetInput(vbInputSlot); + for (uint32_t dawnVertexBufferIndex : IterateBitSet(GetInputsSetMask())) { + const VertexBufferInfo& info = GetInput(dawnVertexBufferIndex); - auto layoutDesc = [MTLVertexBufferLayoutDescriptor new]; + MTLVertexBufferLayoutDescriptor* layoutDesc = [MTLVertexBufferLayoutDescriptor new]; if (info.stride == 0) { // For MTLVertexStepFunctionConstant, the stepRate must be 0, // but the stride must NOT be 0, so we made up it with @@ -426,7 +435,7 @@ namespace dawn_native { namespace metal { for (uint32_t attribIndex : IterateBitSet(GetAttributesSetMask())) { const VertexAttributeInfo& attrib = GetAttribute(attribIndex); // Only use the attributes that use the current input - if (attrib.inputSlot != vbInputSlot) { + if (attrib.inputSlot != dawnVertexBufferIndex) { continue; } max_stride = std::max(max_stride, @@ -442,10 +451,25 @@ namespace dawn_native { namespace metal { layoutDesc.stepRate = 1; layoutDesc.stride = info.stride; } - // TODO(cwallez@chromium.org): make the offset depend on the pipeline layout - mtlVertexDescriptor.layouts[kMaxBindingsPerGroup + vbInputSlot] = layoutDesc; + + mtlVertexDescriptor.layouts[mtlVertexBufferIndex] = layoutDesc; [layoutDesc release]; + + mMtlVertexBufferIndices[dawnVertexBufferIndex] = mtlVertexBufferIndex; + mtlVertexBufferIndex++; + } + + for (uint32_t i : IterateBitSet(GetAttributesSetMask())) { + const VertexAttributeInfo& info = GetAttribute(i); + + auto attribDesc = [MTLVertexAttributeDescriptor new]; + attribDesc.format = VertexFormatType(info.format); + attribDesc.offset = info.offset; + attribDesc.bufferIndex = mMtlVertexBufferIndices[info.inputSlot]; + mtlVertexDescriptor.attributes[i] = attribDesc; + [attribDesc release]; } + return mtlVertexDescriptor; } diff --git a/chromium/third_party/dawn/src/dawn_native/metal/ShaderModuleMTL.h b/chromium/third_party/dawn/src/dawn_native/metal/ShaderModuleMTL.h index 69f9007863f..c31fdf1050e 100644 --- a/chromium/third_party/dawn/src/dawn_native/metal/ShaderModuleMTL.h +++ b/chromium/third_party/dawn/src/dawn_native/metal/ShaderModuleMTL.h @@ -35,12 +35,13 @@ namespace dawn_native { namespace metal { struct MetalFunctionData { id<MTLFunction> function; MTLSize localWorkgroupSize; + bool needsStorageBufferLength; ~MetalFunctionData() { [function release]; } }; MetalFunctionData GetFunction(const char* functionName, - ShaderStage functionStage, + SingleShaderStage functionStage, const PipelineLayout* layout) const; private: diff --git a/chromium/third_party/dawn/src/dawn_native/metal/ShaderModuleMTL.mm b/chromium/third_party/dawn/src/dawn_native/metal/ShaderModuleMTL.mm index b525eba25ff..69c96333bd2 100644 --- a/chromium/third_party/dawn/src/dawn_native/metal/ShaderModuleMTL.mm +++ b/chromium/third_party/dawn/src/dawn_native/metal/ShaderModuleMTL.mm @@ -18,7 +18,7 @@ #include "dawn_native/metal/DeviceMTL.h" #include "dawn_native/metal/PipelineLayoutMTL.h" -#include <spirv-cross/spirv_msl.hpp> +#include <spirv_msl.hpp> #include <sstream> @@ -26,13 +26,13 @@ namespace dawn_native { namespace metal { namespace { - spv::ExecutionModel SpirvExecutionModelForStage(ShaderStage stage) { + spv::ExecutionModel SpirvExecutionModelForStage(SingleShaderStage stage) { switch (stage) { - case ShaderStage::Vertex: + case SingleShaderStage::Vertex: return spv::ExecutionModelVertex; - case ShaderStage::Fragment: + case SingleShaderStage::Fragment: return spv::ExecutionModelFragment; - case ShaderStage::Compute: + case SingleShaderStage::Compute: return spv::ExecutionModelGLCompute; default: UNREACHABLE(); @@ -48,7 +48,7 @@ namespace dawn_native { namespace metal { } ShaderModule::MetalFunctionData ShaderModule::GetFunction(const char* functionName, - ShaderStage functionStage, + SingleShaderStage functionStage, const PipelineLayout* layout) const { spirv_cross::CompilerMSL compiler(mSpirv); @@ -58,13 +58,19 @@ namespace dawn_native { namespace metal { options_glsl.vertex.flip_vert_y = true; compiler.spirv_cross::CompilerGLSL::set_common_options(options_glsl); + spirv_cross::CompilerMSL::Options options_msl; + // Disable PointSize builtin for https://bugs.chromium.org/p/dawn/issues/detail?id=146 - // Becuase Metal will reject PointSize builtin if the shader is compiled into a render + // Because Metal will reject PointSize builtin if the shader is compiled into a render // pipeline that uses a non-point topology. // TODO (hao.x.li@intel.com): Remove this once WebGPU requires there is no // gl_PointSize builtin (https://github.com/gpuweb/gpuweb/issues/332). - spirv_cross::CompilerMSL::Options options_msl; options_msl.enable_point_size_builtin = false; + + // Always use vertex buffer 30 (the last one in the vertex buffer table) to contain + // the shader storage buffer lengths. + options_msl.buffer_size_buffer_index = kBufferLengthBufferSlot; + compiler.set_msl_options(options_msl); // By default SPIRV-Cross will give MSL resources indices in increasing order. @@ -135,6 +141,8 @@ namespace dawn_native { namespace metal { [library release]; } + result.needsStorageBufferLength = compiler.needs_buffer_size_buffer(); + return result; } diff --git a/chromium/third_party/dawn/src/dawn_native/metal/StagingBufferMTL.mm b/chromium/third_party/dawn/src/dawn_native/metal/StagingBufferMTL.mm index f03a7691c5e..491b35cf797 100644 --- a/chromium/third_party/dawn/src/dawn_native/metal/StagingBufferMTL.mm +++ b/chromium/third_party/dawn/src/dawn_native/metal/StagingBufferMTL.mm @@ -25,7 +25,16 @@ namespace dawn_native { namespace metal { const size_t bufferSize = GetSize(); mBuffer = [mDevice->GetMTLDevice() newBufferWithLength:bufferSize options:MTLResourceStorageModeShared]; + + if (mBuffer == nil) { + return DAWN_OUT_OF_MEMORY_ERROR("Unable to allocate buffer."); + } + mMappedPointer = [mBuffer contents]; + if (mMappedPointer == nullptr) { + return DAWN_DEVICE_LOST_ERROR("Unable to map staging buffer."); + } + return {}; } @@ -38,4 +47,4 @@ namespace dawn_native { namespace metal { return mBuffer; } -}} // namespace dawn_native::metal
\ No newline at end of file +}} // namespace dawn_native::metal diff --git a/chromium/third_party/dawn/src/dawn_native/metal/SwapChainMTL.mm b/chromium/third_party/dawn/src/dawn_native/metal/SwapChainMTL.mm index 094e35ac79e..0677ca0a253 100644 --- a/chromium/third_party/dawn/src/dawn_native/metal/SwapChainMTL.mm +++ b/chromium/third_party/dawn/src/dawn_native/metal/SwapChainMTL.mm @@ -37,7 +37,7 @@ namespace dawn_native { namespace metal { DawnSwapChainNextTexture next = {}; DawnSwapChainError error = im.GetNextTexture(im.userData, &next); if (error) { - GetDevice()->HandleError(error); + GetDevice()->HandleError(dawn::ErrorType::Unknown, error); return nullptr; } diff --git a/chromium/third_party/dawn/src/dawn_native/metal/TextureMTL.mm b/chromium/third_party/dawn/src/dawn_native/metal/TextureMTL.mm index 5e12f7a9067..8bbd28be821 100644 --- a/chromium/third_party/dawn/src/dawn_native/metal/TextureMTL.mm +++ b/chromium/third_party/dawn/src/dawn_native/metal/TextureMTL.mm @@ -21,24 +21,24 @@ namespace dawn_native { namespace metal { namespace { - bool UsageNeedsTextureView(dawn::TextureUsageBit usage) { - constexpr dawn::TextureUsageBit kUsageNeedsTextureView = - dawn::TextureUsageBit::Storage | dawn::TextureUsageBit::Sampled; + bool UsageNeedsTextureView(dawn::TextureUsage usage) { + constexpr dawn::TextureUsage kUsageNeedsTextureView = + dawn::TextureUsage::Storage | dawn::TextureUsage::Sampled; return usage & kUsageNeedsTextureView; } - MTLTextureUsage MetalTextureUsage(dawn::TextureUsageBit usage) { + MTLTextureUsage MetalTextureUsage(dawn::TextureUsage usage) { MTLTextureUsage result = MTLTextureUsageUnknown; // This is 0 - if (usage & (dawn::TextureUsageBit::Storage)) { + if (usage & (dawn::TextureUsage::Storage)) { result |= MTLTextureUsageShaderWrite | MTLTextureUsageShaderRead; } - if (usage & (dawn::TextureUsageBit::Sampled)) { + if (usage & (dawn::TextureUsage::Sampled)) { result |= MTLTextureUsageShaderRead; } - if (usage & (dawn::TextureUsageBit::OutputAttachment)) { + if (usage & (dawn::TextureUsage::OutputAttachment)) { result |= MTLTextureUsageRenderTarget; } @@ -109,6 +109,8 @@ namespace dawn_native { namespace metal { ResultOrError<dawn::TextureFormat> GetFormatEquivalentToIOSurfaceFormat(uint32_t format) { switch (format) { + case 'RGBA': + return dawn::TextureFormat::RGBA8Unorm; case 'BGRA': return dawn::TextureFormat::BGRA8Unorm; case '2C08': @@ -132,10 +134,6 @@ namespace dawn_native { namespace metal { case dawn::TextureFormat::R8Sint: return MTLPixelFormatR8Sint; - case dawn::TextureFormat::R16Unorm: - return MTLPixelFormatR16Unorm; - case dawn::TextureFormat::R16Snorm: - return MTLPixelFormatR16Snorm; case dawn::TextureFormat::R16Uint: return MTLPixelFormatR16Uint; case dawn::TextureFormat::R16Sint: @@ -157,10 +155,6 @@ namespace dawn_native { namespace metal { return MTLPixelFormatR32Sint; case dawn::TextureFormat::R32Float: return MTLPixelFormatR32Float; - case dawn::TextureFormat::RG16Unorm: - return MTLPixelFormatRG16Unorm; - case dawn::TextureFormat::RG16Snorm: - return MTLPixelFormatRG16Snorm; case dawn::TextureFormat::RG16Uint: return MTLPixelFormatRG16Uint; case dawn::TextureFormat::RG16Sint: @@ -192,10 +186,6 @@ namespace dawn_native { namespace metal { return MTLPixelFormatRG32Sint; case dawn::TextureFormat::RG32Float: return MTLPixelFormatRG32Float; - case dawn::TextureFormat::RGBA16Unorm: - return MTLPixelFormatRGBA16Unorm; - case dawn::TextureFormat::RGBA16Snorm: - return MTLPixelFormatRGBA16Snorm; case dawn::TextureFormat::RGBA16Uint: return MTLPixelFormatRGBA16Uint; case dawn::TextureFormat::RGBA16Sint: diff --git a/chromium/third_party/dawn/src/dawn_native/null/DeviceNull.cpp b/chromium/third_party/dawn/src/dawn_native/null/DeviceNull.cpp index 693cf09fc96..44e62db51de 100644 --- a/chromium/third_party/dawn/src/dawn_native/null/DeviceNull.cpp +++ b/chromium/third_party/dawn/src/dawn_native/null/DeviceNull.cpp @@ -17,26 +17,32 @@ #include "dawn_native/BackendConnection.h" #include "dawn_native/Commands.h" #include "dawn_native/DynamicUploader.h" +#include "dawn_native/Instance.h" -#include <spirv-cross/spirv_cross.hpp> +#include <spirv_cross.hpp> namespace dawn_native { namespace null { // Implementation of pre-Device objects: the null adapter, null backend connection and Connect() - class Adapter : public AdapterBase { - public: - Adapter(InstanceBase* instance) : AdapterBase(instance, BackendType::Null) { - mPCIInfo.name = "Null backend"; - mDeviceType = DeviceType::CPU; - } - virtual ~Adapter() = default; + Adapter::Adapter(InstanceBase* instance) : AdapterBase(instance, BackendType::Null) { + mPCIInfo.name = "Null backend"; + mDeviceType = DeviceType::CPU; - private: - ResultOrError<DeviceBase*> CreateDeviceImpl(const DeviceDescriptor* descriptor) override { - return {new Device(this, descriptor)}; - } - }; + // Enable all extensions by default for the convenience of tests. + mSupportedExtensions.extensionsBitSet.flip(); + } + + Adapter::~Adapter() = default; + + // Used for the tests that intend to use an adapter without all extensions enabled. + void Adapter::SetSupportedExtensions(const std::vector<const char*>& requiredExtensions) { + mSupportedExtensions = GetInstance()->ExtensionNamesToExtensionsSet(requiredExtensions); + } + + ResultOrError<DeviceBase*> Adapter::CreateDeviceImpl(const DeviceDescriptor* descriptor) { + return {new Device(this, descriptor)}; + } class Backend : public BackendConnection { public: @@ -167,7 +173,7 @@ namespace dawn_native { namespace null { MaybeError Device::IncrementMemoryUsage(size_t bytes) { static_assert(kMaxMemoryUsage <= std::numeric_limits<size_t>::max() / 2, ""); if (bytes > kMaxMemoryUsage || mMemoryUsage + bytes > kMaxMemoryUsage) { - return DAWN_CONTEXT_LOST_ERROR("Out of memory."); + return DAWN_DEVICE_LOST_ERROR("Out of memory."); } mMemoryUsage += bytes; return {}; @@ -233,7 +239,7 @@ namespace dawn_native { namespace null { bool Buffer::IsMapWritable() const { // Only return true for mappable buffers so we can test cases that need / don't need a // staging buffer. - return (GetUsage() & (dawn::BufferUsageBit::MapRead | dawn::BufferUsageBit::MapWrite)) != 0; + return (GetUsage() & (dawn::BufferUsage::MapRead | dawn::BufferUsage::MapWrite)) != 0; } MaybeError Buffer::MapAtCreationImpl(uint8_t** mappedPointer) { @@ -339,7 +345,7 @@ namespace dawn_native { namespace null { } DawnSwapChainError NativeSwapChainImpl::Configure(DawnTextureFormat format, - DawnTextureUsageBit, + DawnTextureUsage, uint32_t width, uint32_t height) { return DAWN_SWAP_CHAIN_NO_ERROR; diff --git a/chromium/third_party/dawn/src/dawn_native/null/DeviceNull.h b/chromium/third_party/dawn/src/dawn_native/null/DeviceNull.h index cff06a0fd58..640ff588c75 100644 --- a/chromium/third_party/dawn/src/dawn_native/null/DeviceNull.h +++ b/chromium/third_party/dawn/src/dawn_native/null/DeviceNull.h @@ -15,6 +15,7 @@ #ifndef DAWNNATIVE_NULL_DEVICENULL_H_ #define DAWNNATIVE_NULL_DEVICENULL_H_ +#include "dawn_native/Adapter.h" #include "dawn_native/BindGroup.h" #include "dawn_native/BindGroupLayout.h" #include "dawn_native/Buffer.h" @@ -137,6 +138,18 @@ namespace dawn_native { namespace null { size_t mMemoryUsage = 0; }; + class Adapter : public AdapterBase { + public: + Adapter(InstanceBase* instance); + virtual ~Adapter(); + + // Used for the tests that intend to use an adapter without all extensions enabled. + void SetSupportedExtensions(const std::vector<const char*>& requiredExtensions); + + private: + ResultOrError<DeviceBase*> CreateDeviceImpl(const DeviceDescriptor* descriptor) override; + }; + class Buffer : public BufferBase { public: Buffer(Device* device, const BufferDescriptor* descriptor); @@ -196,7 +209,7 @@ namespace dawn_native { namespace null { using WSIContext = struct {}; void Init(WSIContext* context); DawnSwapChainError Configure(DawnTextureFormat format, - DawnTextureUsageBit, + DawnTextureUsage, uint32_t width, uint32_t height); DawnSwapChainError GetNextTexture(DawnSwapChainNextTexture* nextTexture); diff --git a/chromium/third_party/dawn/src/dawn_native/null/NullBackend.cpp b/chromium/third_party/dawn/src/dawn_native/null/NullBackend.cpp index ef1bbe49388..14fff85850e 100644 --- a/chromium/third_party/dawn/src/dawn_native/null/NullBackend.cpp +++ b/chromium/third_party/dawn/src/dawn_native/null/NullBackend.cpp @@ -25,7 +25,7 @@ namespace dawn_native { namespace null { DawnSwapChainImplementation CreateNativeSwapChainImpl() { DawnSwapChainImplementation impl; impl = CreateSwapChainImplementation(new NativeSwapChainImpl()); - impl.textureUsage = DAWN_TEXTURE_USAGE_BIT_PRESENT; + impl.textureUsage = DAWN_TEXTURE_USAGE_PRESENT; return impl; } diff --git a/chromium/third_party/dawn/src/dawn_native/opengl/BackendGL.cpp b/chromium/third_party/dawn/src/dawn_native/opengl/BackendGL.cpp index c1689132c7d..65d086a8455 100644 --- a/chromium/third_party/dawn/src/dawn_native/opengl/BackendGL.cpp +++ b/chromium/third_party/dawn/src/dawn_native/opengl/BackendGL.cpp @@ -161,6 +161,7 @@ namespace dawn_native { namespace opengl { mFunctions.Enable(GL_SCISSOR_TEST); mFunctions.Enable(GL_PRIMITIVE_RESTART_FIXED_INDEX); mFunctions.Enable(GL_MULTISAMPLE); + mFunctions.Enable(GL_FRAMEBUFFER_SRGB); mPCIInfo.name = reinterpret_cast<const char*>(mFunctions.GetString(GL_RENDERER)); @@ -168,6 +169,8 @@ namespace dawn_native { namespace opengl { const char* vendor = reinterpret_cast<const char*>(mFunctions.GetString(GL_VENDOR)); mPCIInfo.vendorId = GetVendorIdFromVendors(vendor); + InitializeSupportedExtensions(); + return {}; } @@ -181,6 +184,43 @@ namespace dawn_native { namespace opengl { // all share the same backing OpenGL context. return {new Device(this, descriptor, mFunctions)}; } + + void InitializeSupportedExtensions() { + // TextureCompressionBC + { + // BC1, BC2 and BC3 are not supported in OpenGL or OpenGL ES core features. + bool supportsS3TC = + mFunctions.IsGLExtensionSupported("GL_EXT_texture_compression_s3tc"); + + // COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT and + // COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT requires both GL_EXT_texture_sRGB and + // GL_EXT_texture_compression_s3tc on desktop OpenGL drivers. + // (https://www.khronos.org/registry/OpenGL/extensions/EXT/EXT_texture_sRGB.txt) + bool supportsTextureSRGB = mFunctions.IsGLExtensionSupported("GL_EXT_texture_sRGB"); + + // GL_EXT_texture_compression_s3tc_srgb is an extension in OpenGL ES. + bool supportsS3TCSRGB = + mFunctions.IsGLExtensionSupported("GL_EXT_texture_compression_s3tc_srgb"); + + // BC4 and BC5 + bool supportsRGTC = + mFunctions.IsAtLeastGL(3, 0) || + mFunctions.IsGLExtensionSupported("GL_ARB_texture_compression_rgtc") || + mFunctions.IsGLExtensionSupported("GL_EXT_texture_compression_rgtc"); + + // BC6 and BC7 + bool supportsBPTC = + mFunctions.IsAtLeastGL(4, 2) || + mFunctions.IsGLExtensionSupported("GL_ARB_texture_compression_bptc") || + mFunctions.IsGLExtensionSupported("GL_EXT_texture_compression_bptc"); + + if (supportsS3TC && (supportsTextureSRGB || supportsS3TCSRGB) && supportsRGTC && + supportsBPTC) { + mSupportedExtensions.EnableExtension( + dawn_native::Extension::TextureCompressionBC); + } + } + } }; // Implementation of the OpenGL backend's BackendConnection diff --git a/chromium/third_party/dawn/src/dawn_native/opengl/CommandBufferGL.cpp b/chromium/third_party/dawn/src/dawn_native/opengl/CommandBufferGL.cpp index 8e4a3ea52ad..8351509d0fa 100644 --- a/chromium/third_party/dawn/src/dawn_native/opengl/CommandBufferGL.cpp +++ b/chromium/third_party/dawn/src/dawn_native/opengl/CommandBufferGL.cpp @@ -17,6 +17,7 @@ #include "dawn_native/BindGroup.h" #include "dawn_native/CommandEncoder.h" #include "dawn_native/Commands.h" +#include "dawn_native/RenderBundle.h" #include "dawn_native/opengl/BufferGL.h" #include "dawn_native/opengl/ComputePipelineGL.h" #include "dawn_native/opengl/DeviceGL.h" @@ -220,9 +221,12 @@ namespace dawn_native { namespace opengl { uint32_t index, BindGroupBase* group, PipelineLayout* pipelineLayout, - PipelineGL* pipeline) { + PipelineGL* pipeline, + uint32_t dynamicOffsetCount, + uint64_t* dynamicOffsets) { const auto& indices = pipelineLayout->GetBindingIndexInfo()[index]; const auto& layout = group->GetLayout()->GetBindingInfo(); + uint32_t currentDynamicIndex = 0; for (uint32_t bindingIndex : IterateBitSet(layout.mask)) { switch (layout.types[bindingIndex]) { @@ -230,18 +234,30 @@ namespace dawn_native { namespace opengl { BufferBinding binding = group->GetBindingAsBufferBinding(bindingIndex); GLuint buffer = ToBackend(binding.buffer)->GetHandle(); GLuint uboIndex = indices[bindingIndex]; + GLuint offset = binding.offset; - gl.BindBufferRange(GL_UNIFORM_BUFFER, uboIndex, buffer, binding.offset, + if (layout.dynamic[bindingIndex]) { + offset += dynamicOffsets[currentDynamicIndex]; + ++currentDynamicIndex; + } + + gl.BindBufferRange(GL_UNIFORM_BUFFER, uboIndex, buffer, offset, binding.size); } break; case dawn::BindingType::Sampler: { - GLuint sampler = - ToBackend(group->GetBindingAsSampler(bindingIndex))->GetHandle(); + Sampler* sampler = ToBackend(group->GetBindingAsSampler(bindingIndex)); GLuint samplerIndex = indices[bindingIndex]; - for (auto unit : pipeline->GetTextureUnitsForSampler(samplerIndex)) { - gl.BindSampler(unit, sampler); + for (PipelineGL::SamplerUnit unit : + pipeline->GetTextureUnitsForSampler(samplerIndex)) { + // Only use filtering for certain texture units, because int and uint + // texture are only complete without filtering + if (unit.shouldUseFiltering) { + gl.BindSampler(unit.unit, sampler->GetFilteringHandle()); + } else { + gl.BindSampler(unit.unit, sampler->GetNonFilteringHandle()); + } } } break; @@ -261,9 +277,15 @@ namespace dawn_native { namespace opengl { BufferBinding binding = group->GetBindingAsBufferBinding(bindingIndex); GLuint buffer = ToBackend(binding.buffer)->GetHandle(); GLuint ssboIndex = indices[bindingIndex]; + GLuint offset = binding.offset; - gl.BindBufferRange(GL_SHADER_STORAGE_BUFFER, ssboIndex, buffer, - binding.offset, binding.size); + if (layout.dynamic[bindingIndex]) { + offset += dynamicOffsets[currentDynamicIndex]; + ++currentDynamicIndex; + } + + gl.BindBufferRange(GL_SHADER_STORAGE_BUFFER, ssboIndex, buffer, offset, + binding.size); } break; case dawn::BindingType::StorageTexture: @@ -283,7 +305,8 @@ namespace dawn_native { namespace opengl { GLuint readFbo = 0; GLuint writeFbo = 0; - for (uint32_t i : IterateBitSet(renderPass->colorAttachmentsSet)) { + for (uint32_t i : + IterateBitSet(renderPass->attachmentState->GetColorAttachmentsMask())) { if (renderPass->colorAttachments[i].resolveTarget.Get() != nullptr) { if (readFbo == 0) { ASSERT(writeFbo == 0); @@ -329,6 +352,28 @@ namespace dawn_native { namespace opengl { gl.DeleteFramebuffers(1, &readFbo); gl.DeleteFramebuffers(1, &writeFbo); } + + // OpenGL SPEC requires the source/destination region must be a region that is contained + // within srcImage/dstImage. Here the size of the image refers to the virtual size, while + // Dawn validates texture copy extent with the physical size, so we need to re-calculate the + // texture copy extent to ensure it should fit in the virtual size of the subresource. + Extent3D ComputeTextureCopyExtent(const TextureCopy& textureCopy, + const Extent3D& copySize) { + Extent3D validTextureCopyExtent = copySize; + const TextureBase* texture = textureCopy.texture.Get(); + Extent3D virtualSizeAtLevel = texture->GetMipLevelVirtualSize(textureCopy.mipLevel); + if (textureCopy.origin.x + copySize.width > virtualSizeAtLevel.width) { + ASSERT(texture->GetFormat().isCompressed); + validTextureCopyExtent.width = virtualSizeAtLevel.width - textureCopy.origin.x; + } + if (textureCopy.origin.y + copySize.height > virtualSizeAtLevel.height) { + ASSERT(texture->GetFormat().isCompressed); + validTextureCopyExtent.height = virtualSizeAtLevel.height - textureCopy.origin.y; + } + + return validTextureCopyExtent; + } + } // namespace CommandBuffer::CommandBuffer(CommandEncoderBase* encoder, @@ -346,8 +391,14 @@ namespace dawn_native { namespace opengl { auto TransitionForPass = [](const PassResourceUsage& usages) { for (size_t i = 0; i < usages.textures.size(); i++) { Texture* texture = ToBackend(usages.textures[i]); - texture->EnsureSubresourceContentInitialized(0, texture->GetNumMipLevels(), 0, - texture->GetArrayLayers()); + // We count the lazy clears for non output attachment textures and depth stencil + // textures in order to match the backdoor lazy clear counts in Vulkan and D3D12. + bool isLazyClear = + ((!(usages.textureUsages[i] & dawn::TextureUsage::OutputAttachment) && + texture->GetFormat().IsColor()) || + texture->GetFormat().HasDepthOrStencil()); + texture->EnsureSubresourceContentInitialized( + 0, texture->GetNumMipLevels(), 0, texture->GetArrayLayers(), isLazyClear); } }; @@ -407,28 +458,60 @@ namespace dawn_native { namespace opengl { gl.ActiveTexture(GL_TEXTURE0); gl.BindTexture(target, texture->GetHandle()); - gl.PixelStorei(GL_UNPACK_ROW_LENGTH, - src.rowPitch / texture->GetFormat().blockByteSize); + const Format& formatInfo = texture->GetFormat(); + gl.PixelStorei( + GL_UNPACK_ROW_LENGTH, + src.rowPitch / texture->GetFormat().blockByteSize * formatInfo.blockWidth); gl.PixelStorei(GL_UNPACK_IMAGE_HEIGHT, src.imageHeight); - switch (texture->GetDimension()) { - case dawn::TextureDimension::e2D: - if (texture->GetArrayLayers() > 1) { - gl.TexSubImage3D( - target, dst.mipLevel, dst.origin.x, dst.origin.y, - dst.arrayLayer, copySize.width, copySize.height, 1, - format.format, format.type, - reinterpret_cast<void*>(static_cast<uintptr_t>(src.offset))); - } else { - gl.TexSubImage2D( - target, dst.mipLevel, dst.origin.x, dst.origin.y, - copySize.width, copySize.height, format.format, format.type, - reinterpret_cast<void*>(static_cast<uintptr_t>(src.offset))); - } - break; - default: - UNREACHABLE(); + if (texture->GetFormat().isCompressed) { + gl.PixelStorei(GL_UNPACK_COMPRESSED_BLOCK_SIZE, formatInfo.blockByteSize); + gl.PixelStorei(GL_UNPACK_COMPRESSED_BLOCK_WIDTH, formatInfo.blockWidth); + gl.PixelStorei(GL_UNPACK_COMPRESSED_BLOCK_HEIGHT, formatInfo.blockHeight); + gl.PixelStorei(GL_UNPACK_COMPRESSED_BLOCK_DEPTH, 1); + + ASSERT(texture->GetDimension() == dawn::TextureDimension::e2D); + uint64_t copyDataSize = + (copySize.width / texture->GetFormat().blockWidth) * + (copySize.height / texture->GetFormat().blockHeight) * + texture->GetFormat().blockByteSize; + Extent3D copyExtent = ComputeTextureCopyExtent(dst, copySize); + + if (texture->GetArrayLayers() > 1) { + gl.CompressedTexSubImage3D( + target, dst.mipLevel, dst.origin.x, dst.origin.y, dst.arrayLayer, + copyExtent.width, copyExtent.height, 1, format.internalFormat, + copyDataSize, + reinterpret_cast<void*>(static_cast<uintptr_t>(src.offset))); + } else { + gl.CompressedTexSubImage2D( + target, dst.mipLevel, dst.origin.x, dst.origin.y, copyExtent.width, + copyExtent.height, format.internalFormat, copyDataSize, + reinterpret_cast<void*>(static_cast<uintptr_t>(src.offset))); + } + } else { + switch (texture->GetDimension()) { + case dawn::TextureDimension::e2D: + if (texture->GetArrayLayers() > 1) { + gl.TexSubImage3D(target, dst.mipLevel, dst.origin.x, + dst.origin.y, dst.arrayLayer, copySize.width, + copySize.height, 1, format.format, format.type, + reinterpret_cast<void*>( + static_cast<uintptr_t>(src.offset))); + } else { + gl.TexSubImage2D(target, dst.mipLevel, dst.origin.x, + dst.origin.y, copySize.width, copySize.height, + format.format, format.type, + reinterpret_cast<void*>( + static_cast<uintptr_t>(src.offset))); + } + break; + + default: + UNREACHABLE(); + } } + gl.PixelStorei(GL_UNPACK_ROW_LENGTH, 0); gl.PixelStorei(GL_UNPACK_IMAGE_HEIGHT, 0); @@ -445,6 +528,12 @@ namespace dawn_native { namespace opengl { const GLFormat& format = texture->GetGLFormat(); GLenum target = texture->GetGLTarget(); + // TODO(jiawei.shao@intel.com): support texture-to-buffer copy with compressed + // texture formats. + if (texture->GetFormat().isCompressed) { + UNREACHABLE(); + } + texture->EnsureSubresourceContentInitialized(src.mipLevel, 1, src.arrayLayer, 1); // The only way to move data from a texture to a buffer in GL is via @@ -491,7 +580,12 @@ namespace dawn_native { namespace opengl { mCommands.NextCommand<CopyTextureToTextureCmd>(); auto& src = copy->source; auto& dst = copy->destination; - auto& copySize = copy->copySize; + + // TODO(jiawei.shao@intel.com): add workaround for the case that imageExtentSrc + // is not equal to imageExtentDst. For example when copySize fits in the virtual + // size of the source image but does not fit in the one of the destination + // image. + Extent3D copySize = ComputeTextureCopyExtent(dst, copy->copySize); Texture* srcTexture = ToBackend(src.texture.Get()); Texture* dstTexture = ToBackend(dst.texture.Get()); srcTexture->EnsureSubresourceContentInitialized(src.mipLevel, 1, src.arrayLayer, @@ -554,8 +648,21 @@ namespace dawn_native { namespace opengl { case Command::SetBindGroup: { SetBindGroupCmd* cmd = mCommands.NextCommand<SetBindGroupCmd>(); + uint64_t* dynamicOffsets = nullptr; + if (cmd->dynamicOffsetCount > 0) { + dynamicOffsets = mCommands.NextData<uint64_t>(cmd->dynamicOffsetCount); + } ApplyBindGroup(gl, cmd->index, cmd->group.Get(), - ToBackend(lastPipeline->GetLayout()), lastPipeline); + ToBackend(lastPipeline->GetLayout()), lastPipeline, + cmd->dynamicOffsetCount, dynamicOffsets); + } break; + + case Command::InsertDebugMarker: + case Command::PopDebugGroup: + case Command::PushDebugGroup: { + // Due to lack of linux driver support for GL_EXT_debug_marker + // extension these functions are skipped. + SkipCommand(&mCommands, type); } break; default: { UNREACHABLE(); } break; @@ -590,7 +697,8 @@ namespace dawn_native { namespace opengl { // Construct GL framebuffer unsigned int attachmentCount = 0; - for (uint32_t i : IterateBitSet(renderPass->colorAttachmentsSet)) { + for (uint32_t i : + IterateBitSet(renderPass->attachmentState->GetColorAttachmentsMask())) { TextureViewBase* textureView = renderPass->colorAttachments[i].view.Get(); GLuint texture = ToBackend(textureView->GetTexture())->GetHandle(); @@ -606,18 +714,10 @@ namespace dawn_native { namespace opengl { } drawBuffers[i] = GL_COLOR_ATTACHMENT0 + i; attachmentCount = i + 1; - - // TODO(kainino@chromium.org): the color clears (later in - // this function) may be undefined for non-normalized integer formats. - dawn::TextureFormat format = textureView->GetTexture()->GetFormat().format; - ASSERT(format == dawn::TextureFormat::RGBA8Unorm || - format == dawn::TextureFormat::RG8Unorm || - format == dawn::TextureFormat::R8Unorm || - format == dawn::TextureFormat::BGRA8Unorm); } gl.DrawBuffers(attachmentCount, drawBuffers.data()); - if (renderPass->hasDepthStencilAttachment) { + if (renderPass->attachmentState->HasDepthStencilAttachment()) { TextureViewBase* textureView = renderPass->depthStencilAttachment.view.Get(); GLuint texture = ToBackend(textureView->GetTexture())->GetHandle(); const Format& format = textureView->GetTexture()->GetFormat(); @@ -643,13 +743,11 @@ namespace dawn_native { namespace opengl { GLenum target = ToBackend(textureView->GetTexture())->GetGLTarget(); gl.FramebufferTexture2D(GL_DRAW_FRAMEBUFFER, glAttachment, target, texture, 0); - - // TODO(kainino@chromium.org): the depth/stencil clears (later in - // this function) may be undefined for other texture formats. - ASSERT(format.format == dawn::TextureFormat::Depth24PlusStencil8); } } + ASSERT(gl.CheckFramebufferStatus(GL_DRAW_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE); + // Set defaults for dynamic state before executing clears and commands. PersistentPipelineState persistentPipelineState; persistentPipelineState.SetDefaultState(gl); @@ -660,17 +758,22 @@ namespace dawn_native { namespace opengl { // Clear framebuffer attachments as needed { - for (uint32_t i : IterateBitSet(renderPass->colorAttachmentsSet)) { + for (uint32_t i : + IterateBitSet(renderPass->attachmentState->GetColorAttachmentsMask())) { const auto& attachmentInfo = renderPass->colorAttachments[i]; // Load op - color + // TODO(cwallez@chromium.org): Choose the clear function depending on the + // componentType: things work for now because the clear color is always a float, but + // when that's fixed will lose precision on integer formats when converting to + // float. if (attachmentInfo.loadOp == dawn::LoadOp::Clear) { gl.ColorMaski(i, true, true, true, true); gl.ClearBufferfv(GL_COLOR, i, &attachmentInfo.clearColor.r); } } - if (renderPass->hasDepthStencilAttachment) { + if (renderPass->attachmentState->HasDepthStencilAttachment()) { const auto& attachmentInfo = renderPass->depthStencilAttachment; const Format& attachmentFormat = attachmentInfo.view->GetTexture()->GetFormat(); @@ -704,21 +807,10 @@ namespace dawn_native { namespace opengl { InputBufferTracker inputBuffers; - Command type; - while (mCommands.NextCommandId(&type)) { + auto DoRenderBundleCommand = [&](CommandIterator* iter, Command type) { switch (type) { - case Command::EndRenderPass: { - mCommands.NextCommand<EndRenderPassCmd>(); - - if (renderPass->sampleCount > 1) { - ResolveMultisampledRenderTargets(gl, renderPass); - } - gl.DeleteFramebuffers(1, &fbo); - return; - } break; - case Command::Draw: { - DrawCmd* draw = mCommands.NextCommand<DrawCmd>(); + DrawCmd* draw = iter->NextCommand<DrawCmd>(); inputBuffers.Apply(gl); if (draw->firstInstance > 0) { @@ -734,7 +826,7 @@ namespace dawn_native { namespace opengl { } break; case Command::DrawIndexed: { - DrawIndexedCmd* draw = mCommands.NextCommand<DrawIndexedCmd>(); + DrawIndexedCmd* draw = iter->NextCommand<DrawIndexedCmd>(); inputBuffers.Apply(gl); dawn::IndexFormat indexFormat = @@ -759,7 +851,7 @@ namespace dawn_native { namespace opengl { } break; case Command::DrawIndirect: { - DrawIndirectCmd* draw = mCommands.NextCommand<DrawIndirectCmd>(); + DrawIndirectCmd* draw = iter->NextCommand<DrawIndirectCmd>(); inputBuffers.Apply(gl); uint64_t indirectBufferOffset = draw->indirectOffset; @@ -772,7 +864,7 @@ namespace dawn_native { namespace opengl { } break; case Command::DrawIndexedIndirect: { - DrawIndexedIndirectCmd* draw = mCommands.NextCommand<DrawIndexedIndirectCmd>(); + DrawIndexedIndirectCmd* draw = iter->NextCommand<DrawIndexedIndirectCmd>(); inputBuffers.Apply(gl); dawn::IndexFormat indexFormat = @@ -793,17 +885,60 @@ namespace dawn_native { namespace opengl { case Command::PushDebugGroup: { // Due to lack of linux driver support for GL_EXT_debug_marker // extension these functions are skipped. - SkipCommand(&mCommands, type); + SkipCommand(iter, type); } break; case Command::SetRenderPipeline: { - SetRenderPipelineCmd* cmd = mCommands.NextCommand<SetRenderPipelineCmd>(); + SetRenderPipelineCmd* cmd = iter->NextCommand<SetRenderPipelineCmd>(); lastPipeline = ToBackend(cmd->pipeline).Get(); lastPipeline->ApplyNow(persistentPipelineState); inputBuffers.OnSetPipeline(lastPipeline); } break; + case Command::SetBindGroup: { + SetBindGroupCmd* cmd = iter->NextCommand<SetBindGroupCmd>(); + uint64_t* dynamicOffsets = nullptr; + if (cmd->dynamicOffsetCount > 0) { + dynamicOffsets = iter->NextData<uint64_t>(cmd->dynamicOffsetCount); + } + ApplyBindGroup(gl, cmd->index, cmd->group.Get(), + ToBackend(lastPipeline->GetLayout()), lastPipeline, + cmd->dynamicOffsetCount, dynamicOffsets); + } break; + + case Command::SetIndexBuffer: { + SetIndexBufferCmd* cmd = iter->NextCommand<SetIndexBufferCmd>(); + indexBufferBaseOffset = cmd->offset; + inputBuffers.OnSetIndexBuffer(cmd->buffer.Get()); + } break; + + case Command::SetVertexBuffers: { + SetVertexBuffersCmd* cmd = iter->NextCommand<SetVertexBuffersCmd>(); + auto buffers = iter->NextData<Ref<BufferBase>>(cmd->count); + auto offsets = iter->NextData<uint64_t>(cmd->count); + inputBuffers.OnSetVertexBuffers(cmd->startSlot, cmd->count, buffers, offsets); + } break; + + default: + UNREACHABLE(); + break; + } + }; + + Command type; + while (mCommands.NextCommandId(&type)) { + switch (type) { + case Command::EndRenderPass: { + mCommands.NextCommand<EndRenderPassCmd>(); + + if (renderPass->attachmentState->GetSampleCount() > 1) { + ResolveMultisampledRenderTargets(gl, renderPass); + } + gl.DeleteFramebuffers(1, &fbo); + return; + } break; + case Command::SetStencilReference: { SetStencilReferenceCmd* cmd = mCommands.NextCommand<SetStencilReferenceCmd>(); persistentPipelineState.SetStencilReference(gl, cmd->reference); @@ -825,26 +960,20 @@ namespace dawn_native { namespace opengl { gl.BlendColor(cmd->color.r, cmd->color.g, cmd->color.b, cmd->color.a); } break; - case Command::SetBindGroup: { - SetBindGroupCmd* cmd = mCommands.NextCommand<SetBindGroupCmd>(); - ApplyBindGroup(gl, cmd->index, cmd->group.Get(), - ToBackend(lastPipeline->GetLayout()), lastPipeline); - } break; - - case Command::SetIndexBuffer: { - SetIndexBufferCmd* cmd = mCommands.NextCommand<SetIndexBufferCmd>(); - indexBufferBaseOffset = cmd->offset; - inputBuffers.OnSetIndexBuffer(cmd->buffer.Get()); - } break; + case Command::ExecuteBundles: { + ExecuteBundlesCmd* cmd = mCommands.NextCommand<ExecuteBundlesCmd>(); + auto bundles = mCommands.NextData<Ref<RenderBundleBase>>(cmd->count); - case Command::SetVertexBuffers: { - SetVertexBuffersCmd* cmd = mCommands.NextCommand<SetVertexBuffersCmd>(); - auto buffers = mCommands.NextData<Ref<BufferBase>>(cmd->count); - auto offsets = mCommands.NextData<uint64_t>(cmd->count); - inputBuffers.OnSetVertexBuffers(cmd->startSlot, cmd->count, buffers, offsets); + for (uint32_t i = 0; i < cmd->count; ++i) { + CommandIterator* iter = bundles[i]->GetCommands(); + iter->Reset(); + while (iter->NextCommandId(&type)) { + DoRenderBundleCommand(iter, type); + } + } } break; - default: { UNREACHABLE(); } break; + default: { DoRenderBundleCommand(&mCommands, type); } break; } } diff --git a/chromium/third_party/dawn/src/dawn_native/opengl/ComputePipelineGL.cpp b/chromium/third_party/dawn/src/dawn_native/opengl/ComputePipelineGL.cpp index 362d23b1b35..ab25bb1e23d 100644 --- a/chromium/third_party/dawn/src/dawn_native/opengl/ComputePipelineGL.cpp +++ b/chromium/third_party/dawn/src/dawn_native/opengl/ComputePipelineGL.cpp @@ -21,7 +21,7 @@ namespace dawn_native { namespace opengl { ComputePipeline::ComputePipeline(Device* device, const ComputePipelineDescriptor* descriptor) : ComputePipelineBase(device, descriptor) { PerStage<const ShaderModule*> modules(nullptr); - modules[ShaderStage::Compute] = ToBackend(descriptor->computeStage->module); + modules[SingleShaderStage::Compute] = ToBackend(descriptor->computeStage.module); PipelineGL::Initialize(device->gl, ToBackend(descriptor->layout), modules); } diff --git a/chromium/third_party/dawn/src/dawn_native/opengl/GLFormat.cpp b/chromium/third_party/dawn/src/dawn_native/opengl/GLFormat.cpp index 617a02ece23..460690c2b82 100644 --- a/chromium/third_party/dawn/src/dawn_native/opengl/GLFormat.cpp +++ b/chromium/third_party/dawn/src/dawn_native/opengl/GLFormat.cpp @@ -19,28 +19,98 @@ namespace dawn_native { namespace opengl { GLFormatTable BuildGLFormatTable() { GLFormatTable table; + using Type = GLFormat::ComponentType; + auto AddFormat = [&table](dawn::TextureFormat dawnFormat, GLenum internalFormat, - GLenum format, GLenum type) { + GLenum format, GLenum type, Type componentType) { size_t index = ComputeFormatIndex(dawnFormat); ASSERT(index < table.size()); table[index].internalFormat = internalFormat; table[index].format = format; table[index].type = type; + table[index].componentType = componentType; table[index].isSupportedOnBackend = true; }; - AddFormat(dawn::TextureFormat::RGBA8Unorm, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE); - AddFormat(dawn::TextureFormat::RG8Unorm, GL_RG8, GL_RG, GL_UNSIGNED_BYTE); - AddFormat(dawn::TextureFormat::R8Unorm, GL_R8, GL_RED, GL_UNSIGNED_BYTE); - AddFormat(dawn::TextureFormat::RGBA8Uint, GL_RGBA8UI, GL_RGBA, GL_UNSIGNED_INT); - AddFormat(dawn::TextureFormat::RG8Uint, GL_RG8UI, GL_RG, GL_UNSIGNED_INT); - AddFormat(dawn::TextureFormat::R8Uint, GL_R8UI, GL_RED, GL_UNSIGNED_INT); + // It's dangerous to go alone, take this: + // + // [ANGLE's formatutils.cpp] + // [ANGLE's formatutilsgl.cpp] + // + // The format tables in these files are extremely complete and the best reference on GL + // format support, enums, etc. + + // clang-format off + + // 1 byte color formats + AddFormat(dawn::TextureFormat::R8Unorm, GL_R8, GL_RED, GL_UNSIGNED_BYTE, Type::Float); + AddFormat(dawn::TextureFormat::R8Snorm, GL_R8_SNORM, GL_RED, GL_BYTE, Type::Float); + AddFormat(dawn::TextureFormat::R8Uint, GL_R8UI, GL_RED_INTEGER, GL_UNSIGNED_BYTE, Type::Uint); + AddFormat(dawn::TextureFormat::R8Sint, GL_R8I, GL_RED_INTEGER, GL_BYTE, Type::Int); + + // 2 bytes color formats + AddFormat(dawn::TextureFormat::R16Uint, GL_R16UI, GL_RED_INTEGER, GL_UNSIGNED_SHORT, Type::Uint); + AddFormat(dawn::TextureFormat::R16Sint, GL_R16I, GL_RED_INTEGER, GL_SHORT, Type::Int); + AddFormat(dawn::TextureFormat::R16Float, GL_R16F, GL_RED, GL_HALF_FLOAT, Type::Float); + AddFormat(dawn::TextureFormat::RG8Unorm, GL_RG8, GL_RG, GL_UNSIGNED_BYTE, Type::Float); + AddFormat(dawn::TextureFormat::RG8Snorm, GL_RG8_SNORM, GL_RG, GL_BYTE, Type::Float); + AddFormat(dawn::TextureFormat::RG8Uint, GL_RG8UI, GL_RG_INTEGER, GL_UNSIGNED_BYTE, Type::Uint); + AddFormat(dawn::TextureFormat::RG8Sint, GL_RG8I, GL_RG_INTEGER, GL_BYTE, Type::Int); + + // 4 bytes color formats + AddFormat(dawn::TextureFormat::R32Uint, GL_R32UI, GL_RED_INTEGER, GL_UNSIGNED_INT, Type::Uint); + AddFormat(dawn::TextureFormat::R32Sint, GL_R32I, GL_RED_INTEGER, GL_INT, Type::Int); + AddFormat(dawn::TextureFormat::R32Float, GL_R32F, GL_RED, GL_FLOAT, Type::Float); + AddFormat(dawn::TextureFormat::RG16Uint, GL_RG16UI, GL_RG_INTEGER, GL_UNSIGNED_SHORT, Type::Uint); + AddFormat(dawn::TextureFormat::RG16Sint, GL_RG16I, GL_RG_INTEGER, GL_SHORT, Type::Int); + AddFormat(dawn::TextureFormat::RG16Float, GL_RG16F, GL_RG, GL_HALF_FLOAT, Type::Float); + AddFormat(dawn::TextureFormat::RGBA8Unorm, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, Type::Float); + AddFormat(dawn::TextureFormat::RGBA8UnormSrgb, GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, Type::Float); + AddFormat(dawn::TextureFormat::RGBA8Snorm, GL_RGBA8_SNORM, GL_RGBA, GL_BYTE, Type::Float); + AddFormat(dawn::TextureFormat::RGBA8Uint, GL_RGBA8UI, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE, Type::Uint); + AddFormat(dawn::TextureFormat::RGBA8Sint, GL_RGBA8I, GL_RGBA_INTEGER, GL_BYTE, Type::Int); + // This doesn't have an enum for the internal format in OpenGL, so use RGBA8. - AddFormat(dawn::TextureFormat::BGRA8Unorm, GL_RGBA8, GL_BGRA, GL_UNSIGNED_BYTE); + AddFormat(dawn::TextureFormat::BGRA8Unorm, GL_RGBA8, GL_BGRA, GL_UNSIGNED_BYTE, Type::Float); + AddFormat(dawn::TextureFormat::RGB10A2Unorm, GL_RGB10_A2, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, Type::Float); + AddFormat(dawn::TextureFormat::RG11B10Float, GL_R11F_G11F_B10F, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV, Type::Float); + + // 8 bytes color formats + AddFormat(dawn::TextureFormat::RG32Uint, GL_RG32UI, GL_RG_INTEGER, GL_UNSIGNED_INT, Type::Uint); + AddFormat(dawn::TextureFormat::RG32Sint, GL_RG32I, GL_RG_INTEGER, GL_INT, Type::Int); + AddFormat(dawn::TextureFormat::RG32Float, GL_RG32F, GL_RG, GL_FLOAT, Type::Float); + AddFormat(dawn::TextureFormat::RGBA16Uint, GL_RGBA16UI, GL_RGBA_INTEGER, GL_UNSIGNED_SHORT, Type::Uint); + AddFormat(dawn::TextureFormat::RGBA16Sint, GL_RGBA16I, GL_RGBA_INTEGER, GL_SHORT, Type::Int); + AddFormat(dawn::TextureFormat::RGBA16Float, GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT, Type::Float); + + // 16 bytes color formats + AddFormat(dawn::TextureFormat::RGBA32Uint, GL_RGBA32UI, GL_RGBA_INTEGER, GL_UNSIGNED_INT, Type::Uint); + AddFormat(dawn::TextureFormat::RGBA32Sint, GL_RGBA32I, GL_RGBA_INTEGER, GL_INT, Type::Int); + AddFormat(dawn::TextureFormat::RGBA32Float, GL_RGBA32F, GL_RGBA, GL_FLOAT, Type::Float); + + // Depth stencil formats + AddFormat(dawn::TextureFormat::Depth32Float, GL_DEPTH_COMPONENT32F, GL_DEPTH, GL_FLOAT, Type::DepthStencil); + AddFormat(dawn::TextureFormat::Depth24Plus, GL_DEPTH_COMPONENT32F, GL_DEPTH, GL_FLOAT, Type::DepthStencil); + AddFormat(dawn::TextureFormat::Depth24PlusStencil8, GL_DEPTH32F_STENCIL8, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV, Type::DepthStencil); + + // Block compressed formats + AddFormat(dawn::TextureFormat::BC1RGBAUnorm, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, GL_RGBA, GL_UNSIGNED_BYTE, Type::Float); + AddFormat(dawn::TextureFormat::BC1RGBAUnormSrgb, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, GL_RGBA, GL_UNSIGNED_BYTE, Type::Float); + AddFormat(dawn::TextureFormat::BC2RGBAUnorm, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, GL_RGBA, GL_UNSIGNED_BYTE, Type::Float); + AddFormat(dawn::TextureFormat::BC2RGBAUnormSrgb, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, GL_RGBA, GL_UNSIGNED_BYTE, Type::Float); + AddFormat(dawn::TextureFormat::BC3RGBAUnorm, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_RGBA, GL_UNSIGNED_BYTE, Type::Float); + AddFormat(dawn::TextureFormat::BC3RGBAUnormSrgb, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, GL_RGBA, GL_UNSIGNED_BYTE, Type::Float); + AddFormat(dawn::TextureFormat::BC4RSnorm, GL_COMPRESSED_SIGNED_RED_RGTC1, GL_RED, GL_BYTE, Type::Float); + AddFormat(dawn::TextureFormat::BC4RUnorm, GL_COMPRESSED_RED_RGTC1, GL_RED, GL_UNSIGNED_BYTE, Type::Float); + AddFormat(dawn::TextureFormat::BC5RGSnorm, GL_COMPRESSED_SIGNED_RG_RGTC2, GL_RG, GL_BYTE, Type::Float); + AddFormat(dawn::TextureFormat::BC5RGUnorm, GL_COMPRESSED_RG_RGTC2, GL_RG, GL_UNSIGNED_BYTE, Type::Float); + AddFormat(dawn::TextureFormat::BC6HRGBSfloat, GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT, GL_RGB, GL_HALF_FLOAT, Type::Float); + AddFormat(dawn::TextureFormat::BC6HRGBUfloat, GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT, GL_RGB, GL_HALF_FLOAT, Type::Float); + AddFormat(dawn::TextureFormat::BC7RGBAUnorm, GL_COMPRESSED_RGBA_BPTC_UNORM, GL_RGBA, GL_UNSIGNED_BYTE, Type::Float); + AddFormat(dawn::TextureFormat::BC7RGBAUnormSrgb, GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM, GL_RGBA, GL_UNSIGNED_BYTE, Type::Float); - AddFormat(dawn::TextureFormat::Depth24PlusStencil8, GL_DEPTH32F_STENCIL8, GL_DEPTH_STENCIL, - GL_FLOAT_32_UNSIGNED_INT_24_8_REV); + // clang-format on return table; } diff --git a/chromium/third_party/dawn/src/dawn_native/opengl/GLFormat.h b/chromium/third_party/dawn/src/dawn_native/opengl/GLFormat.h index fdd04e9a618..255b17cdd5e 100644 --- a/chromium/third_party/dawn/src/dawn_native/opengl/GLFormat.h +++ b/chromium/third_party/dawn/src/dawn_native/opengl/GLFormat.h @@ -27,6 +27,11 @@ namespace dawn_native { namespace opengl { GLenum format = 0; GLenum type = 0; bool isSupportedOnBackend = false; + + // OpenGL has different functions depending on the format component type, for example + // glClearBufferfv is only valid on formats with the Float ComponentType + enum ComponentType { Float, Int, Uint, DepthStencil }; + ComponentType componentType; }; using GLFormatTable = std::array<GLFormat, kKnownFormatCount>; diff --git a/chromium/third_party/dawn/src/dawn_native/opengl/NativeSwapChainImplGL.cpp b/chromium/third_party/dawn/src/dawn_native/opengl/NativeSwapChainImplGL.cpp index 656a4acb3c3..f1078754915 100644 --- a/chromium/third_party/dawn/src/dawn_native/opengl/NativeSwapChainImplGL.cpp +++ b/chromium/third_party/dawn/src/dawn_native/opengl/NativeSwapChainImplGL.cpp @@ -43,7 +43,7 @@ namespace dawn_native { namespace opengl { } DawnSwapChainError NativeSwapChainImpl::Configure(DawnTextureFormat format, - DawnTextureUsageBit usage, + DawnTextureUsage usage, uint32_t width, uint32_t height) { if (format != DAWN_TEXTURE_FORMAT_RGBA8_UNORM) { diff --git a/chromium/third_party/dawn/src/dawn_native/opengl/NativeSwapChainImplGL.h b/chromium/third_party/dawn/src/dawn_native/opengl/NativeSwapChainImplGL.h index ff38f6dc4b6..81a5dc9d86c 100644 --- a/chromium/third_party/dawn/src/dawn_native/opengl/NativeSwapChainImplGL.h +++ b/chromium/third_party/dawn/src/dawn_native/opengl/NativeSwapChainImplGL.h @@ -33,7 +33,7 @@ namespace dawn_native { namespace opengl { void Init(DawnWSIContextGL* context); DawnSwapChainError Configure(DawnTextureFormat format, - DawnTextureUsageBit, + DawnTextureUsage, uint32_t width, uint32_t height); DawnSwapChainError GetNextTexture(DawnSwapChainNextTexture* nextTexture); diff --git a/chromium/third_party/dawn/src/dawn_native/opengl/OpenGLBackend.cpp b/chromium/third_party/dawn/src/dawn_native/opengl/OpenGLBackend.cpp index 22dc697ea3a..91b019f2131 100644 --- a/chromium/third_party/dawn/src/dawn_native/opengl/OpenGLBackend.cpp +++ b/chromium/third_party/dawn/src/dawn_native/opengl/OpenGLBackend.cpp @@ -35,7 +35,7 @@ namespace dawn_native { namespace opengl { DawnSwapChainImplementation impl; impl = CreateSwapChainImplementation( new NativeSwapChainImpl(backendDevice, present, presentUserdata)); - impl.textureUsage = DAWN_TEXTURE_USAGE_BIT_PRESENT; + impl.textureUsage = DAWN_TEXTURE_USAGE_PRESENT; return impl; } diff --git a/chromium/third_party/dawn/src/dawn_native/opengl/OpenGLFunctions.cpp b/chromium/third_party/dawn/src/dawn_native/opengl/OpenGLFunctions.cpp index 12d5794ab20..0bc5781a1aa 100644 --- a/chromium/third_party/dawn/src/dawn_native/opengl/OpenGLFunctions.cpp +++ b/chromium/third_party/dawn/src/dawn_native/opengl/OpenGLFunctions.cpp @@ -22,7 +22,7 @@ namespace dawn_native { namespace opengl { MaybeError OpenGLFunctions::Initialize(GetProcAddress getProc) { PFNGLGETSTRINGPROC getString = reinterpret_cast<PFNGLGETSTRINGPROC>(getProc("glGetString")); if (getString == nullptr) { - return DAWN_CONTEXT_LOST_ERROR("Couldn't load glGetString"); + return DAWN_DEVICE_LOST_ERROR("Couldn't load glGetString"); } std::string version = reinterpret_cast<const char*>(getString(GL_VERSION)); @@ -54,9 +54,26 @@ namespace dawn_native { namespace opengl { DAWN_TRY(LoadDesktopGLProcs(getProc, mMajorVersion, mMinorVersion)); } + InitializeSupportedGLExtensions(); + return {}; } + void OpenGLFunctions::InitializeSupportedGLExtensions() { + int32_t numExtensions; + GetIntegerv(GL_NUM_EXTENSIONS, &numExtensions); + + for (int32_t i = 0; i < numExtensions; ++i) { + const char* extensionName = reinterpret_cast<const char*>(GetStringi(GL_EXTENSIONS, i)); + mSupportedGLExtensionsSet.insert(extensionName); + } + } + + bool OpenGLFunctions::IsGLExtensionSupported(const char* extension) const { + ASSERT(extension != nullptr); + return mSupportedGLExtensionsSet.count(extension) != 0; + } + bool OpenGLFunctions::IsAtLeastGL(uint32_t majorVersion, uint32_t minorVersion) { return mStandard == Standard::Desktop && std::tie(mMajorVersion, mMinorVersion) >= std::tie(majorVersion, minorVersion); diff --git a/chromium/third_party/dawn/src/dawn_native/opengl/OpenGLFunctions.h b/chromium/third_party/dawn/src/dawn_native/opengl/OpenGLFunctions.h index 9fe81a5759c..14c7e9198a7 100644 --- a/chromium/third_party/dawn/src/dawn_native/opengl/OpenGLFunctions.h +++ b/chromium/third_party/dawn/src/dawn_native/opengl/OpenGLFunctions.h @@ -15,6 +15,8 @@ #ifndef DAWNNATIVE_OPENGL_OPENGLFUNCTIONS_H_ #define DAWNNATIVE_OPENGL_OPENGLFUNCTIONS_H_ +#include <unordered_set> + #include "dawn_native/opengl/OpenGLFunctionsBase_autogen.h" namespace dawn_native { namespace opengl { @@ -26,7 +28,11 @@ namespace dawn_native { namespace opengl { bool IsAtLeastGL(uint32_t majorVersion, uint32_t minorVersion); bool IsAtLeastGLES(uint32_t majorVersion, uint32_t minorVersion); + bool IsGLExtensionSupported(const char* extension) const; + private: + void InitializeSupportedGLExtensions(); + uint32_t mMajorVersion; uint32_t mMinorVersion; @@ -35,6 +41,8 @@ namespace dawn_native { namespace opengl { ES, }; Standard mStandard; + + std::unordered_set<std::string> mSupportedGLExtensionsSet; }; }} // namespace dawn_native::opengl diff --git a/chromium/third_party/dawn/src/dawn_native/opengl/PipelineGL.cpp b/chromium/third_party/dawn/src/dawn_native/opengl/PipelineGL.cpp index e04dbc7baba..57d72643379 100644 --- a/chromium/third_party/dawn/src/dawn_native/opengl/PipelineGL.cpp +++ b/chromium/third_party/dawn/src/dawn_native/opengl/PipelineGL.cpp @@ -28,13 +28,13 @@ namespace dawn_native { namespace opengl { namespace { - GLenum GLShaderType(ShaderStage stage) { + GLenum GLShaderType(SingleShaderStage stage) { switch (stage) { - case ShaderStage::Vertex: + case SingleShaderStage::Vertex: return GL_VERTEX_SHADER; - case ShaderStage::Fragment: + case SingleShaderStage::Fragment: return GL_FRAGMENT_SHADER; - case ShaderStage::Compute: + case SingleShaderStage::Compute: return GL_COMPUTE_SHADER; default: UNREACHABLE(); @@ -74,14 +74,14 @@ namespace dawn_native { namespace opengl { mProgram = gl.CreateProgram(); - dawn::ShaderStageBit activeStages = dawn::ShaderStageBit::None; - for (ShaderStage stage : IterateStages(kAllStages)) { + dawn::ShaderStage activeStages = dawn::ShaderStage::None; + for (SingleShaderStage stage : IterateStages(kAllStages)) { if (modules[stage] != nullptr) { activeStages |= StageBit(stage); } } - for (ShaderStage stage : IterateStages(activeStages)) { + for (SingleShaderStage stage : IterateStages(activeStages)) { GLuint shader = CreateShader(gl, GLShaderType(stage), modules[stage]->GetSource()); gl.AttachShader(mProgram, shader); } @@ -153,7 +153,7 @@ namespace dawn_native { namespace opengl { // Compute links between stages for combined samplers, then bind them to texture units { std::set<CombinedSampler> combinedSamplersSet; - for (ShaderStage stage : IterateStages(activeStages)) { + for (SingleShaderStage stage : IterateStages(activeStages)) { for (const auto& combined : modules[stage]->GetCombinedSamplerInfo()) { combinedSamplersSet.insert(combined); } @@ -173,20 +173,27 @@ namespace dawn_native { namespace opengl { gl.Uniform1i(location, textureUnit); - GLuint samplerIndex = - indices[combined.samplerLocation.group][combined.samplerLocation.binding]; - mUnitsForSamplers[samplerIndex].push_back(textureUnit); - GLuint textureIndex = indices[combined.textureLocation.group][combined.textureLocation.binding]; mUnitsForTextures[textureIndex].push_back(textureUnit); + dawn::TextureComponentType componentType = + layout->GetBindGroupLayout(combined.textureLocation.group) + ->GetBindingInfo() + .textureComponentTypes[combined.textureLocation.binding]; + bool shouldUseFiltering = componentType == dawn::TextureComponentType::Float; + + GLuint samplerIndex = + indices[combined.samplerLocation.group][combined.samplerLocation.binding]; + mUnitsForSamplers[samplerIndex].push_back({textureUnit, shouldUseFiltering}); + textureUnit++; } } } - const std::vector<GLuint>& PipelineGL::GetTextureUnitsForSampler(GLuint index) const { + const std::vector<PipelineGL::SamplerUnit>& PipelineGL::GetTextureUnitsForSampler( + GLuint index) const { ASSERT(index < mUnitsForSamplers.size()); return mUnitsForSamplers[index]; } diff --git a/chromium/third_party/dawn/src/dawn_native/opengl/PipelineGL.h b/chromium/third_party/dawn/src/dawn_native/opengl/PipelineGL.h index b5745892c3c..6a081c119e5 100644 --- a/chromium/third_party/dawn/src/dawn_native/opengl/PipelineGL.h +++ b/chromium/third_party/dawn/src/dawn_native/opengl/PipelineGL.h @@ -39,7 +39,13 @@ namespace dawn_native { namespace opengl { using BindingLocations = std::array<std::array<GLint, kMaxBindingsPerGroup>, kMaxBindGroups>; - const std::vector<GLuint>& GetTextureUnitsForSampler(GLuint index) const; + // For each unit a sampler is bound to we need to know if we should use filtering or not + // because int and uint texture are only complete without filtering. + struct SamplerUnit { + GLuint unit; + bool shouldUseFiltering; + }; + const std::vector<SamplerUnit>& GetTextureUnitsForSampler(GLuint index) const; const std::vector<GLuint>& GetTextureUnitsForTextureView(GLuint index) const; GLuint GetProgramHandle() const; @@ -47,7 +53,7 @@ namespace dawn_native { namespace opengl { private: GLuint mProgram; - std::vector<std::vector<GLuint>> mUnitsForSamplers; + std::vector<std::vector<SamplerUnit>> mUnitsForSamplers; std::vector<std::vector<GLuint>> mUnitsForTextures; }; diff --git a/chromium/third_party/dawn/src/dawn_native/opengl/RenderPipelineGL.cpp b/chromium/third_party/dawn/src/dawn_native/opengl/RenderPipelineGL.cpp index 49023803126..efbe76184b4 100644 --- a/chromium/third_party/dawn/src/dawn_native/opengl/RenderPipelineGL.cpp +++ b/chromium/third_party/dawn/src/dawn_native/opengl/RenderPipelineGL.cpp @@ -198,8 +198,8 @@ namespace dawn_native { namespace opengl { mVertexArrayObject(0), mGlPrimitiveTopology(GLPrimitiveTopology(GetPrimitiveTopology())) { PerStage<const ShaderModule*> modules(nullptr); - modules[ShaderStage::Vertex] = ToBackend(descriptor->vertexStage->module); - modules[ShaderStage::Fragment] = ToBackend(descriptor->fragmentStage->module); + modules[SingleShaderStage::Vertex] = ToBackend(descriptor->vertexStage.module); + modules[SingleShaderStage::Fragment] = ToBackend(descriptor->fragmentStage->module); PipelineGL::Initialize(device->gl, ToBackend(GetLayout()), modules); CreateVAOForVertexInput(descriptor->vertexInput); diff --git a/chromium/third_party/dawn/src/dawn_native/opengl/SamplerGL.cpp b/chromium/third_party/dawn/src/dawn_native/opengl/SamplerGL.cpp index 832a4ffc278..17bf353ed51 100644 --- a/chromium/third_party/dawn/src/dawn_native/opengl/SamplerGL.cpp +++ b/chromium/third_party/dawn/src/dawn_native/opengl/SamplerGL.cpp @@ -76,26 +76,53 @@ namespace dawn_native { namespace opengl { : SamplerBase(device, descriptor) { const OpenGLFunctions& gl = ToBackend(GetDevice())->gl; - gl.GenSamplers(1, &mHandle); - gl.SamplerParameteri(mHandle, GL_TEXTURE_MAG_FILTER, MagFilterMode(descriptor->magFilter)); - gl.SamplerParameteri(mHandle, GL_TEXTURE_MIN_FILTER, - MinFilterMode(descriptor->minFilter, descriptor->mipmapFilter)); - gl.SamplerParameteri(mHandle, GL_TEXTURE_WRAP_R, WrapMode(descriptor->addressModeW)); - gl.SamplerParameteri(mHandle, GL_TEXTURE_WRAP_S, WrapMode(descriptor->addressModeU)); - gl.SamplerParameteri(mHandle, GL_TEXTURE_WRAP_T, WrapMode(descriptor->addressModeV)); + gl.GenSamplers(1, &mFilteringHandle); + SetupGLSampler(mFilteringHandle, descriptor, false); - gl.SamplerParameterf(mHandle, GL_TEXTURE_MIN_LOD, descriptor->lodMinClamp); - gl.SamplerParameterf(mHandle, GL_TEXTURE_MAX_LOD, descriptor->lodMaxClamp); + gl.GenSamplers(1, &mNonFilteringHandle); + SetupGLSampler(mNonFilteringHandle, descriptor, true); + } + + Sampler::~Sampler() { + const OpenGLFunctions& gl = ToBackend(GetDevice())->gl; + gl.DeleteSamplers(1, &mFilteringHandle); + gl.DeleteSamplers(1, &mNonFilteringHandle); + } + + void Sampler::SetupGLSampler(GLuint sampler, + const SamplerDescriptor* descriptor, + bool forceNearest) { + const OpenGLFunctions& gl = ToBackend(GetDevice())->gl; + + if (forceNearest) { + gl.SamplerParameteri(sampler, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + gl.SamplerParameteri(sampler, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST); + } else { + gl.SamplerParameteri(sampler, GL_TEXTURE_MAG_FILTER, + MagFilterMode(descriptor->magFilter)); + gl.SamplerParameteri(sampler, GL_TEXTURE_MIN_FILTER, + MinFilterMode(descriptor->minFilter, descriptor->mipmapFilter)); + } + gl.SamplerParameteri(sampler, GL_TEXTURE_WRAP_R, WrapMode(descriptor->addressModeW)); + gl.SamplerParameteri(sampler, GL_TEXTURE_WRAP_S, WrapMode(descriptor->addressModeU)); + gl.SamplerParameteri(sampler, GL_TEXTURE_WRAP_T, WrapMode(descriptor->addressModeV)); + + gl.SamplerParameterf(sampler, GL_TEXTURE_MIN_LOD, descriptor->lodMinClamp); + gl.SamplerParameterf(sampler, GL_TEXTURE_MAX_LOD, descriptor->lodMaxClamp); if (ToOpenGLCompareFunction(descriptor->compare) != GL_NEVER) { - gl.SamplerParameteri(mHandle, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); - gl.SamplerParameteri(mHandle, GL_TEXTURE_COMPARE_FUNC, + gl.SamplerParameteri(sampler, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); + gl.SamplerParameteri(sampler, GL_TEXTURE_COMPARE_FUNC, ToOpenGLCompareFunction(descriptor->compare)); } } - GLuint Sampler::GetHandle() const { - return mHandle; + GLuint Sampler::GetFilteringHandle() const { + return mFilteringHandle; + } + + GLuint Sampler::GetNonFilteringHandle() const { + return mNonFilteringHandle; } }} // namespace dawn_native::opengl diff --git a/chromium/third_party/dawn/src/dawn_native/opengl/SamplerGL.h b/chromium/third_party/dawn/src/dawn_native/opengl/SamplerGL.h index 3c4911be4e1..19b185b10f3 100644 --- a/chromium/third_party/dawn/src/dawn_native/opengl/SamplerGL.h +++ b/chromium/third_party/dawn/src/dawn_native/opengl/SamplerGL.h @@ -26,11 +26,19 @@ namespace dawn_native { namespace opengl { class Sampler : public SamplerBase { public: Sampler(Device* device, const SamplerDescriptor* descriptor); + ~Sampler(); - GLuint GetHandle() const; + GLuint GetFilteringHandle() const; + GLuint GetNonFilteringHandle() const; private: - GLuint mHandle; + void SetupGLSampler(GLuint sampler, const SamplerDescriptor* descriptor, bool forceNearest); + + GLuint mFilteringHandle; + + // This is a sampler equivalent to mFilteringHandle except that it uses NEAREST filtering + // for everything, which is important to preserve texture completeness for u/int textures. + GLuint mNonFilteringHandle; }; }} // namespace dawn_native::opengl diff --git a/chromium/third_party/dawn/src/dawn_native/opengl/ShaderModuleGL.cpp b/chromium/third_party/dawn/src/dawn_native/opengl/ShaderModuleGL.cpp index 0166b3f2d9e..e7e2d33e537 100644 --- a/chromium/third_party/dawn/src/dawn_native/opengl/ShaderModuleGL.cpp +++ b/chromium/third_party/dawn/src/dawn_native/opengl/ShaderModuleGL.cpp @@ -18,7 +18,7 @@ #include "common/Platform.h" #include "dawn_native/opengl/DeviceGL.h" -#include <spirv-cross/spirv_glsl.hpp> +#include <spirv_glsl.hpp> #include <sstream> diff --git a/chromium/third_party/dawn/src/dawn_native/opengl/SwapChainGL.cpp b/chromium/third_party/dawn/src/dawn_native/opengl/SwapChainGL.cpp index 2a9fe294d55..e988bc4dea8 100644 --- a/chromium/third_party/dawn/src/dawn_native/opengl/SwapChainGL.cpp +++ b/chromium/third_party/dawn/src/dawn_native/opengl/SwapChainGL.cpp @@ -36,7 +36,7 @@ namespace dawn_native { namespace opengl { DawnSwapChainNextTexture next = {}; DawnSwapChainError error = im.GetNextTexture(im.userData, &next); if (error) { - GetDevice()->HandleError(error); + GetDevice()->HandleError(dawn::ErrorType::Unknown, error); return nullptr; } GLuint nativeTexture = next.texture.u32; diff --git a/chromium/third_party/dawn/src/dawn_native/opengl/TextureGL.cpp b/chromium/third_party/dawn/src/dawn_native/opengl/TextureGL.cpp index cdb74192838..94bd58f0286 100644 --- a/chromium/third_party/dawn/src/dawn_native/opengl/TextureGL.cpp +++ b/chromium/third_party/dawn/src/dawn_native/opengl/TextureGL.cpp @@ -66,9 +66,9 @@ namespace dawn_native { namespace opengl { return handle; } - bool UsageNeedsTextureView(dawn::TextureUsageBit usage) { - constexpr dawn::TextureUsageBit kUsageNeedingTextureView = - dawn::TextureUsageBit::Storage | dawn::TextureUsageBit::Sampled; + bool UsageNeedsTextureView(dawn::TextureUsage usage) { + constexpr dawn::TextureUsage kUsageNeedingTextureView = + dawn::TextureUsage::Storage | dawn::TextureUsage::Sampled; return usage & kUsageNeedingTextureView; } @@ -187,6 +187,11 @@ namespace dawn_native { namespace opengl { GLint baseArrayLayer, uint32_t layerCount) { const OpenGLFunctions& gl = ToBackend(GetDevice())->gl; + // TODO(jiawei.shao@intel.com): initialize the textures with compressed formats. + if (GetFormat().isCompressed) { + return; + } + if (GetFormat().HasDepthOrStencil()) { bool doDepthClear = GetFormat().HasDepth(); bool doStencilClear = GetFormat().HasStencil(); @@ -221,19 +226,24 @@ namespace dawn_native { namespace opengl { nullptr); } } - SetIsSubresourceContentInitialized(baseMipLevel, levelCount, baseArrayLayer, layerCount); } void Texture::EnsureSubresourceContentInitialized(uint32_t baseMipLevel, uint32_t levelCount, uint32_t baseArrayLayer, - uint32_t layerCount) { + uint32_t layerCount, + bool isLazyClear) { if (!GetDevice()->IsToggleEnabled(Toggle::LazyClearResourceOnFirstUse)) { return; } if (!IsSubresourceContentInitialized(baseMipLevel, levelCount, baseArrayLayer, layerCount)) { ClearTexture(baseMipLevel, levelCount, baseArrayLayer, layerCount); + if (isLazyClear) { + GetDevice()->IncrementLazyClearCountForTesting(); + } + SetIsSubresourceContentInitialized(baseMipLevel, levelCount, baseArrayLayer, + layerCount); } } diff --git a/chromium/third_party/dawn/src/dawn_native/opengl/TextureGL.h b/chromium/third_party/dawn/src/dawn_native/opengl/TextureGL.h index 4b8798e4626..40d82e8a91f 100644 --- a/chromium/third_party/dawn/src/dawn_native/opengl/TextureGL.h +++ b/chromium/third_party/dawn/src/dawn_native/opengl/TextureGL.h @@ -40,7 +40,8 @@ namespace dawn_native { namespace opengl { void EnsureSubresourceContentInitialized(uint32_t baseMipLevel, uint32_t levelCount, uint32_t baseArrayLayer, - uint32_t layerCount); + uint32_t layerCount, + bool isLazyClear = true); private: void DestroyImpl() override; diff --git a/chromium/third_party/dawn/src/dawn_native/opengl/supported_extensions.json b/chromium/third_party/dawn/src/dawn_native/opengl/supported_extensions.json new file mode 100644 index 00000000000..344fe3df3bc --- /dev/null +++ b/chromium/third_party/dawn/src/dawn_native/opengl/supported_extensions.json @@ -0,0 +1,22 @@ +{ + "_comment": [ + "Copyright 2019 The Dawn Authors", + "", + "Licensed under the Apache License, Version 2.0 (the \"License\");", + "you may not use this file except in compliance with the License.", + "You may obtain a copy of the License at", + "", + " http://www.apache.org/licenses/LICENSE-2.0", + "", + "Unless required by applicable law or agreed to in writing, software", + "distributed under the License is distributed on an \"AS IS\" BASIS,", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", + "See the License for the specific language governing permissions and", + "limitations under the License." + ], + + "supported_extensions": [ + "GL_EXT_texture_compression_s3tc", + "GL_EXT_texture_compression_s3tc_srgb" + ] +} diff --git a/chromium/third_party/dawn/src/dawn_native/vulkan/AdapterVk.cpp b/chromium/third_party/dawn/src/dawn_native/vulkan/AdapterVk.cpp index 614eedadefe..d86a3bb0afa 100644 --- a/chromium/third_party/dawn/src/dawn_native/vulkan/AdapterVk.cpp +++ b/chromium/third_party/dawn/src/dawn_native/vulkan/AdapterVk.cpp @@ -40,6 +40,8 @@ namespace dawn_native { namespace vulkan { MaybeError Adapter::Initialize() { DAWN_TRY_ASSIGN(mDeviceInfo, GatherDeviceInfo(*this)); + InitializeSupportedExtensions(); + mPCIInfo.deviceId = mDeviceInfo.properties.deviceID; mPCIInfo.vendorId = mDeviceInfo.properties.vendorID; mPCIInfo.name = mDeviceInfo.properties.deviceName; @@ -62,6 +64,12 @@ namespace dawn_native { namespace vulkan { return {}; } + void Adapter::InitializeSupportedExtensions() { + if (mDeviceInfo.features.textureCompressionBC == VK_TRUE) { + mSupportedExtensions.EnableExtension(Extension::TextureCompressionBC); + } + } + ResultOrError<DeviceBase*> Adapter::CreateDeviceImpl(const DeviceDescriptor* descriptor) { std::unique_ptr<Device> device = std::make_unique<Device>(this, descriptor); DAWN_TRY(device->Initialize()); diff --git a/chromium/third_party/dawn/src/dawn_native/vulkan/AdapterVk.h b/chromium/third_party/dawn/src/dawn_native/vulkan/AdapterVk.h index 2d9ed83ed6f..a4a3d53b613 100644 --- a/chromium/third_party/dawn/src/dawn_native/vulkan/AdapterVk.h +++ b/chromium/third_party/dawn/src/dawn_native/vulkan/AdapterVk.h @@ -37,6 +37,7 @@ namespace dawn_native { namespace vulkan { private: ResultOrError<DeviceBase*> CreateDeviceImpl(const DeviceDescriptor* descriptor) override; + void InitializeSupportedExtensions(); VkPhysicalDevice mPhysicalDevice; Backend* mBackend; diff --git a/chromium/third_party/dawn/src/dawn_native/vulkan/BackendVk.cpp b/chromium/third_party/dawn/src/dawn_native/vulkan/BackendVk.cpp index 6ca0a26ca35..dff6bbea062 100644 --- a/chromium/third_party/dawn/src/dawn_native/vulkan/BackendVk.cpp +++ b/chromium/third_party/dawn/src/dawn_native/vulkan/BackendVk.cpp @@ -55,9 +55,13 @@ namespace dawn_native { namespace vulkan { return mInstance; } + const VulkanGlobalInfo& Backend::GetGlobalInfo() const { + return mGlobalInfo; + } + MaybeError Backend::Initialize() { if (!mVulkanLib.Open(kVulkanLibName)) { - return DAWN_CONTEXT_LOST_ERROR(std::string("Couldn't open ") + kVulkanLibName); + return DAWN_DEVICE_LOST_ERROR(std::string("Couldn't open ") + kVulkanLibName); } DAWN_TRY(mFunctions.LoadGlobalProcs(mVulkanLib)); @@ -138,6 +142,18 @@ namespace dawn_native { namespace vulkan { extensionsToRequest.push_back(kExtensionNameMvkMacosSurface); usedKnobs.macosSurface = true; } + if (mGlobalInfo.externalMemoryCapabilities) { + extensionsToRequest.push_back(kExtensionNameKhrExternalMemoryCapabilities); + usedKnobs.externalMemoryCapabilities = true; + } + if (mGlobalInfo.externalSemaphoreCapabilities) { + extensionsToRequest.push_back(kExtensionNameKhrExternalSemaphoreCapabilities); + usedKnobs.externalSemaphoreCapabilities = true; + } + if (mGlobalInfo.getPhysicalDeviceProperties2) { + extensionsToRequest.push_back(kExtensionNameKhrGetPhysicalDeviceProperties2); + usedKnobs.getPhysicalDeviceProperties2 = true; + } if (mGlobalInfo.surface) { extensionsToRequest.push_back(kExtensionNameKhrSurface); usedKnobs.surface = true; @@ -166,7 +182,7 @@ namespace dawn_native { namespace vulkan { appInfo.applicationVersion = 0; appInfo.pEngineName = nullptr; appInfo.engineVersion = 0; - appInfo.apiVersion = VK_API_VERSION_1_0; + appInfo.apiVersion = mGlobalInfo.apiVersion; VkInstanceCreateInfo createInfo; createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; diff --git a/chromium/third_party/dawn/src/dawn_native/vulkan/BackendVk.h b/chromium/third_party/dawn/src/dawn_native/vulkan/BackendVk.h index b3ab47ec9bd..a0606b7c7ce 100644 --- a/chromium/third_party/dawn/src/dawn_native/vulkan/BackendVk.h +++ b/chromium/third_party/dawn/src/dawn_native/vulkan/BackendVk.h @@ -30,6 +30,7 @@ namespace dawn_native { namespace vulkan { const VulkanFunctions& GetFunctions() const; VkInstance GetVkInstance() const; + const VulkanGlobalInfo& GetGlobalInfo() const; MaybeError Initialize(); diff --git a/chromium/third_party/dawn/src/dawn_native/vulkan/BindGroupLayoutVk.cpp b/chromium/third_party/dawn/src/dawn_native/vulkan/BindGroupLayoutVk.cpp index fb221537f58..e2d36ae179c 100644 --- a/chromium/third_party/dawn/src/dawn_native/vulkan/BindGroupLayoutVk.cpp +++ b/chromium/third_party/dawn/src/dawn_native/vulkan/BindGroupLayoutVk.cpp @@ -21,16 +21,16 @@ namespace dawn_native { namespace vulkan { namespace { - VkShaderStageFlags VulkanShaderStageFlags(dawn::ShaderStageBit stages) { + VkShaderStageFlags VulkanShaderStageFlags(dawn::ShaderStage stages) { VkShaderStageFlags flags = 0; - if (stages & dawn::ShaderStageBit::Vertex) { + if (stages & dawn::ShaderStage::Vertex) { flags |= VK_SHADER_STAGE_VERTEX_BIT; } - if (stages & dawn::ShaderStageBit::Fragment) { + if (stages & dawn::ShaderStage::Fragment) { flags |= VK_SHADER_STAGE_FRAGMENT_BIT; } - if (stages & dawn::ShaderStageBit::Compute) { + if (stages & dawn::ShaderStage::Compute) { flags |= VK_SHADER_STAGE_COMPUTE_BIT; } diff --git a/chromium/third_party/dawn/src/dawn_native/vulkan/BufferVk.cpp b/chromium/third_party/dawn/src/dawn_native/vulkan/BufferVk.cpp index e7b3bea1e7a..53085b27488 100644 --- a/chromium/third_party/dawn/src/dawn_native/vulkan/BufferVk.cpp +++ b/chromium/third_party/dawn/src/dawn_native/vulkan/BufferVk.cpp @@ -23,86 +23,86 @@ namespace dawn_native { namespace vulkan { namespace { - VkBufferUsageFlags VulkanBufferUsage(dawn::BufferUsageBit usage) { + VkBufferUsageFlags VulkanBufferUsage(dawn::BufferUsage usage) { VkBufferUsageFlags flags = 0; - if (usage & dawn::BufferUsageBit::CopySrc) { + if (usage & dawn::BufferUsage::CopySrc) { flags |= VK_BUFFER_USAGE_TRANSFER_SRC_BIT; } - if (usage & dawn::BufferUsageBit::CopyDst) { + if (usage & dawn::BufferUsage::CopyDst) { flags |= VK_BUFFER_USAGE_TRANSFER_DST_BIT; } - if (usage & dawn::BufferUsageBit::Index) { + if (usage & dawn::BufferUsage::Index) { flags |= VK_BUFFER_USAGE_INDEX_BUFFER_BIT; } - if (usage & dawn::BufferUsageBit::Vertex) { + if (usage & dawn::BufferUsage::Vertex) { flags |= VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; } - if (usage & dawn::BufferUsageBit::Uniform) { + if (usage & dawn::BufferUsage::Uniform) { flags |= VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; } - if (usage & dawn::BufferUsageBit::Storage) { + if (usage & dawn::BufferUsage::Storage) { flags |= VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; } - if (usage & dawn::BufferUsageBit::Indirect) { + if (usage & dawn::BufferUsage::Indirect) { flags |= VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT; } return flags; } - VkPipelineStageFlags VulkanPipelineStage(dawn::BufferUsageBit usage) { + VkPipelineStageFlags VulkanPipelineStage(dawn::BufferUsage usage) { VkPipelineStageFlags flags = 0; - if (usage & (dawn::BufferUsageBit::MapRead | dawn::BufferUsageBit::MapWrite)) { + if (usage & (dawn::BufferUsage::MapRead | dawn::BufferUsage::MapWrite)) { flags |= VK_PIPELINE_STAGE_HOST_BIT; } - if (usage & (dawn::BufferUsageBit::CopySrc | dawn::BufferUsageBit::CopyDst)) { + if (usage & (dawn::BufferUsage::CopySrc | dawn::BufferUsage::CopyDst)) { flags |= VK_PIPELINE_STAGE_TRANSFER_BIT; } - if (usage & (dawn::BufferUsageBit::Index | dawn::BufferUsageBit::Vertex)) { + if (usage & (dawn::BufferUsage::Index | dawn::BufferUsage::Vertex)) { flags |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT; } - if (usage & (dawn::BufferUsageBit::Uniform | dawn::BufferUsageBit::Storage)) { + if (usage & (dawn::BufferUsage::Uniform | dawn::BufferUsage::Storage)) { flags |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; } - if (usage & dawn::BufferUsageBit::Indirect) { + if (usage & dawn::BufferUsage::Indirect) { flags |= VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT; } return flags; } - VkAccessFlags VulkanAccessFlags(dawn::BufferUsageBit usage) { + VkAccessFlags VulkanAccessFlags(dawn::BufferUsage usage) { VkAccessFlags flags = 0; - if (usage & dawn::BufferUsageBit::MapRead) { + if (usage & dawn::BufferUsage::MapRead) { flags |= VK_ACCESS_HOST_READ_BIT; } - if (usage & dawn::BufferUsageBit::MapWrite) { + if (usage & dawn::BufferUsage::MapWrite) { flags |= VK_ACCESS_HOST_WRITE_BIT; } - if (usage & dawn::BufferUsageBit::CopySrc) { + if (usage & dawn::BufferUsage::CopySrc) { flags |= VK_ACCESS_TRANSFER_READ_BIT; } - if (usage & dawn::BufferUsageBit::CopyDst) { + if (usage & dawn::BufferUsage::CopyDst) { flags |= VK_ACCESS_TRANSFER_WRITE_BIT; } - if (usage & dawn::BufferUsageBit::Index) { + if (usage & dawn::BufferUsage::Index) { flags |= VK_ACCESS_INDEX_READ_BIT; } - if (usage & dawn::BufferUsageBit::Vertex) { + if (usage & dawn::BufferUsage::Vertex) { flags |= VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT; } - if (usage & dawn::BufferUsageBit::Uniform) { + if (usage & dawn::BufferUsage::Uniform) { flags |= VK_ACCESS_UNIFORM_READ_BIT; } - if (usage & dawn::BufferUsageBit::Storage) { + if (usage & dawn::BufferUsage::Storage) { flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; } - if (usage & dawn::BufferUsageBit::Indirect) { + if (usage & dawn::BufferUsage::Indirect) { flags |= VK_ACCESS_INDIRECT_COMMAND_READ_BIT; } @@ -120,7 +120,7 @@ namespace dawn_native { namespace vulkan { createInfo.size = GetSize(); // Add CopyDst for non-mappable buffer initialization in CreateBufferMapped // and robust resource initialization. - createInfo.usage = VulkanBufferUsage(GetUsage() | dawn::BufferUsageBit::CopyDst); + createInfo.usage = VulkanBufferUsage(GetUsage() | dawn::BufferUsage::CopyDst); createInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; createInfo.queueFamilyIndexCount = 0; createInfo.pQueueFamilyIndices = 0; @@ -134,7 +134,7 @@ namespace dawn_native { namespace vulkan { device->fn.GetBufferMemoryRequirements(device->GetVkDevice(), mHandle, &requirements); bool requestMappable = - (GetUsage() & (dawn::BufferUsageBit::MapRead | dawn::BufferUsageBit::MapWrite)) != 0; + (GetUsage() & (dawn::BufferUsage::MapRead | dawn::BufferUsage::MapWrite)) != 0; if (!device->GetMemoryAllocator()->Allocate(requirements, requestMappable, &mMemoryAllocation)) { ASSERT(false); @@ -163,7 +163,8 @@ namespace dawn_native { namespace vulkan { return mHandle; } - void Buffer::TransitionUsageNow(VkCommandBuffer commands, dawn::BufferUsageBit usage) { + void Buffer::TransitionUsageNow(CommandRecordingContext* recordingContext, + dawn::BufferUsage usage) { bool lastIncludesTarget = (mLastUsage & usage) == usage; bool lastReadOnly = (mLastUsage & kReadOnlyBufferUsages) == mLastUsage; @@ -173,7 +174,7 @@ namespace dawn_native { namespace vulkan { } // Special-case for the initial transition: Vulkan doesn't allow access flags to be 0. - if (mLastUsage == dawn::BufferUsageBit::None) { + if (mLastUsage == dawn::BufferUsage::None) { mLastUsage = usage; return; } @@ -193,8 +194,8 @@ namespace dawn_native { namespace vulkan { barrier.size = GetSize(); ToBackend(GetDevice()) - ->fn.CmdPipelineBarrier(commands, srcStages, dstStages, 0, 0, nullptr, 1, &barrier, 0, - nullptr); + ->fn.CmdPipelineBarrier(recordingContext->commandBuffer, srcStages, dstStages, 0, 0, + nullptr, 1, &barrier, 0, nullptr); mLastUsage = usage; } @@ -212,8 +213,8 @@ namespace dawn_native { namespace vulkan { MaybeError Buffer::MapReadAsyncImpl(uint32_t serial) { Device* device = ToBackend(GetDevice()); - VkCommandBuffer commands = device->GetPendingCommandBuffer(); - TransitionUsageNow(commands, dawn::BufferUsageBit::MapRead); + CommandRecordingContext* recordingContext = device->GetPendingRecordingContext(); + TransitionUsageNow(recordingContext, dawn::BufferUsage::MapRead); uint8_t* memory = mMemoryAllocation.GetMappedPointer(); ASSERT(memory != nullptr); @@ -226,8 +227,8 @@ namespace dawn_native { namespace vulkan { MaybeError Buffer::MapWriteAsyncImpl(uint32_t serial) { Device* device = ToBackend(GetDevice()); - VkCommandBuffer commands = device->GetPendingCommandBuffer(); - TransitionUsageNow(commands, dawn::BufferUsageBit::MapWrite); + CommandRecordingContext* recordingContext = device->GetPendingRecordingContext(); + TransitionUsageNow(recordingContext, dawn::BufferUsage::MapWrite); uint8_t* memory = mMemoryAllocation.GetMappedPointer(); ASSERT(memory != nullptr); diff --git a/chromium/third_party/dawn/src/dawn_native/vulkan/BufferVk.h b/chromium/third_party/dawn/src/dawn_native/vulkan/BufferVk.h index 81d7a4e3ff1..354c39e34e4 100644 --- a/chromium/third_party/dawn/src/dawn_native/vulkan/BufferVk.h +++ b/chromium/third_party/dawn/src/dawn_native/vulkan/BufferVk.h @@ -23,6 +23,7 @@ namespace dawn_native { namespace vulkan { + struct CommandRecordingContext; class Device; class Buffer : public BufferBase { @@ -38,7 +39,7 @@ namespace dawn_native { namespace vulkan { // Transitions the buffer to be used as `usage`, recording any necessary barrier in // `commands`. // TODO(cwallez@chromium.org): coalesce barriers and do them early when possible. - void TransitionUsageNow(VkCommandBuffer commands, dawn::BufferUsageBit usage); + void TransitionUsageNow(CommandRecordingContext* recordingContext, dawn::BufferUsage usage); private: // Dawn API @@ -53,7 +54,7 @@ namespace dawn_native { namespace vulkan { VkBuffer mHandle = VK_NULL_HANDLE; DeviceMemoryAllocation mMemoryAllocation; - dawn::BufferUsageBit mLastUsage = dawn::BufferUsageBit::None; + dawn::BufferUsage mLastUsage = dawn::BufferUsage::None; }; class MapRequestTracker { diff --git a/chromium/third_party/dawn/src/dawn_native/vulkan/CommandBufferVk.cpp b/chromium/third_party/dawn/src/dawn_native/vulkan/CommandBufferVk.cpp index 8f1afa37e39..ab503d779da 100644 --- a/chromium/third_party/dawn/src/dawn_native/vulkan/CommandBufferVk.cpp +++ b/chromium/third_party/dawn/src/dawn_native/vulkan/CommandBufferVk.cpp @@ -16,8 +16,10 @@ #include "dawn_native/CommandEncoder.h" #include "dawn_native/Commands.h" +#include "dawn_native/RenderBundle.h" #include "dawn_native/vulkan/BindGroupVk.h" #include "dawn_native/vulkan/BufferVk.h" +#include "dawn_native/vulkan/CommandRecordingContext.h" #include "dawn_native/vulkan/ComputePipelineVk.h" #include "dawn_native/vulkan/DeviceVk.h" #include "dawn_native/vulkan/FencedDeleter.h" @@ -25,6 +27,7 @@ #include "dawn_native/vulkan/RenderPassCache.h" #include "dawn_native/vulkan/RenderPipelineVk.h" #include "dawn_native/vulkan/TextureVk.h" +#include "dawn_native/vulkan/UtilsVulkan.h" namespace dawn_native { namespace vulkan { @@ -41,57 +44,14 @@ namespace dawn_native { namespace vulkan { } } - // Vulkan SPEC requires the source/destination region specified by each element of - // pRegions must be a region that is contained within srcImage/dstImage. Here the size of - // the image refers to the virtual size, while Dawn validates texture copy extent with the - // physical size, so we need to re-calculate the texture copy extent to ensure it should fit - // in the virtual size of the subresource. - Extent3D ComputeTextureCopyExtent(const TextureCopy& textureCopy, - const Extent3D& copySize) { - Extent3D validTextureCopyExtent = copySize; - const TextureBase* texture = textureCopy.texture.Get(); - Extent3D virtualSizeAtLevel = texture->GetMipLevelVirtualSize(textureCopy.mipLevel); - if (textureCopy.origin.x + copySize.width > virtualSizeAtLevel.width) { - ASSERT(texture->GetFormat().isCompressed); - validTextureCopyExtent.width = virtualSizeAtLevel.width - textureCopy.origin.x; - } - if (textureCopy.origin.y + copySize.height > virtualSizeAtLevel.height) { - ASSERT(texture->GetFormat().isCompressed); - validTextureCopyExtent.height = virtualSizeAtLevel.height - textureCopy.origin.y; - } - - return validTextureCopyExtent; - } - - VkBufferImageCopy ComputeBufferImageCopyRegion(const BufferCopy& bufferCopy, - const TextureCopy& textureCopy, - const Extent3D& copySize) { - const Texture* texture = ToBackend(textureCopy.texture.Get()); - - VkBufferImageCopy region; - - region.bufferOffset = bufferCopy.offset; - // In Vulkan the row length is in texels while it is in bytes for Dawn - const Format& format = texture->GetFormat(); - ASSERT(bufferCopy.rowPitch % format.blockByteSize == 0); - region.bufferRowLength = bufferCopy.rowPitch / format.blockByteSize * format.blockWidth; - region.bufferImageHeight = bufferCopy.imageHeight; - - region.imageSubresource.aspectMask = texture->GetVkAspectMask(); - region.imageSubresource.mipLevel = textureCopy.mipLevel; - region.imageSubresource.baseArrayLayer = textureCopy.arrayLayer; - region.imageSubresource.layerCount = 1; - - region.imageOffset.x = textureCopy.origin.x; - region.imageOffset.y = textureCopy.origin.y; - region.imageOffset.z = textureCopy.origin.z; - - Extent3D imageExtent = ComputeTextureCopyExtent(textureCopy, copySize); - region.imageExtent.width = imageExtent.width; - region.imageExtent.height = imageExtent.height; - region.imageExtent.depth = copySize.depth; - - return region; + bool HasSameTextureCopyExtent(const TextureCopy& srcCopy, + const TextureCopy& dstCopy, + const Extent3D& copySize) { + Extent3D imageExtentSrc = ComputeTextureCopyExtent(srcCopy, copySize); + Extent3D imageExtentDst = ComputeTextureCopyExtent(dstCopy, copySize); + return imageExtentSrc.width == imageExtentDst.width && + imageExtentSrc.height == imageExtentDst.height && + imageExtentSrc.depth == imageExtentDst.depth; } VkImageCopy ComputeImageCopyRegion(const TextureCopy& srcCopy, @@ -120,11 +80,8 @@ namespace dawn_native { namespace vulkan { region.dstOffset.y = dstCopy.origin.y; region.dstOffset.z = dstCopy.origin.z; - Extent3D imageExtentDst = ComputeTextureCopyExtent(dstCopy, copySize); - // TODO(jiawei.shao@intel.com): add workaround for the case that imageExtentSrc is not - // equal to imageExtentDst. For example when copySize fits in the virtual size of the - // source image but does not fit in the one of the destination image. - Extent3D imageExtent = imageExtentDst; + ASSERT(HasSameTextureCopyExtent(srcCopy, dstCopy, copySize)); + Extent3D imageExtent = ComputeTextureCopyExtent(dstCopy, copySize); region.extent.width = imageExtent.width; region.extent.height = imageExtent.height; region.extent.depth = imageExtent.depth; @@ -189,15 +146,18 @@ namespace dawn_native { namespace vulkan { std::array<std::array<uint32_t, kMaxBindingsPerGroup>, kMaxBindGroups> mDynamicOffsets; }; - void RecordBeginRenderPass(VkCommandBuffer commands, + void RecordBeginRenderPass(CommandRecordingContext* recordingContext, Device* device, BeginRenderPassCmd* renderPass) { + VkCommandBuffer commands = recordingContext->commandBuffer; + // Query a VkRenderPass from the cache VkRenderPass renderPassVK = VK_NULL_HANDLE; { RenderPassCacheQuery query; - for (uint32_t i : IterateBitSet(renderPass->colorAttachmentsSet)) { + for (uint32_t i : + IterateBitSet(renderPass->attachmentState->GetColorAttachmentsMask())) { auto& attachmentInfo = renderPass->colorAttachments[i]; TextureView* view = ToBackend(attachmentInfo.view.Get()); bool hasResolveTarget = attachmentInfo.resolveTarget.Get() != nullptr; @@ -210,6 +170,18 @@ namespace dawn_native { namespace vulkan { view->GetBaseMipLevel(), 1, view->GetBaseArrayLayer(), 1)) { loadOp = dawn::LoadOp::Clear; } + + if (hasResolveTarget) { + // We need to set the resolve target to initialized so that it does not get + // cleared later in the pipeline. The texture will be resolved from the + // source color attachment, which will be correctly initialized. + TextureView* resolveView = ToBackend(attachmentInfo.resolveTarget.Get()); + ToBackend(resolveView->GetTexture()) + ->SetIsSubresourceContentInitialized( + resolveView->GetBaseMipLevel(), resolveView->GetLevelCount(), + resolveView->GetBaseArrayLayer(), resolveView->GetLayerCount()); + } + switch (attachmentInfo.storeOp) { case dawn::StoreOp::Store: { view->GetTexture()->SetIsSubresourceContentInitialized( @@ -223,7 +195,7 @@ namespace dawn_native { namespace vulkan { hasResolveTarget); } - if (renderPass->hasDepthStencilAttachment) { + if (renderPass->attachmentState->HasDepthStencilAttachment()) { auto& attachmentInfo = renderPass->depthStencilAttachment; query.SetDepthStencil(attachmentInfo.view->GetTexture()->GetFormat().format, attachmentInfo.depthLoadOp, attachmentInfo.stencilLoadOp); @@ -231,14 +203,14 @@ namespace dawn_native { namespace vulkan { attachmentInfo.stencilLoadOp == dawn::LoadOp::Load) { ToBackend(attachmentInfo.view->GetTexture()) ->EnsureSubresourceContentInitialized( - commands, attachmentInfo.view->GetBaseMipLevel(), + recordingContext, attachmentInfo.view->GetBaseMipLevel(), attachmentInfo.view->GetLevelCount(), attachmentInfo.view->GetBaseArrayLayer(), attachmentInfo.view->GetLayerCount()); } } - query.SetSampleCount(renderPass->sampleCount); + query.SetSampleCount(renderPass->attachmentState->GetSampleCount()); renderPassVK = device->GetRenderPassCache()->GetRenderPass(query); } @@ -252,7 +224,8 @@ namespace dawn_native { namespace vulkan { // Fill in the attachment info that will be chained in the framebuffer create info. std::array<VkImageView, kMaxColorAttachments * 2 + 1> attachments; - for (uint32_t i : IterateBitSet(renderPass->colorAttachmentsSet)) { + for (uint32_t i : + IterateBitSet(renderPass->attachmentState->GetColorAttachmentsMask())) { auto& attachmentInfo = renderPass->colorAttachments[i]; TextureView* view = ToBackend(attachmentInfo.view.Get()); @@ -266,7 +239,7 @@ namespace dawn_native { namespace vulkan { attachmentCount++; } - if (renderPass->hasDepthStencilAttachment) { + if (renderPass->attachmentState->HasDepthStencilAttachment()) { auto& attachmentInfo = renderPass->depthStencilAttachment; TextureView* view = ToBackend(attachmentInfo.view.Get()); @@ -278,7 +251,8 @@ namespace dawn_native { namespace vulkan { attachmentCount++; } - for (uint32_t i : IterateBitSet(renderPass->colorAttachmentsSet)) { + for (uint32_t i : + IterateBitSet(renderPass->attachmentState->GetColorAttachmentsMask())) { if (renderPass->colorAttachments[i].resolveTarget.Get() != nullptr) { TextureView* view = ToBackend(renderPass->colorAttachments[i].resolveTarget.Get()); @@ -336,26 +310,88 @@ namespace dawn_native { namespace vulkan { FreeCommands(&mCommands); } - void CommandBuffer::RecordCommands(VkCommandBuffer commands) { + void CommandBuffer::RecordCopyImageWithTemporaryBuffer( + CommandRecordingContext* recordingContext, + const TextureCopy& srcCopy, + const TextureCopy& dstCopy, + const Extent3D& copySize) { + ASSERT(srcCopy.texture->GetFormat().format == dstCopy.texture->GetFormat().format); + dawn_native::Format format = srcCopy.texture->GetFormat(); + ASSERT(copySize.width % format.blockWidth == 0); + ASSERT(copySize.height % format.blockHeight == 0); + + // Create the temporary buffer. Note that We don't need to respect WebGPU's 256 alignment + // because it isn't a hard constraint in Vulkan. + uint64_t tempBufferSize = + (copySize.width / format.blockWidth * copySize.height / format.blockHeight) * + format.blockByteSize; + BufferDescriptor tempBufferDescriptor; + tempBufferDescriptor.size = tempBufferSize; + tempBufferDescriptor.usage = dawn::BufferUsage::CopySrc | dawn::BufferUsage::CopyDst; + + Device* device = ToBackend(GetDevice()); + Ref<Buffer> tempBuffer = ToBackend(device->CreateBuffer(&tempBufferDescriptor)); + // After device->CreateBuffer(&tempBufferDescriptor) is called, the ref count of the buffer + // object is 1, and after assigning it to a Ref<Buffer>, the ref count of it will be 2. To + // prevent memory leak, we must reduce the ref count here to ensure the ref count of this + // object to be 0 after all the Ref<> objects that contain the buffer object are released. + tempBuffer->Release(); + + BufferCopy tempBufferCopy; + tempBufferCopy.buffer = tempBuffer.Get(); + tempBufferCopy.imageHeight = copySize.height; + tempBufferCopy.offset = 0; + tempBufferCopy.rowPitch = copySize.width / format.blockWidth * format.blockByteSize; + + VkCommandBuffer commands = recordingContext->commandBuffer; + VkImage srcImage = ToBackend(srcCopy.texture)->GetHandle(); + VkImage dstImage = ToBackend(dstCopy.texture)->GetHandle(); + + tempBuffer->TransitionUsageNow(recordingContext, dawn::BufferUsage::CopyDst); + VkBufferImageCopy srcToTempBufferRegion = + ComputeBufferImageCopyRegion(tempBufferCopy, srcCopy, copySize); + + // The Dawn CopySrc usage is always mapped to GENERAL + device->fn.CmdCopyImageToBuffer(commands, srcImage, VK_IMAGE_LAYOUT_GENERAL, + tempBuffer->GetHandle(), 1, &srcToTempBufferRegion); + + tempBuffer->TransitionUsageNow(recordingContext, dawn::BufferUsage::CopySrc); + VkBufferImageCopy tempBufferToDstRegion = + ComputeBufferImageCopyRegion(tempBufferCopy, dstCopy, copySize); + + // Dawn guarantees dstImage be in the TRANSFER_DST_OPTIMAL layout after the + // copy command. + device->fn.CmdCopyBufferToImage(commands, tempBuffer->GetHandle(), dstImage, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, + &tempBufferToDstRegion); + + recordingContext->tempBuffers.emplace_back(tempBuffer); + } + + void CommandBuffer::RecordCommands(CommandRecordingContext* recordingContext) { Device* device = ToBackend(GetDevice()); + VkCommandBuffer commands = recordingContext->commandBuffer; // Records the necessary barriers for the resource usage pre-computed by the frontend - auto TransitionForPass = [](VkCommandBuffer commands, const PassResourceUsage& usages) { + auto TransitionForPass = [](CommandRecordingContext* recordingContext, + const PassResourceUsage& usages) { for (size_t i = 0; i < usages.buffers.size(); ++i) { Buffer* buffer = ToBackend(usages.buffers[i]); - buffer->TransitionUsageNow(commands, usages.bufferUsages[i]); + buffer->TransitionUsageNow(recordingContext, usages.bufferUsages[i]); } for (size_t i = 0; i < usages.textures.size(); ++i) { Texture* texture = ToBackend(usages.textures[i]); - - // TODO(natlee@microsoft.com): Update clearing here when subresource tracking is - // implemented - texture->EnsureSubresourceContentInitialized( - commands, 0, texture->GetNumMipLevels(), 0, texture->GetArrayLayers()); - texture->TransitionUsageNow(commands, usages.textureUsages[i]); + // Clear textures that are not output attachments. Output attachments will be + // cleared in RecordBeginRenderPass by setting the loadop to clear when the + // texture subresource has not been initialized before the render pass. + if (!(usages.textureUsages[i] & dawn::TextureUsage::OutputAttachment)) { + texture->EnsureSubresourceContentInitialized(recordingContext, 0, + texture->GetNumMipLevels(), 0, + texture->GetArrayLayers()); + } + texture->TransitionUsageNow(recordingContext, usages.textureUsages[i]); } }; - const std::vector<PassResourceUsage>& passResourceUsages = GetResourceUsages().perPass; size_t nextPassNumber = 0; @@ -367,8 +403,8 @@ namespace dawn_native { namespace vulkan { Buffer* srcBuffer = ToBackend(copy->source.Get()); Buffer* dstBuffer = ToBackend(copy->destination.Get()); - srcBuffer->TransitionUsageNow(commands, dawn::BufferUsageBit::CopySrc); - dstBuffer->TransitionUsageNow(commands, dawn::BufferUsageBit::CopyDst); + srcBuffer->TransitionUsageNow(recordingContext, dawn::BufferUsage::CopySrc); + dstBuffer->TransitionUsageNow(recordingContext, dawn::BufferUsage::CopyDst); VkBufferCopy region; region.srcOffset = copy->sourceOffset; @@ -396,18 +432,19 @@ namespace dawn_native { namespace vulkan { subresource.mipLevel, 1, subresource.baseArrayLayer, 1); } else { ToBackend(dst.texture) - ->EnsureSubresourceContentInitialized(commands, subresource.mipLevel, 1, + ->EnsureSubresourceContentInitialized(recordingContext, + subresource.mipLevel, 1, subresource.baseArrayLayer, 1); } ToBackend(src.buffer) - ->TransitionUsageNow(commands, dawn::BufferUsageBit::CopySrc); + ->TransitionUsageNow(recordingContext, dawn::BufferUsage::CopySrc); ToBackend(dst.texture) - ->TransitionUsageNow(commands, dawn::TextureUsageBit::CopyDst); + ->TransitionUsageNow(recordingContext, dawn::TextureUsage::CopyDst); VkBuffer srcBuffer = ToBackend(src.buffer)->GetHandle(); VkImage dstImage = ToBackend(dst.texture)->GetHandle(); - // The image is written to so the Dawn guarantees make sure it is in the - // TRANSFER_DST_OPTIMAL layout + // Dawn guarantees dstImage be in the TRANSFER_DST_OPTIMAL layout after the + // copy command. device->fn.CmdCopyBufferToImage(commands, srcBuffer, dstImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); @@ -423,13 +460,14 @@ namespace dawn_native { namespace vulkan { VkImageSubresourceLayers subresource = region.imageSubresource; ToBackend(src.texture) - ->EnsureSubresourceContentInitialized(commands, subresource.mipLevel, 1, + ->EnsureSubresourceContentInitialized(recordingContext, + subresource.mipLevel, 1, subresource.baseArrayLayer, 1); ToBackend(src.texture) - ->TransitionUsageNow(commands, dawn::TextureUsageBit::CopySrc); + ->TransitionUsageNow(recordingContext, dawn::TextureUsage::CopySrc); ToBackend(dst.buffer) - ->TransitionUsageNow(commands, dawn::BufferUsageBit::CopyDst); + ->TransitionUsageNow(recordingContext, dawn::BufferUsage::CopyDst); VkImage srcImage = ToBackend(src.texture)->GetHandle(); VkBuffer dstBuffer = ToBackend(dst.buffer)->GetHandle(); @@ -444,42 +482,64 @@ namespace dawn_native { namespace vulkan { TextureCopy& src = copy->source; TextureCopy& dst = copy->destination; - VkImageCopy region = ComputeImageCopyRegion(src, dst, copy->copySize); - VkImageSubresourceLayers dstSubresource = region.dstSubresource; - VkImageSubresourceLayers srcSubresource = region.srcSubresource; - ToBackend(src.texture) - ->EnsureSubresourceContentInitialized(commands, srcSubresource.mipLevel, 1, - srcSubresource.baseArrayLayer, 1); + ->EnsureSubresourceContentInitialized(recordingContext, src.mipLevel, 1, + src.arrayLayer, 1); if (IsCompleteSubresourceCopiedTo(dst.texture.Get(), copy->copySize, - dstSubresource.mipLevel)) { + dst.mipLevel)) { // Since destination texture has been overwritten, it has been "initialized" - dst.texture->SetIsSubresourceContentInitialized( - dstSubresource.mipLevel, 1, dstSubresource.baseArrayLayer, 1); + dst.texture->SetIsSubresourceContentInitialized(dst.mipLevel, 1, + dst.arrayLayer, 1); } else { ToBackend(dst.texture) - ->EnsureSubresourceContentInitialized(commands, dstSubresource.mipLevel, - 1, dstSubresource.baseArrayLayer, - 1); + ->EnsureSubresourceContentInitialized(recordingContext, dst.mipLevel, 1, + dst.arrayLayer, 1); } + ToBackend(src.texture) - ->TransitionUsageNow(commands, dawn::TextureUsageBit::CopySrc); + ->TransitionUsageNow(recordingContext, dawn::TextureUsage::CopySrc); ToBackend(dst.texture) - ->TransitionUsageNow(commands, dawn::TextureUsageBit::CopyDst); - VkImage srcImage = ToBackend(src.texture)->GetHandle(); - VkImage dstImage = ToBackend(dst.texture)->GetHandle(); + ->TransitionUsageNow(recordingContext, dawn::TextureUsage::CopyDst); + + // In some situations we cannot do texture-to-texture copies with vkCmdCopyImage + // because as Vulkan SPEC always validates image copies with the virtual size of + // the image subresource, when the extent that fits in the copy region of one + // subresource but does not fit in the one of another subresource, we will fail + // to find a valid extent to satisfy the requirements on both source and + // destination image subresource. For example, when the source is the first + // level of a 16x16 texture in BC format, and the destination is the third level + // of a 60x60 texture in the same format, neither 16x16 nor 15x15 is valid as + // the extent of vkCmdCopyImage. + // Our workaround for this issue is replacing the texture-to-texture copy with + // one texture-to-buffer copy and one buffer-to-texture copy. + bool copyUsingTemporaryBuffer = + device->IsToggleEnabled( + Toggle::UseTemporaryBufferInCompressedTextureToTextureCopy) && + src.texture->GetFormat().isCompressed && + !HasSameTextureCopyExtent(src, dst, copy->copySize); + + if (!copyUsingTemporaryBuffer) { + VkImage srcImage = ToBackend(src.texture)->GetHandle(); + VkImage dstImage = ToBackend(dst.texture)->GetHandle(); + VkImageCopy region = ComputeImageCopyRegion(src, dst, copy->copySize); + + // Dawn guarantees dstImage be in the TRANSFER_DST_OPTIMAL layout after the + // copy command. + device->fn.CmdCopyImage(commands, srcImage, VK_IMAGE_LAYOUT_GENERAL, + dstImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, + ®ion); + } else { + RecordCopyImageWithTemporaryBuffer(recordingContext, src, dst, + copy->copySize); + } - // The dstImage is written to so the Dawn guarantees make sure it is in the - // TRANSFER_DST_OPTIMAL layout - device->fn.CmdCopyImage(commands, srcImage, VK_IMAGE_LAYOUT_GENERAL, dstImage, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); } break; case Command::BeginRenderPass: { BeginRenderPassCmd* cmd = mCommands.NextCommand<BeginRenderPassCmd>(); - TransitionForPass(commands, passResourceUsages[nextPassNumber]); - RecordRenderPass(commands, cmd); + TransitionForPass(recordingContext, passResourceUsages[nextPassNumber]); + RecordRenderPass(recordingContext, cmd); nextPassNumber++; } break; @@ -487,8 +547,8 @@ namespace dawn_native { namespace vulkan { case Command::BeginComputePass: { mCommands.NextCommand<BeginComputePassCmd>(); - TransitionForPass(commands, passResourceUsages[nextPassNumber]); - RecordComputePass(commands); + TransitionForPass(recordingContext, passResourceUsages[nextPassNumber]); + RecordComputePass(recordingContext); nextPassNumber++; } break; @@ -498,8 +558,9 @@ namespace dawn_native { namespace vulkan { } } - void CommandBuffer::RecordComputePass(VkCommandBuffer commands) { + void CommandBuffer::RecordComputePass(CommandRecordingContext* recordingContext) { Device* device = ToBackend(GetDevice()); + VkCommandBuffer commands = recordingContext->commandBuffer; DescriptorSetTracker descriptorSets; @@ -548,6 +609,53 @@ namespace dawn_native { namespace vulkan { descriptorSets.OnPipelineLayoutChange(ToBackend(pipeline->GetLayout())); } break; + case Command::InsertDebugMarker: { + if (device->GetDeviceInfo().debugMarker) { + InsertDebugMarkerCmd* cmd = mCommands.NextCommand<InsertDebugMarkerCmd>(); + const char* label = mCommands.NextData<char>(cmd->length + 1); + VkDebugMarkerMarkerInfoEXT markerInfo; + markerInfo.sType = VK_STRUCTURE_TYPE_DEBUG_MARKER_MARKER_INFO_EXT; + markerInfo.pNext = nullptr; + markerInfo.pMarkerName = label; + // Default color to black + markerInfo.color[0] = 0.0; + markerInfo.color[1] = 0.0; + markerInfo.color[2] = 0.0; + markerInfo.color[3] = 1.0; + device->fn.CmdDebugMarkerInsertEXT(commands, &markerInfo); + } else { + SkipCommand(&mCommands, Command::InsertDebugMarker); + } + } break; + + case Command::PopDebugGroup: { + if (device->GetDeviceInfo().debugMarker) { + mCommands.NextCommand<PopDebugGroupCmd>(); + device->fn.CmdDebugMarkerEndEXT(commands); + } else { + SkipCommand(&mCommands, Command::PopDebugGroup); + } + } break; + + case Command::PushDebugGroup: { + if (device->GetDeviceInfo().debugMarker) { + PushDebugGroupCmd* cmd = mCommands.NextCommand<PushDebugGroupCmd>(); + const char* label = mCommands.NextData<char>(cmd->length + 1); + VkDebugMarkerMarkerInfoEXT markerInfo; + markerInfo.sType = VK_STRUCTURE_TYPE_DEBUG_MARKER_MARKER_INFO_EXT; + markerInfo.pNext = nullptr; + markerInfo.pMarkerName = label; + // Default color to black + markerInfo.color[0] = 0.0; + markerInfo.color[1] = 0.0; + markerInfo.color[2] = 0.0; + markerInfo.color[3] = 1.0; + device->fn.CmdDebugMarkerBeginEXT(commands, &markerInfo); + } else { + SkipCommand(&mCommands, Command::PushDebugGroup); + } + } break; + default: { UNREACHABLE(); } break; } } @@ -555,11 +663,12 @@ namespace dawn_native { namespace vulkan { // EndComputePass should have been called UNREACHABLE(); } - void CommandBuffer::RecordRenderPass(VkCommandBuffer commands, + void CommandBuffer::RecordRenderPass(CommandRecordingContext* recordingContext, BeginRenderPassCmd* renderPassCmd) { Device* device = ToBackend(GetDevice()); + VkCommandBuffer commands = recordingContext->commandBuffer; - RecordBeginRenderPass(commands, device, renderPassCmd); + RecordBeginRenderPass(recordingContext, device, renderPassCmd); // Set the default value for the dynamic state { @@ -597,17 +706,10 @@ namespace dawn_native { namespace vulkan { DescriptorSetTracker descriptorSets; RenderPipeline* lastPipeline = nullptr; - Command type; - while (mCommands.NextCommandId(&type)) { + auto EncodeRenderBundleCommand = [&](CommandIterator* iter, Command type) { switch (type) { - case Command::EndRenderPass: { - mCommands.NextCommand<EndRenderPassCmd>(); - device->fn.CmdEndRenderPass(commands); - return; - } break; - case Command::Draw: { - DrawCmd* draw = mCommands.NextCommand<DrawCmd>(); + DrawCmd* draw = iter->NextCommand<DrawCmd>(); descriptorSets.Flush(device, commands, VK_PIPELINE_BIND_POINT_GRAPHICS); device->fn.CmdDraw(commands, draw->vertexCount, draw->instanceCount, @@ -615,7 +717,7 @@ namespace dawn_native { namespace vulkan { } break; case Command::DrawIndexed: { - DrawIndexedCmd* draw = mCommands.NextCommand<DrawIndexedCmd>(); + DrawIndexedCmd* draw = iter->NextCommand<DrawIndexedCmd>(); descriptorSets.Flush(device, commands, VK_PIPELINE_BIND_POINT_GRAPHICS); device->fn.CmdDrawIndexed(commands, draw->indexCount, draw->instanceCount, @@ -624,7 +726,7 @@ namespace dawn_native { namespace vulkan { } break; case Command::DrawIndirect: { - DrawIndirectCmd* draw = mCommands.NextCommand<DrawIndirectCmd>(); + DrawIndirectCmd* draw = iter->NextCommand<DrawIndirectCmd>(); VkBuffer indirectBuffer = ToBackend(draw->indirectBuffer)->GetHandle(); descriptorSets.Flush(device, commands, VK_PIPELINE_BIND_POINT_GRAPHICS); @@ -634,7 +736,7 @@ namespace dawn_native { namespace vulkan { } break; case Command::DrawIndexedIndirect: { - DrawIndirectCmd* draw = mCommands.NextCommand<DrawIndirectCmd>(); + DrawIndirectCmd* draw = iter->NextCommand<DrawIndirectCmd>(); VkBuffer indirectBuffer = ToBackend(draw->indirectBuffer)->GetHandle(); descriptorSets.Flush(device, commands, VK_PIPELINE_BIND_POINT_GRAPHICS); @@ -645,8 +747,8 @@ namespace dawn_native { namespace vulkan { case Command::InsertDebugMarker: { if (device->GetDeviceInfo().debugMarker) { - InsertDebugMarkerCmd* cmd = mCommands.NextCommand<InsertDebugMarkerCmd>(); - const char* label = mCommands.NextData<char>(cmd->length + 1); + InsertDebugMarkerCmd* cmd = iter->NextCommand<InsertDebugMarkerCmd>(); + const char* label = iter->NextData<char>(cmd->length + 1); VkDebugMarkerMarkerInfoEXT markerInfo; markerInfo.sType = VK_STRUCTURE_TYPE_DEBUG_MARKER_MARKER_INFO_EXT; markerInfo.pNext = nullptr; @@ -658,23 +760,23 @@ namespace dawn_native { namespace vulkan { markerInfo.color[3] = 1.0; device->fn.CmdDebugMarkerInsertEXT(commands, &markerInfo); } else { - SkipCommand(&mCommands, Command::InsertDebugMarker); + SkipCommand(iter, Command::InsertDebugMarker); } } break; case Command::PopDebugGroup: { if (device->GetDeviceInfo().debugMarker) { - mCommands.NextCommand<PopDebugGroupCmd>(); + iter->NextCommand<PopDebugGroupCmd>(); device->fn.CmdDebugMarkerEndEXT(commands); } else { - SkipCommand(&mCommands, Command::PopDebugGroup); + SkipCommand(iter, Command::PopDebugGroup); } } break; case Command::PushDebugGroup: { if (device->GetDeviceInfo().debugMarker) { - PushDebugGroupCmd* cmd = mCommands.NextCommand<PushDebugGroupCmd>(); - const char* label = mCommands.NextData<char>(cmd->length + 1); + PushDebugGroupCmd* cmd = iter->NextCommand<PushDebugGroupCmd>(); + const char* label = iter->NextData<char>(cmd->length + 1); VkDebugMarkerMarkerInfoEXT markerInfo; markerInfo.sType = VK_STRUCTURE_TYPE_DEBUG_MARKER_MARKER_INFO_EXT; markerInfo.pNext = nullptr; @@ -686,35 +788,24 @@ namespace dawn_native { namespace vulkan { markerInfo.color[3] = 1.0; device->fn.CmdDebugMarkerBeginEXT(commands, &markerInfo); } else { - SkipCommand(&mCommands, Command::PushDebugGroup); + SkipCommand(iter, Command::PushDebugGroup); } } break; case Command::SetBindGroup: { - SetBindGroupCmd* cmd = mCommands.NextCommand<SetBindGroupCmd>(); + SetBindGroupCmd* cmd = iter->NextCommand<SetBindGroupCmd>(); VkDescriptorSet set = ToBackend(cmd->group.Get())->GetHandle(); uint64_t* dynamicOffsets = nullptr; if (cmd->dynamicOffsetCount > 0) { - dynamicOffsets = mCommands.NextData<uint64_t>(cmd->dynamicOffsetCount); + dynamicOffsets = iter->NextData<uint64_t>(cmd->dynamicOffsetCount); } descriptorSets.OnSetBindGroup(cmd->index, set, cmd->dynamicOffsetCount, dynamicOffsets); } break; - case Command::SetBlendColor: { - SetBlendColorCmd* cmd = mCommands.NextCommand<SetBlendColorCmd>(); - float blendConstants[4] = { - cmd->color.r, - cmd->color.g, - cmd->color.b, - cmd->color.a, - }; - device->fn.CmdSetBlendConstants(commands, blendConstants); - } break; - case Command::SetIndexBuffer: { - SetIndexBufferCmd* cmd = mCommands.NextCommand<SetIndexBufferCmd>(); + SetIndexBufferCmd* cmd = iter->NextCommand<SetIndexBufferCmd>(); VkBuffer indexBuffer = ToBackend(cmd->buffer)->GetHandle(); // TODO(cwallez@chromium.org): get the index type from the last render pipeline @@ -727,7 +818,7 @@ namespace dawn_native { namespace vulkan { } break; case Command::SetRenderPipeline: { - SetRenderPipelineCmd* cmd = mCommands.NextCommand<SetRenderPipelineCmd>(); + SetRenderPipelineCmd* cmd = iter->NextCommand<SetRenderPipelineCmd>(); RenderPipeline* pipeline = ToBackend(cmd->pipeline).Get(); device->fn.CmdBindPipeline(commands, VK_PIPELINE_BIND_POINT_GRAPHICS, @@ -737,6 +828,50 @@ namespace dawn_native { namespace vulkan { descriptorSets.OnPipelineLayoutChange(ToBackend(pipeline->GetLayout())); } break; + case Command::SetVertexBuffers: { + SetVertexBuffersCmd* cmd = iter->NextCommand<SetVertexBuffersCmd>(); + auto buffers = iter->NextData<Ref<BufferBase>>(cmd->count); + auto offsets = iter->NextData<uint64_t>(cmd->count); + + std::array<VkBuffer, kMaxVertexBuffers> vkBuffers; + std::array<VkDeviceSize, kMaxVertexBuffers> vkOffsets; + + for (uint32_t i = 0; i < cmd->count; ++i) { + Buffer* buffer = ToBackend(buffers[i].Get()); + vkBuffers[i] = buffer->GetHandle(); + vkOffsets[i] = static_cast<VkDeviceSize>(offsets[i]); + } + + device->fn.CmdBindVertexBuffers(commands, cmd->startSlot, cmd->count, + vkBuffers.data(), vkOffsets.data()); + } break; + + default: + UNREACHABLE(); + break; + } + }; + + Command type; + while (mCommands.NextCommandId(&type)) { + switch (type) { + case Command::EndRenderPass: { + mCommands.NextCommand<EndRenderPassCmd>(); + device->fn.CmdEndRenderPass(commands); + return; + } break; + + case Command::SetBlendColor: { + SetBlendColorCmd* cmd = mCommands.NextCommand<SetBlendColorCmd>(); + float blendConstants[4] = { + cmd->color.r, + cmd->color.g, + cmd->color.b, + cmd->color.a, + }; + device->fn.CmdSetBlendConstants(commands, blendConstants); + } break; + case Command::SetStencilReference: { SetStencilReferenceCmd* cmd = mCommands.NextCommand<SetStencilReferenceCmd>(); device->fn.CmdSetStencilReference(commands, VK_STENCIL_FRONT_AND_BACK, @@ -767,25 +902,20 @@ namespace dawn_native { namespace vulkan { device->fn.CmdSetScissor(commands, 0, 1, &rect); } break; - case Command::SetVertexBuffers: { - SetVertexBuffersCmd* cmd = mCommands.NextCommand<SetVertexBuffersCmd>(); - auto buffers = mCommands.NextData<Ref<BufferBase>>(cmd->count); - auto offsets = mCommands.NextData<uint64_t>(cmd->count); - - std::array<VkBuffer, kMaxVertexBuffers> vkBuffers; - std::array<VkDeviceSize, kMaxVertexBuffers> vkOffsets; + case Command::ExecuteBundles: { + ExecuteBundlesCmd* cmd = mCommands.NextCommand<ExecuteBundlesCmd>(); + auto bundles = mCommands.NextData<Ref<RenderBundleBase>>(cmd->count); for (uint32_t i = 0; i < cmd->count; ++i) { - Buffer* buffer = ToBackend(buffers[i].Get()); - vkBuffers[i] = buffer->GetHandle(); - vkOffsets[i] = static_cast<VkDeviceSize>(offsets[i]); + CommandIterator* iter = bundles[i]->GetCommands(); + iter->Reset(); + while (iter->NextCommandId(&type)) { + EncodeRenderBundleCommand(iter, type); + } } - - device->fn.CmdBindVertexBuffers(commands, cmd->startSlot, cmd->count, - vkBuffers.data(), vkOffsets.data()); } break; - default: { UNREACHABLE(); } break; + default: { EncodeRenderBundleCommand(&mCommands, type); } break; } } diff --git a/chromium/third_party/dawn/src/dawn_native/vulkan/CommandBufferVk.h b/chromium/third_party/dawn/src/dawn_native/vulkan/CommandBufferVk.h index a9608fed6ef..c6d15c22894 100644 --- a/chromium/third_party/dawn/src/dawn_native/vulkan/CommandBufferVk.h +++ b/chromium/third_party/dawn/src/dawn_native/vulkan/CommandBufferVk.h @@ -22,10 +22,12 @@ namespace dawn_native { struct BeginRenderPassCmd; + struct TextureCopy; } // namespace dawn_native namespace dawn_native { namespace vulkan { + struct CommandRecordingContext; class Device; class CommandBuffer : public CommandBufferBase { @@ -33,11 +35,16 @@ namespace dawn_native { namespace vulkan { CommandBuffer(CommandEncoderBase* encoder, const CommandBufferDescriptor* descriptor); ~CommandBuffer(); - void RecordCommands(VkCommandBuffer commands); + void RecordCommands(CommandRecordingContext* recordingContext); private: - void RecordComputePass(VkCommandBuffer commands); - void RecordRenderPass(VkCommandBuffer commands, BeginRenderPassCmd* renderPass); + void RecordComputePass(CommandRecordingContext* recordingContext); + void RecordRenderPass(CommandRecordingContext* recordingContext, + BeginRenderPassCmd* renderPass); + void RecordCopyImageWithTemporaryBuffer(CommandRecordingContext* recordingContext, + const TextureCopy& srcCopy, + const TextureCopy& dstCopy, + const Extent3D& copySize); CommandIterator mCommands; }; diff --git a/chromium/third_party/dawn/src/dawn_native/vulkan/CommandRecordingContext.h b/chromium/third_party/dawn/src/dawn_native/vulkan/CommandRecordingContext.h new file mode 100644 index 00000000000..025de69469e --- /dev/null +++ b/chromium/third_party/dawn/src/dawn_native/vulkan/CommandRecordingContext.h @@ -0,0 +1,38 @@ +// Copyright 2019 The Dawn Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#ifndef DAWNNATIVE_VULKAN_COMMANDRECORDINGCONTEXT_H_ +#define DAWNNATIVE_VULKAN_COMMANDRECORDINGCONTEXT_H_ + +#include "common/vulkan_platform.h" + +#include <vector> + +namespace dawn_native { namespace vulkan { + class Buffer; + + // Used to track operations that are handled after recording. + // Currently only tracks semaphores, but may be used to do barrier coalescing in the future. + struct CommandRecordingContext { + VkCommandBuffer commandBuffer = VK_NULL_HANDLE; + std::vector<VkSemaphore> waitSemaphores = {}; + std::vector<VkSemaphore> signalSemaphores = {}; + + // The internal buffers used in the workaround of texture-to-texture copies with compressed + // formats. + std::vector<Ref<Buffer>> tempBuffers; + }; + +}} // namespace dawn_native::vulkan + +#endif // DAWNNATIVE_VULKAN_COMMANDRECORDINGCONTEXT_H_ diff --git a/chromium/third_party/dawn/src/dawn_native/vulkan/ComputePipelineVk.cpp b/chromium/third_party/dawn/src/dawn_native/vulkan/ComputePipelineVk.cpp index 8e7c7aa746d..34375434814 100644 --- a/chromium/third_party/dawn/src/dawn_native/vulkan/ComputePipelineVk.cpp +++ b/chromium/third_party/dawn/src/dawn_native/vulkan/ComputePipelineVk.cpp @@ -35,8 +35,8 @@ namespace dawn_native { namespace vulkan { createInfo.stage.pNext = nullptr; createInfo.stage.flags = 0; createInfo.stage.stage = VK_SHADER_STAGE_COMPUTE_BIT; - createInfo.stage.module = ToBackend(descriptor->computeStage->module)->GetHandle(); - createInfo.stage.pName = descriptor->computeStage->entryPoint; + createInfo.stage.module = ToBackend(descriptor->computeStage.module)->GetHandle(); + createInfo.stage.pName = descriptor->computeStage.entryPoint; createInfo.stage.pSpecializationInfo = nullptr; if (device->fn.CreateComputePipelines(device->GetVkDevice(), VK_NULL_HANDLE, 1, &createInfo, diff --git a/chromium/third_party/dawn/src/dawn_native/vulkan/DeviceVk.cpp b/chromium/third_party/dawn/src/dawn_native/vulkan/DeviceVk.cpp index 7ff3f3f4e2e..025f2c71803 100644 --- a/chromium/third_party/dawn/src/dawn_native/vulkan/DeviceVk.cpp +++ b/chromium/third_party/dawn/src/dawn_native/vulkan/DeviceVk.cpp @@ -18,7 +18,9 @@ #include "dawn_native/BackendConnection.h" #include "dawn_native/Commands.h" #include "dawn_native/DynamicUploader.h" +#include "dawn_native/Error.h" #include "dawn_native/ErrorData.h" +#include "dawn_native/VulkanBackend.h" #include "dawn_native/vulkan/AdapterVk.h" #include "dawn_native/vulkan/BackendVk.h" #include "dawn_native/vulkan/BindGroupLayoutVk.h" @@ -42,6 +44,7 @@ namespace dawn_native { namespace vulkan { Device::Device(Adapter* adapter, const DeviceDescriptor* descriptor) : DeviceBase(adapter, descriptor) { + InitTogglesFromDriver(); if (descriptor != nullptr) { ApplyToggleOverrides(descriptor); } @@ -68,6 +71,9 @@ namespace dawn_native { namespace vulkan { mMemoryAllocator = std::make_unique<MemoryAllocator>(this); mRenderPassCache = std::make_unique<RenderPassCache>(this); + mExternalMemoryService = std::make_unique<external_memory::Service>(this); + mExternalSemaphoreService = std::make_unique<external_semaphore::Service>(this); + return {}; } @@ -108,7 +114,8 @@ namespace dawn_native { namespace vulkan { } mUnusedCommands.clear(); - ASSERT(mWaitSemaphores.empty()); + ASSERT(mRecordingContext.waitSemaphores.empty()); + ASSERT(mRecordingContext.signalSemaphores.empty()); for (VkFence fence : mUnusedFences) { fn.DestroyFence(mVkDevice, fence, nullptr); @@ -276,6 +283,14 @@ namespace dawn_native { namespace vulkan { return mPendingCommands.commandBuffer; } + CommandRecordingContext* Device::GetPendingRecordingContext() { + if (mRecordingContext.commandBuffer == VK_NULL_HANDLE) { + mRecordingContext.commandBuffer = GetPendingCommandBuffer(); + } + + return &mRecordingContext; + } + void Device::SubmitPendingCommands() { if (mPendingCommands.pool == VK_NULL_HANDLE) { return; @@ -285,19 +300,21 @@ namespace dawn_native { namespace vulkan { ASSERT(false); } - std::vector<VkPipelineStageFlags> dstStageMasks(mWaitSemaphores.size(), + std::vector<VkPipelineStageFlags> dstStageMasks(mRecordingContext.waitSemaphores.size(), VK_PIPELINE_STAGE_ALL_COMMANDS_BIT); VkSubmitInfo submitInfo; submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submitInfo.pNext = nullptr; - submitInfo.waitSemaphoreCount = static_cast<uint32_t>(mWaitSemaphores.size()); - submitInfo.pWaitSemaphores = mWaitSemaphores.data(); + submitInfo.waitSemaphoreCount = + static_cast<uint32_t>(mRecordingContext.waitSemaphores.size()); + submitInfo.pWaitSemaphores = mRecordingContext.waitSemaphores.data(); submitInfo.pWaitDstStageMask = dstStageMasks.data(); submitInfo.commandBufferCount = 1; submitInfo.pCommandBuffers = &mPendingCommands.commandBuffer; - submitInfo.signalSemaphoreCount = 0; - submitInfo.pSignalSemaphores = 0; + submitInfo.signalSemaphoreCount = + static_cast<uint32_t>(mRecordingContext.signalSemaphores.size()); + submitInfo.pSignalSemaphores = mRecordingContext.signalSemaphores.data(); VkFence fence = GetUnusedFence(); if (fn.QueueSubmit(mQueue, 1, &submitInfo, fence) != VK_SUCCESS) { @@ -309,14 +326,15 @@ namespace dawn_native { namespace vulkan { mPendingCommands = CommandPoolAndBuffer(); mFencesInFlight.emplace(fence, mLastSubmittedSerial); - for (VkSemaphore semaphore : mWaitSemaphores) { + for (VkSemaphore semaphore : mRecordingContext.waitSemaphores) { mDeleter->DeleteWhenUnused(semaphore); } - mWaitSemaphores.clear(); - } - void Device::AddWaitSemaphore(VkSemaphore semaphore) { - mWaitSemaphores.push_back(semaphore); + for (VkSemaphore semaphore : mRecordingContext.signalSemaphores) { + mDeleter->DeleteWhenUnused(semaphore); + } + + mRecordingContext = CommandRecordingContext(); } ResultOrError<VulkanDeviceKnobs> Device::CreateDevice(VkPhysicalDevice physicalDevice) { @@ -331,7 +349,22 @@ namespace dawn_native { namespace vulkan { extensionsToRequest.push_back(kExtensionNameExtDebugMarker); usedKnobs.debugMarker = true; } - + if (mDeviceInfo.externalMemory) { + extensionsToRequest.push_back(kExtensionNameKhrExternalMemory); + usedKnobs.externalMemory = true; + } + if (mDeviceInfo.externalMemoryFD) { + extensionsToRequest.push_back(kExtensionNameKhrExternalMemoryFD); + usedKnobs.externalMemoryFD = true; + } + if (mDeviceInfo.externalSemaphore) { + extensionsToRequest.push_back(kExtensionNameKhrExternalSemaphore); + usedKnobs.externalSemaphore = true; + } + if (mDeviceInfo.externalSemaphoreFD) { + extensionsToRequest.push_back(kExtensionNameKhrExternalSemaphoreFD); + usedKnobs.externalSemaphoreFD = true; + } if (mDeviceInfo.swapchain) { extensionsToRequest.push_back(kExtensionNameKhrSwapchain); usedKnobs.swapchain = true; @@ -344,8 +377,11 @@ namespace dawn_native { namespace vulkan { // Always require fragmentStoresAndAtomics because it is required by end2end tests. usedKnobs.features.fragmentStoresAndAtomics = VK_TRUE; - // TODO(jiawei.shao@intel.com): support BC formats as extension - usedKnobs.features.textureCompressionBC = VK_TRUE; + if (IsExtensionEnabled(Extension::TextureCompressionBC)) { + ASSERT(ToBackend(GetAdapter())->GetDeviceInfo().features.textureCompressionBC == + VK_TRUE); + usedKnobs.features.textureCompressionBC = VK_TRUE; + } // Find a universal queue family { @@ -361,7 +397,7 @@ namespace dawn_native { namespace vulkan { } if (universalQueueFamily == -1) { - return DAWN_CONTEXT_LOST_ERROR("No universal queue family"); + return DAWN_DEVICE_LOST_ERROR("No universal queue family"); } mQueueFamily = static_cast<uint32_t>(universalQueueFamily); } @@ -401,6 +437,12 @@ namespace dawn_native { namespace vulkan { fn.GetDeviceQueue(mVkDevice, mQueueFamily, 0, &mQueue); } + void Device::InitTogglesFromDriver() { + // TODO(jiawei.shao@intel.com): tighten this workaround when this issue is fixed in both + // Vulkan SPEC and drivers. + SetToggle(Toggle::UseTemporaryBufferInCompressedTextureToTextureCopy, true); + } + VulkanFunctions* Device::GetMutableFunctions() { return const_cast<VulkanFunctions*>(&fn); } @@ -526,7 +568,7 @@ namespace dawn_native { namespace vulkan { // Insert pipeline barrier to ensure correct ordering with previous memory operations on the // buffer. ToBackend(destination) - ->TransitionUsageNow(GetPendingCommandBuffer(), dawn::BufferUsageBit::CopyDst); + ->TransitionUsageNow(GetPendingRecordingContext(), dawn::BufferUsage::CopyDst); VkBufferCopy copy; copy.srcOffset = sourceOffset; @@ -538,4 +580,99 @@ namespace dawn_native { namespace vulkan { return {}; } + + MaybeError Device::ImportExternalImage(const ExternalImageDescriptor* descriptor, + ExternalMemoryHandle memoryHandle, + const std::vector<ExternalSemaphoreHandle>& waitHandles, + VkSemaphore* outSignalSemaphore, + VkDeviceMemory* outAllocation, + std::vector<VkSemaphore>* outWaitSemaphores) { + const TextureDescriptor* textureDescriptor = + reinterpret_cast<const TextureDescriptor*>(descriptor->cTextureDescriptor); + + // Check services support this combination of handle type / image info + if (!mExternalSemaphoreService->Supported()) { + return DAWN_VALIDATION_ERROR("External semaphore usage not supported"); + } + if (!mExternalMemoryService->Supported( + VulkanImageFormat(textureDescriptor->format), VK_IMAGE_TYPE_2D, + VK_IMAGE_TILING_OPTIMAL, + VulkanImageUsage(textureDescriptor->usage, + GetValidInternalFormat(textureDescriptor->format)), + VK_IMAGE_CREATE_ALIAS_BIT_KHR)) { + return DAWN_VALIDATION_ERROR("External memory usage not supported"); + } + + // Create an external semaphore to signal when the texture is done being used + DAWN_TRY_ASSIGN(*outSignalSemaphore, + mExternalSemaphoreService->CreateExportableSemaphore()); + + // Import the external image's memory + DAWN_TRY_ASSIGN(*outAllocation, + mExternalMemoryService->ImportMemory( + memoryHandle, descriptor->allocationSize, descriptor->memoryTypeIndex)); + + // Import semaphores we have to wait on before using the texture + for (const ExternalSemaphoreHandle& handle : waitHandles) { + VkSemaphore semaphore = VK_NULL_HANDLE; + DAWN_TRY_ASSIGN(semaphore, mExternalSemaphoreService->ImportSemaphore(handle)); + outWaitSemaphores->push_back(semaphore); + } + + return {}; + } + + MaybeError Device::SignalAndExportExternalTexture(Texture* texture, + ExternalSemaphoreHandle* outHandle) { + DAWN_TRY(ValidateObject(texture)); + + VkSemaphore outSignalSemaphore; + DAWN_TRY(texture->SignalAndDestroy(&outSignalSemaphore)); + + // This has to happen right after SignalAndDestroy, since the semaphore will be + // deleted when the fenced deleter runs after the queue submission + DAWN_TRY_ASSIGN(*outHandle, mExternalSemaphoreService->ExportSemaphore(outSignalSemaphore)); + + return {}; + } + + TextureBase* Device::CreateTextureWrappingVulkanImage( + const ExternalImageDescriptor* descriptor, + ExternalMemoryHandle memoryHandle, + const std::vector<ExternalSemaphoreHandle>& waitHandles) { + const TextureDescriptor* textureDescriptor = + reinterpret_cast<const TextureDescriptor*>(descriptor->cTextureDescriptor); + + // Initial validation + if (ConsumedError(ValidateTextureDescriptor(this, textureDescriptor))) { + return nullptr; + } + if (ConsumedError(ValidateVulkanImageCanBeWrapped(this, textureDescriptor))) { + return nullptr; + } + + VkSemaphore signalSemaphore = VK_NULL_HANDLE; + VkDeviceMemory allocation = VK_NULL_HANDLE; + std::vector<VkSemaphore> waitSemaphores; + waitSemaphores.reserve(waitHandles.size()); + + // If failed, cleanup + if (ConsumedError(ImportExternalImage(descriptor, memoryHandle, waitHandles, + &signalSemaphore, &allocation, &waitSemaphores))) { + // Clear the signal semaphore + fn.DestroySemaphore(GetVkDevice(), signalSemaphore, nullptr); + + // Clear image memory + fn.FreeMemory(GetVkDevice(), allocation, nullptr); + + // Clear any wait semaphores we were able to import + for (VkSemaphore semaphore : waitSemaphores) { + fn.DestroySemaphore(GetVkDevice(), semaphore, nullptr); + } + return nullptr; + } + + return new Texture(this, descriptor, textureDescriptor, signalSemaphore, allocation, + waitSemaphores); + } }} // namespace dawn_native::vulkan diff --git a/chromium/third_party/dawn/src/dawn_native/vulkan/DeviceVk.h b/chromium/third_party/dawn/src/dawn_native/vulkan/DeviceVk.h index 7eb33620d6c..c3ff3522e2b 100644 --- a/chromium/third_party/dawn/src/dawn_native/vulkan/DeviceVk.h +++ b/chromium/third_party/dawn/src/dawn_native/vulkan/DeviceVk.h @@ -20,10 +20,14 @@ #include "common/Serial.h" #include "common/SerialQueue.h" #include "dawn_native/Device.h" +#include "dawn_native/vulkan/CommandRecordingContext.h" #include "dawn_native/vulkan/Forward.h" #include "dawn_native/vulkan/VulkanFunctions.h" #include "dawn_native/vulkan/VulkanInfo.h" +#include "dawn_native/vulkan/external_memory/MemoryService.h" +#include "dawn_native/vulkan/external_semaphore/SemaphoreService.h" + #include <memory> #include <queue> @@ -31,6 +35,7 @@ namespace dawn_native { namespace vulkan { class Adapter; class BufferUploader; + struct ExternalImageDescriptor; class FencedDeleter; class MapRequestTracker; class MemoryAllocator; @@ -59,9 +64,17 @@ namespace dawn_native { namespace vulkan { RenderPassCache* GetRenderPassCache() const; VkCommandBuffer GetPendingCommandBuffer(); + CommandRecordingContext* GetPendingRecordingContext(); Serial GetPendingCommandSerial() const override; void SubmitPendingCommands(); - void AddWaitSemaphore(VkSemaphore semaphore); + + TextureBase* CreateTextureWrappingVulkanImage( + const ExternalImageDescriptor* descriptor, + ExternalMemoryHandle memoryHandle, + const std::vector<ExternalSemaphoreHandle>& waitHandles); + + MaybeError SignalAndExportExternalTexture(Texture* texture, + ExternalSemaphoreHandle* outHandle); // Dawn API CommandBufferBase* CreateCommandBuffer(CommandEncoderBase* encoder, @@ -104,6 +117,8 @@ namespace dawn_native { namespace vulkan { ResultOrError<VulkanDeviceKnobs> CreateDevice(VkPhysicalDevice physicalDevice); void GatherQueueFromDevice(); + void InitTogglesFromDriver(); + // To make it easier to use fn it is a public const member. However // the Device is allowed to mutate them through these private methods. VulkanFunctions* GetMutableFunctions(); @@ -118,6 +133,9 @@ namespace dawn_native { namespace vulkan { std::unique_ptr<MemoryAllocator> mMemoryAllocator; std::unique_ptr<RenderPassCache> mRenderPassCache; + std::unique_ptr<external_memory::Service> mExternalMemoryService; + std::unique_ptr<external_semaphore::Service> mExternalSemaphoreService; + VkFence GetUnusedFence(); void CheckPassedFences(); @@ -142,7 +160,14 @@ namespace dawn_native { namespace vulkan { SerialQueue<CommandPoolAndBuffer> mCommandsInFlight; std::vector<CommandPoolAndBuffer> mUnusedCommands; CommandPoolAndBuffer mPendingCommands; - std::vector<VkSemaphore> mWaitSemaphores; + CommandRecordingContext mRecordingContext; + + MaybeError ImportExternalImage(const ExternalImageDescriptor* descriptor, + ExternalMemoryHandle memoryHandle, + const std::vector<ExternalSemaphoreHandle>& waitHandles, + VkSemaphore* outSignalSemaphore, + VkDeviceMemory* outAllocation, + std::vector<VkSemaphore>* outWaitSemaphores); }; }} // namespace dawn_native::vulkan diff --git a/chromium/third_party/dawn/src/dawn_native/vulkan/ExternalHandle.h b/chromium/third_party/dawn/src/dawn_native/vulkan/ExternalHandle.h new file mode 100644 index 00000000000..37a2e21d1e8 --- /dev/null +++ b/chromium/third_party/dawn/src/dawn_native/vulkan/ExternalHandle.h @@ -0,0 +1,19 @@ +#ifndef DAWNNATIVE_VULKAN_EXTERNALHANDLE_H_ +#define DAWNNATIVE_VULKAN_EXTERNALHANDLE_H_ + +namespace dawn_native { namespace vulkan { + +#ifdef DAWN_PLATFORM_LINUX + // File descriptor + using ExternalMemoryHandle = int; + // File descriptor + using ExternalSemaphoreHandle = int; +#else + // Generic types so that the Null service can compile, not used for real handles + using ExternalMemoryHandle = void*; + using ExternalSemaphoreHandle = void*; +#endif + +}} // namespace dawn_native::vulkan + +#endif // DAWNNATIVE_VULKAN_EXTERNALHANDLE_H_ diff --git a/chromium/third_party/dawn/src/dawn_native/vulkan/MemoryAllocator.cpp b/chromium/third_party/dawn/src/dawn_native/vulkan/MemoryAllocator.cpp index 66a779e6f47..abd53da6f16 100644 --- a/chromium/third_party/dawn/src/dawn_native/vulkan/MemoryAllocator.cpp +++ b/chromium/third_party/dawn/src/dawn_native/vulkan/MemoryAllocator.cpp @@ -41,9 +41,7 @@ namespace dawn_native { namespace vulkan { MemoryAllocator::~MemoryAllocator() { } - bool MemoryAllocator::Allocate(VkMemoryRequirements requirements, - bool mappable, - DeviceMemoryAllocation* allocation) { + int MemoryAllocator::FindBestTypeIndex(VkMemoryRequirements requirements, bool mappable) { const VulkanDeviceInfo& info = mDevice->GetDeviceInfo(); // Find a suitable memory type for this allocation @@ -93,6 +91,14 @@ namespace dawn_native { namespace vulkan { } } + return bestType; + } + + bool MemoryAllocator::Allocate(VkMemoryRequirements requirements, + bool mappable, + DeviceMemoryAllocation* allocation) { + int bestType = FindBestTypeIndex(requirements, mappable); + // TODO(cwallez@chromium.org): I think the Vulkan spec guarantees this should never happen if (bestType == -1) { ASSERT(false); diff --git a/chromium/third_party/dawn/src/dawn_native/vulkan/MemoryAllocator.h b/chromium/third_party/dawn/src/dawn_native/vulkan/MemoryAllocator.h index afea7afc93f..56d3350f1d6 100644 --- a/chromium/third_party/dawn/src/dawn_native/vulkan/MemoryAllocator.h +++ b/chromium/third_party/dawn/src/dawn_native/vulkan/MemoryAllocator.h @@ -42,6 +42,7 @@ namespace dawn_native { namespace vulkan { MemoryAllocator(Device* device); ~MemoryAllocator(); + int FindBestTypeIndex(VkMemoryRequirements requirements, bool mappable); bool Allocate(VkMemoryRequirements requirements, bool mappable, DeviceMemoryAllocation* allocation); diff --git a/chromium/third_party/dawn/src/dawn_native/vulkan/NativeSwapChainImplVk.cpp b/chromium/third_party/dawn/src/dawn_native/vulkan/NativeSwapChainImplVk.cpp index 264ad32770e..858d478461f 100644 --- a/chromium/third_party/dawn/src/dawn_native/vulkan/NativeSwapChainImplVk.cpp +++ b/chromium/third_party/dawn/src/dawn_native/vulkan/NativeSwapChainImplVk.cpp @@ -73,7 +73,7 @@ namespace dawn_native { namespace vulkan { } DawnSwapChainError NativeSwapChainImpl::Configure(DawnTextureFormat format, - DawnTextureUsageBit usage, + DawnTextureUsage usage, uint32_t width, uint32_t height) { UpdateSurfaceConfig(); @@ -99,7 +99,7 @@ namespace dawn_native { namespace vulkan { createInfo.imageExtent.width = width; createInfo.imageExtent.height = height; createInfo.imageArrayLayers = 1; - createInfo.imageUsage = VulkanImageUsage(static_cast<dawn::TextureUsageBit>(usage), + createInfo.imageUsage = VulkanImageUsage(static_cast<dawn::TextureUsage>(usage), mDevice->GetValidInternalFormat(mConfig.format)); createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; createInfo.queueFamilyIndexCount = 0; @@ -184,7 +184,7 @@ namespace dawn_native { namespace vulkan { } nextTexture->texture.u64 = mSwapChainImages[mLastImageIndex].GetU64(); - mDevice->AddWaitSemaphore(semaphore); + mDevice->GetPendingRecordingContext()->waitSemaphores.push_back(semaphore); return DAWN_SWAP_CHAIN_NO_ERROR; } diff --git a/chromium/third_party/dawn/src/dawn_native/vulkan/NativeSwapChainImplVk.h b/chromium/third_party/dawn/src/dawn_native/vulkan/NativeSwapChainImplVk.h index 1b89784831f..c213cb45c11 100644 --- a/chromium/third_party/dawn/src/dawn_native/vulkan/NativeSwapChainImplVk.h +++ b/chromium/third_party/dawn/src/dawn_native/vulkan/NativeSwapChainImplVk.h @@ -33,7 +33,7 @@ namespace dawn_native { namespace vulkan { void Init(DawnWSIContextVulkan* context); DawnSwapChainError Configure(DawnTextureFormat format, - DawnTextureUsageBit, + DawnTextureUsage, uint32_t width, uint32_t height); DawnSwapChainError GetNextTexture(DawnSwapChainNextTexture* nextTexture); diff --git a/chromium/third_party/dawn/src/dawn_native/vulkan/QueueVk.cpp b/chromium/third_party/dawn/src/dawn_native/vulkan/QueueVk.cpp index a5451b182b6..c268bcd3d48 100644 --- a/chromium/third_party/dawn/src/dawn_native/vulkan/QueueVk.cpp +++ b/chromium/third_party/dawn/src/dawn_native/vulkan/QueueVk.cpp @@ -15,6 +15,7 @@ #include "dawn_native/vulkan/QueueVk.h" #include "dawn_native/vulkan/CommandBufferVk.h" +#include "dawn_native/vulkan/CommandRecordingContext.h" #include "dawn_native/vulkan/DeviceVk.h" namespace dawn_native { namespace vulkan { @@ -30,9 +31,9 @@ namespace dawn_native { namespace vulkan { device->Tick(); - VkCommandBuffer commandBuffer = device->GetPendingCommandBuffer(); + CommandRecordingContext* recordingContext = device->GetPendingRecordingContext(); for (uint32_t i = 0; i < commandCount; ++i) { - ToBackend(commands[i])->RecordCommands(commandBuffer); + ToBackend(commands[i])->RecordCommands(recordingContext); } device->SubmitPendingCommands(); diff --git a/chromium/third_party/dawn/src/dawn_native/vulkan/RenderPipelineVk.cpp b/chromium/third_party/dawn/src/dawn_native/vulkan/RenderPipelineVk.cpp index 7eb164ffb60..8b8f5bf2666 100644 --- a/chromium/third_party/dawn/src/dawn_native/vulkan/RenderPipelineVk.cpp +++ b/chromium/third_party/dawn/src/dawn_native/vulkan/RenderPipelineVk.cpp @@ -320,8 +320,8 @@ namespace dawn_native { namespace vulkan { shaderStages[0].flags = 0; shaderStages[0].stage = VK_SHADER_STAGE_VERTEX_BIT; shaderStages[0].pSpecializationInfo = nullptr; - shaderStages[0].module = ToBackend(descriptor->vertexStage->module)->GetHandle(); - shaderStages[0].pName = descriptor->vertexStage->entryPoint; + shaderStages[0].module = ToBackend(descriptor->vertexStage.module)->GetHandle(); + shaderStages[0].pName = descriptor->vertexStage.entryPoint; shaderStages[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; shaderStages[1].pNext = nullptr; diff --git a/chromium/third_party/dawn/src/dawn_native/vulkan/ShaderModuleVk.cpp b/chromium/third_party/dawn/src/dawn_native/vulkan/ShaderModuleVk.cpp index 0dd8810d232..9f48e170678 100644 --- a/chromium/third_party/dawn/src/dawn_native/vulkan/ShaderModuleVk.cpp +++ b/chromium/third_party/dawn/src/dawn_native/vulkan/ShaderModuleVk.cpp @@ -17,7 +17,7 @@ #include "dawn_native/vulkan/DeviceVk.h" #include "dawn_native/vulkan/FencedDeleter.h" -#include <spirv-cross/spirv_cross.hpp> +#include <spirv_cross.hpp> namespace dawn_native { namespace vulkan { diff --git a/chromium/third_party/dawn/src/dawn_native/vulkan/StagingBufferVk.cpp b/chromium/third_party/dawn/src/dawn_native/vulkan/StagingBufferVk.cpp index 4e96f85f9b8..38bb84eeedb 100644 --- a/chromium/third_party/dawn/src/dawn_native/vulkan/StagingBufferVk.cpp +++ b/chromium/third_party/dawn/src/dawn_native/vulkan/StagingBufferVk.cpp @@ -36,24 +36,24 @@ namespace dawn_native { namespace vulkan { if (mDevice->fn.CreateBuffer(mDevice->GetVkDevice(), &createInfo, nullptr, &mBuffer) != VK_SUCCESS) { - return DAWN_CONTEXT_LOST_ERROR("Unable to create staging buffer."); + return DAWN_DEVICE_LOST_ERROR("Unable to create staging buffer."); } VkMemoryRequirements requirements; mDevice->fn.GetBufferMemoryRequirements(mDevice->GetVkDevice(), mBuffer, &requirements); if (!mDevice->GetMemoryAllocator()->Allocate(requirements, true, &mAllocation)) { - return DAWN_CONTEXT_LOST_ERROR("Unable to allocate memory for staging buffer."); + return DAWN_DEVICE_LOST_ERROR("Unable to allocate memory for staging buffer."); } if (mDevice->fn.BindBufferMemory(mDevice->GetVkDevice(), mBuffer, mAllocation.GetMemory(), mAllocation.GetMemoryOffset()) != VK_SUCCESS) { - return DAWN_CONTEXT_LOST_ERROR("Unable to attach memory to the staging buffer."); + return DAWN_DEVICE_LOST_ERROR("Unable to attach memory to the staging buffer."); } mMappedPointer = mAllocation.GetMappedPointer(); if (mMappedPointer == nullptr) { - return DAWN_CONTEXT_LOST_ERROR("Unable to map staging buffer."); + return DAWN_DEVICE_LOST_ERROR("Unable to map staging buffer."); } return {}; @@ -69,4 +69,4 @@ namespace dawn_native { namespace vulkan { return mBuffer; } -}} // namespace dawn_native::vulkan
\ No newline at end of file +}} // namespace dawn_native::vulkan diff --git a/chromium/third_party/dawn/src/dawn_native/vulkan/SwapChainVk.cpp b/chromium/third_party/dawn/src/dawn_native/vulkan/SwapChainVk.cpp index f4e857d4d85..570760d15a4 100644 --- a/chromium/third_party/dawn/src/dawn_native/vulkan/SwapChainVk.cpp +++ b/chromium/third_party/dawn/src/dawn_native/vulkan/SwapChainVk.cpp @@ -25,8 +25,8 @@ namespace dawn_native { namespace vulkan { DawnWSIContextVulkan wsiContext = {}; im.Init(im.userData, &wsiContext); - ASSERT(im.textureUsage != DAWN_TEXTURE_USAGE_BIT_NONE); - mTextureUsage = static_cast<dawn::TextureUsageBit>(im.textureUsage); + ASSERT(im.textureUsage != DAWN_TEXTURE_USAGE_NONE); + mTextureUsage = static_cast<dawn::TextureUsage>(im.textureUsage); } SwapChain::~SwapChain() { @@ -38,7 +38,7 @@ namespace dawn_native { namespace vulkan { DawnSwapChainError error = im.GetNextTexture(im.userData, &next); if (error) { - GetDevice()->HandleError(error); + GetDevice()->HandleError(dawn::ErrorType::Unknown, error); return nullptr; } @@ -51,8 +51,8 @@ namespace dawn_native { namespace vulkan { // Perform the necessary pipeline barriers for the texture to be used with the usage // requested by the implementation. - VkCommandBuffer commands = device->GetPendingCommandBuffer(); - ToBackend(texture)->TransitionUsageNow(commands, mTextureUsage); + CommandRecordingContext* recordingContext = device->GetPendingRecordingContext(); + ToBackend(texture)->TransitionUsageNow(recordingContext, mTextureUsage); device->SubmitPendingCommands(); } diff --git a/chromium/third_party/dawn/src/dawn_native/vulkan/SwapChainVk.h b/chromium/third_party/dawn/src/dawn_native/vulkan/SwapChainVk.h index e546c34067b..190346ceffa 100644 --- a/chromium/third_party/dawn/src/dawn_native/vulkan/SwapChainVk.h +++ b/chromium/third_party/dawn/src/dawn_native/vulkan/SwapChainVk.h @@ -33,7 +33,7 @@ namespace dawn_native { namespace vulkan { void OnBeforePresent(TextureBase* texture) override; private: - dawn::TextureUsageBit mTextureUsage; + dawn::TextureUsage mTextureUsage; }; }} // namespace dawn_native::vulkan diff --git a/chromium/third_party/dawn/src/dawn_native/vulkan/TextureVk.cpp b/chromium/third_party/dawn/src/dawn_native/vulkan/TextureVk.cpp index ba1f4b55278..a37e300a03c 100644 --- a/chromium/third_party/dawn/src/dawn_native/vulkan/TextureVk.cpp +++ b/chromium/third_party/dawn/src/dawn_native/vulkan/TextureVk.cpp @@ -14,9 +14,18 @@ #include "dawn_native/vulkan/TextureVk.h" +#include "common/Assert.h" +#include "common/Math.h" +#include "dawn_native/DynamicUploader.h" +#include "dawn_native/Error.h" +#include "dawn_native/VulkanBackend.h" #include "dawn_native/vulkan/AdapterVk.h" +#include "dawn_native/vulkan/BufferVk.h" +#include "dawn_native/vulkan/CommandRecordingContext.h" #include "dawn_native/vulkan/DeviceVk.h" #include "dawn_native/vulkan/FencedDeleter.h" +#include "dawn_native/vulkan/StagingBufferVk.h" +#include "dawn_native/vulkan/UtilsVulkan.h" namespace dawn_native { namespace vulkan { @@ -51,22 +60,22 @@ namespace dawn_native { namespace vulkan { } // Computes which vulkan access type could be required for the given Dawn usage. - VkAccessFlags VulkanAccessFlags(dawn::TextureUsageBit usage, const Format& format) { + VkAccessFlags VulkanAccessFlags(dawn::TextureUsage usage, const Format& format) { VkAccessFlags flags = 0; - if (usage & dawn::TextureUsageBit::CopySrc) { + if (usage & dawn::TextureUsage::CopySrc) { flags |= VK_ACCESS_TRANSFER_READ_BIT; } - if (usage & dawn::TextureUsageBit::CopyDst) { + if (usage & dawn::TextureUsage::CopyDst) { flags |= VK_ACCESS_TRANSFER_WRITE_BIT; } - if (usage & dawn::TextureUsageBit::Sampled) { + if (usage & dawn::TextureUsage::Sampled) { flags |= VK_ACCESS_SHADER_READ_BIT; } - if (usage & dawn::TextureUsageBit::Storage) { + if (usage & dawn::TextureUsage::Storage) { flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; } - if (usage & dawn::TextureUsageBit::OutputAttachment) { + if (usage & dawn::TextureUsage::OutputAttachment) { if (format.HasDepthOrStencil()) { flags |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; @@ -75,7 +84,7 @@ namespace dawn_native { namespace vulkan { VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; } } - if (usage & dawn::TextureUsageBit::Present) { + if (usage & dawn::TextureUsage::Present) { // There is no access flag for present because the VK_KHR_SWAPCHAIN extension says // that vkQueuePresentKHR makes the memory of the image visible to the presentation // engine. There's also a note explicitly saying dstAccessMask should be 0. On the @@ -88,8 +97,8 @@ namespace dawn_native { namespace vulkan { } // Chooses which Vulkan image layout should be used for the given Dawn usage - VkImageLayout VulkanImageLayout(dawn::TextureUsageBit usage, const Format& format) { - if (usage == dawn::TextureUsageBit::None) { + VkImageLayout VulkanImageLayout(dawn::TextureUsage usage, const Format& format) { + if (usage == dawn::TextureUsage::None) { return VK_IMAGE_LAYOUT_UNDEFINED; } @@ -99,27 +108,27 @@ namespace dawn_native { namespace vulkan { // Usage has a single bit so we can switch on its value directly. switch (usage) { - case dawn::TextureUsageBit::CopyDst: + case dawn::TextureUsage::CopyDst: return VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; - case dawn::TextureUsageBit::Sampled: + case dawn::TextureUsage::Sampled: return VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; // Vulkan texture copy functions require the image to be in _one_ known layout. // Depending on whether parts of the texture have been transitioned to only // CopySrc or a combination with something else, the texture could be in a // combination of GENERAL and TRANSFER_SRC_OPTIMAL. This would be a problem, so we // make CopySrc use GENERAL. - case dawn::TextureUsageBit::CopySrc: + case dawn::TextureUsage::CopySrc: // Writable storage textures must use general. If we could know the texture is read // only we could use SHADER_READ_ONLY_OPTIMAL - case dawn::TextureUsageBit::Storage: + case dawn::TextureUsage::Storage: return VK_IMAGE_LAYOUT_GENERAL; - case dawn::TextureUsageBit::OutputAttachment: + case dawn::TextureUsage::OutputAttachment: if (format.HasDepthOrStencil()) { return VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; } else { return VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; } - case dawn::TextureUsageBit::Present: + case dawn::TextureUsage::Present: return VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; default: UNREACHABLE(); @@ -127,24 +136,23 @@ namespace dawn_native { namespace vulkan { } // Computes which Vulkan pipeline stage can access a texture in the given Dawn usage - VkPipelineStageFlags VulkanPipelineStage(dawn::TextureUsageBit usage, - const Format& format) { + VkPipelineStageFlags VulkanPipelineStage(dawn::TextureUsage usage, const Format& format) { VkPipelineStageFlags flags = 0; - if (usage == dawn::TextureUsageBit::None) { + if (usage == dawn::TextureUsage::None) { // This only happens when a texture is initially created (and for srcAccessMask) in // which case there is no need to wait on anything to stop accessing this texture. return VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; } - if (usage & (dawn::TextureUsageBit::CopySrc | dawn::TextureUsageBit::CopyDst)) { + if (usage & (dawn::TextureUsage::CopySrc | dawn::TextureUsage::CopyDst)) { flags |= VK_PIPELINE_STAGE_TRANSFER_BIT; } - if (usage & (dawn::TextureUsageBit::Sampled | dawn::TextureUsageBit::Storage)) { + if (usage & (dawn::TextureUsage::Sampled | dawn::TextureUsage::Storage)) { flags |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; } - if (usage & dawn::TextureUsageBit::OutputAttachment) { + if (usage & dawn::TextureUsage::OutputAttachment) { if (format.HasDepthOrStencil()) { flags |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; @@ -154,7 +162,7 @@ namespace dawn_native { namespace vulkan { flags |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; } } - if (usage & dawn::TextureUsageBit::Present) { + if (usage & dawn::TextureUsage::Present) { // There is no pipeline stage for present but a pipeline stage is required so we use // "bottom of pipe" to block as little as possible and vkQueuePresentKHR will make // the memory visible to the presentation engine. The spec explicitly mentions that @@ -220,10 +228,6 @@ namespace dawn_native { namespace vulkan { case dawn::TextureFormat::R8Sint: return VK_FORMAT_R8_SINT; - case dawn::TextureFormat::R16Unorm: - return VK_FORMAT_R16_UNORM; - case dawn::TextureFormat::R16Snorm: - return VK_FORMAT_R16_SNORM; case dawn::TextureFormat::R16Uint: return VK_FORMAT_R16_UINT; case dawn::TextureFormat::R16Sint: @@ -245,10 +249,6 @@ namespace dawn_native { namespace vulkan { return VK_FORMAT_R32_SINT; case dawn::TextureFormat::R32Float: return VK_FORMAT_R32_SFLOAT; - case dawn::TextureFormat::RG16Unorm: - return VK_FORMAT_R16G16_UNORM; - case dawn::TextureFormat::RG16Snorm: - return VK_FORMAT_R16G16_SNORM; case dawn::TextureFormat::RG16Uint: return VK_FORMAT_R16G16_UINT; case dawn::TextureFormat::RG16Sint: @@ -280,10 +280,6 @@ namespace dawn_native { namespace vulkan { return VK_FORMAT_R32G32_SINT; case dawn::TextureFormat::RG32Float: return VK_FORMAT_R32G32_SFLOAT; - case dawn::TextureFormat::RGBA16Unorm: - return VK_FORMAT_R16G16B16A16_UNORM; - case dawn::TextureFormat::RGBA16Snorm: - return VK_FORMAT_R16G16B16A16_SNORM; case dawn::TextureFormat::RGBA16Uint: return VK_FORMAT_R16G16B16A16_UINT; case dawn::TextureFormat::RGBA16Sint: @@ -341,22 +337,22 @@ namespace dawn_native { namespace vulkan { // Converts the Dawn usage flags to Vulkan usage flags. Also needs the format to choose // between color and depth attachment usages. - VkImageUsageFlags VulkanImageUsage(dawn::TextureUsageBit usage, const Format& format) { + VkImageUsageFlags VulkanImageUsage(dawn::TextureUsage usage, const Format& format) { VkImageUsageFlags flags = 0; - if (usage & dawn::TextureUsageBit::CopySrc) { + if (usage & dawn::TextureUsage::CopySrc) { flags |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT; } - if (usage & dawn::TextureUsageBit::CopyDst) { + if (usage & dawn::TextureUsage::CopyDst) { flags |= VK_IMAGE_USAGE_TRANSFER_DST_BIT; } - if (usage & dawn::TextureUsageBit::Sampled) { + if (usage & dawn::TextureUsage::Sampled) { flags |= VK_IMAGE_USAGE_SAMPLED_BIT; } - if (usage & dawn::TextureUsageBit::Storage) { + if (usage & dawn::TextureUsage::Storage) { flags |= VK_IMAGE_USAGE_STORAGE_BIT; } - if (usage & dawn::TextureUsageBit::OutputAttachment) { + if (usage & dawn::TextureUsage::OutputAttachment) { if (format.HasDepthOrStencil()) { flags |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; } else { @@ -378,12 +374,33 @@ namespace dawn_native { namespace vulkan { } } + MaybeError ValidateVulkanImageCanBeWrapped(const DeviceBase*, + const TextureDescriptor* descriptor) { + if (descriptor->dimension != dawn::TextureDimension::e2D) { + return DAWN_VALIDATION_ERROR("Texture must be 2D"); + } + + if (descriptor->mipLevelCount != 1) { + return DAWN_VALIDATION_ERROR("Mip level count must be 1"); + } + + if (descriptor->arrayLayerCount != 1) { + return DAWN_VALIDATION_ERROR("Array layer count must be 1"); + } + + if (descriptor->sampleCount != 1) { + return DAWN_VALIDATION_ERROR("Sample count must be 1"); + } + + return {}; + } + Texture::Texture(Device* device, const TextureDescriptor* descriptor) : TextureBase(device, descriptor, TextureState::OwnedInternal) { // Create the Vulkan image "container". We don't need to check that the format supports the // combination of sample, usage etc. because validation should have been done in the Dawn // frontend already based on the minimum supported formats in the Vulkan spec - VkImageCreateInfo createInfo; + VkImageCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; createInfo.pNext = nullptr; createInfo.flags = 0; @@ -430,33 +447,9 @@ namespace dawn_native { namespace vulkan { ASSERT(false); } if (device->IsToggleEnabled(Toggle::NonzeroClearResourcesOnCreationForTesting)) { - VkImageSubresourceRange range = {}; - range.aspectMask = GetVkAspectMask(); - range.baseMipLevel = 0; - range.levelCount = GetNumMipLevels(); - range.baseArrayLayer = 0; - range.layerCount = GetArrayLayers(); - TransitionUsageNow(ToBackend(GetDevice())->GetPendingCommandBuffer(), - dawn::TextureUsageBit::CopyDst); - - if (GetFormat().HasDepthOrStencil()) { - VkClearDepthStencilValue clear_color[1]; - clear_color[0].depth = 1.0f; - clear_color[0].stencil = 1u; - ToBackend(GetDevice()) - ->fn.CmdClearDepthStencilImage( - ToBackend(GetDevice())->GetPendingCommandBuffer(), GetHandle(), - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, clear_color, 1, &range); - } else { - // TODO(natlee@microsoft.com): use correct union member depending on the texture - // format - VkClearColorValue clear_color = {{1.0, 1.0, 1.0, 1.0}}; - - ToBackend(GetDevice()) - ->fn.CmdClearColorImage(ToBackend(GetDevice())->GetPendingCommandBuffer(), - GetHandle(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - &clear_color, 1, &range); - } + device->ConsumedError(ClearTexture(ToBackend(GetDevice())->GetPendingRecordingContext(), + 0, GetNumMipLevels(), 0, GetArrayLayers(), + TextureBase::ClearValue::NonZero)); } } @@ -465,6 +458,95 @@ namespace dawn_native { namespace vulkan { : TextureBase(device, descriptor, TextureState::OwnedExternal), mHandle(nativeImage) { } + // Internally managed, but imported from file descriptor + Texture::Texture(Device* device, + const ExternalImageDescriptor* descriptor, + const TextureDescriptor* textureDescriptor, + VkSemaphore signalSemaphore, + VkDeviceMemory externalMemoryAllocation, + std::vector<VkSemaphore> waitSemaphores) + : TextureBase(device, textureDescriptor, TextureState::OwnedInternal), + mExternalAllocation(externalMemoryAllocation), + mExternalState(ExternalState::PendingAcquire), + mSignalSemaphore(signalSemaphore), + mWaitRequirements(std::move(waitSemaphores)) { + VkImageCreateInfo createInfo = {}; + createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + createInfo.pNext = nullptr; + createInfo.flags = VK_IMAGE_CREATE_ALIAS_BIT_KHR; + createInfo.imageType = VulkanImageType(GetDimension()); + createInfo.format = VulkanImageFormat(GetFormat().format); + createInfo.extent = VulkanExtent3D(GetSize()); + createInfo.mipLevels = GetNumMipLevels(); + createInfo.arrayLayers = GetArrayLayers(); + createInfo.samples = VulkanSampleCount(GetSampleCount()); + createInfo.tiling = VK_IMAGE_TILING_OPTIMAL; + createInfo.usage = VulkanImageUsage(GetUsage(), GetFormat()); + createInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + createInfo.queueFamilyIndexCount = 0; + createInfo.pQueueFamilyIndices = nullptr; + createInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + + ASSERT(IsSampleCountSupported(device, createInfo)); + + // We always set VK_IMAGE_USAGE_TRANSFER_DST_BIT unconditionally beause the Vulkan images + // that are used in vkCmdClearColorImage() must have been created with this flag, which is + // also required for the implementation of robust resource initialization. + createInfo.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT; + + if (device->fn.CreateImage(device->GetVkDevice(), &createInfo, nullptr, &mHandle) != + VK_SUCCESS) { + ASSERT(false); + } + + // Create the image memory and associate it with the container + VkMemoryRequirements requirements; + device->fn.GetImageMemoryRequirements(device->GetVkDevice(), mHandle, &requirements); + + ASSERT(requirements.size <= descriptor->allocationSize); + + if (device->fn.BindImageMemory(device->GetVkDevice(), mHandle, mExternalAllocation, 0) != + VK_SUCCESS) { + ASSERT(false); + } + + // Don't clear imported texture if already cleared + if (descriptor->isCleared) { + SetIsSubresourceContentInitialized(0, 1, 0, 1); + } + } + + MaybeError Texture::SignalAndDestroy(VkSemaphore* outSignalSemaphore) { + Device* device = ToBackend(GetDevice()); + + if (mExternalState == ExternalState::Released) { + return DAWN_VALIDATION_ERROR("Can't export signal semaphore from signaled texture"); + } + + if (mExternalAllocation == VK_NULL_HANDLE) { + return DAWN_VALIDATION_ERROR( + "Can't export signal semaphore from destroyed / non-external texture"); + } + + ASSERT(mSignalSemaphore != VK_NULL_HANDLE); + + // Release the texture + mExternalState = ExternalState::PendingRelease; + TransitionUsageNow(device->GetPendingRecordingContext(), dawn::TextureUsage::None); + + // Queue submit to signal we are done with the texture + device->GetPendingRecordingContext()->signalSemaphores.push_back(mSignalSemaphore); + device->SubmitPendingCommands(); + + // Write out the signal semaphore + *outSignalSemaphore = mSignalSemaphore; + mSignalSemaphore = VK_NULL_HANDLE; + + // Destroy the texture so it can't be used again + DestroyInternal(); + return {}; + } + Texture::~Texture() { DestroyInternal(); } @@ -478,12 +560,20 @@ namespace dawn_native { namespace vulkan { // freed after the VkImage is destroyed and this is taken care of by the // FencedDeleter. device->GetMemoryAllocator()->Free(&mMemoryAllocation); + } - if (mHandle != VK_NULL_HANDLE) { - device->GetFencedDeleter()->DeleteWhenUnused(mHandle); - } + if (mHandle != VK_NULL_HANDLE) { + device->GetFencedDeleter()->DeleteWhenUnused(mHandle); + } + + if (mExternalAllocation != VK_NULL_HANDLE) { + device->GetFencedDeleter()->DeleteWhenUnused(mExternalAllocation); } + mHandle = VK_NULL_HANDLE; + mExternalAllocation = VK_NULL_HANDLE; + // If a signal semaphore exists it should be requested before we delete the texture + ASSERT(mSignalSemaphore == VK_NULL_HANDLE); } VkImage Texture::GetHandle() const { @@ -494,10 +584,11 @@ namespace dawn_native { namespace vulkan { return VulkanAspectMask(GetFormat()); } - void Texture::TransitionUsageNow(VkCommandBuffer commands, dawn::TextureUsageBit usage) { + void Texture::TransitionUsageNow(CommandRecordingContext* recordingContext, + dawn::TextureUsage usage) { // Avoid encoding barriers when it isn't needed. bool lastReadOnly = (mLastUsage & kReadOnlyTextureUsages) == mLastUsage; - if (lastReadOnly && mLastUsage == usage) { + if (lastReadOnly && mLastUsage == usage && mLastExternalState == mExternalState) { return; } @@ -513,8 +604,6 @@ namespace dawn_native { namespace vulkan { barrier.dstAccessMask = VulkanAccessFlags(usage, format); barrier.oldLayout = VulkanImageLayout(mLastUsage, format); barrier.newLayout = VulkanImageLayout(usage, format); - barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; barrier.image = mHandle; // This transitions the whole resource but assumes it is a 2D texture ASSERT(GetDimension() == dawn::TextureDimension::e2D); @@ -524,48 +613,120 @@ namespace dawn_native { namespace vulkan { barrier.subresourceRange.baseArrayLayer = 0; barrier.subresourceRange.layerCount = GetArrayLayers(); + barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + + if (mExternalState == ExternalState::PendingAcquire) { + // Transfer texture from external queue to graphics queue + barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL_KHR; + barrier.dstQueueFamilyIndex = ToBackend(GetDevice())->GetGraphicsQueueFamily(); + // Don't override oldLayout to leave it as VK_IMAGE_LAYOUT_UNDEFINED + // TODO(http://crbug.com/dawn/200) + mExternalState = ExternalState::Acquired; + + } else if (mExternalState == ExternalState::PendingRelease) { + // Transfer texture from graphics queue to external queue + barrier.srcQueueFamilyIndex = ToBackend(GetDevice())->GetGraphicsQueueFamily(); + barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL_KHR; + barrier.newLayout = VK_IMAGE_LAYOUT_GENERAL; + mExternalState = ExternalState::Released; + } + + // Move required semaphores into waitSemaphores + recordingContext->waitSemaphores.insert(recordingContext->waitSemaphores.end(), + mWaitRequirements.begin(), mWaitRequirements.end()); + mWaitRequirements.clear(); + ToBackend(GetDevice()) - ->fn.CmdPipelineBarrier(commands, srcStages, dstStages, 0, 0, nullptr, 0, nullptr, 1, - &barrier); + ->fn.CmdPipelineBarrier(recordingContext->commandBuffer, srcStages, dstStages, 0, 0, + nullptr, 0, nullptr, 1, &barrier); mLastUsage = usage; + mLastExternalState = mExternalState; } - void Texture::ClearTexture(VkCommandBuffer commands, - uint32_t baseMipLevel, - uint32_t levelCount, - uint32_t baseArrayLayer, - uint32_t layerCount) { + MaybeError Texture::ClearTexture(CommandRecordingContext* recordingContext, + uint32_t baseMipLevel, + uint32_t levelCount, + uint32_t baseArrayLayer, + uint32_t layerCount, + TextureBase::ClearValue clearValue) { + Device* device = ToBackend(GetDevice()); VkImageSubresourceRange range = {}; range.aspectMask = GetVkAspectMask(); range.baseMipLevel = baseMipLevel; range.levelCount = levelCount; range.baseArrayLayer = baseArrayLayer; range.layerCount = layerCount; + uint8_t clearColor = (clearValue == TextureBase::ClearValue::Zero) ? 0 : 1; - TransitionUsageNow(commands, dawn::TextureUsageBit::CopyDst); - if (GetFormat().HasDepthOrStencil()) { - VkClearDepthStencilValue clear_color[1]; - clear_color[0].depth = 0.0f; - clear_color[0].stencil = 0u; - ToBackend(GetDevice()) - ->fn.CmdClearDepthStencilImage(commands, GetHandle(), - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, clear_color, 1, - &range); + TransitionUsageNow(recordingContext, dawn::TextureUsage::CopyDst); + if (GetFormat().isRenderable) { + if (GetFormat().HasDepthOrStencil()) { + VkClearDepthStencilValue clearDepthStencilValue[1]; + clearDepthStencilValue[0].depth = clearColor; + clearDepthStencilValue[0].stencil = clearColor; + device->fn.CmdClearDepthStencilImage(recordingContext->commandBuffer, GetHandle(), + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + clearDepthStencilValue, 1, &range); + } else { + VkClearColorValue clearColorValue = { + {clearColor, clearColor, clearColor, clearColor}}; + device->fn.CmdClearColorImage(recordingContext->commandBuffer, GetHandle(), + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + &clearColorValue, 1, &range); + } } else { - VkClearColorValue clear_color[1]; - clear_color[0].float32[0] = 0.0f; - clear_color[0].float32[1] = 0.0f; - clear_color[0].float32[2] = 0.0f; - clear_color[0].float32[3] = 0.0f; - ToBackend(GetDevice()) - ->fn.CmdClearColorImage(commands, GetHandle(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - clear_color, 1, &range); - } - SetIsSubresourceContentInitialized(baseMipLevel, levelCount, baseArrayLayer, layerCount); + // TODO(natlee@microsoft.com): test compressed textures are cleared + // create temp buffer with clear color to copy to the texture image + uint32_t rowPitch = + Align((GetSize().width / GetFormat().blockWidth) * GetFormat().blockByteSize, + kTextureRowPitchAlignment); + uint64_t bufferSize64 = rowPitch * (GetSize().height / GetFormat().blockHeight); + if (bufferSize64 > std::numeric_limits<uint32_t>::max()) { + return DAWN_OUT_OF_MEMORY_ERROR("Unable to allocate buffer."); + } + uint32_t bufferSize = static_cast<uint32_t>(bufferSize64); + DynamicUploader* uploader = nullptr; + DAWN_TRY_ASSIGN(uploader, device->GetDynamicUploader()); + UploadHandle uploadHandle; + DAWN_TRY_ASSIGN(uploadHandle, uploader->Allocate(bufferSize)); + std::fill(reinterpret_cast<uint32_t*>(uploadHandle.mappedBuffer), + reinterpret_cast<uint32_t*>(uploadHandle.mappedBuffer + bufferSize), + clearColor); + + // compute the buffer image copy to set the clear region of entire texture + dawn_native::BufferCopy bufferCopy; + bufferCopy.imageHeight = 0; + bufferCopy.offset = uploadHandle.startOffset; + bufferCopy.rowPitch = rowPitch; + + dawn_native::TextureCopy textureCopy; + textureCopy.texture = this; + textureCopy.origin = {0, 0, 0}; + textureCopy.mipLevel = baseMipLevel; + textureCopy.arrayLayer = baseArrayLayer; + + Extent3D copySize = {GetSize().width, GetSize().height, 1}; + + VkBufferImageCopy region = + ComputeBufferImageCopyRegion(bufferCopy, textureCopy, copySize); + + // copy the clear buffer to the texture image + device->fn.CmdCopyBufferToImage( + recordingContext->commandBuffer, + ToBackend(uploadHandle.stagingBuffer)->GetBufferHandle(), GetHandle(), + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); + } + if (clearValue == TextureBase::ClearValue::Zero) { + SetIsSubresourceContentInitialized(baseMipLevel, levelCount, baseArrayLayer, + layerCount); + device->IncrementLazyClearCountForTesting(); + } + return {}; } - void Texture::EnsureSubresourceContentInitialized(VkCommandBuffer commands, + void Texture::EnsureSubresourceContentInitialized(CommandRecordingContext* recordingContext, uint32_t baseMipLevel, uint32_t levelCount, uint32_t baseArrayLayer, @@ -583,7 +744,9 @@ namespace dawn_native { namespace vulkan { // If subresource has not been initialized, clear it to black as it could contain dirty // bits from recycled memory - ClearTexture(commands, baseMipLevel, levelCount, baseArrayLayer, layerCount); + GetDevice()->ConsumedError(ClearTexture(recordingContext, baseMipLevel, levelCount, + baseArrayLayer, layerCount, + TextureBase::ClearValue::Zero)); } } diff --git a/chromium/third_party/dawn/src/dawn_native/vulkan/TextureVk.h b/chromium/third_party/dawn/src/dawn_native/vulkan/TextureVk.h index 41cdf6d30a0..5d049e8cf1d 100644 --- a/chromium/third_party/dawn/src/dawn_native/vulkan/TextureVk.h +++ b/chromium/third_party/dawn/src/dawn_native/vulkan/TextureVk.h @@ -18,18 +18,39 @@ #include "dawn_native/Texture.h" #include "common/vulkan_platform.h" +#include "dawn_native/vulkan/ExternalHandle.h" #include "dawn_native/vulkan/MemoryAllocator.h" namespace dawn_native { namespace vulkan { + struct CommandRecordingContext; + struct ExternalImageDescriptor; + VkFormat VulkanImageFormat(dawn::TextureFormat format); - VkImageUsageFlags VulkanImageUsage(dawn::TextureUsageBit usage, const Format& format); + VkImageUsageFlags VulkanImageUsage(dawn::TextureUsage usage, const Format& format); VkSampleCountFlagBits VulkanSampleCount(uint32_t sampleCount); + MaybeError ValidateVulkanImageCanBeWrapped(const DeviceBase* device, + const TextureDescriptor* descriptor); + class Texture : public TextureBase { public: + enum class ExternalState { + InternalOnly, + PendingAcquire, + Acquired, + PendingRelease, + Released + }; + Texture(Device* device, const TextureDescriptor* descriptor); Texture(Device* device, const TextureDescriptor* descriptor, VkImage nativeImage); + Texture(Device* device, + const ExternalImageDescriptor* descriptor, + const TextureDescriptor* textureDescriptor, + VkSemaphore signalSemaphore, + VkDeviceMemory externalMemoryAllocation, + std::vector<VkSemaphore> waitSemaphores); ~Texture(); VkImage GetHandle() const; @@ -38,27 +59,37 @@ namespace dawn_native { namespace vulkan { // Transitions the texture to be used as `usage`, recording any necessary barrier in // `commands`. // TODO(cwallez@chromium.org): coalesce barriers and do them early when possible. - void TransitionUsageNow(VkCommandBuffer commands, dawn::TextureUsageBit usage); - void EnsureSubresourceContentInitialized(VkCommandBuffer commands, + void TransitionUsageNow(CommandRecordingContext* recordingContext, + dawn::TextureUsage usage); + void EnsureSubresourceContentInitialized(CommandRecordingContext* recordingContext, uint32_t baseMipLevel, uint32_t levelCount, uint32_t baseArrayLayer, uint32_t layerCount); + MaybeError SignalAndDestroy(VkSemaphore* outSignalSemaphore); + private: void DestroyImpl() override; - void ClearTexture(VkCommandBuffer commands, - uint32_t baseMipLevel, - uint32_t levelCount, - uint32_t baseArrayLayer, - uint32_t layerCount); + MaybeError ClearTexture(CommandRecordingContext* recordingContext, + uint32_t baseMipLevel, + uint32_t levelCount, + uint32_t baseArrayLayer, + uint32_t layerCount, + TextureBase::ClearValue); VkImage mHandle = VK_NULL_HANDLE; DeviceMemoryAllocation mMemoryAllocation; + VkDeviceMemory mExternalAllocation = VK_NULL_HANDLE; + + ExternalState mExternalState = ExternalState::InternalOnly; + ExternalState mLastExternalState = ExternalState::InternalOnly; + VkSemaphore mSignalSemaphore = VK_NULL_HANDLE; + std::vector<VkSemaphore> mWaitRequirements; // A usage of none will make sure the texture is transitioned before its first use as // required by the spec. - dawn::TextureUsageBit mLastUsage = dawn::TextureUsageBit::None; + dawn::TextureUsage mLastUsage = dawn::TextureUsage::None; }; class TextureView : public TextureViewBase { diff --git a/chromium/third_party/dawn/src/dawn_native/vulkan/UtilsVulkan.cpp b/chromium/third_party/dawn/src/dawn_native/vulkan/UtilsVulkan.cpp index 723a6bb9c80..dd81f3fb5ce 100644 --- a/chromium/third_party/dawn/src/dawn_native/vulkan/UtilsVulkan.cpp +++ b/chromium/third_party/dawn/src/dawn_native/vulkan/UtilsVulkan.cpp @@ -15,6 +15,9 @@ #include "dawn_native/vulkan/UtilsVulkan.h" #include "common/Assert.h" +#include "dawn_native/Format.h" +#include "dawn_native/vulkan/Forward.h" +#include "dawn_native/vulkan/TextureVk.h" namespace dawn_native { namespace vulkan { @@ -41,4 +44,55 @@ namespace dawn_native { namespace vulkan { } } + // Vulkan SPEC requires the source/destination region specified by each element of + // pRegions must be a region that is contained within srcImage/dstImage. Here the size of + // the image refers to the virtual size, while Dawn validates texture copy extent with the + // physical size, so we need to re-calculate the texture copy extent to ensure it should fit + // in the virtual size of the subresource. + Extent3D ComputeTextureCopyExtent(const TextureCopy& textureCopy, const Extent3D& copySize) { + Extent3D validTextureCopyExtent = copySize; + const TextureBase* texture = textureCopy.texture.Get(); + Extent3D virtualSizeAtLevel = texture->GetMipLevelVirtualSize(textureCopy.mipLevel); + if (textureCopy.origin.x + copySize.width > virtualSizeAtLevel.width) { + ASSERT(texture->GetFormat().isCompressed); + validTextureCopyExtent.width = virtualSizeAtLevel.width - textureCopy.origin.x; + } + if (textureCopy.origin.y + copySize.height > virtualSizeAtLevel.height) { + ASSERT(texture->GetFormat().isCompressed); + validTextureCopyExtent.height = virtualSizeAtLevel.height - textureCopy.origin.y; + } + + return validTextureCopyExtent; + } + + VkBufferImageCopy ComputeBufferImageCopyRegion(const BufferCopy& bufferCopy, + const TextureCopy& textureCopy, + const Extent3D& copySize) { + const Texture* texture = ToBackend(textureCopy.texture.Get()); + + VkBufferImageCopy region; + + region.bufferOffset = bufferCopy.offset; + // In Vulkan the row length is in texels while it is in bytes for Dawn + const Format& format = texture->GetFormat(); + ASSERT(bufferCopy.rowPitch % format.blockByteSize == 0); + region.bufferRowLength = bufferCopy.rowPitch / format.blockByteSize * format.blockWidth; + region.bufferImageHeight = bufferCopy.imageHeight; + + region.imageSubresource.aspectMask = texture->GetVkAspectMask(); + region.imageSubresource.mipLevel = textureCopy.mipLevel; + region.imageSubresource.baseArrayLayer = textureCopy.arrayLayer; + region.imageSubresource.layerCount = 1; + + region.imageOffset.x = textureCopy.origin.x; + region.imageOffset.y = textureCopy.origin.y; + region.imageOffset.z = textureCopy.origin.z; + + Extent3D imageExtent = ComputeTextureCopyExtent(textureCopy, copySize); + region.imageExtent.width = imageExtent.width; + region.imageExtent.height = imageExtent.height; + region.imageExtent.depth = copySize.depth; + + return region; + } }} // namespace dawn_native::vulkan diff --git a/chromium/third_party/dawn/src/dawn_native/vulkan/UtilsVulkan.h b/chromium/third_party/dawn/src/dawn_native/vulkan/UtilsVulkan.h index 80fa2da0479..8f4b5acee94 100644 --- a/chromium/third_party/dawn/src/dawn_native/vulkan/UtilsVulkan.h +++ b/chromium/third_party/dawn/src/dawn_native/vulkan/UtilsVulkan.h @@ -16,12 +16,18 @@ #define DAWNNATIVE_VULKAN_UTILSVULKAN_H_ #include "common/vulkan_platform.h" +#include "dawn_native/Commands.h" #include "dawn_native/dawn_platform.h" namespace dawn_native { namespace vulkan { VkCompareOp ToVulkanCompareOp(dawn::CompareFunction op); + Extent3D ComputeTextureCopyExtent(const TextureCopy& textureCopy, const Extent3D& copySize); + VkBufferImageCopy ComputeBufferImageCopyRegion(const BufferCopy& bufferCopy, + const TextureCopy& textureCopy, + const Extent3D& copySize); + }} // namespace dawn_native::vulkan #endif // DAWNNATIVE_VULKAN_UTILSVULKAN_H_ diff --git a/chromium/third_party/dawn/src/dawn_native/vulkan/VulkanBackend.cpp b/chromium/third_party/dawn/src/dawn_native/vulkan/VulkanBackend.cpp index acc624a618a..60eda449326 100644 --- a/chromium/third_party/dawn/src/dawn_native/vulkan/VulkanBackend.cpp +++ b/chromium/third_party/dawn/src/dawn_native/vulkan/VulkanBackend.cpp @@ -24,6 +24,7 @@ #include "common/SwapChainUtils.h" #include "dawn_native/vulkan/DeviceVk.h" #include "dawn_native/vulkan/NativeSwapChainImplVk.h" +#include "dawn_native/vulkan/TextureVk.h" namespace dawn_native { namespace vulkan { @@ -41,7 +42,7 @@ namespace dawn_native { namespace vulkan { DawnSwapChainImplementation impl; impl = CreateSwapChainImplementation(new NativeSwapChainImpl(backendDevice, surface)); - impl.textureUsage = DAWN_TEXTURE_USAGE_BIT_PRESENT; + impl.textureUsage = DAWN_TEXTURE_USAGE_PRESENT; return impl; } @@ -52,4 +53,32 @@ namespace dawn_native { namespace vulkan { return static_cast<DawnTextureFormat>(impl->GetPreferredFormat()); } +#ifdef DAWN_PLATFORM_LINUX + DawnTexture WrapVulkanImageOpaqueFD(DawnDevice cDevice, + const ExternalImageDescriptorOpaqueFD* descriptor) { + Device* device = reinterpret_cast<Device*>(cDevice); + + TextureBase* texture = device->CreateTextureWrappingVulkanImage( + descriptor, descriptor->memoryFD, descriptor->waitFDs); + + return reinterpret_cast<DawnTexture>(texture); + } + + int ExportSignalSemaphoreOpaqueFD(DawnDevice cDevice, DawnTexture cTexture) { + Device* device = reinterpret_cast<Device*>(cDevice); + Texture* texture = reinterpret_cast<Texture*>(cTexture); + + if (!texture) { + return -1; + } + + ExternalSemaphoreHandle outHandle; + if (device->ConsumedError(device->SignalAndExportExternalTexture(texture, &outHandle))) { + return -1; + } + + return outHandle; + } +#endif + }} // namespace dawn_native::vulkan diff --git a/chromium/third_party/dawn/src/dawn_native/vulkan/VulkanError.cpp b/chromium/third_party/dawn/src/dawn_native/vulkan/VulkanError.cpp index a01475c23f4..543c9b0964c 100644 --- a/chromium/third_party/dawn/src/dawn_native/vulkan/VulkanError.cpp +++ b/chromium/third_party/dawn/src/dawn_native/vulkan/VulkanError.cpp @@ -67,7 +67,7 @@ namespace dawn_native { namespace vulkan { } std::string message = std::string(context) + " failed with " + VkResultAsString(result); - return DAWN_CONTEXT_LOST_ERROR(message); + return DAWN_DEVICE_LOST_ERROR(message); } }} // namespace dawn_native::vulkan diff --git a/chromium/third_party/dawn/src/dawn_native/vulkan/VulkanFunctions.cpp b/chromium/third_party/dawn/src/dawn_native/vulkan/VulkanFunctions.cpp index 771c5d5f1fe..0d36776b73a 100644 --- a/chromium/third_party/dawn/src/dawn_native/vulkan/VulkanFunctions.cpp +++ b/chromium/third_party/dawn/src/dawn_native/vulkan/VulkanFunctions.cpp @@ -22,29 +22,33 @@ namespace dawn_native { namespace vulkan { #define GET_GLOBAL_PROC(name) \ name = reinterpret_cast<decltype(name)>(GetInstanceProcAddr(nullptr, "vk" #name)); \ if (name == nullptr) { \ - return DAWN_CONTEXT_LOST_ERROR(std::string("Couldn't get proc vk") + #name); \ + return DAWN_DEVICE_LOST_ERROR(std::string("Couldn't get proc vk") + #name); \ } MaybeError VulkanFunctions::LoadGlobalProcs(const DynamicLib& vulkanLib) { if (!vulkanLib.GetProc(&GetInstanceProcAddr, "vkGetInstanceProcAddr")) { - return DAWN_CONTEXT_LOST_ERROR("Couldn't get vkGetInstanceProcAddr"); + return DAWN_DEVICE_LOST_ERROR("Couldn't get vkGetInstanceProcAddr"); } GET_GLOBAL_PROC(CreateInstance); GET_GLOBAL_PROC(EnumerateInstanceExtensionProperties); GET_GLOBAL_PROC(EnumerateInstanceLayerProperties); + // Is not available in Vulkan 1.0, so allow nullptr + EnumerateInstanceVersion = reinterpret_cast<decltype(EnumerateInstanceVersion)>( + GetInstanceProcAddr(nullptr, "vkEnumerateInstanceVersion")); + return {}; } #define GET_INSTANCE_PROC(name) \ name = reinterpret_cast<decltype(name)>(GetInstanceProcAddr(instance, "vk" #name)); \ if (name == nullptr) { \ - return DAWN_CONTEXT_LOST_ERROR(std::string("Couldn't get proc vk") + #name); \ + return DAWN_DEVICE_LOST_ERROR(std::string("Couldn't get proc vk") + #name); \ } MaybeError VulkanFunctions::LoadInstanceProcs(VkInstance instance, - const VulkanGlobalKnobs& usedKnobs) { + const VulkanGlobalInfo& globalInfo) { // Load this proc first so that we can destroy the instance even if some other // GET_INSTANCE_PROC fails GET_INSTANCE_PROC(DestroyInstance); @@ -63,13 +67,35 @@ namespace dawn_native { namespace vulkan { GET_INSTANCE_PROC(GetPhysicalDeviceQueueFamilyProperties); GET_INSTANCE_PROC(GetPhysicalDeviceSparseImageFormatProperties); - if (usedKnobs.debugReport) { + if (globalInfo.debugReport) { GET_INSTANCE_PROC(CreateDebugReportCallbackEXT); GET_INSTANCE_PROC(DebugReportMessageEXT); GET_INSTANCE_PROC(DestroyDebugReportCallbackEXT); } - if (usedKnobs.surface) { + // Vulkan 1.1 is not required to report promoted extensions from 1.0 + if (globalInfo.externalMemoryCapabilities || + globalInfo.apiVersion >= VK_MAKE_VERSION(1, 1, 0)) { + GET_INSTANCE_PROC(GetPhysicalDeviceExternalBufferPropertiesKHR); + } + + if (globalInfo.externalSemaphoreCapabilities || + globalInfo.apiVersion >= VK_MAKE_VERSION(1, 1, 0)) { + GET_INSTANCE_PROC(GetPhysicalDeviceExternalSemaphorePropertiesKHR); + } + + if (globalInfo.getPhysicalDeviceProperties2 || + globalInfo.apiVersion >= VK_MAKE_VERSION(1, 1, 0)) { + GET_INSTANCE_PROC(GetPhysicalDeviceFeatures2KHR); + GET_INSTANCE_PROC(GetPhysicalDeviceProperties2KHR); + GET_INSTANCE_PROC(GetPhysicalDeviceFormatProperties2KHR); + GET_INSTANCE_PROC(GetPhysicalDeviceImageFormatProperties2KHR); + GET_INSTANCE_PROC(GetPhysicalDeviceQueueFamilyProperties2KHR); + GET_INSTANCE_PROC(GetPhysicalDeviceMemoryProperties2KHR); + GET_INSTANCE_PROC(GetPhysicalDeviceSparseImageFormatProperties2KHR); + } + + if (globalInfo.surface) { GET_INSTANCE_PROC(DestroySurfaceKHR); GET_INSTANCE_PROC(GetPhysicalDeviceSurfaceSupportKHR); GET_INSTANCE_PROC(GetPhysicalDeviceSurfaceCapabilitiesKHR); @@ -80,10 +106,10 @@ namespace dawn_native { namespace vulkan { return {}; } -#define GET_DEVICE_PROC(name) \ - name = reinterpret_cast<decltype(name)>(GetDeviceProcAddr(device, "vk" #name)); \ - if (name == nullptr) { \ - return DAWN_CONTEXT_LOST_ERROR(std::string("Couldn't get proc vk") + #name); \ +#define GET_DEVICE_PROC(name) \ + name = reinterpret_cast<decltype(name)>(GetDeviceProcAddr(device, "vk" #name)); \ + if (name == nullptr) { \ + return DAWN_DEVICE_LOST_ERROR(std::string("Couldn't get proc vk") + #name); \ } MaybeError VulkanFunctions::LoadDeviceProcs(VkDevice device, @@ -214,6 +240,16 @@ namespace dawn_native { namespace vulkan { GET_DEVICE_PROC(CmdDebugMarkerInsertEXT); } + if (usedKnobs.externalMemoryFD) { + GET_DEVICE_PROC(GetMemoryFdKHR); + GET_DEVICE_PROC(GetMemoryFdPropertiesKHR); + } + + if (usedKnobs.externalSemaphoreFD) { + GET_DEVICE_PROC(ImportSemaphoreFdKHR); + GET_DEVICE_PROC(GetSemaphoreFdKHR); + } + if (usedKnobs.swapchain) { GET_DEVICE_PROC(CreateSwapchainKHR); GET_DEVICE_PROC(DestroySwapchainKHR); diff --git a/chromium/third_party/dawn/src/dawn_native/vulkan/VulkanFunctions.h b/chromium/third_party/dawn/src/dawn_native/vulkan/VulkanFunctions.h index 6dcfe7e1356..b1f24f191f9 100644 --- a/chromium/third_party/dawn/src/dawn_native/vulkan/VulkanFunctions.h +++ b/chromium/third_party/dawn/src/dawn_native/vulkan/VulkanFunctions.h @@ -23,14 +23,14 @@ class DynamicLib; namespace dawn_native { namespace vulkan { - struct VulkanGlobalKnobs; + struct VulkanGlobalInfo; struct VulkanDeviceKnobs; // Stores the Vulkan entry points. Also loads them from the dynamic library // and the vkGet*ProcAddress entry points. struct VulkanFunctions { MaybeError LoadGlobalProcs(const DynamicLib& vulkanLib); - MaybeError LoadInstanceProcs(VkInstance instance, const VulkanGlobalKnobs& usedGlobals); + MaybeError LoadInstanceProcs(VkInstance instance, const VulkanGlobalInfo& globalInfo); MaybeError LoadDeviceProcs(VkDevice device, const VulkanDeviceKnobs& usedKnobs); // ---------- Global procs @@ -45,6 +45,9 @@ namespace dawn_native { namespace vulkan { // before querying the instance procs in case we need to error out during initialization. PFN_vkDestroyInstance DestroyInstance = nullptr; + // Core Vulkan 1.1 + PFN_vkEnumerateInstanceVersion EnumerateInstanceVersion = nullptr; + // ---------- Instance procs // Core Vulkan 1.0 @@ -81,6 +84,28 @@ namespace dawn_native { namespace vulkan { PFN_vkGetPhysicalDeviceSurfacePresentModesKHR GetPhysicalDeviceSurfacePresentModesKHR = nullptr; + // Core Vulkan 1.1 promoted extensions + + // VK_KHR_external_memory_capabilities + PFN_vkGetPhysicalDeviceExternalBufferPropertiesKHR + GetPhysicalDeviceExternalBufferPropertiesKHR = nullptr; + + // VK_KHR_external_semaphore_capabilities + PFN_vkGetPhysicalDeviceExternalSemaphorePropertiesKHR + GetPhysicalDeviceExternalSemaphorePropertiesKHR = nullptr; + + // VK_KHR_get_physical_device_properties2 + PFN_vkGetPhysicalDeviceFeatures2KHR GetPhysicalDeviceFeatures2KHR = nullptr; + PFN_vkGetPhysicalDeviceProperties2KHR GetPhysicalDeviceProperties2KHR = nullptr; + PFN_vkGetPhysicalDeviceFormatProperties2KHR GetPhysicalDeviceFormatProperties2KHR = nullptr; + PFN_vkGetPhysicalDeviceImageFormatProperties2KHR + GetPhysicalDeviceImageFormatProperties2KHR = nullptr; + PFN_vkGetPhysicalDeviceQueueFamilyProperties2KHR + GetPhysicalDeviceQueueFamilyProperties2KHR = nullptr; + PFN_vkGetPhysicalDeviceMemoryProperties2KHR GetPhysicalDeviceMemoryProperties2KHR = nullptr; + PFN_vkGetPhysicalDeviceSparseImageFormatProperties2KHR + GetPhysicalDeviceSparseImageFormatProperties2KHR = nullptr; + // ---------- Device procs // Core Vulkan 1.0 @@ -215,6 +240,14 @@ namespace dawn_native { namespace vulkan { PFN_vkGetSwapchainImagesKHR GetSwapchainImagesKHR = nullptr; PFN_vkAcquireNextImageKHR AcquireNextImageKHR = nullptr; PFN_vkQueuePresentKHR QueuePresentKHR = nullptr; + + // VK_KHR_external_memory_fd + PFN_vkGetMemoryFdKHR GetMemoryFdKHR = nullptr; + PFN_vkGetMemoryFdPropertiesKHR GetMemoryFdPropertiesKHR = nullptr; + + // VK_KHR_external_semaphore_fd + PFN_vkImportSemaphoreFdKHR ImportSemaphoreFdKHR = nullptr; + PFN_vkGetSemaphoreFdKHR GetSemaphoreFdKHR = nullptr; }; }} // namespace dawn_native::vulkan diff --git a/chromium/third_party/dawn/src/dawn_native/vulkan/VulkanInfo.cpp b/chromium/third_party/dawn/src/dawn_native/vulkan/VulkanInfo.cpp index 747202aae0d..f4f0284154f 100644 --- a/chromium/third_party/dawn/src/dawn_native/vulkan/VulkanInfo.cpp +++ b/chromium/third_party/dawn/src/dawn_native/vulkan/VulkanInfo.cpp @@ -38,6 +38,16 @@ namespace dawn_native { namespace vulkan { const char kExtensionNameExtDebugMarker[] = "VK_EXT_debug_marker"; const char kExtensionNameExtDebugReport[] = "VK_EXT_debug_report"; const char kExtensionNameMvkMacosSurface[] = "VK_MVK_macos_surface"; + const char kExtensionNameKhrExternalMemory[] = "VK_KHR_external_memory"; + const char kExtensionNameKhrExternalMemoryCapabilities[] = + "VK_KHR_external_memory_capabilities"; + const char kExtensionNameKhrExternalMemoryFD[] = "VK_KHR_external_memory_fd"; + const char kExtensionNameKhrExternalSemaphore[] = "VK_KHR_external_semaphore"; + const char kExtensionNameKhrExternalSemaphoreCapabilities[] = + "VK_KHR_external_semaphore_capabilities"; + const char kExtensionNameKhrExternalSemaphoreFD[] = "VK_KHR_external_semaphore_fd"; + const char kExtensionNameKhrGetPhysicalDeviceProperties2[] = + "VK_KHR_get_physical_device_properties2"; const char kExtensionNameKhrSurface[] = "VK_KHR_surface"; const char kExtensionNameKhrSwapchain[] = "VK_KHR_swapchain"; const char kExtensionNameKhrWaylandSurface[] = "VK_KHR_wayland_surface"; @@ -57,13 +67,13 @@ namespace dawn_native { namespace vulkan { // incomplete otherwise. This means that both values represent a success. // This is the same for all Enumarte functions if (result != VK_SUCCESS && result != VK_INCOMPLETE) { - return DAWN_CONTEXT_LOST_ERROR("vkEnumerateInstanceLayerProperties"); + return DAWN_DEVICE_LOST_ERROR("vkEnumerateInstanceLayerProperties"); } info.layers.resize(count); result = vkFunctions.EnumerateInstanceLayerProperties(&count, info.layers.data()); if (result != VK_SUCCESS) { - return DAWN_CONTEXT_LOST_ERROR("vkEnumerateInstanceLayerProperties"); + return DAWN_DEVICE_LOST_ERROR("vkEnumerateInstanceLayerProperties"); } for (const auto& layer : info.layers) { @@ -85,14 +95,14 @@ namespace dawn_native { namespace vulkan { VkResult result = vkFunctions.EnumerateInstanceExtensionProperties(nullptr, &count, nullptr); if (result != VK_SUCCESS && result != VK_INCOMPLETE) { - return DAWN_CONTEXT_LOST_ERROR("vkEnumerateInstanceExtensionProperties"); + return DAWN_DEVICE_LOST_ERROR("vkEnumerateInstanceExtensionProperties"); } info.extensions.resize(count); result = vkFunctions.EnumerateInstanceExtensionProperties(nullptr, &count, info.extensions.data()); if (result != VK_SUCCESS) { - return DAWN_CONTEXT_LOST_ERROR("vkEnumerateInstanceExtensionProperties"); + return DAWN_DEVICE_LOST_ERROR("vkEnumerateInstanceExtensionProperties"); } for (const auto& extension : info.extensions) { @@ -102,6 +112,15 @@ namespace dawn_native { namespace vulkan { if (IsExtensionName(extension, kExtensionNameMvkMacosSurface)) { info.macosSurface = true; } + if (IsExtensionName(extension, kExtensionNameKhrExternalMemoryCapabilities)) { + info.externalMemoryCapabilities = true; + } + if (IsExtensionName(extension, kExtensionNameKhrExternalSemaphoreCapabilities)) { + info.externalSemaphoreCapabilities = true; + } + if (IsExtensionName(extension, kExtensionNameKhrGetPhysicalDeviceProperties2)) { + info.getPhysicalDeviceProperties2 = true; + } if (IsExtensionName(extension, kExtensionNameKhrSurface)) { info.surface = true; } @@ -120,6 +139,19 @@ namespace dawn_native { namespace vulkan { } } + // Gather info on available API version + { + uint32_t supportedAPIVersion = VK_MAKE_VERSION(1, 0, 0); + if (vkFunctions.EnumerateInstanceVersion) { + vkFunctions.EnumerateInstanceVersion(&supportedAPIVersion); + } + + // Use Vulkan 1.1 if it's available. + info.apiVersion = (supportedAPIVersion >= VK_MAKE_VERSION(1, 1, 0)) + ? VK_MAKE_VERSION(1, 1, 0) + : VK_MAKE_VERSION(1, 0, 0); + } + // TODO(cwallez@chromium:org): Each layer can expose additional extensions, query them? return info; @@ -132,13 +164,13 @@ namespace dawn_native { namespace vulkan { uint32_t count = 0; VkResult result = vkFunctions.EnumeratePhysicalDevices(instance, &count, nullptr); if (result != VK_SUCCESS && result != VK_INCOMPLETE) { - return DAWN_CONTEXT_LOST_ERROR("vkEnumeratePhysicalDevices"); + return DAWN_DEVICE_LOST_ERROR("vkEnumeratePhysicalDevices"); } std::vector<VkPhysicalDevice> physicalDevices(count); result = vkFunctions.EnumeratePhysicalDevices(instance, &count, physicalDevices.data()); if (result != VK_SUCCESS) { - return DAWN_CONTEXT_LOST_ERROR("vkEnumeratePhysicalDevices"); + return DAWN_DEVICE_LOST_ERROR("vkEnumeratePhysicalDevices"); } return physicalDevices; @@ -180,14 +212,14 @@ namespace dawn_native { namespace vulkan { VkResult result = vkFunctions.EnumerateDeviceLayerProperties(physicalDevice, &count, nullptr); if (result != VK_SUCCESS && result != VK_INCOMPLETE) { - return DAWN_CONTEXT_LOST_ERROR("vkEnumerateDeviceLayerProperties"); + return DAWN_DEVICE_LOST_ERROR("vkEnumerateDeviceLayerProperties"); } info.layers.resize(count); result = vkFunctions.EnumerateDeviceLayerProperties(physicalDevice, &count, info.layers.data()); if (result != VK_SUCCESS) { - return DAWN_CONTEXT_LOST_ERROR("vkEnumerateDeviceLayerProperties"); + return DAWN_DEVICE_LOST_ERROR("vkEnumerateDeviceLayerProperties"); } } @@ -197,21 +229,32 @@ namespace dawn_native { namespace vulkan { VkResult result = vkFunctions.EnumerateDeviceExtensionProperties( physicalDevice, nullptr, &count, nullptr); if (result != VK_SUCCESS && result != VK_INCOMPLETE) { - return DAWN_CONTEXT_LOST_ERROR("vkEnumerateDeviceExtensionProperties"); + return DAWN_DEVICE_LOST_ERROR("vkEnumerateDeviceExtensionProperties"); } info.extensions.resize(count); result = vkFunctions.EnumerateDeviceExtensionProperties(physicalDevice, nullptr, &count, info.extensions.data()); if (result != VK_SUCCESS) { - return DAWN_CONTEXT_LOST_ERROR("vkEnumerateDeviceExtensionProperties"); + return DAWN_DEVICE_LOST_ERROR("vkEnumerateDeviceExtensionProperties"); } for (const auto& extension : info.extensions) { if (IsExtensionName(extension, kExtensionNameExtDebugMarker)) { info.debugMarker = true; } - + if (IsExtensionName(extension, kExtensionNameKhrExternalMemory)) { + info.externalMemory = true; + } + if (IsExtensionName(extension, kExtensionNameKhrExternalMemoryFD)) { + info.externalMemoryFD = true; + } + if (IsExtensionName(extension, kExtensionNameKhrExternalSemaphore)) { + info.externalSemaphore = true; + } + if (IsExtensionName(extension, kExtensionNameKhrExternalSemaphoreFD)) { + info.externalSemaphoreFD = true; + } if (IsExtensionName(extension, kExtensionNameKhrSwapchain)) { info.swapchain = true; } @@ -234,7 +277,7 @@ namespace dawn_native { namespace vulkan { VkResult result = vkFunctions.GetPhysicalDeviceSurfaceCapabilitiesKHR( physicalDevice, surface, &info->capabilities); if (result != VK_SUCCESS) { - return DAWN_CONTEXT_LOST_ERROR("vkGetPhysicalDeviceSurfaceCapabilitiesKHR"); + return DAWN_DEVICE_LOST_ERROR("vkGetPhysicalDeviceSurfaceCapabilitiesKHR"); } } @@ -249,7 +292,7 @@ namespace dawn_native { namespace vulkan { physicalDevice, i, surface, &supported); if (result != VK_SUCCESS) { - return DAWN_CONTEXT_LOST_ERROR("vkGetPhysicalDeviceSurfaceSupportKHR"); + return DAWN_DEVICE_LOST_ERROR("vkGetPhysicalDeviceSurfaceSupportKHR"); } info->supportedQueueFamilies[i] = (supported == VK_TRUE); @@ -262,14 +305,14 @@ namespace dawn_native { namespace vulkan { VkResult result = vkFunctions.GetPhysicalDeviceSurfaceFormatsKHR( physicalDevice, surface, &count, nullptr); if (result != VK_SUCCESS && result != VK_INCOMPLETE) { - return DAWN_CONTEXT_LOST_ERROR("vkGetPhysicalDeviceSurfaceFormatsKHR"); + return DAWN_DEVICE_LOST_ERROR("vkGetPhysicalDeviceSurfaceFormatsKHR"); } info->formats.resize(count); result = vkFunctions.GetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &count, info->formats.data()); if (result != VK_SUCCESS) { - return DAWN_CONTEXT_LOST_ERROR("vkGetPhysicalDeviceSurfaceFormatsKHR"); + return DAWN_DEVICE_LOST_ERROR("vkGetPhysicalDeviceSurfaceFormatsKHR"); } } @@ -279,14 +322,14 @@ namespace dawn_native { namespace vulkan { VkResult result = vkFunctions.GetPhysicalDeviceSurfacePresentModesKHR( physicalDevice, surface, &count, nullptr); if (result != VK_SUCCESS && result != VK_INCOMPLETE) { - return DAWN_CONTEXT_LOST_ERROR("vkGetPhysicalDeviceSurfacePresentModesKHR"); + return DAWN_DEVICE_LOST_ERROR("vkGetPhysicalDeviceSurfacePresentModesKHR"); } info->presentModes.resize(count); result = vkFunctions.GetPhysicalDeviceSurfacePresentModesKHR( physicalDevice, surface, &count, info->presentModes.data()); if (result != VK_SUCCESS) { - return DAWN_CONTEXT_LOST_ERROR("vkGetPhysicalDeviceSurfacePresentModesKHR"); + return DAWN_DEVICE_LOST_ERROR("vkGetPhysicalDeviceSurfacePresentModesKHR"); } } diff --git a/chromium/third_party/dawn/src/dawn_native/vulkan/VulkanInfo.h b/chromium/third_party/dawn/src/dawn_native/vulkan/VulkanInfo.h index 4425de5148d..48bcd9a3dec 100644 --- a/chromium/third_party/dawn/src/dawn_native/vulkan/VulkanInfo.h +++ b/chromium/third_party/dawn/src/dawn_native/vulkan/VulkanInfo.h @@ -32,6 +32,13 @@ namespace dawn_native { namespace vulkan { extern const char kExtensionNameExtDebugMarker[]; extern const char kExtensionNameExtDebugReport[]; extern const char kExtensionNameMvkMacosSurface[]; + extern const char kExtensionNameKhrExternalMemory[]; + extern const char kExtensionNameKhrExternalMemoryCapabilities[]; + extern const char kExtensionNameKhrExternalMemoryFD[]; + extern const char kExtensionNameKhrExternalSemaphore[]; + extern const char kExtensionNameKhrExternalSemaphoreCapabilities[]; + extern const char kExtensionNameKhrExternalSemaphoreFD[]; + extern const char kExtensionNameKhrGetPhysicalDeviceProperties2[]; extern const char kExtensionNameKhrSurface[]; extern const char kExtensionNameKhrSwapchain[]; extern const char kExtensionNameKhrWaylandSurface[]; @@ -48,6 +55,9 @@ namespace dawn_native { namespace vulkan { // Extensions bool debugReport = false; + bool externalMemoryCapabilities = false; + bool externalSemaphoreCapabilities = false; + bool getPhysicalDeviceProperties2 = false; bool macosSurface = false; bool surface = false; bool waylandSurface = false; @@ -59,6 +69,7 @@ namespace dawn_native { namespace vulkan { struct VulkanGlobalInfo : VulkanGlobalKnobs { std::vector<VkLayerProperties> layers; std::vector<VkExtensionProperties> extensions; + uint32_t apiVersion; // TODO(cwallez@chromium.org): layer instance extensions }; @@ -68,6 +79,10 @@ namespace dawn_native { namespace vulkan { // Extensions bool debugMarker = false; + bool externalMemory = false; + bool externalMemoryFD = false; + bool externalSemaphore = false; + bool externalSemaphoreFD = false; bool swapchain = false; }; diff --git a/chromium/third_party/dawn/src/dawn_native/vulkan/external_memory/MemoryService.h b/chromium/third_party/dawn/src/dawn_native/vulkan/external_memory/MemoryService.h new file mode 100644 index 00000000000..e49d3ff8a2b --- /dev/null +++ b/chromium/third_party/dawn/src/dawn_native/vulkan/external_memory/MemoryService.h @@ -0,0 +1,54 @@ +// Copyright 2019 The Dawn Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef DAWNNATIVE_VULKAN_EXTERNALMEMORY_SERVICE_H_ +#define DAWNNATIVE_VULKAN_EXTERNALMEMORY_SERVICE_H_ + +#include "common/vulkan_platform.h" +#include "dawn_native/Error.h" +#include "dawn_native/vulkan/ExternalHandle.h" + +namespace dawn_native { namespace vulkan { + class Device; +}} // namespace dawn_native::vulkan + +namespace dawn_native { namespace vulkan { namespace external_memory { + + class Service { + public: + explicit Service(Device* device); + ~Service(); + + // True if the device reports it supports this feature + bool Supported(VkFormat format, + VkImageType type, + VkImageTiling tiling, + VkImageUsageFlags usage, + VkImageCreateFlags flags); + + // Given an external handle pointing to memory, import it into a VkDeviceMemory + ResultOrError<VkDeviceMemory> ImportMemory(ExternalMemoryHandle handle, + VkDeviceSize allocationSize, + uint32_t memoryTypeIndex); + + private: + Device* mDevice = nullptr; + + // True if early checks pass that determine if the service is supported + bool mSupported = false; + }; + +}}} // namespace dawn_native::vulkan::external_memory + +#endif // DAWNNATIVE_VULKAN_EXTERNALMEMORY_SERVICE_H_ diff --git a/chromium/third_party/dawn/src/dawn_native/vulkan/external_memory/MemoryServiceNull.cpp b/chromium/third_party/dawn/src/dawn_native/vulkan/external_memory/MemoryServiceNull.cpp new file mode 100644 index 00000000000..7804ad3623a --- /dev/null +++ b/chromium/third_party/dawn/src/dawn_native/vulkan/external_memory/MemoryServiceNull.cpp @@ -0,0 +1,41 @@ +// Copyright 2019 The Dawn Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "dawn_native/vulkan/DeviceVk.h" +#include "dawn_native/vulkan/external_memory/MemoryService.h" + +namespace dawn_native { namespace vulkan { namespace external_memory { + + Service::Service(Device* device) : mDevice(device) { + DAWN_UNUSED(mDevice); + DAWN_UNUSED(mSupported); + } + + Service::~Service() = default; + + bool Service::Supported(VkFormat format, + VkImageType type, + VkImageTiling tiling, + VkImageUsageFlags usage, + VkImageCreateFlags flags) { + return false; + } + + ResultOrError<VkDeviceMemory> Service::ImportMemory(ExternalMemoryHandle handle, + VkDeviceSize allocationSize, + uint32_t memoryTypeIndex) { + return DAWN_UNIMPLEMENTED_ERROR("Using null semaphore service to interop inside Vulkan"); + } + +}}} // namespace dawn_native::vulkan::external_memory diff --git a/chromium/third_party/dawn/src/dawn_native/vulkan/external_memory/MemoryServiceOpaqueFD.cpp b/chromium/third_party/dawn/src/dawn_native/vulkan/external_memory/MemoryServiceOpaqueFD.cpp new file mode 100644 index 00000000000..d6e0e5a0fa7 --- /dev/null +++ b/chromium/third_party/dawn/src/dawn_native/vulkan/external_memory/MemoryServiceOpaqueFD.cpp @@ -0,0 +1,108 @@ +// Copyright 2019 The Dawn Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "dawn_native/vulkan/AdapterVk.h" +#include "dawn_native/vulkan/BackendVk.h" +#include "dawn_native/vulkan/DeviceVk.h" +#include "dawn_native/vulkan/VulkanError.h" +#include "dawn_native/vulkan/external_memory/MemoryService.h" + +namespace dawn_native { namespace vulkan { namespace external_memory { + + Service::Service(Device* device) : mDevice(device) { + const VulkanDeviceInfo& deviceInfo = mDevice->GetDeviceInfo(); + const VulkanGlobalInfo& globalInfo = + ToBackend(mDevice->GetAdapter())->GetBackend()->GetGlobalInfo(); + + mSupported = globalInfo.getPhysicalDeviceProperties2 && + globalInfo.externalMemoryCapabilities && deviceInfo.externalMemory && + deviceInfo.externalMemoryFD; + } + + Service::~Service() = default; + + bool Service::Supported(VkFormat format, + VkImageType type, + VkImageTiling tiling, + VkImageUsageFlags usage, + VkImageCreateFlags flags) { + // Early out before we try using extension functions + if (!mSupported) { + return false; + } + + VkPhysicalDeviceExternalImageFormatInfo externalFormatInfo; + externalFormatInfo.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO_KHR; + externalFormatInfo.pNext = nullptr; + externalFormatInfo.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR; + + VkPhysicalDeviceImageFormatInfo2 formatInfo; + formatInfo.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2_KHR; + formatInfo.pNext = &externalFormatInfo; + formatInfo.format = format; + formatInfo.type = type; + formatInfo.tiling = tiling; + formatInfo.usage = usage; + formatInfo.flags = flags; + + VkExternalImageFormatProperties externalFormatProperties; + externalFormatProperties.sType = VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES_KHR; + externalFormatProperties.pNext = nullptr; + + VkImageFormatProperties2 formatProperties; + formatProperties.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2_KHR; + formatProperties.pNext = &externalFormatProperties; + + VkResult result = mDevice->fn.GetPhysicalDeviceImageFormatProperties2KHR( + ToBackend(mDevice->GetAdapter())->GetPhysicalDevice(), &formatInfo, &formatProperties); + + // If handle not supported, result == VK_ERROR_FORMAT_NOT_SUPPORTED + if (result != VK_SUCCESS) { + return false; + } + + // TODO(http://crbug.com/dawn/206): Investigate dedicated only images + VkFlags memoryFlags = + externalFormatProperties.externalMemoryProperties.externalMemoryFeatures; + return (memoryFlags & VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_KHR) && + !(memoryFlags & VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT_KHR); + } + + ResultOrError<VkDeviceMemory> Service::ImportMemory(ExternalMemoryHandle handle, + VkDeviceSize allocationSize, + uint32_t memoryTypeIndex) { + if (handle < 0) { + return DAWN_VALIDATION_ERROR("Trying to import memory with invalid handle"); + } + + VkImportMemoryFdInfoKHR importMemoryFdInfo; + importMemoryFdInfo.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR; + importMemoryFdInfo.pNext = nullptr; + importMemoryFdInfo.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR; + importMemoryFdInfo.fd = handle; + + VkMemoryAllocateInfo allocateInfo; + allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + allocateInfo.pNext = &importMemoryFdInfo; + allocateInfo.allocationSize = allocationSize; + allocateInfo.memoryTypeIndex = memoryTypeIndex; + + VkDeviceMemory allocatedMemory = VK_NULL_HANDLE; + DAWN_TRY(CheckVkSuccess(mDevice->fn.AllocateMemory(mDevice->GetVkDevice(), &allocateInfo, + nullptr, &allocatedMemory), + "vkAllocateMemory")); + return allocatedMemory; + } + +}}} // namespace dawn_native::vulkan::external_memory diff --git a/chromium/third_party/dawn/src/dawn_native/vulkan/external_semaphore/SemaphoreService.h b/chromium/third_party/dawn/src/dawn_native/vulkan/external_semaphore/SemaphoreService.h new file mode 100644 index 00000000000..cceaa2da5e7 --- /dev/null +++ b/chromium/third_party/dawn/src/dawn_native/vulkan/external_semaphore/SemaphoreService.h @@ -0,0 +1,54 @@ +// Copyright 2019 The Dawn Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef DAWNNATIVE_VULKAN_EXTERNALSEMAPHORE_SERVICE_H_ +#define DAWNNATIVE_VULKAN_EXTERNALSEMAPHORE_SERVICE_H_ + +#include "common/vulkan_platform.h" +#include "dawn_native/Error.h" +#include "dawn_native/vulkan/ExternalHandle.h" + +namespace dawn_native { namespace vulkan { + class Device; +}} // namespace dawn_native::vulkan + +namespace dawn_native { namespace vulkan { namespace external_semaphore { + + class Service { + public: + explicit Service(Device* device); + ~Service(); + + // True if the device reports it supports this feature + bool Supported(); + + // Given an external handle, import it into a VkSemaphore + ResultOrError<VkSemaphore> ImportSemaphore(ExternalSemaphoreHandle handle); + + // Create a VkSemaphore that is exportable into an external handle later + ResultOrError<VkSemaphore> CreateExportableSemaphore(); + + // Export a VkSemaphore into an external handle + ResultOrError<ExternalSemaphoreHandle> ExportSemaphore(VkSemaphore semaphore); + + private: + Device* mDevice = nullptr; + + // True if early checks pass that determine if the service is supported + bool mSupported = false; + }; + +}}} // namespace dawn_native::vulkan::external_semaphore + +#endif // DAWNNATIVE_VULKAN_EXTERNALSEMAPHORE_SERVICE_H_ diff --git a/chromium/third_party/dawn/src/dawn_native/vulkan/external_semaphore/SemaphoreServiceNull.cpp b/chromium/third_party/dawn/src/dawn_native/vulkan/external_semaphore/SemaphoreServiceNull.cpp new file mode 100644 index 00000000000..aca4cb12682 --- /dev/null +++ b/chromium/third_party/dawn/src/dawn_native/vulkan/external_semaphore/SemaphoreServiceNull.cpp @@ -0,0 +1,43 @@ +// Copyright 2019 The Dawn Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "dawn_native/vulkan/DeviceVk.h" +#include "dawn_native/vulkan/external_semaphore/SemaphoreService.h" + +namespace dawn_native { namespace vulkan { namespace external_semaphore { + + Service::Service(Device* device) : mDevice(device) { + DAWN_UNUSED(mDevice); + DAWN_UNUSED(mSupported); + } + + Service::~Service() = default; + + bool Service::Supported() { + return false; + } + + ResultOrError<VkSemaphore> Service::ImportSemaphore(ExternalSemaphoreHandle handle) { + return DAWN_UNIMPLEMENTED_ERROR("Using null semaphore service to interop inside Vulkan"); + } + + ResultOrError<VkSemaphore> Service::CreateExportableSemaphore() { + return DAWN_UNIMPLEMENTED_ERROR("Using null semaphore service to interop inside Vulkan"); + } + + ResultOrError<ExternalSemaphoreHandle> Service::ExportSemaphore(VkSemaphore semaphore) { + return DAWN_UNIMPLEMENTED_ERROR("Using null semaphore service to interop inside Vulkan"); + } + +}}} // namespace dawn_native::vulkan::external_semaphore diff --git a/chromium/third_party/dawn/src/dawn_native/vulkan/external_semaphore/SemaphoreServiceOpaqueFD.cpp b/chromium/third_party/dawn/src/dawn_native/vulkan/external_semaphore/SemaphoreServiceOpaqueFD.cpp new file mode 100644 index 00000000000..ea7bf47d0f0 --- /dev/null +++ b/chromium/third_party/dawn/src/dawn_native/vulkan/external_semaphore/SemaphoreServiceOpaqueFD.cpp @@ -0,0 +1,133 @@ +// Copyright 2019 The Dawn Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "dawn_native/vulkan/AdapterVk.h" +#include "dawn_native/vulkan/BackendVk.h" +#include "dawn_native/vulkan/DeviceVk.h" +#include "dawn_native/vulkan/VulkanError.h" +#include "dawn_native/vulkan/external_semaphore/SemaphoreService.h" + +namespace dawn_native { namespace vulkan { namespace external_semaphore { + + Service::Service(Device* device) : mDevice(device) { + const VulkanDeviceInfo& deviceInfo = mDevice->GetDeviceInfo(); + const VulkanGlobalInfo& globalInfo = + ToBackend(mDevice->GetAdapter())->GetBackend()->GetGlobalInfo(); + + mSupported = globalInfo.getPhysicalDeviceProperties2 && + globalInfo.externalSemaphoreCapabilities && deviceInfo.externalSemaphore && + deviceInfo.externalSemaphoreFD; + + // Early out before we try using extension functions + if (!mSupported) { + return; + } + + VkPhysicalDeviceExternalSemaphoreInfoKHR semaphoreInfo; + semaphoreInfo.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO_KHR; + semaphoreInfo.pNext = nullptr; + semaphoreInfo.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR; + + VkExternalSemaphorePropertiesKHR semaphoreProperties; + semaphoreProperties.sType = VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES_KHR; + semaphoreProperties.pNext = nullptr; + + mDevice->fn.GetPhysicalDeviceExternalSemaphorePropertiesKHR( + ToBackend(mDevice->GetAdapter())->GetPhysicalDevice(), &semaphoreInfo, + &semaphoreProperties); + + VkFlags requiredFlags = VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT_KHR | + VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT_KHR; + mSupported = + mSupported && + ((semaphoreProperties.externalSemaphoreFeatures & requiredFlags) == requiredFlags); + } + + Service::~Service() = default; + + bool Service::Supported() { + return mSupported; + } + + ResultOrError<VkSemaphore> Service::ImportSemaphore(ExternalSemaphoreHandle handle) { + if (handle < 0) { + return DAWN_VALIDATION_ERROR("Trying to import semaphore with invalid handle"); + } + + VkSemaphore semaphore = VK_NULL_HANDLE; + VkSemaphoreCreateInfo info; + info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; + info.pNext = nullptr; + info.flags = 0; + + DAWN_TRY(CheckVkSuccess( + mDevice->fn.CreateSemaphore(mDevice->GetVkDevice(), &info, nullptr, &semaphore), + "vkCreateSemaphore")); + + VkImportSemaphoreFdInfoKHR importSemaphoreFdInfo; + importSemaphoreFdInfo.sType = VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR; + importSemaphoreFdInfo.pNext = nullptr; + importSemaphoreFdInfo.semaphore = semaphore; + importSemaphoreFdInfo.flags = 0; + importSemaphoreFdInfo.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR; + importSemaphoreFdInfo.fd = handle; + + MaybeError status = CheckVkSuccess( + mDevice->fn.ImportSemaphoreFdKHR(mDevice->GetVkDevice(), &importSemaphoreFdInfo), + "vkImportSemaphoreFdKHR"); + + if (status.IsError()) { + mDevice->fn.DestroySemaphore(mDevice->GetVkDevice(), semaphore, nullptr); + DAWN_TRY(std::move(status)); + } + + return semaphore; + } + + ResultOrError<VkSemaphore> Service::CreateExportableSemaphore() { + VkExportSemaphoreCreateInfoKHR exportSemaphoreInfo; + exportSemaphoreInfo.sType = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO_KHR; + exportSemaphoreInfo.pNext = nullptr; + exportSemaphoreInfo.handleTypes = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR; + + VkSemaphoreCreateInfo semaphoreCreateInfo; + semaphoreCreateInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; + semaphoreCreateInfo.pNext = &exportSemaphoreInfo; + semaphoreCreateInfo.flags = 0; + + VkSemaphore signalSemaphore; + DAWN_TRY( + CheckVkSuccess(mDevice->fn.CreateSemaphore(mDevice->GetVkDevice(), &semaphoreCreateInfo, + nullptr, &signalSemaphore), + "vkCreateSemaphore")); + return signalSemaphore; + } + + ResultOrError<ExternalSemaphoreHandle> Service::ExportSemaphore(VkSemaphore semaphore) { + VkSemaphoreGetFdInfoKHR semaphoreGetFdInfo; + semaphoreGetFdInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR; + semaphoreGetFdInfo.pNext = nullptr; + semaphoreGetFdInfo.semaphore = semaphore; + semaphoreGetFdInfo.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR; + + int fd = -1; + DAWN_TRY(CheckVkSuccess( + mDevice->fn.GetSemaphoreFdKHR(mDevice->GetVkDevice(), &semaphoreGetFdInfo, &fd), + "vkGetSemaphoreFdKHR")); + + ASSERT(fd >= 0); + return fd; + } + +}}} // namespace dawn_native::vulkan::external_semaphore |