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>
This commit is contained in:
Jiawei Shao 2018-12-05 03:22:04 +00:00 committed by Commit Bot service account
parent 66b024e499
commit 33af94fd8d
11 changed files with 288 additions and 74 deletions

View File

@ -103,19 +103,20 @@ namespace dawn_native {
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;

View File

@ -300,7 +300,9 @@ namespace dawn_native {
: ObjectBase(texture->GetDevice()),
mTexture(texture),
mFormat(descriptor->format),
mBaseMipLevel(descriptor->baseMipLevel),
mLevelCount(descriptor->levelCount),
mBaseArrayLayer(descriptor->baseArrayLayer),
mLayerCount(descriptor->layerCount) {
}
@ -316,10 +318,18 @@ namespace dawn_native {
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;
}

View File

@ -76,14 +76,18 @@ namespace dawn_native {
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;
};

View File

@ -226,22 +226,33 @@ namespace dawn_native { namespace d3d12 {
}
}
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;

View File

@ -49,9 +49,11 @@ namespace dawn_native { namespace d3d12 {
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;

View File

@ -63,9 +63,8 @@ namespace dawn_native { namespace metal {
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;
}

View File

@ -292,6 +292,7 @@ std::ostringstream& DawnTest::AddTextureExpectation(const char* file,
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 @@ std::ostringstream& DawnTest::AddTextureExpectation(const char* file,
// 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};

View File

@ -36,11 +36,12 @@
// 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), \
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 @@ class DawnTest : public ::testing::TestWithParam<BackendType> {
uint32_t width,
uint32_t height,
uint32_t level,
uint32_t slice,
uint32_t pixelSize,
detail::Expectation* expectation);

View File

@ -235,7 +235,7 @@ protected:
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 <<

View File

@ -133,10 +133,10 @@ TEST_P(RenderPassLoadOpTests, ColorClearThenLoadAndDraw) {
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 @@ TEST_P(RenderPassLoadOpTests, ColorClearThenLoadAndDraw) {
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)

View File

@ -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 @@ protected:
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 @@ protected:
};
// 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_P(TextureViewTest, Default2DArrayTexture) {
}
// 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_P(TextureViewTest, TextureCubeMapArrayViewOnPartOfTexture) {
}
// 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_P(TextureViewTest, TextureCubeMapArrayViewCoveringLastLayer) {
}
// 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 @@ TEST_P(TextureViewTest, TextureCubeMapArrayViewSingleCubeMap) {
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)