• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2024 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // TextureWgpu.cpp:
7 //    Implements the class methods for TextureWgpu.
8 //
9 
10 #include "libANGLE/renderer/wgpu/TextureWgpu.h"
11 
12 #include "common/debug.h"
13 #include "libANGLE/Error.h"
14 #include "libANGLE/angletypes.h"
15 #include "libANGLE/renderer/wgpu/ContextWgpu.h"
16 #include "libANGLE/renderer/wgpu/DisplayWgpu.h"
17 #include "libANGLE/renderer/wgpu/RenderTargetWgpu.h"
18 
19 namespace rx
20 {
21 
22 namespace
23 {
24 
GetRenderTargetLayerCountAndIndex(webgpu::ImageHelper * image,const gl::ImageIndex & index,GLuint * layerIndex,GLuint * layerCount,GLuint * imageLayerCount)25 void GetRenderTargetLayerCountAndIndex(webgpu::ImageHelper *image,
26                                        const gl::ImageIndex &index,
27                                        GLuint *layerIndex,
28                                        GLuint *layerCount,
29                                        GLuint *imageLayerCount)
30 {
31     *layerIndex = index.hasLayer() ? index.getLayerIndex() : 0;
32     *layerCount = index.getLayerCount();
33 
34     switch (index.getType())
35     {
36         case gl::TextureType::_2D:
37         case gl::TextureType::_2DMultisample:
38         case gl::TextureType::External:
39             ASSERT(*layerIndex == 0 &&
40                    (*layerCount == 1 ||
41                     *layerCount == static_cast<GLuint>(gl::ImageIndex::kEntireLevel)));
42             *imageLayerCount = 1;
43             break;
44 
45         case gl::TextureType::CubeMap:
46             ASSERT(!index.hasLayer() ||
47                    *layerIndex == static_cast<GLuint>(index.cubeMapFaceIndex()));
48             *imageLayerCount = gl::kCubeFaceCount;
49             break;
50 
51         case gl::TextureType::_3D:
52         {
53             gl::LevelIndex levelGL(index.getLevelIndex());
54             *imageLayerCount = image->getTextureDescriptor().size.depthOrArrayLayers;
55             break;
56         }
57 
58         case gl::TextureType::_2DArray:
59         case gl::TextureType::_2DMultisampleArray:
60         case gl::TextureType::CubeMapArray:
61             // NOTE: Not yet supported, should set *imageLayerCount.
62             UNIMPLEMENTED();
63             break;
64 
65         default:
66             UNREACHABLE();
67     }
68 
69     if (*layerCount == static_cast<GLuint>(gl::ImageIndex::kEntireLevel))
70     {
71         ASSERT(*layerIndex == 0);
72         *layerCount = *imageLayerCount;
73     }
74 }
75 
76 }  // namespace
77 
TextureWgpu(const gl::TextureState & state)78 TextureWgpu::TextureWgpu(const gl::TextureState &state)
79     : TextureImpl(state),
80       mImage(new webgpu::ImageHelper()),
81       mCurrentBaseLevel(state.getBaseLevel()),
82       mCurrentMaxLevel(state.getMaxLevel())
83 {}
84 
~TextureWgpu()85 TextureWgpu::~TextureWgpu() {}
86 
setImage(const gl::Context * context,const gl::ImageIndex & index,GLenum internalFormat,const gl::Extents & size,GLenum format,GLenum type,const gl::PixelUnpackState & unpack,gl::Buffer * unpackBuffer,const uint8_t * pixels)87 angle::Result TextureWgpu::setImage(const gl::Context *context,
88                                     const gl::ImageIndex &index,
89                                     GLenum internalFormat,
90                                     const gl::Extents &size,
91                                     GLenum format,
92                                     GLenum type,
93                                     const gl::PixelUnpackState &unpack,
94                                     gl::Buffer *unpackBuffer,
95                                     const uint8_t *pixels)
96 {
97     return setImageImpl(context, internalFormat, type, index, size, unpack, pixels);
98 }
99 
setSubImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Box & area,GLenum format,GLenum type,const gl::PixelUnpackState & unpack,gl::Buffer * unpackBuffer,const uint8_t * pixels)100 angle::Result TextureWgpu::setSubImage(const gl::Context *context,
101                                        const gl::ImageIndex &index,
102                                        const gl::Box &area,
103                                        GLenum format,
104                                        GLenum type,
105                                        const gl::PixelUnpackState &unpack,
106                                        gl::Buffer *unpackBuffer,
107                                        const uint8_t *pixels)
108 {
109     return setSubImageImpl(context, format, type, index, area, unpack, pixels);
110 }
111 
setCompressedImage(const gl::Context * context,const gl::ImageIndex & index,GLenum internalFormat,const gl::Extents & size,const gl::PixelUnpackState & unpack,size_t imageSize,const uint8_t * pixels)112 angle::Result TextureWgpu::setCompressedImage(const gl::Context *context,
113                                               const gl::ImageIndex &index,
114                                               GLenum internalFormat,
115                                               const gl::Extents &size,
116                                               const gl::PixelUnpackState &unpack,
117                                               size_t imageSize,
118                                               const uint8_t *pixels)
119 {
120     return angle::Result::Continue;
121 }
122 
setCompressedSubImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Box & area,GLenum format,const gl::PixelUnpackState & unpack,size_t imageSize,const uint8_t * pixels)123 angle::Result TextureWgpu::setCompressedSubImage(const gl::Context *context,
124                                                  const gl::ImageIndex &index,
125                                                  const gl::Box &area,
126                                                  GLenum format,
127                                                  const gl::PixelUnpackState &unpack,
128                                                  size_t imageSize,
129                                                  const uint8_t *pixels)
130 {
131     return angle::Result::Continue;
132 }
133 
copyImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Rectangle & sourceArea,GLenum internalFormat,gl::Framebuffer * source)134 angle::Result TextureWgpu::copyImage(const gl::Context *context,
135                                      const gl::ImageIndex &index,
136                                      const gl::Rectangle &sourceArea,
137                                      GLenum internalFormat,
138                                      gl::Framebuffer *source)
139 {
140     return angle::Result::Continue;
141 }
142 
copySubImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Offset & destOffset,const gl::Rectangle & sourceArea,gl::Framebuffer * source)143 angle::Result TextureWgpu::copySubImage(const gl::Context *context,
144                                         const gl::ImageIndex &index,
145                                         const gl::Offset &destOffset,
146                                         const gl::Rectangle &sourceArea,
147                                         gl::Framebuffer *source)
148 {
149     return angle::Result::Continue;
150 }
151 
copyTexture(const gl::Context * context,const gl::ImageIndex & index,GLenum internalFormat,GLenum type,GLint sourceLevel,bool unpackFlipY,bool unpackPremultiplyAlpha,bool unpackUnmultiplyAlpha,const gl::Texture * source)152 angle::Result TextureWgpu::copyTexture(const gl::Context *context,
153                                        const gl::ImageIndex &index,
154                                        GLenum internalFormat,
155                                        GLenum type,
156                                        GLint sourceLevel,
157                                        bool unpackFlipY,
158                                        bool unpackPremultiplyAlpha,
159                                        bool unpackUnmultiplyAlpha,
160                                        const gl::Texture *source)
161 {
162     return angle::Result::Continue;
163 }
164 
copySubTexture(const gl::Context * context,const gl::ImageIndex & index,const gl::Offset & destOffset,GLint sourceLevel,const gl::Box & sourceBox,bool unpackFlipY,bool unpackPremultiplyAlpha,bool unpackUnmultiplyAlpha,const gl::Texture * source)165 angle::Result TextureWgpu::copySubTexture(const gl::Context *context,
166                                           const gl::ImageIndex &index,
167                                           const gl::Offset &destOffset,
168                                           GLint sourceLevel,
169                                           const gl::Box &sourceBox,
170                                           bool unpackFlipY,
171                                           bool unpackPremultiplyAlpha,
172                                           bool unpackUnmultiplyAlpha,
173                                           const gl::Texture *source)
174 {
175     return angle::Result::Continue;
176 }
177 
copyRenderbufferSubData(const gl::Context * context,const gl::Renderbuffer * srcBuffer,GLint srcLevel,GLint srcX,GLint srcY,GLint srcZ,GLint dstLevel,GLint dstX,GLint dstY,GLint dstZ,GLsizei srcWidth,GLsizei srcHeight,GLsizei srcDepth)178 angle::Result TextureWgpu::copyRenderbufferSubData(const gl::Context *context,
179                                                    const gl::Renderbuffer *srcBuffer,
180                                                    GLint srcLevel,
181                                                    GLint srcX,
182                                                    GLint srcY,
183                                                    GLint srcZ,
184                                                    GLint dstLevel,
185                                                    GLint dstX,
186                                                    GLint dstY,
187                                                    GLint dstZ,
188                                                    GLsizei srcWidth,
189                                                    GLsizei srcHeight,
190                                                    GLsizei srcDepth)
191 {
192     return angle::Result::Continue;
193 }
194 
copyTextureSubData(const gl::Context * context,const gl::Texture * srcTexture,GLint srcLevel,GLint srcX,GLint srcY,GLint srcZ,GLint dstLevel,GLint dstX,GLint dstY,GLint dstZ,GLsizei srcWidth,GLsizei srcHeight,GLsizei srcDepth)195 angle::Result TextureWgpu::copyTextureSubData(const gl::Context *context,
196                                               const gl::Texture *srcTexture,
197                                               GLint srcLevel,
198                                               GLint srcX,
199                                               GLint srcY,
200                                               GLint srcZ,
201                                               GLint dstLevel,
202                                               GLint dstX,
203                                               GLint dstY,
204                                               GLint dstZ,
205                                               GLsizei srcWidth,
206                                               GLsizei srcHeight,
207                                               GLsizei srcDepth)
208 {
209     return angle::Result::Continue;
210 }
211 
copyCompressedTexture(const gl::Context * context,const gl::Texture * source)212 angle::Result TextureWgpu::copyCompressedTexture(const gl::Context *context,
213                                                  const gl::Texture *source)
214 {
215     return angle::Result::Continue;
216 }
217 
setStorage(const gl::Context * context,gl::TextureType type,size_t levels,GLenum internalFormat,const gl::Extents & size)218 angle::Result TextureWgpu::setStorage(const gl::Context *context,
219                                       gl::TextureType type,
220                                       size_t levels,
221                                       GLenum internalFormat,
222                                       const gl::Extents &size)
223 {
224     return angle::Result::Continue;
225 }
226 
setStorageExternalMemory(const gl::Context * context,gl::TextureType type,size_t levels,GLenum internalFormat,const gl::Extents & size,gl::MemoryObject * memoryObject,GLuint64 offset,GLbitfield createFlags,GLbitfield usageFlags,const void * imageCreateInfoPNext)227 angle::Result TextureWgpu::setStorageExternalMemory(const gl::Context *context,
228                                                     gl::TextureType type,
229                                                     size_t levels,
230                                                     GLenum internalFormat,
231                                                     const gl::Extents &size,
232                                                     gl::MemoryObject *memoryObject,
233                                                     GLuint64 offset,
234                                                     GLbitfield createFlags,
235                                                     GLbitfield usageFlags,
236                                                     const void *imageCreateInfoPNext)
237 {
238     return angle::Result::Continue;
239 }
240 
setEGLImageTarget(const gl::Context * context,gl::TextureType type,egl::Image * image)241 angle::Result TextureWgpu::setEGLImageTarget(const gl::Context *context,
242                                              gl::TextureType type,
243                                              egl::Image *image)
244 {
245     return angle::Result::Continue;
246 }
247 
setImageExternal(const gl::Context * context,gl::TextureType type,egl::Stream * stream,const egl::Stream::GLTextureDescription & desc)248 angle::Result TextureWgpu::setImageExternal(const gl::Context *context,
249                                             gl::TextureType type,
250                                             egl::Stream *stream,
251                                             const egl::Stream::GLTextureDescription &desc)
252 {
253     return angle::Result::Continue;
254 }
255 
generateMipmap(const gl::Context * context)256 angle::Result TextureWgpu::generateMipmap(const gl::Context *context)
257 {
258     return angle::Result::Continue;
259 }
260 
setBaseLevel(const gl::Context * context,GLuint baseLevel)261 angle::Result TextureWgpu::setBaseLevel(const gl::Context *context, GLuint baseLevel)
262 {
263     return angle::Result::Continue;
264 }
265 
bindTexImage(const gl::Context * context,egl::Surface * surface)266 angle::Result TextureWgpu::bindTexImage(const gl::Context *context, egl::Surface *surface)
267 {
268     return angle::Result::Continue;
269 }
270 
releaseTexImage(const gl::Context * context)271 angle::Result TextureWgpu::releaseTexImage(const gl::Context *context)
272 {
273     return angle::Result::Continue;
274 }
275 
syncState(const gl::Context * context,const gl::Texture::DirtyBits & dirtyBits,gl::Command source)276 angle::Result TextureWgpu::syncState(const gl::Context *context,
277                                      const gl::Texture::DirtyBits &dirtyBits,
278                                      gl::Command source)
279 {
280     ContextWgpu *contextWgpu = GetImplAs<ContextWgpu>(context);
281     ANGLE_TRY(respecifyImageStorageIfNecessary(contextWgpu, source));
282     const bool isGenerateMipmap = source == gl::Command::GenerateMipmap;
283     ANGLE_TRY(initializeImage(contextWgpu, isGenerateMipmap
284                                                ? ImageMipLevels::FullMipChainForGenerateMipmap
285                                                : ImageMipLevels::EnabledLevels));
286     ANGLE_TRY(mImage->flushStagedUpdates(contextWgpu));
287     return angle::Result::Continue;
288 }
289 
setStorageMultisample(const gl::Context * context,gl::TextureType type,GLsizei samples,GLint internalformat,const gl::Extents & size,bool fixedSampleLocations)290 angle::Result TextureWgpu::setStorageMultisample(const gl::Context *context,
291                                                  gl::TextureType type,
292                                                  GLsizei samples,
293                                                  GLint internalformat,
294                                                  const gl::Extents &size,
295                                                  bool fixedSampleLocations)
296 {
297     return angle::Result::Continue;
298 }
299 
initializeContents(const gl::Context * context,GLenum binding,const gl::ImageIndex & imageIndex)300 angle::Result TextureWgpu::initializeContents(const gl::Context *context,
301                                               GLenum binding,
302                                               const gl::ImageIndex &imageIndex)
303 {
304     return angle::Result::Continue;
305 }
306 
getAttachmentRenderTarget(const gl::Context * context,GLenum binding,const gl::ImageIndex & imageIndex,GLsizei samples,FramebufferAttachmentRenderTarget ** rtOut)307 angle::Result TextureWgpu::getAttachmentRenderTarget(const gl::Context *context,
308                                                      GLenum binding,
309                                                      const gl::ImageIndex &imageIndex,
310                                                      GLsizei samples,
311                                                      FramebufferAttachmentRenderTarget **rtOut)
312 {
313     ContextWgpu *contextWgpu = GetImplAs<ContextWgpu>(context);
314     ANGLE_TRY(respecifyImageStorageIfNecessary(contextWgpu, gl::Command::Draw));
315     if (!mImage->isInitialized())
316     {
317         ANGLE_TRY(initializeImage(contextWgpu, ImageMipLevels::EnabledLevels));
318     }
319 
320     GLuint layerIndex = 0, layerCount = 0, imageLayerCount = 0;
321     GetRenderTargetLayerCountAndIndex(mImage, imageIndex, &layerIndex, &layerCount,
322                                       &imageLayerCount);
323 
324     // NOTE: Multisampling not yet supported
325     ASSERT(samples <= 1);
326     const gl::RenderToTextureImageIndex renderToTextureIndex =
327         gl::RenderToTextureImageIndex::Default;
328 
329     if (layerCount == 1)
330     {
331         ANGLE_TRY(initSingleLayerRenderTargets(contextWgpu, imageLayerCount,
332                                                gl::LevelIndex(imageIndex.getLevelIndex()),
333                                                renderToTextureIndex));
334 
335         std::vector<std::vector<RenderTargetWgpu>> &levelRenderTargets =
336             mSingleLayerRenderTargets[renderToTextureIndex];
337         ASSERT(imageIndex.getLevelIndex() < static_cast<int32_t>(levelRenderTargets.size()));
338 
339         std::vector<RenderTargetWgpu> &layerRenderTargets =
340             levelRenderTargets[imageIndex.getLevelIndex()];
341         ASSERT(imageIndex.getLayerIndex() < static_cast<int32_t>(layerRenderTargets.size()));
342 
343         *rtOut = &layerRenderTargets[layerIndex];
344     }
345     else
346     {
347         // Not yet supported.
348         UNIMPLEMENTED();
349     }
350 
351     return angle::Result::Continue;
352 }
353 
setImageImpl(const gl::Context * context,GLenum internalFormat,GLenum type,const gl::ImageIndex & index,const gl::Extents & size,const gl::PixelUnpackState & unpack,const uint8_t * pixels)354 angle::Result TextureWgpu::setImageImpl(const gl::Context *context,
355                                         GLenum internalFormat,
356                                         GLenum type,
357                                         const gl::ImageIndex &index,
358                                         const gl::Extents &size,
359                                         const gl::PixelUnpackState &unpack,
360                                         const uint8_t *pixels)
361 {
362     ANGLE_TRY(redefineLevel(context, index, size));
363     return setSubImageImpl(context, internalFormat, type, index, gl::Box(gl::kOffsetZero, size),
364                            unpack, pixels);
365 }
366 
setSubImageImpl(const gl::Context * context,GLenum internalFormat,GLenum type,const gl::ImageIndex & index,const gl::Box & area,const gl::PixelUnpackState & unpack,const uint8_t * pixels)367 angle::Result TextureWgpu::setSubImageImpl(const gl::Context *context,
368                                            GLenum internalFormat,
369                                            GLenum type,
370                                            const gl::ImageIndex &index,
371                                            const gl::Box &area,
372                                            const gl::PixelUnpackState &unpack,
373                                            const uint8_t *pixels)
374 {
375 
376     ContextWgpu *contextWgpu = GetImplAs<ContextWgpu>(context);
377 
378     gl::InternalFormat internalFormatInfo = gl::GetInternalFormatInfo(internalFormat, type);
379     gl::Extents glExtents                 = gl::Extents(area.width, area.height, area.depth);
380     GLuint inputRowPitch                  = 0;
381     GLuint inputDepthPitch                = 0;
382     uint32_t outputRowPitch = roundUp(internalFormatInfo.pixelBytes * glExtents.width, (GLuint)256);
383     uint32_t outputDepthPitch = outputRowPitch * glExtents.height;
384     uint32_t allocationSize   = outputDepthPitch * glExtents.depth;
385     ANGLE_CHECK_GL_MATH(contextWgpu,
386                         internalFormatInfo.computeRowPitch(type, glExtents.width, unpack.alignment,
387                                                            unpack.rowLength, &inputRowPitch));
388     ANGLE_CHECK_GL_MATH(contextWgpu,
389                         internalFormatInfo.computeDepthPitch(glExtents.height, unpack.imageHeight,
390                                                              inputRowPitch, &inputDepthPitch));
391 
392     ANGLE_TRY(mImage->stageTextureUpload(contextWgpu, glExtents, inputRowPitch, inputDepthPitch,
393                                          outputRowPitch, outputDepthPitch, allocationSize, index,
394                                          pixels));
395     return angle::Result::Continue;
396 }
397 
initializeImage(ContextWgpu * contextWgpu,ImageMipLevels mipLevels)398 angle::Result TextureWgpu::initializeImage(ContextWgpu *contextWgpu, ImageMipLevels mipLevels)
399 {
400     if (mImage->isInitialized())
401     {
402         return angle::Result::Continue;
403     }
404     DisplayWgpu *displayWgpu                = contextWgpu->getDisplay();
405     const gl::ImageDesc *firstLevelDesc     = &mState.getBaseLevelDesc();
406     uint32_t levelCount                     = getMipLevelCount(mipLevels);
407     gl::LevelIndex firstLevel               = gl::LevelIndex(mState.getEffectiveBaseLevel());
408     const gl::Extents &firstLevelExtents    = firstLevelDesc->size;
409     wgpu::TextureDimension textureDimension = gl_wgpu::getWgpuTextureDimension(mState.getType());
410     wgpu::TextureUsage textureUsage = wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::CopyDst |
411                                       wgpu::TextureUsage::RenderAttachment |
412                                       wgpu::TextureUsage::TextureBinding;
413     return mImage->initImage(
414         displayWgpu->getDevice(), firstLevel,
415         mImage->createTextureDescriptor(textureUsage, textureDimension,
416                                         gl_wgpu::getExtent3D(firstLevelExtents),
417                                         wgpu::TextureFormat::RGBA8Unorm, levelCount, 1));
418 }
419 
redefineLevel(const gl::Context * context,const gl::ImageIndex & index,const gl::Extents & size)420 angle::Result TextureWgpu::redefineLevel(const gl::Context *context,
421                                          const gl::ImageIndex &index,
422                                          const gl::Extents &size)
423 {
424     if (mImage != nullptr)
425     {
426         // If there are any staged changes for this index, we can remove them since we're going to
427         // override them with this call.
428         gl::LevelIndex levelIndexGL(index.getLevelIndex());
429         // Multilayer images are not yet supported.
430         const uint32_t layerIndex = 0;
431         mImage->removeStagedUpdates(levelIndexGL);
432 
433         if (mImage->isInitialized())
434         {
435             TextureLevelAllocation levelAllocation =
436                 mImage->isTextureLevelInAllocatedImage(levelIndexGL)
437                     ? TextureLevelAllocation::WithinAllocatedImage
438                     : TextureLevelAllocation::OutsideAllocatedImage;
439             TextureLevelDefinition levelDefinition =
440                 (size == wgpu_gl::getExtents(mImage->getSize()))
441                     ? TextureLevelDefinition::Compatible
442                     : TextureLevelDefinition::Incompatible;
443             if (TextureRedefineLevel(levelAllocation, levelDefinition, mState.getImmutableFormat(),
444                                      mImage->getLevelCount(), layerIndex, index,
445                                      mImage->getFirstAllocatedLevel(), &mRedefinedLevels))
446             {
447                 mImage->resetImage();
448             }
449         }
450     }
451     else
452     {
453         mImage = new webgpu::ImageHelper;
454     }
455 
456     return angle::Result::Continue;
457 }
458 
getMipLevelCount(ImageMipLevels mipLevels) const459 uint32_t TextureWgpu::getMipLevelCount(ImageMipLevels mipLevels) const
460 {
461     switch (mipLevels)
462     {
463         // Returns level count from base to max that has been specified, i.e, enabled.
464         case ImageMipLevels::EnabledLevels:
465             return mState.getEnabledLevelCount();
466         // Returns all mipmap levels from base to max regardless if an image has been specified or
467         // not.
468         case ImageMipLevels::FullMipChainForGenerateMipmap:
469             return getMaxLevelCount() - mState.getEffectiveBaseLevel();
470 
471         default:
472             UNREACHABLE();
473             return 0;
474     }
475 }
476 
getMaxLevelCount() const477 uint32_t TextureWgpu::getMaxLevelCount() const
478 {
479     // getMipmapMaxLevel will be 0 here if mipmaps are not used, so the levelCount is always +1.
480     return mState.getMipmapMaxLevel() + 1;
481 }
482 
respecifyImageStorageIfNecessary(ContextWgpu * contextWgpu,gl::Command source)483 angle::Result TextureWgpu::respecifyImageStorageIfNecessary(ContextWgpu *contextWgpu,
484                                                             gl::Command source)
485 {
486     ASSERT(mState.getBuffer().get() == nullptr);
487 
488     // Before redefining the image for any reason, check to see if it's about to go through mipmap
489     // generation.  In that case, drop every staged change for the subsequent mips after base, and
490     // make sure the image is created with the complete mip chain.
491     const bool isGenerateMipmap = source == gl::Command::GenerateMipmap;
492     if (isGenerateMipmap)
493     {
494         prepareForGenerateMipmap(contextWgpu);
495     }
496 
497     // Set base and max level before initializing the image
498     ANGLE_TRY(maybeUpdateBaseMaxLevels(contextWgpu));
499 
500     // It is possible for the image to have a single level (because it doesn't use mipmapping),
501     // then have more levels defined in it and mipmapping enabled.  In that case, the image needs
502     // to be recreated.
503     bool isMipmapEnabledByMinFilter = false;
504     if (!isGenerateMipmap && mImage && mImage->isInitialized())
505     {
506         isMipmapEnabledByMinFilter =
507             mImage->getLevelCount() < getMipLevelCount(ImageMipLevels::EnabledLevels);
508     }
509 
510     // If generating mipmaps and the image needs to be recreated (not full-mip already, or changed
511     // usage flags), make sure it's recreated.
512     if (isGenerateMipmap && mImage && mImage->isInitialized() &&
513         (!mState.getImmutableFormat() &&
514          mImage->getLevelCount() !=
515              getMipLevelCount(ImageMipLevels::FullMipChainForGenerateMipmap)))
516     {
517         ANGLE_TRY(mImage->flushStagedUpdates(contextWgpu));
518 
519         mImage->resetImage();
520     }
521 
522     // Also recreate the image if it's changed in usage, or if any of its levels are redefined and
523     // no update to base/max levels were done (otherwise the above call would have already taken
524     // care of this).
525     // TODO(liza): Respecify the image once copying images is supported.
526     if (TextureHasAnyRedefinedLevels(mRedefinedLevels) || isMipmapEnabledByMinFilter)
527     {
528         ANGLE_TRY(mImage->flushStagedUpdates(contextWgpu));
529 
530         mImage->resetImage();
531     }
532 
533     return angle::Result::Continue;
534 }
535 
prepareForGenerateMipmap(ContextWgpu * contextWgpu)536 void TextureWgpu::prepareForGenerateMipmap(ContextWgpu *contextWgpu)
537 {
538     gl::LevelIndex baseLevel(mState.getEffectiveBaseLevel());
539     gl::LevelIndex maxLevel(mState.getMipmapMaxLevel());
540 
541     // Remove staged updates to the range that's being respecified (which is all the mips except
542     // baseLevel).
543     gl::LevelIndex firstGeneratedLevel = baseLevel + 1;
544     for (GLuint levelToRemove = mState.getEffectiveBaseLevel();
545          levelToRemove < mState.getMipmapMaxLevel(); levelToRemove++)
546     {
547         mImage->removeStagedUpdates(gl::LevelIndex(levelToRemove));
548     }
549 
550     TextureRedefineGenerateMipmapLevels(baseLevel, maxLevel, firstGeneratedLevel,
551                                         &mRedefinedLevels);
552 
553     // If generating mipmap and base level is incompatibly redefined, the image is going to be
554     // recreated.  Don't try to preserve the other mips.
555     if (IsTextureLevelRedefined(mRedefinedLevels, mState.getType(), baseLevel))
556     {
557         ASSERT(!mState.getImmutableFormat());
558         mImage->resetImage();
559     }
560 }
561 
maybeUpdateBaseMaxLevels(ContextWgpu * contextWgpu)562 angle::Result TextureWgpu::maybeUpdateBaseMaxLevels(ContextWgpu *contextWgpu)
563 {
564     bool baseLevelChanged = mCurrentBaseLevel.get() != static_cast<GLint>(mState.getBaseLevel());
565     bool maxLevelChanged  = mCurrentMaxLevel.get() != static_cast<GLint>(mState.getMaxLevel());
566 
567     if (!maxLevelChanged && !baseLevelChanged)
568     {
569         return angle::Result::Continue;
570     }
571 
572     gl::LevelIndex newBaseLevel = gl::LevelIndex(mState.getEffectiveBaseLevel());
573     gl::LevelIndex newMaxLevel  = gl::LevelIndex(mState.getEffectiveMaxLevel());
574     ASSERT(newBaseLevel <= newMaxLevel);
575 
576     if (!mImage->isInitialized())
577     {
578         return angle::Result::Continue;
579     }
580 
581     if (mState.getImmutableFormat())
582     {
583         // For immutable texture, baseLevel/maxLevel should be a subset of the texture's actual
584         // number of mip levels. We don't need to respecify an image.
585         ASSERT(!baseLevelChanged || newBaseLevel >= mImage->getFirstAllocatedLevel());
586         ASSERT(!maxLevelChanged || newMaxLevel < gl::LevelIndex(mImage->getLevelCount()));
587     }
588     else if (!baseLevelChanged && (newMaxLevel <= mImage->getLastAllocatedLevel()))
589     {
590         // With a valid image, check if only changing the maxLevel to a subset of the texture's
591         // actual number of mip levels
592         ASSERT(maxLevelChanged);
593     }
594     else
595     {
596         // TODO(liza): Respecify the image once copying images is supported.
597         mImage->resetImage();
598         return angle::Result::Continue;
599     }
600 
601     mCurrentBaseLevel = newBaseLevel;
602     mCurrentMaxLevel  = newMaxLevel;
603 
604     return angle::Result::Continue;
605 }
606 
initSingleLayerRenderTargets(ContextWgpu * contextWgpu,GLuint layerCount,gl::LevelIndex levelIndex,gl::RenderToTextureImageIndex renderToTextureIndex)607 angle::Result TextureWgpu::initSingleLayerRenderTargets(
608     ContextWgpu *contextWgpu,
609     GLuint layerCount,
610     gl::LevelIndex levelIndex,
611     gl::RenderToTextureImageIndex renderToTextureIndex)
612 {
613     std::vector<std::vector<RenderTargetWgpu>> &allLevelsRenderTargets =
614         mSingleLayerRenderTargets[renderToTextureIndex];
615 
616     if (allLevelsRenderTargets.size() <= static_cast<uint32_t>(levelIndex.get()))
617     {
618         allLevelsRenderTargets.resize(levelIndex.get() + 1);
619     }
620 
621     std::vector<RenderTargetWgpu> &renderTargets = allLevelsRenderTargets[levelIndex.get()];
622 
623     // Lazy init. Check if already initialized.
624     if (!renderTargets.empty())
625     {
626         return angle::Result::Continue;
627     }
628 
629     // There are |layerCount| render targets, one for each layer
630     renderTargets.resize(layerCount);
631 
632     for (uint32_t layerIndex = 0; layerIndex < layerCount; ++layerIndex)
633     {
634         wgpu::TextureView textureView;
635         ANGLE_TRY(mImage->createTextureView(levelIndex, layerIndex, textureView));
636 
637         renderTargets[layerIndex].set(mImage, textureView, mImage->toWgpuLevel(levelIndex),
638                                       layerIndex, mImage->toWgpuTextureFormat());
639     }
640 
641     return angle::Result::Continue;
642 }
643 
644 }  // namespace rx
645