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