Add visibleRect to ExternalTextureDescriptor
Add visibleRect in ExternalTextureDescriptor to create ExternalTexture.
This helps ExternalTexture present the content correctly if needed.
Bug: chromium:1361363
Change-Id: I54b1912305080943babd7558ef40bca8528c932c
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/106181
Reviewed-by: Austin Eng <enga@chromium.org>
Commit-Queue: Shaobo Yan <shaobo.yan@intel.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
diff --git a/dawn.json b/dawn.json
index 2bcd047..4b2f150 100644
--- a/dawn.json
+++ b/dawn.json
@@ -1330,6 +1330,14 @@
{"value": 3, "name": "error"}
]
},
+ "extent 2D": {
+ "category": "structure",
+ "_TODO": "crbug.com/1316671: Remove default value of 'width' after chromium side chagnes landed",
+ "members": [
+ {"name": "width", "type": "uint32_t", "default": 0},
+ {"name": "height", "type": "uint32_t", "default": 1}
+ ]
+ },
"extent 3D": {
"category": "structure",
"members": [
@@ -1359,10 +1367,12 @@
"category": "structure",
"extensible": "in",
"tags": ["dawn"],
+ "_TODO": "crbug.com/1316671: Mark 'visible rect' as must have after chromium side changes landed",
"members": [
{"name": "label", "type": "char", "annotation": "const*", "length": "strlen", "optional": true},
{"name": "plane 0", "type": "texture view"},
{"name": "plane 1", "type": "texture view", "optional": true},
+ {"name": "visible rect", "type": "extent 2D"},
{"name": "do yuv to rgb conversion only", "type": "bool", "default": "false"},
{"name": "yuv to rgb conversion matrix", "type": "float", "annotation": "const*",
"length": 12, "optional": true},
diff --git a/src/dawn/native/ExternalTexture.cpp b/src/dawn/native/ExternalTexture.cpp
index ab40470..14ea84f 100644
--- a/src/dawn/native/ExternalTexture.cpp
+++ b/src/dawn/native/ExternalTexture.cpp
@@ -99,6 +99,22 @@
}
}
+ // TODO(crbug.com/1316671): visibleRect must have valid value after chromium side changes
+ // landed.
+ if (descriptor->visibleRect.width > 0) {
+ DAWN_INVALID_IF(descriptor->visibleRect.width == 0 || descriptor->visibleRect.height == 0,
+ "VisibleRect(%u, %u) have 0 on width or height.",
+ descriptor->visibleRect.width, descriptor->visibleRect.height);
+
+ Extent3D maxVisibleRectSize = descriptor->plane0->GetTexture()->GetSize();
+ DAWN_INVALID_IF(descriptor->visibleRect.width > maxVisibleRectSize.width ||
+ descriptor->visibleRect.height > maxVisibleRectSize.height,
+ "VisibleRect(%u, %u) is exceed the max visible rect size, defined by "
+ "Plane0 size (%u, %u).",
+ descriptor->visibleRect.width, descriptor->visibleRect.height,
+ maxVisibleRectSize.width, maxVisibleRectSize.height);
+ }
+
return {};
}
@@ -114,7 +130,9 @@
ExternalTextureBase::ExternalTextureBase(DeviceBase* device,
const ExternalTextureDescriptor* descriptor)
- : ApiObjectBase(device, descriptor->label), mState(ExternalTextureState::Alive) {
+ : ApiObjectBase(device, descriptor->label),
+ mVisibleRect(descriptor->visibleRect),
+ mState(ExternalTextureState::Alive) {
GetObjectTrackingList()->Track(this);
}
@@ -200,6 +218,13 @@
ASSERT(!IsError());
DAWN_INVALID_IF(mState == ExternalTextureState::Destroyed,
"Destroyed external texture %s is used in a submit.", this);
+
+ for (uint32_t i = 0; i < kMaxPlanesPerFormat; ++i) {
+ if (mTextureViews[i] != nullptr) {
+ DAWN_TRY_CONTEXT(mTextureViews[i]->GetTexture()->ValidateCanUseInSubmitNow(),
+ "Validate plane %u of %s can be used in a submit.", i, this);
+ }
+ }
return {};
}
@@ -227,4 +252,9 @@
return ObjectType::ExternalTexture;
}
+const Extent2D& ExternalTextureBase::GetVisibleRect() const {
+ ASSERT(!IsError());
+ return mVisibleRect;
+}
+
} // namespace dawn::native
diff --git a/src/dawn/native/ExternalTexture.h b/src/dawn/native/ExternalTexture.h
index 509a7ee..6ea47e8 100644
--- a/src/dawn/native/ExternalTexture.h
+++ b/src/dawn/native/ExternalTexture.h
@@ -49,6 +49,7 @@
BufferBase* GetParamsBuffer() const;
const std::array<Ref<TextureViewBase>, kMaxPlanesPerFormat>& GetTextureViews() const;
ObjectType GetType() const override;
+ const Extent2D& GetVisibleRect() const;
MaybeError ValidateCanUseInSubmitNow() const;
static ExternalTextureBase* MakeError(DeviceBase* device);
@@ -73,6 +74,10 @@
Ref<BufferBase> mParamsBuffer;
std::array<Ref<TextureViewBase>, kMaxPlanesPerFormat> mTextureViews;
+ // TODO(dawn:1082) Use the visible rect in the external texture shader code to sample
+ // video content.
+ Extent2D mVisibleRect;
+
ExternalTextureState mState;
};
} // namespace dawn::native
diff --git a/src/dawn/tests/unittests/validation/ExternalTextureTests.cpp b/src/dawn/tests/unittests/validation/ExternalTextureTests.cpp
index 6f6aebc..55d9499 100644
--- a/src/dawn/tests/unittests/validation/ExternalTextureTests.cpp
+++ b/src/dawn/tests/unittests/validation/ExternalTextureTests.cpp
@@ -581,4 +581,90 @@
}
}
+// Test create external texture with too large visible rect results in error.
+TEST_F(ExternalTextureTest, CreateExternalTextureWithErrorVisibleRect) {
+ // Control case should succeed.
+ {
+ wgpu::TextureDescriptor textureDescriptor = CreateTextureDescriptor();
+ wgpu::Texture texture = device.CreateTexture(&textureDescriptor);
+
+ wgpu::ExternalTextureDescriptor externalDesc = CreateDefaultExternalTextureDescriptor();
+ externalDesc.plane0 = texture.CreateView();
+ externalDesc.visibleRect = {texture.GetWidth(), texture.GetHeight()};
+ device.CreateExternalTexture(&externalDesc);
+ }
+
+ // VisibleRect is OOB on width
+ {
+ wgpu::TextureDescriptor textureDescriptor = CreateTextureDescriptor();
+ wgpu::Texture texture = device.CreateTexture(&textureDescriptor);
+
+ wgpu::ExternalTextureDescriptor externalDesc = CreateDefaultExternalTextureDescriptor();
+ externalDesc.plane0 = texture.CreateView();
+ externalDesc.visibleRect = {texture.GetWidth() + 1, texture.GetHeight()};
+ ASSERT_DEVICE_ERROR(device.CreateExternalTexture(&externalDesc));
+ }
+
+ // VisibleRect is OOB on height
+ {
+ wgpu::TextureDescriptor textureDescriptor = CreateTextureDescriptor();
+ wgpu::Texture texture = device.CreateTexture(&textureDescriptor);
+
+ wgpu::ExternalTextureDescriptor externalDesc = CreateDefaultExternalTextureDescriptor();
+ externalDesc.plane0 = texture.CreateView();
+ externalDesc.visibleRect = {texture.GetWidth(), texture.GetHeight() + 1};
+ ASSERT_DEVICE_ERROR(device.CreateExternalTexture(&externalDesc));
+ }
+}
+
+// Test that submitting an external texture with a plane that is not submittable results in error.
+TEST_F(ExternalTextureTest, SubmitExternalTextureWithDestroyedPlane) {
+ wgpu::TextureDescriptor textureDescriptor = CreateTextureDescriptor();
+ wgpu::Texture texture = device.CreateTexture(&textureDescriptor);
+
+ wgpu::ExternalTextureDescriptor externalDesc = CreateDefaultExternalTextureDescriptor();
+ externalDesc.plane0 = texture.CreateView();
+ wgpu::ExternalTexture externalTexture = device.CreateExternalTexture(&externalDesc);
+
+ // Create a bind group that contains the external texture.
+ wgpu::BindGroupLayout bgl = utils::MakeBindGroupLayout(
+ device, {{0, wgpu::ShaderStage::Fragment, &utils::kExternalTextureBindingLayout}});
+ wgpu::BindGroup bindGroup = utils::MakeBindGroup(device, bgl, {{0, externalTexture}});
+
+ // Create another texture to use as a color attachment.
+ wgpu::TextureDescriptor renderTextureDescriptor = CreateTextureDescriptor();
+ wgpu::Texture renderTexture = device.CreateTexture(&renderTextureDescriptor);
+ wgpu::TextureView renderView = renderTexture.CreateView();
+
+ utils::ComboRenderPassDescriptor renderPass({renderView}, nullptr);
+
+ // Control case should succeed.
+ {
+ wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
+ wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
+ {
+ pass.SetBindGroup(0, bindGroup);
+ pass.End();
+ }
+
+ wgpu::CommandBuffer commands = encoder.Finish();
+
+ queue.Submit(1, &commands);
+ }
+
+ // Destroying the plane0 backed texture should result in an error.
+ {
+ texture.Destroy();
+ wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
+ wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
+ {
+ pass.SetBindGroup(0, bindGroup);
+ pass.End();
+ }
+
+ wgpu::CommandBuffer commands = encoder.Finish();
+ ASSERT_DEVICE_ERROR(queue.Submit(1, &commands));
+ }
+}
+
} // namespace