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