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