[Compat] Fix a bug when textureDimension with 1 arg is first called
When textureDimension with 1 arg is first called,
it accidentally returns TextureQueryType::kTextureNumSamples.
Add tests and asserts to add some robustness.
Also fixes same bug for TextureLoad.
Bug: dawn:2442
Change-Id: Ida753f7ae99417c683e20704e89c379837ccdf70
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/184640
Reviewed-by: dan sinclair <dsinclair@chromium.org>
Commit-Queue: Shrek Shao <shrekshao@google.com>
diff --git a/src/dawn/tests/end2end/TextureShaderBuiltinTests.cpp b/src/dawn/tests/end2end/TextureShaderBuiltinTests.cpp
index 429f722..847bfa0 100644
--- a/src/dawn/tests/end2end/TextureShaderBuiltinTests.cpp
+++ b/src/dawn/tests/end2end/TextureShaderBuiltinTests.cpp
@@ -203,6 +203,139 @@
EXPECT_BUFFER_U32_RANGE_EQ(expected, buffer, 0, sizeof(expected) / sizeof(uint32_t));
}
+// Testing that baseMipLevel is handled correctly.
+TEST_P(TextureShaderBuiltinTests, BaseMipLevelTextureView) {
+ // TODO(dawn:2538): failing on OpenGLES Angle backed by D3D11.
+ DAWN_SUPPRESS_TEST_IF(IsANGLED3D11());
+ constexpr uint32_t kCubeLayers = 1;
+ constexpr uint32_t kMipLevels = 3;
+ wgpu::Texture tex =
+ CreateTexture("tex", kCubeLayers, kMipLevels, 1, wgpu::TextureViewDimension::e2D);
+
+ constexpr uint32_t kBaseMipLevel = 1;
+ constexpr uint32_t kViewMipLevelCount = 2;
+ DAWN_ASSERT(kBaseMipLevel + kViewMipLevelCount <= kMipLevels);
+ wgpu::TextureView texView = CreateTextureView(tex, "texView", wgpu::TextureViewDimension::e2D,
+ kBaseMipLevel, kViewMipLevelCount);
+
+ const uint32_t textureWidthLevel0 = 1 << kMipLevels;
+ const uint32_t textureWidthLevel1 = textureWidthLevel0 >> 1;
+ const uint32_t textureWidthLevel2 = textureWidthLevel1 >> 1;
+ const uint32_t expected[] = {
+ textureWidthLevel1,
+ textureWidthLevel1,
+ textureWidthLevel2,
+ };
+
+ wgpu::BufferDescriptor bufferDesc;
+ bufferDesc.size = sizeof(expected);
+ bufferDesc.usage = wgpu::BufferUsage::Storage | wgpu::BufferUsage::CopySrc;
+ wgpu::Buffer buffer = device.CreateBuffer(&bufferDesc);
+
+ std::ostringstream shaderSource;
+ // clang-format off
+ shaderSource << R"(
+ @group(0) @binding(0) var<storage, read_write> dstBuf : array<u32>;
+ @group(0) @binding(1) var tex : texture_2d<f32>;
+
+ @compute @workgroup_size(1, 1, 1) fn main() {
+ dstBuf[0] = textureDimensions(tex).x;
+ dstBuf[1] = textureDimensions(tex, 0).x;
+ dstBuf[2] = textureDimensions(tex, 1).x;
+ }
+ )";
+ // clang-format on
+
+ wgpu::ComputePipelineDescriptor pipelineDescriptor;
+ pipelineDescriptor.compute.module = utils::CreateShaderModule(device, shaderSource.str());
+ wgpu::ComputePipeline pipeline = device.CreateComputePipeline(&pipelineDescriptor);
+
+ wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
+ {
+ wgpu::ComputePassEncoder pass = encoder.BeginComputePass();
+ pass.SetPipeline(pipeline);
+ pass.SetBindGroup(0, utils::MakeBindGroup(device, pipeline.GetBindGroupLayout(0),
+ {
+ {0, buffer},
+ {1, texView},
+ }));
+ pass.DispatchWorkgroups(1);
+ pass.End();
+ }
+
+ wgpu::CommandBuffer commands = encoder.Finish();
+ queue.Submit(1, &commands);
+
+ EXPECT_BUFFER_U32_RANGE_EQ(expected, buffer, 0, sizeof(expected) / sizeof(uint32_t));
+}
+
+// Testing that baseMipLevel is handled correctly for texture_cube.
+TEST_P(TextureShaderBuiltinTests, BaseMipLevelTextureViewCube) {
+ // TODO(dawn:2442): fix texture_cube base mip level bug.
+ DAWN_SUPPRESS_TEST_IF(IsCompatibilityMode());
+ constexpr uint32_t kCubeLayers = 6;
+ constexpr uint32_t kMipLevels = 3;
+ wgpu::Texture texCube =
+ CreateTexture("texCube", kCubeLayers, kMipLevels, 1, wgpu::TextureViewDimension::Cube);
+
+ constexpr uint32_t kBaseMipLevel = 1;
+ constexpr uint32_t kViewMipLevelCount = 2;
+ DAWN_ASSERT(kBaseMipLevel + kViewMipLevelCount <= kMipLevels);
+ wgpu::TextureView texViewCube =
+ CreateTextureView(texCube, "texViewCube", wgpu::TextureViewDimension::Cube, kBaseMipLevel,
+ kViewMipLevelCount);
+
+ const uint32_t textureWidthLevel0 = 1 << kMipLevels;
+ const uint32_t textureWidthLevel1 = textureWidthLevel0 >> 1;
+ const uint32_t textureWidthLevel2 = textureWidthLevel1 >> 1;
+ const uint32_t expected[] = {
+ textureWidthLevel1,
+ textureWidthLevel1,
+ textureWidthLevel2,
+ };
+
+ wgpu::BufferDescriptor bufferDesc;
+ bufferDesc.size = sizeof(expected);
+ bufferDesc.usage = wgpu::BufferUsage::Storage | wgpu::BufferUsage::CopySrc;
+ wgpu::Buffer buffer = device.CreateBuffer(&bufferDesc);
+
+ std::ostringstream shaderSource;
+ // clang-format off
+ shaderSource << R"(
+ @group(0) @binding(0) var<storage, read_write> dstBuf : array<u32>;
+ @group(0) @binding(1) var tex_cube : texture_cube<f32>;
+
+ @compute @workgroup_size(1, 1, 1) fn main() {
+ dstBuf[0] = textureDimensions(tex_cube).x;
+ dstBuf[1] = textureDimensions(tex_cube, 0).x;
+ dstBuf[2] = textureDimensions(tex_cube, 1).x;
+ }
+ )";
+ // clang-format on
+
+ wgpu::ComputePipelineDescriptor pipelineDescriptor;
+ pipelineDescriptor.compute.module = utils::CreateShaderModule(device, shaderSource.str());
+ wgpu::ComputePipeline pipeline = device.CreateComputePipeline(&pipelineDescriptor);
+
+ wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
+ {
+ wgpu::ComputePassEncoder pass = encoder.BeginComputePass();
+ pass.SetPipeline(pipeline);
+ pass.SetBindGroup(0, utils::MakeBindGroup(device, pipeline.GetBindGroupLayout(0),
+ {
+ {0, buffer},
+ {1, texViewCube},
+ }));
+ pass.DispatchWorkgroups(1);
+ pass.End();
+ }
+
+ wgpu::CommandBuffer commands = encoder.Finish();
+ queue.Submit(1, &commands);
+
+ EXPECT_BUFFER_U32_RANGE_EQ(expected, buffer, 0, sizeof(expected) / sizeof(uint32_t));
+}
+
// Test calling textureNumLevels & textureNumSamples inside function and taking a function param as
// the argument.
TEST_P(TextureShaderBuiltinTests, BuiltinCallInFunction) {
diff --git a/src/tint/lang/wgsl/inspector/inspector.cc b/src/tint/lang/wgsl/inspector/inspector.cc
index f00ab13..1cdbcac 100644
--- a/src/tint/lang/wgsl/inspector/inspector.cc
+++ b/src/tint/lang/wgsl/inspector/inspector.cc
@@ -1029,24 +1029,14 @@
std::unordered_set<BindingPoint> seen = {};
- auto sample_type_for_call_and_type = [](wgsl::BuiltinFn builtin, const core::type::Type* ty,
- const Vector<const ast::Expression*, 8>& args) {
- if (builtin == wgsl::BuiltinFn::kTextureNumLevels) {
+ auto sample_type_for_call_and_type = [](wgsl::BuiltinFn builtin) {
+ if (builtin == wgsl::BuiltinFn::kTextureNumLevels ||
+ builtin == wgsl::BuiltinFn::kTextureDimensions ||
+ builtin == wgsl::BuiltinFn::kTextureLoad) {
return TextureQueryType::kTextureNumLevels;
}
- if (builtin == wgsl::BuiltinFn::kTextureDimensions && args.Length() > 1) {
- // When textureDimension takes level as the input,
- // it requires calls to textureNumLevels to clamp mip levels.
- return TextureQueryType::kTextureNumLevels;
- }
- if (builtin == wgsl::BuiltinFn::kTextureLoad) {
- if (!ty->UnwrapRef()
- ->IsAnyOf<core::type::MultisampledTexture,
- core::type::DepthMultisampledTexture>()) {
- return TextureQueryType::kTextureNumLevels;
- }
- }
+ TINT_ASSERT(builtin == wgsl::BuiltinFn::kTextureNumSamples);
return TextureQueryType::kTextureNumSamples;
};
@@ -1101,19 +1091,27 @@
call->Target(),
[&](const sem::BuiltinFn* builtin) {
if (builtin->Fn() != wgsl::BuiltinFn::kTextureNumLevels &&
- builtin->Fn() != wgsl::BuiltinFn::kTextureDimensions &&
builtin->Fn() != wgsl::BuiltinFn::kTextureNumSamples &&
- builtin->Fn() != wgsl::BuiltinFn::kTextureLoad) {
+ builtin->Fn() != wgsl::BuiltinFn::kTextureLoad &&
+ // When textureDimension takes level as the input,
+ // it requires calls to textureNumLevels to clamp mip levels.
+ !(builtin->Fn() == wgsl::BuiltinFn::kTextureDimensions &&
+ call->Declaration()->args.Length() > 1)) {
return;
}
auto* texture_expr = call->Declaration()->args[0];
auto* texture_sem = sem.GetVal(texture_expr)->RootIdentifier();
TINT_ASSERT(texture_sem);
+ if (builtin->Fn() == wgsl::BuiltinFn::kTextureLoad &&
+ texture_sem->Type()
+ ->UnwrapRef()
+ ->IsAnyOf<core::type::MultisampledTexture,
+ core::type::DepthMultisampledTexture>()) {
+ return;
+ }
- auto type = sample_type_for_call_and_type(builtin->Fn(), texture_sem->Type(),
- call->Declaration()->args);
-
+ auto type = sample_type_for_call_and_type(builtin->Fn());
tint::Switch(
texture_sem, //
[&](const sem::GlobalVariable* global) { save_if_needed(global, type); },
diff --git a/src/tint/lang/wgsl/inspector/inspector_test.cc b/src/tint/lang/wgsl/inspector/inspector_test.cc
index 8d1a4b3..7468ccc 100644
--- a/src/tint/lang/wgsl/inspector/inspector_test.cc
+++ b/src/tint/lang/wgsl/inspector/inspector_test.cc
@@ -3931,22 +3931,20 @@
Inspector& inspector = Initialize(shader);
auto info = inspector.GetTextureQueries("main");
- ASSERT_EQ(1u, info.size());
-
- EXPECT_EQ(Inspector::TextureQueryType::kTextureNumSamples, info[0].type);
- EXPECT_EQ(2u, info[0].group);
- EXPECT_EQ(3u, info[0].binding);
+ ASSERT_EQ(0u, info.size());
}
TEST_F(InspectorTextureTest, TextureLoadMultipleInEP) {
std::string shader = R"(
@group(2) @binding(3) var tex1: texture_2d<f32>;
@group(1) @binding(4) var tex2: texture_multisampled_2d<f32>;
+@group(0) @binding(1) var tex3: texture_2d<f32>;
@compute @workgroup_size(1)
fn main() {
let num1 = textureLoad(tex1, vec2(0, 0), 0);
let num2 = textureLoad(tex2, vec2(0, 0), 0);
+ let num3 = textureLoad(tex3, vec2(0, 0), 0);
})";
Inspector& inspector = Initialize(shader);
@@ -3957,9 +3955,9 @@
EXPECT_EQ(Inspector::TextureQueryType::kTextureNumLevels, info[0].type);
EXPECT_EQ(2u, info[0].group);
EXPECT_EQ(3u, info[0].binding);
- EXPECT_EQ(Inspector::TextureQueryType::kTextureNumSamples, info[1].type);
- EXPECT_EQ(1u, info[1].group);
- EXPECT_EQ(4u, info[1].binding);
+ EXPECT_EQ(Inspector::TextureQueryType::kTextureNumLevels, info[1].type);
+ EXPECT_EQ(0u, info[1].group);
+ EXPECT_EQ(1u, info[1].binding);
}
TEST_F(InspectorTextureTest, TextureInSubfunction) {