Implement a basic setImage to TextureWgpu.

Bug: angleproject:8457
Change-Id: I62d7996b0492aa5dccfbc95892b5edc5cc05b20d
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/5392381
Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org>
Commit-Queue: Liza Burakova <liza@chromium.org>
Reviewed-by: Matthew Denton <mpdenton@chromium.org>
diff --git a/src/libANGLE/renderer/wgpu/TextureWgpu.cpp b/src/libANGLE/renderer/wgpu/TextureWgpu.cpp
index 35d3cf0..bf63049 100644
--- a/src/libANGLE/renderer/wgpu/TextureWgpu.cpp
+++ b/src/libANGLE/renderer/wgpu/TextureWgpu.cpp
@@ -10,6 +10,9 @@
 #include "libANGLE/renderer/wgpu/TextureWgpu.h"
 
 #include "common/debug.h"
+#include "libANGLE/angletypes.h"
+#include "libANGLE/renderer/wgpu/ContextWgpu.h"
+#include "libANGLE/renderer/wgpu/DisplayWgpu.h"
 
 namespace rx
 {
@@ -28,7 +31,9 @@
                                     gl::Buffer *unpackBuffer,
                                     const uint8_t *pixels)
 {
-    return angle::Result::Continue;
+    // TODO(liza): Upload texture data.
+    UNIMPLEMENTED();
+    return setImageImpl(context, index, size);
 }
 
 angle::Result TextureWgpu::setSubImage(const gl::Context *context,
@@ -231,4 +236,48 @@
     return angle::Result::Continue;
 }
 
+angle::Result TextureWgpu::setImageImpl(const gl::Context *context,
+                                        const gl::ImageIndex &index,
+                                        const gl::Extents &size)
+{
+    return redefineLevel(context, index, size);
+}
+
+angle::Result TextureWgpu::redefineLevel(const gl::Context *context,
+                                         const gl::ImageIndex &index,
+                                         const gl::Extents &size)
+{
+    bool levelWithinRange = false;
+    gl::LevelIndex levelIndexGL(index.getLevelIndex());
+    if (mImage && levelIndexGL >= mImage->getFirstAllocatedLevel() &&
+        levelIndexGL <
+            (mImage->getFirstAllocatedLevel() + mImage->getTextureDescriptor().mipLevelCount))
+    {
+        levelWithinRange      = true;
+        bool dimensionChanged = mImage->getTextureDescriptor().dimension !=
+                                gl_wgpu::getWgpuTextureDimension(index.getType());
+        if (dimensionChanged || size != wgpu_gl::getExtents(mImage->getTextureDescriptor().size))
+        {
+            mImage = nullptr;
+        }
+    }
+
+    if (size.empty())
+    {
+        return angle::Result::Continue;
+    }
+    ContextWgpu *contextWgpu = GetImplAs<ContextWgpu>(context);
+    DisplayWgpu *displayWgpu = contextWgpu->getDisplay();
+
+    if (mImage == nullptr && !levelWithinRange)
+    {
+        mImage                          = new webgpu::ImageHelper();
+        webgpu::TextureInfo textureInfo = mImage->getWgpuTextureInfo(index);
+        return mImage->initImage(displayWgpu->getDevice(), textureInfo.usage, textureInfo.dimension,
+                                 gl_wgpu::getExtent3D(size), wgpu::TextureFormat::RGBA8Sint,
+                                 textureInfo.mipLevelCount, 1, 0);
+    }
+    return angle::Result::Continue;
+}
+
 }  // namespace rx
diff --git a/src/libANGLE/renderer/wgpu/TextureWgpu.h b/src/libANGLE/renderer/wgpu/TextureWgpu.h
index 41c6080..d945cdf 100644
--- a/src/libANGLE/renderer/wgpu/TextureWgpu.h
+++ b/src/libANGLE/renderer/wgpu/TextureWgpu.h
@@ -164,10 +164,17 @@
                                      GLenum binding,
                                      const gl::ImageIndex &imageIndex) override;
 
-    webgpu::ImageHelper &getImage() { return mImage; }
+    webgpu::ImageHelper *getImage() { return mImage; }
 
   private:
-    webgpu::ImageHelper mImage;
+    angle::Result setImageImpl(const gl::Context *context,
+                               const gl::ImageIndex &index,
+                               const gl::Extents &size);
+
+    angle::Result redefineLevel(const gl::Context *context,
+                                const gl::ImageIndex &index,
+                                const gl::Extents &size);
+    webgpu::ImageHelper *mImage;
 };
 
 }  // namespace rx