Implement EGLImage external texture API for GL.

Tests are based on the IOSurfaceWrappingTests.
Sampling tests are not implemented, since they would require
support for the samplerExternalOES sampler type in WGSL.

Bug: chromium:1205155
Change-Id: Icc114eaf6efaee93f1b8486e615f0fd307f23080
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/50201
Commit-Queue: Stephen White <senorblanco@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@google.com>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
diff --git a/src/dawn_native/opengl/DeviceGL.cpp b/src/dawn_native/opengl/DeviceGL.cpp
index 183875d..dd38faa 100644
--- a/src/dawn_native/opengl/DeviceGL.cpp
+++ b/src/dawn_native/opengl/DeviceGL.cpp
@@ -176,6 +176,65 @@
         mFencesInFlight.emplace(sync, GetLastSubmittedCommandSerial());
     }
 
+    MaybeError Device::ValidateEGLImageCanBeWrapped(const TextureDescriptor* descriptor,
+                                                    ::EGLImage image) {
+        if (descriptor->dimension != wgpu::TextureDimension::e2D) {
+            return DAWN_VALIDATION_ERROR("EGLImage texture must be 2D");
+        }
+
+        if (descriptor->usage & (wgpu::TextureUsage::Sampled | wgpu::TextureUsage::Storage)) {
+            return DAWN_VALIDATION_ERROR("EGLImage texture cannot have sampled or storage usage");
+        }
+
+        if (descriptor->mipLevelCount != 1) {
+            return DAWN_VALIDATION_ERROR("EGLImage mip level count must be 1");
+        }
+
+        if (descriptor->size.depthOrArrayLayers != 1) {
+            return DAWN_VALIDATION_ERROR("EGLImage array layer count must be 1");
+        }
+
+        if (descriptor->sampleCount != 1) {
+            return DAWN_VALIDATION_ERROR("EGLImage sample count must be 1");
+        }
+
+        return {};
+    }
+    TextureBase* Device::CreateTextureWrappingEGLImage(const ExternalImageDescriptor* descriptor,
+                                                       ::EGLImage image) {
+        const TextureDescriptor* textureDescriptor =
+            reinterpret_cast<const TextureDescriptor*>(descriptor->cTextureDescriptor);
+
+        if (ConsumedError(ValidateTextureDescriptor(this, textureDescriptor))) {
+            return nullptr;
+        }
+        if (ConsumedError(ValidateEGLImageCanBeWrapped(textureDescriptor, image))) {
+            return nullptr;
+        }
+
+        GLuint tex;
+        gl.GenTextures(1, &tex);
+        gl.BindTexture(GL_TEXTURE_2D, tex);
+        gl.EGLImageTargetTexture2DOES(GL_TEXTURE_2D, image);
+
+        GLint width, height, internalFormat;
+        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) ||
+            textureDescriptor->size.depthOrArrayLayers != 1) {
+            ConsumedError(DAWN_VALIDATION_ERROR("EGLImage size doesn't match descriptor"));
+            gl.DeleteTextures(1, &tex);
+            return nullptr;
+        }
+
+        // TODO(dawn:803): Validate the OpenGL texture format from the EGLImage against the format
+        // in the passed-in TextureDescriptor.
+        return new Texture(this, textureDescriptor, tex, TextureBase::TextureState::OwnedInternal);
+    }
+
     MaybeError Device::TickImpl() {
         return {};
     }
diff --git a/src/dawn_native/opengl/DeviceGL.h b/src/dawn_native/opengl/DeviceGL.h
index 4e30a0e..1bb16bc 100644
--- a/src/dawn_native/opengl/DeviceGL.h
+++ b/src/dawn_native/opengl/DeviceGL.h
@@ -31,6 +31,8 @@
 #    include "common/windows_with_undefs.h"
 #endif
 
+typedef void* EGLImage;
+
 namespace dawn_native { namespace opengl {
 
     class Device : public DeviceBase {
@@ -49,6 +51,11 @@
 
         void SubmitFenceSync();
 
+        MaybeError ValidateEGLImageCanBeWrapped(const TextureDescriptor* descriptor,
+                                                ::EGLImage image);
+        TextureBase* CreateTextureWrappingEGLImage(const ExternalImageDescriptor* descriptor,
+                                                   ::EGLImage image);
+
         ResultOrError<Ref<CommandBufferBase>> CreateCommandBuffer(
             CommandEncoder* encoder,
             const CommandBufferDescriptor* descriptor) override;
diff --git a/src/dawn_native/opengl/OpenGLBackend.cpp b/src/dawn_native/opengl/OpenGLBackend.cpp
index 6cc87b0..3e089bb 100644
--- a/src/dawn_native/opengl/OpenGLBackend.cpp
+++ b/src/dawn_native/opengl/OpenGLBackend.cpp
@@ -50,4 +50,15 @@
         return static_cast<WGPUTextureFormat>(impl->GetPreferredFormat());
     }
 
+    ExternalImageDescriptorEGLImage::ExternalImageDescriptorEGLImage()
+        : ExternalImageDescriptor(ExternalImageType::EGLImage) {
+    }
+
+    WGPUTexture WrapExternalEGLImage(WGPUDevice cDevice,
+                                     const ExternalImageDescriptorEGLImage* descriptor) {
+        Device* device = reinterpret_cast<Device*>(cDevice);
+        TextureBase* texture = device->CreateTextureWrappingEGLImage(descriptor, descriptor->image);
+        return reinterpret_cast<WGPUTexture>(texture);
+    }
+
 }}  // namespace dawn_native::opengl
diff --git a/src/dawn_native/opengl/supported_extensions.json b/src/dawn_native/opengl/supported_extensions.json
index 344fe3d..8e00633 100644
--- a/src/dawn_native/opengl/supported_extensions.json
+++ b/src/dawn_native/opengl/supported_extensions.json
@@ -17,6 +17,7 @@
 
     "supported_extensions": [
         "GL_EXT_texture_compression_s3tc",
-        "GL_EXT_texture_compression_s3tc_srgb"
+        "GL_EXT_texture_compression_s3tc_srgb",
+        "GL_OES_EGL_image"
     ]
 }