Implement using a layer of a texture as color attachment - Part I
This patch implements using a layer of a texture as a color
attachment on D3D12, Metal and Vulkan.
This feature is not implemented on OpenGL back-ends in this patch.
BUG=dawn:16
TEST=dawn_unittests
Change-Id: Iffc194c6117f6e3e6506c6fcbfd51ca2fbe9ede8
Reviewed-on: https://dawn-review.googlesource.com/c/2660
Commit-Queue: Jiawei Shao <jiawei.shao@intel.com>
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
diff --git a/src/dawn_native/RenderPassDescriptor.cpp b/src/dawn_native/RenderPassDescriptor.cpp
index 1426095..22f3b9f 100644
--- a/src/dawn_native/RenderPassDescriptor.cpp
+++ b/src/dawn_native/RenderPassDescriptor.cpp
@@ -103,19 +103,20 @@
RenderPassDescriptorBase* RenderPassDescriptorBuilder::GetResultImpl() {
auto CheckOrSetSize = [this](const TextureViewBase* attachment) -> bool {
+ uint32_t mipLevel = attachment->GetBaseMipLevel();
if (this->mWidth == 0) {
ASSERT(this->mHeight == 0);
- this->mWidth = attachment->GetTexture()->GetSize().width;
- this->mHeight = attachment->GetTexture()->GetSize().height;
+ this->mWidth = attachment->GetTexture()->GetSize().width >> mipLevel;
+ this->mHeight = attachment->GetTexture()->GetSize().height >> mipLevel;
ASSERT(this->mWidth != 0 && this->mHeight != 0);
return true;
}
ASSERT(this->mWidth != 0 && this->mHeight != 0);
- return this->mWidth == attachment->GetTexture()->GetSize().width &&
- this->mHeight == attachment->GetTexture()->GetSize().height;
+ return this->mWidth == attachment->GetTexture()->GetSize().width >> mipLevel &&
+ this->mHeight == attachment->GetTexture()->GetSize().height >> mipLevel;
};
uint32_t attachmentCount = 0;
diff --git a/src/dawn_native/Texture.cpp b/src/dawn_native/Texture.cpp
index 0923fcc..00c8b9f 100644
--- a/src/dawn_native/Texture.cpp
+++ b/src/dawn_native/Texture.cpp
@@ -300,7 +300,9 @@
: ObjectBase(texture->GetDevice()),
mTexture(texture),
mFormat(descriptor->format),
+ mBaseMipLevel(descriptor->baseMipLevel),
mLevelCount(descriptor->levelCount),
+ mBaseArrayLayer(descriptor->baseArrayLayer),
mLayerCount(descriptor->layerCount) {
}
@@ -316,10 +318,18 @@
return mFormat;
}
+ uint32_t TextureViewBase::GetBaseMipLevel() const {
+ return mBaseMipLevel;
+ }
+
uint32_t TextureViewBase::GetLevelCount() const {
return mLevelCount;
}
+ uint32_t TextureViewBase::GetBaseArrayLayer() const {
+ return mBaseArrayLayer;
+ }
+
uint32_t TextureViewBase::GetLayerCount() const {
return mLayerCount;
}
diff --git a/src/dawn_native/Texture.h b/src/dawn_native/Texture.h
index f1194f0..2020ec5 100644
--- a/src/dawn_native/Texture.h
+++ b/src/dawn_native/Texture.h
@@ -76,14 +76,18 @@
TextureBase* GetTexture();
dawn::TextureFormat GetFormat() const;
+ uint32_t GetBaseMipLevel() const;
uint32_t GetLevelCount() const;
+ uint32_t GetBaseArrayLayer() const;
uint32_t GetLayerCount() const;
private:
Ref<TextureBase> mTexture;
dawn::TextureFormat mFormat;
+ uint32_t mBaseMipLevel;
uint32_t mLevelCount;
+ uint32_t mBaseArrayLayer;
uint32_t mLayerCount;
};
diff --git a/src/dawn_native/d3d12/TextureD3D12.cpp b/src/dawn_native/d3d12/TextureD3D12.cpp
index 4fd16ab..fb49dea 100644
--- a/src/dawn_native/d3d12/TextureD3D12.cpp
+++ b/src/dawn_native/d3d12/TextureD3D12.cpp
@@ -226,22 +226,33 @@
}
}
+ DXGI_FORMAT TextureView::GetD3D12Format() const {
+ return D3D12TextureFormat(GetFormat());
+ }
+
const D3D12_SHADER_RESOURCE_VIEW_DESC& TextureView::GetSRVDescriptor() const {
return mSrvDesc;
}
- // TODO(jiawei.shao@intel.com): support rendering into a layer of a texture.
- D3D12_RENDER_TARGET_VIEW_DESC TextureView::GetRTVDescriptor() {
+ D3D12_RENDER_TARGET_VIEW_DESC TextureView::GetRTVDescriptor() const {
+ ASSERT(GetTexture()->GetDimension() == dawn::TextureDimension::e2D);
D3D12_RENDER_TARGET_VIEW_DESC rtvDesc;
- rtvDesc.Format = ToBackend(GetTexture())->GetD3D12Format();
- rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;
- rtvDesc.Texture2D.MipSlice = 0;
- rtvDesc.Texture2D.PlaneSlice = 0;
+ rtvDesc.Format = GetD3D12Format();
+ // Currently we always use D3D12_TEX2D_ARRAY_RTV because we cannot specify base array layer
+ // and layer count in D3D12_TEX2D_RTV. For 2D texture views, we treat them as 1-layer 2D
+ // array textures. (Just like how we treat SRVs)
+ // https://docs.microsoft.com/en-us/windows/desktop/api/d3d12/ns-d3d12-d3d12_tex2d_rtv
+ // https://docs.microsoft.com/en-us/windows/desktop/api/d3d12/ns-d3d12-d3d12_tex2d_array_rtv
+ rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY;
+ rtvDesc.Texture2DArray.FirstArraySlice = GetBaseArrayLayer();
+ rtvDesc.Texture2DArray.ArraySize = GetLayerCount();
+ rtvDesc.Texture2DArray.MipSlice = GetBaseMipLevel();
+ rtvDesc.Texture2DArray.PlaneSlice = 0;
return rtvDesc;
}
// TODO(jiawei.shao@intel.com): support rendering into a layer of a texture.
- D3D12_DEPTH_STENCIL_VIEW_DESC TextureView::GetDSVDescriptor() {
+ D3D12_DEPTH_STENCIL_VIEW_DESC TextureView::GetDSVDescriptor() const {
D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc;
dsvDesc.Format = ToBackend(GetTexture())->GetD3D12Format();
dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D;
diff --git a/src/dawn_native/d3d12/TextureD3D12.h b/src/dawn_native/d3d12/TextureD3D12.h
index 23a0d52..2edfb7c 100644
--- a/src/dawn_native/d3d12/TextureD3D12.h
+++ b/src/dawn_native/d3d12/TextureD3D12.h
@@ -49,9 +49,11 @@
public:
TextureView(TextureBase* texture, const TextureViewDescriptor* descriptor);
+ DXGI_FORMAT GetD3D12Format() const;
+
const D3D12_SHADER_RESOURCE_VIEW_DESC& GetSRVDescriptor() const;
- D3D12_RENDER_TARGET_VIEW_DESC GetRTVDescriptor();
- D3D12_DEPTH_STENCIL_VIEW_DESC GetDSVDescriptor();
+ D3D12_RENDER_TARGET_VIEW_DESC GetRTVDescriptor() const;
+ D3D12_DEPTH_STENCIL_VIEW_DESC GetDSVDescriptor() const;
private:
D3D12_SHADER_RESOURCE_VIEW_DESC mSrvDesc;
diff --git a/src/dawn_native/metal/CommandBufferMTL.mm b/src/dawn_native/metal/CommandBufferMTL.mm
index bf37d1f..26b2bb1 100644
--- a/src/dawn_native/metal/CommandBufferMTL.mm
+++ b/src/dawn_native/metal/CommandBufferMTL.mm
@@ -63,9 +63,8 @@
descriptor.colorAttachments[i].loadAction = MTLLoadActionLoad;
}
- // TODO(jiawei.shao@intel.com): support rendering into a layer of a texture.
descriptor.colorAttachments[i].texture =
- ToBackend(attachmentInfo.view->GetTexture())->GetMTLTexture();
+ ToBackend(attachmentInfo.view)->GetMTLTexture();
descriptor.colorAttachments[i].storeAction = MTLStoreActionStore;
}
diff --git a/src/tests/DawnTest.cpp b/src/tests/DawnTest.cpp
index 8001941..6e54cfe 100644
--- a/src/tests/DawnTest.cpp
+++ b/src/tests/DawnTest.cpp
@@ -292,6 +292,7 @@
uint32_t width,
uint32_t height,
uint32_t level,
+ uint32_t slice,
uint32_t pixelSize,
detail::Expectation* expectation) {
uint32_t rowPitch = Align(width * pixelSize, kTextureRowPitchAlignment);
@@ -302,7 +303,7 @@
// We need to enqueue the copy immediately because by the time we resolve the expectation,
// the texture might have been modified.
dawn::TextureCopyView textureCopyView =
- utils::CreateTextureCopyView(texture, level, 0, {x, y, 0}, dawn::TextureAspect::Color);
+ utils::CreateTextureCopyView(texture, level, slice, {x, y, 0}, dawn::TextureAspect::Color);
dawn::BufferCopyView bufferCopyView =
utils::CreateBufferCopyView(readback.buffer, readback.offset, rowPitch, 0);
dawn::Extent3D copySize = {width, height, 1};
diff --git a/src/tests/DawnTest.h b/src/tests/DawnTest.h
index 1c68116..f0c8823 100644
--- a/src/tests/DawnTest.h
+++ b/src/tests/DawnTest.h
@@ -35,12 +35,13 @@
new detail::ExpectEq<uint8_t>(expected))
// Test a pixel of the mip level 0 of a 2D texture.
-#define EXPECT_PIXEL_RGBA8_EQ(expected, texture, x, y) \
- AddTextureExpectation(__FILE__, __LINE__, texture, x, y, 1, 1, 0, sizeof(RGBA8), \
+#define EXPECT_PIXEL_RGBA8_EQ(expected, texture, x, y) \
+ AddTextureExpectation(__FILE__, __LINE__, texture, x, y, 1, 1, 0, 0, sizeof(RGBA8), \
new detail::ExpectEq<RGBA8>(expected))
-#define EXPECT_TEXTURE_RGBA8_EQ(expected, texture, x, y, width, height, level) \
- AddTextureExpectation(__FILE__, __LINE__, texture, x, y, width, height, level, sizeof(RGBA8), \
+#define EXPECT_TEXTURE_RGBA8_EQ(expected, texture, x, y, width, height, level, slice) \
+ AddTextureExpectation(__FILE__, __LINE__, texture, x, y, width, height, level, slice, \
+ sizeof(RGBA8), \
new detail::ExpectEq<RGBA8>(expected, (width) * (height)))
struct RGBA8 {
@@ -122,6 +123,7 @@
uint32_t width,
uint32_t height,
uint32_t level,
+ uint32_t slice,
uint32_t pixelSize,
detail::Expectation* expectation);
diff --git a/src/tests/end2end/CopyTests.cpp b/src/tests/end2end/CopyTests.cpp
index 3732303..02c2e51 100644
--- a/src/tests/end2end/CopyTests.cpp
+++ b/src/tests/end2end/CopyTests.cpp
@@ -235,7 +235,7 @@
std::vector<RGBA8> expected(rowPitch / kBytesPerTexel * (textureSpec.copyHeight - 1) + textureSpec.copyWidth);
PackTextureData(&bufferData[bufferSpec.offset / kBytesPerTexel], textureSpec.copyWidth, textureSpec.copyHeight, bufferSpec.rowPitch / kBytesPerTexel, expected.data(), textureSpec.copyWidth);
- EXPECT_TEXTURE_RGBA8_EQ(expected.data(), texture, textureSpec.x, textureSpec.y, textureSpec.copyWidth, textureSpec.copyHeight, textureSpec.level) <<
+ EXPECT_TEXTURE_RGBA8_EQ(expected.data(), texture, textureSpec.x, textureSpec.y, textureSpec.copyWidth, textureSpec.copyHeight, textureSpec.level, 0) <<
"Buffer to Texture copy failed copying "
<< bufferSpec.size << "-byte buffer with offset " << bufferSpec.offset << " and row pitch " << bufferSpec.rowPitch << " to [("
<< textureSpec.x << ", " << textureSpec.y << "), (" << textureSpec.x + textureSpec.copyWidth << ", " << textureSpec.y + textureSpec.copyHeight <<
diff --git a/src/tests/end2end/RenderPassLoadOpTests.cpp b/src/tests/end2end/RenderPassLoadOpTests.cpp
index 0c8cee3..d8efd8e 100644
--- a/src/tests/end2end/RenderPassLoadOpTests.cpp
+++ b/src/tests/end2end/RenderPassLoadOpTests.cpp
@@ -133,10 +133,10 @@
auto commandsClearGreen = commandsClearGreenBuilder.GetResult();
queue.Submit(1, &commandsClearZero);
- EXPECT_TEXTURE_RGBA8_EQ(expectZero.data(), renderTarget, 0, 0, kRTSize, kRTSize, 0);
+ EXPECT_TEXTURE_RGBA8_EQ(expectZero.data(), renderTarget, 0, 0, kRTSize, kRTSize, 0, 0);
queue.Submit(1, &commandsClearGreen);
- EXPECT_TEXTURE_RGBA8_EQ(expectGreen.data(), renderTarget, 0, 0, kRTSize, kRTSize, 0);
+ EXPECT_TEXTURE_RGBA8_EQ(expectGreen.data(), renderTarget, 0, 0, kRTSize, kRTSize, 0, 0);
// Part 2: draw a blue quad into the right half of the render target, and check result
@@ -155,9 +155,9 @@
queue.Submit(1, &commandsLoad);
// Left half should still be green
- EXPECT_TEXTURE_RGBA8_EQ(expectGreen.data(), renderTarget, 0, 0, kRTSize / 2, kRTSize, 0);
+ EXPECT_TEXTURE_RGBA8_EQ(expectGreen.data(), renderTarget, 0, 0, kRTSize / 2, kRTSize, 0, 0);
// Right half should now be blue
- EXPECT_TEXTURE_RGBA8_EQ(expectBlue.data(), renderTarget, kRTSize / 2, 0, kRTSize / 2, kRTSize, 0);
+ EXPECT_TEXTURE_RGBA8_EQ(expectBlue.data(), renderTarget, kRTSize / 2, 0, kRTSize / 2, kRTSize, 0, 0);
}
DAWN_INSTANTIATE_TEST(RenderPassLoadOpTests, D3D12Backend, MetalBackend, OpenGLBackend, VulkanBackend)
diff --git a/src/tests/end2end/TextureViewTests.cpp b/src/tests/end2end/TextureViewTests.cpp
index 9a33470..98926a1 100644
--- a/src/tests/end2end/TextureViewTests.cpp
+++ b/src/tests/end2end/TextureViewTests.cpp
@@ -16,13 +16,59 @@
#include "common/Assert.h"
#include "common/Constants.h"
+#include "common/Math.h"
#include "utils/DawnHelpers.h"
#include <array>
constexpr static unsigned int kRTSize = 64;
+constexpr dawn::TextureFormat kDefaultFormat = dawn::TextureFormat::R8G8B8A8Unorm;
+constexpr uint32_t kBytesPerTexel = 4;
-class TextureViewTest : public DawnTest {
+namespace {
+ dawn::Texture Create2DTexture(dawn::Device device,
+ uint32_t width,
+ uint32_t height,
+ uint32_t layerCount,
+ uint32_t levelCount,
+ dawn::TextureUsageBit usage) {
+ dawn::TextureDescriptor descriptor;
+ descriptor.dimension = dawn::TextureDimension::e2D;
+ descriptor.size.width = width;
+ descriptor.size.height = height;
+ descriptor.size.depth = 1;
+ descriptor.arrayLayer = layerCount;
+ descriptor.format = kDefaultFormat;
+ descriptor.levelCount = levelCount;
+ descriptor.usage = usage;
+ return device.CreateTexture(&descriptor);
+ }
+
+ dawn::ShaderModule CreateDefaultVertexShaderModule(dawn::Device device) {
+ return utils::CreateShaderModule(device, dawn::ShaderStage::Vertex, R"(
+ #version 450
+ layout (location = 0) out vec2 o_texCoord;
+ void main() {
+ const vec2 pos[6] = vec2[6](vec2(-2.f, -2.f),
+ vec2(-2.f, 2.f),
+ vec2( 2.f, -2.f),
+ vec2(-2.f, 2.f),
+ vec2( 2.f, -2.f),
+ vec2( 2.f, 2.f));
+ const vec2 texCoord[6] = vec2[6](vec2(0.f, 0.f),
+ vec2(0.f, 1.f),
+ vec2(1.f, 0.f),
+ vec2(0.f, 1.f),
+ vec2(1.f, 0.f),
+ vec2(1.f, 1.f));
+ gl_Position = vec4(pos[gl_VertexIndex], 0.f, 1.f);
+ o_texCoord = texCoord[gl_VertexIndex];
+ }
+ )");
+ }
+} // anonymous namespace
+
+class TextureViewSamplingTest : public DawnTest {
protected:
// Generates an arbitrary pixel value per-layer-per-level, used for the "actual" uploaded
// textures and the "expected" results.
@@ -55,50 +101,22 @@
mPipelineLayout = utils::MakeBasicPipelineLayout(device, &mBindGroupLayout);
- mVSModule = utils::CreateShaderModule(device, dawn::ShaderStage::Vertex, R"(
- #version 450
- layout (location = 0) out vec2 o_texCoord;
- void main() {
- const vec2 pos[6] = vec2[6](vec2(-2.f, -2.f),
- vec2(-2.f, 2.f),
- vec2( 2.f, -2.f),
- vec2(-2.f, 2.f),
- vec2( 2.f, -2.f),
- vec2( 2.f, 2.f));
- const vec2 texCoord[6] = vec2[6](vec2(0.f, 0.f),
- vec2(0.f, 1.f),
- vec2(1.f, 0.f),
- vec2(0.f, 1.f),
- vec2(1.f, 0.f),
- vec2(1.f, 1.f));
- gl_Position = vec4(pos[gl_VertexIndex], 0.f, 1.f);
- o_texCoord = texCoord[gl_VertexIndex];
- }
- )");
+ mVSModule = CreateDefaultVertexShaderModule(device);
}
void initTexture(uint32_t layerCount, uint32_t levelCount) {
ASSERT(layerCount > 0 && levelCount > 0);
- constexpr dawn::TextureFormat kFormat = dawn::TextureFormat::R8G8B8A8Unorm;
-
const uint32_t textureWidthLevel0 = 1 << levelCount;
const uint32_t textureHeightLevel0 = 1 << levelCount;
-
- dawn::TextureDescriptor descriptor;
- descriptor.dimension = dawn::TextureDimension::e2D;
- descriptor.size.width = textureWidthLevel0;
- descriptor.size.height = textureHeightLevel0;
- descriptor.size.depth = 1;
- descriptor.arrayLayer = layerCount;
- descriptor.format = kFormat;
- descriptor.levelCount = levelCount;
- descriptor.usage = dawn::TextureUsageBit::TransferDst | dawn::TextureUsageBit::Sampled;
- mTexture = device.CreateTexture(&descriptor);
+ constexpr dawn::TextureUsageBit kUsage =
+ dawn::TextureUsageBit::TransferDst | dawn::TextureUsageBit::Sampled;
+ mTexture = Create2DTexture(
+ device, textureWidthLevel0, textureHeightLevel0, layerCount, levelCount, kUsage);
mDefaultTextureViewDescriptor.nextInChain = nullptr;
mDefaultTextureViewDescriptor.dimension = dawn::TextureViewDimension::e2DArray;
- mDefaultTextureViewDescriptor.format = kFormat;
+ mDefaultTextureViewDescriptor.format = kDefaultFormat;
mDefaultTextureViewDescriptor.baseMipLevel = 0;
mDefaultTextureViewDescriptor.levelCount = levelCount;
mDefaultTextureViewDescriptor.baseArrayLayer = 0;
@@ -328,7 +346,7 @@
};
// Test drawing a rect with a 2D array texture.
-TEST_P(TextureViewTest, Default2DArrayTexture) {
+TEST_P(TextureViewSamplingTest, Default2DArrayTexture) {
// TODO(cwallez@chromium.org) understand what the issue is
DAWN_SKIP_TEST_IF(IsVulkan() && IsNvidia());
@@ -359,58 +377,58 @@
}
// Test sampling from a 2D texture view created on a 2D array texture.
-TEST_P(TextureViewTest, Texture2DViewOn2DArrayTexture) {
+TEST_P(TextureViewSamplingTest, Texture2DViewOn2DArrayTexture) {
Texture2DViewTest(6, 1, 4, 0);
}
// Test sampling from a 2D array texture view created on a 2D array texture.
-TEST_P(TextureViewTest, Texture2DArrayViewOn2DArrayTexture) {
+TEST_P(TextureViewSamplingTest, Texture2DArrayViewOn2DArrayTexture) {
DAWN_SKIP_TEST_IF(IsMetal() && IsIntel());
Texture2DArrayViewTest(6, 1, 2, 0);
}
// Test sampling from a 2D texture view created on a mipmap level of a 2D texture.
-TEST_P(TextureViewTest, Texture2DViewOnOneLevelOf2DTexture) {
+TEST_P(TextureViewSamplingTest, Texture2DViewOnOneLevelOf2DTexture) {
Texture2DViewTest(1, 6, 0, 4);
}
// Test sampling from a 2D texture view created on a mipmap level of a 2D array texture layer.
-TEST_P(TextureViewTest, Texture2DViewOnOneLevelOf2DArrayTexture) {
+TEST_P(TextureViewSamplingTest, Texture2DViewOnOneLevelOf2DArrayTexture) {
Texture2DViewTest(6, 6, 3, 4);
}
// Test sampling from a 2D array texture view created on a mipmap level of a 2D array texture.
-TEST_P(TextureViewTest, Texture2DArrayViewOnOneLevelOf2DArrayTexture) {
+TEST_P(TextureViewSamplingTest, Texture2DArrayViewOnOneLevelOf2DArrayTexture) {
DAWN_SKIP_TEST_IF(IsMetal() && IsIntel());
Texture2DArrayViewTest(6, 6, 2, 4);
}
// Test sampling from a cube map texture view that covers a whole 2D array texture.
-TEST_P(TextureViewTest, TextureCubeMapOnWholeTexture) {
+TEST_P(TextureViewSamplingTest, TextureCubeMapOnWholeTexture) {
constexpr uint32_t kTotalLayers = 6;
TextureCubeMapTest(kTotalLayers, 0, kTotalLayers, false);
}
// Test sampling from a cube map texture view that covers a sub part of a 2D array texture.
-TEST_P(TextureViewTest, TextureCubeMapViewOnPartOfTexture) {
+TEST_P(TextureViewSamplingTest, TextureCubeMapViewOnPartOfTexture) {
TextureCubeMapTest(10, 2, 6, false);
}
// Test sampling from a cube map texture view that covers the last layer of a 2D array texture.
-TEST_P(TextureViewTest, TextureCubeMapViewCoveringLastLayer) {
+TEST_P(TextureViewSamplingTest, TextureCubeMapViewCoveringLastLayer) {
constexpr uint32_t kTotalLayers = 10;
constexpr uint32_t kBaseLayer = 4;
TextureCubeMapTest(kTotalLayers, kBaseLayer, kTotalLayers - kBaseLayer, false);
}
// Test sampling from a cube map texture array view that covers a whole 2D array texture.
-TEST_P(TextureViewTest, TextureCubeMapArrayOnWholeTexture) {
+TEST_P(TextureViewSamplingTest, TextureCubeMapArrayOnWholeTexture) {
constexpr uint32_t kTotalLayers = 12;
TextureCubeMapTest(kTotalLayers, 0, kTotalLayers, true);
}
// Test sampling from a cube map texture array view that covers a sub part of a 2D array texture.
-TEST_P(TextureViewTest, TextureCubeMapArrayViewOnPartOfTexture) {
+TEST_P(TextureViewSamplingTest, TextureCubeMapArrayViewOnPartOfTexture) {
// Test failing on the GPU FYI Mac Pro (AMD), see
// https://bugs.chromium.org/p/dawn/issues/detail?id=58
DAWN_SKIP_TEST_IF(IsMacOS() && IsMetal() && IsAMD());
@@ -419,7 +437,7 @@
}
// Test sampling from a cube map texture array view that covers the last layer of a 2D array texture.
-TEST_P(TextureViewTest, TextureCubeMapArrayViewCoveringLastLayer) {
+TEST_P(TextureViewSamplingTest, TextureCubeMapArrayViewCoveringLastLayer) {
// Test failing on the GPU FYI Mac Pro (AMD), see
// https://bugs.chromium.org/p/dawn/issues/detail?id=58
DAWN_SKIP_TEST_IF(IsMacOS() && IsMetal() && IsAMD());
@@ -430,7 +448,7 @@
}
// Test sampling from a cube map array texture view that only has a single cube map.
-TEST_P(TextureViewTest, TextureCubeMapArrayViewSingleCubeMap) {
+TEST_P(TextureViewSamplingTest, TextureCubeMapArrayViewSingleCubeMap) {
// Test failing on the GPU FYI Mac Pro (AMD), see
// https://bugs.chromium.org/p/dawn/issues/detail?id=58
DAWN_SKIP_TEST_IF(IsMacOS() && IsMetal() && IsAMD());
@@ -438,4 +456,170 @@
TextureCubeMapTest(20, 7, 6, true);
}
-DAWN_INSTANTIATE_TEST(TextureViewTest, D3D12Backend, MetalBackend, OpenGLBackend, VulkanBackend)
+class TextureViewRenderingTest : public DawnTest {
+ protected:
+ void TextureLayerAsColorAttachmentTest(dawn::TextureViewDimension dimension,
+ uint32_t layerCount,
+ uint32_t levelCount,
+ uint32_t textureViewBaseLayer,
+ uint32_t textureViewBaseLevel) {
+ ASSERT(dimension == dawn::TextureViewDimension::e2D ||
+ dimension == dawn::TextureViewDimension::e2DArray);
+ ASSERT_LT(textureViewBaseLayer, layerCount);
+ ASSERT_LT(textureViewBaseLevel, levelCount);
+
+ const uint32_t textureWidthLevel0 = 1 << levelCount;
+ const uint32_t textureHeightLevel0 = 1 << levelCount;
+ constexpr dawn::TextureUsageBit kUsage = dawn::TextureUsageBit::OutputAttachment |
+ dawn::TextureUsageBit::TransferSrc;
+ dawn::Texture texture = Create2DTexture(
+ device, textureWidthLevel0, textureHeightLevel0, layerCount, levelCount, kUsage);
+
+ dawn::TextureViewDescriptor descriptor;
+ descriptor.format = kDefaultFormat;
+ descriptor.dimension = dimension;
+ descriptor.baseArrayLayer = textureViewBaseLayer;
+ descriptor.layerCount = 1;
+ descriptor.baseMipLevel = textureViewBaseLevel;
+ descriptor.levelCount = 1;
+ dawn::TextureView textureView = texture.CreateTextureView(&descriptor);
+
+ dawn::ShaderModule vsModule = CreateDefaultVertexShaderModule(device);
+
+ // Clear textureView with Red(255, 0, 0, 255) and render Green(0, 255, 0, 255) into it
+ dawn::RenderPassDescriptor renderPassInfo = device.CreateRenderPassDescriptorBuilder()
+ .SetColorAttachment(0, textureView, dawn::LoadOp::Clear)
+ .SetColorAttachmentClearColor(0, 1.0, 0.0, 0.0, 1.0)
+ .GetResult();
+
+ const char* oneColorFragmentShader = R"(
+ #version 450
+ layout(location = 0) out vec4 fragColor;
+
+ void main() {
+ fragColor = vec4(0.0, 1.0, 0.0, 1.0);
+ }
+ )";
+ dawn::ShaderModule oneColorFsModule =
+ utils::CreateShaderModule(device, dawn::ShaderStage::Fragment, oneColorFragmentShader);
+
+ dawn::RenderPipeline oneColorPipeline = device.CreateRenderPipelineBuilder()
+ .SetColorAttachmentFormat(0, kDefaultFormat)
+ .SetStage(dawn::ShaderStage::Vertex, vsModule, "main")
+ .SetStage(dawn::ShaderStage::Fragment, oneColorFsModule, "main")
+ .GetResult();
+ dawn::CommandBufferBuilder commandBufferBuilder = device.CreateCommandBufferBuilder();
+ {
+ dawn::RenderPassEncoder pass =
+ commandBufferBuilder.BeginRenderPass(renderPassInfo);
+ pass.SetRenderPipeline(oneColorPipeline);
+ pass.DrawArrays(6, 1, 0, 0);
+ pass.EndPass();
+ }
+
+ dawn::CommandBuffer commands = commandBufferBuilder.GetResult();
+ queue.Submit(1, &commands);
+
+ // Check if the right pixels (Green) have been written into the right part of the texture.
+ uint32_t textureViewWidth = textureWidthLevel0 >> textureViewBaseLevel;
+ uint32_t textureViewHeight = textureHeightLevel0 >> textureViewBaseLevel;
+ uint32_t rowPitch = Align(kBytesPerTexel * textureWidthLevel0, kTextureRowPitchAlignment);
+ uint32_t expectedDataSize =
+ rowPitch / kBytesPerTexel * (textureWidthLevel0 - 1) + textureHeightLevel0;
+ constexpr RGBA8 kExpectedPixel(0, 255, 0, 255);
+ std::vector<RGBA8> expected(expectedDataSize, kExpectedPixel);
+ EXPECT_TEXTURE_RGBA8_EQ(
+ expected.data(), texture, 0, 0, textureViewWidth, textureViewHeight,
+ textureViewBaseLevel, textureViewBaseLayer);
+ }
+};
+
+// Test rendering into a 2D texture view created on a mipmap level of a 2D texture.
+TEST_P(TextureViewRenderingTest, Texture2DViewOnALevelOf2DTextureAsColorAttachment) {
+ constexpr uint32_t kLayers = 1;
+ constexpr uint32_t kMipLevels = 4;
+ constexpr uint32_t kBaseLayer = 0;
+
+ // Rendering into the first level
+ {
+ constexpr uint32_t kBaseLevel = 0;
+ TextureLayerAsColorAttachmentTest(
+ dawn::TextureViewDimension::e2D, kLayers, kMipLevels, kBaseLayer, kBaseLevel);
+ }
+
+ // Rendering into the last level
+ {
+ constexpr uint32_t kBaseLevel = kMipLevels - 1;
+ TextureLayerAsColorAttachmentTest(
+ dawn::TextureViewDimension::e2D, kLayers, kMipLevels, kBaseLayer, kBaseLevel);
+ }
+}
+
+// Test rendering into a 2D texture view created on a layer of a 2D array texture.
+TEST_P(TextureViewRenderingTest, Texture2DViewOnALayerOf2DArrayTextureAsColorAttachment) {
+ constexpr uint32_t kMipLevels = 1;
+ constexpr uint32_t kBaseLevel = 0;
+ constexpr uint32_t kLayers = 10;
+
+ // Rendering into the first layer
+ {
+ constexpr uint32_t kBaseLayer = 0;
+ TextureLayerAsColorAttachmentTest(
+ dawn::TextureViewDimension::e2D, kLayers, kMipLevels, kBaseLayer, kBaseLevel);
+ }
+
+ // Rendering into the last layer
+ {
+ constexpr uint32_t kBaseLayer = kLayers - 1;
+ TextureLayerAsColorAttachmentTest(
+ dawn::TextureViewDimension::e2D, kLayers, kMipLevels, kBaseLayer, kBaseLevel);
+ }
+
+}
+
+// Test rendering into a 1-layer 2D array texture view created on a mipmap level of a 2D texture.
+TEST_P(TextureViewRenderingTest, Texture2DArrayViewOnALevelOf2DTextureAsColorAttachment) {
+ constexpr uint32_t kLayers = 1;
+ constexpr uint32_t kMipLevels = 4;
+ constexpr uint32_t kBaseLayer = 0;
+
+ // Rendering into the first level
+ {
+ constexpr uint32_t kBaseLevel = 0;
+ TextureLayerAsColorAttachmentTest(
+ dawn::TextureViewDimension::e2DArray, kLayers, kMipLevels, kBaseLayer, kBaseLevel);
+ }
+
+ // Rendering into the last level
+ {
+ constexpr uint32_t kBaseLevel = kMipLevels - 1;
+ TextureLayerAsColorAttachmentTest(
+ dawn::TextureViewDimension::e2DArray, kLayers, kMipLevels, kBaseLayer, kBaseLevel);
+ }
+}
+
+// Test rendering into a 1-layer 2D array texture view created on a layer of a 2D array texture.
+TEST_P(TextureViewRenderingTest, Texture2DArrayViewOnALayerOf2DArrayTextureAsColorAttachment) {
+ constexpr uint32_t kMipLevels = 1;
+ constexpr uint32_t kBaseLevel = 0;
+ constexpr uint32_t kLayers = 10;
+
+ // Rendering into the first layer
+ {
+ constexpr uint32_t kBaseLayer = 0;
+ TextureLayerAsColorAttachmentTest(
+ dawn::TextureViewDimension::e2DArray, kLayers, kMipLevels, kBaseLayer, kBaseLevel);
+ }
+
+ // Rendering into the last layer
+ {
+ constexpr uint32_t kBaseLayer = kLayers - 1;
+ TextureLayerAsColorAttachmentTest(
+ dawn::TextureViewDimension::e2DArray, kLayers, kMipLevels, kBaseLayer, kBaseLevel);
+ }
+}
+
+DAWN_INSTANTIATE_TEST(TextureViewSamplingTest, D3D12Backend, MetalBackend, OpenGLBackend, VulkanBackend)
+
+// TODO(jiawei.shao@intel.com): support using a layer of a texture as color attachment on OpenGL
+DAWN_INSTANTIATE_TEST(TextureViewRenderingTest, D3D12Backend, MetalBackend, VulkanBackend)