Add checks on the texture view used as color or depth stencil attachment

This patch adds checks when we set a texture view as color or depth
stencil attachments:
1. The mipmap level of the texture view must be 1 as it is limited in
   D3D12, Metal and Vulkan.
2. The array layer count of the texture view must be 1 as currently we
   do not plan to support layered rendering in WebGPU.
3. The format of the texture view must be color renderable when it is
   used as a color attachment.
4. The format of the texture view must be a depth stencil format when it
   is used as a depth stencil attachment.

BUG=dawn:16
TEST=dawn_unittests

Change-Id: Ibce3bda20d49a725c26796aa627c5067532761ad
Reviewed-on: https://dawn-review.googlesource.com/c/2661
Commit-Queue: Jiawei Shao <jiawei.shao@intel.com>
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
This commit is contained in:
Jiawei Shao 2018-11-28 02:44:17 +00:00 committed by Commit Bot service account
parent 0bd32409b7
commit cf714a81c8
5 changed files with 307 additions and 11 deletions

View File

@ -83,6 +83,24 @@ namespace dawn_native {
RenderPassDescriptorBuilder::RenderPassDescriptorBuilder(DeviceBase* device) : Builder(device) {
}
bool RenderPassDescriptorBuilder::CheckArrayLayersAndLevelCountForAttachment(
const TextureViewBase* textureView) {
// Currently we do not support layered rendering.
if (textureView->GetLayerCount() > 1) {
HandleError(
"The layer count of the texture view used as attachment cannot be greater than 1");
return false;
}
if (textureView->GetLevelCount() > 1) {
HandleError(
"The mipmap level count of the texture view used as attachment cannot be greater "
"than 1");
return false;
}
return true;
}
RenderPassDescriptorBase* RenderPassDescriptorBuilder::GetResultImpl() {
auto CheckOrSetSize = [this](const TextureViewBase* attachment) -> bool {
if (this->mWidth == 0) {
@ -133,8 +151,13 @@ namespace dawn_native {
return;
}
if (TextureFormatHasDepthOrStencil(textureView->GetTexture()->GetFormat())) {
HandleError("Using depth stencil texture as color attachment");
if (!IsColorRenderableTextureFormat(textureView->GetFormat())) {
HandleError(
"The format of the texture view used as color attachment is not color renderable");
return;
}
if (!CheckArrayLayersAndLevelCountForAttachment(textureView)) {
return;
}
@ -162,8 +185,14 @@ namespace dawn_native {
void RenderPassDescriptorBuilder::SetDepthStencilAttachment(TextureViewBase* textureView,
dawn::LoadOp depthLoadOp,
dawn::LoadOp stencilLoadOp) {
if (!TextureFormatHasDepthOrStencil(textureView->GetTexture()->GetFormat())) {
HandleError("Using color texture as depth stencil attachment");
if (!TextureFormatHasDepthOrStencil(textureView->GetFormat())) {
HandleError(
"The format of the texture view used as depth stencil attachment is not a depth "
"stencil format");
return;
}
if (!CheckArrayLayersAndLevelCountForAttachment(textureView)) {
return;
}

View File

@ -94,6 +94,8 @@ namespace dawn_native {
private:
friend class RenderPassDescriptorBase;
bool CheckArrayLayersAndLevelCountForAttachment(const TextureViewBase* textureView);
std::bitset<kMaxColorAttachments> mColorAttachmentsSet;
std::array<RenderPassColorAttachmentInfo, kMaxColorAttachments> mColorAttachments;

View File

@ -230,6 +230,26 @@ namespace dawn_native {
}
}
bool IsColorRenderableTextureFormat(dawn::TextureFormat format) {
switch (format) {
case dawn::TextureFormat::B8G8R8A8Unorm:
case dawn::TextureFormat::R8G8B8A8Uint:
case dawn::TextureFormat::R8G8B8A8Unorm:
case dawn::TextureFormat::R8G8Uint:
case dawn::TextureFormat::R8G8Unorm:
case dawn::TextureFormat::R8Uint:
case dawn::TextureFormat::R8Unorm:
return true;
case dawn::TextureFormat::D32FloatS8Uint:
return false;
default:
UNREACHABLE();
return false;
}
}
// TextureBase
TextureBase::TextureBase(DeviceBase* device, const TextureDescriptor* descriptor)
@ -277,7 +297,11 @@ namespace dawn_native {
// TextureViewBase
TextureViewBase::TextureViewBase(TextureBase* texture, const TextureViewDescriptor* descriptor)
: ObjectBase(texture->GetDevice()), mTexture(texture) {
: ObjectBase(texture->GetDevice()),
mTexture(texture),
mFormat(descriptor->format),
mLevelCount(descriptor->levelCount),
mLayerCount(descriptor->layerCount) {
}
const TextureBase* TextureViewBase::GetTexture() const {
@ -288,4 +312,15 @@ namespace dawn_native {
return mTexture.Get();
}
dawn::TextureFormat TextureViewBase::GetFormat() const {
return mFormat;
}
uint32_t TextureViewBase::GetLevelCount() const {
return mLevelCount;
}
uint32_t TextureViewBase::GetLayerCount() const {
return mLayerCount;
}
} // namespace dawn_native

View File

@ -32,6 +32,7 @@ namespace dawn_native {
bool TextureFormatHasDepth(dawn::TextureFormat format);
bool TextureFormatHasStencil(dawn::TextureFormat format);
bool TextureFormatHasDepthOrStencil(dawn::TextureFormat format);
bool IsColorRenderableTextureFormat(dawn::TextureFormat format);
static constexpr dawn::TextureUsageBit kReadOnlyTextureUsages =
dawn::TextureUsageBit::TransferSrc | dawn::TextureUsageBit::Sampled |
@ -74,8 +75,16 @@ namespace dawn_native {
const TextureBase* GetTexture() const;
TextureBase* GetTexture();
dawn::TextureFormat GetFormat() const;
uint32_t GetLevelCount() const;
uint32_t GetLayerCount() const;
private:
Ref<TextureBase> mTexture;
dawn::TextureFormat mFormat;
uint32_t mLevelCount;
uint32_t mLayerCount;
};
} // namespace dawn_native

View File

@ -21,19 +21,33 @@ namespace {
class RenderPassDescriptorValidationTest : public ValidationTest {
};
dawn::TextureView Create2DAttachment(dawn::Device& device, uint32_t width, uint32_t height, dawn::TextureFormat format) {
dawn::Texture CreateTexture(dawn::Device& device,
dawn::TextureDimension dimension,
dawn::TextureFormat format,
uint32_t width,
uint32_t height,
uint32_t arrayLayer,
uint32_t levelCount) {
dawn::TextureDescriptor descriptor;
descriptor.dimension = dawn::TextureDimension::e2D;
descriptor.dimension = dimension;
descriptor.size.width = width;
descriptor.size.height = height;
descriptor.size.depth = 1;
descriptor.arrayLayer = 1;
descriptor.arrayLayer = arrayLayer;
descriptor.format = format;
descriptor.levelCount = 1;
descriptor.levelCount = levelCount;
descriptor.usage = dawn::TextureUsageBit::OutputAttachment;
dawn::Texture attachment = device.CreateTexture(&descriptor);
return attachment.CreateDefaultTextureView();
return device.CreateTexture(&descriptor);
}
dawn::TextureView Create2DAttachment(dawn::Device& device,
uint32_t width,
uint32_t height,
dawn::TextureFormat format) {
dawn::Texture texture = CreateTexture(
device, dawn::TextureDimension::e2D, format, width, height, 1, 1);
return texture.CreateDefaultTextureView();
}
// A render pass with no attachments isn't valid
@ -177,6 +191,213 @@ TEST_F(RenderPassDescriptorValidationTest, FormatMismatch) {
}
}
// Currently only texture views with layerCount == 1 are allowed to be color and depth stencil
// attachments
TEST_F(RenderPassDescriptorValidationTest, TextureViewLayerCountForColorAndDepthStencil) {
constexpr uint32_t kLevelCount = 1;
constexpr uint32_t kSize = 32;
constexpr dawn::TextureFormat kColorFormat = dawn::TextureFormat::R8G8B8A8Unorm;
constexpr dawn::TextureFormat kDepthStencilFormat = dawn::TextureFormat::D32FloatS8Uint;
constexpr uint32_t kArrayLayers = 10;
dawn::Texture colorTexture = CreateTexture(
device, dawn::TextureDimension::e2D, kColorFormat, kSize, kSize, kArrayLayers, kLevelCount);
dawn::Texture depthStencilTexture = CreateTexture(
device, dawn::TextureDimension::e2D, kDepthStencilFormat, kSize, kSize, kArrayLayers,
kLevelCount);
dawn::TextureViewDescriptor baseDescriptor;
baseDescriptor.dimension = dawn::TextureViewDimension::e2DArray;
baseDescriptor.baseArrayLayer = 0;
baseDescriptor.layerCount = kArrayLayers;
baseDescriptor.baseMipLevel = 0;
baseDescriptor.levelCount = kLevelCount;
// Using 2D array texture view with layerCount > 1 is not allowed for color
{
dawn::TextureViewDescriptor descriptor = baseDescriptor;
descriptor.format = kColorFormat;
descriptor.layerCount = 5;
dawn::TextureView colorTextureView = colorTexture.CreateTextureView(&descriptor);
AssertWillBeError(device.CreateRenderPassDescriptorBuilder())
.SetColorAttachment(0, colorTextureView, dawn::LoadOp::Clear)
.GetResult();
}
// Using 2D array texture view with layerCount > 1 is not allowed for depth stencil
{
dawn::TextureViewDescriptor descriptor = baseDescriptor;
descriptor.format = kDepthStencilFormat;
descriptor.layerCount = 5;
dawn::TextureView depthStencilView = depthStencilTexture.CreateTextureView(&descriptor);
AssertWillBeError(device.CreateRenderPassDescriptorBuilder())
.SetDepthStencilAttachment(depthStencilView, dawn::LoadOp::Clear, dawn::LoadOp::Clear)
.GetResult();
}
// Using 2D array texture view that covers the first layer of the texture is OK for color
{
dawn::TextureViewDescriptor descriptor = baseDescriptor;
descriptor.format = kColorFormat;
descriptor.baseArrayLayer = 0;
descriptor.layerCount = 1;
dawn::TextureView colorTextureView = colorTexture.CreateTextureView(&descriptor);
AssertWillBeSuccess(device.CreateRenderPassDescriptorBuilder())
.SetColorAttachment(0, colorTextureView, dawn::LoadOp::Clear)
.GetResult();
}
// Using 2D array texture view that covers the first layer is OK for depth stencil
{
dawn::TextureViewDescriptor descriptor = baseDescriptor;
descriptor.format = kDepthStencilFormat;
descriptor.baseArrayLayer = 0;
descriptor.layerCount = 1;
dawn::TextureView depthStencilTextureView =
depthStencilTexture.CreateTextureView(&descriptor);
AssertWillBeSuccess(device.CreateRenderPassDescriptorBuilder())
.SetDepthStencilAttachment(
depthStencilTextureView, dawn::LoadOp::Clear, dawn::LoadOp::Clear)
.GetResult();
}
// Using 2D array texture view that covers the last layer is OK for color
{
dawn::TextureViewDescriptor descriptor = baseDescriptor;
descriptor.format = kColorFormat;
descriptor.baseArrayLayer = kArrayLayers - 1;
descriptor.layerCount = 1;
dawn::TextureView colorTextureView = colorTexture.CreateTextureView(&descriptor);
AssertWillBeSuccess(device.CreateRenderPassDescriptorBuilder())
.SetColorAttachment(0, colorTextureView, dawn::LoadOp::Clear)
.GetResult();
}
// Using 2D array texture view that covers the last layer is OK for depth stencil
{
dawn::TextureViewDescriptor descriptor = baseDescriptor;
descriptor.format = kDepthStencilFormat;
descriptor.baseArrayLayer = kArrayLayers - 1;
descriptor.layerCount = 1;
dawn::TextureView depthStencilTextureView =
depthStencilTexture.CreateTextureView(&descriptor);
AssertWillBeSuccess(device.CreateRenderPassDescriptorBuilder())
.SetDepthStencilAttachment(
depthStencilTextureView, dawn::LoadOp::Clear, dawn::LoadOp::Clear)
.GetResult();
}
}
// Only 2D texture views with levelCount == 1 are allowed to be color attachments
TEST_F(RenderPassDescriptorValidationTest, TextureViewLevelCountForColorAndDepthStencil) {
constexpr uint32_t kArrayLayers = 1;
constexpr uint32_t kSize = 32;
constexpr dawn::TextureFormat kColorFormat = dawn::TextureFormat::R8G8B8A8Unorm;
constexpr dawn::TextureFormat kDepthStencilFormat = dawn::TextureFormat::D32FloatS8Uint;
constexpr uint32_t kLevelCount = 4;
dawn::Texture colorTexture = CreateTexture(
device, dawn::TextureDimension::e2D, kColorFormat, kSize, kSize, kArrayLayers, kLevelCount);
dawn::Texture depthStencilTexture = CreateTexture(
device, dawn::TextureDimension::e2D, kDepthStencilFormat, kSize, kSize, kArrayLayers,
kLevelCount);
dawn::TextureViewDescriptor baseDescriptor;
baseDescriptor.dimension = dawn::TextureViewDimension::e2D;
baseDescriptor.baseArrayLayer = 0;
baseDescriptor.layerCount = kArrayLayers;
baseDescriptor.baseMipLevel = 0;
baseDescriptor.levelCount = kLevelCount;
// Using 2D texture view with levelCount > 1 is not allowed for color
{
dawn::TextureViewDescriptor descriptor = baseDescriptor;
descriptor.format = kColorFormat;
descriptor.levelCount = 2;
dawn::TextureView colorTextureView = colorTexture.CreateTextureView(&descriptor);
AssertWillBeError(device.CreateRenderPassDescriptorBuilder())
.SetColorAttachment(0, colorTextureView, dawn::LoadOp::Clear)
.GetResult();
}
// Using 2D texture view with levelCount > 1 is not allowed for depth stencil
{
dawn::TextureViewDescriptor descriptor = baseDescriptor;
descriptor.format = kDepthStencilFormat;
descriptor.levelCount = 2;
dawn::TextureView depthStencilView = depthStencilTexture.CreateTextureView(&descriptor);
AssertWillBeError(device.CreateRenderPassDescriptorBuilder())
.SetDepthStencilAttachment(depthStencilView, dawn::LoadOp::Clear, dawn::LoadOp::Clear)
.GetResult();
}
// Using 2D texture view that covers the first level of the texture is OK for color
{
dawn::TextureViewDescriptor descriptor = baseDescriptor;
descriptor.format = kColorFormat;
descriptor.baseMipLevel = 0;
descriptor.levelCount = 1;
dawn::TextureView colorTextureView = colorTexture.CreateTextureView(&descriptor);
AssertWillBeSuccess(device.CreateRenderPassDescriptorBuilder())
.SetColorAttachment(0, colorTextureView, dawn::LoadOp::Clear)
.GetResult();
}
// Using 2D texture view that covers the first level is OK for depth stencil
{
dawn::TextureViewDescriptor descriptor = baseDescriptor;
descriptor.format = kDepthStencilFormat;
descriptor.baseMipLevel = 0;
descriptor.levelCount = 1;
dawn::TextureView depthStencilTextureView =
depthStencilTexture.CreateTextureView(&descriptor);
AssertWillBeSuccess(device.CreateRenderPassDescriptorBuilder())
.SetDepthStencilAttachment(
depthStencilTextureView, dawn::LoadOp::Clear, dawn::LoadOp::Clear)
.GetResult();
}
// Using 2D texture view that covers the last level is OK for color
{
dawn::TextureViewDescriptor descriptor = baseDescriptor;
descriptor.format = kColorFormat;
descriptor.baseMipLevel = kLevelCount - 1;
descriptor.levelCount = 1;
dawn::TextureView colorTextureView = colorTexture.CreateTextureView(&descriptor);
AssertWillBeSuccess(device.CreateRenderPassDescriptorBuilder())
.SetColorAttachment(0, colorTextureView, dawn::LoadOp::Clear)
.GetResult();
}
// Using 2D texture view that covers the last level is OK for depth stencil
{
dawn::TextureViewDescriptor descriptor = baseDescriptor;
descriptor.format = kDepthStencilFormat;
descriptor.baseMipLevel = kLevelCount - 1;
descriptor.levelCount = 1;
dawn::TextureView depthStencilTextureView =
depthStencilTexture.CreateTextureView(&descriptor);
AssertWillBeSuccess(device.CreateRenderPassDescriptorBuilder())
.SetDepthStencilAttachment(
depthStencilTextureView, dawn::LoadOp::Clear, dawn::LoadOp::Clear)
.GetResult();
}
}
// TODO(cwallez@chromium.org): Constraints on attachment aliasing?
} // anonymous namespace