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