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