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) {
switch (copy.texture->GetDimension()) {
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:
UNREACHABLE();
return {};
@ -113,36 +113,31 @@ namespace dawn_native {
ASSERT(view->GetLevelCount() == 1);
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
// clear to init the contents to 0's
if (!view->GetTexture()->IsSubresourceContentInitialized(range)) {
if (view->GetTexture()->GetFormat().HasDepth() &&
attachmentInfo.depthLoadOp == wgpu::LoadOp::Load) {
attachmentInfo.clearDepth = 0.0f;
attachmentInfo.depthLoadOp = wgpu::LoadOp::Clear;
}
if (view->GetTexture()->GetFormat().HasStencil() &&
attachmentInfo.stencilLoadOp == wgpu::LoadOp::Load) {
attachmentInfo.clearStencil = 0u;
attachmentInfo.stencilLoadOp = wgpu::LoadOp::Clear;
}
if (!view->GetTexture()->IsSubresourceContentInitialized(depthRange) &&
attachmentInfo.depthLoadOp == wgpu::LoadOp::Load) {
attachmentInfo.clearDepth = 0.0f;
attachmentInfo.depthLoadOp = wgpu::LoadOp::Clear;
}
// If these have different store ops, make them both Store because we can't track
// initialized state separately yet. TODO(crbug.com/dawn/145)
if (attachmentInfo.depthStoreOp != attachmentInfo.stencilStoreOp) {
attachmentInfo.depthStoreOp = wgpu::StoreOp::Store;
attachmentInfo.stencilStoreOp = wgpu::StoreOp::Store;
if (!view->GetTexture()->IsSubresourceContentInitialized(stencilRange) &&
attachmentInfo.stencilLoadOp == wgpu::LoadOp::Load) {
attachmentInfo.clearStencil = 0u;
attachmentInfo.stencilLoadOp = wgpu::LoadOp::Clear;
}
if (attachmentInfo.depthStoreOp == wgpu::StoreOp::Store &&
attachmentInfo.stencilStoreOp == wgpu::StoreOp::Store) {
view->GetTexture()->SetIsSubresourceContentInitialized(true, range);
} else {
ASSERT(attachmentInfo.depthStoreOp == wgpu::StoreOp::Clear &&
attachmentInfo.stencilStoreOp == wgpu::StoreOp::Clear);
view->GetTexture()->SetIsSubresourceContentInitialized(false, range);
}
view->GetTexture()->SetIsSubresourceContentInitialized(
attachmentInfo.depthStoreOp == wgpu::StoreOp::Store, depthRange);
view->GetTexture()->SetIsSubresourceContentInitialized(
attachmentInfo.stencilStoreOp == wgpu::StoreOp::Store, stencilRange);
}
}

View File

@ -384,12 +384,6 @@ namespace dawn_native {
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
// do not need to validate the sample count of the depth stencil attachment.
const uint32_t depthStencilSampleCount = attachment->GetTexture()->GetSampleCount();
@ -732,7 +726,8 @@ namespace dawn_native {
copy->destination.texture = destination->texture;
copy->destination.origin = destination->origin;
copy->destination.mipLevel = destination->mipLevel;
copy->destination.aspect = destination->aspect;
copy->destination.aspect =
ConvertAspect(destination->texture->GetFormat(), destination->aspect);
copy->copySize = *copySize;
return {};
@ -795,7 +790,7 @@ namespace dawn_native {
copy->source.texture = source->texture;
copy->source.origin = source->origin;
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.offset = destination->layout.offset;
copy->destination.bytesPerRow = bytesPerRow;
@ -844,11 +839,12 @@ namespace dawn_native {
copy->source.texture = source->texture;
copy->source.origin = source->origin;
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.origin = destination->origin;
copy->destination.mipLevel = destination->mipLevel;
copy->destination.aspect = destination->aspect;
copy->destination.aspect =
ConvertAspect(destination->texture->GetFormat(), destination->aspect);
copy->copySize = *copySize;
return {};

View File

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

View File

@ -179,10 +179,13 @@ namespace dawn_native {
uint32_t baseMipLevel,
uint32_t levelCount,
uint32_t baseArrayLayer,
uint32_t layerCount) {
uint32_t layerCount,
WGPUTextureAspect aspect) {
dawn_native::TextureBase* textureBase =
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);
}

View File

@ -36,6 +36,13 @@ namespace dawn_native {
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
#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 {
return ComputeFormatIndex(format);
}

View File

@ -67,6 +67,7 @@ namespace dawn_native {
bool HasComponentType(Type componentType) 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
// in [0, kKnownFormatCount)

View File

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

View File

@ -20,6 +20,7 @@
#include "common/Constants.h"
#include "common/Math.h"
#include "dawn_native/Device.h"
#include "dawn_native/EnumMaskIterator.h"
#include "dawn_native/PassResourceUsage.h"
#include "dawn_native/ValidationUtils_autogen.h"
@ -200,6 +201,11 @@ namespace dawn_native {
return {};
}
uint8_t GetPlaneIndex(Aspect aspect) {
ASSERT(HasOneBit(aspect));
return static_cast<uint8_t>(Log2(static_cast<uint32_t>(aspect)));
}
} // anonymous namespace
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
SubresourceRange SubresourceRange::SingleSubresource(uint32_t baseMipLevel,
uint32_t baseArrayLayer) {
return {baseMipLevel, 1, baseArrayLayer, 1};
SubresourceRange SubresourceRange::SingleMipAndLayer(uint32_t baseMipLevel,
uint32_t baseArrayLayer,
Aspect aspects) {
return {baseMipLevel, 1, baseArrayLayer, 1, aspects};
}
// TextureBase
@ -376,7 +405,13 @@ namespace dawn_native {
mSampleCount(descriptor->sampleCount),
mUsage(descriptor->usage),
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);
// 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 {
ASSERT(!IsError());
return {0, mMipLevelCount, 0, GetArrayLayers()};
return {0, mMipLevelCount, 0, GetArrayLayers(), mFormat.aspects};
}
uint32_t TextureBase::GetSampleCount() const {
ASSERT(!IsError());
@ -446,7 +481,7 @@ namespace dawn_native {
}
uint32_t TextureBase::GetSubresourceCount() const {
ASSERT(!IsError());
return mMipLevelCount * mSize.depth;
return static_cast<uint32_t>(mIsSubresourceContentInitializedAtIndex.size());
}
wgpu::TextureUsage TextureBase::GetUsage() const {
ASSERT(!IsError());
@ -458,25 +493,32 @@ namespace dawn_native {
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(mipLevel <= kMaxTexture2DMipLevels);
ASSERT(HasOneBit(aspect));
static_assert(kMaxTexture2DMipLevels <=
std::numeric_limits<uint32_t>::max() / kMaxTexture2DArrayLayers,
"texture size overflows uint32_t");
return GetNumMipLevels() * arraySlice + mipLevel;
return mipLevel +
GetNumMipLevels() *
(arraySlice + GetArrayLayers() * mPlaneIndices[GetPlaneIndex(aspect)]);
}
bool TextureBase::IsSubresourceContentInitialized(const SubresourceRange& range) const {
ASSERT(!IsError());
for (uint32_t arrayLayer = range.baseArrayLayer;
arrayLayer < range.baseArrayLayer + range.layerCount; ++arrayLayer) {
for (uint32_t mipLevel = range.baseMipLevel;
mipLevel < range.baseMipLevel + range.levelCount; ++mipLevel) {
uint32_t subresourceIndex = GetSubresourceIndex(mipLevel, arrayLayer);
ASSERT(subresourceIndex < mIsSubresourceContentInitializedAtIndex.size());
if (!mIsSubresourceContentInitializedAtIndex[subresourceIndex]) {
return false;
for (Aspect aspect : IterateEnumMask(range.aspects)) {
for (uint32_t arrayLayer = range.baseArrayLayer;
arrayLayer < range.baseArrayLayer + range.layerCount; ++arrayLayer) {
for (uint32_t mipLevel = range.baseMipLevel;
mipLevel < range.baseMipLevel + range.levelCount; ++mipLevel) {
uint32_t subresourceIndex = GetSubresourceIndex(mipLevel, arrayLayer, aspect);
ASSERT(subresourceIndex < mIsSubresourceContentInitializedAtIndex.size());
if (!mIsSubresourceContentInitializedAtIndex[subresourceIndex]) {
return false;
}
}
}
}
@ -486,13 +528,15 @@ namespace dawn_native {
void TextureBase::SetIsSubresourceContentInitialized(bool isInitialized,
const SubresourceRange& range) {
ASSERT(!IsError());
for (uint32_t arrayLayer = range.baseArrayLayer;
arrayLayer < range.baseArrayLayer + range.layerCount; ++arrayLayer) {
for (uint32_t mipLevel = range.baseMipLevel;
mipLevel < range.baseMipLevel + range.levelCount; ++mipLevel) {
uint32_t subresourceIndex = GetSubresourceIndex(mipLevel, arrayLayer);
ASSERT(subresourceIndex < mIsSubresourceContentInitializedAtIndex.size());
mIsSubresourceContentInitializedAtIndex[subresourceIndex] = isInitialized;
for (Aspect aspect : IterateEnumMask(range.aspects)) {
for (uint32_t arrayLayer = range.baseArrayLayer;
arrayLayer < range.baseArrayLayer + range.layerCount; ++arrayLayer) {
for (uint32_t mipLevel = range.baseMipLevel;
mipLevel < range.baseMipLevel + range.levelCount; ++mipLevel) {
uint32_t subresourceIndex = GetSubresourceIndex(mipLevel, arrayLayer, aspect);
ASSERT(subresourceIndex < mIsSubresourceContentInitializedAtIndex.size());
mIsSubresourceContentInitializedAtIndex[subresourceIndex] = isInitialized;
}
}
}
}
@ -588,7 +632,9 @@ namespace dawn_native {
mFormat(GetDevice()->GetValidInternalFormat(descriptor->format)),
mDimension(descriptor->dimension),
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)

View File

@ -15,6 +15,7 @@
#ifndef DAWNNATIVE_TEXTURE_H_
#define DAWNNATIVE_TEXTURE_H_
#include "common/ityp_array.h"
#include "common/ityp_bitset.h"
#include "dawn_native/EnumClassBitmasks.h"
#include "dawn_native/Error.h"
@ -27,7 +28,11 @@
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 {
None = 0x0,
Color = 0x1,
Depth = 0x2,
Stencil = 0x4,
@ -73,13 +78,19 @@ namespace dawn_native {
wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::Storage |
wgpu::TextureUsage::OutputAttachment;
Aspect ConvertSingleAspect(const Format& format, wgpu::TextureAspect aspect);
Aspect ConvertAspect(const Format& format, wgpu::TextureAspect aspect);
struct SubresourceRange {
uint32_t baseMipLevel;
uint32_t levelCount;
uint32_t baseArrayLayer;
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 {
@ -103,7 +114,7 @@ namespace dawn_native {
uint32_t GetSubresourceCount() const;
wgpu::TextureUsage GetUsage() 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;
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
std::vector<bool> mIsSubresourceContentInitializedAtIndex;
std::array<uint8_t, EnumBitmaskSize<Aspect>::value> mPlaneIndices;
};
class TextureViewBase : public ObjectBase {

View File

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

View File

@ -86,12 +86,14 @@ namespace dawn_native { namespace d3d12 {
D3D12EndingAccessResolveSubresourceParameters(TextureView* resolveDestination) {
D3D12_RENDER_PASS_ENDING_ACCESS_RESOLVE_SUBRESOURCE_PARAMETERS subresourceParameters;
Texture* resolveDestinationTexture = ToBackend(resolveDestination->GetTexture());
ASSERT(resolveDestinationTexture->GetFormat().aspects == Aspect::Color);
subresourceParameters.DstX = 0;
subresourceParameters.DstY = 0;
subresourceParameters.SrcSubresource = 0;
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
// 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

View File

@ -17,6 +17,7 @@
#include "common/Constants.h"
#include "common/Math.h"
#include "dawn_native/DynamicUploader.h"
#include "dawn_native/EnumMaskIterator.h"
#include "dawn_native/Error.h"
#include "dawn_native/d3d12/BufferD3D12.h"
#include "dawn_native/d3d12/CommandRecordingContext.h"
@ -574,7 +575,15 @@ namespace dawn_native { namespace d3d12 {
}
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);
if (barriers.size()) {
@ -652,19 +661,6 @@ namespace dawn_native { namespace d3d12 {
barrier.Transition.Subresource =
allSubresources ? D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES : index;
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;
}
@ -686,7 +682,6 @@ namespace dawn_native { namespace d3d12 {
HandleTransitionSpecialCases(commandContext);
const Serial pendingCommandSerial = ToBackend(GetDevice())->GetPendingCommandSerial();
uint32_t subresourceCount = GetSubresourceCount();
// This transitions assume it is a 2D texture
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.
// Note that if the texture has only one mip level and one array slice, it will fall into
// this category.
bool areAllSubresourcesCovered = range.levelCount * range.layerCount == subresourceCount;
bool areAllSubresourcesCovered = (range.levelCount == GetNumMipLevels() && //
range.layerCount == GetArrayLayers() && //
range.aspects == GetFormat().aspects);
if (mSameLastUsagesAcrossSubresources && areAllSubresourcesCovered) {
TransitionSingleOrAllSubresources(barriers, 0, newState, pendingCommandSerial, true);
// TODO(yunchao.he@intel.com): compress and decompress if all subresources have the
// 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];
}
return;
}
for (uint32_t arrayLayer = 0; arrayLayer < range.layerCount; ++arrayLayer) {
for (uint32_t mipLevel = 0; mipLevel < range.levelCount; ++mipLevel) {
uint32_t index = GetSubresourceIndex(range.baseMipLevel + mipLevel,
range.baseArrayLayer + arrayLayer);
for (Aspect aspect : IterateEnumMask(range.aspects)) {
for (uint32_t arrayLayer = 0; arrayLayer < range.layerCount; ++arrayLayer) {
for (uint32_t mipLevel = 0; mipLevel < range.levelCount; ++mipLevel) {
uint32_t index = GetSubresourceIndex(range.baseMipLevel + mipLevel,
range.baseArrayLayer + arrayLayer, aspect);
TransitionSingleOrAllSubresources(barriers, index, newState, pendingCommandSerial,
false);
TransitionSingleOrAllSubresources(barriers, index, newState,
pendingCommandSerial, false);
}
}
}
mSameLastUsagesAcrossSubresources = areAllSubresourcesCovered;
@ -748,20 +747,22 @@ namespace dawn_native { namespace d3d12 {
return;
}
for (uint32_t arrayLayer = 0; arrayLayer < GetArrayLayers(); ++arrayLayer) {
for (uint32_t mipLevel = 0; mipLevel < GetNumMipLevels(); ++mipLevel) {
uint32_t index = GetSubresourceIndex(mipLevel, arrayLayer);
for (Aspect aspect : IterateEnumMask(GetFormat().aspects)) {
for (uint32_t arrayLayer = 0; arrayLayer < GetArrayLayers(); ++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
if (textureUsages.subresourceUsages[index] == wgpu::TextureUsage::None) {
continue;
// Skip if this subresource is not used during the current pass
if (textureUsages.subresourceUsages[index] == wgpu::TextureUsage::None) {
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;
@ -838,16 +839,34 @@ namespace dawn_native { namespace d3d12 {
if (GetFormat().HasDepthOrStencil()) {
TrackUsageAndTransitionNow(commandContext, D3D12_RESOURCE_STATE_DEPTH_WRITE, range);
D3D12_CLEAR_FLAGS clearFlags = {};
for (uint32_t level = range.baseMipLevel;
level < range.baseMipLevel + range.levelCount; ++level) {
for (uint32_t layer = range.baseArrayLayer;
layer < range.baseArrayLayer + range.layerCount; ++layer) {
if (clearValue == TextureBase::ClearValue::Zero &&
IsSubresourceContentInitialized(
SubresourceRange::SingleSubresource(level, layer))) {
// Skip lazy clears if already initialized.
// Iterate the aspects individually to determine which clear flags to use.
D3D12_CLEAR_FLAGS clearFlags = {};
for (Aspect aspect : IterateEnumMask(range.aspects)) {
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;
}
@ -860,13 +879,6 @@ namespace dawn_native { namespace d3d12 {
device->GetD3D12Device()->CreateDepthStencilView(GetD3D12Resource(),
&dsvDesc, baseDescriptor);
if (GetFormat().HasDepth()) {
clearFlags |= D3D12_CLEAR_FLAG_DEPTH;
}
if (GetFormat().HasStencil()) {
clearFlags |= D3D12_CLEAR_FLAG_STENCIL;
}
commandList->ClearDepthStencilView(baseDescriptor, clearFlags, fClearColor,
clearColor, 0, nullptr);
}
@ -878,13 +890,14 @@ namespace dawn_native { namespace d3d12 {
const float clearColorRGBA[4] = {fClearColor, fClearColor, fClearColor,
fClearColor};
ASSERT(range.aspects == Aspect::Color);
for (uint32_t level = range.baseMipLevel;
level < range.baseMipLevel + range.levelCount; ++level) {
for (uint32_t layer = range.baseArrayLayer;
layer < range.baseArrayLayer + range.layerCount; ++layer) {
if (clearValue == TextureBase::ClearValue::Zero &&
IsSubresourceContentInitialized(
SubresourceRange::SingleSubresource(level, layer))) {
SubresourceRange::SingleMipAndLayer(level, layer, Aspect::Color))) {
// Skip lazy clears if already initialized.
continue;
}
@ -920,6 +933,7 @@ namespace dawn_native { namespace d3d12 {
TrackUsageAndTransitionNow(commandContext, D3D12_RESOURCE_STATE_COPY_DEST, range);
ASSERT(range.aspects == Aspect::Color);
for (uint32_t level = range.baseMipLevel; level < range.baseMipLevel + range.levelCount;
++level) {
// compute d3d12 texture copy locations for texture and buffer
@ -934,13 +948,13 @@ namespace dawn_native { namespace d3d12 {
layer < range.baseArrayLayer + range.layerCount; ++layer) {
if (clearValue == TextureBase::ClearValue::Zero &&
IsSubresourceContentInitialized(
SubresourceRange::SingleSubresource(level, layer))) {
SubresourceRange::SingleMipAndLayer(level, layer, Aspect::Color))) {
// Skip lazy clears if already initialized.
continue;
}
D3D12_TEXTURE_COPY_LOCATION textureLocation =
ComputeTextureCopyLocationForTexture(this, level, layer);
ComputeTextureCopyLocationForTexture(this, level, layer, Aspect::Color);
for (uint32_t i = 0; i < copySplit.count; ++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,
uint32_t level,
uint32_t slice) {
uint32_t slice,
Aspect aspect) {
D3D12_TEXTURE_COPY_LOCATION copyLocation;
copyLocation.pResource = texture->GetD3D12Resource();
copyLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
copyLocation.SubresourceIndex = texture->GetSubresourceIndex(level, slice);
copyLocation.SubresourceIndex = texture->GetSubresourceIndex(level, slice, aspect);
return copyLocation;
}

View File

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

View File

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

View File

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

View File

@ -53,7 +53,7 @@ namespace dawn_native { namespace metal {
const TextureCopy& dst,
const Extent3D& size);
MTLBlitOption ComputeMTLBlitOption(const Format& format, wgpu::TextureAspect aspect);
MTLBlitOption ComputeMTLBlitOption(const Format& format, Aspect aspect);
}} // 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;
if ((format.aspects & kDepthStencil) == kDepthStencil) {
// We only provide a blit option if the format has both depth and stencil.
// It is invalid to provide a blit option otherwise.
switch (aspect) {
case wgpu::TextureAspect::DepthOnly:
case Aspect::Depth:
return MTLBlitOptionDepthFromDepthStencil;
case wgpu::TextureAspect::StencilOnly:
case Aspect::Stencil:
return MTLBlitOptionStencilFromDepthStencil;
default:
UNREACHABLE();

View File

@ -525,8 +525,8 @@ namespace dawn_native { namespace opengl {
buffer->EnsureDataInitialized();
ASSERT(texture->GetDimension() == wgpu::TextureDimension::e2D);
SubresourceRange subresources = {dst.mipLevel, 1, dst.origin.z,
copy->copySize.depth};
SubresourceRange subresources =
GetSubresourcesAffectedByCopy(dst, copy->copySize);
if (IsCompleteSubresourceCopiedTo(texture, copySize, dst.mipLevel)) {
texture->SetIsSubresourceContentInitialized(true, subresources);
} else {
@ -618,8 +618,8 @@ namespace dawn_native { namespace opengl {
buffer->EnsureDataInitializedAsDestination(copy);
ASSERT(texture->GetDimension() == wgpu::TextureDimension::e2D);
SubresourceRange subresources = {src.mipLevel, 1, src.origin.z,
copy->copySize.depth};
SubresourceRange subresources =
GetSubresourcesAffectedByCopy(src, copy->copySize);
texture->EnsureSubresourceContentInitialized(subresources);
// 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.
@ -699,10 +699,9 @@ namespace dawn_native { namespace opengl {
Extent3D copySize = ComputeTextureCopyExtent(dst, copy->copySize);
Texture* srcTexture = ToBackend(src.texture.Get());
Texture* dstTexture = ToBackend(dst.texture.Get());
SubresourceRange srcRange = {src.mipLevel, 1, src.origin.z,
copy->copySize.depth};
SubresourceRange dstRange = {dst.mipLevel, 1, dst.origin.z,
copy->copySize.depth};
SubresourceRange srcRange = GetSubresourcesAffectedByCopy(src, copy->copySize);
SubresourceRange dstRange = GetSubresourcesAffectedByCopy(dst, copy->copySize);
srcTexture->EnsureSubresourceContentInitialized(srcRange);
if (IsCompleteSubresourceCopiedTo(dstTexture, copySize, dst.mipLevel)) {

View File

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

View File

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

View File

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

View File

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

View File

@ -193,28 +193,6 @@ namespace dawn_native { namespace vulkan {
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,
const VkImage& image,
wgpu::TextureUsage lastUsage,
@ -597,7 +575,7 @@ namespace dawn_native { namespace vulkan {
// Don't clear imported texture if already cleared
if (descriptor->isCleared) {
SetIsSubresourceContentInitialized(true, {0, 1, 0, 1});
SetIsSubresourceContentInitialized(true, GetAllSubresources());
}
// Success, acquire all the external objects.
@ -700,7 +678,7 @@ namespace dawn_native { namespace vulkan {
if (barriers->size() == transitionBarrierStart) {
barriers->push_back(BuildMemoryBarrier(
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
@ -714,7 +692,7 @@ namespace dawn_native { namespace vulkan {
if (barriers->size() == transitionBarrierStart) {
barriers->push_back(BuildMemoryBarrier(
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
@ -781,24 +759,40 @@ namespace dawn_native { namespace vulkan {
} else {
for (uint32_t arrayLayer = 0; arrayLayer < GetArrayLayers(); ++arrayLayer) {
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.
if (textureUsages.subresourceUsages[index] == wgpu::TextureUsage::None) {
if (usage == wgpu::TextureUsage::None) {
continue;
}
if (CanReuseWithoutBarrier(mSubresourceLastUsages[index],
textureUsages.subresourceUsages[index])) {
if (CanReuseWithoutBarrier(lastUsage, usage)) {
continue;
}
imageBarriers->push_back(BuildMemoryBarrier(
format, mHandle, mSubresourceLastUsages[index],
textureUsages.subresourceUsages[index],
SubresourceRange::SingleSubresource(mipLevel, arrayLayer)));
allLastUsages |= mSubresourceLastUsages[index];
allUsages |= textureUsages.subresourceUsages[index];
mSubresourceLastUsages[index] = textureUsages.subresourceUsages[index];
allLastUsages |= lastUsage;
allUsages |= usage;
for (Aspect aspect : IterateEnumMask(GetFormat().aspects)) {
uint32_t index = GetSubresourceIndex(mipLevel, arrayLayer, aspect);
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();
wgpu::TextureUsage allLastUsages = wgpu::TextureUsage::None;
uint32_t subresourceCount = GetSubresourceCount();
// This transitions assume it is a 2D texture
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.
// Note that if the texture has only one mip level and one array slice, it will fall into
// this category.
bool areAllSubresourcesCovered = range.levelCount * range.layerCount == subresourceCount;
bool areAllSubresourcesCovered = (range.levelCount == GetNumMipLevels() && //
range.layerCount == GetArrayLayers() && //
range.aspects == format.aspects);
if (mSameLastUsagesAcrossSubresources && areAllSubresourcesCovered) {
ASSERT(range.baseMipLevel == 0 && range.baseArrayLayer == 0);
if (CanReuseWithoutBarrier(mSubresourceLastUsages[0], usage)) {
@ -838,7 +833,7 @@ namespace dawn_native { namespace vulkan {
barriers.push_back(
BuildMemoryBarrier(format, mHandle, mSubresourceLastUsages[0], usage, range));
allLastUsages = mSubresourceLastUsages[0];
for (uint32_t i = 0; i < subresourceCount; ++i) {
for (uint32_t i = 0; i < GetSubresourceCount(); ++i) {
mSubresourceLastUsages[i] = usage;
}
} else {
@ -846,17 +841,29 @@ namespace dawn_native { namespace vulkan {
layer < range.baseArrayLayer + range.layerCount; ++layer) {
for (uint32_t level = range.baseMipLevel;
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;
}
barriers.push_back(
BuildMemoryBarrier(format, mHandle, mSubresourceLastUsages[index], usage,
SubresourceRange::SingleSubresource(level, layer)));
allLastUsages |= mSubresourceLastUsages[index];
mSubresourceLastUsages[index] = usage;
allLastUsages |= lastUsage;
for (Aspect aspect : IterateEnumMask(format.aspects)) {
uint32_t index = GetSubresourceIndex(level, layer, aspect);
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);
if (GetFormat().isRenderable) {
VkImageSubresourceRange imageRange = {};
imageRange.aspectMask = GetVkAspectMask(wgpu::TextureAspect::All);
imageRange.levelCount = 1;
imageRange.layerCount = 1;
@ -894,16 +900,25 @@ namespace dawn_native { namespace vulkan {
imageRange.baseMipLevel = level;
for (uint32_t layer = range.baseArrayLayer;
layer < range.baseArrayLayer + range.layerCount; ++layer) {
if (clearValue == TextureBase::ClearValue::Zero &&
IsSubresourceContentInitialized(
SubresourceRange::SingleSubresource(level, layer))) {
// Skip lazy clears if already initialized.
Aspect aspects = Aspect::None;
for (Aspect aspect : IterateEnumMask(range.aspects)) {
if (clearValue == TextureBase::ClearValue::Zero &&
IsSubresourceContentInitialized(
SubresourceRange::SingleMipAndLayer(level, layer, aspect))) {
// Skip lazy clears if already initialized.
continue;
}
aspects |= aspect;
}
if (aspects == Aspect::None) {
continue;
}
imageRange.aspectMask = VulkanAspectMask(aspects);
imageRange.baseArrayLayer = layer;
if (GetFormat().HasDepthOrStencil()) {
if (aspects & (Aspect::Depth | Aspect::Stencil)) {
VkClearDepthStencilValue clearDepthStencilValue[1];
clearDepthStencilValue[0].depth = fClearColor;
clearDepthStencilValue[0].stencil = clearColor;
@ -912,6 +927,7 @@ namespace dawn_native { namespace vulkan {
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, clearDepthStencilValue, 1,
&imageRange);
} else {
ASSERT(aspects == Aspect::Color);
VkClearColorValue clearColorValue = {
{fClearColor, fClearColor, fClearColor, fClearColor}};
device->fn.CmdClearColorImage(recordingContext->commandBuffer, GetHandle(),
@ -943,6 +959,7 @@ namespace dawn_native { namespace vulkan {
bufferCopy.offset = uploadHandle.startOffset;
bufferCopy.bytesPerRow = bytesPerRow;
ASSERT(range.aspects == Aspect::Color);
for (uint32_t level = range.baseMipLevel; level < range.baseMipLevel + range.levelCount;
++level) {
Extent3D copySize = GetMipLevelVirtualSize(level);
@ -951,7 +968,7 @@ namespace dawn_native { namespace vulkan {
layer < range.baseArrayLayer + range.layerCount; ++layer) {
if (clearValue == TextureBase::ClearValue::Zero &&
IsSubresourceContentInitialized(
SubresourceRange::SingleSubresource(level, layer))) {
SubresourceRange::SingleMipAndLayer(level, layer, Aspect::Color))) {
// Skip lazy clears if already initialized.
continue;
}
@ -961,7 +978,7 @@ namespace dawn_native { namespace vulkan {
textureCopy.texture = this;
textureCopy.origin = {0, 0, layer};
textureCopy.mipLevel = level;
textureCopy.aspect = wgpu::TextureAspect::All;
textureCopy.aspect = GetFormat().aspects;
VkBufferImageCopy region =
ComputeBufferImageCopyRegion(bufferCopy, textureCopy, copySize);
@ -1028,11 +1045,13 @@ namespace dawn_native { namespace vulkan {
createInfo.format = VulkanImageFormat(device, descriptor->format);
createInfo.components = VkComponentMapping{VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G,
VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A};
createInfo.subresourceRange.aspectMask = VulkanAspectMask(GetFormat().aspects);
createInfo.subresourceRange.baseMipLevel = descriptor->baseMipLevel;
createInfo.subresourceRange.levelCount = descriptor->mipLevelCount;
createInfo.subresourceRange.baseArrayLayer = descriptor->baseArrayLayer;
createInfo.subresourceRange.layerCount = descriptor->arrayLayerCount;
const SubresourceRange& subresources = GetSubresourceRange();
createInfo.subresourceRange.baseMipLevel = subresources.baseMipLevel;
createInfo.subresourceRange.levelCount = subresources.levelCount;
createInfo.subresourceRange.baseArrayLayer = subresources.baseArrayLayer;
createInfo.subresourceRange.layerCount = subresources.layerCount;
createInfo.subresourceRange.aspectMask = VulkanAspectMask(subresources.aspects);
return CheckVkSuccess(
device->fn.CreateImageView(device->GetVkDevice(), &createInfo, nullptr, &*mHandle),

View File

@ -15,6 +15,7 @@
#include "dawn_native/vulkan/UtilsVulkan.h"
#include "common/Assert.h"
#include "dawn_native/EnumMaskIterator.h"
#include "dawn_native/Format.h"
#include "dawn_native/vulkan/Forward.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
// 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
@ -91,7 +114,7 @@ namespace dawn_native { namespace vulkan {
dataLayout.bytesPerRow / blockInfo.blockByteSize * blockInfo.blockWidth;
region.bufferImageHeight = dataLayout.rowsPerImage;
region.imageSubresource.aspectMask = texture->GetVkAspectMask(textureCopy.aspect);
region.imageSubresource.aspectMask = VulkanAspectMask(textureCopy.aspect);
region.imageSubresource.mipLevel = textureCopy.mipLevel;
switch (textureCopy.texture->GetDimension()) {

View File

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

View File

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

View File

@ -62,9 +62,9 @@ class TextureZeroInitTest : public DawnTest {
descriptor.dimension = wgpu::TextureViewDimension::e2D;
return descriptor;
}
wgpu::RenderPipeline CreatePipelineForTest() {
wgpu::RenderPipeline CreatePipelineForTest(float depth = 0.f) {
utils::ComboRenderPipelineDescriptor pipelineDescriptor(device);
pipelineDescriptor.vertexStage.module = CreateBasicVertexShaderForTest();
pipelineDescriptor.vertexStage.module = CreateBasicVertexShaderForTest(depth);
const char* fs =
R"(#version 450
layout(location = 0) out vec4 fragColor;
@ -80,8 +80,8 @@ class TextureZeroInitTest : public DawnTest {
return device.CreateRenderPipeline(&pipelineDescriptor);
}
wgpu::ShaderModule CreateBasicVertexShaderForTest() {
return utils::CreateShaderModule(device, utils::SingleShaderStage::Vertex, R"(#version 450
wgpu::ShaderModule CreateBasicVertexShaderForTest(float depth = 0.f) {
std::string source = R"(#version 450
const vec2 pos[6] = vec2[6](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() {
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() {
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));
}
// 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
TEST_P(TextureZeroInitTest, ColorAttachmentsClear) {
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) {
constexpr uint32_t kArrayLayers = 1;
constexpr uint32_t kLevelCount = 1;
@ -223,15 +223,7 @@ namespace {
wgpu::TextureView colorTextureView = colorTexture.CreateView(&descriptor);
wgpu::TextureView depthStencilView = depthStencilTexture.CreateView(&descriptor);
// StoreOps mismatch causing the render pass to error
{
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
// Base case: StoreOps match so render pass is a success
{
utils::ComboRenderPassDescriptor renderPass({}, depthStencilView);
renderPass.cDepthStencilAttachmentInfo.stencilStoreOp = wgpu::StoreOp::Store;
@ -239,13 +231,21 @@ namespace {
AssertBeginRenderPassSuccess(&renderPass);
}
// StoreOps match so render pass is a success
// Base case: StoreOps match so render pass is a success
{
utils::ComboRenderPassDescriptor renderPass({}, depthStencilView);
renderPass.cDepthStencilAttachmentInfo.stencilStoreOp = wgpu::StoreOp::Clear;
renderPass.cDepthStencilAttachmentInfo.depthStoreOp = wgpu::StoreOp::Clear;
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