Add ExternalTexture::Refresh() and ExternalTexture::Expire()

ExternalTexture has active, expired and destroyed states.

Only active state external texture is valid to submit.

Expired state external texture can be refresh to active but
destroyed external texture cannot be refresh.

Bug: chromium:1412338
Change-Id: Ic7f12d274d27b644f19ec3ef8b46c110610afa2b
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/120982
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Commit-Queue: Shaobo Yan <shaobo.yan@intel.com>
This commit is contained in:
Yan,Shaobo 2023-02-24 02:09:38 +00:00 committed by Dawn LUCI CQ
parent dd0332ec91
commit e958db0490
4 changed files with 172 additions and 190 deletions

View File

@ -1399,6 +1399,14 @@
{
"name": "destroy",
"returns": "void"
},
{
"name": "expire",
"returns": "void"
},
{
"name": "refresh",
"returns": "void"
}
]
},

View File

@ -133,7 +133,7 @@ ExternalTextureBase::ExternalTextureBase(DeviceBase* device,
: ApiObjectBase(device, descriptor->label),
mVisibleOrigin(descriptor->visibleOrigin),
mVisibleSize(descriptor->visibleSize),
mState(ExternalTextureState::Alive) {
mState(ExternalTextureState::Active) {
GetObjectTrackingList()->Track(this);
}
@ -324,8 +324,8 @@ const std::array<Ref<TextureViewBase>, kMaxPlanesPerFormat>& ExternalTextureBase
MaybeError ExternalTextureBase::ValidateCanUseInSubmitNow() const {
ASSERT(!IsError());
DAWN_INVALID_IF(mState == ExternalTextureState::Destroyed,
"Destroyed external texture %s is used in a submit.", this);
DAWN_INVALID_IF(mState != ExternalTextureState::Active,
"External texture %s used in a submit is not active.", this);
for (uint32_t i = 0; i < kMaxPlanesPerFormat; ++i) {
if (mTextureViews[i] != nullptr) {
@ -336,10 +336,33 @@ MaybeError ExternalTextureBase::ValidateCanUseInSubmitNow() const {
return {};
}
void ExternalTextureBase::APIDestroy() {
if (GetDevice()->ConsumedError(GetDevice()->ValidateObject(this))) {
MaybeError ExternalTextureBase::ValidateRefresh() {
DAWN_TRY(GetDevice()->ValidateObject(this));
DAWN_INVALID_IF(mState == ExternalTextureState::Destroyed, "%s is destroyed.", this);
return {};
}
MaybeError ExternalTextureBase::ValidateExpire() {
DAWN_TRY(GetDevice()->ValidateObject(this));
DAWN_INVALID_IF(mState != ExternalTextureState::Active, "%s is not active.", this);
return {};
}
void ExternalTextureBase::APIRefresh() {
if (GetDevice()->ConsumedError(ValidateRefresh(), "calling %s.Refresh()", this)) {
return;
}
mState = ExternalTextureState::Active;
}
void ExternalTextureBase::APIExpire() {
if (GetDevice()->ConsumedError(ValidateExpire(), "calling %s.Expire()", this)) {
return;
}
mState = ExternalTextureState::Expired;
}
void ExternalTextureBase::APIDestroy() {
Destroy();
}

View File

@ -57,7 +57,9 @@ class ExternalTextureBase : public ApiObjectBase {
MaybeError ValidateCanUseInSubmitNow() const;
static ExternalTextureBase* MakeError(DeviceBase* device);
void APIExpire();
void APIDestroy();
void APIRefresh();
protected:
ExternalTextureBase(DeviceBase* device, const ExternalTextureDescriptor* descriptor);
@ -68,9 +70,12 @@ class ExternalTextureBase : public ApiObjectBase {
~ExternalTextureBase() override;
private:
enum class ExternalTextureState { Alive, Destroyed };
enum class ExternalTextureState { Active, Expired, Destroyed };
ExternalTextureBase(DeviceBase* device, ObjectBase::ErrorTag tag);
MaybeError ValidateRefresh();
MaybeError ValidateExpire();
Ref<TextureBase> mPlaceholderTexture;
Ref<BufferBase> mParamsBuffer;
std::array<Ref<TextureViewBase>, kMaxPlanesPerFormat> mTextureViews;

View File

@ -34,11 +34,68 @@ class ExternalTextureTest : public ValidationTest {
return descriptor;
}
wgpu::ExternalTexture CreateDefaultExternalTexture() {
wgpu::ExternalTextureDescriptor externalDesc = CreateDefaultExternalTextureDescriptor();
externalDesc.plane0 = defaultTexture.CreateView();
return device.CreateExternalTexture(&externalDesc);
}
void SubmitExternalTextureInDefaultRenderPass(wgpu::ExternalTexture externalTexture,
bool success) {
// 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);
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
pass.SetBindGroup(0, bindGroup);
pass.End();
wgpu::CommandBuffer commands = encoder.Finish();
if (success) {
queue.Submit(1, &commands);
} else {
ASSERT_DEVICE_ERROR(queue.Submit(1, &commands));
}
}
void SubmitExternalTextureInDefaultComputePass(wgpu::ExternalTexture externalTexture,
bool success) {
// 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}});
wgpu::ComputePassDescriptor computePass;
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
wgpu::ComputePassEncoder pass = encoder.BeginComputePass(&computePass);
pass.SetBindGroup(0, bindGroup);
pass.End();
wgpu::CommandBuffer commands = encoder.Finish();
if (success) {
queue.Submit(1, &commands);
} else {
ASSERT_DEVICE_ERROR(queue.Submit(1, &commands));
}
}
protected:
void SetUp() override {
ValidationTest::SetUp();
queue = device.GetQueue();
wgpu::TextureDescriptor textureDescriptor = CreateTextureDescriptor();
defaultTexture = device.CreateTexture(&textureDescriptor);
}
wgpu::ExternalTextureDescriptor CreateDefaultExternalTextureDescriptor() {
@ -67,6 +124,7 @@ class ExternalTextureTest : public ValidationTest {
std::array<float, 12> mPlaceholderConstantArray;
wgpu::Queue queue;
wgpu::Texture defaultTexture;
};
TEST_F(ExternalTextureTest, CreateExternalTextureValidation) {
@ -273,55 +331,85 @@ TEST_F(ExternalTextureTest, CreateMultiplanarExternalTextureValidation) {
}
}
// Test that submitting a render pass that contains a destroyed external texture results in
// an error.
// Test that refresh on an expired/active external texture.
TEST_F(ExternalTextureTest, RefreshExternalTexture) {
wgpu::ExternalTexture externalTexture = CreateDefaultExternalTexture();
externalTexture.Refresh();
externalTexture.Expire();
externalTexture.Refresh();
}
// Test that refresh on a destroyed external texture results in an error.
TEST_F(ExternalTextureTest, RefreshDestroyedExternalTexture) {
wgpu::ExternalTexture externalTexture = CreateDefaultExternalTexture();
// Refresh on destroyed external texture should result in an error.
externalTexture.Destroy();
ASSERT_DEVICE_ERROR(externalTexture.Refresh());
}
// Test that expire on a destroyed external texture results in an error.
TEST_F(ExternalTextureTest, ExpireDestroyedExternalTexture) {
wgpu::ExternalTexture externalTexture = CreateDefaultExternalTexture();
externalTexture.Destroy();
ASSERT_DEVICE_ERROR(externalTexture.Expire());
}
// Test that submitting a render pass that contains an active external texture.
TEST_F(ExternalTextureTest, SubmitActiveExternalTextureInRenderPass) {
wgpu::ExternalTexture externalTexture = CreateDefaultExternalTexture();
SubmitExternalTextureInDefaultRenderPass(externalTexture, true /* success = true */);
}
// Test that submitting a render pass that contains an expired external texture results in an error.
TEST_F(ExternalTextureTest, SubmitExpiredExternalTextureInRenderPass) {
wgpu::ExternalTexture externalTexture = CreateDefaultExternalTexture();
externalTexture.Expire();
SubmitExternalTextureInDefaultRenderPass(externalTexture, false /* success = false */);
}
// Test that submitting a render pass that contains an destroyed external texture results in an
// error.
TEST_F(ExternalTextureTest, SubmitDestroyedExternalTextureInRenderPass) {
wgpu::TextureDescriptor textureDescriptor = CreateTextureDescriptor();
wgpu::Texture texture = device.CreateTexture(&textureDescriptor);
wgpu::ExternalTexture externalTexture = CreateDefaultExternalTexture();
externalTexture.Destroy();
SubmitExternalTextureInDefaultRenderPass(externalTexture, false /* success = false */);
}
wgpu::ExternalTextureDescriptor externalDesc = CreateDefaultExternalTextureDescriptor();
externalDesc.plane0 = texture.CreateView();
wgpu::ExternalTexture externalTexture = device.CreateExternalTexture(&externalDesc);
// Test that submitting a compute pass that contains an active external.
TEST_F(ExternalTextureTest, SubmitActiveExternalTextureInComputePass) {
wgpu::ExternalTexture externalTexture = CreateDefaultExternalTexture();
SubmitExternalTextureInDefaultComputePass(externalTexture, true /* success = true */);
}
// 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}});
// Test that submitting a compute pass that contains an expired external texture results in an
// error.
TEST_F(ExternalTextureTest, SubmitExpiredExternalTextureInComputePass) {
wgpu::ExternalTexture externalTexture = CreateDefaultExternalTexture();
externalTexture.Expire();
SubmitExternalTextureInDefaultComputePass(externalTexture, false /* success = false */);
}
// Create another texture to use as a color attachment.
wgpu::TextureDescriptor renderTextureDescriptor = CreateTextureDescriptor();
wgpu::Texture renderTexture = device.CreateTexture(&renderTextureDescriptor);
wgpu::TextureView renderView = renderTexture.CreateView();
// Test that submitting a compute pass that contains an active external texture should success.
TEST_F(ExternalTextureTest, SubmitDestroyedExternalTextureInComputePass) {
wgpu::ExternalTexture externalTexture = CreateDefaultExternalTexture();
externalTexture.Destroy();
SubmitExternalTextureInDefaultComputePass(externalTexture, false /* success = false */);
}
utils::ComboRenderPassDescriptor renderPass({renderView}, nullptr);
// Test that refresh an expired external texture and submit a compute pass with it.
TEST_F(ExternalTextureTest, RefreshExpiredExternalTexture) {
wgpu::ExternalTexture externalTexture = CreateDefaultExternalTexture();
externalTexture.Expire();
// Control case should succeed.
{
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
{
pass.SetBindGroup(0, bindGroup);
pass.End();
}
// Submit with expired external texture results in error
SubmitExternalTextureInDefaultComputePass(externalTexture, false /* success = false */);
wgpu::CommandBuffer commands = encoder.Finish();
queue.Submit(1, &commands);
}
// Destroying the external texture should result in an error.
{
externalTexture.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));
}
externalTexture.Refresh();
// Refreshed external texture could be submitted.
SubmitExternalTextureInDefaultComputePass(externalTexture, true /* success = true */);
}
// Test that submitting a render pass that contains a dereferenced external texture results in
@ -375,148 +463,6 @@ TEST_F(ExternalTextureTest, SubmitDereferencedExternalTextureInRenderPass) {
}
}
// Test that submitting a render pass that contains a destroyed external texture plane
// results in an error.
TEST_F(ExternalTextureTest, SubmitDestroyedExternalTexturePlaneInRenderPass) {
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 an external texture underlying plane 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));
}
}
// Test that submitting a compute pass that contains a destroyed external texture results in
// an error.
TEST_F(ExternalTextureTest, SubmitDestroyedExternalTextureInComputePass) {
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}});
wgpu::ComputePassDescriptor computePass;
// Control case should succeed.
{
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
wgpu::ComputePassEncoder pass = encoder.BeginComputePass(&computePass);
{
pass.SetBindGroup(0, bindGroup);
pass.End();
}
wgpu::CommandBuffer commands = encoder.Finish();
queue.Submit(1, &commands);
}
// Destroying the external texture should result in an error.
{
externalTexture.Destroy();
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
wgpu::ComputePassEncoder pass = encoder.BeginComputePass(&computePass);
{
pass.SetBindGroup(0, bindGroup);
pass.End();
}
wgpu::CommandBuffer commands = encoder.Finish();
ASSERT_DEVICE_ERROR(queue.Submit(1, &commands));
}
}
// Test that submitting a compute pass that contains a destroyed external texture plane
// results in an error.
TEST_F(ExternalTextureTest, SubmitDestroyedExternalTexturePlaneInComputePass) {
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}});
wgpu::ComputePassDescriptor computePass;
// Control case should succeed.
{
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
wgpu::ComputePassEncoder pass = encoder.BeginComputePass(&computePass);
{
pass.SetBindGroup(0, bindGroup);
pass.End();
}
wgpu::CommandBuffer commands = encoder.Finish();
queue.Submit(1, &commands);
}
// Destroying an external texture underlying plane should result in an error.
{
texture.Destroy();
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
wgpu::ComputePassEncoder pass = encoder.BeginComputePass(&computePass);
{
pass.SetBindGroup(0, bindGroup);
pass.End();
}
wgpu::CommandBuffer commands = encoder.Finish();
ASSERT_DEVICE_ERROR(queue.Submit(1, &commands));
}
}
// Ensure that bind group validation catches external textures mimatched from the BGL.
TEST_F(ExternalTextureTest, BindGroupDoesNotMatchLayout) {
wgpu::TextureDescriptor textureDescriptor = CreateTextureDescriptor();