Rephrase Format::aspect enum as an enum class mask

Format::aspect should be a mask so that it is easier to iterate over
and test if an aspect is present.

This CL also re-exports wgpu's EnumClassBitMask helpers in dawn_native.
It also adds an EnumMaskIterator which wraps BitSetIterator to allow
iterating over the enums in an enum mask.

Bug: dawn:439
Change-Id: I08180a45b27c6031e2f80b0fa1801716677fd813
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/24682
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Jiawei Shao <jiawei.shao@intel.com>
Commit-Queue: Austin Eng <enga@chromium.org>
This commit is contained in:
Austin Eng 2020-07-30 15:25:37 +00:00 committed by Commit Bot service account
parent 38ba51ce7a
commit b8a56af176
14 changed files with 291 additions and 72 deletions

View File

@ -192,6 +192,8 @@ source_set("dawn_native_sources") {
"DynamicUploader.h",
"EncodingContext.cpp",
"EncodingContext.h",
"EnumClassBitmasks.h",
"EnumMaskIterator.h",
"Error.cpp",
"Error.h",
"ErrorData.cpp",

View File

@ -67,6 +67,8 @@ target_sources(dawn_native PRIVATE
"DynamicUploader.h"
"EncodingContext.cpp"
"EncodingContext.h"
"EnumClassBitmasks.h"
"EnumMaskIterator.h"
"Error.cpp"
"Error.h"
"ErrorData.cpp"

View File

@ -0,0 +1,41 @@
// Copyright 2020 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef DAWNNATIVE_ENUMCLASSBITMASK_H_
#define DAWNNATIVE_ENUMCLASSBITMASK_H_
#include "dawn/EnumClassBitmasks.h"
namespace dawn_native {
// EnumClassBitmmasks is a WebGPU helper in the wgpu:: namespace.
// Re-export it in the dawn_native namespace.
// Specify this for usage with EnumMaskIterator
template <typename T>
struct EnumBitmaskSize {
static constexpr unsigned value = 0;
};
using wgpu::operator|;
using wgpu::operator&;
using wgpu::operator^;
using wgpu::operator~;
using wgpu::operator&=;
using wgpu::operator|=;
using wgpu::operator^=;
} // namespace dawn_native
#endif // DAWNNATIVE_ENUMCLASSBITMASK_H_

View File

@ -0,0 +1,80 @@
// Copyright 2020 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef DAWNNATIVE_ENUMMASKITERATOR_H_
#define DAWNNATIVE_ENUMMASKITERATOR_H_
#include "common/BitSetIterator.h"
#include "dawn_native/EnumClassBitmasks.h"
namespace dawn_native {
template <typename T>
class EnumMaskIterator final {
static constexpr size_t N = EnumBitmaskSize<T>::value;
static_assert(N > 0, "");
using U = std::underlying_type_t<T>;
public:
EnumMaskIterator(const T& mask) : mBitSetIterator(std::bitset<N>(static_cast<U>(mask))) {
}
class Iterator final {
public:
Iterator(const typename BitSetIterator<N, U>::Iterator& iter) : mIter(iter) {
}
Iterator& operator++() {
++mIter;
return *this;
}
bool operator==(const Iterator& other) const {
return mIter == other.mIter;
}
bool operator!=(const Iterator& other) const {
return mIter != other.mIter;
}
T operator*() const {
U value = *mIter;
return static_cast<T>(U(1) << value);
}
private:
typename BitSetIterator<N, U>::Iterator mIter;
};
Iterator begin() const {
return Iterator(mBitSetIterator.begin());
}
Iterator end() const {
return Iterator(mBitSetIterator.end());
}
private:
BitSetIterator<N, U> mBitSetIterator;
};
template <typename T>
EnumMaskIterator<T> IterateEnumMask(const T& mask) {
return EnumMaskIterator<T>(mask);
}
} // namespace dawn_native
#endif // DAWNNATIVE_ENUMMASKITERATOR_H_

View File

@ -13,8 +13,10 @@
// limitations under the License.
#include "dawn_native/Format.h"
#include "dawn_native/Device.h"
#include "dawn_native/Extensions.h"
#include "dawn_native/Texture.h"
#include <bitset>
@ -58,19 +60,19 @@ namespace dawn_native {
}
bool Format::IsColor() const {
return aspect == Aspect::Color;
return aspects == Aspect::Color;
}
bool Format::HasDepth() const {
return aspect == Depth || aspect == DepthStencil;
return (aspects & Aspect::Depth) != 0;
}
bool Format::HasStencil() const {
return aspect == Stencil || aspect == DepthStencil;
return (aspects & Aspect::Stencil) != 0;
}
bool Format::HasDepthOrStencil() const {
return aspect != Color;
return (aspects & (Aspect::Depth | Aspect::Stencil)) != 0;
}
bool Format::HasComponentType(Type componentType) const {
@ -98,7 +100,6 @@ namespace dawn_native {
std::bitset<kKnownFormatCount> formatsSet;
using Type = Format::Type;
using Aspect = Format::Aspect;
auto AddFormat = [&table, &formatsSet](Format format) {
size_t index = ComputeFormatIndex(format.format);
@ -121,7 +122,7 @@ namespace dawn_native {
internalFormat.isCompressed = false;
internalFormat.isSupported = true;
internalFormat.supportsStorageUsage = supportsStorageUsage;
internalFormat.aspect = Aspect::Color;
internalFormat.aspects = Aspect::Color;
internalFormat.type = type;
internalFormat.blockByteSize = byteSize;
internalFormat.blockWidth = 1;
@ -129,7 +130,7 @@ namespace dawn_native {
AddFormat(internalFormat);
};
auto AddDepthStencilFormat = [&AddFormat](wgpu::TextureFormat format, Format::Aspect aspect,
auto AddDepthStencilFormat = [&AddFormat](wgpu::TextureFormat format, Aspect aspects,
uint32_t byteSize) {
Format internalFormat;
internalFormat.format = format;
@ -137,7 +138,7 @@ namespace dawn_native {
internalFormat.isCompressed = false;
internalFormat.isSupported = true;
internalFormat.supportsStorageUsage = false;
internalFormat.aspect = aspect;
internalFormat.aspects = aspects;
internalFormat.type = Type::Other;
internalFormat.blockByteSize = byteSize;
internalFormat.blockWidth = 1;
@ -153,7 +154,7 @@ namespace dawn_native {
internalFormat.isCompressed = false;
internalFormat.isSupported = true;
internalFormat.supportsStorageUsage = false;
internalFormat.aspect = Aspect::Depth;
internalFormat.aspects = Aspect::Depth;
internalFormat.type = type;
internalFormat.blockByteSize = byteSize;
internalFormat.blockWidth = 1;
@ -169,7 +170,7 @@ namespace dawn_native {
internalFormat.isCompressed = true;
internalFormat.isSupported = isSupported;
internalFormat.supportsStorageUsage = false;
internalFormat.aspect = Aspect::Color;
internalFormat.aspects = Aspect::Color;
internalFormat.type = Type::Float;
internalFormat.blockByteSize = byteSize;
internalFormat.blockWidth = width;
@ -232,7 +233,8 @@ namespace dawn_native {
AddDepthStencilFormat(wgpu::TextureFormat::Depth24Plus, Aspect::Depth, 4);
// TODO(cwallez@chromium.org): It isn't clear if this format should be copyable
// because its size isn't well defined, is it 4, 5 or 8?
AddDepthStencilFormat(wgpu::TextureFormat::Depth24PlusStencil8, Aspect::DepthStencil, 4);
AddDepthStencilFormat(wgpu::TextureFormat::Depth24PlusStencil8,
Aspect::Depth | Aspect::Stencil, 4);
// BC compressed formats
bool isBCFormatSupported = device->IsExtensionEnabled(Extension::TextureCompressionBC);

View File

@ -17,12 +17,16 @@
#include "dawn_native/dawn_platform.h"
#include "common/ityp_bitset.h"
#include "dawn_native/Error.h"
#include "dawn_native/EnumClassBitmasks.h"
#include <array>
namespace dawn_native {
enum class Aspect : uint8_t;
class DeviceBase;
// The number of formats Dawn knows about. Asserts in BuildFormatTable ensure that this is the
@ -31,14 +35,7 @@ namespace dawn_native {
// A wgpu::TextureFormat along with all the information about it necessary for validation.
struct Format {
enum Aspect {
Color,
Depth,
Stencil,
DepthStencil,
};
enum Type {
enum class Type {
Float,
Sint,
Uint,
@ -51,8 +48,8 @@ namespace dawn_native {
// A format can be known but not supported because it is part of a disabled extension.
bool isSupported;
bool supportsStorageUsage;
Aspect aspect;
Type type;
Aspect aspects;
uint32_t blockByteSize;
uint32_t blockWidth;

View File

@ -39,14 +39,14 @@ namespace dawn_native {
Format::Type SpirvCrossBaseTypeToFormatType(spirv_cross::SPIRType::BaseType spirvBaseType) {
switch (spirvBaseType) {
case spirv_cross::SPIRType::Float:
return Format::Float;
return Format::Type::Float;
case spirv_cross::SPIRType::Int:
return Format::Sint;
return Format::Type::Sint;
case spirv_cross::SPIRType::UInt:
return Format::Uint;
return Format::Type::Uint;
default:
UNREACHABLE();
return Format::Other;
return Format::Type::Other;
}
}
@ -463,7 +463,7 @@ namespace dawn_native {
UNREACHABLE();
}
mFragmentOutputFormatBaseTypes.fill(Format::Other);
mFragmentOutputFormatBaseTypes.fill(Format::Type::Other);
if (GetDevice()->IsToggleEnabled(Toggle::UseSpvcParser)) {
mSpvcContext.SetUseSpvcParser(true);
}

View File

@ -15,6 +15,8 @@
#ifndef DAWNNATIVE_TEXTURE_H_
#define DAWNNATIVE_TEXTURE_H_
#include "common/ityp_bitset.h"
#include "dawn_native/EnumClassBitmasks.h"
#include "dawn_native/Error.h"
#include "dawn_native/Forward.h"
#include "dawn_native/ObjectBase.h"
@ -24,6 +26,31 @@
#include <vector>
namespace dawn_native {
enum class Aspect : uint8_t {
Color = 0x1,
Depth = 0x2,
Stencil = 0x4,
};
template <>
struct EnumBitmaskSize<Aspect> {
static constexpr unsigned value = 3;
};
} // namespace dawn_native
namespace wgpu {
template <>
struct IsDawnBitmask<dawn_native::Aspect> {
static constexpr bool enable = true;
};
} // namespace wgpu
namespace dawn_native {
MaybeError ValidateTextureDescriptor(const DeviceBase* device,
const TextureDescriptor* descriptor);
MaybeError ValidateTextureViewDescriptor(const TextureBase* texture,

View File

@ -371,7 +371,7 @@ namespace dawn_native { namespace metal {
descriptorMTL.colorAttachments[i].pixelFormat =
MetalPixelFormat(GetColorAttachmentFormat(i));
const ColorStateDescriptor* descriptor = GetColorStateDescriptor(i);
bool isDeclaredInFragmentShader = fragmentOutputBaseTypes[i] != Format::Other;
bool isDeclaredInFragmentShader = fragmentOutputBaseTypes[i] != Format::Type::Other;
ComputeBlendDesc(descriptorMTL.colorAttachments[i], descriptor,
isDeclaredInFragmentShader);
}

View File

@ -630,22 +630,16 @@ namespace dawn_native { namespace opengl {
gl.BindFramebuffer(GL_READ_FRAMEBUFFER, readFBO);
GLenum glAttachment = 0;
switch (format.aspect) {
case Format::Aspect::Color:
glAttachment = GL_COLOR_ATTACHMENT0;
break;
case Format::Aspect::Depth:
glAttachment = GL_DEPTH_ATTACHMENT;
break;
case Format::Aspect::Stencil:
glAttachment = GL_STENCIL_ATTACHMENT;
break;
case Format::Aspect::DepthStencil:
glAttachment = GL_DEPTH_STENCIL_ATTACHMENT;
break;
default:
UNREACHABLE();
break;
if (format.aspects == (Aspect::Depth | Aspect::Stencil)) {
glAttachment = GL_DEPTH_STENCIL_ATTACHMENT;
} else if (format.aspects == Aspect::Depth) {
glAttachment = GL_DEPTH_ATTACHMENT;
} else if (format.aspects == Aspect::Stencil) {
glAttachment = GL_STENCIL_ATTACHMENT;
} else if (format.aspects == Aspect::Color) {
glAttachment = GL_COLOR_ATTACHMENT0;
} else {
UNREACHABLE();
}
gl.BindBuffer(GL_PIXEL_PACK_BUFFER, buffer->GetHandle());
@ -880,19 +874,14 @@ namespace dawn_native { namespace opengl {
GLenum glAttachment = 0;
// TODO(kainino@chromium.org): it may be valid to just always use
// GL_DEPTH_STENCIL_ATTACHMENT here.
switch (format.aspect) {
case Format::Aspect::Depth:
glAttachment = GL_DEPTH_ATTACHMENT;
break;
case Format::Aspect::Stencil:
glAttachment = GL_STENCIL_ATTACHMENT;
break;
case Format::Aspect::DepthStencil:
glAttachment = GL_DEPTH_STENCIL_ATTACHMENT;
break;
default:
UNREACHABLE();
break;
if (format.aspects == (Aspect::Depth | Aspect::Stencil)) {
glAttachment = GL_DEPTH_STENCIL_ATTACHMENT;
} else if (format.aspects == Aspect::Depth) {
glAttachment = GL_DEPTH_ATTACHMENT;
} else if (format.aspects == Aspect::Stencil) {
glAttachment = GL_STENCIL_ATTACHMENT;
} else {
UNREACHABLE();
}
if (textureView->GetTexture()->GetArrayLayers() == 1) {

View File

@ -429,7 +429,7 @@ namespace dawn_native { namespace vulkan {
descriptor->fragmentStage->module->GetFragmentOutputBaseTypes();
for (uint32_t i : IterateBitSet(GetColorAttachmentsMask())) {
const ColorStateDescriptor* colorStateDescriptor = GetColorStateDescriptor(i);
bool isDeclaredInFragmentShader = fragmentOutputBaseTypes[i] != Format::Other;
bool isDeclaredInFragmentShader = fragmentOutputBaseTypes[i] != Format::Type::Other;
colorBlendAttachments[i] =
ComputeColorDesc(colorStateDescriptor, isDeclaredInFragmentShader);
}

View File

@ -17,6 +17,7 @@
#include "common/Assert.h"
#include "common/Math.h"
#include "dawn_native/DynamicUploader.h"
#include "dawn_native/EnumMaskIterator.h"
#include "dawn_native/Error.h"
#include "dawn_native/VulkanBackend.h"
#include "dawn_native/vulkan/AdapterVk.h"
@ -193,20 +194,25 @@ namespace dawn_native { namespace vulkan {
}
// Computes which Vulkan texture aspects are relevant for the given Dawn format
VkImageAspectFlags VulkanAspectMask(const Format& format) {
switch (format.aspect) {
case Format::Aspect::Color:
return VK_IMAGE_ASPECT_COLOR_BIT;
case Format::Aspect::Depth:
return VK_IMAGE_ASPECT_DEPTH_BIT;
case Format::Aspect::Stencil:
return VK_IMAGE_ASPECT_STENCIL_BIT;
case Format::Aspect::DepthStencil:
return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
default:
UNREACHABLE();
return 0;
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,
@ -222,7 +228,7 @@ namespace dawn_native { namespace vulkan {
barrier.oldLayout = VulkanImageLayout(lastUsage, format);
barrier.newLayout = VulkanImageLayout(usage, format);
barrier.image = image;
barrier.subresourceRange.aspectMask = VulkanAspectMask(format);
barrier.subresourceRange.aspectMask = VulkanAspectMask(format.aspects);
barrier.subresourceRange.baseMipLevel = range.baseMipLevel;
barrier.subresourceRange.levelCount = range.levelCount;
barrier.subresourceRange.baseArrayLayer = range.baseArrayLayer;
@ -664,7 +670,7 @@ namespace dawn_native { namespace vulkan {
}
VkImageAspectFlags Texture::GetVkAspectMask() const {
return VulkanAspectMask(GetFormat());
return VulkanAspectMask(GetFormat().aspects);
}
void Texture::TweakTransitionForExternalUsage(CommandRecordingContext* recordingContext,
@ -1007,7 +1013,7 @@ 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());
createInfo.subresourceRange.aspectMask = VulkanAspectMask(GetFormat().aspects);
createInfo.subresourceRange.baseMipLevel = descriptor->baseMipLevel;
createInfo.subresourceRange.levelCount = descriptor->mipLevelCount;
createInfo.subresourceRange.baseArrayLayer = descriptor->baseArrayLayer;

View File

@ -156,6 +156,7 @@ test("dawn_unittests") {
"unittests/BuddyMemoryAllocatorTests.cpp",
"unittests/CommandAllocatorTests.cpp",
"unittests/EnumClassBitmasksTests.cpp",
"unittests/EnumMaskIteratorTests.cpp",
"unittests/ErrorTests.cpp",
"unittests/ExtensionTests.cpp",
"unittests/GetProcAddressTests.cpp",

View File

@ -0,0 +1,72 @@
// Copyright 2020 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "dawn_native/EnumMaskIterator.h"
#include "gtest/gtest.h"
namespace dawn_native {
enum class TestAspect : uint8_t {
Color = 1,
Depth = 2,
Stencil = 4,
};
template <>
struct EnumBitmaskSize<TestAspect> {
static constexpr unsigned value = 3;
};
} // namespace dawn_native
namespace wgpu {
template <>
struct IsDawnBitmask<dawn_native::TestAspect> {
static constexpr bool enable = true;
};
} // namespace wgpu
namespace dawn_native {
static_assert(EnumBitmaskSize<TestAspect>::value == 3, "");
TEST(EnumMaskIteratorTests, None) {
for (TestAspect aspect : IterateEnumMask(static_cast<TestAspect>(0))) {
FAIL();
DAWN_UNUSED(aspect);
}
}
TEST(EnumMaskIteratorTests, All) {
TestAspect expected[] = {TestAspect::Color, TestAspect::Depth, TestAspect::Stencil};
uint32_t i = 0;
TestAspect aspects = TestAspect::Color | TestAspect::Depth | TestAspect::Stencil;
for (TestAspect aspect : IterateEnumMask(aspects)) {
EXPECT_EQ(aspect, expected[i++]);
}
}
TEST(EnumMaskIteratorTests, Partial) {
TestAspect expected[] = {TestAspect::Color, TestAspect::Stencil};
uint32_t i = 0;
TestAspect aspects = TestAspect::Stencil | TestAspect::Color;
for (TestAspect aspect : IterateEnumMask(aspects)) {
EXPECT_EQ(aspect, expected[i++]);
}
}
} // namespace dawn_native