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/GLImplFactory.h"
20 #include "libANGLE/renderer/TextureImpl.h"
21
22 namespace gl
23 {
24
25 namespace
26 {
27 constexpr angle::SubjectIndex kBufferSubjectIndex = 2;
28 static_assert(kBufferSubjectIndex != rx::kTextureImageImplObserverMessageIndex, "Index collision");
29 static_assert(kBufferSubjectIndex != rx::kTextureImageSiblingMessageIndex, "Index collision");
30
IsPointSampled(const SamplerState & samplerState)31 bool IsPointSampled(const SamplerState &samplerState)
32 {
33 return (samplerState.getMagFilter() == GL_NEAREST &&
34 (samplerState.getMinFilter() == GL_NEAREST ||
35 samplerState.getMinFilter() == GL_NEAREST_MIPMAP_NEAREST));
36 }
37
GetImageDescIndex(TextureTarget target,size_t level)38 size_t GetImageDescIndex(TextureTarget target, size_t level)
39 {
40 return IsCubeMapFaceTarget(target) ? (level * 6 + CubeMapTextureTargetToFaceIndex(target))
41 : level;
42 }
43
DetermineInitState(const Context * context,Buffer * unpackBuffer,const uint8_t * pixels)44 InitState DetermineInitState(const Context *context, Buffer *unpackBuffer, const uint8_t *pixels)
45 {
46 // Can happen in tests.
47 if (!context || !context->isRobustResourceInitEnabled())
48 {
49 return InitState::Initialized;
50 }
51
52 return (!pixels && !unpackBuffer) ? InitState::MayNeedInit : InitState::Initialized;
53 }
54 } // namespace
55
IsMipmapFiltered(GLenum minFilterMode)56 bool IsMipmapFiltered(GLenum minFilterMode)
57 {
58 switch (minFilterMode)
59 {
60 case GL_NEAREST:
61 case GL_LINEAR:
62 return false;
63 case GL_NEAREST_MIPMAP_NEAREST:
64 case GL_LINEAR_MIPMAP_NEAREST:
65 case GL_NEAREST_MIPMAP_LINEAR:
66 case GL_LINEAR_MIPMAP_LINEAR:
67 return true;
68 default:
69 UNREACHABLE();
70 return false;
71 }
72 }
73
ConvertToNearestFilterMode(GLenum filterMode)74 GLenum ConvertToNearestFilterMode(GLenum filterMode)
75 {
76 switch (filterMode)
77 {
78 case GL_LINEAR:
79 return GL_NEAREST;
80 case GL_LINEAR_MIPMAP_NEAREST:
81 return GL_NEAREST_MIPMAP_NEAREST;
82 case GL_LINEAR_MIPMAP_LINEAR:
83 return GL_NEAREST_MIPMAP_LINEAR;
84 default:
85 return filterMode;
86 }
87 }
88
ConvertToNearestMipFilterMode(GLenum filterMode)89 GLenum ConvertToNearestMipFilterMode(GLenum filterMode)
90 {
91 switch (filterMode)
92 {
93 case GL_LINEAR_MIPMAP_LINEAR:
94 return GL_LINEAR_MIPMAP_NEAREST;
95 case GL_NEAREST_MIPMAP_LINEAR:
96 return GL_NEAREST_MIPMAP_NEAREST;
97 default:
98 return filterMode;
99 }
100 }
101
IsMipmapSupported(const TextureType & type)102 bool IsMipmapSupported(const TextureType &type)
103 {
104 if (type == TextureType::_2DMultisample || type == TextureType::Buffer)
105 {
106 return false;
107 }
108 return true;
109 }
110
SwizzleState()111 SwizzleState::SwizzleState()
112 : swizzleRed(GL_RED), swizzleGreen(GL_GREEN), swizzleBlue(GL_BLUE), swizzleAlpha(GL_ALPHA)
113 {}
114
SwizzleState(GLenum red,GLenum green,GLenum blue,GLenum alpha)115 SwizzleState::SwizzleState(GLenum red, GLenum green, GLenum blue, GLenum alpha)
116 : swizzleRed(red), swizzleGreen(green), swizzleBlue(blue), swizzleAlpha(alpha)
117 {}
118
swizzleRequired() const119 bool SwizzleState::swizzleRequired() const
120 {
121 return swizzleRed != GL_RED || swizzleGreen != GL_GREEN || swizzleBlue != GL_BLUE ||
122 swizzleAlpha != GL_ALPHA;
123 }
124
operator ==(const SwizzleState & other) const125 bool SwizzleState::operator==(const SwizzleState &other) const
126 {
127 return swizzleRed == other.swizzleRed && swizzleGreen == other.swizzleGreen &&
128 swizzleBlue == other.swizzleBlue && swizzleAlpha == other.swizzleAlpha;
129 }
130
operator !=(const SwizzleState & other) const131 bool SwizzleState::operator!=(const SwizzleState &other) const
132 {
133 return !(*this == other);
134 }
135
TextureState(TextureType type)136 TextureState::TextureState(TextureType type)
137 : mType(type),
138 mSamplerState(SamplerState::CreateDefaultForTarget(type)),
139 mSrgbOverride(SrgbOverride::Default),
140 mBaseLevel(0),
141 mMaxLevel(kInitialMaxLevel),
142 mDepthStencilTextureMode(GL_DEPTH_COMPONENT),
143 mHasBeenBoundAsImage(false),
144 mImmutableFormat(false),
145 mImmutableLevels(0),
146 mUsage(GL_NONE),
147 mImageDescs((IMPLEMENTATION_MAX_TEXTURE_LEVELS + 1) * (type == TextureType::CubeMap ? 6 : 1)),
148 mCropRect(0, 0, 0, 0),
149 mGenerateMipmapHint(GL_FALSE),
150 mInitState(InitState::Initialized),
151 mCachedSamplerFormat(SamplerFormat::InvalidEnum),
152 mCachedSamplerCompareMode(GL_NONE),
153 mCachedSamplerFormatValid(false)
154 {}
155
~TextureState()156 TextureState::~TextureState() {}
157
swizzleRequired() const158 bool TextureState::swizzleRequired() const
159 {
160 return mSwizzleState.swizzleRequired();
161 }
162
getEffectiveBaseLevel() const163 GLuint TextureState::getEffectiveBaseLevel() const
164 {
165 if (mImmutableFormat)
166 {
167 // GLES 3.0.4 section 3.8.10
168 return std::min(mBaseLevel, mImmutableLevels - 1);
169 }
170 // Some classes use the effective base level to index arrays with level data. By clamping the
171 // effective base level to max levels these arrays need just one extra item to store properties
172 // that should be returned for all out-of-range base level values, instead of needing special
173 // handling for out-of-range base levels.
174 return std::min(mBaseLevel, static_cast<GLuint>(IMPLEMENTATION_MAX_TEXTURE_LEVELS));
175 }
176
getEffectiveMaxLevel() const177 GLuint TextureState::getEffectiveMaxLevel() const
178 {
179 if (mImmutableFormat)
180 {
181 // GLES 3.0.4 section 3.8.10
182 GLuint clampedMaxLevel = std::max(mMaxLevel, getEffectiveBaseLevel());
183 clampedMaxLevel = std::min(clampedMaxLevel, mImmutableLevels - 1);
184 return clampedMaxLevel;
185 }
186 return mMaxLevel;
187 }
188
getMipmapMaxLevel() const189 GLuint TextureState::getMipmapMaxLevel() const
190 {
191 const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), getEffectiveBaseLevel());
192 GLuint expectedMipLevels = 0;
193 if (mType == TextureType::_3D)
194 {
195 const int maxDim = std::max(std::max(baseImageDesc.size.width, baseImageDesc.size.height),
196 baseImageDesc.size.depth);
197 expectedMipLevels = static_cast<GLuint>(log2(maxDim));
198 }
199 else
200 {
201 expectedMipLevels = static_cast<GLuint>(
202 log2(std::max(baseImageDesc.size.width, baseImageDesc.size.height)));
203 }
204
205 return std::min<GLuint>(getEffectiveBaseLevel() + expectedMipLevels, getEffectiveMaxLevel());
206 }
207
setBaseLevel(GLuint baseLevel)208 bool TextureState::setBaseLevel(GLuint baseLevel)
209 {
210 if (mBaseLevel != baseLevel)
211 {
212 mBaseLevel = baseLevel;
213 return true;
214 }
215 return false;
216 }
217
setMaxLevel(GLuint maxLevel)218 bool TextureState::setMaxLevel(GLuint maxLevel)
219 {
220 if (mMaxLevel != maxLevel)
221 {
222 mMaxLevel = maxLevel;
223 return true;
224 }
225
226 return false;
227 }
228
229 // Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
230 // According to [OpenGL ES 3.0.5] section 3.8.13 Texture Completeness page 160 any
231 // per-level checks begin at the base-level.
232 // For OpenGL ES2 the base level is always zero.
isCubeComplete() const233 bool TextureState::isCubeComplete() const
234 {
235 ASSERT(mType == TextureType::CubeMap);
236
237 angle::EnumIterator<TextureTarget> face = kCubeMapTextureTargetMin;
238 const ImageDesc &baseImageDesc = getImageDesc(*face, getEffectiveBaseLevel());
239 if (baseImageDesc.size.width == 0 || baseImageDesc.size.width != baseImageDesc.size.height)
240 {
241 return false;
242 }
243
244 ++face;
245
246 for (; face != kAfterCubeMapTextureTargetMax; ++face)
247 {
248 const ImageDesc &faceImageDesc = getImageDesc(*face, getEffectiveBaseLevel());
249 if (faceImageDesc.size.width != baseImageDesc.size.width ||
250 faceImageDesc.size.height != baseImageDesc.size.height ||
251 !Format::SameSized(faceImageDesc.format, baseImageDesc.format))
252 {
253 return false;
254 }
255 }
256
257 return true;
258 }
259
getBaseLevelDesc() const260 const ImageDesc &TextureState::getBaseLevelDesc() const
261 {
262 ASSERT(mType != TextureType::CubeMap || isCubeComplete());
263 return getImageDesc(getBaseImageTarget(), getEffectiveBaseLevel());
264 }
265
getLevelZeroDesc() const266 const ImageDesc &TextureState::getLevelZeroDesc() const
267 {
268 ASSERT(mType != TextureType::CubeMap || isCubeComplete());
269 return getImageDesc(getBaseImageTarget(), 0);
270 }
271
setCrop(const Rectangle & rect)272 void TextureState::setCrop(const Rectangle &rect)
273 {
274 mCropRect = rect;
275 }
276
getCrop() const277 const Rectangle &TextureState::getCrop() const
278 {
279 return mCropRect;
280 }
281
setGenerateMipmapHint(GLenum hint)282 void TextureState::setGenerateMipmapHint(GLenum hint)
283 {
284 mGenerateMipmapHint = hint;
285 }
286
getGenerateMipmapHint() const287 GLenum TextureState::getGenerateMipmapHint() const
288 {
289 return mGenerateMipmapHint;
290 }
291
computeRequiredSamplerFormat(const SamplerState & samplerState) const292 SamplerFormat TextureState::computeRequiredSamplerFormat(const SamplerState &samplerState) const
293 {
294 const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), getEffectiveBaseLevel());
295 if ((baseImageDesc.format.info->format == GL_DEPTH_COMPONENT ||
296 baseImageDesc.format.info->format == GL_DEPTH_STENCIL) &&
297 samplerState.getCompareMode() != GL_NONE)
298 {
299 return SamplerFormat::Shadow;
300 }
301 else
302 {
303 switch (baseImageDesc.format.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.
323 if (mType == TextureType::Buffer)
324 {
325 return true;
326 }
327
328 if (!mImmutableFormat && mBaseLevel > mMaxLevel)
329 {
330 return false;
331 }
332 const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), getEffectiveBaseLevel());
333 if (baseImageDesc.size.width == 0 || baseImageDesc.size.height == 0 ||
334 baseImageDesc.size.depth == 0)
335 {
336 return false;
337 }
338 // The cases where the texture is incomplete because base level is out of range should be
339 // handled by the above condition.
340 ASSERT(mBaseLevel < IMPLEMENTATION_MAX_TEXTURE_LEVELS || mImmutableFormat);
341
342 if (mType == TextureType::CubeMap && baseImageDesc.size.width != baseImageDesc.size.height)
343 {
344 return false;
345 }
346
347 // According to es 3.1 spec, texture is justified as incomplete if sized internalformat is
348 // unfilterable(table 20.11) and filter is not GL_NEAREST(8.16). The default value of minFilter
349 // is NEAREST_MIPMAP_LINEAR and magFilter is LINEAR(table 20.11,). For multismaple texture,
350 // filter state of multisample texture is ignored(11.1.3.3). So it shouldn't be judged as
351 // incomplete texture. So, we ignore filtering for multisample texture completeness here.
352 if (!IsMultisampled(mType) &&
353 !baseImageDesc.format.info->filterSupport(state.getClientVersion(),
354 state.getExtensions()) &&
355 !IsPointSampled(samplerState))
356 {
357 return false;
358 }
359 bool npotSupport = state.getExtensions().textureNPOTOES || state.getClientMajorVersion() >= 3;
360 if (!npotSupport)
361 {
362 if ((samplerState.getWrapS() != GL_CLAMP_TO_EDGE &&
363 samplerState.getWrapS() != GL_CLAMP_TO_BORDER && !isPow2(baseImageDesc.size.width)) ||
364 (samplerState.getWrapT() != GL_CLAMP_TO_EDGE &&
365 samplerState.getWrapT() != GL_CLAMP_TO_BORDER && !isPow2(baseImageDesc.size.height)))
366 {
367 return false;
368 }
369 }
370
371 if (IsMipmapSupported(mType) && IsMipmapFiltered(samplerState.getMinFilter()))
372 {
373 if (!npotSupport)
374 {
375 if (!isPow2(baseImageDesc.size.width) || !isPow2(baseImageDesc.size.height))
376 {
377 return false;
378 }
379 }
380
381 if (!computeMipmapCompleteness())
382 {
383 return false;
384 }
385 }
386 else
387 {
388 if (mType == TextureType::CubeMap && !isCubeComplete())
389 {
390 return false;
391 }
392 }
393
394 // From GL_OES_EGL_image_external_essl3: If state is present in a sampler object bound to a
395 // texture unit that would have been rejected by a call to TexParameter* for the texture bound
396 // to that unit, the behavior of the implementation is as if the texture were incomplete. For
397 // example, if TEXTURE_WRAP_S or TEXTURE_WRAP_T is set to anything but CLAMP_TO_EDGE on the
398 // sampler object bound to a texture unit and the texture bound to that unit is an external
399 // texture and EXT_EGL_image_external_wrap_modes is not enabled, the texture will be considered
400 // incomplete.
401 // Sampler object state which does not affect sampling for the type of texture bound
402 // to a texture unit, such as TEXTURE_WRAP_R for an external texture, does not affect
403 // completeness.
404 if (mType == TextureType::External)
405 {
406 if (!state.getExtensions().eglImageExternalWrapModesEXT)
407 {
408 if (samplerState.getWrapS() != GL_CLAMP_TO_EDGE ||
409 samplerState.getWrapT() != GL_CLAMP_TO_EDGE)
410 {
411 return false;
412 }
413 }
414
415 if (samplerState.getMinFilter() != GL_LINEAR && samplerState.getMinFilter() != GL_NEAREST)
416 {
417 return false;
418 }
419 }
420
421 // OpenGLES 3.0.2 spec section 3.8.13 states that a texture is not mipmap complete if:
422 // The internalformat specified for the texture arrays is a sized internal depth or
423 // depth and stencil format (see table 3.13), the value of TEXTURE_COMPARE_-
424 // MODE is NONE, and either the magnification filter is not NEAREST or the mini-
425 // fication filter is neither NEAREST nor NEAREST_MIPMAP_NEAREST.
426 if (!IsMultisampled(mType) && baseImageDesc.format.info->depthBits > 0 &&
427 state.getClientMajorVersion() >= 3)
428 {
429 // Note: we restrict this validation to sized types. For the OES_depth_textures
430 // extension, due to some underspecification problems, we must allow linear filtering
431 // for legacy compatibility with WebGL 1.
432 // See http://crbug.com/649200
433 if (samplerState.getCompareMode() == GL_NONE && baseImageDesc.format.info->sized)
434 {
435 if ((samplerState.getMinFilter() != GL_NEAREST &&
436 samplerState.getMinFilter() != GL_NEAREST_MIPMAP_NEAREST) ||
437 samplerState.getMagFilter() != GL_NEAREST)
438 {
439 return false;
440 }
441 }
442 }
443
444 // OpenGLES 3.1 spec section 8.16 states that a texture is not mipmap complete if:
445 // The internalformat specified for the texture is DEPTH_STENCIL format, the value of
446 // DEPTH_STENCIL_TEXTURE_MODE is STENCIL_INDEX, and either the magnification filter is
447 // not NEAREST or the minification filter is neither NEAREST nor NEAREST_MIPMAP_NEAREST.
448 // However, the ES 3.1 spec differs from the statement above, because it is incorrect.
449 // See the issue at https://github.com/KhronosGroup/OpenGL-API/issues/33.
450 // For multismaple texture, filter state of multisample texture is ignored(11.1.3.3).
451 // So it shouldn't be judged as incomplete texture. So, we ignore filtering for multisample
452 // texture completeness here.
453 if (!IsMultisampled(mType) && baseImageDesc.format.info->depthBits > 0 &&
454 mDepthStencilTextureMode == GL_STENCIL_INDEX)
455 {
456 if ((samplerState.getMinFilter() != GL_NEAREST &&
457 samplerState.getMinFilter() != GL_NEAREST_MIPMAP_NEAREST) ||
458 samplerState.getMagFilter() != GL_NEAREST)
459 {
460 return false;
461 }
462 }
463
464 return true;
465 }
466
computeMipmapCompleteness() const467 bool TextureState::computeMipmapCompleteness() const
468 {
469 const GLuint maxLevel = getMipmapMaxLevel();
470
471 for (GLuint level = getEffectiveBaseLevel(); level <= maxLevel; level++)
472 {
473 if (mType == TextureType::CubeMap)
474 {
475 for (TextureTarget face : AllCubeFaceTextureTargets())
476 {
477 if (!computeLevelCompleteness(face, level))
478 {
479 return false;
480 }
481 }
482 }
483 else
484 {
485 if (!computeLevelCompleteness(NonCubeTextureTypeToTarget(mType), level))
486 {
487 return false;
488 }
489 }
490 }
491
492 return true;
493 }
494
computeLevelCompleteness(TextureTarget target,size_t level) const495 bool TextureState::computeLevelCompleteness(TextureTarget target, size_t level) const
496 {
497 ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
498
499 if (mImmutableFormat)
500 {
501 return true;
502 }
503
504 const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), getEffectiveBaseLevel());
505 if (baseImageDesc.size.width == 0 || baseImageDesc.size.height == 0 ||
506 baseImageDesc.size.depth == 0)
507 {
508 return false;
509 }
510
511 const ImageDesc &levelImageDesc = getImageDesc(target, level);
512 if (levelImageDesc.size.width == 0 || levelImageDesc.size.height == 0 ||
513 levelImageDesc.size.depth == 0)
514 {
515 return false;
516 }
517
518 if (!Format::SameSized(levelImageDesc.format, baseImageDesc.format))
519 {
520 return false;
521 }
522
523 ASSERT(level >= getEffectiveBaseLevel());
524 const size_t relativeLevel = level - getEffectiveBaseLevel();
525 if (levelImageDesc.size.width != std::max(1, baseImageDesc.size.width >> relativeLevel))
526 {
527 return false;
528 }
529
530 if (levelImageDesc.size.height != std::max(1, baseImageDesc.size.height >> relativeLevel))
531 {
532 return false;
533 }
534
535 if (mType == TextureType::_3D)
536 {
537 if (levelImageDesc.size.depth != std::max(1, baseImageDesc.size.depth >> relativeLevel))
538 {
539 return false;
540 }
541 }
542 else if (IsArrayTextureType(mType))
543 {
544 if (levelImageDesc.size.depth != baseImageDesc.size.depth)
545 {
546 return false;
547 }
548 }
549
550 return true;
551 }
552
getBaseImageTarget() const553 TextureTarget TextureState::getBaseImageTarget() const
554 {
555 return mType == TextureType::CubeMap ? kCubeMapTextureTargetMin
556 : NonCubeTextureTypeToTarget(mType);
557 }
558
getEnabledLevelCount() const559 GLuint TextureState::getEnabledLevelCount() const
560 {
561 GLuint levelCount = 0;
562 const GLuint baseLevel = getEffectiveBaseLevel();
563 const GLuint maxLevel = std::min(getEffectiveMaxLevel(), getMipmapMaxLevel());
564
565 // The mip chain will have either one or more sequential levels, or max levels,
566 // but not a sparse one.
567 Optional<Extents> expectedSize;
568 for (size_t enabledLevel = baseLevel; enabledLevel <= maxLevel; ++enabledLevel, ++levelCount)
569 {
570 // Note: for cube textures, we only check the first face.
571 TextureTarget target = TextureTypeToTarget(mType, 0);
572 size_t descIndex = GetImageDescIndex(target, enabledLevel);
573 const Extents &levelSize = mImageDescs[descIndex].size;
574
575 if (levelSize.empty())
576 {
577 break;
578 }
579 if (expectedSize.valid())
580 {
581 Extents newSize = expectedSize.value();
582 newSize.width = std::max(1, newSize.width >> 1);
583 newSize.height = std::max(1, newSize.height >> 1);
584
585 if (!IsArrayTextureType(mType))
586 {
587 newSize.depth = std::max(1, newSize.depth >> 1);
588 }
589
590 if (newSize != levelSize)
591 {
592 break;
593 }
594 }
595 expectedSize = levelSize;
596 }
597
598 return levelCount;
599 }
600
ImageDesc()601 ImageDesc::ImageDesc()
602 : ImageDesc(Extents(0, 0, 0), Format::Invalid(), 0, GL_TRUE, InitState::Initialized)
603 {}
604
ImageDesc(const Extents & size,const Format & format,const InitState initState)605 ImageDesc::ImageDesc(const Extents &size, const Format &format, const InitState initState)
606 : size(size), format(format), samples(0), fixedSampleLocations(GL_TRUE), initState(initState)
607 {}
608
ImageDesc(const Extents & size,const Format & format,const GLsizei samples,const bool fixedSampleLocations,const InitState initState)609 ImageDesc::ImageDesc(const Extents &size,
610 const Format &format,
611 const GLsizei samples,
612 const bool fixedSampleLocations,
613 const InitState initState)
614 : size(size),
615 format(format),
616 samples(samples),
617 fixedSampleLocations(fixedSampleLocations),
618 initState(initState)
619 {}
620
getMemorySize() const621 GLint ImageDesc::getMemorySize() const
622 {
623 // Assume allocated size is around width * height * depth * samples * pixelBytes
624 angle::CheckedNumeric<GLint> levelSize = 1;
625 levelSize *= format.info->pixelBytes;
626 levelSize *= size.width;
627 levelSize *= size.height;
628 levelSize *= size.depth;
629 levelSize *= std::max(samples, 1);
630 return levelSize.ValueOrDefault(std::numeric_limits<GLint>::max());
631 }
632
getImageDesc(TextureTarget target,size_t level) const633 const ImageDesc &TextureState::getImageDesc(TextureTarget target, size_t level) const
634 {
635 size_t descIndex = GetImageDescIndex(target, level);
636 ASSERT(descIndex < mImageDescs.size());
637 return mImageDescs[descIndex];
638 }
639
setImageDesc(TextureTarget target,size_t level,const ImageDesc & desc)640 void TextureState::setImageDesc(TextureTarget target, size_t level, const ImageDesc &desc)
641 {
642 size_t descIndex = GetImageDescIndex(target, level);
643 ASSERT(descIndex < mImageDescs.size());
644 mImageDescs[descIndex] = desc;
645 if (desc.initState == InitState::MayNeedInit)
646 {
647 mInitState = InitState::MayNeedInit;
648 }
649 else
650 {
651 // Scan for any uninitialized images. If there are none, set the init state of the entire
652 // texture to initialized. The cost of the scan is only paid after doing image
653 // initialization which is already very expensive.
654 bool allImagesInitialized = true;
655
656 for (const ImageDesc &initDesc : mImageDescs)
657 {
658 if (initDesc.initState == InitState::MayNeedInit)
659 {
660 allImagesInitialized = false;
661 break;
662 }
663 }
664
665 if (allImagesInitialized)
666 {
667 mInitState = InitState::Initialized;
668 }
669 }
670 }
671
672 // Note that an ImageIndex that represents an entire level of a cube map corresponds to 6
673 // ImageDescs, so if the cube map is cube complete, we return the ImageDesc of the first cube
674 // face, and we don't allow using this function when the cube map is not cube complete.
getImageDesc(const ImageIndex & imageIndex) const675 const ImageDesc &TextureState::getImageDesc(const ImageIndex &imageIndex) const
676 {
677 if (imageIndex.isEntireLevelCubeMap())
678 {
679 ASSERT(isCubeComplete());
680 const GLint levelIndex = imageIndex.getLevelIndex();
681 return getImageDesc(kCubeMapTextureTargetMin, levelIndex);
682 }
683
684 return getImageDesc(imageIndex.getTarget(), imageIndex.getLevelIndex());
685 }
686
setImageDescChain(GLuint baseLevel,GLuint maxLevel,Extents baseSize,const Format & format,InitState initState)687 void TextureState::setImageDescChain(GLuint baseLevel,
688 GLuint maxLevel,
689 Extents baseSize,
690 const Format &format,
691 InitState initState)
692 {
693 for (GLuint level = baseLevel; level <= maxLevel; level++)
694 {
695 int relativeLevel = (level - baseLevel);
696 Extents levelSize(std::max<int>(baseSize.width >> relativeLevel, 1),
697 std::max<int>(baseSize.height >> relativeLevel, 1),
698 (IsArrayTextureType(mType))
699 ? baseSize.depth
700 : std::max<int>(baseSize.depth >> relativeLevel, 1));
701 ImageDesc levelInfo(levelSize, format, initState);
702
703 if (mType == TextureType::CubeMap)
704 {
705 for (TextureTarget face : AllCubeFaceTextureTargets())
706 {
707 setImageDesc(face, level, levelInfo);
708 }
709 }
710 else
711 {
712 setImageDesc(NonCubeTextureTypeToTarget(mType), level, levelInfo);
713 }
714 }
715 }
716
setImageDescChainMultisample(Extents baseSize,const Format & format,GLsizei samples,bool fixedSampleLocations,InitState initState)717 void TextureState::setImageDescChainMultisample(Extents baseSize,
718 const Format &format,
719 GLsizei samples,
720 bool fixedSampleLocations,
721 InitState initState)
722 {
723 ASSERT(mType == TextureType::_2DMultisample || mType == TextureType::_2DMultisampleArray);
724 ImageDesc levelInfo(baseSize, format, samples, fixedSampleLocations, initState);
725 setImageDesc(NonCubeTextureTypeToTarget(mType), 0, levelInfo);
726 }
727
clearImageDesc(TextureTarget target,size_t level)728 void TextureState::clearImageDesc(TextureTarget target, size_t level)
729 {
730 setImageDesc(target, level, ImageDesc());
731 }
732
clearImageDescs()733 void TextureState::clearImageDescs()
734 {
735 for (size_t descIndex = 0; descIndex < mImageDescs.size(); descIndex++)
736 {
737 mImageDescs[descIndex] = ImageDesc();
738 }
739 }
740
Texture(rx::GLImplFactory * factory,TextureID id,TextureType type)741 Texture::Texture(rx::GLImplFactory *factory, TextureID id, TextureType type)
742 : RefCountObject(factory->generateSerial(), id),
743 mState(type),
744 mTexture(factory->createTexture(mState)),
745 mImplObserver(this, rx::kTextureImageImplObserverMessageIndex),
746 mBufferObserver(this, kBufferSubjectIndex),
747 mBoundSurface(nullptr),
748 mBoundStream(nullptr)
749 {
750 mImplObserver.bind(mTexture);
751
752 // Initially assume the implementation is dirty.
753 mDirtyBits.set(DIRTY_BIT_IMPLEMENTATION);
754 }
755
onDestroy(const Context * context)756 void Texture::onDestroy(const Context *context)
757 {
758 if (mBoundSurface)
759 {
760 ANGLE_SWALLOW_ERR(mBoundSurface->releaseTexImage(context, EGL_BACK_BUFFER));
761 mBoundSurface = nullptr;
762 }
763 if (mBoundStream)
764 {
765 mBoundStream->releaseTextures();
766 mBoundStream = nullptr;
767 }
768
769 (void)(orphanImages(context));
770
771 mState.mBuffer.set(context, nullptr, 0, 0);
772
773 if (mTexture)
774 {
775 mTexture->onDestroy(context);
776 }
777 }
778
~Texture()779 Texture::~Texture()
780 {
781 SafeDelete(mTexture);
782 }
783
setLabel(const Context * context,const std::string & label)784 void Texture::setLabel(const Context *context, const std::string &label)
785 {
786 mState.mLabel = label;
787 signalDirtyState(DIRTY_BIT_LABEL);
788 }
789
getLabel() const790 const std::string &Texture::getLabel() const
791 {
792 return mState.mLabel;
793 }
794
setSwizzleRed(const Context * context,GLenum swizzleRed)795 void Texture::setSwizzleRed(const Context *context, GLenum swizzleRed)
796 {
797 mState.mSwizzleState.swizzleRed = swizzleRed;
798 signalDirtyState(DIRTY_BIT_SWIZZLE_RED);
799 }
800
getSwizzleRed() const801 GLenum Texture::getSwizzleRed() const
802 {
803 return mState.mSwizzleState.swizzleRed;
804 }
805
setSwizzleGreen(const Context * context,GLenum swizzleGreen)806 void Texture::setSwizzleGreen(const Context *context, GLenum swizzleGreen)
807 {
808 mState.mSwizzleState.swizzleGreen = swizzleGreen;
809 signalDirtyState(DIRTY_BIT_SWIZZLE_GREEN);
810 }
811
getSwizzleGreen() const812 GLenum Texture::getSwizzleGreen() const
813 {
814 return mState.mSwizzleState.swizzleGreen;
815 }
816
setSwizzleBlue(const Context * context,GLenum swizzleBlue)817 void Texture::setSwizzleBlue(const Context *context, GLenum swizzleBlue)
818 {
819 mState.mSwizzleState.swizzleBlue = swizzleBlue;
820 signalDirtyState(DIRTY_BIT_SWIZZLE_BLUE);
821 }
822
getSwizzleBlue() const823 GLenum Texture::getSwizzleBlue() const
824 {
825 return mState.mSwizzleState.swizzleBlue;
826 }
827
setSwizzleAlpha(const Context * context,GLenum swizzleAlpha)828 void Texture::setSwizzleAlpha(const Context *context, GLenum swizzleAlpha)
829 {
830 mState.mSwizzleState.swizzleAlpha = swizzleAlpha;
831 signalDirtyState(DIRTY_BIT_SWIZZLE_ALPHA);
832 }
833
getSwizzleAlpha() const834 GLenum Texture::getSwizzleAlpha() const
835 {
836 return mState.mSwizzleState.swizzleAlpha;
837 }
838
setMinFilter(const Context * context,GLenum minFilter)839 void Texture::setMinFilter(const Context *context, GLenum minFilter)
840 {
841 if (mState.mSamplerState.setMinFilter(minFilter))
842 {
843 signalDirtyState(DIRTY_BIT_MIN_FILTER);
844 }
845 }
846
getMinFilter() const847 GLenum Texture::getMinFilter() const
848 {
849 return mState.mSamplerState.getMinFilter();
850 }
851
setMagFilter(const Context * context,GLenum magFilter)852 void Texture::setMagFilter(const Context *context, GLenum magFilter)
853 {
854 if (mState.mSamplerState.setMagFilter(magFilter))
855 {
856 signalDirtyState(DIRTY_BIT_MAG_FILTER);
857 }
858 }
859
getMagFilter() const860 GLenum Texture::getMagFilter() const
861 {
862 return mState.mSamplerState.getMagFilter();
863 }
864
setWrapS(const Context * context,GLenum wrapS)865 void Texture::setWrapS(const Context *context, GLenum wrapS)
866 {
867 if (mState.mSamplerState.setWrapS(wrapS))
868 {
869 signalDirtyState(DIRTY_BIT_WRAP_S);
870 }
871 }
872
getWrapS() const873 GLenum Texture::getWrapS() const
874 {
875 return mState.mSamplerState.getWrapS();
876 }
877
setWrapT(const Context * context,GLenum wrapT)878 void Texture::setWrapT(const Context *context, GLenum wrapT)
879 {
880 if (mState.mSamplerState.getWrapT() == wrapT)
881 return;
882 if (mState.mSamplerState.setWrapT(wrapT))
883 {
884 signalDirtyState(DIRTY_BIT_WRAP_T);
885 }
886 }
887
getWrapT() const888 GLenum Texture::getWrapT() const
889 {
890 return mState.mSamplerState.getWrapT();
891 }
892
setWrapR(const Context * context,GLenum wrapR)893 void Texture::setWrapR(const Context *context, GLenum wrapR)
894 {
895 if (mState.mSamplerState.setWrapR(wrapR))
896 {
897 signalDirtyState(DIRTY_BIT_WRAP_R);
898 }
899 }
900
getWrapR() const901 GLenum Texture::getWrapR() const
902 {
903 return mState.mSamplerState.getWrapR();
904 }
905
setMaxAnisotropy(const Context * context,float maxAnisotropy)906 void Texture::setMaxAnisotropy(const Context *context, float maxAnisotropy)
907 {
908 if (mState.mSamplerState.setMaxAnisotropy(maxAnisotropy))
909 {
910 signalDirtyState(DIRTY_BIT_MAX_ANISOTROPY);
911 }
912 }
913
getMaxAnisotropy() const914 float Texture::getMaxAnisotropy() const
915 {
916 return mState.mSamplerState.getMaxAnisotropy();
917 }
918
setMinLod(const Context * context,GLfloat minLod)919 void Texture::setMinLod(const Context *context, GLfloat minLod)
920 {
921 if (mState.mSamplerState.setMinLod(minLod))
922 {
923 signalDirtyState(DIRTY_BIT_MIN_LOD);
924 }
925 }
926
getMinLod() const927 GLfloat Texture::getMinLod() const
928 {
929 return mState.mSamplerState.getMinLod();
930 }
931
setMaxLod(const Context * context,GLfloat maxLod)932 void Texture::setMaxLod(const Context *context, GLfloat maxLod)
933 {
934 if (mState.mSamplerState.setMaxLod(maxLod))
935 {
936 signalDirtyState(DIRTY_BIT_MAX_LOD);
937 }
938 }
939
getMaxLod() const940 GLfloat Texture::getMaxLod() const
941 {
942 return mState.mSamplerState.getMaxLod();
943 }
944
setCompareMode(const Context * context,GLenum compareMode)945 void Texture::setCompareMode(const Context *context, GLenum compareMode)
946 {
947 if (mState.mSamplerState.setCompareMode(compareMode))
948 {
949 signalDirtyState(DIRTY_BIT_COMPARE_MODE);
950 }
951 }
952
getCompareMode() const953 GLenum Texture::getCompareMode() const
954 {
955 return mState.mSamplerState.getCompareMode();
956 }
957
setCompareFunc(const Context * context,GLenum compareFunc)958 void Texture::setCompareFunc(const Context *context, GLenum compareFunc)
959 {
960 if (mState.mSamplerState.setCompareFunc(compareFunc))
961 {
962 signalDirtyState(DIRTY_BIT_COMPARE_FUNC);
963 }
964 }
965
getCompareFunc() const966 GLenum Texture::getCompareFunc() const
967 {
968 return mState.mSamplerState.getCompareFunc();
969 }
970
setSRGBDecode(const Context * context,GLenum sRGBDecode)971 void Texture::setSRGBDecode(const Context *context, GLenum sRGBDecode)
972 {
973 if (mState.mSamplerState.setSRGBDecode(sRGBDecode))
974 {
975 signalDirtyState(DIRTY_BIT_SRGB_DECODE);
976 }
977 }
978
getSRGBDecode() const979 GLenum Texture::getSRGBDecode() const
980 {
981 return mState.mSamplerState.getSRGBDecode();
982 }
983
setSRGBOverride(const Context * context,GLenum sRGBOverride)984 void Texture::setSRGBOverride(const Context *context, GLenum sRGBOverride)
985 {
986 SrgbOverride oldOverride = mState.mSrgbOverride;
987 mState.mSrgbOverride = (sRGBOverride == GL_SRGB) ? SrgbOverride::SRGB : SrgbOverride::Default;
988 if (mState.mSrgbOverride != oldOverride)
989 {
990 signalDirtyState(DIRTY_BIT_SRGB_OVERRIDE);
991 }
992 }
993
getSRGBOverride() const994 GLenum Texture::getSRGBOverride() const
995 {
996 return (mState.mSrgbOverride == SrgbOverride::SRGB) ? GL_SRGB : GL_NONE;
997 }
998
getSamplerState() const999 const SamplerState &Texture::getSamplerState() const
1000 {
1001 return mState.mSamplerState;
1002 }
1003
setBaseLevel(const Context * context,GLuint baseLevel)1004 angle::Result Texture::setBaseLevel(const Context *context, GLuint baseLevel)
1005 {
1006 if (mState.setBaseLevel(baseLevel))
1007 {
1008 ANGLE_TRY(mTexture->setBaseLevel(context, mState.getEffectiveBaseLevel()));
1009 signalDirtyState(DIRTY_BIT_BASE_LEVEL);
1010 }
1011
1012 return angle::Result::Continue;
1013 }
1014
getBaseLevel() const1015 GLuint Texture::getBaseLevel() const
1016 {
1017 return mState.mBaseLevel;
1018 }
1019
setMaxLevel(const Context * context,GLuint maxLevel)1020 void Texture::setMaxLevel(const Context *context, GLuint maxLevel)
1021 {
1022 if (mState.setMaxLevel(maxLevel))
1023 {
1024 signalDirtyState(DIRTY_BIT_MAX_LEVEL);
1025 }
1026 }
1027
getMaxLevel() const1028 GLuint Texture::getMaxLevel() const
1029 {
1030 return mState.mMaxLevel;
1031 }
1032
setDepthStencilTextureMode(const Context * context,GLenum mode)1033 void Texture::setDepthStencilTextureMode(const Context *context, GLenum mode)
1034 {
1035 if (mState.mDepthStencilTextureMode != mode)
1036 {
1037 mState.mDepthStencilTextureMode = mode;
1038 signalDirtyState(DIRTY_BIT_DEPTH_STENCIL_TEXTURE_MODE);
1039 }
1040 }
1041
getDepthStencilTextureMode() const1042 GLenum Texture::getDepthStencilTextureMode() const
1043 {
1044 return mState.mDepthStencilTextureMode;
1045 }
1046
getImmutableFormat() const1047 bool Texture::getImmutableFormat() const
1048 {
1049 return mState.mImmutableFormat;
1050 }
1051
getImmutableLevels() const1052 GLuint Texture::getImmutableLevels() const
1053 {
1054 return mState.mImmutableLevels;
1055 }
1056
setUsage(const Context * context,GLenum usage)1057 void Texture::setUsage(const Context *context, GLenum usage)
1058 {
1059 mState.mUsage = usage;
1060 signalDirtyState(DIRTY_BIT_USAGE);
1061 }
1062
getUsage() const1063 GLenum Texture::getUsage() const
1064 {
1065 return mState.mUsage;
1066 }
1067
getTextureState() const1068 const TextureState &Texture::getTextureState() const
1069 {
1070 return mState;
1071 }
1072
getExtents(TextureTarget target,size_t level) const1073 const Extents &Texture::getExtents(TextureTarget target, size_t level) const
1074 {
1075 ASSERT(TextureTargetToType(target) == mState.mType);
1076 return mState.getImageDesc(target, level).size;
1077 }
1078
getWidth(TextureTarget target,size_t level) const1079 size_t Texture::getWidth(TextureTarget target, size_t level) const
1080 {
1081 ASSERT(TextureTargetToType(target) == mState.mType);
1082 return mState.getImageDesc(target, level).size.width;
1083 }
1084
getHeight(TextureTarget target,size_t level) const1085 size_t Texture::getHeight(TextureTarget target, size_t level) const
1086 {
1087 ASSERT(TextureTargetToType(target) == mState.mType);
1088 return mState.getImageDesc(target, level).size.height;
1089 }
1090
getDepth(TextureTarget target,size_t level) const1091 size_t Texture::getDepth(TextureTarget target, size_t level) const
1092 {
1093 ASSERT(TextureTargetToType(target) == mState.mType);
1094 return mState.getImageDesc(target, level).size.depth;
1095 }
1096
getFormat(TextureTarget target,size_t level) const1097 const Format &Texture::getFormat(TextureTarget target, size_t level) const
1098 {
1099 ASSERT(TextureTargetToType(target) == mState.mType);
1100 return mState.getImageDesc(target, level).format;
1101 }
1102
getSamples(TextureTarget target,size_t level) const1103 GLsizei Texture::getSamples(TextureTarget target, size_t level) const
1104 {
1105 ASSERT(TextureTargetToType(target) == mState.mType);
1106 return mState.getImageDesc(target, level).samples;
1107 }
1108
getFixedSampleLocations(TextureTarget target,size_t level) const1109 bool Texture::getFixedSampleLocations(TextureTarget target, size_t level) const
1110 {
1111 ASSERT(TextureTargetToType(target) == mState.mType);
1112 return mState.getImageDesc(target, level).fixedSampleLocations;
1113 }
1114
getMipmapMaxLevel() const1115 GLuint Texture::getMipmapMaxLevel() const
1116 {
1117 return mState.getMipmapMaxLevel();
1118 }
1119
isMipmapComplete() const1120 bool Texture::isMipmapComplete() const
1121 {
1122 return mState.computeMipmapCompleteness();
1123 }
1124
getBoundSurface() const1125 egl::Surface *Texture::getBoundSurface() const
1126 {
1127 return mBoundSurface;
1128 }
1129
getBoundStream() const1130 egl::Stream *Texture::getBoundStream() const
1131 {
1132 return mBoundStream;
1133 }
1134
getMemorySize() const1135 GLint Texture::getMemorySize() const
1136 {
1137 GLint implSize = mTexture->getMemorySize();
1138 if (implSize > 0)
1139 {
1140 return implSize;
1141 }
1142
1143 angle::CheckedNumeric<GLint> size = 0;
1144 for (const ImageDesc &imageDesc : mState.mImageDescs)
1145 {
1146 size += imageDesc.getMemorySize();
1147 }
1148 return size.ValueOrDefault(std::numeric_limits<GLint>::max());
1149 }
1150
getLevelMemorySize(TextureTarget target,GLint level) const1151 GLint Texture::getLevelMemorySize(TextureTarget target, GLint level) const
1152 {
1153 GLint implSize = mTexture->getLevelMemorySize(target, level);
1154 if (implSize > 0)
1155 {
1156 return implSize;
1157 }
1158
1159 return mState.getImageDesc(target, level).getMemorySize();
1160 }
1161
signalDirtyStorage(InitState initState)1162 void Texture::signalDirtyStorage(InitState initState)
1163 {
1164 mState.mInitState = initState;
1165 invalidateCompletenessCache();
1166 mState.mCachedSamplerFormatValid = false;
1167 onStateChange(angle::SubjectMessage::SubjectChanged);
1168 }
1169
signalDirtyState(size_t dirtyBit)1170 void Texture::signalDirtyState(size_t dirtyBit)
1171 {
1172 mDirtyBits.set(dirtyBit);
1173 invalidateCompletenessCache();
1174 mState.mCachedSamplerFormatValid = false;
1175 onStateChange(angle::SubjectMessage::DirtyBitsFlagged);
1176 }
1177
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)1178 angle::Result Texture::setImage(Context *context,
1179 const PixelUnpackState &unpackState,
1180 Buffer *unpackBuffer,
1181 TextureTarget target,
1182 GLint level,
1183 GLenum internalFormat,
1184 const Extents &size,
1185 GLenum format,
1186 GLenum type,
1187 const uint8_t *pixels)
1188 {
1189 ASSERT(TextureTargetToType(target) == mState.mType);
1190
1191 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1192 ANGLE_TRY(releaseTexImageInternal(context));
1193 ANGLE_TRY(orphanImages(context));
1194
1195 ImageIndex index = ImageIndex::MakeFromTarget(target, level, size.depth);
1196
1197 ANGLE_TRY(mTexture->setImage(context, index, internalFormat, size, format, type, unpackState,
1198 unpackBuffer, pixels));
1199
1200 InitState initState = DetermineInitState(context, unpackBuffer, pixels);
1201 mState.setImageDesc(target, level, ImageDesc(size, Format(internalFormat, type), initState));
1202
1203 ANGLE_TRY(handleMipmapGenerationHint(context, level));
1204
1205 signalDirtyStorage(initState);
1206
1207 return angle::Result::Continue;
1208 }
1209
setSubImage(Context * context,const PixelUnpackState & unpackState,Buffer * unpackBuffer,TextureTarget target,GLint level,const Box & area,GLenum format,GLenum type,const uint8_t * pixels)1210 angle::Result Texture::setSubImage(Context *context,
1211 const PixelUnpackState &unpackState,
1212 Buffer *unpackBuffer,
1213 TextureTarget target,
1214 GLint level,
1215 const Box &area,
1216 GLenum format,
1217 GLenum type,
1218 const uint8_t *pixels)
1219 {
1220 ASSERT(TextureTargetToType(target) == mState.mType);
1221
1222 ImageIndex index = ImageIndex::MakeFromTarget(target, level, area.depth);
1223 ANGLE_TRY(ensureSubImageInitialized(context, index, area));
1224
1225 ANGLE_TRY(mTexture->setSubImage(context, index, area, format, type, unpackState, unpackBuffer,
1226 pixels));
1227
1228 ANGLE_TRY(handleMipmapGenerationHint(context, level));
1229
1230 onStateChange(angle::SubjectMessage::ContentsChanged);
1231
1232 return angle::Result::Continue;
1233 }
1234
setCompressedImage(Context * context,const PixelUnpackState & unpackState,TextureTarget target,GLint level,GLenum internalFormat,const Extents & size,size_t imageSize,const uint8_t * pixels)1235 angle::Result Texture::setCompressedImage(Context *context,
1236 const PixelUnpackState &unpackState,
1237 TextureTarget target,
1238 GLint level,
1239 GLenum internalFormat,
1240 const Extents &size,
1241 size_t imageSize,
1242 const uint8_t *pixels)
1243 {
1244 ASSERT(TextureTargetToType(target) == mState.mType);
1245
1246 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1247 ANGLE_TRY(releaseTexImageInternal(context));
1248 ANGLE_TRY(orphanImages(context));
1249
1250 ImageIndex index = ImageIndex::MakeFromTarget(target, level, size.depth);
1251
1252 ANGLE_TRY(mTexture->setCompressedImage(context, index, internalFormat, size, unpackState,
1253 imageSize, pixels));
1254
1255 Buffer *unpackBuffer = context->getState().getTargetBuffer(BufferBinding::PixelUnpack);
1256
1257 InitState initState = DetermineInitState(context, unpackBuffer, pixels);
1258 mState.setImageDesc(target, level, ImageDesc(size, Format(internalFormat), initState));
1259 signalDirtyStorage(initState);
1260
1261 return angle::Result::Continue;
1262 }
1263
setCompressedSubImage(const Context * context,const PixelUnpackState & unpackState,TextureTarget target,GLint level,const Box & area,GLenum format,size_t imageSize,const uint8_t * pixels)1264 angle::Result Texture::setCompressedSubImage(const Context *context,
1265 const PixelUnpackState &unpackState,
1266 TextureTarget target,
1267 GLint level,
1268 const Box &area,
1269 GLenum format,
1270 size_t imageSize,
1271 const uint8_t *pixels)
1272 {
1273 ASSERT(TextureTargetToType(target) == mState.mType);
1274
1275 ImageIndex index = ImageIndex::MakeFromTarget(target, level, area.depth);
1276 ANGLE_TRY(ensureSubImageInitialized(context, index, area));
1277
1278 ANGLE_TRY(mTexture->setCompressedSubImage(context, index, area, format, unpackState, imageSize,
1279 pixels));
1280
1281 onStateChange(angle::SubjectMessage::ContentsChanged);
1282
1283 return angle::Result::Continue;
1284 }
1285
copyImage(Context * context,TextureTarget target,GLint level,const Rectangle & sourceArea,GLenum internalFormat,Framebuffer * source)1286 angle::Result Texture::copyImage(Context *context,
1287 TextureTarget target,
1288 GLint level,
1289 const Rectangle &sourceArea,
1290 GLenum internalFormat,
1291 Framebuffer *source)
1292 {
1293 ASSERT(TextureTargetToType(target) == mState.mType);
1294
1295 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1296 ANGLE_TRY(releaseTexImageInternal(context));
1297 ANGLE_TRY(orphanImages(context));
1298
1299 ImageIndex index = ImageIndex::MakeFromTarget(target, level, 1);
1300
1301 const InternalFormat &internalFormatInfo =
1302 GetInternalFormatInfo(internalFormat, GL_UNSIGNED_BYTE);
1303
1304 // Most if not all renderers clip these copies to the size of the source framebuffer, leaving
1305 // other pixels untouched. For safety in robust resource initialization, assume that that
1306 // clipping is going to occur when computing the region for which to ensure initialization. If
1307 // the copy lies entirely off the source framebuffer, initialize as though a zero-size box is
1308 // going to be set during the copy operation.
1309 Box destBox;
1310 bool forceCopySubImage = false;
1311 if (context->isRobustResourceInitEnabled())
1312 {
1313 const FramebufferAttachment *sourceReadAttachment = source->getReadColorAttachment();
1314 Extents fbSize = sourceReadAttachment->getSize();
1315 // Force using copySubImage when the source area is out of bounds AND
1316 // we're not copying to and from the same texture
1317 forceCopySubImage = ((sourceArea.x < 0) || (sourceArea.y < 0) ||
1318 ((sourceArea.x + sourceArea.width) > fbSize.width) ||
1319 ((sourceArea.y + sourceArea.height) > fbSize.height)) &&
1320 (sourceReadAttachment->getResource() != this);
1321 Rectangle clippedArea;
1322 if (ClipRectangle(sourceArea, Rectangle(0, 0, fbSize.width, fbSize.height), &clippedArea))
1323 {
1324 const Offset clippedOffset(clippedArea.x - sourceArea.x, clippedArea.y - sourceArea.y,
1325 0);
1326 destBox = Box(clippedOffset.x, clippedOffset.y, clippedOffset.z, clippedArea.width,
1327 clippedArea.height, 1);
1328 }
1329 }
1330
1331 // If we need to initialize the destination texture we split the call into a create call,
1332 // an initializeContents call, and then a copySubImage call. This ensures the destination
1333 // texture exists before we try to clear it.
1334 Extents size(sourceArea.width, sourceArea.height, 1);
1335 if (forceCopySubImage || doesSubImageNeedInit(context, index, destBox))
1336 {
1337 ANGLE_TRY(mTexture->setImage(context, index, internalFormat, size,
1338 internalFormatInfo.format, internalFormatInfo.type,
1339 PixelUnpackState(), nullptr, nullptr));
1340 mState.setImageDesc(target, level,
1341 ImageDesc(size, Format(internalFormatInfo), InitState::MayNeedInit));
1342 ANGLE_TRY(ensureSubImageInitialized(context, index, destBox));
1343 ANGLE_TRY(mTexture->copySubImage(context, index, Offset(), sourceArea, source));
1344 }
1345 else
1346 {
1347 ANGLE_TRY(mTexture->copyImage(context, index, sourceArea, internalFormat, source));
1348 }
1349
1350 mState.setImageDesc(target, level,
1351 ImageDesc(size, Format(internalFormatInfo), InitState::Initialized));
1352
1353 ANGLE_TRY(handleMipmapGenerationHint(context, level));
1354
1355 // Because this could affect the texture storage we might need to init other layers/levels.
1356 signalDirtyStorage(InitState::MayNeedInit);
1357
1358 return angle::Result::Continue;
1359 }
1360
copySubImage(Context * context,const ImageIndex & index,const Offset & destOffset,const Rectangle & sourceArea,Framebuffer * source)1361 angle::Result Texture::copySubImage(Context *context,
1362 const ImageIndex &index,
1363 const Offset &destOffset,
1364 const Rectangle &sourceArea,
1365 Framebuffer *source)
1366 {
1367 ASSERT(TextureTargetToType(index.getTarget()) == mState.mType);
1368
1369 // Most if not all renderers clip these copies to the size of the source framebuffer, leaving
1370 // other pixels untouched. For safety in robust resource initialization, assume that that
1371 // clipping is going to occur when computing the region for which to ensure initialization. If
1372 // the copy lies entirely off the source framebuffer, initialize as though a zero-size box is
1373 // going to be set during the copy operation. Note that this assumes that
1374 // ensureSubImageInitialized ensures initialization of the entire destination texture, and not
1375 // just a sub-region.
1376 Box destBox;
1377 if (context->isRobustResourceInitEnabled())
1378 {
1379 Extents fbSize = source->getReadColorAttachment()->getSize();
1380 Rectangle clippedArea;
1381 if (ClipRectangle(sourceArea, Rectangle(0, 0, fbSize.width, fbSize.height), &clippedArea))
1382 {
1383 const Offset clippedOffset(destOffset.x + clippedArea.x - sourceArea.x,
1384 destOffset.y + clippedArea.y - sourceArea.y, 0);
1385 destBox = Box(clippedOffset.x, clippedOffset.y, clippedOffset.z, clippedArea.width,
1386 clippedArea.height, 1);
1387 }
1388 }
1389
1390 ANGLE_TRY(ensureSubImageInitialized(context, index, destBox));
1391
1392 ANGLE_TRY(mTexture->copySubImage(context, index, destOffset, sourceArea, source));
1393 ANGLE_TRY(handleMipmapGenerationHint(context, index.getLevelIndex()));
1394
1395 onStateChange(angle::SubjectMessage::ContentsChanged);
1396
1397 return angle::Result::Continue;
1398 }
1399
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)1400 angle::Result Texture::copyRenderbufferSubData(Context *context,
1401 const gl::Renderbuffer *srcBuffer,
1402 GLint srcLevel,
1403 GLint srcX,
1404 GLint srcY,
1405 GLint srcZ,
1406 GLint dstLevel,
1407 GLint dstX,
1408 GLint dstY,
1409 GLint dstZ,
1410 GLsizei srcWidth,
1411 GLsizei srcHeight,
1412 GLsizei srcDepth)
1413 {
1414 ANGLE_TRY(mTexture->copyRenderbufferSubData(context, srcBuffer, srcLevel, srcX, srcY, srcZ,
1415 dstLevel, dstX, dstY, dstZ, srcWidth, srcHeight,
1416 srcDepth));
1417
1418 signalDirtyStorage(InitState::Initialized);
1419
1420 return angle::Result::Continue;
1421 }
1422
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)1423 angle::Result Texture::copyTextureSubData(Context *context,
1424 const gl::Texture *srcTexture,
1425 GLint srcLevel,
1426 GLint srcX,
1427 GLint srcY,
1428 GLint srcZ,
1429 GLint dstLevel,
1430 GLint dstX,
1431 GLint dstY,
1432 GLint dstZ,
1433 GLsizei srcWidth,
1434 GLsizei srcHeight,
1435 GLsizei srcDepth)
1436 {
1437 ANGLE_TRY(mTexture->copyTextureSubData(context, srcTexture, srcLevel, srcX, srcY, srcZ,
1438 dstLevel, dstX, dstY, dstZ, srcWidth, srcHeight,
1439 srcDepth));
1440
1441 signalDirtyStorage(InitState::Initialized);
1442
1443 return angle::Result::Continue;
1444 }
1445
copyTexture(Context * context,TextureTarget target,GLint level,GLenum internalFormat,GLenum type,GLint sourceLevel,bool unpackFlipY,bool unpackPremultiplyAlpha,bool unpackUnmultiplyAlpha,Texture * source)1446 angle::Result Texture::copyTexture(Context *context,
1447 TextureTarget target,
1448 GLint level,
1449 GLenum internalFormat,
1450 GLenum type,
1451 GLint sourceLevel,
1452 bool unpackFlipY,
1453 bool unpackPremultiplyAlpha,
1454 bool unpackUnmultiplyAlpha,
1455 Texture *source)
1456 {
1457 ASSERT(TextureTargetToType(target) == mState.mType);
1458 ASSERT(source->getType() != TextureType::CubeMap);
1459
1460 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1461 ANGLE_TRY(releaseTexImageInternal(context));
1462 ANGLE_TRY(orphanImages(context));
1463
1464 // Initialize source texture.
1465 // Note: we don't have a way to notify which portions of the image changed currently.
1466 ANGLE_TRY(source->ensureInitialized(context));
1467
1468 ImageIndex index = ImageIndex::MakeFromTarget(target, level, ImageIndex::kEntireLevel);
1469
1470 ANGLE_TRY(mTexture->copyTexture(context, index, internalFormat, type, sourceLevel, unpackFlipY,
1471 unpackPremultiplyAlpha, unpackUnmultiplyAlpha, source));
1472
1473 const auto &sourceDesc =
1474 source->mState.getImageDesc(NonCubeTextureTypeToTarget(source->getType()), sourceLevel);
1475 const InternalFormat &internalFormatInfo = GetInternalFormatInfo(internalFormat, type);
1476 mState.setImageDesc(
1477 target, level,
1478 ImageDesc(sourceDesc.size, Format(internalFormatInfo), InitState::Initialized));
1479
1480 signalDirtyStorage(InitState::Initialized);
1481
1482 return angle::Result::Continue;
1483 }
1484
copySubTexture(const Context * context,TextureTarget target,GLint level,const Offset & destOffset,GLint sourceLevel,const Box & sourceBox,bool unpackFlipY,bool unpackPremultiplyAlpha,bool unpackUnmultiplyAlpha,Texture * source)1485 angle::Result Texture::copySubTexture(const Context *context,
1486 TextureTarget target,
1487 GLint level,
1488 const Offset &destOffset,
1489 GLint sourceLevel,
1490 const Box &sourceBox,
1491 bool unpackFlipY,
1492 bool unpackPremultiplyAlpha,
1493 bool unpackUnmultiplyAlpha,
1494 Texture *source)
1495 {
1496 ASSERT(TextureTargetToType(target) == mState.mType);
1497
1498 // Ensure source is initialized.
1499 ANGLE_TRY(source->ensureInitialized(context));
1500
1501 Box destBox(destOffset.x, destOffset.y, destOffset.z, sourceBox.width, sourceBox.height,
1502 sourceBox.depth);
1503 ImageIndex index = ImageIndex::MakeFromTarget(target, level, sourceBox.depth);
1504 ANGLE_TRY(ensureSubImageInitialized(context, index, destBox));
1505
1506 ANGLE_TRY(mTexture->copySubTexture(context, index, destOffset, sourceLevel, sourceBox,
1507 unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha,
1508 source));
1509
1510 onStateChange(angle::SubjectMessage::ContentsChanged);
1511
1512 return angle::Result::Continue;
1513 }
1514
copyCompressedTexture(Context * context,const Texture * source)1515 angle::Result Texture::copyCompressedTexture(Context *context, const Texture *source)
1516 {
1517 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1518 ANGLE_TRY(releaseTexImageInternal(context));
1519 ANGLE_TRY(orphanImages(context));
1520
1521 ANGLE_TRY(mTexture->copyCompressedTexture(context, source));
1522
1523 ASSERT(source->getType() != TextureType::CubeMap && getType() != TextureType::CubeMap);
1524 const auto &sourceDesc =
1525 source->mState.getImageDesc(NonCubeTextureTypeToTarget(source->getType()), 0);
1526 mState.setImageDesc(NonCubeTextureTypeToTarget(getType()), 0, sourceDesc);
1527
1528 return angle::Result::Continue;
1529 }
1530
setStorage(Context * context,TextureType type,GLsizei levels,GLenum internalFormat,const Extents & size)1531 angle::Result Texture::setStorage(Context *context,
1532 TextureType type,
1533 GLsizei levels,
1534 GLenum internalFormat,
1535 const Extents &size)
1536 {
1537 ASSERT(type == mState.mType);
1538
1539 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1540 ANGLE_TRY(releaseTexImageInternal(context));
1541 ANGLE_TRY(orphanImages(context));
1542
1543 mState.mImmutableFormat = true;
1544 mState.mImmutableLevels = static_cast<GLuint>(levels);
1545 mState.clearImageDescs();
1546 mState.setImageDescChain(0, static_cast<GLuint>(levels - 1), size, Format(internalFormat),
1547 InitState::MayNeedInit);
1548
1549 ANGLE_TRY(mTexture->setStorage(context, type, levels, internalFormat, size));
1550
1551 // Changing the texture to immutable can trigger a change in the base and max levels:
1552 // GLES 3.0.4 section 3.8.10 pg 158:
1553 // "For immutable-format textures, levelbase is clamped to the range[0;levels],levelmax is then
1554 // clamped to the range[levelbase;levels].
1555 mDirtyBits.set(DIRTY_BIT_BASE_LEVEL);
1556 mDirtyBits.set(DIRTY_BIT_MAX_LEVEL);
1557
1558 signalDirtyStorage(InitState::MayNeedInit);
1559
1560 return angle::Result::Continue;
1561 }
1562
setImageExternal(Context * context,TextureTarget target,GLint level,GLenum internalFormat,const Extents & size,GLenum format,GLenum type)1563 angle::Result Texture::setImageExternal(Context *context,
1564 TextureTarget target,
1565 GLint level,
1566 GLenum internalFormat,
1567 const Extents &size,
1568 GLenum format,
1569 GLenum type)
1570 {
1571 ASSERT(TextureTargetToType(target) == mState.mType);
1572
1573 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1574 ANGLE_TRY(releaseTexImageInternal(context));
1575 ANGLE_TRY(orphanImages(context));
1576
1577 ImageIndex index = ImageIndex::MakeFromTarget(target, level, size.depth);
1578
1579 ANGLE_TRY(mTexture->setImageExternal(context, index, internalFormat, size, format, type));
1580
1581 InitState initState = InitState::Initialized;
1582 mState.setImageDesc(target, level, ImageDesc(size, Format(internalFormat, type), initState));
1583
1584 ANGLE_TRY(handleMipmapGenerationHint(context, level));
1585
1586 signalDirtyStorage(initState);
1587
1588 return angle::Result::Continue;
1589 }
1590
setStorageMultisample(Context * context,TextureType type,GLsizei samplesIn,GLint internalFormat,const Extents & size,bool fixedSampleLocations)1591 angle::Result Texture::setStorageMultisample(Context *context,
1592 TextureType type,
1593 GLsizei samplesIn,
1594 GLint internalFormat,
1595 const Extents &size,
1596 bool fixedSampleLocations)
1597 {
1598 ASSERT(type == mState.mType);
1599
1600 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1601 ANGLE_TRY(releaseTexImageInternal(context));
1602 ANGLE_TRY(orphanImages(context));
1603
1604 // Potentially adjust "samples" to a supported value
1605 const TextureCaps &formatCaps = context->getTextureCaps().get(internalFormat);
1606 GLsizei samples = formatCaps.getNearestSamples(samplesIn);
1607
1608 mState.mImmutableFormat = true;
1609 mState.mImmutableLevels = static_cast<GLuint>(1);
1610 mState.clearImageDescs();
1611 mState.setImageDescChainMultisample(size, Format(internalFormat), samples, fixedSampleLocations,
1612 InitState::MayNeedInit);
1613
1614 ANGLE_TRY(mTexture->setStorageMultisample(context, type, samples, internalFormat, size,
1615 fixedSampleLocations));
1616
1617 signalDirtyStorage(InitState::MayNeedInit);
1618
1619 return angle::Result::Continue;
1620 }
1621
setStorageExternalMemory(Context * context,TextureType type,GLsizei levels,GLenum internalFormat,const Extents & size,MemoryObject * memoryObject,GLuint64 offset,GLbitfield createFlags,GLbitfield usageFlags)1622 angle::Result Texture::setStorageExternalMemory(Context *context,
1623 TextureType type,
1624 GLsizei levels,
1625 GLenum internalFormat,
1626 const Extents &size,
1627 MemoryObject *memoryObject,
1628 GLuint64 offset,
1629 GLbitfield createFlags,
1630 GLbitfield usageFlags)
1631 {
1632 ASSERT(type == mState.mType);
1633
1634 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1635 ANGLE_TRY(releaseTexImageInternal(context));
1636 ANGLE_TRY(orphanImages(context));
1637
1638 ANGLE_TRY(mTexture->setStorageExternalMemory(context, type, levels, internalFormat, size,
1639 memoryObject, offset, createFlags, usageFlags));
1640
1641 mState.mImmutableFormat = true;
1642 mState.mImmutableLevels = static_cast<GLuint>(levels);
1643 mState.clearImageDescs();
1644 mState.setImageDescChain(0, static_cast<GLuint>(levels - 1), size, Format(internalFormat),
1645 InitState::MayNeedInit);
1646
1647 // Changing the texture to immutable can trigger a change in the base and max levels:
1648 // GLES 3.0.4 section 3.8.10 pg 158:
1649 // "For immutable-format textures, levelbase is clamped to the range[0;levels],levelmax is then
1650 // clamped to the range[levelbase;levels].
1651 mDirtyBits.set(DIRTY_BIT_BASE_LEVEL);
1652 mDirtyBits.set(DIRTY_BIT_MAX_LEVEL);
1653
1654 signalDirtyStorage(InitState::Initialized);
1655
1656 return angle::Result::Continue;
1657 }
1658
generateMipmap(Context * context)1659 angle::Result Texture::generateMipmap(Context *context)
1660 {
1661 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1662 ANGLE_TRY(releaseTexImageInternal(context));
1663
1664 // EGL_KHR_gl_image states that images are only orphaned when generating mipmaps if the texture
1665 // is not mip complete.
1666 if (!isMipmapComplete())
1667 {
1668 ANGLE_TRY(orphanImages(context));
1669 }
1670
1671 const GLuint baseLevel = mState.getEffectiveBaseLevel();
1672 const GLuint maxLevel = mState.getMipmapMaxLevel();
1673
1674 if (maxLevel <= baseLevel)
1675 {
1676 return angle::Result::Continue;
1677 }
1678
1679 // If any dimension is zero, this is a no-op:
1680 //
1681 // > Otherwise, if level_base is not defined, or if any dimension is zero, all mipmap levels are
1682 // > left unchanged. This is not an error.
1683 const ImageDesc &baseImageInfo = mState.getImageDesc(mState.getBaseImageTarget(), baseLevel);
1684 if (baseImageInfo.size.empty())
1685 {
1686 return angle::Result::Continue;
1687 }
1688
1689 ANGLE_TRY(syncState(context, Command::GenerateMipmap));
1690
1691 // Clear the base image(s) immediately if needed
1692 if (context->isRobustResourceInitEnabled())
1693 {
1694 ImageIndexIterator it =
1695 ImageIndexIterator::MakeGeneric(mState.mType, baseLevel, baseLevel + 1,
1696 ImageIndex::kEntireLevel, ImageIndex::kEntireLevel);
1697 while (it.hasNext())
1698 {
1699 const ImageIndex index = it.next();
1700 const ImageDesc &desc = mState.getImageDesc(index.getTarget(), index.getLevelIndex());
1701
1702 if (desc.initState == InitState::MayNeedInit)
1703 {
1704 ANGLE_TRY(initializeContents(context, index));
1705 }
1706 }
1707 }
1708
1709 ANGLE_TRY(mTexture->generateMipmap(context));
1710
1711 // Propagate the format and size of the base mip to the smaller ones. Cube maps are guaranteed
1712 // to have faces of the same size and format so any faces can be picked.
1713 mState.setImageDescChain(baseLevel, maxLevel, baseImageInfo.size, baseImageInfo.format,
1714 InitState::Initialized);
1715
1716 signalDirtyStorage(InitState::Initialized);
1717
1718 return angle::Result::Continue;
1719 }
1720
bindTexImageFromSurface(Context * context,egl::Surface * surface)1721 angle::Result Texture::bindTexImageFromSurface(Context *context, egl::Surface *surface)
1722 {
1723 ASSERT(surface);
1724
1725 if (mBoundSurface)
1726 {
1727 ANGLE_TRY(releaseTexImageFromSurface(context));
1728 }
1729
1730 ANGLE_TRY(mTexture->bindTexImage(context, surface));
1731 mBoundSurface = surface;
1732
1733 // Set the image info to the size and format of the surface
1734 ASSERT(mState.mType == TextureType::_2D || mState.mType == TextureType::Rectangle);
1735 Extents size(surface->getWidth(), surface->getHeight(), 1);
1736 ImageDesc desc(size, surface->getBindTexImageFormat(), InitState::Initialized);
1737 mState.setImageDesc(NonCubeTextureTypeToTarget(mState.mType), 0, desc);
1738 signalDirtyStorage(InitState::Initialized);
1739 return angle::Result::Continue;
1740 }
1741
releaseTexImageFromSurface(const Context * context)1742 angle::Result Texture::releaseTexImageFromSurface(const Context *context)
1743 {
1744 ASSERT(mBoundSurface);
1745 mBoundSurface = nullptr;
1746 ANGLE_TRY(mTexture->releaseTexImage(context));
1747
1748 // Erase the image info for level 0
1749 ASSERT(mState.mType == TextureType::_2D || mState.mType == TextureType::Rectangle);
1750 mState.clearImageDesc(NonCubeTextureTypeToTarget(mState.mType), 0);
1751 signalDirtyStorage(InitState::Initialized);
1752 return angle::Result::Continue;
1753 }
1754
bindStream(egl::Stream * stream)1755 void Texture::bindStream(egl::Stream *stream)
1756 {
1757 ASSERT(stream);
1758
1759 // It should not be possible to bind a texture already bound to another stream
1760 ASSERT(mBoundStream == nullptr);
1761
1762 mBoundStream = stream;
1763
1764 ASSERT(mState.mType == TextureType::External);
1765 }
1766
releaseStream()1767 void Texture::releaseStream()
1768 {
1769 ASSERT(mBoundStream);
1770 mBoundStream = nullptr;
1771 }
1772
acquireImageFromStream(const Context * context,const egl::Stream::GLTextureDescription & desc)1773 angle::Result Texture::acquireImageFromStream(const Context *context,
1774 const egl::Stream::GLTextureDescription &desc)
1775 {
1776 ASSERT(mBoundStream != nullptr);
1777 ANGLE_TRY(mTexture->setImageExternal(context, mState.mType, mBoundStream, desc));
1778
1779 Extents size(desc.width, desc.height, 1);
1780 mState.setImageDesc(NonCubeTextureTypeToTarget(mState.mType), 0,
1781 ImageDesc(size, Format(desc.internalFormat), InitState::Initialized));
1782 signalDirtyStorage(InitState::Initialized);
1783 return angle::Result::Continue;
1784 }
1785
releaseImageFromStream(const Context * context)1786 angle::Result Texture::releaseImageFromStream(const Context *context)
1787 {
1788 ASSERT(mBoundStream != nullptr);
1789 ANGLE_TRY(mTexture->setImageExternal(context, mState.mType, nullptr,
1790 egl::Stream::GLTextureDescription()));
1791
1792 // Set to incomplete
1793 mState.clearImageDesc(NonCubeTextureTypeToTarget(mState.mType), 0);
1794 signalDirtyStorage(InitState::Initialized);
1795 return angle::Result::Continue;
1796 }
1797
releaseTexImageInternal(Context * context)1798 angle::Result Texture::releaseTexImageInternal(Context *context)
1799 {
1800 if (mBoundSurface)
1801 {
1802 // Notify the surface
1803 egl::Error eglErr = mBoundSurface->releaseTexImageFromTexture(context);
1804 // TODO(jmadill): Remove this once refactor is complete. http://anglebug.com/3041
1805 if (eglErr.isError())
1806 {
1807 context->handleError(GL_INVALID_OPERATION, "Error releasing tex image from texture",
1808 __FILE__, ANGLE_FUNCTION, __LINE__);
1809 }
1810
1811 // Then, call the same method as from the surface
1812 ANGLE_TRY(releaseTexImageFromSurface(context));
1813 }
1814 return angle::Result::Continue;
1815 }
1816
setEGLImageTarget(Context * context,TextureType type,egl::Image * imageTarget)1817 angle::Result Texture::setEGLImageTarget(Context *context,
1818 TextureType type,
1819 egl::Image *imageTarget)
1820 {
1821 ASSERT(type == mState.mType);
1822 ASSERT(type == TextureType::_2D || type == TextureType::External ||
1823 type == TextureType::_2DArray);
1824
1825 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1826 ANGLE_TRY(releaseTexImageInternal(context));
1827 ANGLE_TRY(orphanImages(context));
1828
1829 ANGLE_TRY(mTexture->setEGLImageTarget(context, type, imageTarget));
1830
1831 setTargetImage(context, imageTarget);
1832
1833 Extents size(static_cast<int>(imageTarget->getWidth()),
1834 static_cast<int>(imageTarget->getHeight()), 1);
1835
1836 auto initState = imageTarget->sourceInitState();
1837
1838 mState.clearImageDescs();
1839 mState.setImageDesc(NonCubeTextureTypeToTarget(type), 0,
1840 ImageDesc(size, imageTarget->getFormat(), initState));
1841 signalDirtyStorage(initState);
1842
1843 return angle::Result::Continue;
1844 }
1845
getAttachmentSize(const ImageIndex & imageIndex) const1846 Extents Texture::getAttachmentSize(const ImageIndex &imageIndex) const
1847 {
1848 // As an ImageIndex that represents an entire level of a cube map corresponds to 6 ImageDescs,
1849 // we only allow querying ImageDesc on a complete cube map, and this ImageDesc is exactly the
1850 // one that belongs to the first face of the cube map.
1851 if (imageIndex.isEntireLevelCubeMap())
1852 {
1853 // A cube map texture is cube complete if the following conditions all hold true:
1854 // - The levelbase arrays of each of the six texture images making up the cube map have
1855 // identical, positive, and square dimensions.
1856 if (!mState.isCubeComplete())
1857 {
1858 return Extents();
1859 }
1860 }
1861
1862 return mState.getImageDesc(imageIndex).size;
1863 }
1864
getAttachmentFormat(GLenum,const ImageIndex & imageIndex) const1865 Format Texture::getAttachmentFormat(GLenum /*binding*/, const ImageIndex &imageIndex) const
1866 {
1867 // As an ImageIndex that represents an entire level of a cube map corresponds to 6 ImageDescs,
1868 // we only allow querying ImageDesc on a complete cube map, and this ImageDesc is exactly the
1869 // one that belongs to the first face of the cube map.
1870 if (imageIndex.isEntireLevelCubeMap())
1871 {
1872 // A cube map texture is cube complete if the following conditions all hold true:
1873 // - The levelbase arrays were each specified with the same effective internal format.
1874 if (!mState.isCubeComplete())
1875 {
1876 return Format::Invalid();
1877 }
1878 }
1879 return mState.getImageDesc(imageIndex).format;
1880 }
1881
getAttachmentSamples(const ImageIndex & imageIndex) const1882 GLsizei Texture::getAttachmentSamples(const ImageIndex &imageIndex) const
1883 {
1884 // We do not allow querying TextureTarget by an ImageIndex that represents an entire level of a
1885 // cube map (See comments in function TextureTypeToTarget() in ImageIndex.cpp).
1886 if (imageIndex.isEntireLevelCubeMap())
1887 {
1888 return 0;
1889 }
1890
1891 return getSamples(imageIndex.getTarget(), imageIndex.getLevelIndex());
1892 }
1893
isRenderable(const Context * context,GLenum binding,const ImageIndex & imageIndex) const1894 bool Texture::isRenderable(const Context *context,
1895 GLenum binding,
1896 const ImageIndex &imageIndex) const
1897 {
1898 if (isEGLImageTarget())
1899 {
1900 return ImageSibling::isRenderable(context, binding, imageIndex);
1901 }
1902
1903 // Surfaces bound to textures are always renderable. This avoids issues with surfaces with ES3+
1904 // formats not being renderable when bound to textures in ES2 contexts.
1905 if (mBoundSurface)
1906 {
1907 return true;
1908 }
1909
1910 return getAttachmentFormat(binding, imageIndex)
1911 .info->textureAttachmentSupport(context->getClientVersion(), context->getExtensions());
1912 }
1913
getAttachmentFixedSampleLocations(const ImageIndex & imageIndex) const1914 bool Texture::getAttachmentFixedSampleLocations(const ImageIndex &imageIndex) const
1915 {
1916 // We do not allow querying TextureTarget by an ImageIndex that represents an entire level of a
1917 // cube map (See comments in function TextureTypeToTarget() in ImageIndex.cpp).
1918 if (imageIndex.isEntireLevelCubeMap())
1919 {
1920 return true;
1921 }
1922
1923 // ES3.1 (section 9.4) requires that the value of TEXTURE_FIXED_SAMPLE_LOCATIONS should be
1924 // the same for all attached textures.
1925 return getFixedSampleLocations(imageIndex.getTarget(), imageIndex.getLevelIndex());
1926 }
1927
setBorderColor(const Context * context,const ColorGeneric & color)1928 void Texture::setBorderColor(const Context *context, const ColorGeneric &color)
1929 {
1930 mState.mSamplerState.setBorderColor(color);
1931 signalDirtyState(DIRTY_BIT_BORDER_COLOR);
1932 }
1933
getBorderColor() const1934 const ColorGeneric &Texture::getBorderColor() const
1935 {
1936 return mState.mSamplerState.getBorderColor();
1937 }
1938
getRequiredTextureImageUnits(const Context * context) const1939 GLint Texture::getRequiredTextureImageUnits(const Context *context) const
1940 {
1941 // Only external texture types can return non-1.
1942 if (mState.mType != TextureType::External)
1943 {
1944 return 1;
1945 }
1946
1947 return mTexture->getRequiredExternalTextureImageUnits(context);
1948 }
1949
setCrop(const Rectangle & rect)1950 void Texture::setCrop(const Rectangle &rect)
1951 {
1952 mState.setCrop(rect);
1953 }
1954
getCrop() const1955 const Rectangle &Texture::getCrop() const
1956 {
1957 return mState.getCrop();
1958 }
1959
setGenerateMipmapHint(GLenum hint)1960 void Texture::setGenerateMipmapHint(GLenum hint)
1961 {
1962 mState.setGenerateMipmapHint(hint);
1963 }
1964
getGenerateMipmapHint() const1965 GLenum Texture::getGenerateMipmapHint() const
1966 {
1967 return mState.getGenerateMipmapHint();
1968 }
1969
setBuffer(const gl::Context * context,gl::Buffer * buffer,GLenum internalFormat)1970 angle::Result Texture::setBuffer(const gl::Context *context,
1971 gl::Buffer *buffer,
1972 GLenum internalFormat)
1973 {
1974 // Use 0 to indicate that the size is taken from whatever size the buffer has when the texture
1975 // buffer is used.
1976 return setBufferRange(context, buffer, internalFormat, 0, 0);
1977 }
1978
setBufferRange(const gl::Context * context,gl::Buffer * buffer,GLenum internalFormat,GLintptr offset,GLsizeiptr size)1979 angle::Result Texture::setBufferRange(const gl::Context *context,
1980 gl::Buffer *buffer,
1981 GLenum internalFormat,
1982 GLintptr offset,
1983 GLsizeiptr size)
1984 {
1985 mState.mImmutableFormat = true;
1986 mState.mBuffer.set(context, buffer, offset, size);
1987 ANGLE_TRY(mTexture->setBuffer(context, internalFormat));
1988
1989 mState.clearImageDescs();
1990 if (buffer == nullptr)
1991 {
1992 mBufferObserver.reset();
1993 signalDirtyStorage(InitState::MayNeedInit);
1994 return angle::Result::Continue;
1995 }
1996
1997 size = GetBoundBufferAvailableSize(mState.mBuffer);
1998
1999 mState.mImmutableLevels = static_cast<GLuint>(1);
2000 InternalFormat internalFormatInfo = GetSizedInternalFormatInfo(internalFormat);
2001 Format format(internalFormat);
2002 Extents extents(static_cast<GLuint>(size / internalFormatInfo.pixelBytes), 1, 1);
2003 mState.setImageDesc(TextureTarget::Buffer, 0,
2004 ImageDesc(extents, format, InitState::MayNeedInit));
2005
2006 signalDirtyStorage(InitState::MayNeedInit);
2007
2008 // Observe modifications to the buffer, so that extents can be updated.
2009 mBufferObserver.bind(buffer);
2010
2011 return angle::Result::Continue;
2012 }
2013
getBuffer() const2014 const OffsetBindingPointer<Buffer> &Texture::getBuffer() const
2015 {
2016 return mState.mBuffer;
2017 }
2018
onAttach(const Context * context,rx::Serial framebufferSerial)2019 void Texture::onAttach(const Context *context, rx::Serial framebufferSerial)
2020 {
2021 addRef();
2022
2023 // Duplicates allowed for multiple attachment points. See the comment in the header.
2024 mBoundFramebufferSerials.push_back(framebufferSerial);
2025 }
2026
onDetach(const Context * context,rx::Serial framebufferSerial)2027 void Texture::onDetach(const Context *context, rx::Serial framebufferSerial)
2028 {
2029 // Erase first instance. If there are multiple bindings, leave the others.
2030 ASSERT(isBoundToFramebuffer(framebufferSerial));
2031 mBoundFramebufferSerials.remove_and_permute(framebufferSerial);
2032
2033 release(context);
2034 }
2035
getId() const2036 GLuint Texture::getId() const
2037 {
2038 return id().value;
2039 }
2040
getNativeID() const2041 GLuint Texture::getNativeID() const
2042 {
2043 return mTexture->getNativeID();
2044 }
2045
syncState(const Context * context,Command source)2046 angle::Result Texture::syncState(const Context *context, Command source)
2047 {
2048 ASSERT(hasAnyDirtyBit() || source == Command::GenerateMipmap);
2049 ANGLE_TRY(mTexture->syncState(context, mDirtyBits, source));
2050 mDirtyBits.reset();
2051 return angle::Result::Continue;
2052 }
2053
getAttachmentImpl() const2054 rx::FramebufferAttachmentObjectImpl *Texture::getAttachmentImpl() const
2055 {
2056 return mTexture;
2057 }
2058
isSamplerComplete(const Context * context,const Sampler * optionalSampler)2059 bool Texture::isSamplerComplete(const Context *context, const Sampler *optionalSampler)
2060 {
2061 const auto &samplerState =
2062 optionalSampler ? optionalSampler->getSamplerState() : mState.mSamplerState;
2063 const auto &contextState = context->getState();
2064
2065 if (contextState.getContextID() != mCompletenessCache.context ||
2066 !mCompletenessCache.samplerState.sameCompleteness(samplerState))
2067 {
2068 mCompletenessCache.context = context->getState().getContextID();
2069 mCompletenessCache.samplerState = samplerState;
2070 mCompletenessCache.samplerComplete =
2071 mState.computeSamplerCompleteness(samplerState, contextState);
2072 }
2073
2074 return mCompletenessCache.samplerComplete;
2075 }
2076
SamplerCompletenessCache()2077 Texture::SamplerCompletenessCache::SamplerCompletenessCache()
2078 : context({0}), samplerState(), samplerComplete(false)
2079 {}
2080
invalidateCompletenessCache() const2081 void Texture::invalidateCompletenessCache() const
2082 {
2083 mCompletenessCache.context = {0};
2084 }
2085
ensureInitialized(const Context * context)2086 angle::Result Texture::ensureInitialized(const Context *context)
2087 {
2088 if (!context->isRobustResourceInitEnabled() || mState.mInitState == InitState::Initialized)
2089 {
2090 return angle::Result::Continue;
2091 }
2092
2093 bool anyDirty = false;
2094
2095 ImageIndexIterator it =
2096 ImageIndexIterator::MakeGeneric(mState.mType, 0, IMPLEMENTATION_MAX_TEXTURE_LEVELS + 1,
2097 ImageIndex::kEntireLevel, ImageIndex::kEntireLevel);
2098 while (it.hasNext())
2099 {
2100 const ImageIndex index = it.next();
2101 ImageDesc &desc =
2102 mState.mImageDescs[GetImageDescIndex(index.getTarget(), index.getLevelIndex())];
2103 if (desc.initState == InitState::MayNeedInit && !desc.size.empty())
2104 {
2105 ASSERT(mState.mInitState == InitState::MayNeedInit);
2106 ANGLE_TRY(initializeContents(context, index));
2107 desc.initState = InitState::Initialized;
2108 anyDirty = true;
2109 }
2110 }
2111 if (anyDirty)
2112 {
2113 signalDirtyStorage(InitState::Initialized);
2114 }
2115 mState.mInitState = InitState::Initialized;
2116
2117 return angle::Result::Continue;
2118 }
2119
initState(const ImageIndex & imageIndex) const2120 InitState Texture::initState(const ImageIndex &imageIndex) const
2121 {
2122 // As an ImageIndex that represents an entire level of a cube map corresponds to 6 ImageDescs,
2123 // we need to check all the related ImageDescs.
2124 if (imageIndex.isEntireLevelCubeMap())
2125 {
2126 const GLint levelIndex = imageIndex.getLevelIndex();
2127 for (TextureTarget cubeFaceTarget : AllCubeFaceTextureTargets())
2128 {
2129 if (mState.getImageDesc(cubeFaceTarget, levelIndex).initState == InitState::MayNeedInit)
2130 {
2131 return InitState::MayNeedInit;
2132 }
2133 }
2134 return InitState::Initialized;
2135 }
2136
2137 return mState.getImageDesc(imageIndex).initState;
2138 }
2139
setInitState(const ImageIndex & imageIndex,InitState initState)2140 void Texture::setInitState(const ImageIndex &imageIndex, InitState initState)
2141 {
2142 // As an ImageIndex that represents an entire level of a cube map corresponds to 6 ImageDescs,
2143 // we need to update all the related ImageDescs.
2144 if (imageIndex.isEntireLevelCubeMap())
2145 {
2146 const GLint levelIndex = imageIndex.getLevelIndex();
2147 for (TextureTarget cubeFaceTarget : AllCubeFaceTextureTargets())
2148 {
2149 setInitState(ImageIndex::MakeCubeMapFace(cubeFaceTarget, levelIndex), initState);
2150 }
2151 }
2152 else
2153 {
2154 ImageDesc newDesc = mState.getImageDesc(imageIndex);
2155 newDesc.initState = initState;
2156 mState.setImageDesc(imageIndex.getTarget(), imageIndex.getLevelIndex(), newDesc);
2157 }
2158 }
2159
setInitState(InitState initState)2160 void Texture::setInitState(InitState initState)
2161 {
2162 for (ImageDesc &imageDesc : mState.mImageDescs)
2163 {
2164 // Only modifiy defined images, undefined images will remain in the initialized state
2165 if (!imageDesc.size.empty())
2166 {
2167 imageDesc.initState = initState;
2168 }
2169 }
2170 mState.mInitState = initState;
2171 }
2172
doesSubImageNeedInit(const Context * context,const ImageIndex & imageIndex,const Box & area) const2173 bool Texture::doesSubImageNeedInit(const Context *context,
2174 const ImageIndex &imageIndex,
2175 const Box &area) const
2176 {
2177 if (!context->isRobustResourceInitEnabled() || mState.mInitState == InitState::Initialized)
2178 {
2179 return false;
2180 }
2181
2182 // Pre-initialize the texture contents if necessary.
2183 const ImageDesc &desc = mState.getImageDesc(imageIndex);
2184 if (desc.initState != InitState::MayNeedInit)
2185 {
2186 return false;
2187 }
2188
2189 ASSERT(mState.mInitState == InitState::MayNeedInit);
2190 return !area.coversSameExtent(desc.size);
2191 }
2192
ensureSubImageInitialized(const Context * context,const ImageIndex & imageIndex,const Box & area)2193 angle::Result Texture::ensureSubImageInitialized(const Context *context,
2194 const ImageIndex &imageIndex,
2195 const Box &area)
2196 {
2197 if (doesSubImageNeedInit(context, imageIndex, area))
2198 {
2199 // NOTE: do not optimize this to only initialize the passed area of the texture, or the
2200 // initialization logic in copySubImage will be incorrect.
2201 ANGLE_TRY(initializeContents(context, imageIndex));
2202 }
2203 setInitState(imageIndex, InitState::Initialized);
2204 return angle::Result::Continue;
2205 }
2206
handleMipmapGenerationHint(Context * context,int level)2207 angle::Result Texture::handleMipmapGenerationHint(Context *context, int level)
2208 {
2209 if (getGenerateMipmapHint() == GL_TRUE && level == 0)
2210 {
2211 ANGLE_TRY(generateMipmap(context));
2212 }
2213
2214 return angle::Result::Continue;
2215 }
2216
onSubjectStateChange(angle::SubjectIndex index,angle::SubjectMessage message)2217 void Texture::onSubjectStateChange(angle::SubjectIndex index, angle::SubjectMessage message)
2218 {
2219 switch (message)
2220 {
2221 case angle::SubjectMessage::ContentsChanged:
2222 if (index == kBufferSubjectIndex)
2223 {
2224 // If the contents of the buffer attached to a texture buffer has changed, mark the
2225 // texture dirty.
2226 signalDirtyState(DIRTY_BIT_IMPLEMENTATION);
2227 onStateChange(angle::SubjectMessage::ContentsChanged);
2228 }
2229 else
2230 {
2231 // ContentsChange originates from TextureStorage11::resolveAndReleaseTexture
2232 // which resolves the underlying multisampled texture if it exists and so
2233 // Texture will signal dirty storage to invalidate its own cache and the
2234 // attached framebuffer's cache.
2235 signalDirtyStorage(InitState::Initialized);
2236 }
2237 break;
2238 case angle::SubjectMessage::DirtyBitsFlagged:
2239 signalDirtyState(DIRTY_BIT_IMPLEMENTATION);
2240
2241 // Notify siblings that we are dirty.
2242 if (index == rx::kTextureImageImplObserverMessageIndex)
2243 {
2244 notifySiblings(message);
2245 }
2246 break;
2247 case angle::SubjectMessage::SubjectChanged:
2248 mState.mInitState = InitState::MayNeedInit;
2249 signalDirtyState(DIRTY_BIT_IMPLEMENTATION);
2250 onStateChange(angle::SubjectMessage::ContentsChanged);
2251
2252 // Notify siblings that we are dirty.
2253 if (index == rx::kTextureImageImplObserverMessageIndex)
2254 {
2255 notifySiblings(message);
2256 }
2257 else if (index == kBufferSubjectIndex)
2258 {
2259 const gl::Buffer *buffer = mState.mBuffer.get();
2260 ASSERT(buffer != nullptr);
2261
2262 // Update cached image desc based on buffer size.
2263 GLsizeiptr size = GetBoundBufferAvailableSize(mState.mBuffer);
2264
2265 ImageDesc desc = mState.getImageDesc(TextureTarget::Buffer, 0);
2266 const GLuint pixelBytes = desc.format.info->pixelBytes;
2267 desc.size.width = static_cast<GLuint>(size / pixelBytes);
2268
2269 mState.setImageDesc(TextureTarget::Buffer, 0, desc);
2270 }
2271 break;
2272 case angle::SubjectMessage::SubjectMapped:
2273 case angle::SubjectMessage::SubjectUnmapped:
2274 case angle::SubjectMessage::BindingChanged:
2275 ASSERT(index == kBufferSubjectIndex);
2276 break;
2277 default:
2278 UNREACHABLE();
2279 break;
2280 }
2281 }
2282
getImplementationColorReadFormat(const Context * context) const2283 GLenum Texture::getImplementationColorReadFormat(const Context *context) const
2284 {
2285 return mTexture->getColorReadFormat(context);
2286 }
2287
getImplementationColorReadType(const Context * context) const2288 GLenum Texture::getImplementationColorReadType(const Context *context) const
2289 {
2290 return mTexture->getColorReadType(context);
2291 }
2292
getTexImage(const Context * context,const PixelPackState & packState,Buffer * packBuffer,TextureTarget target,GLint level,GLenum format,GLenum type,void * pixels)2293 angle::Result Texture::getTexImage(const Context *context,
2294 const PixelPackState &packState,
2295 Buffer *packBuffer,
2296 TextureTarget target,
2297 GLint level,
2298 GLenum format,
2299 GLenum type,
2300 void *pixels)
2301 {
2302 if (hasAnyDirtyBit())
2303 {
2304 ANGLE_TRY(syncState(context, Command::Other));
2305 }
2306
2307 return mTexture->getTexImage(context, packState, packBuffer, target, level, format, type,
2308 pixels);
2309 }
2310
onBindAsImageTexture()2311 void Texture::onBindAsImageTexture()
2312 {
2313 if (!mState.mHasBeenBoundAsImage)
2314 {
2315 mDirtyBits.set(DIRTY_BIT_BOUND_AS_IMAGE);
2316 mState.mHasBeenBoundAsImage = true;
2317 }
2318 }
2319
2320 } // namespace gl
2321