1 //
2 // Copyright 2002 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
7 // Texture.cpp: Implements the gl::Texture class. [OpenGL ES 2.0.24] section 3.7 page 63.
8
9 #include "libANGLE/Texture.h"
10
11 #include "common/mathutil.h"
12 #include "common/utilities.h"
13 #include "libANGLE/Config.h"
14 #include "libANGLE/Context.h"
15 #include "libANGLE/Image.h"
16 #include "libANGLE/State.h"
17 #include "libANGLE/Surface.h"
18 #include "libANGLE/formatutils.h"
19 #include "libANGLE/renderer/ContextImpl.h"
20 #include "libANGLE/renderer/GLImplFactory.h"
21 #include "libANGLE/renderer/TextureImpl.h"
22
23 namespace gl
24 {
25
26 namespace
27 {
28 constexpr angle::SubjectIndex kBufferSubjectIndex = 2;
29 static_assert(kBufferSubjectIndex != rx::kTextureImageImplObserverMessageIndex, "Index collision");
30 static_assert(kBufferSubjectIndex != rx::kTextureImageSiblingMessageIndex, "Index collision");
31
IsPointSampled(const SamplerState & samplerState)32 bool IsPointSampled(const SamplerState &samplerState)
33 {
34 return (samplerState.getMagFilter() == GL_NEAREST &&
35 (samplerState.getMinFilter() == GL_NEAREST ||
36 samplerState.getMinFilter() == GL_NEAREST_MIPMAP_NEAREST));
37 }
38
GetImageDescIndex(TextureTarget target,size_t level)39 size_t GetImageDescIndex(TextureTarget target, size_t level)
40 {
41 return IsCubeMapFaceTarget(target) ? (level * 6 + CubeMapTextureTargetToFaceIndex(target))
42 : level;
43 }
44
DetermineInitState(const Context * context,Buffer * unpackBuffer,const uint8_t * pixels)45 InitState DetermineInitState(const Context *context, Buffer *unpackBuffer, const uint8_t *pixels)
46 {
47 // Can happen in tests.
48 if (!context || !context->isRobustResourceInitEnabled())
49 {
50 return InitState::Initialized;
51 }
52
53 return (!pixels && !unpackBuffer) ? InitState::MayNeedInit : InitState::Initialized;
54 }
55 } // namespace
56
ConvertToNearestFilterMode(GLenum filterMode)57 GLenum ConvertToNearestFilterMode(GLenum filterMode)
58 {
59 switch (filterMode)
60 {
61 case GL_LINEAR:
62 return GL_NEAREST;
63 case GL_LINEAR_MIPMAP_NEAREST:
64 return GL_NEAREST_MIPMAP_NEAREST;
65 case GL_LINEAR_MIPMAP_LINEAR:
66 return GL_NEAREST_MIPMAP_LINEAR;
67 default:
68 return filterMode;
69 }
70 }
71
ConvertToNearestMipFilterMode(GLenum filterMode)72 GLenum ConvertToNearestMipFilterMode(GLenum filterMode)
73 {
74 switch (filterMode)
75 {
76 case GL_LINEAR_MIPMAP_LINEAR:
77 return GL_LINEAR_MIPMAP_NEAREST;
78 case GL_NEAREST_MIPMAP_LINEAR:
79 return GL_NEAREST_MIPMAP_NEAREST;
80 default:
81 return filterMode;
82 }
83 }
84
IsMipmapSupported(const TextureType & type)85 bool IsMipmapSupported(const TextureType &type)
86 {
87 switch (type)
88 {
89 case TextureType::_2DMultisample:
90 case TextureType::_2DMultisampleArray:
91 case TextureType::Buffer:
92 return false;
93 default:
94 return true;
95 }
96 }
97
SwizzleState()98 SwizzleState::SwizzleState()
99 : swizzleRed(GL_RED), swizzleGreen(GL_GREEN), swizzleBlue(GL_BLUE), swizzleAlpha(GL_ALPHA)
100 {}
101
SwizzleState(GLenum red,GLenum green,GLenum blue,GLenum alpha)102 SwizzleState::SwizzleState(GLenum red, GLenum green, GLenum blue, GLenum alpha)
103 : swizzleRed(red), swizzleGreen(green), swizzleBlue(blue), swizzleAlpha(alpha)
104 {}
105
swizzleRequired() const106 bool SwizzleState::swizzleRequired() const
107 {
108 return swizzleRed != GL_RED || swizzleGreen != GL_GREEN || swizzleBlue != GL_BLUE ||
109 swizzleAlpha != GL_ALPHA;
110 }
111
operator ==(const SwizzleState & other) const112 bool SwizzleState::operator==(const SwizzleState &other) const
113 {
114 return swizzleRed == other.swizzleRed && swizzleGreen == other.swizzleGreen &&
115 swizzleBlue == other.swizzleBlue && swizzleAlpha == other.swizzleAlpha;
116 }
117
operator !=(const SwizzleState & other) const118 bool SwizzleState::operator!=(const SwizzleState &other) const
119 {
120 return !(*this == other);
121 }
122
TextureState(TextureType type)123 TextureState::TextureState(TextureType type)
124 : mType(type),
125 mSamplerState(SamplerState::CreateDefaultForTarget(type)),
126 mSrgbOverride(SrgbOverride::Default),
127 mBaseLevel(0),
128 mMaxLevel(kInitialMaxLevel),
129 mDepthStencilTextureMode(GL_DEPTH_COMPONENT),
130 mIsInternalIncompleteTexture(false),
131 mHasBeenBoundAsImage(false),
132 mHasBeenBoundAsAttachment(false),
133 mHasBeenBoundToMSRTTFramebuffer(false),
134 mImmutableFormat(false),
135 mImmutableLevels(0),
136 mUsage(GL_NONE),
137 mHasProtectedContent(false),
138 mRenderabilityValidation(true),
139 mTilingMode(gl::TilingMode::Optimal),
140 mImageDescs((IMPLEMENTATION_MAX_TEXTURE_LEVELS + 1) * (type == TextureType::CubeMap ? 6 : 1)),
141 mCropRect(0, 0, 0, 0),
142 mGenerateMipmapHint(GL_FALSE),
143 mInitState(InitState::Initialized),
144 mCachedSamplerFormat(SamplerFormat::InvalidEnum),
145 mCachedSamplerCompareMode(GL_NONE),
146 mCachedSamplerFormatValid(false)
147 {}
148
~TextureState()149 TextureState::~TextureState() {}
150
swizzleRequired() const151 bool TextureState::swizzleRequired() const
152 {
153 return mSwizzleState.swizzleRequired();
154 }
155
getEffectiveBaseLevel() const156 GLuint TextureState::getEffectiveBaseLevel() const
157 {
158 if (mImmutableFormat)
159 {
160 // GLES 3.0.4 section 3.8.10
161 return std::min(mBaseLevel, mImmutableLevels - 1);
162 }
163 // Some classes use the effective base level to index arrays with level data. By clamping the
164 // effective base level to max levels these arrays need just one extra item to store properties
165 // that should be returned for all out-of-range base level values, instead of needing special
166 // handling for out-of-range base levels.
167 return std::min(mBaseLevel, static_cast<GLuint>(IMPLEMENTATION_MAX_TEXTURE_LEVELS));
168 }
169
getEffectiveMaxLevel() const170 GLuint TextureState::getEffectiveMaxLevel() const
171 {
172 if (mImmutableFormat)
173 {
174 // GLES 3.0.4 section 3.8.10
175 GLuint clampedMaxLevel = std::max(mMaxLevel, getEffectiveBaseLevel());
176 clampedMaxLevel = std::min(clampedMaxLevel, mImmutableLevels - 1);
177 return clampedMaxLevel;
178 }
179 return mMaxLevel;
180 }
181
getMipmapMaxLevel() const182 GLuint TextureState::getMipmapMaxLevel() const
183 {
184 const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), getEffectiveBaseLevel());
185 GLuint expectedMipLevels = 0;
186 if (mType == TextureType::_3D)
187 {
188 const int maxDim = std::max(
189 {baseImageDesc.size.width, baseImageDesc.size.height, baseImageDesc.size.depth});
190 expectedMipLevels = static_cast<GLuint>(log2(maxDim));
191 }
192 else
193 {
194 expectedMipLevels = static_cast<GLuint>(
195 log2(std::max(baseImageDesc.size.width, baseImageDesc.size.height)));
196 }
197
198 return std::min<GLuint>(getEffectiveBaseLevel() + expectedMipLevels, getEffectiveMaxLevel());
199 }
200
setBaseLevel(GLuint baseLevel)201 bool TextureState::setBaseLevel(GLuint baseLevel)
202 {
203 if (mBaseLevel != baseLevel)
204 {
205 mBaseLevel = baseLevel;
206 return true;
207 }
208 return false;
209 }
210
setMaxLevel(GLuint maxLevel)211 bool TextureState::setMaxLevel(GLuint maxLevel)
212 {
213 if (mMaxLevel != maxLevel)
214 {
215 mMaxLevel = maxLevel;
216 return true;
217 }
218
219 return false;
220 }
221
222 // Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
223 // According to [OpenGL ES 3.0.5] section 3.8.13 Texture Completeness page 160 any
224 // per-level checks begin at the base-level.
225 // For OpenGL ES2 the base level is always zero.
isCubeComplete() const226 bool TextureState::isCubeComplete() const
227 {
228 ASSERT(mType == TextureType::CubeMap);
229
230 angle::EnumIterator<TextureTarget> face = kCubeMapTextureTargetMin;
231 const ImageDesc &baseImageDesc = getImageDesc(*face, getEffectiveBaseLevel());
232 if (baseImageDesc.size.width == 0 || baseImageDesc.size.width != baseImageDesc.size.height)
233 {
234 return false;
235 }
236
237 ++face;
238
239 for (; face != kAfterCubeMapTextureTargetMax; ++face)
240 {
241 const ImageDesc &faceImageDesc = getImageDesc(*face, getEffectiveBaseLevel());
242 if (faceImageDesc.size.width != baseImageDesc.size.width ||
243 faceImageDesc.size.height != baseImageDesc.size.height ||
244 !Format::SameSized(faceImageDesc.format, baseImageDesc.format))
245 {
246 return false;
247 }
248 }
249
250 return true;
251 }
252
getBaseLevelDesc() const253 const ImageDesc &TextureState::getBaseLevelDesc() const
254 {
255 ASSERT(mType != TextureType::CubeMap || isCubeComplete());
256 return getImageDesc(getBaseImageTarget(), getEffectiveBaseLevel());
257 }
258
getLevelZeroDesc() const259 const ImageDesc &TextureState::getLevelZeroDesc() const
260 {
261 ASSERT(mType != TextureType::CubeMap || isCubeComplete());
262 return getImageDesc(getBaseImageTarget(), 0);
263 }
264
setCrop(const Rectangle & rect)265 void TextureState::setCrop(const Rectangle &rect)
266 {
267 mCropRect = rect;
268 }
269
getCrop() const270 const Rectangle &TextureState::getCrop() const
271 {
272 return mCropRect;
273 }
274
setGenerateMipmapHint(GLenum hint)275 void TextureState::setGenerateMipmapHint(GLenum hint)
276 {
277 mGenerateMipmapHint = hint;
278 }
279
getGenerateMipmapHint() const280 GLenum TextureState::getGenerateMipmapHint() const
281 {
282 return mGenerateMipmapHint;
283 }
284
computeRequiredSamplerFormat(const SamplerState & samplerState) const285 SamplerFormat TextureState::computeRequiredSamplerFormat(const SamplerState &samplerState) const
286 {
287 const InternalFormat &info =
288 *getImageDesc(getBaseImageTarget(), getEffectiveBaseLevel()).format.info;
289 if ((info.format == GL_DEPTH_COMPONENT ||
290 (info.format == GL_DEPTH_STENCIL && mDepthStencilTextureMode == GL_DEPTH_COMPONENT)) &&
291 samplerState.getCompareMode() != GL_NONE)
292 {
293 return SamplerFormat::Shadow;
294 }
295 else if (info.format == GL_STENCIL_INDEX ||
296 (info.format == GL_DEPTH_STENCIL && mDepthStencilTextureMode == GL_STENCIL_INDEX))
297 {
298 return SamplerFormat::Unsigned;
299 }
300 else
301 {
302 switch (info.componentType)
303 {
304 case GL_UNSIGNED_NORMALIZED:
305 case GL_SIGNED_NORMALIZED:
306 case GL_FLOAT:
307 return SamplerFormat::Float;
308 case GL_INT:
309 return SamplerFormat::Signed;
310 case GL_UNSIGNED_INT:
311 return SamplerFormat::Unsigned;
312 default:
313 return SamplerFormat::InvalidEnum;
314 }
315 }
316 }
317
computeSamplerCompleteness(const SamplerState & samplerState,const State & state) const318 bool TextureState::computeSamplerCompleteness(const SamplerState &samplerState,
319 const State &state) const
320 {
321 // Buffer textures cannot be incomplete. But if they are, the spec says -
322 //
323 // If no buffer object is bound to the buffer texture,
324 // the results of the texel access are undefined.
325 //
326 // Mark as incomplete so we use the default IncompleteTexture instead
327 if (mType == TextureType::Buffer)
328 {
329 return mBuffer.get() != nullptr;
330 }
331
332 // Check for all non-format-based completeness rules
333 if (!computeSamplerCompletenessForCopyImage(samplerState, state))
334 {
335 return false;
336 }
337
338 // OpenGL ES 3.2, Sections 8.8 and 11.1.3.3
339 // Multisample textures do not have mipmaps and filter state is ignored.
340 if (IsMultisampled(mType))
341 {
342 return true;
343 }
344
345 // OpenGL ES 3.2, Section 8.17
346 // A texture is complete unless either the magnification filter is not NEAREST,
347 // or the minification filter is neither NEAREST nor NEAREST_MIPMAP_NEAREST; and any of
348 if (IsPointSampled(samplerState))
349 {
350 return true;
351 }
352
353 const InternalFormat *info =
354 getImageDesc(getBaseImageTarget(), getEffectiveBaseLevel()).format.info;
355
356 // The effective internal format specified for the texture images
357 // is a sized internal color format that is not texture-filterable.
358 if (!info->isDepthOrStencil())
359 {
360 return info->filterSupport(state.getClientVersion(), state.getExtensions());
361 }
362
363 // The effective internal format specified for the texture images
364 // is a sized internal depth or depth and stencil format (see table 8.11),
365 // and the value of TEXTURE_COMPARE_MODE is NONE.
366 if (info->depthBits > 0 && samplerState.getCompareMode() == GL_NONE)
367 {
368 // Note: we restrict this validation to sized types. For the OES_depth_textures
369 // extension, due to some underspecification problems, we must allow linear filtering
370 // for legacy compatibility with WebGL 1.0.
371 // See http://crbug.com/649200
372 if (state.getClientMajorVersion() >= 3 && info->sized)
373 {
374 return false;
375 }
376 }
377
378 if (info->stencilBits > 0)
379 {
380 if (info->depthBits > 0)
381 {
382 // The internal format of the texture is DEPTH_STENCIL,
383 // and the value of DEPTH_STENCIL_TEXTURE_MODE for the
384 // texture is STENCIL_INDEX.
385 if (mDepthStencilTextureMode == GL_STENCIL_INDEX)
386 {
387 return false;
388 }
389 }
390 else
391 {
392 // The internal format is STENCIL_INDEX.
393 return false;
394 }
395 }
396
397 return true;
398 }
399
400 // CopyImageSubData has more lax rules for texture completeness: format-based completeness rules are
401 // ignored, so a texture can still be considered complete even if it violates format-specific
402 // conditions
computeSamplerCompletenessForCopyImage(const SamplerState & samplerState,const State & state) const403 bool TextureState::computeSamplerCompletenessForCopyImage(const SamplerState &samplerState,
404 const State &state) const
405 {
406 // Buffer textures cannot be incomplete. But if they are, the spec says -
407 //
408 // If no buffer object is bound to the buffer texture,
409 // the results of the texel access are undefined.
410 //
411 // Mark as incomplete so we use the default IncompleteTexture instead
412 if (mType == TextureType::Buffer)
413 {
414 return mBuffer.get() != nullptr;
415 }
416
417 if (!mImmutableFormat && mBaseLevel > mMaxLevel)
418 {
419 return false;
420 }
421 const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), getEffectiveBaseLevel());
422 if (baseImageDesc.size.width == 0 || baseImageDesc.size.height == 0 ||
423 baseImageDesc.size.depth == 0)
424 {
425 return false;
426 }
427 // The cases where the texture is incomplete because base level is out of range should be
428 // handled by the above condition.
429 ASSERT(mBaseLevel < IMPLEMENTATION_MAX_TEXTURE_LEVELS || mImmutableFormat);
430
431 if (mType == TextureType::CubeMap && baseImageDesc.size.width != baseImageDesc.size.height)
432 {
433 return false;
434 }
435
436 bool npotSupport = state.getExtensions().textureNpotOES || state.getClientMajorVersion() >= 3;
437 if (!npotSupport)
438 {
439 if ((samplerState.getWrapS() != GL_CLAMP_TO_EDGE &&
440 samplerState.getWrapS() != GL_CLAMP_TO_BORDER && !isPow2(baseImageDesc.size.width)) ||
441 (samplerState.getWrapT() != GL_CLAMP_TO_EDGE &&
442 samplerState.getWrapT() != GL_CLAMP_TO_BORDER && !isPow2(baseImageDesc.size.height)))
443 {
444 return false;
445 }
446 }
447
448 if (IsMipmapSupported(mType) && IsMipmapFiltered(samplerState.getMinFilter()))
449 {
450 if (!npotSupport)
451 {
452 if (!isPow2(baseImageDesc.size.width) || !isPow2(baseImageDesc.size.height))
453 {
454 return false;
455 }
456 }
457
458 if (!computeMipmapCompleteness())
459 {
460 return false;
461 }
462 }
463 else
464 {
465 if (mType == TextureType::CubeMap && !isCubeComplete())
466 {
467 return false;
468 }
469 }
470
471 // From GL_OES_EGL_image_external_essl3: If state is present in a sampler object bound to a
472 // texture unit that would have been rejected by a call to TexParameter* for the texture bound
473 // to that unit, the behavior of the implementation is as if the texture were incomplete. For
474 // example, if TEXTURE_WRAP_S or TEXTURE_WRAP_T is set to anything but CLAMP_TO_EDGE on the
475 // sampler object bound to a texture unit and the texture bound to that unit is an external
476 // texture and EXT_EGL_image_external_wrap_modes is not enabled, the texture will be considered
477 // incomplete.
478 // Sampler object state which does not affect sampling for the type of texture bound
479 // to a texture unit, such as TEXTURE_WRAP_R for an external texture, does not affect
480 // completeness.
481 if (mType == TextureType::External)
482 {
483 if (!state.getExtensions().EGLImageExternalWrapModesEXT)
484 {
485 if (samplerState.getWrapS() != GL_CLAMP_TO_EDGE ||
486 samplerState.getWrapT() != GL_CLAMP_TO_EDGE)
487 {
488 return false;
489 }
490 }
491
492 if (samplerState.getMinFilter() != GL_LINEAR && samplerState.getMinFilter() != GL_NEAREST)
493 {
494 return false;
495 }
496 }
497
498 return true;
499 }
500
computeMipmapCompleteness() const501 bool TextureState::computeMipmapCompleteness() const
502 {
503 const GLuint maxLevel = getMipmapMaxLevel();
504
505 for (GLuint level = getEffectiveBaseLevel(); level <= maxLevel; level++)
506 {
507 if (mType == TextureType::CubeMap)
508 {
509 for (TextureTarget face : AllCubeFaceTextureTargets())
510 {
511 if (!computeLevelCompleteness(face, level))
512 {
513 return false;
514 }
515 }
516 }
517 else
518 {
519 if (!computeLevelCompleteness(NonCubeTextureTypeToTarget(mType), level))
520 {
521 return false;
522 }
523 }
524 }
525
526 return true;
527 }
528
computeLevelCompleteness(TextureTarget target,size_t level) const529 bool TextureState::computeLevelCompleteness(TextureTarget target, size_t level) const
530 {
531 ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
532
533 if (mImmutableFormat)
534 {
535 return true;
536 }
537
538 const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), getEffectiveBaseLevel());
539 if (baseImageDesc.size.width == 0 || baseImageDesc.size.height == 0 ||
540 baseImageDesc.size.depth == 0)
541 {
542 return false;
543 }
544
545 const ImageDesc &levelImageDesc = getImageDesc(target, level);
546 if (levelImageDesc.size.width == 0 || levelImageDesc.size.height == 0 ||
547 levelImageDesc.size.depth == 0)
548 {
549 return false;
550 }
551
552 if (!Format::SameSized(levelImageDesc.format, baseImageDesc.format))
553 {
554 return false;
555 }
556
557 ASSERT(level >= getEffectiveBaseLevel());
558 const size_t relativeLevel = level - getEffectiveBaseLevel();
559 if (levelImageDesc.size.width != std::max(1, baseImageDesc.size.width >> relativeLevel))
560 {
561 return false;
562 }
563
564 if (levelImageDesc.size.height != std::max(1, baseImageDesc.size.height >> relativeLevel))
565 {
566 return false;
567 }
568
569 if (mType == TextureType::_3D)
570 {
571 if (levelImageDesc.size.depth != std::max(1, baseImageDesc.size.depth >> relativeLevel))
572 {
573 return false;
574 }
575 }
576 else if (IsArrayTextureType(mType))
577 {
578 if (levelImageDesc.size.depth != baseImageDesc.size.depth)
579 {
580 return false;
581 }
582 }
583
584 return true;
585 }
586
getBaseImageTarget() const587 TextureTarget TextureState::getBaseImageTarget() const
588 {
589 return mType == TextureType::CubeMap ? kCubeMapTextureTargetMin
590 : NonCubeTextureTypeToTarget(mType);
591 }
592
getEnabledLevelCount() const593 GLuint TextureState::getEnabledLevelCount() const
594 {
595 GLuint levelCount = 0;
596 const GLuint baseLevel = getEffectiveBaseLevel();
597 const GLuint maxLevel = getMipmapMaxLevel();
598
599 // The mip chain will have either one or more sequential levels, or max levels,
600 // but not a sparse one.
601 Optional<Extents> expectedSize;
602 for (size_t enabledLevel = baseLevel; enabledLevel <= maxLevel; ++enabledLevel, ++levelCount)
603 {
604 // Note: for cube textures, we only check the first face.
605 TextureTarget target = TextureTypeToTarget(mType, 0);
606 size_t descIndex = GetImageDescIndex(target, enabledLevel);
607 const Extents &levelSize = mImageDescs[descIndex].size;
608
609 if (levelSize.empty())
610 {
611 break;
612 }
613 if (expectedSize.valid())
614 {
615 Extents newSize = expectedSize.value();
616 newSize.width = std::max(1, newSize.width >> 1);
617 newSize.height = std::max(1, newSize.height >> 1);
618
619 if (!IsArrayTextureType(mType))
620 {
621 newSize.depth = std::max(1, newSize.depth >> 1);
622 }
623
624 if (newSize != levelSize)
625 {
626 break;
627 }
628 }
629 expectedSize = levelSize;
630 }
631
632 return levelCount;
633 }
634
ImageDesc()635 ImageDesc::ImageDesc()
636 : ImageDesc(Extents(0, 0, 0), Format::Invalid(), 0, GL_TRUE, InitState::Initialized)
637 {}
638
ImageDesc(const Extents & size,const Format & format,const InitState initState)639 ImageDesc::ImageDesc(const Extents &size, const Format &format, const InitState initState)
640 : size(size), format(format), samples(0), fixedSampleLocations(GL_TRUE), initState(initState)
641 {}
642
ImageDesc(const Extents & size,const Format & format,const GLsizei samples,const bool fixedSampleLocations,const InitState initState)643 ImageDesc::ImageDesc(const Extents &size,
644 const Format &format,
645 const GLsizei samples,
646 const bool fixedSampleLocations,
647 const InitState initState)
648 : size(size),
649 format(format),
650 samples(samples),
651 fixedSampleLocations(fixedSampleLocations),
652 initState(initState)
653 {}
654
getMemorySize() const655 GLint ImageDesc::getMemorySize() const
656 {
657 // Assume allocated size is around width * height * depth * samples * pixelBytes
658 angle::CheckedNumeric<GLint> levelSize = 1;
659 levelSize *= format.info->pixelBytes;
660 levelSize *= size.width;
661 levelSize *= size.height;
662 levelSize *= size.depth;
663 levelSize *= std::max(samples, 1);
664 return levelSize.ValueOrDefault(std::numeric_limits<GLint>::max());
665 }
666
getImageDesc(TextureTarget target,size_t level) const667 const ImageDesc &TextureState::getImageDesc(TextureTarget target, size_t level) const
668 {
669 size_t descIndex = GetImageDescIndex(target, level);
670 ASSERT(descIndex < mImageDescs.size());
671 return mImageDescs[descIndex];
672 }
673
setImageDesc(TextureTarget target,size_t level,const ImageDesc & desc)674 void TextureState::setImageDesc(TextureTarget target, size_t level, const ImageDesc &desc)
675 {
676 size_t descIndex = GetImageDescIndex(target, level);
677 ASSERT(descIndex < mImageDescs.size());
678 mImageDescs[descIndex] = desc;
679 if (desc.initState == InitState::MayNeedInit)
680 {
681 mInitState = InitState::MayNeedInit;
682 }
683 else
684 {
685 // Scan for any uninitialized images. If there are none, set the init state of the entire
686 // texture to initialized. The cost of the scan is only paid after doing image
687 // initialization which is already very expensive.
688 bool allImagesInitialized = true;
689
690 for (const ImageDesc &initDesc : mImageDescs)
691 {
692 if (initDesc.initState == InitState::MayNeedInit)
693 {
694 allImagesInitialized = false;
695 break;
696 }
697 }
698
699 if (allImagesInitialized)
700 {
701 mInitState = InitState::Initialized;
702 }
703 }
704 }
705
706 // Note that an ImageIndex that represents an entire level of a cube map corresponds to 6
707 // ImageDescs, so if the cube map is cube complete, we return the ImageDesc of the first cube
708 // face, and we don't allow using this function when the cube map is not cube complete.
getImageDesc(const ImageIndex & imageIndex) const709 const ImageDesc &TextureState::getImageDesc(const ImageIndex &imageIndex) const
710 {
711 if (imageIndex.isEntireLevelCubeMap())
712 {
713 ASSERT(isCubeComplete());
714 const GLint levelIndex = imageIndex.getLevelIndex();
715 return getImageDesc(kCubeMapTextureTargetMin, levelIndex);
716 }
717
718 return getImageDesc(imageIndex.getTarget(), imageIndex.getLevelIndex());
719 }
720
setImageDescChain(GLuint baseLevel,GLuint maxLevel,Extents baseSize,const Format & format,InitState initState)721 void TextureState::setImageDescChain(GLuint baseLevel,
722 GLuint maxLevel,
723 Extents baseSize,
724 const Format &format,
725 InitState initState)
726 {
727 for (GLuint level = baseLevel; level <= maxLevel; level++)
728 {
729 int relativeLevel = (level - baseLevel);
730 Extents levelSize(std::max<int>(baseSize.width >> relativeLevel, 1),
731 std::max<int>(baseSize.height >> relativeLevel, 1),
732 (IsArrayTextureType(mType))
733 ? baseSize.depth
734 : std::max<int>(baseSize.depth >> relativeLevel, 1));
735 ImageDesc levelInfo(levelSize, format, initState);
736
737 if (mType == TextureType::CubeMap)
738 {
739 for (TextureTarget face : AllCubeFaceTextureTargets())
740 {
741 setImageDesc(face, level, levelInfo);
742 }
743 }
744 else
745 {
746 setImageDesc(NonCubeTextureTypeToTarget(mType), level, levelInfo);
747 }
748 }
749 }
750
setImageDescChainMultisample(Extents baseSize,const Format & format,GLsizei samples,bool fixedSampleLocations,InitState initState)751 void TextureState::setImageDescChainMultisample(Extents baseSize,
752 const Format &format,
753 GLsizei samples,
754 bool fixedSampleLocations,
755 InitState initState)
756 {
757 ASSERT(mType == TextureType::_2DMultisample || mType == TextureType::_2DMultisampleArray);
758 ImageDesc levelInfo(baseSize, format, samples, fixedSampleLocations, initState);
759 setImageDesc(NonCubeTextureTypeToTarget(mType), 0, levelInfo);
760 }
761
clearImageDesc(TextureTarget target,size_t level)762 void TextureState::clearImageDesc(TextureTarget target, size_t level)
763 {
764 setImageDesc(target, level, ImageDesc());
765 }
766
clearImageDescs()767 void TextureState::clearImageDescs()
768 {
769 for (size_t descIndex = 0; descIndex < mImageDescs.size(); descIndex++)
770 {
771 mImageDescs[descIndex] = ImageDesc();
772 }
773 }
774
TextureBufferContentsObservers(Texture * texture)775 TextureBufferContentsObservers::TextureBufferContentsObservers(Texture *texture) : mTexture(texture)
776 {}
777
enableForBuffer(Buffer * buffer)778 void TextureBufferContentsObservers::enableForBuffer(Buffer *buffer)
779 {
780 buffer->addContentsObserver(mTexture);
781 }
782
disableForBuffer(Buffer * buffer)783 void TextureBufferContentsObservers::disableForBuffer(Buffer *buffer)
784 {
785 buffer->removeContentsObserver(mTexture);
786 }
787
Texture(rx::GLImplFactory * factory,TextureID id,TextureType type)788 Texture::Texture(rx::GLImplFactory *factory, TextureID id, TextureType type)
789 : RefCountObject(factory->generateSerial(), id),
790 mState(type),
791 mTexture(factory->createTexture(mState)),
792 mImplObserver(this, rx::kTextureImageImplObserverMessageIndex),
793 mBufferObserver(this, kBufferSubjectIndex),
794 mBoundSurface(nullptr),
795 mBoundStream(nullptr),
796 mBufferContentsObservers(this)
797 {
798 mImplObserver.bind(mTexture);
799 if (mTexture)
800 {
801 mTexture->setContentsObservers(&mBufferContentsObservers);
802 }
803
804 // Initially assume the implementation is dirty.
805 mDirtyBits.set(DIRTY_BIT_IMPLEMENTATION);
806 }
807
onDestroy(const Context * context)808 void Texture::onDestroy(const Context *context)
809 {
810 onStateChange(angle::SubjectMessage::TextureIDDeleted);
811
812 if (mBoundSurface)
813 {
814 ANGLE_SWALLOW_ERR(mBoundSurface->releaseTexImage(context, EGL_BACK_BUFFER));
815 mBoundSurface = nullptr;
816 }
817 if (mBoundStream)
818 {
819 mBoundStream->releaseTextures();
820 mBoundStream = nullptr;
821 }
822
823 egl::RefCountObjectReleaser<egl::Image> releaseImage;
824 (void)orphanImages(context, &releaseImage);
825
826 mState.mBuffer.set(context, nullptr, 0, 0);
827
828 if (mTexture)
829 {
830 mTexture->onDestroy(context);
831 }
832 }
833
~Texture()834 Texture::~Texture()
835 {
836 SafeDelete(mTexture);
837 }
838
setLabel(const Context * context,const std::string & label)839 angle::Result Texture::setLabel(const Context *context, const std::string &label)
840 {
841 mState.mLabel = label;
842 return mTexture->onLabelUpdate(context);
843 }
844
getLabel() const845 const std::string &Texture::getLabel() const
846 {
847 return mState.mLabel;
848 }
849
setSwizzleRed(const Context * context,GLenum swizzleRed)850 void Texture::setSwizzleRed(const Context *context, GLenum swizzleRed)
851 {
852 if (mState.mSwizzleState.swizzleRed != swizzleRed)
853 {
854 mState.mSwizzleState.swizzleRed = swizzleRed;
855 signalDirtyState(DIRTY_BIT_SWIZZLE_RED);
856 }
857 }
858
getSwizzleRed() const859 GLenum Texture::getSwizzleRed() const
860 {
861 return mState.mSwizzleState.swizzleRed;
862 }
863
setSwizzleGreen(const Context * context,GLenum swizzleGreen)864 void Texture::setSwizzleGreen(const Context *context, GLenum swizzleGreen)
865 {
866 if (mState.mSwizzleState.swizzleGreen != swizzleGreen)
867 {
868 mState.mSwizzleState.swizzleGreen = swizzleGreen;
869 signalDirtyState(DIRTY_BIT_SWIZZLE_GREEN);
870 }
871 }
872
getSwizzleGreen() const873 GLenum Texture::getSwizzleGreen() const
874 {
875 return mState.mSwizzleState.swizzleGreen;
876 }
877
setSwizzleBlue(const Context * context,GLenum swizzleBlue)878 void Texture::setSwizzleBlue(const Context *context, GLenum swizzleBlue)
879 {
880 if (mState.mSwizzleState.swizzleBlue != swizzleBlue)
881 {
882 mState.mSwizzleState.swizzleBlue = swizzleBlue;
883 signalDirtyState(DIRTY_BIT_SWIZZLE_BLUE);
884 }
885 }
886
getSwizzleBlue() const887 GLenum Texture::getSwizzleBlue() const
888 {
889 return mState.mSwizzleState.swizzleBlue;
890 }
891
setSwizzleAlpha(const Context * context,GLenum swizzleAlpha)892 void Texture::setSwizzleAlpha(const Context *context, GLenum swizzleAlpha)
893 {
894 if (mState.mSwizzleState.swizzleAlpha != swizzleAlpha)
895 {
896 mState.mSwizzleState.swizzleAlpha = swizzleAlpha;
897 signalDirtyState(DIRTY_BIT_SWIZZLE_ALPHA);
898 }
899 }
900
getSwizzleAlpha() const901 GLenum Texture::getSwizzleAlpha() const
902 {
903 return mState.mSwizzleState.swizzleAlpha;
904 }
905
setMinFilter(const Context * context,GLenum minFilter)906 void Texture::setMinFilter(const Context *context, GLenum minFilter)
907 {
908 if (mState.mSamplerState.setMinFilter(minFilter))
909 {
910 signalDirtyState(DIRTY_BIT_MIN_FILTER);
911 }
912 }
913
getMinFilter() const914 GLenum Texture::getMinFilter() const
915 {
916 return mState.mSamplerState.getMinFilter();
917 }
918
setMagFilter(const Context * context,GLenum magFilter)919 void Texture::setMagFilter(const Context *context, GLenum magFilter)
920 {
921 if (mState.mSamplerState.setMagFilter(magFilter))
922 {
923 signalDirtyState(DIRTY_BIT_MAG_FILTER);
924 }
925 }
926
getMagFilter() const927 GLenum Texture::getMagFilter() const
928 {
929 return mState.mSamplerState.getMagFilter();
930 }
931
setWrapS(const Context * context,GLenum wrapS)932 void Texture::setWrapS(const Context *context, GLenum wrapS)
933 {
934 if (mState.mSamplerState.setWrapS(wrapS))
935 {
936 signalDirtyState(DIRTY_BIT_WRAP_S);
937 }
938 }
939
getWrapS() const940 GLenum Texture::getWrapS() const
941 {
942 return mState.mSamplerState.getWrapS();
943 }
944
setWrapT(const Context * context,GLenum wrapT)945 void Texture::setWrapT(const Context *context, GLenum wrapT)
946 {
947 if (mState.mSamplerState.getWrapT() == wrapT)
948 return;
949 if (mState.mSamplerState.setWrapT(wrapT))
950 {
951 signalDirtyState(DIRTY_BIT_WRAP_T);
952 }
953 }
954
getWrapT() const955 GLenum Texture::getWrapT() const
956 {
957 return mState.mSamplerState.getWrapT();
958 }
959
setWrapR(const Context * context,GLenum wrapR)960 void Texture::setWrapR(const Context *context, GLenum wrapR)
961 {
962 if (mState.mSamplerState.setWrapR(wrapR))
963 {
964 signalDirtyState(DIRTY_BIT_WRAP_R);
965 }
966 }
967
getWrapR() const968 GLenum Texture::getWrapR() const
969 {
970 return mState.mSamplerState.getWrapR();
971 }
972
setMaxAnisotropy(const Context * context,float maxAnisotropy)973 void Texture::setMaxAnisotropy(const Context *context, float maxAnisotropy)
974 {
975 if (mState.mSamplerState.setMaxAnisotropy(maxAnisotropy))
976 {
977 signalDirtyState(DIRTY_BIT_MAX_ANISOTROPY);
978 }
979 }
980
getMaxAnisotropy() const981 float Texture::getMaxAnisotropy() const
982 {
983 return mState.mSamplerState.getMaxAnisotropy();
984 }
985
setMinLod(const Context * context,GLfloat minLod)986 void Texture::setMinLod(const Context *context, GLfloat minLod)
987 {
988 if (mState.mSamplerState.setMinLod(minLod))
989 {
990 signalDirtyState(DIRTY_BIT_MIN_LOD);
991 }
992 }
993
getMinLod() const994 GLfloat Texture::getMinLod() const
995 {
996 return mState.mSamplerState.getMinLod();
997 }
998
setMaxLod(const Context * context,GLfloat maxLod)999 void Texture::setMaxLod(const Context *context, GLfloat maxLod)
1000 {
1001 if (mState.mSamplerState.setMaxLod(maxLod))
1002 {
1003 signalDirtyState(DIRTY_BIT_MAX_LOD);
1004 }
1005 }
1006
getMaxLod() const1007 GLfloat Texture::getMaxLod() const
1008 {
1009 return mState.mSamplerState.getMaxLod();
1010 }
1011
setCompareMode(const Context * context,GLenum compareMode)1012 void Texture::setCompareMode(const Context *context, GLenum compareMode)
1013 {
1014 if (mState.mSamplerState.setCompareMode(compareMode))
1015 {
1016 signalDirtyState(DIRTY_BIT_COMPARE_MODE);
1017 }
1018 }
1019
getCompareMode() const1020 GLenum Texture::getCompareMode() const
1021 {
1022 return mState.mSamplerState.getCompareMode();
1023 }
1024
setCompareFunc(const Context * context,GLenum compareFunc)1025 void Texture::setCompareFunc(const Context *context, GLenum compareFunc)
1026 {
1027 if (mState.mSamplerState.setCompareFunc(compareFunc))
1028 {
1029 signalDirtyState(DIRTY_BIT_COMPARE_FUNC);
1030 }
1031 }
1032
getCompareFunc() const1033 GLenum Texture::getCompareFunc() const
1034 {
1035 return mState.mSamplerState.getCompareFunc();
1036 }
1037
setSRGBDecode(const Context * context,GLenum sRGBDecode)1038 void Texture::setSRGBDecode(const Context *context, GLenum sRGBDecode)
1039 {
1040 if (mState.mSamplerState.setSRGBDecode(sRGBDecode))
1041 {
1042 signalDirtyState(DIRTY_BIT_SRGB_DECODE);
1043 }
1044 }
1045
getSRGBDecode() const1046 GLenum Texture::getSRGBDecode() const
1047 {
1048 return mState.mSamplerState.getSRGBDecode();
1049 }
1050
setSRGBOverride(const Context * context,GLenum sRGBOverride)1051 void Texture::setSRGBOverride(const Context *context, GLenum sRGBOverride)
1052 {
1053 SrgbOverride oldOverride = mState.mSrgbOverride;
1054 mState.mSrgbOverride = (sRGBOverride == GL_SRGB) ? SrgbOverride::SRGB : SrgbOverride::Default;
1055 if (mState.mSrgbOverride != oldOverride)
1056 {
1057 signalDirtyState(DIRTY_BIT_SRGB_OVERRIDE);
1058 }
1059 }
1060
getSRGBOverride() const1061 GLenum Texture::getSRGBOverride() const
1062 {
1063 return (mState.mSrgbOverride == SrgbOverride::SRGB) ? GL_SRGB : GL_NONE;
1064 }
1065
getSamplerState() const1066 const SamplerState &Texture::getSamplerState() const
1067 {
1068 return mState.mSamplerState;
1069 }
1070
setBaseLevel(const Context * context,GLuint baseLevel)1071 angle::Result Texture::setBaseLevel(const Context *context, GLuint baseLevel)
1072 {
1073 if (mState.setBaseLevel(baseLevel))
1074 {
1075 ANGLE_TRY(mTexture->setBaseLevel(context, mState.getEffectiveBaseLevel()));
1076 signalDirtyState(DIRTY_BIT_BASE_LEVEL);
1077 }
1078
1079 return angle::Result::Continue;
1080 }
1081
getBaseLevel() const1082 GLuint Texture::getBaseLevel() const
1083 {
1084 return mState.mBaseLevel;
1085 }
1086
setMaxLevel(const Context * context,GLuint maxLevel)1087 void Texture::setMaxLevel(const Context *context, GLuint maxLevel)
1088 {
1089 if (mState.setMaxLevel(maxLevel))
1090 {
1091 signalDirtyState(DIRTY_BIT_MAX_LEVEL);
1092 }
1093 }
1094
getMaxLevel() const1095 GLuint Texture::getMaxLevel() const
1096 {
1097 return mState.mMaxLevel;
1098 }
1099
setDepthStencilTextureMode(const Context * context,GLenum mode)1100 void Texture::setDepthStencilTextureMode(const Context *context, GLenum mode)
1101 {
1102 if (mState.mDepthStencilTextureMode != mode)
1103 {
1104 mState.mDepthStencilTextureMode = mode;
1105 signalDirtyState(DIRTY_BIT_DEPTH_STENCIL_TEXTURE_MODE);
1106 }
1107 }
1108
getDepthStencilTextureMode() const1109 GLenum Texture::getDepthStencilTextureMode() const
1110 {
1111 return mState.mDepthStencilTextureMode;
1112 }
1113
getImmutableFormat() const1114 bool Texture::getImmutableFormat() const
1115 {
1116 return mState.mImmutableFormat;
1117 }
1118
getImmutableLevels() const1119 GLuint Texture::getImmutableLevels() const
1120 {
1121 return mState.mImmutableLevels;
1122 }
1123
setUsage(const Context * context,GLenum usage)1124 void Texture::setUsage(const Context *context, GLenum usage)
1125 {
1126 mState.mUsage = usage;
1127 signalDirtyState(DIRTY_BIT_USAGE);
1128 }
1129
getUsage() const1130 GLenum Texture::getUsage() const
1131 {
1132 return mState.mUsage;
1133 }
1134
setProtectedContent(Context * context,bool hasProtectedContent)1135 void Texture::setProtectedContent(Context *context, bool hasProtectedContent)
1136 {
1137 mState.mHasProtectedContent = hasProtectedContent;
1138 }
1139
hasProtectedContent() const1140 bool Texture::hasProtectedContent() const
1141 {
1142 return mState.mHasProtectedContent;
1143 }
1144
setRenderabilityValidation(Context * context,bool renderabilityValidation)1145 void Texture::setRenderabilityValidation(Context *context, bool renderabilityValidation)
1146 {
1147 mState.mRenderabilityValidation = renderabilityValidation;
1148 signalDirtyState(DIRTY_BIT_RENDERABILITY_VALIDATION_ANGLE);
1149 }
1150
setTilingMode(Context * context,GLenum tilingMode)1151 void Texture::setTilingMode(Context *context, GLenum tilingMode)
1152 {
1153 mState.mTilingMode = gl::FromGLenum<gl::TilingMode>(tilingMode);
1154 }
1155
getTilingMode() const1156 GLenum Texture::getTilingMode() const
1157 {
1158 return gl::ToGLenum(mState.mTilingMode);
1159 }
1160
getTextureState() const1161 const TextureState &Texture::getTextureState() const
1162 {
1163 return mState;
1164 }
1165
getExtents(TextureTarget target,size_t level) const1166 const Extents &Texture::getExtents(TextureTarget target, size_t level) const
1167 {
1168 ASSERT(TextureTargetToType(target) == mState.mType);
1169 return mState.getImageDesc(target, level).size;
1170 }
1171
getWidth(TextureTarget target,size_t level) const1172 size_t Texture::getWidth(TextureTarget target, size_t level) const
1173 {
1174 ASSERT(TextureTargetToType(target) == mState.mType);
1175 return mState.getImageDesc(target, level).size.width;
1176 }
1177
getHeight(TextureTarget target,size_t level) const1178 size_t Texture::getHeight(TextureTarget target, size_t level) const
1179 {
1180 ASSERT(TextureTargetToType(target) == mState.mType);
1181 return mState.getImageDesc(target, level).size.height;
1182 }
1183
getDepth(TextureTarget target,size_t level) const1184 size_t Texture::getDepth(TextureTarget target, size_t level) const
1185 {
1186 ASSERT(TextureTargetToType(target) == mState.mType);
1187 return mState.getImageDesc(target, level).size.depth;
1188 }
1189
getFormat(TextureTarget target,size_t level) const1190 const Format &Texture::getFormat(TextureTarget target, size_t level) const
1191 {
1192 ASSERT(TextureTargetToType(target) == mState.mType);
1193 return mState.getImageDesc(target, level).format;
1194 }
1195
getSamples(TextureTarget target,size_t level) const1196 GLsizei Texture::getSamples(TextureTarget target, size_t level) const
1197 {
1198 ASSERT(TextureTargetToType(target) == mState.mType);
1199 return mState.getImageDesc(target, level).samples;
1200 }
1201
getFixedSampleLocations(TextureTarget target,size_t level) const1202 bool Texture::getFixedSampleLocations(TextureTarget target, size_t level) const
1203 {
1204 ASSERT(TextureTargetToType(target) == mState.mType);
1205 return mState.getImageDesc(target, level).fixedSampleLocations;
1206 }
1207
getMipmapMaxLevel() const1208 GLuint Texture::getMipmapMaxLevel() const
1209 {
1210 return mState.getMipmapMaxLevel();
1211 }
1212
isMipmapComplete() const1213 bool Texture::isMipmapComplete() const
1214 {
1215 return mState.computeMipmapCompleteness();
1216 }
1217
getFoveatedFeatureBits() const1218 GLuint Texture::getFoveatedFeatureBits() const
1219 {
1220 return mState.mFoveationState.getFoveatedFeatureBits();
1221 }
1222
setFoveatedFeatureBits(const GLuint features)1223 void Texture::setFoveatedFeatureBits(const GLuint features)
1224 {
1225 mState.mFoveationState.setFoveatedFeatureBits(features);
1226 }
1227
isFoveationEnabled() const1228 bool Texture::isFoveationEnabled() const
1229 {
1230 return (mState.mFoveationState.getFoveatedFeatureBits() & GL_FOVEATION_ENABLE_BIT_QCOM);
1231 }
1232
getSupportedFoveationFeatures() const1233 GLuint Texture::getSupportedFoveationFeatures() const
1234 {
1235 return mState.mFoveationState.getSupportedFoveationFeatures();
1236 }
1237
getMinPixelDensity() const1238 GLfloat Texture::getMinPixelDensity() const
1239 {
1240 return mState.mFoveationState.getMinPixelDensity();
1241 }
1242
setMinPixelDensity(const GLfloat density)1243 void Texture::setMinPixelDensity(const GLfloat density)
1244 {
1245 mState.mFoveationState.setMinPixelDensity(density);
1246 }
1247
setFocalPoint(uint32_t layer,uint32_t focalPointIndex,float focalX,float focalY,float gainX,float gainY,float foveaArea)1248 void Texture::setFocalPoint(uint32_t layer,
1249 uint32_t focalPointIndex,
1250 float focalX,
1251 float focalY,
1252 float gainX,
1253 float gainY,
1254 float foveaArea)
1255 {
1256 gl::FocalPoint newFocalPoint(focalX, focalY, gainX, gainY, foveaArea);
1257 if (mState.mFoveationState.getFocalPoint(layer, focalPointIndex) == newFocalPoint)
1258 {
1259 // Nothing to do, early out.
1260 return;
1261 }
1262
1263 mState.mFoveationState.setFocalPoint(layer, focalPointIndex, newFocalPoint);
1264 mState.mFoveationState.setFoveatedFeatureBits(GL_FOVEATION_ENABLE_BIT_QCOM);
1265 onStateChange(angle::SubjectMessage::FoveatedRenderingStateChanged);
1266 }
1267
getFocalPoint(uint32_t layer,uint32_t focalPoint) const1268 const FocalPoint &Texture::getFocalPoint(uint32_t layer, uint32_t focalPoint) const
1269 {
1270 return mState.mFoveationState.getFocalPoint(layer, focalPoint);
1271 }
1272
getBoundSurface() const1273 egl::Surface *Texture::getBoundSurface() const
1274 {
1275 return mBoundSurface;
1276 }
1277
getBoundStream() const1278 egl::Stream *Texture::getBoundStream() const
1279 {
1280 return mBoundStream;
1281 }
1282
getMemorySize() const1283 GLint Texture::getMemorySize() const
1284 {
1285 GLint implSize = mTexture->getMemorySize();
1286 if (implSize > 0)
1287 {
1288 return implSize;
1289 }
1290
1291 angle::CheckedNumeric<GLint> size = 0;
1292 for (const ImageDesc &imageDesc : mState.mImageDescs)
1293 {
1294 size += imageDesc.getMemorySize();
1295 }
1296 return size.ValueOrDefault(std::numeric_limits<GLint>::max());
1297 }
1298
getLevelMemorySize(TextureTarget target,GLint level) const1299 GLint Texture::getLevelMemorySize(TextureTarget target, GLint level) const
1300 {
1301 GLint implSize = mTexture->getLevelMemorySize(target, level);
1302 if (implSize > 0)
1303 {
1304 return implSize;
1305 }
1306
1307 return mState.getImageDesc(target, level).getMemorySize();
1308 }
1309
signalDirtyStorage(InitState initState)1310 void Texture::signalDirtyStorage(InitState initState)
1311 {
1312 mState.mInitState = initState;
1313 invalidateCompletenessCache();
1314 mState.mCachedSamplerFormatValid = false;
1315 onStateChange(angle::SubjectMessage::SubjectChanged);
1316 }
1317
signalDirtyState(size_t dirtyBit)1318 void Texture::signalDirtyState(size_t dirtyBit)
1319 {
1320 mDirtyBits.set(dirtyBit);
1321 invalidateCompletenessCache();
1322 mState.mCachedSamplerFormatValid = false;
1323
1324 if (dirtyBit == DIRTY_BIT_BASE_LEVEL || dirtyBit == DIRTY_BIT_MAX_LEVEL)
1325 {
1326 onStateChange(angle::SubjectMessage::SubjectChanged);
1327 }
1328 else
1329 {
1330 onStateChange(angle::SubjectMessage::DirtyBitsFlagged);
1331 }
1332 }
1333
setImage(Context * context,const PixelUnpackState & unpackState,Buffer * unpackBuffer,TextureTarget target,GLint level,GLenum internalFormat,const Extents & size,GLenum format,GLenum type,const uint8_t * pixels)1334 angle::Result Texture::setImage(Context *context,
1335 const PixelUnpackState &unpackState,
1336 Buffer *unpackBuffer,
1337 TextureTarget target,
1338 GLint level,
1339 GLenum internalFormat,
1340 const Extents &size,
1341 GLenum format,
1342 GLenum type,
1343 const uint8_t *pixels)
1344 {
1345 ASSERT(TextureTargetToType(target) == mState.mType);
1346
1347 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1348 ANGLE_TRY(releaseTexImageInternal(context));
1349
1350 egl::RefCountObjectReleaser<egl::Image> releaseImage;
1351 ANGLE_TRY(orphanImages(context, &releaseImage));
1352
1353 ImageIndex index = ImageIndex::MakeFromTarget(target, level, size.depth);
1354
1355 ANGLE_TRY(mTexture->setImage(context, index, internalFormat, size, format, type, unpackState,
1356 unpackBuffer, pixels));
1357
1358 InitState initState = DetermineInitState(context, unpackBuffer, pixels);
1359 mState.setImageDesc(target, level, ImageDesc(size, Format(internalFormat, type), initState));
1360
1361 ANGLE_TRY(handleMipmapGenerationHint(context, level));
1362
1363 signalDirtyStorage(initState);
1364
1365 return angle::Result::Continue;
1366 }
1367
setSubImage(Context * context,const PixelUnpackState & unpackState,Buffer * unpackBuffer,TextureTarget target,GLint level,const Box & area,GLenum format,GLenum type,const uint8_t * pixels)1368 angle::Result Texture::setSubImage(Context *context,
1369 const PixelUnpackState &unpackState,
1370 Buffer *unpackBuffer,
1371 TextureTarget target,
1372 GLint level,
1373 const Box &area,
1374 GLenum format,
1375 GLenum type,
1376 const uint8_t *pixels)
1377 {
1378 ASSERT(TextureTargetToType(target) == mState.mType);
1379
1380 ImageIndex index = ImageIndex::MakeFromTarget(target, level, area.depth);
1381 ANGLE_TRY(ensureSubImageInitialized(context, index, area));
1382
1383 ANGLE_TRY(mTexture->setSubImage(context, index, area, format, type, unpackState, unpackBuffer,
1384 pixels));
1385
1386 ANGLE_TRY(handleMipmapGenerationHint(context, level));
1387
1388 onStateChange(angle::SubjectMessage::ContentsChanged);
1389
1390 return angle::Result::Continue;
1391 }
1392
setCompressedImage(Context * context,const PixelUnpackState & unpackState,TextureTarget target,GLint level,GLenum internalFormat,const Extents & size,size_t imageSize,const uint8_t * pixels)1393 angle::Result Texture::setCompressedImage(Context *context,
1394 const PixelUnpackState &unpackState,
1395 TextureTarget target,
1396 GLint level,
1397 GLenum internalFormat,
1398 const Extents &size,
1399 size_t imageSize,
1400 const uint8_t *pixels)
1401 {
1402 ASSERT(TextureTargetToType(target) == mState.mType);
1403
1404 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1405 ANGLE_TRY(releaseTexImageInternal(context));
1406
1407 egl::RefCountObjectReleaser<egl::Image> releaseImage;
1408 ANGLE_TRY(orphanImages(context, &releaseImage));
1409
1410 ImageIndex index = ImageIndex::MakeFromTarget(target, level, size.depth);
1411
1412 ANGLE_TRY(mTexture->setCompressedImage(context, index, internalFormat, size, unpackState,
1413 imageSize, pixels));
1414
1415 Buffer *unpackBuffer = context->getState().getTargetBuffer(BufferBinding::PixelUnpack);
1416
1417 InitState initState = DetermineInitState(context, unpackBuffer, pixels);
1418 mState.setImageDesc(target, level, ImageDesc(size, Format(internalFormat), initState));
1419 signalDirtyStorage(initState);
1420
1421 return angle::Result::Continue;
1422 }
1423
setCompressedSubImage(const Context * context,const PixelUnpackState & unpackState,TextureTarget target,GLint level,const Box & area,GLenum format,size_t imageSize,const uint8_t * pixels)1424 angle::Result Texture::setCompressedSubImage(const Context *context,
1425 const PixelUnpackState &unpackState,
1426 TextureTarget target,
1427 GLint level,
1428 const Box &area,
1429 GLenum format,
1430 size_t imageSize,
1431 const uint8_t *pixels)
1432 {
1433 ASSERT(TextureTargetToType(target) == mState.mType);
1434
1435 ImageIndex index = ImageIndex::MakeFromTarget(target, level, area.depth);
1436 ANGLE_TRY(ensureSubImageInitialized(context, index, area));
1437
1438 ANGLE_TRY(mTexture->setCompressedSubImage(context, index, area, format, unpackState, imageSize,
1439 pixels));
1440
1441 onStateChange(angle::SubjectMessage::ContentsChanged);
1442
1443 return angle::Result::Continue;
1444 }
1445
copyImage(Context * context,TextureTarget target,GLint level,const Rectangle & sourceArea,GLenum internalFormat,Framebuffer * source)1446 angle::Result Texture::copyImage(Context *context,
1447 TextureTarget target,
1448 GLint level,
1449 const Rectangle &sourceArea,
1450 GLenum internalFormat,
1451 Framebuffer *source)
1452 {
1453 ASSERT(TextureTargetToType(target) == mState.mType);
1454
1455 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1456 ANGLE_TRY(releaseTexImageInternal(context));
1457
1458 egl::RefCountObjectReleaser<egl::Image> releaseImage;
1459 ANGLE_TRY(orphanImages(context, &releaseImage));
1460
1461 ImageIndex index = ImageIndex::MakeFromTarget(target, level, 1);
1462
1463 const InternalFormat &internalFormatInfo =
1464 GetInternalFormatInfo(internalFormat, GL_UNSIGNED_BYTE);
1465
1466 // Most if not all renderers clip these copies to the size of the source framebuffer, leaving
1467 // other pixels untouched. For safety in robust resource initialization, assume that that
1468 // clipping is going to occur when computing the region for which to ensure initialization. If
1469 // the copy lies entirely off the source framebuffer, initialize as though a zero-size box is
1470 // going to be set during the copy operation.
1471 Box destBox;
1472 bool forceCopySubImage = false;
1473 if (context->isRobustResourceInitEnabled())
1474 {
1475 const FramebufferAttachment *sourceReadAttachment = source->getReadColorAttachment();
1476 Extents fbSize = sourceReadAttachment->getSize();
1477 // Force using copySubImage when the source area is out of bounds AND
1478 // we're not copying to and from the same texture
1479 forceCopySubImage = ((sourceArea.x < 0) || (sourceArea.y < 0) ||
1480 ((sourceArea.x + sourceArea.width) > fbSize.width) ||
1481 ((sourceArea.y + sourceArea.height) > fbSize.height)) &&
1482 (sourceReadAttachment->getResource() != this);
1483 Rectangle clippedArea;
1484 if (ClipRectangle(sourceArea, Rectangle(0, 0, fbSize.width, fbSize.height), &clippedArea))
1485 {
1486 const Offset clippedOffset(clippedArea.x - sourceArea.x, clippedArea.y - sourceArea.y,
1487 0);
1488 destBox = Box(clippedOffset.x, clippedOffset.y, clippedOffset.z, clippedArea.width,
1489 clippedArea.height, 1);
1490 }
1491 }
1492
1493 InitState initState = DetermineInitState(context, nullptr, nullptr);
1494
1495 // If we need to initialize the destination texture we split the call into a create call,
1496 // an initializeContents call, and then a copySubImage call. This ensures the destination
1497 // texture exists before we try to clear it.
1498 Extents size(sourceArea.width, sourceArea.height, 1);
1499 if (forceCopySubImage || doesSubImageNeedInit(context, index, destBox))
1500 {
1501 ANGLE_TRY(mTexture->setImage(context, index, internalFormat, size,
1502 internalFormatInfo.format, internalFormatInfo.type,
1503 PixelUnpackState(), nullptr, nullptr));
1504 mState.setImageDesc(target, level, ImageDesc(size, Format(internalFormatInfo), initState));
1505 ANGLE_TRY(ensureSubImageInitialized(context, index, destBox));
1506 ANGLE_TRY(mTexture->copySubImage(context, index, Offset(), sourceArea, source));
1507 }
1508 else
1509 {
1510 ANGLE_TRY(mTexture->copyImage(context, index, sourceArea, internalFormat, source));
1511 }
1512
1513 mState.setImageDesc(target, level,
1514 ImageDesc(size, Format(internalFormatInfo), InitState::Initialized));
1515
1516 ANGLE_TRY(handleMipmapGenerationHint(context, level));
1517
1518 // Because this could affect the texture storage we might need to init other layers/levels.
1519 signalDirtyStorage(initState);
1520
1521 return angle::Result::Continue;
1522 }
1523
copySubImage(Context * context,const ImageIndex & index,const Offset & destOffset,const Rectangle & sourceArea,Framebuffer * source)1524 angle::Result Texture::copySubImage(Context *context,
1525 const ImageIndex &index,
1526 const Offset &destOffset,
1527 const Rectangle &sourceArea,
1528 Framebuffer *source)
1529 {
1530 ASSERT(TextureTargetToType(index.getTarget()) == mState.mType);
1531
1532 // Most if not all renderers clip these copies to the size of the source framebuffer, leaving
1533 // other pixels untouched. For safety in robust resource initialization, assume that that
1534 // clipping is going to occur when computing the region for which to ensure initialization. If
1535 // the copy lies entirely off the source framebuffer, initialize as though a zero-size box is
1536 // going to be set during the copy operation. Note that this assumes that
1537 // ensureSubImageInitialized ensures initialization of the entire destination texture, and not
1538 // just a sub-region.
1539 Box destBox;
1540 if (context->isRobustResourceInitEnabled())
1541 {
1542 Extents fbSize = source->getReadColorAttachment()->getSize();
1543 Rectangle clippedArea;
1544 if (ClipRectangle(sourceArea, Rectangle(0, 0, fbSize.width, fbSize.height), &clippedArea))
1545 {
1546 const Offset clippedOffset(destOffset.x + clippedArea.x - sourceArea.x,
1547 destOffset.y + clippedArea.y - sourceArea.y, 0);
1548 destBox = Box(clippedOffset.x, clippedOffset.y, clippedOffset.z, clippedArea.width,
1549 clippedArea.height, 1);
1550 }
1551 }
1552
1553 ANGLE_TRY(ensureSubImageInitialized(context, index, destBox));
1554
1555 ANGLE_TRY(mTexture->copySubImage(context, index, destOffset, sourceArea, source));
1556 ANGLE_TRY(handleMipmapGenerationHint(context, index.getLevelIndex()));
1557
1558 onStateChange(angle::SubjectMessage::ContentsChanged);
1559
1560 return angle::Result::Continue;
1561 }
1562
copyRenderbufferSubData(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)1563 angle::Result Texture::copyRenderbufferSubData(Context *context,
1564 const gl::Renderbuffer *srcBuffer,
1565 GLint srcLevel,
1566 GLint srcX,
1567 GLint srcY,
1568 GLint srcZ,
1569 GLint dstLevel,
1570 GLint dstX,
1571 GLint dstY,
1572 GLint dstZ,
1573 GLsizei srcWidth,
1574 GLsizei srcHeight,
1575 GLsizei srcDepth)
1576 {
1577 ANGLE_TRY(mTexture->copyRenderbufferSubData(context, srcBuffer, srcLevel, srcX, srcY, srcZ,
1578 dstLevel, dstX, dstY, dstZ, srcWidth, srcHeight,
1579 srcDepth));
1580
1581 signalDirtyStorage(InitState::Initialized);
1582
1583 return angle::Result::Continue;
1584 }
1585
copyTextureSubData(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)1586 angle::Result Texture::copyTextureSubData(Context *context,
1587 const gl::Texture *srcTexture,
1588 GLint srcLevel,
1589 GLint srcX,
1590 GLint srcY,
1591 GLint srcZ,
1592 GLint dstLevel,
1593 GLint dstX,
1594 GLint dstY,
1595 GLint dstZ,
1596 GLsizei srcWidth,
1597 GLsizei srcHeight,
1598 GLsizei srcDepth)
1599 {
1600 ANGLE_TRY(mTexture->copyTextureSubData(context, srcTexture, srcLevel, srcX, srcY, srcZ,
1601 dstLevel, dstX, dstY, dstZ, srcWidth, srcHeight,
1602 srcDepth));
1603
1604 signalDirtyStorage(InitState::Initialized);
1605
1606 return angle::Result::Continue;
1607 }
1608
copyTexture(Context * context,TextureTarget target,GLint level,GLenum internalFormat,GLenum type,GLint sourceLevel,bool unpackFlipY,bool unpackPremultiplyAlpha,bool unpackUnmultiplyAlpha,Texture * source)1609 angle::Result Texture::copyTexture(Context *context,
1610 TextureTarget target,
1611 GLint level,
1612 GLenum internalFormat,
1613 GLenum type,
1614 GLint sourceLevel,
1615 bool unpackFlipY,
1616 bool unpackPremultiplyAlpha,
1617 bool unpackUnmultiplyAlpha,
1618 Texture *source)
1619 {
1620 ASSERT(TextureTargetToType(target) == mState.mType);
1621 ASSERT(source->getType() != TextureType::CubeMap);
1622
1623 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1624 ANGLE_TRY(releaseTexImageInternal(context));
1625
1626 egl::RefCountObjectReleaser<egl::Image> releaseImage;
1627 ANGLE_TRY(orphanImages(context, &releaseImage));
1628
1629 // Initialize source texture.
1630 // Note: we don't have a way to notify which portions of the image changed currently.
1631 ANGLE_TRY(source->ensureInitialized(context));
1632
1633 ImageIndex index = ImageIndex::MakeFromTarget(target, level, ImageIndex::kEntireLevel);
1634
1635 ANGLE_TRY(mTexture->copyTexture(context, index, internalFormat, type, sourceLevel, unpackFlipY,
1636 unpackPremultiplyAlpha, unpackUnmultiplyAlpha, source));
1637
1638 const auto &sourceDesc =
1639 source->mState.getImageDesc(NonCubeTextureTypeToTarget(source->getType()), sourceLevel);
1640 const InternalFormat &internalFormatInfo = GetInternalFormatInfo(internalFormat, type);
1641 mState.setImageDesc(
1642 target, level,
1643 ImageDesc(sourceDesc.size, Format(internalFormatInfo), InitState::Initialized));
1644
1645 signalDirtyStorage(InitState::Initialized);
1646
1647 return angle::Result::Continue;
1648 }
1649
copySubTexture(const Context * context,TextureTarget target,GLint level,const Offset & destOffset,GLint sourceLevel,const Box & sourceBox,bool unpackFlipY,bool unpackPremultiplyAlpha,bool unpackUnmultiplyAlpha,Texture * source)1650 angle::Result Texture::copySubTexture(const Context *context,
1651 TextureTarget target,
1652 GLint level,
1653 const Offset &destOffset,
1654 GLint sourceLevel,
1655 const Box &sourceBox,
1656 bool unpackFlipY,
1657 bool unpackPremultiplyAlpha,
1658 bool unpackUnmultiplyAlpha,
1659 Texture *source)
1660 {
1661 ASSERT(TextureTargetToType(target) == mState.mType);
1662
1663 // Ensure source is initialized.
1664 ANGLE_TRY(source->ensureInitialized(context));
1665
1666 Box destBox(destOffset.x, destOffset.y, destOffset.z, sourceBox.width, sourceBox.height,
1667 sourceBox.depth);
1668 ImageIndex index = ImageIndex::MakeFromTarget(target, level, sourceBox.depth);
1669 ANGLE_TRY(ensureSubImageInitialized(context, index, destBox));
1670
1671 ANGLE_TRY(mTexture->copySubTexture(context, index, destOffset, sourceLevel, sourceBox,
1672 unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha,
1673 source));
1674
1675 onStateChange(angle::SubjectMessage::ContentsChanged);
1676
1677 return angle::Result::Continue;
1678 }
1679
copyCompressedTexture(Context * context,const Texture * source)1680 angle::Result Texture::copyCompressedTexture(Context *context, const Texture *source)
1681 {
1682 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1683 ANGLE_TRY(releaseTexImageInternal(context));
1684
1685 egl::RefCountObjectReleaser<egl::Image> releaseImage;
1686 ANGLE_TRY(orphanImages(context, &releaseImage));
1687
1688 ANGLE_TRY(mTexture->copyCompressedTexture(context, source));
1689
1690 ASSERT(source->getType() != TextureType::CubeMap && getType() != TextureType::CubeMap);
1691 const auto &sourceDesc =
1692 source->mState.getImageDesc(NonCubeTextureTypeToTarget(source->getType()), 0);
1693 mState.setImageDesc(NonCubeTextureTypeToTarget(getType()), 0, sourceDesc);
1694
1695 return angle::Result::Continue;
1696 }
1697
setStorage(Context * context,TextureType type,GLsizei levels,GLenum internalFormat,const Extents & size)1698 angle::Result Texture::setStorage(Context *context,
1699 TextureType type,
1700 GLsizei levels,
1701 GLenum internalFormat,
1702 const Extents &size)
1703 {
1704 ASSERT(type == mState.mType);
1705
1706 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1707 ANGLE_TRY(releaseTexImageInternal(context));
1708
1709 egl::RefCountObjectReleaser<egl::Image> releaseImage;
1710 ANGLE_TRY(orphanImages(context, &releaseImage));
1711
1712 mState.mImmutableFormat = true;
1713 mState.mImmutableLevels = static_cast<GLuint>(levels);
1714 mState.clearImageDescs();
1715 InitState initState = DetermineInitState(context, nullptr, nullptr);
1716 mState.setImageDescChain(0, static_cast<GLuint>(levels - 1), size, Format(internalFormat),
1717 initState);
1718
1719 ANGLE_TRY(mTexture->setStorage(context, type, levels, internalFormat, size));
1720
1721 // Changing the texture to immutable can trigger a change in the base and max levels:
1722 // GLES 3.0.4 section 3.8.10 pg 158:
1723 // "For immutable-format textures, levelbase is clamped to the range[0;levels],levelmax is then
1724 // clamped to the range[levelbase;levels].
1725 mDirtyBits.set(DIRTY_BIT_BASE_LEVEL);
1726 mDirtyBits.set(DIRTY_BIT_MAX_LEVEL);
1727
1728 signalDirtyStorage(initState);
1729
1730 return angle::Result::Continue;
1731 }
1732
setImageExternal(Context * context,TextureTarget target,GLint level,GLenum internalFormat,const Extents & size,GLenum format,GLenum type)1733 angle::Result Texture::setImageExternal(Context *context,
1734 TextureTarget target,
1735 GLint level,
1736 GLenum internalFormat,
1737 const Extents &size,
1738 GLenum format,
1739 GLenum type)
1740 {
1741 ASSERT(TextureTargetToType(target) == mState.mType);
1742
1743 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1744 ANGLE_TRY(releaseTexImageInternal(context));
1745
1746 egl::RefCountObjectReleaser<egl::Image> releaseImage;
1747 ANGLE_TRY(orphanImages(context, &releaseImage));
1748
1749 ImageIndex index = ImageIndex::MakeFromTarget(target, level, size.depth);
1750
1751 ANGLE_TRY(mTexture->setImageExternal(context, index, internalFormat, size, format, type));
1752
1753 InitState initState = InitState::Initialized;
1754 mState.setImageDesc(target, level, ImageDesc(size, Format(internalFormat, type), initState));
1755
1756 ANGLE_TRY(handleMipmapGenerationHint(context, level));
1757
1758 signalDirtyStorage(initState);
1759
1760 return angle::Result::Continue;
1761 }
1762
setStorageMultisample(Context * context,TextureType type,GLsizei samplesIn,GLint internalFormat,const Extents & size,bool fixedSampleLocations)1763 angle::Result Texture::setStorageMultisample(Context *context,
1764 TextureType type,
1765 GLsizei samplesIn,
1766 GLint internalFormat,
1767 const Extents &size,
1768 bool fixedSampleLocations)
1769 {
1770 ASSERT(type == mState.mType);
1771
1772 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1773 ANGLE_TRY(releaseTexImageInternal(context));
1774
1775 egl::RefCountObjectReleaser<egl::Image> releaseImage;
1776 ANGLE_TRY(orphanImages(context, &releaseImage));
1777
1778 // Potentially adjust "samples" to a supported value
1779 const TextureCaps &formatCaps = context->getTextureCaps().get(internalFormat);
1780 GLsizei samples = formatCaps.getNearestSamples(samplesIn);
1781
1782 mState.mImmutableFormat = true;
1783 mState.mImmutableLevels = static_cast<GLuint>(1);
1784 mState.clearImageDescs();
1785 InitState initState = DetermineInitState(context, nullptr, nullptr);
1786 mState.setImageDescChainMultisample(size, Format(internalFormat), samples, fixedSampleLocations,
1787 initState);
1788
1789 ANGLE_TRY(mTexture->setStorageMultisample(context, type, samples, internalFormat, size,
1790 fixedSampleLocations));
1791 signalDirtyStorage(initState);
1792
1793 return angle::Result::Continue;
1794 }
1795
setStorageExternalMemory(Context * context,TextureType type,GLsizei levels,GLenum internalFormat,const Extents & size,MemoryObject * memoryObject,GLuint64 offset,GLbitfield createFlags,GLbitfield usageFlags,const void * imageCreateInfoPNext)1796 angle::Result Texture::setStorageExternalMemory(Context *context,
1797 TextureType type,
1798 GLsizei levels,
1799 GLenum internalFormat,
1800 const Extents &size,
1801 MemoryObject *memoryObject,
1802 GLuint64 offset,
1803 GLbitfield createFlags,
1804 GLbitfield usageFlags,
1805 const void *imageCreateInfoPNext)
1806 {
1807 ASSERT(type == mState.mType);
1808
1809 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1810 ANGLE_TRY(releaseTexImageInternal(context));
1811
1812 egl::RefCountObjectReleaser<egl::Image> releaseImage;
1813 ANGLE_TRY(orphanImages(context, &releaseImage));
1814
1815 ANGLE_TRY(mTexture->setStorageExternalMemory(context, type, levels, internalFormat, size,
1816 memoryObject, offset, createFlags, usageFlags,
1817 imageCreateInfoPNext));
1818
1819 mState.mImmutableFormat = true;
1820 mState.mImmutableLevels = static_cast<GLuint>(levels);
1821 mState.clearImageDescs();
1822 mState.setImageDescChain(0, static_cast<GLuint>(levels - 1), size, Format(internalFormat),
1823 InitState::Initialized);
1824
1825 // Changing the texture to immutable can trigger a change in the base and max levels:
1826 // GLES 3.0.4 section 3.8.10 pg 158:
1827 // "For immutable-format textures, levelbase is clamped to the range[0;levels],levelmax is then
1828 // clamped to the range[levelbase;levels].
1829 mDirtyBits.set(DIRTY_BIT_BASE_LEVEL);
1830 mDirtyBits.set(DIRTY_BIT_MAX_LEVEL);
1831
1832 signalDirtyStorage(InitState::Initialized);
1833
1834 return angle::Result::Continue;
1835 }
1836
generateMipmap(Context * context)1837 angle::Result Texture::generateMipmap(Context *context)
1838 {
1839 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1840 ANGLE_TRY(releaseTexImageInternal(context));
1841
1842 // EGL_KHR_gl_image states that images are only orphaned when generating mipmaps if the texture
1843 // is not mip complete.
1844 egl::RefCountObjectReleaser<egl::Image> releaseImage;
1845 if (!isMipmapComplete())
1846 {
1847 ANGLE_TRY(orphanImages(context, &releaseImage));
1848 }
1849
1850 const GLuint baseLevel = mState.getEffectiveBaseLevel();
1851 const GLuint maxLevel = mState.getMipmapMaxLevel();
1852
1853 if (maxLevel <= baseLevel)
1854 {
1855 return angle::Result::Continue;
1856 }
1857
1858 // If any dimension is zero, this is a no-op:
1859 //
1860 // > Otherwise, if level_base is not defined, or if any dimension is zero, all mipmap levels are
1861 // > left unchanged. This is not an error.
1862 const ImageDesc &baseImageInfo = mState.getImageDesc(mState.getBaseImageTarget(), baseLevel);
1863 if (baseImageInfo.size.empty())
1864 {
1865 return angle::Result::Continue;
1866 }
1867
1868 // Clear the base image(s) immediately if needed
1869 if (context->isRobustResourceInitEnabled())
1870 {
1871 ImageIndexIterator it =
1872 ImageIndexIterator::MakeGeneric(mState.mType, baseLevel, baseLevel + 1,
1873 ImageIndex::kEntireLevel, ImageIndex::kEntireLevel);
1874 while (it.hasNext())
1875 {
1876 const ImageIndex index = it.next();
1877 const ImageDesc &desc = mState.getImageDesc(index.getTarget(), index.getLevelIndex());
1878
1879 if (desc.initState == InitState::MayNeedInit)
1880 {
1881 ANGLE_TRY(initializeContents(context, GL_NONE, index));
1882 }
1883 }
1884 }
1885
1886 ANGLE_TRY(syncState(context, Command::GenerateMipmap));
1887 ANGLE_TRY(mTexture->generateMipmap(context));
1888
1889 // Propagate the format and size of the base mip to the smaller ones. Cube maps are guaranteed
1890 // to have faces of the same size and format so any faces can be picked.
1891 mState.setImageDescChain(baseLevel, maxLevel, baseImageInfo.size, baseImageInfo.format,
1892 InitState::Initialized);
1893
1894 signalDirtyStorage(InitState::Initialized);
1895
1896 return angle::Result::Continue;
1897 }
1898
bindTexImageFromSurface(Context * context,egl::Surface * surface)1899 angle::Result Texture::bindTexImageFromSurface(Context *context, egl::Surface *surface)
1900 {
1901 ASSERT(surface);
1902 ASSERT(!mBoundSurface);
1903 mBoundSurface = surface;
1904
1905 // Set the image info to the size and format of the surface
1906 ASSERT(mState.mType == TextureType::_2D || mState.mType == TextureType::Rectangle);
1907 Extents size(surface->getWidth(), surface->getHeight(), 1);
1908 ImageDesc desc(size, surface->getBindTexImageFormat(), InitState::Initialized);
1909 mState.setImageDesc(NonCubeTextureTypeToTarget(mState.mType), 0, desc);
1910 mState.mHasProtectedContent = surface->hasProtectedContent();
1911
1912 ANGLE_TRY(mTexture->bindTexImage(context, surface));
1913
1914 signalDirtyStorage(InitState::Initialized);
1915 return angle::Result::Continue;
1916 }
1917
releaseTexImageFromSurface(const Context * context)1918 angle::Result Texture::releaseTexImageFromSurface(const Context *context)
1919 {
1920 ASSERT(mBoundSurface);
1921 mBoundSurface = nullptr;
1922 ANGLE_TRY(mTexture->releaseTexImage(context));
1923
1924 // Erase the image info for level 0
1925 ASSERT(mState.mType == TextureType::_2D || mState.mType == TextureType::Rectangle);
1926 mState.clearImageDesc(NonCubeTextureTypeToTarget(mState.mType), 0);
1927 mState.mHasProtectedContent = false;
1928 signalDirtyStorage(InitState::Initialized);
1929 return angle::Result::Continue;
1930 }
1931
bindStream(egl::Stream * stream)1932 void Texture::bindStream(egl::Stream *stream)
1933 {
1934 ASSERT(stream);
1935
1936 // It should not be possible to bind a texture already bound to another stream
1937 ASSERT(mBoundStream == nullptr);
1938
1939 mBoundStream = stream;
1940
1941 ASSERT(mState.mType == TextureType::External);
1942 }
1943
releaseStream()1944 void Texture::releaseStream()
1945 {
1946 ASSERT(mBoundStream);
1947 mBoundStream = nullptr;
1948 }
1949
acquireImageFromStream(const Context * context,const egl::Stream::GLTextureDescription & desc)1950 angle::Result Texture::acquireImageFromStream(const Context *context,
1951 const egl::Stream::GLTextureDescription &desc)
1952 {
1953 ASSERT(mBoundStream != nullptr);
1954 ANGLE_TRY(mTexture->setImageExternal(context, mState.mType, mBoundStream, desc));
1955
1956 Extents size(desc.width, desc.height, 1);
1957 mState.setImageDesc(NonCubeTextureTypeToTarget(mState.mType), 0,
1958 ImageDesc(size, Format(desc.internalFormat), InitState::Initialized));
1959 signalDirtyStorage(InitState::Initialized);
1960 return angle::Result::Continue;
1961 }
1962
releaseImageFromStream(const Context * context)1963 angle::Result Texture::releaseImageFromStream(const Context *context)
1964 {
1965 ASSERT(mBoundStream != nullptr);
1966 ANGLE_TRY(mTexture->setImageExternal(context, mState.mType, nullptr,
1967 egl::Stream::GLTextureDescription()));
1968
1969 // Set to incomplete
1970 mState.clearImageDesc(NonCubeTextureTypeToTarget(mState.mType), 0);
1971 signalDirtyStorage(InitState::Initialized);
1972 return angle::Result::Continue;
1973 }
1974
releaseTexImageInternal(Context * context)1975 angle::Result Texture::releaseTexImageInternal(Context *context)
1976 {
1977 if (mBoundSurface)
1978 {
1979 // Notify the surface
1980 egl::Error eglErr = mBoundSurface->releaseTexImageFromTexture(context);
1981 // TODO(jmadill): Remove this once refactor is complete. http://anglebug.com/3041
1982 if (eglErr.isError())
1983 {
1984 context->handleError(GL_INVALID_OPERATION, "Error releasing tex image from texture",
1985 __FILE__, ANGLE_FUNCTION, __LINE__);
1986 }
1987
1988 // Then, call the same method as from the surface
1989 ANGLE_TRY(releaseTexImageFromSurface(context));
1990 }
1991 return angle::Result::Continue;
1992 }
1993
setEGLImageTargetImpl(Context * context,TextureType type,GLuint levels,egl::Image * imageTarget)1994 angle::Result Texture::setEGLImageTargetImpl(Context *context,
1995 TextureType type,
1996 GLuint levels,
1997 egl::Image *imageTarget)
1998 {
1999 ASSERT(type == mState.mType);
2000
2001 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
2002 ANGLE_TRY(releaseTexImageInternal(context));
2003
2004 egl::RefCountObjectReleaser<egl::Image> releaseImage;
2005 ANGLE_TRY(orphanImages(context, &releaseImage));
2006
2007 setTargetImage(context, imageTarget);
2008
2009 auto initState = imageTarget->sourceInitState();
2010
2011 mState.clearImageDescs();
2012 mState.setImageDescChain(0, levels - 1, imageTarget->getExtents(), imageTarget->getFormat(),
2013 initState);
2014 mState.mHasProtectedContent = imageTarget->hasProtectedContent();
2015
2016 ANGLE_TRY(mTexture->setEGLImageTarget(context, type, imageTarget));
2017
2018 signalDirtyStorage(initState);
2019
2020 return angle::Result::Continue;
2021 }
2022
setEGLImageTarget(Context * context,TextureType type,egl::Image * imageTarget)2023 angle::Result Texture::setEGLImageTarget(Context *context,
2024 TextureType type,
2025 egl::Image *imageTarget)
2026 {
2027 ASSERT(type == TextureType::_2D || type == TextureType::External ||
2028 type == TextureType::_2DArray);
2029
2030 return setEGLImageTargetImpl(context, type, 1u, imageTarget);
2031 }
2032
setStorageEGLImageTarget(Context * context,TextureType type,egl::Image * imageTarget,const GLint * attrib_list)2033 angle::Result Texture::setStorageEGLImageTarget(Context *context,
2034 TextureType type,
2035 egl::Image *imageTarget,
2036 const GLint *attrib_list)
2037 {
2038 ASSERT(type == TextureType::External || type == TextureType::_3D || type == TextureType::_2D ||
2039 type == TextureType::_2DArray || type == TextureType::CubeMap ||
2040 type == TextureType::CubeMapArray);
2041
2042 ANGLE_TRY(setEGLImageTargetImpl(context, type, imageTarget->getLevelCount(), imageTarget));
2043
2044 mState.mImmutableLevels = imageTarget->getLevelCount();
2045 mState.mImmutableFormat = true;
2046
2047 // Changing the texture to immutable can trigger a change in the base and max levels:
2048 // GLES 3.0.4 section 3.8.10 pg 158:
2049 // "For immutable-format textures, levelbase is clamped to the range[0;levels],levelmax is then
2050 // clamped to the range[levelbase;levels].
2051 mDirtyBits.set(DIRTY_BIT_BASE_LEVEL);
2052 mDirtyBits.set(DIRTY_BIT_MAX_LEVEL);
2053
2054 return angle::Result::Continue;
2055 }
2056
getAttachmentSize(const ImageIndex & imageIndex) const2057 Extents Texture::getAttachmentSize(const ImageIndex &imageIndex) const
2058 {
2059 // As an ImageIndex that represents an entire level of a cube map corresponds to 6 ImageDescs,
2060 // we only allow querying ImageDesc on a complete cube map, and this ImageDesc is exactly the
2061 // one that belongs to the first face of the cube map.
2062 if (imageIndex.isEntireLevelCubeMap())
2063 {
2064 // A cube map texture is cube complete if the following conditions all hold true:
2065 // - The levelbase arrays of each of the six texture images making up the cube map have
2066 // identical, positive, and square dimensions.
2067 if (!mState.isCubeComplete())
2068 {
2069 return Extents();
2070 }
2071 }
2072
2073 return mState.getImageDesc(imageIndex).size;
2074 }
2075
getAttachmentFormat(GLenum,const ImageIndex & imageIndex) const2076 Format Texture::getAttachmentFormat(GLenum /*binding*/, const ImageIndex &imageIndex) const
2077 {
2078 // As an ImageIndex that represents an entire level of a cube map corresponds to 6 ImageDescs,
2079 // we only allow querying ImageDesc on a complete cube map, and this ImageDesc is exactly the
2080 // one that belongs to the first face of the cube map.
2081 if (imageIndex.isEntireLevelCubeMap())
2082 {
2083 // A cube map texture is cube complete if the following conditions all hold true:
2084 // - The levelbase arrays were each specified with the same effective internal format.
2085 if (!mState.isCubeComplete())
2086 {
2087 return Format::Invalid();
2088 }
2089 }
2090 return mState.getImageDesc(imageIndex).format;
2091 }
2092
getAttachmentSamples(const ImageIndex & imageIndex) const2093 GLsizei Texture::getAttachmentSamples(const ImageIndex &imageIndex) const
2094 {
2095 // We do not allow querying TextureTarget by an ImageIndex that represents an entire level of a
2096 // cube map (See comments in function TextureTypeToTarget() in ImageIndex.cpp).
2097 if (imageIndex.isEntireLevelCubeMap())
2098 {
2099 return 0;
2100 }
2101
2102 return getSamples(imageIndex.getTarget(), imageIndex.getLevelIndex());
2103 }
2104
isRenderable(const Context * context,GLenum binding,const ImageIndex & imageIndex) const2105 bool Texture::isRenderable(const Context *context,
2106 GLenum binding,
2107 const ImageIndex &imageIndex) const
2108 {
2109 if (isEGLImageTarget())
2110 {
2111 return ImageSibling::isRenderable(context, binding, imageIndex);
2112 }
2113
2114 // Surfaces bound to textures are always renderable. This avoids issues with surfaces with ES3+
2115 // formats not being renderable when bound to textures in ES2 contexts.
2116 if (mBoundSurface)
2117 {
2118 return true;
2119 }
2120
2121 // Skip the renderability checks if it is set via glTexParameteri and current
2122 // context is less than GLES3. Note that we should not skip the check if the
2123 // texture is not renderable at all. Otherwise we would end up rendering to
2124 // textures like compressed textures that are not really renderable.
2125 if (context->getImplementation()
2126 ->getNativeTextureCaps()
2127 .get(getAttachmentFormat(binding, imageIndex).info->sizedInternalFormat)
2128 .textureAttachment &&
2129 !mState.renderabilityValidation() && context->getClientMajorVersion() < 3)
2130 {
2131 return true;
2132 }
2133
2134 return getAttachmentFormat(binding, imageIndex)
2135 .info->textureAttachmentSupport(context->getClientVersion(), context->getExtensions());
2136 }
2137
getAttachmentFixedSampleLocations(const ImageIndex & imageIndex) const2138 bool Texture::getAttachmentFixedSampleLocations(const ImageIndex &imageIndex) const
2139 {
2140 // We do not allow querying TextureTarget by an ImageIndex that represents an entire level of a
2141 // cube map (See comments in function TextureTypeToTarget() in ImageIndex.cpp).
2142 if (imageIndex.isEntireLevelCubeMap())
2143 {
2144 return true;
2145 }
2146
2147 // ES3.1 (section 9.4) requires that the value of TEXTURE_FIXED_SAMPLE_LOCATIONS should be
2148 // the same for all attached textures.
2149 return getFixedSampleLocations(imageIndex.getTarget(), imageIndex.getLevelIndex());
2150 }
2151
setBorderColor(const Context * context,const ColorGeneric & color)2152 void Texture::setBorderColor(const Context *context, const ColorGeneric &color)
2153 {
2154 mState.mSamplerState.setBorderColor(color);
2155 signalDirtyState(DIRTY_BIT_BORDER_COLOR);
2156 }
2157
getBorderColor() const2158 const ColorGeneric &Texture::getBorderColor() const
2159 {
2160 return mState.mSamplerState.getBorderColor();
2161 }
2162
getRequiredTextureImageUnits(const Context * context) const2163 GLint Texture::getRequiredTextureImageUnits(const Context *context) const
2164 {
2165 // Only external texture types can return non-1.
2166 if (mState.mType != TextureType::External)
2167 {
2168 return 1;
2169 }
2170
2171 return mTexture->getRequiredExternalTextureImageUnits(context);
2172 }
2173
setCrop(const Rectangle & rect)2174 void Texture::setCrop(const Rectangle &rect)
2175 {
2176 mState.setCrop(rect);
2177 }
2178
getCrop() const2179 const Rectangle &Texture::getCrop() const
2180 {
2181 return mState.getCrop();
2182 }
2183
setGenerateMipmapHint(GLenum hint)2184 void Texture::setGenerateMipmapHint(GLenum hint)
2185 {
2186 mState.setGenerateMipmapHint(hint);
2187 }
2188
getGenerateMipmapHint() const2189 GLenum Texture::getGenerateMipmapHint() const
2190 {
2191 return mState.getGenerateMipmapHint();
2192 }
2193
setBuffer(const gl::Context * context,gl::Buffer * buffer,GLenum internalFormat)2194 angle::Result Texture::setBuffer(const gl::Context *context,
2195 gl::Buffer *buffer,
2196 GLenum internalFormat)
2197 {
2198 // Use 0 to indicate that the size is taken from whatever size the buffer has when the texture
2199 // buffer is used.
2200 return setBufferRange(context, buffer, internalFormat, 0, 0);
2201 }
2202
setBufferRange(const gl::Context * context,gl::Buffer * buffer,GLenum internalFormat,GLintptr offset,GLsizeiptr size)2203 angle::Result Texture::setBufferRange(const gl::Context *context,
2204 gl::Buffer *buffer,
2205 GLenum internalFormat,
2206 GLintptr offset,
2207 GLsizeiptr size)
2208 {
2209 mState.mImmutableFormat = true;
2210 mState.mBuffer.set(context, buffer, offset, size);
2211 ANGLE_TRY(mTexture->setBuffer(context, internalFormat));
2212
2213 mState.clearImageDescs();
2214 if (buffer == nullptr)
2215 {
2216 mBufferObserver.reset();
2217 InitState initState = DetermineInitState(context, nullptr, nullptr);
2218 signalDirtyStorage(initState);
2219 return angle::Result::Continue;
2220 }
2221
2222 size = GetBoundBufferAvailableSize(mState.mBuffer);
2223
2224 mState.mImmutableLevels = static_cast<GLuint>(1);
2225 InternalFormat internalFormatInfo = GetSizedInternalFormatInfo(internalFormat);
2226 Format format(internalFormat);
2227 Extents extents(static_cast<GLuint>(size / internalFormatInfo.pixelBytes), 1, 1);
2228 InitState initState = buffer->initState();
2229 mState.setImageDesc(TextureTarget::Buffer, 0, ImageDesc(extents, format, initState));
2230
2231 signalDirtyStorage(initState);
2232
2233 // Observe modifications to the buffer, so that extents can be updated.
2234 mBufferObserver.bind(buffer);
2235
2236 return angle::Result::Continue;
2237 }
2238
getBuffer() const2239 const OffsetBindingPointer<Buffer> &Texture::getBuffer() const
2240 {
2241 return mState.mBuffer;
2242 }
2243
onAttach(const Context * context,rx::UniqueSerial framebufferSerial)2244 void Texture::onAttach(const Context *context, rx::UniqueSerial framebufferSerial)
2245 {
2246 addRef();
2247
2248 // Duplicates allowed for multiple attachment points. See the comment in the header.
2249 mBoundFramebufferSerials.push_back(framebufferSerial);
2250
2251 if (!mState.mHasBeenBoundAsAttachment)
2252 {
2253 mDirtyBits.set(DIRTY_BIT_BOUND_AS_ATTACHMENT);
2254 mState.mHasBeenBoundAsAttachment = true;
2255 }
2256 }
2257
onDetach(const Context * context,rx::UniqueSerial framebufferSerial)2258 void Texture::onDetach(const Context *context, rx::UniqueSerial framebufferSerial)
2259 {
2260 // Erase first instance. If there are multiple bindings, leave the others.
2261 ASSERT(isBoundToFramebuffer(framebufferSerial));
2262 mBoundFramebufferSerials.remove_and_permute(framebufferSerial);
2263
2264 release(context);
2265 }
2266
getId() const2267 GLuint Texture::getId() const
2268 {
2269 return id().value;
2270 }
2271
getNativeID() const2272 GLuint Texture::getNativeID() const
2273 {
2274 return mTexture->getNativeID();
2275 }
2276
syncState(const Context * context,Command source)2277 angle::Result Texture::syncState(const Context *context, Command source)
2278 {
2279 ASSERT(hasAnyDirtyBit() || source == Command::GenerateMipmap);
2280 ANGLE_TRY(mTexture->syncState(context, mDirtyBits, source));
2281 mDirtyBits.reset();
2282 mState.mInitState = InitState::Initialized;
2283 return angle::Result::Continue;
2284 }
2285
getAttachmentImpl() const2286 rx::FramebufferAttachmentObjectImpl *Texture::getAttachmentImpl() const
2287 {
2288 return mTexture;
2289 }
2290
isSamplerComplete(const Context * context,const Sampler * optionalSampler)2291 bool Texture::isSamplerComplete(const Context *context, const Sampler *optionalSampler)
2292 {
2293 const auto &samplerState =
2294 optionalSampler ? optionalSampler->getSamplerState() : mState.mSamplerState;
2295 const auto &contextState = context->getState();
2296
2297 if (contextState.getContextID() != mCompletenessCache.context ||
2298 !mCompletenessCache.samplerState.sameCompleteness(samplerState))
2299 {
2300 mCompletenessCache.context = context->getState().getContextID();
2301 mCompletenessCache.samplerState = samplerState;
2302 mCompletenessCache.samplerComplete =
2303 mState.computeSamplerCompleteness(samplerState, contextState);
2304 }
2305
2306 return mCompletenessCache.samplerComplete;
2307 }
2308
2309 // CopyImageSubData requires that we ignore format-based completeness rules
isSamplerCompleteForCopyImage(const Context * context,const Sampler * optionalSampler) const2310 bool Texture::isSamplerCompleteForCopyImage(const Context *context,
2311 const Sampler *optionalSampler) const
2312 {
2313 const gl::SamplerState &samplerState =
2314 optionalSampler ? optionalSampler->getSamplerState() : mState.mSamplerState;
2315 const gl::State &contextState = context->getState();
2316 return mState.computeSamplerCompletenessForCopyImage(samplerState, contextState);
2317 }
2318
SamplerCompletenessCache()2319 Texture::SamplerCompletenessCache::SamplerCompletenessCache()
2320 : context({0}), samplerState(), samplerComplete(false)
2321 {}
2322
invalidateCompletenessCache() const2323 void Texture::invalidateCompletenessCache() const
2324 {
2325 mCompletenessCache.context = {0};
2326 }
2327
ensureInitialized(const Context * context)2328 angle::Result Texture::ensureInitialized(const Context *context)
2329 {
2330 if (!context->isRobustResourceInitEnabled() || mState.mInitState == InitState::Initialized)
2331 {
2332 return angle::Result::Continue;
2333 }
2334
2335 bool anyDirty = false;
2336
2337 ImageIndexIterator it =
2338 ImageIndexIterator::MakeGeneric(mState.mType, 0, IMPLEMENTATION_MAX_TEXTURE_LEVELS + 1,
2339 ImageIndex::kEntireLevel, ImageIndex::kEntireLevel);
2340 while (it.hasNext())
2341 {
2342 const ImageIndex index = it.next();
2343 ImageDesc &desc =
2344 mState.mImageDescs[GetImageDescIndex(index.getTarget(), index.getLevelIndex())];
2345 if (desc.initState == InitState::MayNeedInit && !desc.size.empty())
2346 {
2347 ASSERT(mState.mInitState == InitState::MayNeedInit);
2348 ANGLE_TRY(initializeContents(context, GL_NONE, index));
2349 desc.initState = InitState::Initialized;
2350 anyDirty = true;
2351 }
2352 }
2353 if (anyDirty)
2354 {
2355 signalDirtyStorage(InitState::Initialized);
2356 }
2357 mState.mInitState = InitState::Initialized;
2358
2359 return angle::Result::Continue;
2360 }
2361
initState(GLenum,const ImageIndex & imageIndex) const2362 InitState Texture::initState(GLenum /*binding*/, const ImageIndex &imageIndex) const
2363 {
2364 // As an ImageIndex that represents an entire level of a cube map corresponds to 6 ImageDescs,
2365 // we need to check all the related ImageDescs.
2366 if (imageIndex.isEntireLevelCubeMap())
2367 {
2368 const GLint levelIndex = imageIndex.getLevelIndex();
2369 for (TextureTarget cubeFaceTarget : AllCubeFaceTextureTargets())
2370 {
2371 if (mState.getImageDesc(cubeFaceTarget, levelIndex).initState == InitState::MayNeedInit)
2372 {
2373 return InitState::MayNeedInit;
2374 }
2375 }
2376 return InitState::Initialized;
2377 }
2378
2379 return mState.getImageDesc(imageIndex).initState;
2380 }
2381
setInitState(GLenum binding,const ImageIndex & imageIndex,InitState initState)2382 void Texture::setInitState(GLenum binding, const ImageIndex &imageIndex, InitState initState)
2383 {
2384 // As an ImageIndex that represents an entire level of a cube map corresponds to 6 ImageDescs,
2385 // we need to update all the related ImageDescs.
2386 if (imageIndex.isEntireLevelCubeMap())
2387 {
2388 const GLint levelIndex = imageIndex.getLevelIndex();
2389 for (TextureTarget cubeFaceTarget : AllCubeFaceTextureTargets())
2390 {
2391 setInitState(binding, ImageIndex::MakeCubeMapFace(cubeFaceTarget, levelIndex),
2392 initState);
2393 }
2394 }
2395 else
2396 {
2397 ImageDesc newDesc = mState.getImageDesc(imageIndex);
2398 newDesc.initState = initState;
2399 mState.setImageDesc(imageIndex.getTarget(), imageIndex.getLevelIndex(), newDesc);
2400 }
2401 }
2402
setInitState(InitState initState)2403 void Texture::setInitState(InitState initState)
2404 {
2405 for (ImageDesc &imageDesc : mState.mImageDescs)
2406 {
2407 // Only modify defined images, undefined images will remain in the initialized state
2408 if (!imageDesc.size.empty())
2409 {
2410 imageDesc.initState = initState;
2411 }
2412 }
2413 mState.mInitState = initState;
2414 }
2415
doesSubImageNeedInit(const Context * context,const ImageIndex & imageIndex,const Box & area) const2416 bool Texture::doesSubImageNeedInit(const Context *context,
2417 const ImageIndex &imageIndex,
2418 const Box &area) const
2419 {
2420 if (!context->isRobustResourceInitEnabled() || mState.mInitState == InitState::Initialized)
2421 {
2422 return false;
2423 }
2424
2425 // Pre-initialize the texture contents if necessary.
2426 const ImageDesc &desc = mState.getImageDesc(imageIndex);
2427 if (desc.initState != InitState::MayNeedInit)
2428 {
2429 return false;
2430 }
2431
2432 ASSERT(mState.mInitState == InitState::MayNeedInit);
2433 return !area.coversSameExtent(desc.size);
2434 }
2435
ensureSubImageInitialized(const Context * context,const ImageIndex & imageIndex,const Box & area)2436 angle::Result Texture::ensureSubImageInitialized(const Context *context,
2437 const ImageIndex &imageIndex,
2438 const Box &area)
2439 {
2440 if (doesSubImageNeedInit(context, imageIndex, area))
2441 {
2442 // NOTE: do not optimize this to only initialize the passed area of the texture, or the
2443 // initialization logic in copySubImage will be incorrect.
2444 ANGLE_TRY(initializeContents(context, GL_NONE, imageIndex));
2445 }
2446 // Note: binding is ignored for textures.
2447 setInitState(GL_NONE, imageIndex, InitState::Initialized);
2448 return angle::Result::Continue;
2449 }
2450
handleMipmapGenerationHint(Context * context,int level)2451 angle::Result Texture::handleMipmapGenerationHint(Context *context, int level)
2452 {
2453 if (getGenerateMipmapHint() == GL_TRUE && level == 0)
2454 {
2455 ANGLE_TRY(generateMipmap(context));
2456 }
2457
2458 return angle::Result::Continue;
2459 }
2460
onSubjectStateChange(angle::SubjectIndex index,angle::SubjectMessage message)2461 void Texture::onSubjectStateChange(angle::SubjectIndex index, angle::SubjectMessage message)
2462 {
2463 switch (message)
2464 {
2465 case angle::SubjectMessage::ContentsChanged:
2466 if (index != kBufferSubjectIndex)
2467 {
2468 // ContentsChange originates from TextureStorage11::resolveAndReleaseTexture
2469 // which resolves the underlying multisampled texture if it exists and so
2470 // Texture will signal dirty storage to invalidate its own cache and the
2471 // attached framebuffer's cache.
2472 signalDirtyStorage(InitState::Initialized);
2473 }
2474 break;
2475 case angle::SubjectMessage::DirtyBitsFlagged:
2476 signalDirtyState(DIRTY_BIT_IMPLEMENTATION);
2477
2478 // Notify siblings that we are dirty.
2479 if (index == rx::kTextureImageImplObserverMessageIndex)
2480 {
2481 notifySiblings(message);
2482 }
2483 break;
2484 case angle::SubjectMessage::SubjectChanged:
2485 mState.mInitState = InitState::MayNeedInit;
2486 signalDirtyState(DIRTY_BIT_IMPLEMENTATION);
2487 onStateChange(angle::SubjectMessage::ContentsChanged);
2488
2489 // Notify siblings that we are dirty.
2490 if (index == rx::kTextureImageImplObserverMessageIndex)
2491 {
2492 notifySiblings(message);
2493 }
2494 else if (index == kBufferSubjectIndex)
2495 {
2496 const gl::Buffer *buffer = mState.mBuffer.get();
2497 ASSERT(buffer != nullptr);
2498
2499 // Update cached image desc based on buffer size.
2500 GLsizeiptr size = GetBoundBufferAvailableSize(mState.mBuffer);
2501
2502 ImageDesc desc = mState.getImageDesc(TextureTarget::Buffer, 0);
2503 const GLuint pixelBytes = desc.format.info->pixelBytes;
2504 desc.size.width = static_cast<GLuint>(size / pixelBytes);
2505
2506 mState.setImageDesc(TextureTarget::Buffer, 0, desc);
2507 }
2508 break;
2509 case angle::SubjectMessage::StorageReleased:
2510 // When the TextureStorage is released, it needs to update the
2511 // RenderTargetCache of the Framebuffer attaching this Texture.
2512 // This is currently only for D3D back-end. See http://crbug.com/1234829
2513 if (index == rx::kTextureImageImplObserverMessageIndex)
2514 {
2515 onStateChange(angle::SubjectMessage::StorageReleased);
2516 }
2517 break;
2518 case angle::SubjectMessage::SubjectMapped:
2519 case angle::SubjectMessage::SubjectUnmapped:
2520 case angle::SubjectMessage::BindingChanged:
2521 {
2522 ASSERT(index == kBufferSubjectIndex);
2523 gl::Buffer *buffer = mState.mBuffer.get();
2524 ASSERT(buffer != nullptr);
2525 if (buffer->hasContentsObserver(this))
2526 {
2527 onBufferContentsChange();
2528 }
2529 }
2530 break;
2531 case angle::SubjectMessage::InitializationComplete:
2532 ASSERT(index == rx::kTextureImageImplObserverMessageIndex);
2533 setInitState(InitState::Initialized);
2534 break;
2535 case angle::SubjectMessage::InternalMemoryAllocationChanged:
2536 // Need to mark the texture dirty to give the back end a chance to handle the new
2537 // buffer. For example, the Vulkan back end needs to create a new buffer view that
2538 // points to the newly allocated buffer and update the texture descriptor set.
2539 signalDirtyState(DIRTY_BIT_IMPLEMENTATION);
2540 break;
2541 default:
2542 UNREACHABLE();
2543 break;
2544 }
2545 }
2546
onBufferContentsChange()2547 void Texture::onBufferContentsChange()
2548 {
2549 mState.mInitState = InitState::MayNeedInit;
2550 signalDirtyState(DIRTY_BIT_IMPLEMENTATION);
2551 onStateChange(angle::SubjectMessage::ContentsChanged);
2552 }
2553
onBindToMSRTTFramebuffer()2554 void Texture::onBindToMSRTTFramebuffer()
2555 {
2556 if (!mState.mHasBeenBoundToMSRTTFramebuffer)
2557 {
2558 mDirtyBits.set(DIRTY_BIT_BOUND_TO_MSRTT_FRAMEBUFFER);
2559 mState.mHasBeenBoundToMSRTTFramebuffer = true;
2560 }
2561 }
2562
getImplementationColorReadFormat(const Context * context) const2563 GLenum Texture::getImplementationColorReadFormat(const Context *context) const
2564 {
2565 return mTexture->getColorReadFormat(context);
2566 }
2567
getImplementationColorReadType(const Context * context) const2568 GLenum Texture::getImplementationColorReadType(const Context *context) const
2569 {
2570 return mTexture->getColorReadType(context);
2571 }
2572
getTexImage(const Context * context,const PixelPackState & packState,Buffer * packBuffer,TextureTarget target,GLint level,GLenum format,GLenum type,void * pixels)2573 angle::Result Texture::getTexImage(const Context *context,
2574 const PixelPackState &packState,
2575 Buffer *packBuffer,
2576 TextureTarget target,
2577 GLint level,
2578 GLenum format,
2579 GLenum type,
2580 void *pixels)
2581 {
2582 // No-op if the image level is empty.
2583 if (getExtents(target, level).empty())
2584 {
2585 return angle::Result::Continue;
2586 }
2587
2588 return mTexture->getTexImage(context, packState, packBuffer, target, level, format, type,
2589 pixels);
2590 }
2591
getCompressedTexImage(const Context * context,const PixelPackState & packState,Buffer * packBuffer,TextureTarget target,GLint level,void * pixels)2592 angle::Result Texture::getCompressedTexImage(const Context *context,
2593 const PixelPackState &packState,
2594 Buffer *packBuffer,
2595 TextureTarget target,
2596 GLint level,
2597 void *pixels)
2598 {
2599 // No-op if the image level is empty.
2600 if (getExtents(target, level).empty())
2601 {
2602 return angle::Result::Continue;
2603 }
2604
2605 return mTexture->getCompressedTexImage(context, packState, packBuffer, target, level, pixels);
2606 }
2607
onBindAsImageTexture()2608 void Texture::onBindAsImageTexture()
2609 {
2610 if (!mState.mHasBeenBoundAsImage)
2611 {
2612 mDirtyBits.set(DIRTY_BIT_BOUND_AS_IMAGE);
2613 mState.mHasBeenBoundAsImage = true;
2614 }
2615 }
2616
2617 } // namespace gl
2618