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