OpenGL: Implement support for GL texture as ExternalImage on ANGLE.
Implement functionality to wrap a GL texture as an ExternalImage,
using ANGLE's EGL_ANGLE_display_texture_share_group extension.
Bug: chromium:1414566
Change-Id: Ib61ec97578dca77e62c5d9a191073e837cc3d5ae
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/143426
Reviewed-by: Austin Eng <enga@chromium.org>
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Loko Kung <lokokung@google.com>
Commit-Queue: Stephen White <senorblanco@chromium.org>
diff --git a/include/dawn/native/DawnNative.h b/include/dawn/native/DawnNative.h
index a53218b..df44feb 100644
--- a/include/dawn/native/DawnNative.h
+++ b/include/dawn/native/DawnNative.h
@@ -258,6 +258,7 @@
DXGISharedHandle,
D3D11Texture,
EGLImage,
+ GLTexture,
AHardwareBuffer,
Last = AHardwareBuffer,
};
diff --git a/include/dawn/native/OpenGLBackend.h b/include/dawn/native/OpenGLBackend.h
index 2be897f..9a42bfd 100644
--- a/include/dawn/native/OpenGLBackend.h
+++ b/include/dawn/native/OpenGLBackend.h
@@ -17,6 +17,7 @@
using EGLDisplay = void*;
using EGLImage = void*;
+using GLuint = unsigned int;
#include "dawn/native/DawnNative.h"
#include "dawn/webgpu_cpp_chained_struct.h"
@@ -49,6 +50,16 @@
DAWN_NATIVE_EXPORT WGPUTexture
WrapExternalEGLImage(WGPUDevice device, const ExternalImageDescriptorEGLImage* descriptor);
+struct DAWN_NATIVE_EXPORT ExternalImageDescriptorGLTexture : ExternalImageDescriptor {
+ public:
+ ExternalImageDescriptorGLTexture();
+
+ GLuint texture;
+};
+
+DAWN_NATIVE_EXPORT WGPUTexture
+WrapExternalGLTexture(WGPUDevice device, const ExternalImageDescriptorGLTexture* descriptor);
+
} // namespace dawn::native::opengl
#endif // INCLUDE_DAWN_NATIVE_OPENGLBACKEND_H_
diff --git a/src/dawn/native/opengl/ContextEGL.cpp b/src/dawn/native/opengl/ContextEGL.cpp
index 40ec2e3..1eb05f3 100644
--- a/src/dawn/native/opengl/ContextEGL.cpp
+++ b/src/dawn/native/opengl/ContextEGL.cpp
@@ -66,10 +66,6 @@
return DAWN_INTERNAL_ERROR("EGL_EXT_create_context_robustness must be supported");
}
- // Use ANGLE texture sharing iff the extension is available.
- useANGLETextureSharing &=
- strstr(extensions, "EGL_ANGLE_display_texture_share_group") != nullptr;
-
std::vector<EGLint> attrib_list{
EGL_CONTEXT_MAJOR_VERSION,
major,
@@ -79,6 +75,10 @@
EGL_TRUE,
};
if (useANGLETextureSharing) {
+ if (strstr(extensions, "EGL_ANGLE_display_texture_share_group") == nullptr) {
+ return DAWN_INTERNAL_ERROR(
+ "GL_ANGLE_display_texture_share_group must be supported to use GL texture sharing");
+ }
attrib_list.push_back(EGL_DISPLAY_TEXTURE_SHARE_GROUP_ANGLE);
attrib_list.push_back(EGL_TRUE);
}
diff --git a/src/dawn/native/opengl/DeviceGL.cpp b/src/dawn/native/opengl/DeviceGL.cpp
index 1e59ed3..5c24a8e 100644
--- a/src/dawn/native/opengl/DeviceGL.cpp
+++ b/src/dawn/native/opengl/DeviceGL.cpp
@@ -274,8 +274,7 @@
mHasPendingCommands = false;
}
-MaybeError Device::ValidateEGLImageCanBeWrapped(const TextureDescriptor* descriptor,
- ::EGLImage image) {
+MaybeError Device::ValidateTextureCanBeWrapped(const TextureDescriptor* descriptor) {
DAWN_INVALID_IF(descriptor->dimension != wgpu::TextureDimension::e2D,
"Texture dimension (%s) is not %s.", descriptor->dimension,
wgpu::TextureDimension::e2D);
@@ -304,7 +303,7 @@
if (ConsumedError(ValidateTextureDescriptor(this, textureDescriptor))) {
return nullptr;
}
- if (ConsumedError(ValidateEGLImageCanBeWrapped(textureDescriptor, image))) {
+ if (ConsumedError(ValidateTextureCanBeWrapped(textureDescriptor))) {
return nullptr;
}
@@ -313,10 +312,9 @@
gl.BindTexture(GL_TEXTURE_2D, tex);
gl.EGLImageTargetTexture2DOES(GL_TEXTURE_2D, image);
- GLint width, height, internalFormat;
+ GLint width, height;
gl.GetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width);
gl.GetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &height);
- gl.GetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &internalFormat);
if (textureDescriptor->size.width != static_cast<uint32_t>(width) ||
textureDescriptor->size.height != static_cast<uint32_t>(height) ||
@@ -333,6 +331,40 @@
return new Texture(this, textureDescriptor, tex, TextureBase::TextureState::OwnedInternal);
}
+TextureBase* Device::CreateTextureWrappingGLTexture(const ExternalImageDescriptor* descriptor,
+ GLuint texture) {
+ const OpenGLFunctions& gl = GetGL();
+ const TextureDescriptor* textureDescriptor = FromAPI(descriptor->cTextureDescriptor);
+
+ if (!HasFeature(Feature::ANGLETextureSharing)) {
+ HandleError(DAWN_VALIDATION_ERROR("Device does not support ANGLE GL texture sharing."));
+ return nullptr;
+ }
+ if (ConsumedError(ValidateTextureDescriptor(this, textureDescriptor))) {
+ return nullptr;
+ }
+ if (ConsumedError(ValidateTextureCanBeWrapped(textureDescriptor))) {
+ return nullptr;
+ }
+
+ gl.BindTexture(GL_TEXTURE_2D, texture);
+
+ GLint width, height;
+ gl.GetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width);
+ gl.GetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &height);
+
+ if (textureDescriptor->size.width != static_cast<uint32_t>(width) ||
+ textureDescriptor->size.height != static_cast<uint32_t>(height) ||
+ textureDescriptor->size.depthOrArrayLayers != 1) {
+ HandleError(DAWN_VALIDATION_ERROR(
+ "GL texture size (width: %u, height: %u, depth: 1) doesn't match descriptor size %s.",
+ width, height, &textureDescriptor->size));
+ return nullptr;
+ }
+
+ return new Texture(this, textureDescriptor, texture, TextureBase::TextureState::OwnedInternal);
+}
+
MaybeError Device::TickImpl() {
SubmitFenceSync();
return {};
diff --git a/src/dawn/native/opengl/DeviceGL.h b/src/dawn/native/opengl/DeviceGL.h
index 2be89e1..507379f 100644
--- a/src/dawn/native/opengl/DeviceGL.h
+++ b/src/dawn/native/opengl/DeviceGL.h
@@ -33,7 +33,7 @@
#include "dawn/common/windows_with_undefs.h"
#endif
-typedef void* EGLImage;
+using EGLImage = void*;
namespace dawn::native::opengl {
@@ -57,9 +57,11 @@
void SubmitFenceSync();
- MaybeError ValidateEGLImageCanBeWrapped(const TextureDescriptor* descriptor, ::EGLImage image);
+ MaybeError ValidateTextureCanBeWrapped(const TextureDescriptor* descriptor);
TextureBase* CreateTextureWrappingEGLImage(const ExternalImageDescriptor* descriptor,
::EGLImage image);
+ TextureBase* CreateTextureWrappingGLTexture(const ExternalImageDescriptor* descriptor,
+ GLuint texture);
ResultOrError<Ref<CommandBufferBase>> CreateCommandBuffer(
CommandEncoder* encoder,
diff --git a/src/dawn/native/opengl/OpenGLBackend.cpp b/src/dawn/native/opengl/OpenGLBackend.cpp
index e3f37b1..b066910 100644
--- a/src/dawn/native/opengl/OpenGLBackend.cpp
+++ b/src/dawn/native/opengl/OpenGLBackend.cpp
@@ -31,6 +31,9 @@
ExternalImageDescriptorEGLImage::ExternalImageDescriptorEGLImage()
: ExternalImageDescriptor(ExternalImageType::EGLImage) {}
+ExternalImageDescriptorGLTexture::ExternalImageDescriptorGLTexture()
+ : ExternalImageDescriptor(ExternalImageType::GLTexture) {}
+
WGPUTexture WrapExternalEGLImage(WGPUDevice device,
const ExternalImageDescriptorEGLImage* descriptor) {
Device* backendDevice = ToBackend(FromAPI(device));
@@ -39,4 +42,12 @@
return ToAPI(texture);
}
+WGPUTexture WrapExternalGLTexture(WGPUDevice device,
+ const ExternalImageDescriptorGLTexture* descriptor) {
+ Device* backendDevice = ToBackend(FromAPI(device));
+ TextureBase* texture =
+ backendDevice->CreateTextureWrappingGLTexture(descriptor, descriptor->texture);
+ return ToAPI(texture);
+}
+
} // namespace dawn::native::opengl
diff --git a/src/dawn/tests/BUILD.gn b/src/dawn/tests/BUILD.gn
index df65dfd..1aef11a 100644
--- a/src/dawn/tests/BUILD.gn
+++ b/src/dawn/tests/BUILD.gn
@@ -709,6 +709,7 @@
if (dawn_enable_opengles) {
sources += [ "white_box/EGLImageWrappingTests.cpp" ]
+ sources += [ "white_box/GLTextureWrappingTests.cpp" ]
include_dirs = [ "//third_party/khronos" ]
}
diff --git a/src/dawn/tests/white_box/GLTextureWrappingTests.cpp b/src/dawn/tests/white_box/GLTextureWrappingTests.cpp
new file mode 100644
index 0000000..16289f7
--- /dev/null
+++ b/src/dawn/tests/white_box/GLTextureWrappingTests.cpp
@@ -0,0 +1,333 @@
+// Copyright 2023 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 <utility>
+#include <vector>
+
+#include "dawn/common/DynamicLib.h"
+#include "dawn/native/OpenGLBackend.h"
+#include "dawn/native/opengl/DeviceGL.h"
+#include "dawn/tests/DawnTest.h"
+#include "dawn/utils/ComboRenderPipelineDescriptor.h"
+#include "dawn/utils/WGPUHelpers.h"
+
+namespace dawn {
+namespace {
+
+class ScopedGLTexture {
+ public:
+ ScopedGLTexture(PFNGLDELETETEXTURESPROC deleteTextures, GLuint texture)
+ : mDeleteTextures(deleteTextures), mTexture(texture) {}
+
+ ScopedGLTexture(ScopedGLTexture&& other) {
+ if (mTexture != 0) {
+ mDeleteTextures(1, &mTexture);
+ }
+ mDeleteTextures = std::move(other.mDeleteTextures);
+ mTexture = std::move(other.mTexture);
+ }
+
+ ~ScopedGLTexture() {
+ if (mTexture != 0) {
+ mDeleteTextures(1, &mTexture);
+ }
+ }
+
+ GLuint Get() const { return mTexture; }
+
+ private:
+ PFNGLDELETETEXTURESPROC mDeleteTextures = nullptr;
+ GLuint mTexture = 0;
+};
+
+class GLTextureTestBase : public DawnTest {
+ protected:
+ std::vector<wgpu::FeatureName> GetRequiredFeatures() override {
+ if (SupportsFeatures({wgpu::FeatureName::ANGLETextureSharing})) {
+ return {
+ wgpu::FeatureName::DawnInternalUsages,
+ wgpu::FeatureName::ANGLETextureSharing,
+ };
+ } else {
+ return {
+ wgpu::FeatureName::DawnInternalUsages,
+ };
+ }
+ }
+
+ void SetUp() override {
+ DawnTest::SetUp();
+ DAWN_TEST_UNSUPPORTED_IF(!SupportsFeatures({wgpu::FeatureName::ANGLETextureSharing}));
+ DAWN_TEST_UNSUPPORTED_IF(UsesWire());
+ }
+
+ public:
+ ScopedGLTexture CreateGLTexture(uint32_t width,
+ uint32_t height,
+ GLenum internalFormat,
+ GLenum format,
+ GLenum type,
+ void* data,
+ size_t size) {
+ native::opengl::Device* openglDevice =
+ native::opengl::ToBackend(native::FromAPI(device.Get()));
+ const native::opengl::OpenGLFunctions& gl = openglDevice->GetGL();
+ GLuint tex;
+ gl.GenTextures(1, &tex);
+ gl.BindTexture(GL_TEXTURE_2D, tex);
+ gl.TexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height, 0, format, type, data);
+
+ return ScopedGLTexture(gl.DeleteTextures, tex);
+ }
+ wgpu::Texture WrapGLTexture(const wgpu::TextureDescriptor* descriptor, GLuint texture) {
+ native::opengl::ExternalImageDescriptorGLTexture externDesc;
+ externDesc.cTextureDescriptor = reinterpret_cast<const WGPUTextureDescriptor*>(descriptor);
+ externDesc.texture = texture;
+ return wgpu::Texture::Acquire(
+ native::opengl::WrapExternalGLTexture(device.Get(), &externDesc));
+ }
+};
+
+// A small fixture used to initialize default data for the GLTexture validation tests.
+// These tests are skipped if the harness is using the wire.
+class GLTextureValidationTests : public GLTextureTestBase {
+ public:
+ GLTextureValidationTests() {
+ descriptor.dimension = wgpu::TextureDimension::e2D;
+ descriptor.format = wgpu::TextureFormat::RGBA8Unorm;
+ descriptor.size = {10, 10, 1};
+ descriptor.sampleCount = 1;
+ descriptor.mipLevelCount = 1;
+ descriptor.usage = wgpu::TextureUsage::RenderAttachment;
+ }
+
+ ScopedGLTexture CreateDefaultGLTexture() {
+ return CreateGLTexture(10, 10, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, nullptr, 0);
+ }
+
+ protected:
+ wgpu::TextureDescriptor descriptor;
+};
+
+class GLTextureValidationNoANGLETextureSharingTests : public GLTextureValidationTests {
+ protected:
+ std::vector<wgpu::FeatureName> GetRequiredFeatures() override {
+ return {wgpu::FeatureName::DawnInternalUsages};
+ }
+};
+
+// Test a successful wrapping of a GL texture in a WebGPU texture
+TEST_P(GLTextureValidationTests, Success) {
+ ScopedGLTexture glTexture = CreateDefaultGLTexture();
+ wgpu::Texture texture = WrapGLTexture(&descriptor, glTexture.Get());
+ ASSERT_NE(texture.Get(), nullptr);
+}
+
+// Test an unsuccessful wrapping of a GL texture in a WebGPU texture when
+// the device does not support the ANGLETextureSharing Feature
+TEST_P(GLTextureValidationNoANGLETextureSharingTests, Failure) {
+ ScopedGLTexture glTexture = CreateDefaultGLTexture();
+ ASSERT_DEVICE_ERROR(wgpu::Texture texture = WrapGLTexture(&descriptor, glTexture.Get()));
+ ASSERT_EQ(texture.Get(), nullptr);
+}
+
+// Test a successful wrapping of a GL texture in a texture with DawnTextureInternalUsageDescriptor
+TEST_P(GLTextureValidationTests, SuccessWithInternalUsageDescriptor) {
+ wgpu::DawnTextureInternalUsageDescriptor internalDesc = {};
+ descriptor.nextInChain = &internalDesc;
+ internalDesc.internalUsage = wgpu::TextureUsage::CopySrc;
+ internalDesc.sType = wgpu::SType::DawnTextureInternalUsageDescriptor;
+
+ ScopedGLTexture glTexture = CreateDefaultGLTexture();
+ wgpu::Texture texture = WrapGLTexture(&descriptor, glTexture.Get());
+ ASSERT_NE(texture.Get(), nullptr);
+}
+
+// Test an error occurs if an invalid sType is the nextInChain
+TEST_P(GLTextureValidationTests, InvalidTextureDescriptor) {
+ wgpu::ChainedStruct chainedDescriptor;
+ chainedDescriptor.sType = wgpu::SType::SurfaceDescriptorFromWindowsSwapChainPanel;
+ descriptor.nextInChain = &chainedDescriptor;
+
+ ScopedGLTexture glTexture = CreateDefaultGLTexture();
+ ASSERT_DEVICE_ERROR(wgpu::Texture texture = WrapGLTexture(&descriptor, glTexture.Get()));
+
+ ASSERT_EQ(texture.Get(), nullptr);
+}
+
+// Test an error occurs if the descriptor dimension isn't 2D
+TEST_P(GLTextureValidationTests, InvalidTextureDimension) {
+ descriptor.dimension = wgpu::TextureDimension::e3D;
+
+ ScopedGLTexture glTexture = CreateDefaultGLTexture();
+ ASSERT_DEVICE_ERROR(wgpu::Texture texture = WrapGLTexture(&descriptor, glTexture.Get()));
+
+ ASSERT_EQ(texture.Get(), nullptr);
+}
+
+// Test an error occurs if the texture usage is not RenderAttachment
+TEST_P(GLTextureValidationTests, InvalidTextureUsage) {
+ descriptor.usage = wgpu::TextureUsage::TextureBinding;
+
+ ScopedGLTexture glTexture = CreateDefaultGLTexture();
+ wgpu::Texture texture;
+ ASSERT_DEVICE_ERROR(texture = WrapGLTexture(&descriptor, glTexture.Get()));
+
+ ASSERT_EQ(texture.Get(), nullptr);
+ descriptor.usage = wgpu::TextureUsage::StorageBinding;
+
+ ASSERT_DEVICE_ERROR(texture = WrapGLTexture(&descriptor, glTexture.Get()));
+
+ ASSERT_EQ(texture.Get(), nullptr);
+}
+
+// Test an error occurs if the descriptor mip level count isn't 1
+TEST_P(GLTextureValidationTests, InvalidMipLevelCount) {
+ descriptor.mipLevelCount = 2;
+
+ ScopedGLTexture glTexture = CreateDefaultGLTexture();
+ ASSERT_DEVICE_ERROR(wgpu::Texture texture = WrapGLTexture(&descriptor, glTexture.Get()));
+ ASSERT_EQ(texture.Get(), nullptr);
+}
+
+// Test an error occurs if the descriptor depth isn't 1
+TEST_P(GLTextureValidationTests, InvalidDepth) {
+ descriptor.size.depthOrArrayLayers = 2;
+
+ ScopedGLTexture glTexture = CreateDefaultGLTexture();
+ ASSERT_DEVICE_ERROR(wgpu::Texture texture = WrapGLTexture(&descriptor, glTexture.Get()));
+ ASSERT_EQ(texture.Get(), nullptr);
+}
+
+// Test an error occurs if the descriptor sample count isn't 1
+TEST_P(GLTextureValidationTests, InvalidSampleCount) {
+ descriptor.sampleCount = 4;
+
+ ScopedGLTexture glTexture = CreateDefaultGLTexture();
+ ASSERT_DEVICE_ERROR(wgpu::Texture texture = WrapGLTexture(&descriptor, glTexture.Get()));
+ ASSERT_EQ(texture.Get(), nullptr);
+}
+
+// Test an error occurs if the descriptor width doesn't match the surface's
+TEST_P(GLTextureValidationTests, InvalidWidth) {
+ descriptor.size.width = 11;
+
+ ScopedGLTexture glTexture = CreateDefaultGLTexture();
+ ASSERT_DEVICE_ERROR(wgpu::Texture texture = WrapGLTexture(&descriptor, glTexture.Get()));
+ ASSERT_EQ(texture.Get(), nullptr);
+}
+
+// Test an error occurs if the descriptor height doesn't match the surface's
+TEST_P(GLTextureValidationTests, InvalidHeight) {
+ descriptor.size.height = 11;
+
+ ScopedGLTexture glTexture = CreateDefaultGLTexture();
+ ASSERT_DEVICE_ERROR(wgpu::Texture texture = WrapGLTexture(&descriptor, glTexture.Get()));
+ ASSERT_EQ(texture.Get(), nullptr);
+}
+
+// Fixture to test using GL textures through different usages.
+// These tests are skipped if the harness is using the wire.
+class GLTextureUsageTests : public GLTextureTestBase {
+ public:
+ // Test that clearing using BeginRenderPass writes correct data in the GL texture.
+ void DoClearTest(GLuint texture,
+ wgpu::TextureFormat format,
+ GLenum glFormat,
+ GLenum glType,
+ void* data,
+ size_t dataSize) {
+ native::opengl::Device* openglDevice =
+ native::opengl::ToBackend(native::FromAPI(device.Get()));
+ const native::opengl::OpenGLFunctions& gl = openglDevice->GetGL();
+
+ // Get a texture view for the GL texture.
+ wgpu::TextureDescriptor textureDescriptor;
+ textureDescriptor.dimension = wgpu::TextureDimension::e2D;
+ textureDescriptor.format = format;
+ textureDescriptor.size = {1, 1, 1};
+ textureDescriptor.sampleCount = 1;
+ textureDescriptor.mipLevelCount = 1;
+ textureDescriptor.usage = wgpu::TextureUsage::RenderAttachment;
+
+ wgpu::DawnTextureInternalUsageDescriptor internalDesc = {};
+ textureDescriptor.nextInChain = &internalDesc;
+ internalDesc.internalUsage = wgpu::TextureUsage::CopySrc;
+ internalDesc.sType = wgpu::SType::DawnTextureInternalUsageDescriptor;
+
+ wgpu::Texture wrappedTexture = WrapGLTexture(&textureDescriptor, texture);
+ ASSERT_NE(wrappedTexture, nullptr);
+
+ wgpu::TextureView wrappedView = wrappedTexture.CreateView();
+
+ utils::ComboRenderPassDescriptor renderPassDescriptor({wrappedView}, {});
+ renderPassDescriptor.cColorAttachments[0].clearValue = {1 / 255.0f, 2 / 255.0f, 3 / 255.0f,
+ 4 / 255.0f};
+
+ // Execute commands to clear the wrapped texture
+ wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
+ wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPassDescriptor);
+ pass.End();
+
+ wgpu::CommandBuffer commands = encoder.Finish();
+ queue.Submit(1, &commands);
+
+ // Check the correct data was written
+ std::vector<uint8_t> result(dataSize);
+ GLuint fbo;
+ gl.GenFramebuffers(1, &fbo);
+ gl.BindFramebuffer(GL_FRAMEBUFFER, fbo);
+ gl.FramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture,
+ 0);
+ gl.ReadPixels(0, 0, 1, 1, glFormat, glType, result.data());
+ gl.BindFramebuffer(GL_FRAMEBUFFER, 0);
+ gl.DeleteFramebuffers(1, &fbo);
+ ASSERT_EQ(0, memcmp(result.data(), data, dataSize));
+ }
+};
+
+// Test clearing a R8 GL texture
+TEST_P(GLTextureUsageTests, ClearR8GLTexture) {
+ ScopedGLTexture glTexture = CreateGLTexture(1, 1, GL_R8, GL_RED, GL_UNSIGNED_BYTE, nullptr, 0);
+
+ uint8_t data = 0x01;
+ DoClearTest(glTexture.Get(), wgpu::TextureFormat::R8Unorm, GL_RED, GL_UNSIGNED_BYTE, &data,
+ sizeof(data));
+}
+
+// Test clearing a RG8 GL texture
+TEST_P(GLTextureUsageTests, ClearRG8GLTexture) {
+ ScopedGLTexture glTexture = CreateGLTexture(1, 1, GL_RG8, GL_RG, GL_UNSIGNED_BYTE, nullptr, 0);
+
+ uint16_t data = 0x0201;
+ DoClearTest(glTexture.Get(), wgpu::TextureFormat::RG8Unorm, GL_RG, GL_UNSIGNED_BYTE, &data,
+ sizeof(data));
+}
+
+// Test clearing an RGBA8 GL texture
+TEST_P(GLTextureUsageTests, ClearRGBA8GLTexture) {
+ ScopedGLTexture glTexture =
+ CreateGLTexture(1, 1, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, nullptr, 0);
+
+ uint32_t data = 0x04030201;
+ DoClearTest(glTexture.Get(), wgpu::TextureFormat::RGBA8Unorm, GL_RGBA, GL_UNSIGNED_BYTE, &data,
+ sizeof(data));
+}
+
+DAWN_INSTANTIATE_TEST(GLTextureValidationTests, OpenGLESBackend());
+DAWN_INSTANTIATE_TEST(GLTextureValidationNoANGLETextureSharingTests, OpenGLESBackend());
+DAWN_INSTANTIATE_TEST(GLTextureUsageTests, OpenGLESBackend());
+
+} // anonymous namespace
+} // namespace dawn