Track depth/stencil aspects independently

This enables depth-stencil textures to track per aspect state
independently. It lifts the restriction that depth and stencil
store ops must be the same as they now have independent clear
states. It will also enable correct barriers on Vulkan and D3D12.

Bug: dawn:439
Change-Id: I8a73187df57a1d7eee6790cb4395bdecf42b63aa
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/26127
Reviewed-by: Jiawei Shao <jiawei.shao@intel.com>
Commit-Queue: Austin Eng <enga@chromium.org>
This commit is contained in:
Austin Eng 2020-08-06 17:00:29 +00:00 committed by Commit Bot service account
parent fa4b74d479
commit 2cf5a08cfc
30 changed files with 775 additions and 337 deletions

View File

@ -56,7 +56,7 @@ namespace dawn_native {
const Extent3D& copySize) { const Extent3D& copySize) {
switch (copy.texture->GetDimension()) { switch (copy.texture->GetDimension()) {
case wgpu::TextureDimension::e2D: case wgpu::TextureDimension::e2D:
return {copy.mipLevel, 1, copy.origin.z, copySize.depth}; return {copy.mipLevel, 1, copy.origin.z, copySize.depth, copy.aspect};
default: default:
UNREACHABLE(); UNREACHABLE();
return {}; return {};
@ -113,36 +113,31 @@ namespace dawn_native {
ASSERT(view->GetLevelCount() == 1); ASSERT(view->GetLevelCount() == 1);
SubresourceRange range = view->GetSubresourceRange(); SubresourceRange range = view->GetSubresourceRange();
SubresourceRange depthRange = range;
depthRange.aspects = range.aspects & Aspect::Depth;
SubresourceRange stencilRange = range;
stencilRange.aspects = range.aspects & Aspect::Stencil;
// If the depth stencil texture has not been initialized, we want to use loadop // If the depth stencil texture has not been initialized, we want to use loadop
// clear to init the contents to 0's // clear to init the contents to 0's
if (!view->GetTexture()->IsSubresourceContentInitialized(range)) { if (!view->GetTexture()->IsSubresourceContentInitialized(depthRange) &&
if (view->GetTexture()->GetFormat().HasDepth() && attachmentInfo.depthLoadOp == wgpu::LoadOp::Load) {
attachmentInfo.depthLoadOp == wgpu::LoadOp::Load) { attachmentInfo.clearDepth = 0.0f;
attachmentInfo.clearDepth = 0.0f; attachmentInfo.depthLoadOp = wgpu::LoadOp::Clear;
attachmentInfo.depthLoadOp = wgpu::LoadOp::Clear;
}
if (view->GetTexture()->GetFormat().HasStencil() &&
attachmentInfo.stencilLoadOp == wgpu::LoadOp::Load) {
attachmentInfo.clearStencil = 0u;
attachmentInfo.stencilLoadOp = wgpu::LoadOp::Clear;
}
} }
// If these have different store ops, make them both Store because we can't track if (!view->GetTexture()->IsSubresourceContentInitialized(stencilRange) &&
// initialized state separately yet. TODO(crbug.com/dawn/145) attachmentInfo.stencilLoadOp == wgpu::LoadOp::Load) {
if (attachmentInfo.depthStoreOp != attachmentInfo.stencilStoreOp) { attachmentInfo.clearStencil = 0u;
attachmentInfo.depthStoreOp = wgpu::StoreOp::Store; attachmentInfo.stencilLoadOp = wgpu::LoadOp::Clear;
attachmentInfo.stencilStoreOp = wgpu::StoreOp::Store;
} }
if (attachmentInfo.depthStoreOp == wgpu::StoreOp::Store && view->GetTexture()->SetIsSubresourceContentInitialized(
attachmentInfo.stencilStoreOp == wgpu::StoreOp::Store) { attachmentInfo.depthStoreOp == wgpu::StoreOp::Store, depthRange);
view->GetTexture()->SetIsSubresourceContentInitialized(true, range);
} else { view->GetTexture()->SetIsSubresourceContentInitialized(
ASSERT(attachmentInfo.depthStoreOp == wgpu::StoreOp::Clear && attachmentInfo.stencilStoreOp == wgpu::StoreOp::Store, stencilRange);
attachmentInfo.stencilStoreOp == wgpu::StoreOp::Clear);
view->GetTexture()->SetIsSubresourceContentInitialized(false, range);
}
} }
} }

View File

@ -384,12 +384,6 @@ namespace dawn_native {
return DAWN_VALIDATION_ERROR("Depth clear value cannot be NaN"); return DAWN_VALIDATION_ERROR("Depth clear value cannot be NaN");
} }
// This validates that the depth storeOp and stencil storeOps are the same
if (depthStencilAttachment->depthStoreOp != depthStencilAttachment->stencilStoreOp) {
return DAWN_VALIDATION_ERROR(
"The depth storeOp and stencil storeOp are not the same");
}
// *sampleCount == 0 must only happen when there is no color attachment. In that case we // *sampleCount == 0 must only happen when there is no color attachment. In that case we
// do not need to validate the sample count of the depth stencil attachment. // do not need to validate the sample count of the depth stencil attachment.
const uint32_t depthStencilSampleCount = attachment->GetTexture()->GetSampleCount(); const uint32_t depthStencilSampleCount = attachment->GetTexture()->GetSampleCount();
@ -732,7 +726,8 @@ namespace dawn_native {
copy->destination.texture = destination->texture; copy->destination.texture = destination->texture;
copy->destination.origin = destination->origin; copy->destination.origin = destination->origin;
copy->destination.mipLevel = destination->mipLevel; copy->destination.mipLevel = destination->mipLevel;
copy->destination.aspect = destination->aspect; copy->destination.aspect =
ConvertAspect(destination->texture->GetFormat(), destination->aspect);
copy->copySize = *copySize; copy->copySize = *copySize;
return {}; return {};
@ -795,7 +790,7 @@ namespace dawn_native {
copy->source.texture = source->texture; copy->source.texture = source->texture;
copy->source.origin = source->origin; copy->source.origin = source->origin;
copy->source.mipLevel = source->mipLevel; copy->source.mipLevel = source->mipLevel;
copy->source.aspect = source->aspect; copy->source.aspect = ConvertAspect(source->texture->GetFormat(), source->aspect);
copy->destination.buffer = destination->buffer; copy->destination.buffer = destination->buffer;
copy->destination.offset = destination->layout.offset; copy->destination.offset = destination->layout.offset;
copy->destination.bytesPerRow = bytesPerRow; copy->destination.bytesPerRow = bytesPerRow;
@ -844,11 +839,12 @@ namespace dawn_native {
copy->source.texture = source->texture; copy->source.texture = source->texture;
copy->source.origin = source->origin; copy->source.origin = source->origin;
copy->source.mipLevel = source->mipLevel; copy->source.mipLevel = source->mipLevel;
copy->source.aspect = source->aspect; copy->source.aspect = ConvertAspect(source->texture->GetFormat(), source->aspect);
copy->destination.texture = destination->texture; copy->destination.texture = destination->texture;
copy->destination.origin = destination->origin; copy->destination.origin = destination->origin;
copy->destination.mipLevel = destination->mipLevel; copy->destination.mipLevel = destination->mipLevel;
copy->destination.aspect = destination->aspect; copy->destination.aspect =
ConvertAspect(destination->texture->GetFormat(), destination->aspect);
copy->copySize = *copySize; copy->copySize = *copySize;
return {}; return {};

View File

@ -105,7 +105,7 @@ namespace dawn_native {
Ref<TextureBase> texture; Ref<TextureBase> texture;
uint32_t mipLevel; uint32_t mipLevel;
Origin3D origin; // Texels / array layer Origin3D origin; // Texels / array layer
wgpu::TextureAspect aspect; Aspect aspect;
}; };
struct CopyBufferToBufferCmd { struct CopyBufferToBufferCmd {

View File

@ -179,10 +179,13 @@ namespace dawn_native {
uint32_t baseMipLevel, uint32_t baseMipLevel,
uint32_t levelCount, uint32_t levelCount,
uint32_t baseArrayLayer, uint32_t baseArrayLayer,
uint32_t layerCount) { uint32_t layerCount,
WGPUTextureAspect aspect) {
dawn_native::TextureBase* textureBase = dawn_native::TextureBase* textureBase =
reinterpret_cast<dawn_native::TextureBase*>(texture); reinterpret_cast<dawn_native::TextureBase*>(texture);
SubresourceRange range = {baseMipLevel, levelCount, baseArrayLayer, layerCount}; SubresourceRange range = {
baseMipLevel, levelCount, baseArrayLayer, layerCount,
ConvertAspect(textureBase->GetFormat(), static_cast<wgpu::TextureAspect>(aspect))};
return textureBase->IsSubresourceContentInitialized(range); return textureBase->IsSubresourceContentInitialized(range);
} }

View File

@ -36,6 +36,13 @@ namespace dawn_native {
using wgpu::operator|=; using wgpu::operator|=;
using wgpu::operator^=; using wgpu::operator^=;
using wgpu::HasZeroOrOneBits;
template <typename T>
constexpr bool HasOneBit(T value) {
return HasZeroOrOneBits(value) && value != T(0);
}
} // namespace dawn_native } // namespace dawn_native
#endif // DAWNNATIVE_ENUMCLASSBITMASK_H_ #endif // DAWNNATIVE_ENUMCLASSBITMASK_H_

View File

@ -120,6 +120,36 @@ namespace dawn_native {
} }
} }
TexelBlockInfo Format::GetTexelBlockInfo(Aspect aspect) const {
ASSERT(HasOneBit(aspect));
ASSERT(aspects & aspect);
switch (aspect) {
case Aspect::Color:
ASSERT(aspects == aspect);
return *this;
case Aspect::Depth:
switch (format) {
case wgpu::TextureFormat::Depth32Float:
return *this;
default:
UNREACHABLE();
break;
}
case Aspect::Stencil:
switch (format) {
case wgpu::TextureFormat::Depth24PlusStencil8:
return {1, 1, 1};
default:
UNREACHABLE();
break;
}
break;
default:
UNREACHABLE();
break;
}
}
size_t Format::GetIndex() const { size_t Format::GetIndex() const {
return ComputeFormatIndex(format); return ComputeFormatIndex(format);
} }

View File

