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