Implement 3D texture sampling with e2e tests

This change implements 3D texture sampling with an en2end test.
It turns out that the implementation has already been done. The
test can pass with minor changes.

Bug: dawn:547

Change-Id: I5dfe1a446de3287392e39cb4dd58143e115b02cd
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/56000
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Commit-Queue: Yunchao He <yunchao.he@intel.com>
This commit is contained in:
Yunchao He 2021-06-29 04:56:01 +00:00 committed by Dawn LUCI CQ
parent 98ab91b474
commit 405bec157e
4 changed files with 129 additions and 4 deletions

View File

@ -793,8 +793,8 @@ namespace dawn_native { namespace d3d12 {
const ExecutionSerial pendingCommandSerial =
ToBackend(GetDevice())->GetPendingCommandSerial();
// This transitions assume it is a 2D texture
ASSERT(GetDimension() == wgpu::TextureDimension::e2D);
// TODO(crbug.com/dawn/814): support 1D textures.
ASSERT(GetDimension() != wgpu::TextureDimension::e1D);
mSubresourceStateAndDecay.Merge(textureUsages, [&](const SubresourceRange& mergeRange,
StateAndDecay* state,

View File

@ -904,8 +904,8 @@ namespace dawn_native { namespace vulkan {
wgpu::TextureUsage allUsages = wgpu::TextureUsage::None;
wgpu::TextureUsage allLastUsages = wgpu::TextureUsage::None;
// This transitions assume it is a 2D texture
ASSERT(GetDimension() == wgpu::TextureDimension::e2D);
// TODO(crbug.com/dawn/814): support 1D textures.
ASSERT(GetDimension() != wgpu::TextureDimension::e1D);
mSubresourceLastUsages.Merge(
subresourceUsages, [&](const SubresourceRange& range, wgpu::TextureUsage* lastUsage,

View File

@ -345,6 +345,7 @@ source_set("dawn_end2end_tests_sources") {
"end2end/ShaderTests.cpp",
"end2end/StorageTextureTests.cpp",
"end2end/SubresourceRenderAttachmentTests.cpp",
"end2end/Texture3DTests.cpp",
"end2end/TextureFormatTests.cpp",
"end2end/TextureSubresourceTests.cpp",
"end2end/TextureViewTests.cpp",

View File

@ -0,0 +1,124 @@
// Copyright 2021 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 "tests/DawnTest.h"
#include "utils/ComboRenderPipelineDescriptor.h"
#include "utils/TestUtils.h"
#include "utils/WGPUHelpers.h"
constexpr static uint32_t kRTSize = 4;
constexpr wgpu::TextureFormat kFormat = wgpu::TextureFormat::RGBA8Unorm;
class Texture3DTests : public DawnTest {};
TEST_P(Texture3DTests, Sampling) {
utils::BasicRenderPass renderPass = utils::CreateBasicRenderPass(device, kRTSize, kRTSize);
// Set up pipeline. Two triangles will be drawn via the pipeline. They will fill the entire
// color attachment with data sampled from 3D texture.
wgpu::ShaderModule vsModule = utils::CreateShaderModule(device, R"(
[[stage(vertex)]]
fn main([[builtin(vertex_index)]] VertexIndex : u32) -> [[builtin(position)]] vec4<f32> {
var pos = array<vec2<f32>, 6>(
vec2<f32>(-1.0, 1.0),
vec2<f32>( -1.0, -1.0),
vec2<f32>(1.0, 1.0),
vec2<f32>(1.0, 1.0),
vec2<f32>(-1.0, -1.0),
vec2<f32>(1.0, -1.0));
return vec4<f32>(pos[VertexIndex], 0.0, 1.0);
})");
wgpu::ShaderModule fsModule = utils::CreateShaderModule(device, R"(
[[group(0), binding(0)]] var samp : sampler;
[[group(0), binding(1)]] var tex : texture_3d<f32>;
[[stage(fragment)]]
fn main([[builtin(position)]] FragCoord : vec4<f32>) -> [[location(0)]] vec4<f32> {
return textureSample(tex, samp, vec3<f32>(FragCoord.xy / 4.0, 1.5 / 4.0));
})");
utils::ComboRenderPipelineDescriptor pipelineDescriptor;
pipelineDescriptor.vertex.module = vsModule;
pipelineDescriptor.cFragment.module = fsModule;
pipelineDescriptor.cTargets[0].format = renderPass.colorFormat;
wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&pipelineDescriptor);
wgpu::Sampler sampler = device.CreateSampler();
wgpu::Extent3D copySize = {kRTSize, kRTSize, kRTSize};
// Create a 3D texture, fill the texture via a B2T copy with well-designed data.
// The 3D texture will be used as the data source of a sampler in shader.
wgpu::TextureDescriptor descriptor;
descriptor.dimension = wgpu::TextureDimension::e3D;
descriptor.size = copySize;
descriptor.format = kFormat;
descriptor.usage = wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::Sampled;
wgpu::Texture texture = device.CreateTexture(&descriptor);
wgpu::TextureView textureView = texture.CreateView();
uint32_t bytesPerRow = utils::GetMinimumBytesPerRow(kFormat, copySize.width);
uint32_t sizeInBytes =
utils::RequiredBytesInCopy(bytesPerRow, copySize.height, copySize, kFormat);
const uint32_t bytesPerTexel = utils::GetTexelBlockSizeInBytes(kFormat);
uint32_t size = sizeInBytes / bytesPerTexel;
std::vector<RGBA8> data = std::vector<RGBA8>(size);
for (uint32_t z = 0; z < copySize.depthOrArrayLayers; ++z) {
for (uint32_t y = 0; y < copySize.height; ++y) {
for (uint32_t x = 0; x < copySize.width; ++x) {
uint32_t i = (z * copySize.height + y) * bytesPerRow / bytesPerTexel + x;
data[i] = RGBA8(x, y, z, 255);
}
}
}
wgpu::Buffer buffer =
utils::CreateBufferFromData(device, data.data(), sizeInBytes, wgpu::BufferUsage::CopySrc);
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
wgpu::ImageCopyBuffer imageCopyBuffer =
utils::CreateImageCopyBuffer(buffer, 0, bytesPerRow, copySize.height);
wgpu::ImageCopyTexture imageCopyTexture = utils::CreateImageCopyTexture(texture, 0, {0, 0, 0});
encoder.CopyBufferToTexture(&imageCopyBuffer, &imageCopyTexture, &copySize);
wgpu::BindGroup bindGroup = utils::MakeBindGroup(device, pipeline.GetBindGroupLayout(0),
{{0, sampler}, {1, textureView}});
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
pass.SetPipeline(pipeline);
pass.SetBindGroup(0, bindGroup);
pass.Draw(6);
pass.EndPass();
wgpu::CommandBuffer commands = encoder.Finish();
queue.Submit(1, &commands);
// We sample data from the 3D texture at depth slice 1: 1.5 / 4.0 for z axis in textureSampler()
// in shader, so the expected color at coordinate(x, y) should be (x, y, 1, 255).
for (uint32_t i = 0; i < kRTSize; ++i) {
for (uint32_t j = 0; j < kRTSize; ++j) {
EXPECT_PIXEL_RGBA8_EQ(RGBA8(i, j, 1, 255), renderPass.color, i, j);
}
}
}
DAWN_INSTANTIATE_TEST(Texture3DTests,
D3D12Backend(),
MetalBackend(),
OpenGLBackend(),
OpenGLESBackend(),
VulkanBackend());