@ -67,6 +67,7 @@ namespace dawn_native {
bool HasComponentType(Type componentType) const; bool HasComponentType(Type componentType) const;
TexelBlockInfo GetTexelBlockInfo(wgpu::TextureAspect aspect) const; TexelBlockInfo GetTexelBlockInfo(wgpu::TextureAspect aspect) const;
TexelBlockInfo GetTexelBlockInfo(Aspect aspect) const;
// The index of the format in the list of all known formats: a unique number for each format // The index of the format in the list of all known formats: a unique number for each format
// in [0, kKnownFormatCount) // in [0, kKnownFormatCount)

View File

@ -15,6 +15,8 @@
#include "dawn_native/PassResourceUsageTracker.h" #include "dawn_native/PassResourceUsageTracker.h"
#include "dawn_native/Buffer.h" #include "dawn_native/Buffer.h"
#include "dawn_native/EnumMaskIterator.h"
#include "dawn_native/Format.h"
#include "dawn_native/Texture.h" #include "dawn_native/Texture.h"
namespace dawn_native { namespace dawn_native {
@ -30,10 +32,7 @@ namespace dawn_native {
void PassResourceUsageTracker::TextureViewUsedAs(TextureViewBase* view, void PassResourceUsageTracker::TextureViewUsedAs(TextureViewBase* view,
wgpu::TextureUsage usage) { wgpu::TextureUsage usage) {
TextureBase* texture = view->GetTexture(); TextureBase* texture = view->GetTexture();
uint32_t baseMipLevel = view->GetBaseMipLevel(); const SubresourceRange& range = view->GetSubresourceRange();
uint32_t levelCount = view->GetLevelCount();
uint32_t baseArrayLayer = view->GetBaseArrayLayer();
uint32_t layerCount = view->GetLayerCount();
// std::map's operator[] will create the key and return a PassTextureUsage with usage = 0 // std::map's operator[] will create the key and return a PassTextureUsage with usage = 0
// and an empty vector for subresourceUsages. // and an empty vector for subresourceUsages.
@ -42,20 +41,25 @@ namespace dawn_native {
// Set parameters for the whole texture // Set parameters for the whole texture
textureUsage.usage |= usage; textureUsage.usage |= usage;
uint32_t subresourceCount = texture->GetSubresourceCount(); textureUsage.sameUsagesAcrossSubresources &=
textureUsage.sameUsagesAcrossSubresources &= levelCount * layerCount == subresourceCount; (range.levelCount == texture->GetNumMipLevels() && //
range.layerCount == texture->GetArrayLayers() && //
range.aspects == texture->GetFormat().aspects);
// Set usages for subresources // Set usages for subresources
if (!textureUsage.subresourceUsages.size()) { if (!textureUsage.subresourceUsages.size()) {
textureUsage.subresourceUsages = textureUsage.subresourceUsages = std::vector<wgpu::TextureUsage>(
std::vector<wgpu::TextureUsage>(subresourceCount, wgpu::TextureUsage::None); texture->GetSubresourceCount(), wgpu::TextureUsage::None);
} }
for (uint32_t arrayLayer = baseArrayLayer; arrayLayer < baseArrayLayer + layerCount; for (Aspect aspect : IterateEnumMask(range.aspects)) {
++arrayLayer) { for (uint32_t arrayLayer = range.baseArrayLayer;
for (uint32_t mipLevel = baseMipLevel; mipLevel < baseMipLevel + levelCount; arrayLayer < range.baseArrayLayer + range.layerCount; ++arrayLayer) {
++mipLevel) { for (uint32_t mipLevel = range.baseMipLevel;
uint32_t subresourceIndex = texture->GetSubresourceIndex(mipLevel, arrayLayer); mipLevel < range.baseMipLevel + range.levelCount; ++mipLevel) {
textureUsage.subresourceUsages[subresourceIndex] |= usage; uint32_t subresourceIndex =
texture->GetSubresourceIndex(mipLevel, arrayLayer, aspect);
textureUsage.subresourceUsages[subresourceIndex] |= usage;
}
} }
} }
} }

View File

@ -20,6 +20,7 @@
#include "common/Constants.h" #include "common/Constants.h"
#include "common/Math.h" #include "common/Math.h"
#include "dawn_native/Device.h" #include "dawn_native/Device.h"
#include "dawn_native/EnumMaskIterator.h"
#include "dawn_native/PassResourceUsage.h" #include "dawn_native/PassResourceUsage.h"
#include "dawn_native/ValidationUtils_autogen.h" #include "dawn_native/ValidationUtils_autogen.h"
@ -200,6 +201,11 @@ namespace dawn_native {
return {}; return {};
} }
uint8_t GetPlaneIndex(Aspect aspect) {
ASSERT(HasOneBit(aspect));
return static_cast<uint8_t>(Log2(static_cast<uint32_t>(aspect)));
}
} // anonymous namespace } // anonymous namespace
MaybeError ValidateTextureDescriptor(const DeviceBase* device, MaybeError ValidateTextureDescriptor(const DeviceBase* device,
@ -357,10 +363,33 @@ namespace dawn_native {
} }
} }
Aspect ConvertSingleAspect(const Format& format, wgpu::TextureAspect aspect) {
Aspect aspectMask = ConvertAspect(format, aspect);
ASSERT(HasOneBit(aspectMask));
return aspectMask;
}
Aspect ConvertAspect(const Format& format, wgpu::TextureAspect aspect) {
switch (aspect) {
case wgpu::TextureAspect::All:
return format.aspects;
case wgpu::TextureAspect::DepthOnly:
ASSERT(format.aspects & Aspect::Depth);
return Aspect::Depth;
case wgpu::TextureAspect::StencilOnly:
ASSERT(format.aspects & Aspect::Stencil);
return Aspect::Stencil;
default:
UNREACHABLE();
break;
}
}
// static // static
SubresourceRange SubresourceRange::SingleSubresource(uint32_t baseMipLevel, SubresourceRange SubresourceRange::SingleMipAndLayer(uint32_t baseMipLevel,
uint32_t baseArrayLayer) { uint32_t baseArrayLayer,
return {baseMipLevel, 1, baseArrayLayer, 1}; Aspect aspects) {
return {baseMipLevel, 1, baseArrayLayer, 1, aspects};
} }
// TextureBase // TextureBase
@ -376,7 +405,13 @@ namespace dawn_native {
mSampleCount(descriptor->sampleCount), mSampleCount(descriptor->sampleCount),
mUsage(descriptor->usage), mUsage(descriptor->usage),
mState(state) { mState(state) {
uint32_t subresourceCount = GetSubresourceCount(); uint8_t planeIndex = 0;
for (Aspect aspect : IterateEnumMask(mFormat.aspects)) {
mPlaneIndices[GetPlaneIndex(aspect)] = planeIndex++;
}
uint32_t subresourceCount =
mMipLevelCount * mSize.depth * static_cast<uint32_t>(planeIndex);
mIsSubresourceContentInitializedAtIndex = std::vector<bool>(subresourceCount, false); mIsSubresourceContentInitializedAtIndex = std::vector<bool>(subresourceCount, false);
// Add readonly storage usage if the texture has a storage usage. The validation rules in // Add readonly storage usage if the texture has a storage usage. The validation rules in
@ -438,7 +473,7 @@ namespace dawn_native {
} }
SubresourceRange TextureBase::GetAllSubresources() const { SubresourceRange TextureBase::GetAllSubresources() const {
ASSERT(!IsError()); ASSERT(!IsError());
return {0, mMipLevelCount, 0, GetArrayLayers()}; return {0, mMipLevelCount, 0, GetArrayLayers(), mFormat.aspects};
} }
uint32_t TextureBase::GetSampleCount() const { uint32_t TextureBase::GetSampleCount() const {
ASSERT(!IsError()); ASSERT(!IsError());
@ -446,7 +481,7 @@ namespace dawn_native {
} }
uint32_t TextureBase::GetSubresourceCount() const { uint32_t TextureBase::GetSubresourceCount() const {
ASSERT(!IsError()); ASSERT(!IsError());
return mMipLevelCount * mSize.depth; return static_cast<uint32_t>(mIsSubresourceContentInitializedAtIndex.size());
} }
wgpu::TextureUsage TextureBase::GetUsage() const { wgpu::TextureUsage TextureBase::GetUsage() const {
ASSERT(!IsError()); ASSERT(!IsError());
@ -458,25 +493,32 @@ namespace dawn_native {
return mState; return mState;
} }
uint32_t TextureBase::GetSubresourceIndex(uint32_t mipLevel, uint32_t arraySlice) const { uint32_t TextureBase::GetSubresourceIndex(uint32_t mipLevel,
uint32_t arraySlice,
Aspect aspect) const {
ASSERT(arraySlice <= kMaxTexture2DArrayLayers); ASSERT(arraySlice <= kMaxTexture2DArrayLayers);
ASSERT(mipLevel <= kMaxTexture2DMipLevels); ASSERT(mipLevel <= kMaxTexture2DMipLevels);
ASSERT(HasOneBit(aspect));
static_assert(kMaxTexture2DMipLevels <= static_assert(kMaxTexture2DMipLevels <=
std::numeric_limits<uint32_t>::max() / kMaxTexture2DArrayLayers, std::numeric_limits<uint32_t>::max() / kMaxTexture2DArrayLayers,
"texture size overflows uint32_t"); "texture size overflows uint32_t");
return GetNumMipLevels() * arraySlice + mipLevel; return mipLevel +
GetNumMipLevels() *
(arraySlice + GetArrayLayers() * mPlaneIndices[GetPlaneIndex(aspect)]);
} }
bool TextureBase::IsSubresourceContentInitialized(const SubresourceRange& range) const { bool TextureBase::IsSubresourceContentInitialized(const SubresourceRange& range) const {
ASSERT(!IsError()); ASSERT(!IsError());
for (uint32_t arrayLayer = range.baseArrayLayer; for (Aspect aspect : IterateEnumMask(range.aspects)) {
arrayLayer < range.baseArrayLayer + range.layerCount; ++arrayLayer) { for (uint32_t arrayLayer = range.baseArrayLayer;
for (uint32_t mipLevel = range.baseMipLevel; arrayLayer < range.baseArrayLayer + range.layerCount; ++arrayLayer) {
mipLevel < range.baseMipLevel + range.levelCount; ++mipLevel) { for (uint32_t mipLevel = range.baseMipLevel;
uint32_t subresourceIndex = GetSubresourceIndex(mipLevel, arrayLayer); mipLevel < range.baseMipLevel + range.levelCount; ++mipLevel) {
ASSERT(subresourceIndex < mIsSubresourceContentInitializedAtIndex.size()); uint32_t subresourceIndex = GetSubresourceIndex(mipLevel, arrayLayer, aspect);
if (!mIsSubresourceContentInitializedAtIndex[subresourceIndex]) { ASSERT(subresourceIndex < mIsSubresourceContentInitializedAtIndex.size());
return false; if (!mIsSubresourceContentInitializedAtIndex[subresourceIndex]) {
return false;
}
} }
} }
} }
@ -486,13 +528,15 @@ namespace dawn_native {
void TextureBase::SetIsSubresourceContentInitialized(bool isInitialized, void TextureBase::SetIsSubresourceContentInitialized(bool isInitialized,
const SubresourceRange& range) { const SubresourceRange& range) {
ASSERT(!IsError()); ASSERT(!IsError());
for (uint32_t arrayLayer = range.baseArrayLayer; for (Aspect aspect : IterateEnumMask(range.aspects)) {
arrayLayer < range.baseArrayLayer + range.layerCount; ++arrayLayer) { for (uint32_t arrayLayer = range.baseArrayLayer;
for (uint32_t mipLevel = range.baseMipLevel; arrayLayer < range.baseArrayLayer + range.layerCount; ++arrayLayer) {
mipLevel < range.baseMipLevel + range.levelCount; ++mipLevel) { for (uint32_t mipLevel = range.baseMipLevel;
uint32_t subresourceIndex = GetSubresourceIndex(mipLevel, arrayLayer); mipLevel < range.baseMipLevel + range.levelCount; ++mipLevel) {
ASSERT(subresourceIndex < mIsSubresourceContentInitializedAtIndex.size()); uint32_t subresourceIndex = GetSubresourceIndex(mipLevel, arrayLayer, aspect);
mIsSubresourceContentInitializedAtIndex[subresourceIndex] = isInitialized; ASSERT(subresourceIndex < mIsSubresourceContentInitializedAtIndex.size());
mIsSubresourceContentInitializedAtIndex[subresourceIndex] = isInitialized;
}
} }
} }
} }
@ -588,7 +632,9 @@ namespace dawn_native {
mFormat(GetDevice()->GetValidInternalFormat(descriptor->format)), mFormat(GetDevice()->GetValidInternalFormat(descriptor->format)),
mDimension(descriptor->dimension), mDimension(descriptor->dimension),
mRange({descriptor->baseMipLevel, descriptor->mipLevelCount, descriptor->baseArrayLayer, mRange({descriptor->baseMipLevel, descriptor->mipLevelCount, descriptor->baseArrayLayer,
descriptor->arrayLayerCount}) { descriptor->arrayLayerCount, ConvertAspect(mFormat, mAspect)}) {
// TODO(crbug.com/dawn/439): Current validation only allows texture views with aspect "all".
ASSERT(mAspect == wgpu::TextureAspect::All);
} }
TextureViewBase::TextureViewBase(DeviceBase* device, ObjectBase::ErrorTag tag) TextureViewBase::TextureViewBase(DeviceBase* device, ObjectBase::ErrorTag tag)

View File

@ -15,6 +15,7 @@
#ifndef DAWNNATIVE_TEXTURE_H_ #ifndef DAWNNATIVE_TEXTURE_H_
#define DAWNNATIVE_TEXTURE_H_ #define DAWNNATIVE_TEXTURE_H_
#include "common/ityp_array.h"
#include "common/ityp_bitset.h" #include "common/ityp_bitset.h"
#include "dawn_native/EnumClassBitmasks.h" #include "dawn_native/EnumClassBitmasks.h"
#include "dawn_native/Error.h" #include "dawn_native/Error.h"
@ -27,7 +28,11 @@
namespace dawn_native { namespace dawn_native {
// Note: Subresource indices are computed by iterating the aspects in increasing order.
// D3D12 uses these directly, so the order much match D3D12's indices.
// - Depth/Stencil textures have Depth as Plane 0, and Stencil as Plane 1.
enum class Aspect : uint8_t { enum class Aspect : uint8_t {
None = 0x0,
Color = 0x1, Color = 0x1,
Depth = 0x2, Depth = 0x2,
Stencil = 0x4, Stencil = 0x4,
@ -73,13 +78,19 @@ namespace dawn_native {
wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::Storage | wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::Storage |
wgpu::TextureUsage::OutputAttachment; wgpu::TextureUsage::OutputAttachment;
Aspect ConvertSingleAspect(const Format& format, wgpu::TextureAspect aspect);
Aspect ConvertAspect(const Format& format, wgpu::TextureAspect aspect);
struct SubresourceRange { struct SubresourceRange {
uint32_t baseMipLevel; uint32_t baseMipLevel;
uint32_t levelCount; uint32_t levelCount;
uint32_t baseArrayLayer; uint32_t baseArrayLayer;
uint32_t layerCount; uint32_t layerCount;
Aspect aspects;
static SubresourceRange SingleSubresource(uint32_t baseMipLevel, uint32_t baseArrayLayer); static SubresourceRange SingleMipAndLayer(uint32_t baseMipLevel,
uint32_t baseArrayLayer,
Aspect aspects);
}; };
class TextureBase : public ObjectBase { class TextureBase : public ObjectBase {
@ -103,7 +114,7 @@ namespace dawn_native {
uint32_t GetSubresourceCount() const; uint32_t GetSubresourceCount() const;
wgpu::TextureUsage GetUsage() const; wgpu::TextureUsage GetUsage() const;
TextureState GetTextureState() const; TextureState GetTextureState() const;
uint32_t GetSubresourceIndex(uint32_t mipLevel, uint32_t arraySlice) const; uint32_t GetSubresourceIndex(uint32_t mipLevel, uint32_t arraySlice, Aspect aspect) const;
bool IsSubresourceContentInitialized(const SubresourceRange& range) const; bool IsSubresourceContentInitialized(const SubresourceRange& range) const;
void SetIsSubresourceContentInitialized(bool isInitialized, const SubresourceRange& range); void SetIsSubresourceContentInitialized(bool isInitialized, const SubresourceRange& range);
@ -145,6 +156,7 @@ namespace dawn_native {
// TODO(natlee@microsoft.com): Use a more optimized data structure to save space // TODO(natlee@microsoft.com): Use a more optimized data structure to save space
std::vector<bool> mIsSubresourceContentInitializedAtIndex; std::vector<bool> mIsSubresourceContentInitializedAtIndex;
std::array<uint8_t, EnumBitmaskSize<Aspect>::value> mPlaneIndices;
}; };
class TextureViewBase : public ObjectBase { class TextureViewBase : public ObjectBase {

View File

@ -19,6 +19,7 @@
#include "dawn_native/CommandEncoder.h" #include "dawn_native/CommandEncoder.h"
#include "dawn_native/CommandValidation.h" #include "dawn_native/CommandValidation.h"
#include "dawn_native/Commands.h" #include "dawn_native/Commands.h"
#include "dawn_native/EnumMaskIterator.h"
#include "dawn_native/RenderBundle.h" #include "dawn_native/RenderBundle.h"
#include "dawn_native/d3d12/BindGroupD3D12.h" #include "dawn_native/d3d12/BindGroupD3D12.h"
#include "dawn_native/d3d12/BindGroupLayoutD3D12.h" #include "dawn_native/d3d12/BindGroupLayoutD3D12.h"
@ -101,9 +102,11 @@ namespace dawn_native { namespace d3d12 {
uint64_t bufferBytesPerRow, uint64_t bufferBytesPerRow,
Texture* texture, Texture* texture,
uint32_t textureMiplevel, uint32_t textureMiplevel,
uint32_t textureSlice) { uint32_t textureSlice,
Aspect aspect) {
const D3D12_TEXTURE_COPY_LOCATION textureLocation = const D3D12_TEXTURE_COPY_LOCATION textureLocation =
ComputeTextureCopyLocationForTexture(texture, textureMiplevel, textureSlice); ComputeTextureCopyLocationForTexture(texture, textureMiplevel, textureSlice,
aspect);
const uint64_t offset = baseCopySplit.offset + baseOffset; const uint64_t offset = baseCopySplit.offset + baseOffset;
@ -132,9 +135,11 @@ namespace dawn_native { namespace d3d12 {
uint64_t bufferBytesPerRow, uint64_t bufferBytesPerRow,
Texture* texture, Texture* texture,
uint32_t textureMiplevel, uint32_t textureMiplevel,
uint32_t textureSlice) { uint32_t textureSlice,
Aspect aspect) {
const D3D12_TEXTURE_COPY_LOCATION textureLocation = const D3D12_TEXTURE_COPY_LOCATION textureLocation =
ComputeTextureCopyLocationForTexture(texture, textureMiplevel, textureSlice); ComputeTextureCopyLocationForTexture(texture, textureMiplevel, textureSlice,
aspect);
const uint64_t offset = baseCopySplit.offset + baseOffset; const uint64_t offset = baseCopySplit.offset + baseOffset;
@ -551,7 +556,8 @@ namespace dawn_native { namespace d3d12 {
ID3D12Resource* colorTextureHandle = colorTexture->GetD3D12Resource(); ID3D12Resource* colorTextureHandle = colorTexture->GetD3D12Resource();
ID3D12Resource* resolveTextureHandle = resolveTexture->GetD3D12Resource(); ID3D12Resource* resolveTextureHandle = resolveTexture->GetD3D12Resource();
const uint32_t resolveTextureSubresourceIndex = resolveTexture->GetSubresourceIndex( const uint32_t resolveTextureSubresourceIndex = resolveTexture->GetSubresourceIndex(
resolveTarget->GetBaseMipLevel(), resolveTarget->GetBaseArrayLayer()); resolveTarget->GetBaseMipLevel(), resolveTarget->GetBaseArrayLayer(),
Aspect::Color);
constexpr uint32_t kColorTextureSubresourceIndex = 0; constexpr uint32_t kColorTextureSubresourceIndex = 0;
commandContext->GetCommandList()->ResolveSubresource( commandContext->GetCommandList()->ResolveSubresource(
resolveTextureHandle, resolveTextureSubresourceIndex, colorTextureHandle, resolveTextureHandle, resolveTextureSubresourceIndex, colorTextureHandle,
@ -693,9 +699,9 @@ namespace dawn_native { namespace d3d12 {
DAWN_TRY(buffer->EnsureDataInitialized(commandContext)); DAWN_TRY(buffer->EnsureDataInitialized(commandContext));
ASSERT(texture->GetDimension() == wgpu::TextureDimension::e2D); ASSERT(texture->GetDimension() == wgpu::TextureDimension::e2D);
SubresourceRange subresources = {copy->destination.mipLevel, 1, SubresourceRange subresources =
copy->destination.origin.z, GetSubresourcesAffectedByCopy(copy->destination, copy->copySize);
copy->copySize.depth};
if (IsCompleteSubresourceCopiedTo(texture, copy->copySize, if (IsCompleteSubresourceCopiedTo(texture, copy->copySize,
copy->destination.mipLevel)) { copy->destination.mipLevel)) {
texture->SetIsSubresourceContentInitialized(true, subresources); texture->SetIsSubresourceContentInitialized(true, subresources);
@ -737,7 +743,7 @@ namespace dawn_native { namespace d3d12 {
RecordCopyBufferToTextureFromTextureCopySplit( RecordCopyBufferToTextureFromTextureCopySplit(
commandList, copySplitPerLayerBase, buffer, bufferOffsetForNextSlice, commandList, copySplitPerLayerBase, buffer, bufferOffsetForNextSlice,
copy->source.bytesPerRow, texture, copy->destination.mipLevel, copy->source.bytesPerRow, texture, copy->destination.mipLevel,
copyTextureLayer); copyTextureLayer, subresources.aspects);
bufferOffsetsForNextSlice[splitIndex] += bufferOffsetsForNextSlice[splitIndex] +=
bytesPerSlice * copySplits.copies2D.size(); bytesPerSlice * copySplits.copies2D.size();
@ -754,8 +760,9 @@ namespace dawn_native { namespace d3d12 {
DAWN_TRY(buffer->EnsureDataInitializedAsDestination(commandContext, copy)); DAWN_TRY(buffer->EnsureDataInitializedAsDestination(commandContext, copy));
ASSERT(texture->GetDimension() == wgpu::TextureDimension::e2D); ASSERT(texture->GetDimension() == wgpu::TextureDimension::e2D);
SubresourceRange subresources = {copy->source.mipLevel, 1, SubresourceRange subresources =
copy->source.origin.z, copy->copySize.depth}; GetSubresourcesAffectedByCopy(copy->source, copy->copySize);
texture->EnsureSubresourceContentInitialized(commandContext, subresources); texture->EnsureSubresourceContentInitialized(commandContext, subresources);
texture->TrackUsageAndTransitionNow(commandContext, wgpu::TextureUsage::CopySrc, texture->TrackUsageAndTransitionNow(commandContext, wgpu::TextureUsage::CopySrc,
@ -793,7 +800,7 @@ namespace dawn_native { namespace d3d12 {
RecordCopyTextureToBufferFromTextureCopySplit( RecordCopyTextureToBufferFromTextureCopySplit(
commandList, copySplitPerLayerBase, buffer, bufferOffsetForNextSlice, commandList, copySplitPerLayerBase, buffer, bufferOffsetForNextSlice,
copy->destination.bytesPerRow, texture, copy->source.mipLevel, copy->destination.bytesPerRow, texture, copy->source.mipLevel,
copyTextureLayer); copyTextureLayer, subresources.aspects);
bufferOffsetsForNextSlice[splitIndex] += bufferOffsetsForNextSlice[splitIndex] +=
bytesPerSlice * copySplits.copies2D.size(); bytesPerSlice * copySplits.copies2D.size();
@ -808,10 +815,11 @@ namespace dawn_native { namespace d3d12 {
Texture* source = ToBackend(copy->source.texture.Get()); Texture* source = ToBackend(copy->source.texture.Get());
Texture* destination = ToBackend(copy->destination.texture.Get()); Texture* destination = ToBackend(copy->destination.texture.Get());
SubresourceRange srcRange = {copy->source.mipLevel, 1, copy->source.origin.z,
copy->copySize.depth}; SubresourceRange srcRange =
SubresourceRange dstRange = {copy->destination.mipLevel, 1, GetSubresourcesAffectedByCopy(copy->source, copy->copySize);
copy->destination.origin.z, copy->copySize.depth}; SubresourceRange dstRange =
GetSubresourcesAffectedByCopy(copy->destination, copy->copySize);
source->EnsureSubresourceContentInitialized(commandContext, srcRange); source->EnsureSubresourceContentInitialized(commandContext, srcRange);
if (IsCompleteSubresourceCopiedTo(destination, copy->copySize, if (IsCompleteSubresourceCopiedTo(destination, copy->copySize,
@ -835,6 +843,7 @@ namespace dawn_native { namespace d3d12 {
destination->TrackUsageAndTransitionNow(commandContext, destination->TrackUsageAndTransitionNow(commandContext,
wgpu::TextureUsage::CopyDst, dstRange); wgpu::TextureUsage::CopyDst, dstRange);
ASSERT(srcRange.aspects == dstRange.aspects);
if (CanUseCopyResource(source, destination, copy->copySize)) { if (CanUseCopyResource(source, destination, copy->copySize)) {
commandList->CopyResource(destination->GetD3D12Resource(), commandList->CopyResource(destination->GetD3D12Resource(),
source->GetD3D12Resource()); source->GetD3D12Resource());
@ -844,24 +853,28 @@ namespace dawn_native { namespace d3d12 {
destination->GetDimension() == wgpu::TextureDimension::e2D); destination->GetDimension() == wgpu::TextureDimension::e2D);
const dawn_native::Extent3D copyExtentOneSlice = { const dawn_native::Extent3D copyExtentOneSlice = {
copy->copySize.width, copy->copySize.height, 1u}; copy->copySize.width, copy->copySize.height, 1u};
for (uint32_t slice = 0; slice < copy->copySize.depth; ++slice) {
D3D12_TEXTURE_COPY_LOCATION srcLocation =
ComputeTextureCopyLocationForTexture(source, copy->source.mipLevel,
copy->source.origin.z + slice);
D3D12_TEXTURE_COPY_LOCATION dstLocation = for (Aspect aspect : IterateEnumMask(srcRange.aspects)) {
ComputeTextureCopyLocationForTexture( for (uint32_t slice = 0; slice < copy->copySize.depth; ++slice) {
destination, copy->destination.mipLevel, D3D12_TEXTURE_COPY_LOCATION srcLocation =
copy->destination.origin.z + slice); ComputeTextureCopyLocationForTexture(
source, copy->source.mipLevel,
copy->source.origin.z + slice, aspect);
Origin3D sourceOriginInSubresource = copy->source.origin; D3D12_TEXTURE_COPY_LOCATION dstLocation =
sourceOriginInSubresource.z = 0; ComputeTextureCopyLocationForTexture(
D3D12_BOX sourceRegion = ComputeD3D12BoxFromOffsetAndSize( destination, copy->destination.mipLevel,
sourceOriginInSubresource, copyExtentOneSlice); copy->destination.origin.z + slice, aspect);
commandList->CopyTextureRegion(&dstLocation, copy->destination.origin.x, Origin3D sourceOriginInSubresource = copy->source.origin;
copy->destination.origin.y, 0, sourceOriginInSubresource.z = 0;
&srcLocation, &sourceRegion); D3D12_BOX sourceRegion = ComputeD3D12BoxFromOffsetAndSize(
sourceOriginInSubresource, copyExtentOneSlice);
commandList->CopyTextureRegion(
&dstLocation, copy->destination.origin.x,
copy->destination.origin.y, 0, &srcLocation, &sourceRegion);
}
} }
} }
break; break;

View File

@ -86,12 +86,14 @@ namespace dawn_native { namespace d3d12 {
D3D12EndingAccessResolveSubresourceParameters(TextureView* resolveDestination) { D3D12EndingAccessResolveSubresourceParameters(TextureView* resolveDestination) {
D3D12_RENDER_PASS_ENDING_ACCESS_RESOLVE_SUBRESOURCE_PARAMETERS subresourceParameters; D3D12_RENDER_PASS_ENDING_ACCESS_RESOLVE_SUBRESOURCE_PARAMETERS subresourceParameters;
Texture* resolveDestinationTexture = ToBackend(resolveDestination->GetTexture()); Texture* resolveDestinationTexture = ToBackend(resolveDestination->GetTexture());
ASSERT(resolveDestinationTexture->GetFormat().aspects == Aspect::Color);
subresourceParameters.DstX = 0; subresourceParameters.DstX = 0;
subresourceParameters.DstY = 0; subresourceParameters.DstY = 0;
subresourceParameters.SrcSubresource = 0; subresourceParameters.SrcSubresource = 0;
subresourceParameters.DstSubresource = resolveDestinationTexture->GetSubresourceIndex( subresourceParameters.DstSubresource = resolveDestinationTexture->GetSubresourceIndex(
resolveDestination->GetBaseMipLevel(), resolveDestination->GetBaseArrayLayer()); resolveDestination->GetBaseMipLevel(), resolveDestination->GetBaseArrayLayer(),
Aspect::Color);
// Resolving a specified sub-rect is only valid on hardware that supports sample // Resolving a specified sub-rect is only valid on hardware that supports sample
// positions. This means even {0, 0, width, height} would be invalid if unsupported. To // positions. This means even {0, 0, width, height} would be invalid if unsupported. To
// avoid this, we assume sub-rect resolves never work by setting them to all zeros or // avoid this, we assume sub-rect resolves never work by setting them to all zeros or

View File

@ -17,6 +17,7 @@
#include "common/Constants.h" #include "common/Constants.h"
#include "common/Math.h" #include "common/Math.h"
#include "dawn_native/DynamicUploader.h" #include "dawn_native/DynamicUploader.h"
#include "dawn_native/EnumMaskIterator.h"
#include "dawn_native/Error.h" #include "dawn_native/Error.h"
#include "dawn_native/d3d12/BufferD3D12.h" #include "dawn_native/d3d12/BufferD3D12.h"
#include "dawn_native/d3d12/CommandRecordingContext.h" #include "dawn_native/d3d12/CommandRecordingContext.h"
@ -574,7 +575,15 @@ namespace dawn_native { namespace d3d12 {
} }
std::vector<D3D12_RESOURCE_BARRIER> barriers; std::vector<D3D12_RESOURCE_BARRIER> barriers;
barriers.reserve(range.levelCount * range.layerCount);
// TODO(enga): Consider adding a Count helper.
uint32_t aspectCount = 0;
for (Aspect aspect : IterateEnumMask(range.aspects)) {
aspectCount++;
DAWN_UNUSED(aspect);
}
barriers.reserve(range.levelCount * range.layerCount * aspectCount);
TransitionUsageAndGetResourceBarrier(commandContext, &barriers, newState, range); TransitionUsageAndGetResourceBarrier(commandContext, &barriers, newState, range);
if (barriers.size()) { if (barriers.size()) {
@ -652,19 +661,6 @@ namespace dawn_native { namespace d3d12 {
barrier.Transition.Subresource = barrier.Transition.Subresource =
allSubresources ? D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES : index; allSubresources ? D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES : index;
barriers->push_back(barrier); barriers->push_back(barrier);
// TODO(yunchao.he@intel.com): support subresource for depth/stencil. Depth stencil
// texture has different plane slices. While the current implementation only has differernt
// mip slices and array slices for subresources.
// This is a hack because Dawn doesn't handle subresource of multiplanar resources
// correctly. We force the transition to be the same for all planes to match what the
// frontend validation checks for. This hack might be incorrect for stencil-only texture
// because we always set transition barrier for depth plane.
if (!allSubresources && newState == D3D12_RESOURCE_STATE_DEPTH_WRITE &&
GetFormat().HasStencil()) {
D3D12_RESOURCE_BARRIER barrierStencil = barrier;
barrierStencil.Transition.Subresource += GetArrayLayers() * GetNumMipLevels();
barriers->push_back(barrierStencil);
}
state->isValidToDecay = false; state->isValidToDecay = false;
} }
@ -686,7 +682,6 @@ namespace dawn_native { namespace d3d12 {
HandleTransitionSpecialCases(commandContext); HandleTransitionSpecialCases(commandContext);
const Serial pendingCommandSerial = ToBackend(GetDevice())->GetPendingCommandSerial(); const Serial pendingCommandSerial = ToBackend(GetDevice())->GetPendingCommandSerial();
uint32_t subresourceCount = GetSubresourceCount();
// This transitions assume it is a 2D texture // This transitions assume it is a 2D texture
ASSERT(GetDimension() == wgpu::TextureDimension::e2D); ASSERT(GetDimension() == wgpu::TextureDimension::e2D);
@ -695,25 +690,29 @@ namespace dawn_native { namespace d3d12 {
// are the same, then we can use one barrier to do state transition for all subresources. // are the same, then we can use one barrier to do state transition for all subresources.
// Note that if the texture has only one mip level and one array slice, it will fall into // Note that if the texture has only one mip level and one array slice, it will fall into
// this category. // this category.
bool areAllSubresourcesCovered = range.levelCount * range.layerCount == subresourceCount; bool areAllSubresourcesCovered = (range.levelCount == GetNumMipLevels() && //
range.layerCount == GetArrayLayers() && //
range.aspects == GetFormat().aspects);
if (mSameLastUsagesAcrossSubresources && areAllSubresourcesCovered) { if (mSameLastUsagesAcrossSubresources && areAllSubresourcesCovered) {
TransitionSingleOrAllSubresources(barriers, 0, newState, pendingCommandSerial, true); TransitionSingleOrAllSubresources(barriers, 0, newState, pendingCommandSerial, true);
// TODO(yunchao.he@intel.com): compress and decompress if all subresources have the // TODO(yunchao.he@intel.com): compress and decompress if all subresources have the
// same states. We may need to retain mSubresourceStateAndDecay[0] only. // same states. We may need to retain mSubresourceStateAndDecay[0] only.
for (uint32_t i = 1; i < subresourceCount; ++i) { for (uint32_t i = 1; i < GetSubresourceCount(); ++i) {
mSubresourceStateAndDecay[i] = mSubresourceStateAndDecay[0]; mSubresourceStateAndDecay[i] = mSubresourceStateAndDecay[0];
} }
return; return;
} }
for (uint32_t arrayLayer = 0; arrayLayer < range.layerCount; ++arrayLayer) { for (Aspect aspect : IterateEnumMask(range.aspects)) {
for (uint32_t mipLevel = 0; mipLevel < range.levelCount; ++mipLevel) { for (uint32_t arrayLayer = 0; arrayLayer < range.layerCount; ++arrayLayer) {
uint32_t index = GetSubresourceIndex(range.baseMipLevel + mipLevel, for (uint32_t mipLevel = 0; mipLevel < range.levelCount; ++mipLevel) {
range.baseArrayLayer + arrayLayer); uint32_t index = GetSubresourceIndex(range.baseMipLevel + mipLevel,
range.baseArrayLayer + arrayLayer, aspect);
TransitionSingleOrAllSubresources(barriers, index, newState, pendingCommandSerial, TransitionSingleOrAllSubresources(barriers, index, newState,
false); pendingCommandSerial, false);
}
} }
} }
mSameLastUsagesAcrossSubresources = areAllSubresourcesCovered; mSameLastUsagesAcrossSubresources = areAllSubresourcesCovered;
@ -748,20 +747,22 @@ namespace dawn_native { namespace d3d12 {
return; return;
} }
for (uint32_t arrayLayer = 0; arrayLayer < GetArrayLayers(); ++arrayLayer) { for (Aspect aspect : IterateEnumMask(GetFormat().aspects)) {
for (uint32_t mipLevel = 0; mipLevel < GetNumMipLevels(); ++mipLevel) { for (uint32_t arrayLayer = 0; arrayLayer < GetArrayLayers(); ++arrayLayer) {
uint32_t index = GetSubresourceIndex(mipLevel, arrayLayer); for (uint32_t mipLevel = 0; mipLevel < GetNumMipLevels(); ++mipLevel) {
uint32_t index = GetSubresourceIndex(mipLevel, arrayLayer, aspect);
// Skip if this subresource is not used during the current pass // Skip if this subresource is not used during the current pass
if (textureUsages.subresourceUsages[index] == wgpu::TextureUsage::None) { if (textureUsages.subresourceUsages[index] == wgpu::TextureUsage::None) {
continue; continue;
}
D3D12_RESOURCE_STATES newState =
D3D12TextureUsage(textureUsages.subresourceUsages[index], GetFormat());
TransitionSingleOrAllSubresources(barriers, index, newState,
pendingCommandSerial, false);
} }
D3D12_RESOURCE_STATES newState =
D3D12TextureUsage(textureUsages.subresourceUsages[index], GetFormat());
TransitionSingleOrAllSubresources(barriers, index, newState, pendingCommandSerial,
false);
} }
} }
mSameLastUsagesAcrossSubresources = textureUsages.sameUsagesAcrossSubresources; mSameLastUsagesAcrossSubresources = textureUsages.sameUsagesAcrossSubresources;
@ -838,16 +839,34 @@ namespace dawn_native { namespace d3d12 {
if (GetFormat().HasDepthOrStencil()) { if (GetFormat().HasDepthOrStencil()) {
TrackUsageAndTransitionNow(commandContext, D3D12_RESOURCE_STATE_DEPTH_WRITE, range); TrackUsageAndTransitionNow(commandContext, D3D12_RESOURCE_STATE_DEPTH_WRITE, range);
D3D12_CLEAR_FLAGS clearFlags = {};
for (uint32_t level = range.baseMipLevel; for (uint32_t level = range.baseMipLevel;
level < range.baseMipLevel + range.levelCount; ++level) { level < range.baseMipLevel + range.levelCount; ++level) {
for (uint32_t layer = range.baseArrayLayer; for (uint32_t layer = range.baseArrayLayer;
layer < range.baseArrayLayer + range.layerCount; ++layer) { layer < range.baseArrayLayer + range.layerCount; ++layer) {
if (clearValue == TextureBase::ClearValue::Zero && // Iterate the aspects individually to determine which clear flags to use.
IsSubresourceContentInitialized( D3D12_CLEAR_FLAGS clearFlags = {};
SubresourceRange::SingleSubresource(level, layer))) { for (Aspect aspect : IterateEnumMask(range.aspects)) {
// Skip lazy clears if already initialized. if (clearValue == TextureBase::ClearValue::Zero &&
IsSubresourceContentInitialized(
SubresourceRange::SingleMipAndLayer(level, layer, aspect))) {
// Skip lazy clears if already initialized.
continue;
}
switch (aspect) {
case Aspect::Depth:
clearFlags |= D3D12_CLEAR_FLAG_DEPTH;
break;
case Aspect::Stencil:
clearFlags |= D3D12_CLEAR_FLAG_STENCIL;
break;
default:
UNREACHABLE();
break;
}
}
if (clearFlags == 0) {
continue; continue;
} }
@ -860,13 +879,6 @@ namespace dawn_native { namespace d3d12 {
device->GetD3D12Device()->CreateDepthStencilView(GetD3D12Resource(), device->GetD3D12Device()->CreateDepthStencilView(GetD3D12Resource(),
&dsvDesc, baseDescriptor); &dsvDesc, baseDescriptor);
if (GetFormat().HasDepth()) {
clearFlags |= D3D12_CLEAR_FLAG_DEPTH;
}
if (GetFormat().HasStencil()) {
clearFlags |= D3D12_CLEAR_FLAG_STENCIL;
}
commandList->ClearDepthStencilView(baseDescriptor, clearFlags, fClearColor, commandList->ClearDepthStencilView(baseDescriptor, clearFlags, fClearColor,
clearColor, 0, nullptr); clearColor, 0, nullptr);
} }
@ -878,13 +890,14 @@ namespace dawn_native { namespace d3d12 {
const float clearColorRGBA[4] = {fClearColor, fClearColor, fClearColor, const float clearColorRGBA[4] = {fClearColor, fClearColor, fClearColor,
fClearColor}; fClearColor};
ASSERT(range.aspects == Aspect::Color);
for (uint32_t level = range.baseMipLevel; for (uint32_t level = range.baseMipLevel;
level < range.baseMipLevel + range.levelCount; ++level) { level < range.baseMipLevel + range.levelCount; ++level) {
for (uint32_t layer = range.baseArrayLayer; for (uint32_t layer = range.baseArrayLayer;
layer < range.baseArrayLayer + range.layerCount; ++layer) { layer < range.baseArrayLayer + range.layerCount; ++layer) {
if (clearValue == TextureBase::ClearValue::Zero && if (clearValue == TextureBase::ClearValue::Zero &&
IsSubresourceContentInitialized( IsSubresourceContentInitialized(
SubresourceRange::SingleSubresource(level, layer))) { SubresourceRange::SingleMipAndLayer(level, layer, Aspect::Color))) {
// Skip lazy clears if already initialized. // Skip lazy clears if already initialized.
continue; continue;
} }
@ -920,6 +933,7 @@ namespace dawn_native { namespace d3d12 {
TrackUsageAndTransitionNow(commandContext, D3D12_RESOURCE_STATE_COPY_DEST, range); TrackUsageAndTransitionNow(commandContext, D3D12_RESOURCE_STATE_COPY_DEST, range);
ASSERT(range.aspects == Aspect::Color);
for (uint32_t level = range.baseMipLevel; level < range.baseMipLevel + range.levelCount; for (uint32_t level = range.baseMipLevel; level < range.baseMipLevel + range.levelCount;
++level) { ++level) {
// compute d3d12 texture copy locations for texture and buffer // compute d3d12 texture copy locations for texture and buffer
@ -934,13 +948,13 @@ namespace dawn_native { namespace d3d12 {
layer < range.baseArrayLayer + range.layerCount; ++layer) { layer < range.baseArrayLayer + range.layerCount; ++layer) {
if (clearValue == TextureBase::ClearValue::Zero && if (clearValue == TextureBase::ClearValue::Zero &&
IsSubresourceContentInitialized( IsSubresourceContentInitialized(
SubresourceRange::SingleSubresource(level, layer))) { SubresourceRange::SingleMipAndLayer(level, layer, Aspect::Color))) {
// Skip lazy clears if already initialized. // Skip lazy clears if already initialized.
continue; continue;
} }
D3D12_TEXTURE_COPY_LOCATION textureLocation = D3D12_TEXTURE_COPY_LOCATION textureLocation =
ComputeTextureCopyLocationForTexture(this, level, layer); ComputeTextureCopyLocationForTexture(this, level, layer, Aspect::Color);
for (uint32_t i = 0; i < copySplit.count; ++i) { for (uint32_t i = 0; i < copySplit.count; ++i) {
Texture2DCopySplit::CopyInfo& info = copySplit.copies[i]; Texture2DCopySplit::CopyInfo& info = copySplit.copies[i];

View File

@ -64,11 +64,12 @@ namespace dawn_native { namespace d3d12 {
D3D12_TEXTURE_COPY_LOCATION ComputeTextureCopyLocationForTexture(const Texture* texture, D3D12_TEXTURE_COPY_LOCATION ComputeTextureCopyLocationForTexture(const Texture* texture,
uint32_t level, uint32_t level,
uint32_t slice) { uint32_t slice,
Aspect aspect) {
D3D12_TEXTURE_COPY_LOCATION copyLocation; D3D12_TEXTURE_COPY_LOCATION copyLocation;
copyLocation.pResource = texture->GetD3D12Resource(); copyLocation.pResource = texture->GetD3D12Resource();
copyLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; copyLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
copyLocation.SubresourceIndex = texture->GetSubresourceIndex(level, slice); copyLocation.SubresourceIndex = texture->GetSubresourceIndex(level, slice, aspect);
return copyLocation; return copyLocation;
} }

View File

@ -29,7 +29,8 @@ namespace dawn_native { namespace d3d12 {
D3D12_TEXTURE_COPY_LOCATION ComputeTextureCopyLocationForTexture(const Texture* texture, D3D12_TEXTURE_COPY_LOCATION ComputeTextureCopyLocationForTexture(const Texture* texture,
uint32_t level, uint32_t level,
uint32_t slice); uint32_t slice,
Aspect aspect);
D3D12_TEXTURE_COPY_LOCATION ComputeBufferLocationForCopyTextureRegion( D3D12_TEXTURE_COPY_LOCATION ComputeBufferLocationForCopyTextureRegion(
const Texture* texture, const Texture* texture,

View File

@ -115,7 +115,7 @@ namespace dawn_native { namespace metal {
textureCopy.texture = destination->texture; textureCopy.texture = destination->texture;
textureCopy.mipLevel = destination->mipLevel; textureCopy.mipLevel = destination->mipLevel;
textureCopy.origin = destination->origin; textureCopy.origin = destination->origin;
textureCopy.aspect = destination->aspect; textureCopy.aspect = ConvertAspect(destination->texture->GetFormat(), destination->aspect);
return ToBackend(GetDevice()) return ToBackend(GetDevice())
->CopyFromStagingToTexture(uploadHandle.stagingBuffer, passDataLayout, &textureCopy, ->CopyFromStagingToTexture(uploadHandle.stagingBuffer, passDataLayout, &textureCopy,

View File

@ -18,8 +18,10 @@
#include "common/Math.h" #include "common/Math.h"
#include "common/Platform.h" #include "common/Platform.h"
#include "dawn_native/DynamicUploader.h" #include "dawn_native/DynamicUploader.h"
#include "dawn_native/EnumMaskIterator.h"
#include "dawn_native/metal/DeviceMTL.h" #include "dawn_native/metal/DeviceMTL.h"
#include "dawn_native/metal/StagingBufferMTL.h" #include "dawn_native/metal/StagingBufferMTL.h"
#include "dawn_native/metal/UtilsMetal.h"
#include <CoreVideo/CVPixelBuffer.h> #include <CoreVideo/CVPixelBuffer.h>
@ -353,7 +355,7 @@ namespace dawn_native { namespace metal {
plane:plane]; plane:plane];
[mtlDesc release]; [mtlDesc release];
SetIsSubresourceContentInitialized(descriptor->isCleared, {0, 1, 0, 1}); SetIsSubresourceContentInitialized(descriptor->isCleared, GetAllSubresources());
} }
Texture::~Texture() { Texture::~Texture() {
@ -393,8 +395,8 @@ namespace dawn_native { namespace metal {
for (uint32_t arrayLayer = range.baseArrayLayer; for (uint32_t arrayLayer = range.baseArrayLayer;
arrayLayer < range.baseArrayLayer + range.layerCount; arrayLayer++) { arrayLayer < range.baseArrayLayer + range.layerCount; arrayLayer++) {
if (clearValue == TextureBase::ClearValue::Zero && if (clearValue == TextureBase::ClearValue::Zero &&
IsSubresourceContentInitialized( IsSubresourceContentInitialized(SubresourceRange::SingleMipAndLayer(
SubresourceRange::SingleSubresource(level, arrayLayer))) { level, arrayLayer, range.aspects))) {
// Skip lazy clears if already initialized. // Skip lazy clears if already initialized.
continue; continue;
} }
@ -402,18 +404,34 @@ namespace dawn_native { namespace metal {
MTLRenderPassDescriptor* descriptor = MTLRenderPassDescriptor* descriptor =
[MTLRenderPassDescriptor renderPassDescriptor]; [MTLRenderPassDescriptor renderPassDescriptor];
if (GetFormat().HasDepth()) { // At least one aspect needs clearing. Iterate the aspects individually to
descriptor.depthAttachment.texture = GetMTLTexture(); // determine which to clear.
descriptor.depthAttachment.loadAction = MTLLoadActionClear; for (Aspect aspect : IterateEnumMask(range.aspects)) {
descriptor.depthAttachment.storeAction = MTLStoreActionStore; if (clearValue == TextureBase::ClearValue::Zero &&
descriptor.depthAttachment.clearDepth = dClearColor; IsSubresourceContentInitialized(SubresourceRange::SingleMipAndLayer(
} level, arrayLayer, aspect))) {
if (GetFormat().HasStencil()) { // Skip lazy clears if already initialized.
descriptor.stencilAttachment.texture = GetMTLTexture(); continue;
descriptor.stencilAttachment.loadAction = MTLLoadActionClear; }
descriptor.stencilAttachment.storeAction = MTLStoreActionStore;
descriptor.stencilAttachment.clearStencil = switch (aspect) {
static_cast<uint32_t>(clearColor); case Aspect::Depth:
descriptor.depthAttachment.texture = GetMTLTexture();
descriptor.depthAttachment.loadAction = MTLLoadActionClear;
descriptor.depthAttachment.storeAction = MTLStoreActionStore;
descriptor.depthAttachment.clearDepth = dClearColor;
break;
case Aspect::Stencil:
descriptor.stencilAttachment.texture = GetMTLTexture();
descriptor.stencilAttachment.loadAction = MTLLoadActionClear;
descriptor.stencilAttachment.storeAction = MTLStoreActionStore;
descriptor.stencilAttachment.clearStencil =
static_cast<uint32_t>(clearColor);
break;
default:
UNREACHABLE();
break;
}
} }
commandContext->BeginRender(descriptor); commandContext->BeginRender(descriptor);
@ -433,8 +451,8 @@ namespace dawn_native { namespace metal {
for (uint32_t arrayLayer = range.baseArrayLayer; for (uint32_t arrayLayer = range.baseArrayLayer;
arrayLayer < range.baseArrayLayer + range.layerCount; arrayLayer++) { arrayLayer < range.baseArrayLayer + range.layerCount; arrayLayer++) {
if (clearValue == TextureBase::ClearValue::Zero && if (clearValue == TextureBase::ClearValue::Zero &&
IsSubresourceContentInitialized( IsSubresourceContentInitialized(SubresourceRange::SingleMipAndLayer(
SubresourceRange::SingleSubresource(level, arrayLayer))) { level, arrayLayer, Aspect::Color))) {
// Skip lazy clears if already initialized. // Skip lazy clears if already initialized.
continue; continue;
} }
@ -499,34 +517,21 @@ namespace dawn_native { namespace metal {
id<MTLBuffer> uploadBuffer = ToBackend(uploadHandle.stagingBuffer)->GetBufferHandle(); id<MTLBuffer> uploadBuffer = ToBackend(uploadHandle.stagingBuffer)->GetBufferHandle();
// Encode a buffer to texture copy to clear each subresource. // Encode a buffer to texture copy to clear each subresource.
for (uint32_t level = range.baseMipLevel; level < range.baseMipLevel + range.levelCount; for (Aspect aspect : IterateEnumMask(range.aspects)) {
++level) { for (uint32_t level = range.baseMipLevel;
Extent3D virtualSize = GetMipLevelVirtualSize(level); level < range.baseMipLevel + range.levelCount; ++level) {
Extent3D virtualSize = GetMipLevelVirtualSize(level);
for (uint32_t arrayLayer = range.baseArrayLayer; for (uint32_t arrayLayer = range.baseArrayLayer;
arrayLayer < range.baseArrayLayer + range.layerCount; ++arrayLayer) { arrayLayer < range.baseArrayLayer + range.layerCount; ++arrayLayer) {
if (clearValue == TextureBase::ClearValue::Zero && if (clearValue == TextureBase::ClearValue::Zero &&
IsSubresourceContentInitialized( IsSubresourceContentInitialized(
SubresourceRange::SingleSubresource(level, arrayLayer))) { SubresourceRange::SingleMipAndLayer(level, arrayLayer, aspect))) {
// Skip lazy clears if already initialized. // Skip lazy clears if already initialized.
continue; continue;
} }
// If the textures pixel format is a combined depth/stencil format, then MTLBlitOption blitOption = ComputeMTLBlitOption(GetFormat(), aspect);
// options must be set to either blit the depth attachment portion or blit the
// stencil attachment portion.
std::array<MTLBlitOption, 3> blitOptions = {
MTLBlitOptionNone, MTLBlitOptionDepthFromDepthStencil,
MTLBlitOptionStencilFromDepthStencil};
auto blitOptionStart = blitOptions.begin();
auto blitOptionEnd = blitOptionStart + 1;
if (GetFormat().format == wgpu::TextureFormat::Depth24PlusStencil8) {
blitOptionStart = blitOptions.begin() + 1;
blitOptionEnd = blitOptionStart + 2;
}
for (auto it = blitOptionStart; it != blitOptionEnd; ++it) {
[encoder copyFromBuffer:uploadBuffer [encoder copyFromBuffer:uploadBuffer
sourceOffset:uploadHandle.startOffset sourceOffset:uploadHandle.startOffset
sourceBytesPerRow:largestMipBytesPerRow sourceBytesPerRow:largestMipBytesPerRow
@ -537,7 +542,7 @@ namespace dawn_native { namespace metal {
destinationSlice:arrayLayer destinationSlice:arrayLayer
destinationLevel:level destinationLevel:level
destinationOrigin:MTLOriginMake(0, 0, 0) destinationOrigin:MTLOriginMake(0, 0, 0)
options:(*it)]; options:blitOption];
} }
} }
} }

View File

@ -53,7 +53,7 @@ namespace dawn_native { namespace metal {
const TextureCopy& dst, const TextureCopy& dst,
const Extent3D& size); const Extent3D& size);
MTLBlitOption ComputeMTLBlitOption(const Format& format, wgpu::TextureAspect aspect); MTLBlitOption ComputeMTLBlitOption(const Format& format, Aspect aspect);
}} // namespace dawn_native::metal }} // namespace dawn_native::metal

View File

@ -164,15 +164,18 @@ namespace dawn_native { namespace metal {
} }
} }
MTLBlitOption ComputeMTLBlitOption(const Format& format, wgpu::TextureAspect aspect) { MTLBlitOption ComputeMTLBlitOption(const Format& format, Aspect aspect) {
ASSERT(HasOneBit(aspect));
ASSERT(format.aspects & aspect);
constexpr Aspect kDepthStencil = Aspect::Depth | Aspect::Stencil; constexpr Aspect kDepthStencil = Aspect::Depth | Aspect::Stencil;
if ((format.aspects & kDepthStencil) == kDepthStencil) { if ((format.aspects & kDepthStencil) == kDepthStencil) {
// We only provide a blit option if the format has both depth and stencil. // We only provide a blit option if the format has both depth and stencil.
// It is invalid to provide a blit option otherwise. // It is invalid to provide a blit option otherwise.
switch (aspect) { switch (aspect) {
case wgpu::TextureAspect::DepthOnly: case Aspect::Depth:
return MTLBlitOptionDepthFromDepthStencil; return MTLBlitOptionDepthFromDepthStencil;
case wgpu::TextureAspect::StencilOnly: case Aspect::Stencil:
return MTLBlitOptionStencilFromDepthStencil; return MTLBlitOptionStencilFromDepthStencil;
default: default:
UNREACHABLE(); UNREACHABLE();

View File

@ -525,8 +525,8 @@ namespace dawn_native { namespace opengl {
buffer->EnsureDataInitialized(); buffer->EnsureDataInitialized();
ASSERT(texture->GetDimension() == wgpu::TextureDimension::e2D); ASSERT(texture->GetDimension() == wgpu::TextureDimension::e2D);
SubresourceRange subresources = {dst.mipLevel, 1, dst.origin.z, SubresourceRange subresources =
copy->copySize.depth}; GetSubresourcesAffectedByCopy(dst, copy->copySize);
if (IsCompleteSubresourceCopiedTo(texture, copySize, dst.mipLevel)) { if (IsCompleteSubresourceCopiedTo(texture, copySize, dst.mipLevel)) {
texture->SetIsSubresourceContentInitialized(true, subresources); texture->SetIsSubresourceContentInitialized(true, subresources);
} else { } else {
@ -618,8 +618,8 @@ namespace dawn_native { namespace opengl {
buffer->EnsureDataInitializedAsDestination(copy); buffer->EnsureDataInitializedAsDestination(copy);
ASSERT(texture->GetDimension() == wgpu::TextureDimension::e2D); ASSERT(texture->GetDimension() == wgpu::TextureDimension::e2D);
SubresourceRange subresources = {src.mipLevel, 1, src.origin.z, SubresourceRange subresources =
copy->copySize.depth}; GetSubresourcesAffectedByCopy(src, copy->copySize);
texture->EnsureSubresourceContentInitialized(subresources); texture->EnsureSubresourceContentInitialized(subresources);
// The only way to move data from a texture to a buffer in GL is via // The only way to move data from a texture to a buffer in GL is via
// glReadPixels with a pack buffer. Create a temporary FBO for the copy. // glReadPixels with a pack buffer. Create a temporary FBO for the copy.
@ -699,10 +699,9 @@ namespace dawn_native { namespace opengl {
Extent3D copySize = ComputeTextureCopyExtent(dst, copy->copySize); Extent3D copySize = ComputeTextureCopyExtent(dst, copy->copySize);
Texture* srcTexture = ToBackend(src.texture.Get()); Texture* srcTexture = ToBackend(src.texture.Get());
Texture* dstTexture = ToBackend(dst.texture.Get()); Texture* dstTexture = ToBackend(dst.texture.Get());
SubresourceRange srcRange = {src.mipLevel, 1, src.origin.z,
copy->copySize.depth}; SubresourceRange srcRange = GetSubresourcesAffectedByCopy(src, copy->copySize);
SubresourceRange dstRange = {dst.mipLevel, 1, dst.origin.z, SubresourceRange dstRange = GetSubresourcesAffectedByCopy(dst, copy->copySize);
copy->copySize.depth};
srcTexture->EnsureSubresourceContentInitialized(srcRange); srcTexture->EnsureSubresourceContentInitialized(srcRange);
if (IsCompleteSubresourceCopiedTo(dstTexture, copySize, dst.mipLevel)) { if (IsCompleteSubresourceCopiedTo(dstTexture, copySize, dst.mipLevel)) {

View File

@ -17,6 +17,7 @@
#include "common/Assert.h" #include "common/Assert.h"
#include "common/Constants.h" #include "common/Constants.h"
#include "common/Math.h" #include "common/Math.h"
#include "dawn_native/EnumMaskIterator.h"
#include "dawn_native/opengl/BufferGL.h" #include "dawn_native/opengl/BufferGL.h"
#include "dawn_native/opengl/DeviceGL.h" #include "dawn_native/opengl/DeviceGL.h"
#include "dawn_native/opengl/UtilsGL.h" #include "dawn_native/opengl/UtilsGL.h"
@ -199,25 +200,25 @@ namespace dawn_native { namespace opengl {
float fClearColor = (clearValue == TextureBase::ClearValue::Zero) ? 0.f : 1.f; float fClearColor = (clearValue == TextureBase::ClearValue::Zero) ? 0.f : 1.f;
if (GetFormat().isRenderable) { if (GetFormat().isRenderable) {
if (GetFormat().HasDepthOrStencil()) { if ((range.aspects & (Aspect::Depth | Aspect::Stencil)) != 0) {
bool doDepthClear = GetFormat().HasDepth();
bool doStencilClear = GetFormat().HasStencil();
GLfloat depth = fClearColor; GLfloat depth = fClearColor;
GLint stencil = clearColor; GLint stencil = clearColor;
if (doDepthClear) { if (range.aspects & Aspect::Depth) {
gl.DepthMask(GL_TRUE); gl.DepthMask(GL_TRUE);
} }
if (doStencilClear) { if (range.aspects & Aspect::Stencil) {
gl.StencilMask(GetStencilMaskFromStencilFormat(GetFormat().format)); gl.StencilMask(GetStencilMaskFromStencilFormat(GetFormat().format));
} }
auto DoClear = [&]() { auto DoClear = [&](Aspect aspects) {
if (doDepthClear && doStencilClear) { if (aspects == (Aspect::Depth | Aspect::Stencil)) {
gl.ClearBufferfi(GL_DEPTH_STENCIL, 0, depth, stencil); gl.ClearBufferfi(GL_DEPTH_STENCIL, 0, depth, stencil);
} else if (doDepthClear) { } else if (aspects == Aspect::Depth) {
gl.ClearBufferfv(GL_DEPTH, 0, &depth); gl.ClearBufferfv(GL_DEPTH, 0, &depth);
} else if (doStencilClear) { } else if (aspects == Aspect::Stencil) {
gl.ClearBufferiv(GL_STENCIL, 0, &stencil); gl.ClearBufferiv(GL_STENCIL, 0, &stencil);
} else {
UNREACHABLE();
} }
}; };
@ -230,23 +231,42 @@ namespace dawn_native { namespace opengl {
switch (GetDimension()) { switch (GetDimension()) {
case wgpu::TextureDimension::e2D: case wgpu::TextureDimension::e2D:
if (GetArrayLayers() == 1) { if (GetArrayLayers() == 1) {
if (clearValue == TextureBase::ClearValue::Zero && Aspect aspectsToClear = Aspect::None;
IsSubresourceContentInitialized( for (Aspect aspect : IterateEnumMask(range.aspects)) {
SubresourceRange::SingleSubresource(level, 0))) { if (clearValue == TextureBase::ClearValue::Zero &&
// Skip lazy clears if already initialized. IsSubresourceContentInitialized(
SubresourceRange::SingleMipAndLayer(level, 0,
aspect))) {
// Skip lazy clears if already initialized.
continue;
}
aspectsToClear |= aspect;
}
if (aspectsToClear == Aspect::None) {
continue; continue;
} }
gl.FramebufferTexture2D(GL_DRAW_FRAMEBUFFER, gl.FramebufferTexture2D(GL_DRAW_FRAMEBUFFER,
GL_DEPTH_STENCIL_ATTACHMENT, GetGLTarget(), GL_DEPTH_STENCIL_ATTACHMENT, GetGLTarget(),
GetHandle(), static_cast<GLint>(level)); GetHandle(), static_cast<GLint>(level));
DoClear(); DoClear(aspectsToClear);
} else { } else {
for (uint32_t layer = range.baseArrayLayer; for (uint32_t layer = range.baseArrayLayer;
layer < range.baseArrayLayer + range.layerCount; ++layer) { layer < range.baseArrayLayer + range.layerCount; ++layer) {
if (clearValue == TextureBase::ClearValue::Zero && Aspect aspectsToClear = Aspect::None;
IsSubresourceContentInitialized( for (Aspect aspect : IterateEnumMask(range.aspects)) {
SubresourceRange::SingleSubresource(level, layer))) { if (clearValue == TextureBase::ClearValue::Zero &&
// Skip lazy clears if already initialized. IsSubresourceContentInitialized(
SubresourceRange::SingleMipAndLayer(level, layer,
aspect))) {
// Skip lazy clears if already initialized.
continue;
}
aspectsToClear |= aspect;
}
if (aspectsToClear == Aspect::None) {
continue; continue;
} }
@ -254,7 +274,7 @@ namespace dawn_native { namespace opengl {
GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
GetHandle(), static_cast<GLint>(level), GetHandle(), static_cast<GLint>(level),
static_cast<GLint>(layer)); static_cast<GLint>(layer));
DoClear(); DoClear(aspectsToClear);
} }
} }
break; break;
@ -266,6 +286,8 @@ namespace dawn_native { namespace opengl {
gl.DeleteFramebuffers(1, &framebuffer); gl.DeleteFramebuffers(1, &framebuffer);
} else { } else {
ASSERT(range.aspects == Aspect::Color);
static constexpr uint32_t MAX_TEXEL_SIZE = 16; static constexpr uint32_t MAX_TEXEL_SIZE = 16;
ASSERT(GetFormat().blockByteSize <= MAX_TEXEL_SIZE); ASSERT(GetFormat().blockByteSize <= MAX_TEXEL_SIZE);
std::array<GLbyte, MAX_TEXEL_SIZE> clearColorData; std::array<GLbyte, MAX_TEXEL_SIZE> clearColorData;
@ -280,7 +302,7 @@ namespace dawn_native { namespace opengl {
layer < range.baseArrayLayer + range.layerCount; ++layer) { layer < range.baseArrayLayer + range.layerCount; ++layer) {
if (clearValue == TextureBase::ClearValue::Zero && if (clearValue == TextureBase::ClearValue::Zero &&
IsSubresourceContentInitialized( IsSubresourceContentInitialized(
SubresourceRange::SingleSubresource(level, layer))) { SubresourceRange::SingleMipAndLayer(level, layer, Aspect::Color))) {
// Skip lazy clears if already initialized. // Skip lazy clears if already initialized.
continue; continue;
} }
@ -292,6 +314,8 @@ namespace dawn_native { namespace opengl {
} }
} }
} else { } else {
ASSERT(range.aspects == Aspect::Color);
// TODO(natlee@microsoft.com): test compressed textures are cleared // TODO(natlee@microsoft.com): test compressed textures are cleared
// create temp buffer with clear color to copy to the texture image // create temp buffer with clear color to copy to the texture image
ASSERT(kTextureBytesPerRowAlignment % GetFormat().blockByteSize == 0); ASSERT(kTextureBytesPerRowAlignment % GetFormat().blockByteSize == 0);
@ -334,7 +358,7 @@ namespace dawn_native { namespace opengl {
if (GetArrayLayers() == 1) { if (GetArrayLayers() == 1) {
if (clearValue == TextureBase::ClearValue::Zero && if (clearValue == TextureBase::ClearValue::Zero &&
IsSubresourceContentInitialized( IsSubresourceContentInitialized(
SubresourceRange::SingleSubresource(level, 0))) { SubresourceRange::SingleMipAndLayer(level, 0, Aspect::Color))) {
// Skip lazy clears if already initialized. // Skip lazy clears if already initialized.
continue; continue;
} }
@ -346,7 +370,8 @@ namespace dawn_native { namespace opengl {
layer < range.baseArrayLayer + range.layerCount; ++layer) { layer < range.baseArrayLayer + range.layerCount; ++layer) {
if (clearValue == TextureBase::ClearValue::Zero && if (clearValue == TextureBase::ClearValue::Zero &&
IsSubresourceContentInitialized( IsSubresourceContentInitialized(
SubresourceRange::SingleSubresource(level, layer))) { SubresourceRange::SingleMipAndLayer(level, layer,
Aspect::Color))) {
// Skip lazy clears if already initialized. // Skip lazy clears if already initialized.
continue; continue;
} }

View File

@ -68,7 +68,7 @@ namespace dawn_native { namespace vulkan {
// TODO(jiawei.shao@intel.com): support 1D and 3D textures // TODO(jiawei.shao@intel.com): support 1D and 3D textures
ASSERT(srcTexture->GetDimension() == wgpu::TextureDimension::e2D && ASSERT(srcTexture->GetDimension() == wgpu::TextureDimension::e2D &&
dstTexture->GetDimension() == wgpu::TextureDimension::e2D); dstTexture->GetDimension() == wgpu::TextureDimension::e2D);
region.srcSubresource.aspectMask = srcTexture->GetVkAspectMask(srcCopy.aspect); region.srcSubresource.aspectMask = VulkanAspectMask(srcCopy.aspect);
region.srcSubresource.mipLevel = srcCopy.mipLevel; region.srcSubresource.mipLevel = srcCopy.mipLevel;
region.srcSubresource.baseArrayLayer = srcCopy.origin.z; region.srcSubresource.baseArrayLayer = srcCopy.origin.z;
region.srcSubresource.layerCount = copySize.depth; region.srcSubresource.layerCount = copySize.depth;
@ -77,7 +77,7 @@ namespace dawn_native { namespace vulkan {
region.srcOffset.y = srcCopy.origin.y; region.srcOffset.y = srcCopy.origin.y;
region.srcOffset.z = 0; region.srcOffset.z = 0;
region.dstSubresource.aspectMask = dstTexture->GetVkAspectMask(dstCopy.aspect); region.dstSubresource.aspectMask = VulkanAspectMask(dstCopy.aspect);
region.dstSubresource.mipLevel = dstCopy.mipLevel; region.dstSubresource.mipLevel = dstCopy.mipLevel;
region.dstSubresource.baseArrayLayer = dstCopy.origin.z; region.dstSubresource.baseArrayLayer = dstCopy.origin.z;
region.dstSubresource.layerCount = copySize.depth; region.dstSubresource.layerCount = copySize.depth;
@ -472,8 +472,9 @@ namespace dawn_native { namespace vulkan {
VkImageSubresourceLayers subresource = region.imageSubresource; VkImageSubresourceLayers subresource = region.imageSubresource;
ASSERT(dst.texture->GetDimension() == wgpu::TextureDimension::e2D); ASSERT(dst.texture->GetDimension() == wgpu::TextureDimension::e2D);
SubresourceRange range = {subresource.mipLevel, 1, subresource.baseArrayLayer, SubresourceRange range =
subresource.layerCount}; GetSubresourcesAffectedByCopy(copy->destination, copy->copySize);
if (IsCompleteSubresourceCopiedTo(dst.texture.Get(), copy->copySize, if (IsCompleteSubresourceCopiedTo(dst.texture.Get(), copy->copySize,
subresource.mipLevel)) { subresource.mipLevel)) {
// Since texture has been overwritten, it has been "initialized" // Since texture has been overwritten, it has been "initialized"
@ -507,12 +508,11 @@ namespace dawn_native { namespace vulkan {
VkBufferImageCopy region = VkBufferImageCopy region =
ComputeBufferImageCopyRegion(dst, src, copy->copySize); ComputeBufferImageCopyRegion(dst, src, copy->copySize);
VkImageSubresourceLayers subresource = region.imageSubresource;
ASSERT(src.texture->GetDimension() == wgpu::TextureDimension::e2D); ASSERT(src.texture->GetDimension() == wgpu::TextureDimension::e2D);
const SubresourceRange range = {subresource.mipLevel, 1, SubresourceRange range =
subresource.baseArrayLayer, GetSubresourcesAffectedByCopy(copy->source, copy->copySize);
subresource.layerCount};
ToBackend(src.texture) ToBackend(src.texture)
->EnsureSubresourceContentInitialized(recordingContext, range); ->EnsureSubresourceContentInitialized(recordingContext, range);

View File

@ -628,8 +628,8 @@ namespace dawn_native { namespace vulkan {
VkImageSubresourceLayers subresource = region.imageSubresource; VkImageSubresourceLayers subresource = region.imageSubresource;
ASSERT(dst->texture->GetDimension() == wgpu::TextureDimension::e2D); ASSERT(dst->texture->GetDimension() == wgpu::TextureDimension::e2D);
SubresourceRange range = {subresource.mipLevel, 1, subresource.baseArrayLayer, SubresourceRange range = GetSubresourcesAffectedByCopy(*dst, copySize);
subresource.layerCount};
if (IsCompleteSubresourceCopiedTo(dst->texture.Get(), copySize, subresource.mipLevel)) { if (IsCompleteSubresourceCopiedTo(dst->texture.Get(), copySize, subresource.mipLevel)) {
// Since texture has been overwritten, it has been "initialized" // Since texture has been overwritten, it has been "initialized"
dst->texture->SetIsSubresourceContentInitialized(true, range); dst->texture->SetIsSubresourceContentInitialized(true, range);

View File

@ -142,7 +142,7 @@ namespace dawn_native { namespace vulkan {
textureCopy.texture = destination->texture; textureCopy.texture = destination->texture;
textureCopy.mipLevel = destination->mipLevel; textureCopy.mipLevel = destination->mipLevel;
textureCopy.origin = destination->origin; textureCopy.origin = destination->origin;
textureCopy.aspect = destination->aspect; textureCopy.aspect = ConvertAspect(destination->texture->GetFormat(), destination->aspect);
return ToBackend(GetDevice()) return ToBackend(GetDevice())
->CopyFromStagingToTexture(uploadHandle.stagingBuffer, passDataLayout, &textureCopy, ->CopyFromStagingToTexture(uploadHandle.stagingBuffer, passDataLayout, &textureCopy,

View File

@ -193,28 +193,6 @@ namespace dawn_native { namespace vulkan {
return flags; return flags;
} }
// Computes which Vulkan texture aspects are relevant for the given Dawn format
VkImageAspectFlags VulkanAspectMask(const Aspect& aspects) {
VkImageAspectFlags flags = 0;
for (Aspect aspect : IterateEnumMask(aspects)) {
switch (aspect) {
case Aspect::Color:
flags |= VK_IMAGE_ASPECT_COLOR_BIT;
break;
case Aspect::Depth:
flags |= VK_IMAGE_ASPECT_DEPTH_BIT;
break;
case Aspect::Stencil:
flags |= VK_IMAGE_ASPECT_STENCIL_BIT;
break;
default:
UNREACHABLE();
break;
}
}
return flags;
}
VkImageMemoryBarrier BuildMemoryBarrier(const Format& format, VkImageMemoryBarrier BuildMemoryBarrier(const Format& format,
const VkImage& image, const VkImage& image,
wgpu::TextureUsage lastUsage, wgpu::TextureUsage lastUsage,
@ -597,7 +575,7 @@ namespace dawn_native { namespace vulkan {
// Don't clear imported texture if already cleared // Don't clear imported texture if already cleared
if (descriptor->isCleared) { if (descriptor->isCleared) {
SetIsSubresourceContentInitialized(true, {0, 1, 0, 1}); SetIsSubresourceContentInitialized(true, GetAllSubresources());
} }
// Success, acquire all the external objects. // Success, acquire all the external objects.
@ -700,7 +678,7 @@ namespace dawn_native { namespace vulkan {
if (barriers->size() == transitionBarrierStart) { if (barriers->size() == transitionBarrierStart) {
barriers->push_back(BuildMemoryBarrier( barriers->push_back(BuildMemoryBarrier(
GetFormat(), mHandle, wgpu::TextureUsage::None, wgpu::TextureUsage::None, GetFormat(), mHandle, wgpu::TextureUsage::None, wgpu::TextureUsage::None,
SubresourceRange::SingleSubresource(0, 0))); SubresourceRange::SingleMipAndLayer(0, 0, GetFormat().aspects)));
} }
// Transfer texture from external queue to graphics queue // Transfer texture from external queue to graphics queue
@ -714,7 +692,7 @@ namespace dawn_native { namespace vulkan {
if (barriers->size() == transitionBarrierStart) { if (barriers->size() == transitionBarrierStart) {
barriers->push_back(BuildMemoryBarrier( barriers->push_back(BuildMemoryBarrier(
GetFormat(), mHandle, wgpu::TextureUsage::None, wgpu::TextureUsage::None, GetFormat(), mHandle, wgpu::TextureUsage::None, wgpu::TextureUsage::None,
SubresourceRange::SingleSubresource(0, 0))); SubresourceRange::SingleMipAndLayer(0, 0, GetFormat().aspects)));
} }
// Transfer texture from graphics queue to external queue // Transfer texture from graphics queue to external queue
@ -781,24 +759,40 @@ namespace dawn_native { namespace vulkan {
} else { } else {
for (uint32_t arrayLayer = 0; arrayLayer < GetArrayLayers(); ++arrayLayer) { for (uint32_t arrayLayer = 0; arrayLayer < GetArrayLayers(); ++arrayLayer) {
for (uint32_t mipLevel = 0; mipLevel < GetNumMipLevels(); ++mipLevel) { for (uint32_t mipLevel = 0; mipLevel < GetNumMipLevels(); ++mipLevel) {
uint32_t index = GetSubresourceIndex(mipLevel, arrayLayer); wgpu::TextureUsage lastUsage = wgpu::TextureUsage::None;
wgpu::TextureUsage usage = wgpu::TextureUsage::None;
// Accumulate usage for all format aspects because we cannot transition
// separately.
// TODO(enga): Use VK_KHR_separate_depth_stencil_layouts.
for (Aspect aspect : IterateEnumMask(GetFormat().aspects)) {
uint32_t index = GetSubresourceIndex(mipLevel, arrayLayer, aspect);
usage |= textureUsages.subresourceUsages[index];
lastUsage |= mSubresourceLastUsages[index];
}
// Avoid encoding barriers when it isn't needed. // Avoid encoding barriers when it isn't needed.
if (textureUsages.subresourceUsages[index] == wgpu::TextureUsage::None) { if (usage == wgpu::TextureUsage::None) {
continue; continue;
} }
if (CanReuseWithoutBarrier(mSubresourceLastUsages[index], if (CanReuseWithoutBarrier(lastUsage, usage)) {
textureUsages.subresourceUsages[index])) {
continue; continue;
} }
imageBarriers->push_back(BuildMemoryBarrier(
format, mHandle, mSubresourceLastUsages[index], allLastUsages |= lastUsage;
textureUsages.subresourceUsages[index], allUsages |= usage;
SubresourceRange::SingleSubresource(mipLevel, arrayLayer)));
allLastUsages |= mSubresourceLastUsages[index]; for (Aspect aspect : IterateEnumMask(GetFormat().aspects)) {
allUsages |= textureUsages.subresourceUsages[index]; uint32_t index = GetSubresourceIndex(mipLevel, arrayLayer, aspect);
mSubresourceLastUsages[index] = textureUsages.subresourceUsages[index]; mSubresourceLastUsages[index] = usage;
}
imageBarriers->push_back(
BuildMemoryBarrier(format, mHandle, lastUsage, usage,
SubresourceRange::SingleMipAndLayer(
mipLevel, arrayLayer, GetFormat().aspects)));
} }
} }
} }
@ -820,7 +814,6 @@ namespace dawn_native { namespace vulkan {
const Format& format = GetFormat(); const Format& format = GetFormat();
wgpu::TextureUsage allLastUsages = wgpu::TextureUsage::None; wgpu::TextureUsage allLastUsages = wgpu::TextureUsage::None;
uint32_t subresourceCount = GetSubresourceCount();
// This transitions assume it is a 2D texture // This transitions assume it is a 2D texture
ASSERT(GetDimension() == wgpu::TextureDimension::e2D); ASSERT(GetDimension() == wgpu::TextureDimension::e2D);
@ -829,7 +822,9 @@ namespace dawn_native { namespace vulkan {
// are the same, then we can use one barrier to do state transition for all subresources. // are the same, then we can use one barrier to do state transition for all subresources.
// Note that if the texture has only one mip level and one array slice, it will fall into // Note that if the texture has only one mip level and one array slice, it will fall into
// this category. // this category.
bool areAllSubresourcesCovered = range.levelCount * range.layerCount == subresourceCount; bool areAllSubresourcesCovered = (range.levelCount == GetNumMipLevels() && //
range.layerCount == GetArrayLayers() && //
range.aspects == format.aspects);
if (mSameLastUsagesAcrossSubresources && areAllSubresourcesCovered) { if (mSameLastUsagesAcrossSubresources && areAllSubresourcesCovered) {
ASSERT(range.baseMipLevel == 0 && range.baseArrayLayer == 0); ASSERT(range.baseMipLevel == 0 && range.baseArrayLayer == 0);
if (CanReuseWithoutBarrier(mSubresourceLastUsages[0], usage)) { if (CanReuseWithoutBarrier(mSubresourceLastUsages[0], usage)) {
@ -838,7 +833,7 @@ namespace dawn_native { namespace vulkan {
barriers.push_back( barriers.push_back(
BuildMemoryBarrier(format, mHandle, mSubresourceLastUsages[0], usage, range)); BuildMemoryBarrier(format, mHandle, mSubresourceLastUsages[0], usage, range));
allLastUsages = mSubresourceLastUsages[0]; allLastUsages = mSubresourceLastUsages[0];
for (uint32_t i = 0; i < subresourceCount; ++i) { for (uint32_t i = 0; i < GetSubresourceCount(); ++i) {
mSubresourceLastUsages[i] = usage; mSubresourceLastUsages[i] = usage;
} }
} else { } else {
@ -846,17 +841,29 @@ namespace dawn_native { namespace vulkan {
layer < range.baseArrayLayer + range.layerCount; ++layer) { layer < range.baseArrayLayer + range.layerCount; ++layer) {
for (uint32_t level = range.baseMipLevel; for (uint32_t level = range.baseMipLevel;
level < range.baseMipLevel + range.levelCount; ++level) { level < range.baseMipLevel + range.levelCount; ++level) {
uint32_t index = GetSubresourceIndex(level, layer); // Accumulate usage for all format aspects because we cannot transition
// separately.
// TODO(enga): Use VK_KHR_separate_depth_stencil_layouts.
wgpu::TextureUsage lastUsage = wgpu::TextureUsage::None;
for (Aspect aspect : IterateEnumMask(format.aspects)) {
uint32_t index = GetSubresourceIndex(level, layer, aspect);
lastUsage |= mSubresourceLastUsages[index];
}
if (CanReuseWithoutBarrier(mSubresourceLastUsages[index], usage)) { if (CanReuseWithoutBarrier(lastUsage, usage)) {
continue; continue;
} }
barriers.push_back( allLastUsages |= lastUsage;
BuildMemoryBarrier(format, mHandle, mSubresourceLastUsages[index], usage,
SubresourceRange::SingleSubresource(level, layer))); for (Aspect aspect : IterateEnumMask(format.aspects)) {
allLastUsages |= mSubresourceLastUsages[index]; uint32_t index = GetSubresourceIndex(level, layer, aspect);
mSubresourceLastUsages[index] = usage; mSubresourceLastUsages[index] = usage;
}
barriers.push_back(BuildMemoryBarrier(
format, mHandle, lastUsage, usage,
SubresourceRange::SingleMipAndLayer(level, layer, format.aspects)));
} }
} }
} }
@ -885,7 +892,6 @@ namespace dawn_native { namespace vulkan {
TransitionUsageNow(recordingContext, wgpu::TextureUsage::CopyDst, range); TransitionUsageNow(recordingContext, wgpu::TextureUsage::CopyDst, range);
if (GetFormat().isRenderable) { if (GetFormat().isRenderable) {
VkImageSubresourceRange imageRange = {}; VkImageSubresourceRange imageRange = {};
imageRange.aspectMask = GetVkAspectMask(wgpu::TextureAspect::All);
imageRange.levelCount = 1; imageRange.levelCount = 1;
imageRange.layerCount = 1; imageRange.layerCount = 1;
@ -894,16 +900,25 @@ namespace dawn_native { namespace vulkan {
imageRange.baseMipLevel = level; imageRange.baseMipLevel = level;
for (uint32_t layer = range.baseArrayLayer; for (uint32_t layer = range.baseArrayLayer;
layer < range.baseArrayLayer + range.layerCount; ++layer) { layer < range.baseArrayLayer + range.layerCount; ++layer) {
if (clearValue == TextureBase::ClearValue::Zero && Aspect aspects = Aspect::None;
IsSubresourceContentInitialized( for (Aspect aspect : IterateEnumMask(range.aspects)) {
SubresourceRange::SingleSubresource(level, layer))) { if (clearValue == TextureBase::ClearValue::Zero &&
// Skip lazy clears if already initialized. IsSubresourceContentInitialized(
SubresourceRange::SingleMipAndLayer(level, layer, aspect))) {
// Skip lazy clears if already initialized.
continue;
}
aspects |= aspect;
}
if (aspects == Aspect::None) {
continue; continue;
} }
imageRange.aspectMask = VulkanAspectMask(aspects);
imageRange.baseArrayLayer = layer; imageRange.baseArrayLayer = layer;
if (GetFormat().HasDepthOrStencil()) { if (aspects & (Aspect::Depth | Aspect::Stencil)) {
VkClearDepthStencilValue clearDepthStencilValue[1]; VkClearDepthStencilValue clearDepthStencilValue[1];
clearDepthStencilValue[0].depth = fClearColor; clearDepthStencilValue[0].depth = fClearColor;
clearDepthStencilValue[0].stencil = clearColor; clearDepthStencilValue[0].stencil = clearColor;
@ -912,6 +927,7 @@ namespace dawn_native { namespace vulkan {
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, clearDepthStencilValue, 1, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, clearDepthStencilValue, 1,
&imageRange); &imageRange);
} else { } else {
ASSERT(aspects == Aspect::Color);
VkClearColorValue clearColorValue = { VkClearColorValue clearColorValue = {
{fClearColor, fClearColor, fClearColor, fClearColor}}; {fClearColor, fClearColor, fClearColor, fClearColor}};
device->fn.CmdClearColorImage(recordingContext->commandBuffer, GetHandle(), device->fn.CmdClearColorImage(recordingContext->commandBuffer, GetHandle(),
@ -943,6 +959,7 @@ namespace dawn_native { namespace vulkan {
bufferCopy.offset = uploadHandle.startOffset; bufferCopy.offset = uploadHandle.startOffset;
bufferCopy.bytesPerRow = bytesPerRow; bufferCopy.bytesPerRow = bytesPerRow;
ASSERT(range.aspects == Aspect::Color);
for (uint32_t level = range.baseMipLevel; level < range.baseMipLevel + range.levelCount; for (uint32_t level = range.baseMipLevel; level < range.baseMipLevel + range.levelCount;
++level) { ++level) {
Extent3D copySize = GetMipLevelVirtualSize(level); Extent3D copySize = GetMipLevelVirtualSize(level);
@ -951,7 +968,7 @@ namespace dawn_native { namespace vulkan {
layer < range.baseArrayLayer + range.layerCount; ++layer) { layer < range.baseArrayLayer + range.layerCount; ++layer) {
if (clearValue == TextureBase::ClearValue::Zero && if (clearValue == TextureBase::ClearValue::Zero &&
IsSubresourceContentInitialized( IsSubresourceContentInitialized(
SubresourceRange::SingleSubresource(level, layer))) { SubresourceRange::SingleMipAndLayer(level, layer, Aspect::Color))) {
// Skip lazy clears if already initialized. // Skip lazy clears if already initialized.
continue; continue;
} }
@ -961,7 +978,7 @@ namespace dawn_native { namespace vulkan {
textureCopy.texture = this; textureCopy.texture = this;
textureCopy.origin = {0, 0, layer}; textureCopy.origin = {0, 0, layer};
textureCopy.mipLevel = level; textureCopy.mipLevel = level;
textureCopy.aspect = wgpu::TextureAspect::All; textureCopy.aspect = GetFormat().aspects;
VkBufferImageCopy region = VkBufferImageCopy region =
ComputeBufferImageCopyRegion(bufferCopy, textureCopy, copySize); ComputeBufferImageCopyRegion(bufferCopy, textureCopy, copySize);
@ -1028,11 +1045,13 @@ namespace dawn_native { namespace vulkan {
createInfo.format = VulkanImageFormat(device, descriptor->format); createInfo.format = VulkanImageFormat(device, descriptor->format);
createInfo.components = VkComponentMapping{VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, createInfo.components = VkComponentMapping{VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G,
VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A}; VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A};
createInfo.subresourceRange.aspectMask = VulkanAspectMask(GetFormat().aspects);
createInfo.subresourceRange.baseMipLevel = descriptor->baseMipLevel; const SubresourceRange& subresources = GetSubresourceRange();
createInfo.subresourceRange.levelCount = descriptor->mipLevelCount; createInfo.subresourceRange.baseMipLevel = subresources.baseMipLevel;
createInfo.subresourceRange.baseArrayLayer = descriptor->baseArrayLayer; createInfo.subresourceRange.levelCount = subresources.levelCount;
createInfo.subresourceRange.layerCount = descriptor->arrayLayerCount; createInfo.subresourceRange.baseArrayLayer = subresources.baseArrayLayer;
createInfo.subresourceRange.layerCount = subresources.layerCount;
createInfo.subresourceRange.aspectMask = VulkanAspectMask(subresources.aspects);
return CheckVkSuccess( return CheckVkSuccess(
device->fn.CreateImageView(device->GetVkDevice(), &createInfo, nullptr, &*mHandle), device->fn.CreateImageView(device->GetVkDevice(), &createInfo, nullptr, &*mHandle),

View File

@ -15,6 +15,7 @@
#include "dawn_native/vulkan/UtilsVulkan.h" #include "dawn_native/vulkan/UtilsVulkan.h"
#include "common/Assert.h" #include "common/Assert.h"
#include "dawn_native/EnumMaskIterator.h"
#include "dawn_native/Format.h" #include "dawn_native/Format.h"
#include "dawn_native/vulkan/Forward.h" #include "dawn_native/vulkan/Forward.h"
#include "dawn_native/vulkan/TextureVk.h" #include "dawn_native/vulkan/TextureVk.h"
@ -44,6 +45,28 @@ namespace dawn_native { namespace vulkan {
} }
} }
// Convert Dawn texture aspects to Vulkan texture aspect flags
VkImageAspectFlags VulkanAspectMask(const Aspect& aspects) {
VkImageAspectFlags flags = 0;
for (Aspect aspect : IterateEnumMask(aspects)) {
switch (aspect) {
case Aspect::Color:
flags |= VK_IMAGE_ASPECT_COLOR_BIT;
break;
case Aspect::Depth:
flags |= VK_IMAGE_ASPECT_DEPTH_BIT;
break;
case Aspect::Stencil:
flags |= VK_IMAGE_ASPECT_STENCIL_BIT;
break;
default:
UNREACHABLE();
break;
}
}
return flags;
}
// Vulkan SPEC requires the source/destination region specified by each element of // 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 // 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 // the image refers to the virtual size, while Dawn validates texture copy extent with the
@ -91,7 +114,7 @@ namespace dawn_native { namespace vulkan {
dataLayout.bytesPerRow / blockInfo.blockByteSize * blockInfo.blockWidth; dataLayout.bytesPerRow / blockInfo.blockByteSize * blockInfo.blockWidth;
region.bufferImageHeight = dataLayout.rowsPerImage; region.bufferImageHeight = dataLayout.rowsPerImage;
region.imageSubresource.aspectMask = texture->GetVkAspectMask(textureCopy.aspect); region.imageSubresource.aspectMask = VulkanAspectMask(textureCopy.aspect);
region.imageSubresource.mipLevel = textureCopy.mipLevel; region.imageSubresource.mipLevel = textureCopy.mipLevel;
switch (textureCopy.texture->GetDimension()) { switch (textureCopy.texture->GetDimension()) {

View File

@ -88,6 +88,8 @@ namespace dawn_native { namespace vulkan {
VkCompareOp ToVulkanCompareOp(wgpu::CompareFunction op); VkCompareOp ToVulkanCompareOp(wgpu::CompareFunction op);
VkImageAspectFlags VulkanAspectMask(const Aspect& aspects);
Extent3D ComputeTextureCopyExtent(const TextureCopy& textureCopy, const Extent3D& copySize); Extent3D ComputeTextureCopyExtent(const TextureCopy& textureCopy, const Extent3D& copySize);
VkBufferImageCopy ComputeBufferImageCopyRegion(const BufferCopy& bufferCopy, VkBufferImageCopy ComputeBufferImageCopyRegion(const BufferCopy& bufferCopy,

View File

@ -182,11 +182,13 @@ namespace dawn_native {
DAWN_NATIVE_EXPORT size_t GetDeprecationWarningCountForTesting(WGPUDevice device); DAWN_NATIVE_EXPORT size_t GetDeprecationWarningCountForTesting(WGPUDevice device);
// Query if texture has been initialized // Query if texture has been initialized
DAWN_NATIVE_EXPORT bool IsTextureSubresourceInitialized(WGPUTexture texture, DAWN_NATIVE_EXPORT bool IsTextureSubresourceInitialized(
uint32_t baseMipLevel, WGPUTexture texture,
uint32_t levelCount, uint32_t baseMipLevel,
uint32_t baseArrayLayer, uint32_t levelCount,
uint32_t layerCount); uint32_t baseArrayLayer,
uint32_t layerCount,
WGPUTextureAspect aspect = WGPUTextureAspect_All);
// Backdoor to get the order of the ProcMap for testing // Backdoor to get the order of the ProcMap for testing
DAWN_NATIVE_EXPORT std::vector<const char*> GetProcMapNamesForTesting(); DAWN_NATIVE_EXPORT std::vector<const char*> GetProcMapNamesForTesting();

View File

@ -62,9 +62,9 @@ class TextureZeroInitTest : public DawnTest {
descriptor.dimension = wgpu::TextureViewDimension::e2D; descriptor.dimension = wgpu::TextureViewDimension::e2D;
return descriptor; return descriptor;
} }
wgpu::RenderPipeline CreatePipelineForTest() { wgpu::RenderPipeline CreatePipelineForTest(float depth = 0.f) {
utils::ComboRenderPipelineDescriptor pipelineDescriptor(device); utils::ComboRenderPipelineDescriptor pipelineDescriptor(device);
pipelineDescriptor.vertexStage.module = CreateBasicVertexShaderForTest(); pipelineDescriptor.vertexStage.module = CreateBasicVertexShaderForTest(depth);
const char* fs = const char* fs =
R"(#version 450 R"(#version 450
layout(location = 0) out vec4 fragColor; layout(location = 0) out vec4 fragColor;
@ -80,8 +80,8 @@ class TextureZeroInitTest : public DawnTest {
return device.CreateRenderPipeline(&pipelineDescriptor); return device.CreateRenderPipeline(&pipelineDescriptor);
} }
wgpu::ShaderModule CreateBasicVertexShaderForTest() { wgpu::ShaderModule CreateBasicVertexShaderForTest(float depth = 0.f) {
return utils::CreateShaderModule(device, utils::SingleShaderStage::Vertex, R"(#version 450 std::string source = R"(#version 450
const vec2 pos[6] = vec2[6](vec2(-1.0f, -1.0f), const vec2 pos[6] = vec2[6](vec2(-1.0f, -1.0f),
vec2(-1.0f, 1.0f), vec2(-1.0f, 1.0f),
vec2( 1.0f, -1.0f), vec2( 1.0f, -1.0f),
@ -91,8 +91,10 @@ class TextureZeroInitTest : public DawnTest {
); );
void main() { void main() {
gl_Position = vec4(pos[gl_VertexIndex], 0.0, 1.0); gl_Position = vec4(pos[gl_VertexIndex], )" +
})"); std::to_string(depth) + R"(, 1.0);
})";
return utils::CreateShaderModule(device, utils::SingleShaderStage::Vertex, source.c_str());
} }
wgpu::ShaderModule CreateSampledTextureFragmentShaderForTest() { wgpu::ShaderModule CreateSampledTextureFragmentShaderForTest() {
return utils::CreateShaderModule(device, utils::SingleShaderStage::Fragment, return utils::CreateShaderModule(device, utils::SingleShaderStage::Fragment,
@ -574,6 +576,239 @@ TEST_P(TextureZeroInitTest, RenderingLoadingDepthStencil) {
EXPECT_EQ(true, dawn_native::IsTextureSubresourceInitialized(srcTexture.Get(), 0, 1, 0, 1)); EXPECT_EQ(true, dawn_native::IsTextureSubresourceInitialized(srcTexture.Get(), 0, 1, 0, 1));
} }
// Test that clear state is tracked independently for depth/stencil textures.
TEST_P(TextureZeroInitTest, IndependentDepthStencilLoadAfterDiscard) {
// TODO(enga): Figure out why this fails on Metal Intel.
DAWN_SKIP_TEST_IF(IsMetal() && IsIntel());
wgpu::TextureDescriptor depthStencilDescriptor = CreateTextureDescriptor(
1, 1, wgpu::TextureUsage::OutputAttachment | wgpu::TextureUsage::CopySrc,
kDepthStencilFormat);
wgpu::Texture depthStencilTexture = device.CreateTexture(&depthStencilDescriptor);
// Uninitialize only depth
{
// Clear the stencil to 2 and discard the depth
{
utils::ComboRenderPassDescriptor renderPassDescriptor({},
depthStencilTexture.CreateView());
renderPassDescriptor.cDepthStencilAttachmentInfo.depthStoreOp = wgpu::StoreOp::Clear;
renderPassDescriptor.cDepthStencilAttachmentInfo.clearStencil = 2;
renderPassDescriptor.cDepthStencilAttachmentInfo.stencilStoreOp = wgpu::StoreOp::Store;
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
auto pass = encoder.BeginRenderPass(&renderPassDescriptor);
pass.EndPass();
wgpu::CommandBuffer commandBuffer = encoder.Finish();
EXPECT_LAZY_CLEAR(0u, queue.Submit(1, &commandBuffer));
}
// "all" subresources are not initialized; Depth is not initialized
EXPECT_EQ(false, dawn_native::IsTextureSubresourceInitialized(
depthStencilTexture.Get(), 0, 1, 0, 1, WGPUTextureAspect_All));
EXPECT_EQ(false, dawn_native::IsTextureSubresourceInitialized(
depthStencilTexture.Get(), 0, 1, 0, 1, WGPUTextureAspect_DepthOnly));
EXPECT_EQ(true, dawn_native::IsTextureSubresourceInitialized(
depthStencilTexture.Get(), 0, 1, 0, 1, WGPUTextureAspect_StencilOnly));
// Now load both depth and stencil. Depth should be cleared and stencil should stay the same
// at 2.
{
wgpu::TextureDescriptor colorDescriptor =
CreateTextureDescriptor(1, 1,
wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::CopyDst |
wgpu::TextureUsage::OutputAttachment,
kColorFormat);
wgpu::Texture colorTexture = device.CreateTexture(&colorDescriptor);
utils::ComboRenderPassDescriptor renderPassDescriptor({colorTexture.CreateView()},
depthStencilTexture.CreateView());
renderPassDescriptor.cDepthStencilAttachmentInfo.depthLoadOp = wgpu::LoadOp::Load;
renderPassDescriptor.cDepthStencilAttachmentInfo.stencilLoadOp = wgpu::LoadOp::Load;
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
auto pass = encoder.BeginRenderPass(&renderPassDescriptor);
pass.SetPipeline(CreatePipelineForTest());
pass.SetStencilReference(2);
pass.Draw(6);
pass.EndPass();
wgpu::CommandBuffer commandBuffer = encoder.Finish();
// No lazy clear because depth will be cleared with a loadOp
EXPECT_LAZY_CLEAR(0u, queue.Submit(1, &commandBuffer));
// Expect the texture to be red because the depth and stencil tests passed. Depth was 0
// and stencil was 2.
std::vector<RGBA8> expected(kSize * kSize, {255, 0, 0, 255});
EXPECT_TEXTURE_RGBA8_EQ(expected.data(), colorTexture, 0, 0, kSize, kSize, 0, 0);
}
// Everything is initialized now
EXPECT_EQ(true, dawn_native::IsTextureSubresourceInitialized(
depthStencilTexture.Get(), 0, 1, 0, 1, WGPUTextureAspect_All));
EXPECT_EQ(true, dawn_native::IsTextureSubresourceInitialized(
depthStencilTexture.Get(), 0, 1, 0, 1, WGPUTextureAspect_DepthOnly));
EXPECT_EQ(true, dawn_native::IsTextureSubresourceInitialized(
depthStencilTexture.Get(), 0, 1, 0, 1, WGPUTextureAspect_StencilOnly));
// TODO(crbug.com/dawn/439): Implement stencil copies on other platforms
if (IsMetal() || IsVulkan()) {
// Check by copy that the stencil data is 2.
EXPECT_LAZY_CLEAR(0u, EXPECT_TEXTURE_EQ(uint8_t(2), depthStencilTexture, 0, 0, 0, 0,
wgpu::TextureAspect::StencilOnly));
}
}
// Uninitialize only stencil
{
// Clear the depth to 0.7 and discard the stencil.
{
utils::ComboRenderPassDescriptor renderPassDescriptor({},
depthStencilTexture.CreateView());
renderPassDescriptor.cDepthStencilAttachmentInfo.clearDepth = 0.7;
renderPassDescriptor.cDepthStencilAttachmentInfo.depthStoreOp = wgpu::StoreOp::Store;
renderPassDescriptor.cDepthStencilAttachmentInfo.stencilStoreOp = wgpu::StoreOp::Clear;
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
auto pass = encoder.BeginRenderPass(&renderPassDescriptor);
pass.EndPass();
wgpu::CommandBuffer commandBuffer = encoder.Finish();
EXPECT_LAZY_CLEAR(0u, queue.Submit(1, &commandBuffer));
}
// "all" subresources are not initialized; Stencil is not initialized
EXPECT_EQ(false, dawn_native::IsTextureSubresourceInitialized(
depthStencilTexture.Get(), 0, 1, 0, 1, WGPUTextureAspect_All));
EXPECT_EQ(true, dawn_native::IsTextureSubresourceInitialized(
depthStencilTexture.Get(), 0, 1, 0, 1, WGPUTextureAspect_DepthOnly));
EXPECT_EQ(false, dawn_native::IsTextureSubresourceInitialized(
depthStencilTexture.Get(), 0, 1, 0, 1, WGPUTextureAspect_StencilOnly));
// Now load both depth and stencil. Stencil should be cleared and depth should stay the same
// at 0.7.
{
wgpu::TextureDescriptor colorDescriptor =
CreateTextureDescriptor(1, 1,
wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::CopyDst |
wgpu::TextureUsage::OutputAttachment,
kColorFormat);
wgpu::Texture colorTexture = device.CreateTexture(&colorDescriptor);
utils::ComboRenderPassDescriptor renderPassDescriptor({colorTexture.CreateView()},
depthStencilTexture.CreateView());
renderPassDescriptor.cDepthStencilAttachmentInfo.depthLoadOp = wgpu::LoadOp::Load;
renderPassDescriptor.cDepthStencilAttachmentInfo.stencilLoadOp = wgpu::LoadOp::Load;
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
auto pass = encoder.BeginRenderPass(&renderPassDescriptor);
pass.SetPipeline(CreatePipelineForTest(0.7));
pass.Draw(6);
pass.EndPass();
wgpu::CommandBuffer commandBuffer = encoder.Finish();
// No lazy clear because stencil will clear using a loadOp.
EXPECT_LAZY_CLEAR(0u, queue.Submit(1, &commandBuffer));
// Expect the texture to be red because both the depth a stencil tests passed.
// Depth was 0.7 and stencil was 0
std::vector<RGBA8> expected(kSize * kSize, {255, 0, 0, 255});
EXPECT_TEXTURE_RGBA8_EQ(expected.data(), colorTexture, 0, 0, kSize, kSize, 0, 0);
}
// Everything is initialized now
EXPECT_EQ(true, dawn_native::IsTextureSubresourceInitialized(
depthStencilTexture.Get(), 0, 1, 0, 1, WGPUTextureAspect_All));
EXPECT_EQ(true, dawn_native::IsTextureSubresourceInitialized(
depthStencilTexture.Get(), 0, 1, 0, 1, WGPUTextureAspect_DepthOnly));
EXPECT_EQ(true, dawn_native::IsTextureSubresourceInitialized(
depthStencilTexture.Get(), 0, 1, 0, 1, WGPUTextureAspect_StencilOnly));
// TODO(crbug.com/dawn/439): Implement stencil copies on other platforms
if (IsMetal() || IsVulkan()) {
// Check by copy that the stencil data is 0.
EXPECT_LAZY_CLEAR(0u, EXPECT_TEXTURE_EQ(uint8_t(0), depthStencilTexture, 0, 0, 0, 0,
wgpu::TextureAspect::StencilOnly));
}
}
}
// Test that clear state is tracked independently for depth/stencil textures.
// Lazy clear of the stencil aspect via copy should not touch depth.
TEST_P(TextureZeroInitTest, IndependentDepthStencilCopyAfterDiscard) {
// TODO(crbug.com/dawn/439): Implement stencil copies on other platforms
DAWN_SKIP_TEST_IF(!(IsMetal() || IsVulkan()));
// TODO(enga): Figure out why this fails on Metal Intel.
DAWN_SKIP_TEST_IF(IsMetal() && IsIntel());
wgpu::TextureDescriptor depthStencilDescriptor = CreateTextureDescriptor(
1, 1, wgpu::TextureUsage::OutputAttachment | wgpu::TextureUsage::CopySrc,
kDepthStencilFormat);
wgpu::Texture depthStencilTexture = device.CreateTexture(&depthStencilDescriptor);
// Clear the depth to 0.3 and discard the stencil.
{
utils::ComboRenderPassDescriptor renderPassDescriptor({}, depthStencilTexture.CreateView());
renderPassDescriptor.cDepthStencilAttachmentInfo.clearDepth = 0.3;
renderPassDescriptor.cDepthStencilAttachmentInfo.depthStoreOp = wgpu::StoreOp::Store;
renderPassDescriptor.cDepthStencilAttachmentInfo.stencilStoreOp = wgpu::StoreOp::Clear;
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
auto pass = encoder.BeginRenderPass(&renderPassDescriptor);
pass.EndPass();
wgpu::CommandBuffer commandBuffer = encoder.Finish();
EXPECT_LAZY_CLEAR(0u, queue.Submit(1, &commandBuffer));
}
// "all" subresources are not initialized; Stencil is not initialized
EXPECT_EQ(false, dawn_native::IsTextureSubresourceInitialized(depthStencilTexture.Get(), 0, 1,
0, 1, WGPUTextureAspect_All));
EXPECT_EQ(true, dawn_native::IsTextureSubresourceInitialized(depthStencilTexture.Get(), 0, 1, 0,
1, WGPUTextureAspect_DepthOnly));
EXPECT_EQ(false, dawn_native::IsTextureSubresourceInitialized(
depthStencilTexture.Get(), 0, 1, 0, 1, WGPUTextureAspect_StencilOnly));
// Check by copy that the stencil data is lazily cleared to 0.
EXPECT_LAZY_CLEAR(1u, EXPECT_TEXTURE_EQ(uint8_t(0), depthStencilTexture, 0, 0, 0, 0,
wgpu::TextureAspect::StencilOnly));
// Everything is initialized now
EXPECT_EQ(true, dawn_native::IsTextureSubresourceInitialized(depthStencilTexture.Get(), 0, 1, 0,
1, WGPUTextureAspect_All));
EXPECT_EQ(true, dawn_native::IsTextureSubresourceInitialized(depthStencilTexture.Get(), 0, 1, 0,
1, WGPUTextureAspect_DepthOnly));
EXPECT_EQ(true, dawn_native::IsTextureSubresourceInitialized(depthStencilTexture.Get(), 0, 1, 0,
1, WGPUTextureAspect_StencilOnly));
// Now load both depth and stencil. Stencil should be cleared and depth should stay the same
// at 0.3.
{
wgpu::TextureDescriptor colorDescriptor =
CreateTextureDescriptor(1, 1,
wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::CopyDst |
wgpu::TextureUsage::OutputAttachment,
kColorFormat);
wgpu::Texture colorTexture = device.CreateTexture(&colorDescriptor);
utils::ComboRenderPassDescriptor renderPassDescriptor({colorTexture.CreateView()},
depthStencilTexture.CreateView());
renderPassDescriptor.cDepthStencilAttachmentInfo.depthLoadOp = wgpu::LoadOp::Load;
renderPassDescriptor.cDepthStencilAttachmentInfo.stencilLoadOp = wgpu::LoadOp::Load;
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
auto pass = encoder.BeginRenderPass(&renderPassDescriptor);
pass.SetPipeline(CreatePipelineForTest(0.3));
pass.Draw(6);
pass.EndPass();
wgpu::CommandBuffer commandBuffer = encoder.Finish();
// No lazy clear because stencil will clear using a loadOp.
EXPECT_LAZY_CLEAR(0u, queue.Submit(1, &commandBuffer));
// Expect the texture to be red because both the depth a stencil tests passed.
// Depth was 0.3 and stencil was 0
std::vector<RGBA8> expected(kSize * kSize, {255, 0, 0, 255});
EXPECT_TEXTURE_RGBA8_EQ(expected.data(), colorTexture, 0, 0, kSize, kSize, 0, 0);
}
}
// This tests the color attachments clear to 0s // This tests the color attachments clear to 0s
TEST_P(TextureZeroInitTest, ColorAttachmentsClear) { TEST_P(TextureZeroInitTest, ColorAttachmentsClear) {
wgpu::TextureDescriptor descriptor = CreateTextureDescriptor( wgpu::TextureDescriptor descriptor = CreateTextureDescriptor(

View File

@ -198,7 +198,7 @@ namespace {
} }
} }
// Depth and stencil storeOps must match // Depth and stencil storeOps can be different
TEST_F(RenderPassDescriptorValidationTest, DepthStencilStoreOpMismatch) { TEST_F(RenderPassDescriptorValidationTest, DepthStencilStoreOpMismatch) {
constexpr uint32_t kArrayLayers = 1; constexpr uint32_t kArrayLayers = 1;
constexpr uint32_t kLevelCount = 1; constexpr uint32_t kLevelCount = 1;
@ -223,15 +223,7 @@ namespace {
wgpu::TextureView colorTextureView = colorTexture.CreateView(&descriptor); wgpu::TextureView colorTextureView = colorTexture.CreateView(&descriptor);
wgpu::TextureView depthStencilView = depthStencilTexture.CreateView(&descriptor); wgpu::TextureView depthStencilView = depthStencilTexture.CreateView(&descriptor);
// StoreOps mismatch causing the render pass to error // Base case: StoreOps match so render pass is a success
{
utils::ComboRenderPassDescriptor renderPass({}, depthStencilView);
renderPass.cDepthStencilAttachmentInfo.stencilStoreOp = wgpu::StoreOp::Store;
renderPass.cDepthStencilAttachmentInfo.depthStoreOp = wgpu::StoreOp::Clear;
AssertBeginRenderPassError(&renderPass);
}
// StoreOps match so render pass is a success
{ {
utils::ComboRenderPassDescriptor renderPass({}, depthStencilView); utils::ComboRenderPassDescriptor renderPass({}, depthStencilView);
renderPass.cDepthStencilAttachmentInfo.stencilStoreOp = wgpu::StoreOp::Store; renderPass.cDepthStencilAttachmentInfo.stencilStoreOp = wgpu::StoreOp::Store;
@ -239,13 +231,21 @@ namespace {
AssertBeginRenderPassSuccess(&renderPass); AssertBeginRenderPassSuccess(&renderPass);
} }
// StoreOps match so render pass is a success // Base case: StoreOps match so render pass is a success
{ {
utils::ComboRenderPassDescriptor renderPass({}, depthStencilView); utils::ComboRenderPassDescriptor renderPass({}, depthStencilView);
renderPass.cDepthStencilAttachmentInfo.stencilStoreOp = wgpu::StoreOp::Clear; renderPass.cDepthStencilAttachmentInfo.stencilStoreOp = wgpu::StoreOp::Clear;
renderPass.cDepthStencilAttachmentInfo.depthStoreOp = wgpu::StoreOp::Clear; renderPass.cDepthStencilAttachmentInfo.depthStoreOp = wgpu::StoreOp::Clear;
AssertBeginRenderPassSuccess(&renderPass); AssertBeginRenderPassSuccess(&renderPass);
} }
// StoreOps mismatch still is a success
{
utils::ComboRenderPassDescriptor renderPass({}, depthStencilView);
renderPass.cDepthStencilAttachmentInfo.stencilStoreOp = wgpu::StoreOp::Store;
renderPass.cDepthStencilAttachmentInfo.depthStoreOp = wgpu::StoreOp::Clear;
AssertBeginRenderPassSuccess(&renderPass);
}
} }
// Currently only texture views with arrayLayerCount == 1 are allowed to be color and depth // Currently only texture views with arrayLayerCount == 1 are allowed to be color and depth