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