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,const uint8_t * pixels)40 InitState DetermineInitState(const Context *context, const uint8_t *pixels)
41 {
42 // Can happen in tests.
43 if (!context || !context->isRobustResourceInitEnabled())
44 return InitState::Initialized;
45
46 const auto &glState = context->getState();
47 return (pixels == nullptr && glState.getTargetBuffer(gl::BufferBinding::PixelUnpack) == nullptr)
48 ? InitState::MayNeedInit
49 : InitState::Initialized;
50 }
51 } // namespace
52
IsMipmapFiltered(const SamplerState & samplerState)53 bool IsMipmapFiltered(const SamplerState &samplerState)
54 {
55 switch (samplerState.getMinFilter())
56 {
57 case GL_NEAREST:
58 case GL_LINEAR:
59 return false;
60 case GL_NEAREST_MIPMAP_NEAREST:
61 case GL_LINEAR_MIPMAP_NEAREST:
62 case GL_NEAREST_MIPMAP_LINEAR:
63 case GL_LINEAR_MIPMAP_LINEAR:
64 return true;
65 default:
66 UNREACHABLE();
67 return false;
68 }
69 }
70
SwizzleState()71 SwizzleState::SwizzleState()
72 : swizzleRed(GL_RED), swizzleGreen(GL_GREEN), swizzleBlue(GL_BLUE), swizzleAlpha(GL_ALPHA)
73 {}
74
SwizzleState(GLenum red,GLenum green,GLenum blue,GLenum alpha)75 SwizzleState::SwizzleState(GLenum red, GLenum green, GLenum blue, GLenum alpha)
76 : swizzleRed(red), swizzleGreen(green), swizzleBlue(blue), swizzleAlpha(alpha)
77 {}
78
swizzleRequired() const79 bool SwizzleState::swizzleRequired() const
80 {
81 return swizzleRed != GL_RED || swizzleGreen != GL_GREEN || swizzleBlue != GL_BLUE ||
82 swizzleAlpha != GL_ALPHA;
83 }
84
operator ==(const SwizzleState & other) const85 bool SwizzleState::operator==(const SwizzleState &other) const
86 {
87 return swizzleRed == other.swizzleRed && swizzleGreen == other.swizzleGreen &&
88 swizzleBlue == other.swizzleBlue && swizzleAlpha == other.swizzleAlpha;
89 }
90
operator !=(const SwizzleState & other) const91 bool SwizzleState::operator!=(const SwizzleState &other) const
92 {
93 return !(*this == other);
94 }
95
TextureState(TextureType type)96 TextureState::TextureState(TextureType type)
97 : mType(type),
98 mSamplerState(SamplerState::CreateDefaultForTarget(type)),
99 mBaseLevel(0),
100 mMaxLevel(1000),
101 mDepthStencilTextureMode(GL_DEPTH_COMPONENT),
102 mImmutableFormat(false),
103 mImmutableLevels(0),
104 mUsage(GL_NONE),
105 mImageDescs((IMPLEMENTATION_MAX_TEXTURE_LEVELS + 1) * (type == TextureType::CubeMap ? 6 : 1)),
106 mCropRect(0, 0, 0, 0),
107 mGenerateMipmapHint(GL_FALSE),
108 mInitState(InitState::MayNeedInit),
109 mCachedSamplerFormat(SamplerFormat::InvalidEnum),
110 mCachedSamplerCompareMode(GL_NONE),
111 mCachedSamplerFormatValid(false)
112 {}
113
~TextureState()114 TextureState::~TextureState() {}
115
swizzleRequired() const116 bool TextureState::swizzleRequired() const
117 {
118 return mSwizzleState.swizzleRequired();
119 }
120
getEffectiveBaseLevel() const121 GLuint TextureState::getEffectiveBaseLevel() const
122 {
123 if (mImmutableFormat)
124 {
125 // GLES 3.0.4 section 3.8.10
126 return std::min(mBaseLevel, mImmutableLevels - 1);
127 }
128 // Some classes use the effective base level to index arrays with level data. By clamping the
129 // effective base level to max levels these arrays need just one extra item to store properties
130 // that should be returned for all out-of-range base level values, instead of needing special
131 // handling for out-of-range base levels.
132 return std::min(mBaseLevel, static_cast<GLuint>(IMPLEMENTATION_MAX_TEXTURE_LEVELS));
133 }
134
getEffectiveMaxLevel() const135 GLuint TextureState::getEffectiveMaxLevel() const
136 {
137 if (mImmutableFormat)
138 {
139 // GLES 3.0.4 section 3.8.10
140 GLuint clampedMaxLevel = std::max(mMaxLevel, getEffectiveBaseLevel());
141 clampedMaxLevel = std::min(clampedMaxLevel, mImmutableLevels - 1);
142 return clampedMaxLevel;
143 }
144 return mMaxLevel;
145 }
146
getMipmapMaxLevel() const147 GLuint TextureState::getMipmapMaxLevel() const
148 {
149 const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), getEffectiveBaseLevel());
150 GLuint expectedMipLevels = 0;
151 if (mType == TextureType::_3D)
152 {
153 const int maxDim = std::max(std::max(baseImageDesc.size.width, baseImageDesc.size.height),
154 baseImageDesc.size.depth);
155 expectedMipLevels = static_cast<GLuint>(log2(maxDim));
156 }
157 else
158 {
159 expectedMipLevels = static_cast<GLuint>(
160 log2(std::max(baseImageDesc.size.width, baseImageDesc.size.height)));
161 }
162
163 return std::min<GLuint>(getEffectiveBaseLevel() + expectedMipLevels, getEffectiveMaxLevel());
164 }
165
setBaseLevel(GLuint baseLevel)166 bool TextureState::setBaseLevel(GLuint baseLevel)
167 {
168 if (mBaseLevel != baseLevel)
169 {
170 mBaseLevel = baseLevel;
171 return true;
172 }
173 return false;
174 }
175
setMaxLevel(GLuint maxLevel)176 bool TextureState::setMaxLevel(GLuint maxLevel)
177 {
178 if (mMaxLevel != maxLevel)
179 {
180 mMaxLevel = maxLevel;
181 return true;
182 }
183
184 return false;
185 }
186
187 // Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
188 // According to [OpenGL ES 3.0.5] section 3.8.13 Texture Completeness page 160 any
189 // per-level checks begin at the base-level.
190 // For OpenGL ES2 the base level is always zero.
isCubeComplete() const191 bool TextureState::isCubeComplete() const
192 {
193 ASSERT(mType == TextureType::CubeMap);
194
195 angle::EnumIterator<TextureTarget> face = kCubeMapTextureTargetMin;
196 const ImageDesc &baseImageDesc = getImageDesc(*face, getEffectiveBaseLevel());
197 if (baseImageDesc.size.width == 0 || baseImageDesc.size.width != baseImageDesc.size.height)
198 {
199 return false;
200 }
201
202 ++face;
203
204 for (; face != kAfterCubeMapTextureTargetMax; ++face)
205 {
206 const ImageDesc &faceImageDesc = getImageDesc(*face, getEffectiveBaseLevel());
207 if (faceImageDesc.size.width != baseImageDesc.size.width ||
208 faceImageDesc.size.height != baseImageDesc.size.height ||
209 !Format::SameSized(faceImageDesc.format, baseImageDesc.format))
210 {
211 return false;
212 }
213 }
214
215 return true;
216 }
217
getBaseLevelDesc() const218 const ImageDesc &TextureState::getBaseLevelDesc() const
219 {
220 ASSERT(mType != TextureType::CubeMap || isCubeComplete());
221 return getImageDesc(getBaseImageTarget(), getEffectiveBaseLevel());
222 }
223
setCrop(const gl::Rectangle & rect)224 void TextureState::setCrop(const gl::Rectangle &rect)
225 {
226 mCropRect = rect;
227 }
228
getCrop() const229 const gl::Rectangle &TextureState::getCrop() const
230 {
231 return mCropRect;
232 }
233
setGenerateMipmapHint(GLenum hint)234 void TextureState::setGenerateMipmapHint(GLenum hint)
235 {
236 mGenerateMipmapHint = hint;
237 }
238
getGenerateMipmapHint() const239 GLenum TextureState::getGenerateMipmapHint() const
240 {
241 return mGenerateMipmapHint;
242 }
243
computeRequiredSamplerFormat(const SamplerState & samplerState) const244 SamplerFormat TextureState::computeRequiredSamplerFormat(const SamplerState &samplerState) const
245 {
246 const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), getEffectiveBaseLevel());
247 if ((baseImageDesc.format.info->format == GL_DEPTH_COMPONENT ||
248 baseImageDesc.format.info->format == GL_DEPTH_STENCIL) &&
249 samplerState.getCompareMode() != GL_NONE)
250 {
251 return SamplerFormat::Shadow;
252 }
253 else
254 {
255 switch (baseImageDesc.format.info->componentType)
256 {
257 case GL_UNSIGNED_NORMALIZED:
258 case GL_SIGNED_NORMALIZED:
259 case GL_FLOAT:
260 return SamplerFormat::Float;
261 case GL_INT:
262 return SamplerFormat::Signed;
263 case GL_UNSIGNED_INT:
264 return SamplerFormat::Unsigned;
265 default:
266 return SamplerFormat::InvalidEnum;
267 }
268 }
269 }
270
computeSamplerCompleteness(const SamplerState & samplerState,const State & data) const271 bool TextureState::computeSamplerCompleteness(const SamplerState &samplerState,
272 const State &data) const
273 {
274 if (mBaseLevel > mMaxLevel)
275 {
276 return false;
277 }
278 const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), getEffectiveBaseLevel());
279 if (baseImageDesc.size.width == 0 || baseImageDesc.size.height == 0 ||
280 baseImageDesc.size.depth == 0)
281 {
282 return false;
283 }
284 // The cases where the texture is incomplete because base level is out of range should be
285 // handled by the above condition.
286 ASSERT(mBaseLevel < IMPLEMENTATION_MAX_TEXTURE_LEVELS || mImmutableFormat);
287
288 if (mType == TextureType::CubeMap && baseImageDesc.size.width != baseImageDesc.size.height)
289 {
290 return false;
291 }
292
293 // According to es 3.1 spec, texture is justified as incomplete if sized internalformat is
294 // unfilterable(table 20.11) and filter is not GL_NEAREST(8.16). The default value of minFilter
295 // is NEAREST_MIPMAP_LINEAR and magFilter is LINEAR(table 20.11,). For multismaple texture,
296 // filter state of multisample texture is ignored(11.1.3.3). So it shouldn't be judged as
297 // incomplete texture. So, we ignore filtering for multisample texture completeness here.
298 if (!IsMultisampled(mType) &&
299 !baseImageDesc.format.info->filterSupport(data.getClientVersion(), data.getExtensions()) &&
300 !IsPointSampled(samplerState))
301 {
302 return false;
303 }
304 bool npotSupport = data.getExtensions().textureNPOT || data.getClientMajorVersion() >= 3;
305 if (!npotSupport)
306 {
307 if ((samplerState.getWrapS() != GL_CLAMP_TO_EDGE &&
308 samplerState.getWrapS() != GL_CLAMP_TO_BORDER && !isPow2(baseImageDesc.size.width)) ||
309 (samplerState.getWrapT() != GL_CLAMP_TO_EDGE &&
310 samplerState.getWrapT() != GL_CLAMP_TO_BORDER && !isPow2(baseImageDesc.size.height)))
311 {
312 return false;
313 }
314 }
315
316 if (mType != TextureType::_2DMultisample && IsMipmapFiltered(samplerState))
317 {
318 if (!npotSupport)
319 {
320 if (!isPow2(baseImageDesc.size.width) || !isPow2(baseImageDesc.size.height))
321 {
322 return false;
323 }
324 }
325
326 if (!computeMipmapCompleteness())
327 {
328 return false;
329 }
330 }
331 else
332 {
333 if (mType == TextureType::CubeMap && !isCubeComplete())
334 {
335 return false;
336 }
337 }
338
339 // From GL_OES_EGL_image_external_essl3: If state is present in a sampler object bound to a
340 // texture unit that would have been rejected by a call to TexParameter* for the texture bound
341 // to that unit, the behavior of the implementation is as if the texture were incomplete. For
342 // example, if TEXTURE_WRAP_S or TEXTURE_WRAP_T is set to anything but CLAMP_TO_EDGE on the
343 // sampler object bound to a texture unit and the texture bound to that unit is an external
344 // texture, the texture will be considered incomplete.
345 // Sampler object state which does not affect sampling for the type of texture bound to a
346 // texture unit, such as TEXTURE_WRAP_R for an external texture, does not affect completeness.
347 if (mType == TextureType::External)
348 {
349 if (samplerState.getWrapS() != GL_CLAMP_TO_EDGE ||
350 samplerState.getWrapT() != GL_CLAMP_TO_EDGE)
351 {
352 return false;
353 }
354
355 if (samplerState.getMinFilter() != GL_LINEAR && samplerState.getMinFilter() != GL_NEAREST)
356 {
357 return false;
358 }
359 }
360
361 // OpenGLES 3.0.2 spec section 3.8.13 states that a texture is not mipmap complete if:
362 // The internalformat specified for the texture arrays is a sized internal depth or
363 // depth and stencil format (see table 3.13), the value of TEXTURE_COMPARE_-
364 // MODE is NONE, and either the magnification filter is not NEAREST or the mini-
365 // fication filter is neither NEAREST nor NEAREST_MIPMAP_NEAREST.
366 if (!IsMultisampled(mType) && baseImageDesc.format.info->depthBits > 0 &&
367 data.getClientMajorVersion() >= 3)
368 {
369 // Note: we restrict this validation to sized types. For the OES_depth_textures
370 // extension, due to some underspecification problems, we must allow linear filtering
371 // for legacy compatibility with WebGL 1.
372 // See http://crbug.com/649200
373 if (samplerState.getCompareMode() == GL_NONE && baseImageDesc.format.info->sized)
374 {
375 if ((samplerState.getMinFilter() != GL_NEAREST &&
376 samplerState.getMinFilter() != GL_NEAREST_MIPMAP_NEAREST) ||
377 samplerState.getMagFilter() != GL_NEAREST)
378 {
379 return false;
380 }
381 }
382 }
383
384 // OpenGLES 3.1 spec section 8.16 states that a texture is not mipmap complete if:
385 // The internalformat specified for the texture is DEPTH_STENCIL format, the value of
386 // DEPTH_STENCIL_TEXTURE_MODE is STENCIL_INDEX, and either the magnification filter is
387 // not NEAREST or the minification filter is neither NEAREST nor NEAREST_MIPMAP_NEAREST.
388 // However, the ES 3.1 spec differs from the statement above, because it is incorrect.
389 // See the issue at https://github.com/KhronosGroup/OpenGL-API/issues/33.
390 // For multismaple texture, filter state of multisample texture is ignored(11.1.3.3).
391 // So it shouldn't be judged as incomplete texture. So, we ignore filtering for multisample
392 // texture completeness here.
393 if (!IsMultisampled(mType) && baseImageDesc.format.info->depthBits > 0 &&
394 mDepthStencilTextureMode == GL_STENCIL_INDEX)
395 {
396 if ((samplerState.getMinFilter() != GL_NEAREST &&
397 samplerState.getMinFilter() != GL_NEAREST_MIPMAP_NEAREST) ||
398 samplerState.getMagFilter() != GL_NEAREST)
399 {
400 return false;
401 }
402 }
403
404 return true;
405 }
406
computeMipmapCompleteness() const407 bool TextureState::computeMipmapCompleteness() const
408 {
409 const GLuint maxLevel = getMipmapMaxLevel();
410
411 for (GLuint level = getEffectiveBaseLevel(); level <= maxLevel; level++)
412 {
413 if (mType == TextureType::CubeMap)
414 {
415 for (TextureTarget face : AllCubeFaceTextureTargets())
416 {
417 if (!computeLevelCompleteness(face, level))
418 {
419 return false;
420 }
421 }
422 }
423 else
424 {
425 if (!computeLevelCompleteness(NonCubeTextureTypeToTarget(mType), level))
426 {
427 return false;
428 }
429 }
430 }
431
432 return true;
433 }
434
computeLevelCompleteness(TextureTarget target,size_t level) const435 bool TextureState::computeLevelCompleteness(TextureTarget target, size_t level) const
436 {
437 ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
438
439 if (mImmutableFormat)
440 {
441 return true;
442 }
443
444 const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), getEffectiveBaseLevel());
445 if (baseImageDesc.size.width == 0 || baseImageDesc.size.height == 0 ||
446 baseImageDesc.size.depth == 0)
447 {
448 return false;
449 }
450
451 const ImageDesc &levelImageDesc = getImageDesc(target, level);
452 if (levelImageDesc.size.width == 0 || levelImageDesc.size.height == 0 ||
453 levelImageDesc.size.depth == 0)
454 {
455 return false;
456 }
457
458 if (!Format::SameSized(levelImageDesc.format, baseImageDesc.format))
459 {
460 return false;
461 }
462
463 ASSERT(level >= getEffectiveBaseLevel());
464 const size_t relativeLevel = level - getEffectiveBaseLevel();
465 if (levelImageDesc.size.width != std::max(1, baseImageDesc.size.width >> relativeLevel))
466 {
467 return false;
468 }
469
470 if (levelImageDesc.size.height != std::max(1, baseImageDesc.size.height >> relativeLevel))
471 {
472 return false;
473 }
474
475 if (mType == TextureType::_3D)
476 {
477 if (levelImageDesc.size.depth != std::max(1, baseImageDesc.size.depth >> relativeLevel))
478 {
479 return false;
480 }
481 }
482 else if (mType == TextureType::_2DArray)
483 {
484 if (levelImageDesc.size.depth != baseImageDesc.size.depth)
485 {
486 return false;
487 }
488 }
489
490 return true;
491 }
492
getBaseImageTarget() const493 TextureTarget TextureState::getBaseImageTarget() const
494 {
495 return mType == TextureType::CubeMap ? kCubeMapTextureTargetMin
496 : NonCubeTextureTypeToTarget(mType);
497 }
498
ImageDesc()499 ImageDesc::ImageDesc()
500 : ImageDesc(Extents(0, 0, 0), Format::Invalid(), 0, GL_TRUE, InitState::Initialized)
501 {}
502
ImageDesc(const Extents & size,const Format & format,const InitState initState)503 ImageDesc::ImageDesc(const Extents &size, const Format &format, const InitState initState)
504 : size(size), format(format), samples(0), fixedSampleLocations(GL_TRUE), initState(initState)
505 {}
506
ImageDesc(const Extents & size,const Format & format,const GLsizei samples,const bool fixedSampleLocations,const InitState initState)507 ImageDesc::ImageDesc(const Extents &size,
508 const Format &format,
509 const GLsizei samples,
510 const bool fixedSampleLocations,
511 const InitState initState)
512 : size(size),
513 format(format),
514 samples(samples),
515 fixedSampleLocations(fixedSampleLocations),
516 initState(initState)
517 {}
518
getMemorySize() const519 GLint ImageDesc::getMemorySize() const
520 {
521 // Assume allocated size is around width * height * depth * samples * pixelBytes
522 angle::CheckedNumeric<GLint> levelSize = 1;
523 levelSize *= format.info->pixelBytes;
524 levelSize *= size.width;
525 levelSize *= size.height;
526 levelSize *= size.depth;
527 levelSize *= std::max(samples, 1);
528 return levelSize.ValueOrDefault(std::numeric_limits<GLint>::max());
529 }
530
getImageDesc(TextureTarget target,size_t level) const531 const ImageDesc &TextureState::getImageDesc(TextureTarget target, size_t level) const
532 {
533 size_t descIndex = GetImageDescIndex(target, level);
534 ASSERT(descIndex < mImageDescs.size());
535 return mImageDescs[descIndex];
536 }
537
setImageDesc(TextureTarget target,size_t level,const ImageDesc & desc)538 void TextureState::setImageDesc(TextureTarget target, size_t level, const ImageDesc &desc)
539 {
540 size_t descIndex = GetImageDescIndex(target, level);
541 ASSERT(descIndex < mImageDescs.size());
542 mImageDescs[descIndex] = desc;
543 if (desc.initState == InitState::MayNeedInit)
544 {
545 mInitState = InitState::MayNeedInit;
546 }
547 }
548
549 // Note that an ImageIndex that represents an entire level of a cube map corresponds to 6
550 // ImageDescs, so if the cube map is cube complete, we return the ImageDesc of the first cube
551 // face, and we don't allow using this function when the cube map is not cube complete.
getImageDesc(const ImageIndex & imageIndex) const552 const ImageDesc &TextureState::getImageDesc(const ImageIndex &imageIndex) const
553 {
554 if (imageIndex.isEntireLevelCubeMap())
555 {
556 ASSERT(isCubeComplete());
557 const GLint levelIndex = imageIndex.getLevelIndex();
558 return getImageDesc(kCubeMapTextureTargetMin, levelIndex);
559 }
560
561 return getImageDesc(imageIndex.getTarget(), imageIndex.getLevelIndex());
562 }
563
setImageDescChain(GLuint baseLevel,GLuint maxLevel,Extents baseSize,const Format & format,InitState initState)564 void TextureState::setImageDescChain(GLuint baseLevel,
565 GLuint maxLevel,
566 Extents baseSize,
567 const Format &format,
568 InitState initState)
569 {
570 for (GLuint level = baseLevel; level <= maxLevel; level++)
571 {
572 int relativeLevel = (level - baseLevel);
573 Extents levelSize(std::max<int>(baseSize.width >> relativeLevel, 1),
574 std::max<int>(baseSize.height >> relativeLevel, 1),
575 (mType == TextureType::_2DArray)
576 ? baseSize.depth
577 : std::max<int>(baseSize.depth >> relativeLevel, 1));
578 ImageDesc levelInfo(levelSize, format, initState);
579
580 if (mType == TextureType::CubeMap)
581 {
582 for (TextureTarget face : AllCubeFaceTextureTargets())
583 {
584 setImageDesc(face, level, levelInfo);
585 }
586 }
587 else
588 {
589 setImageDesc(NonCubeTextureTypeToTarget(mType), level, levelInfo);
590 }
591 }
592 }
593
setImageDescChainMultisample(Extents baseSize,const Format & format,GLsizei samples,bool fixedSampleLocations,InitState initState)594 void TextureState::setImageDescChainMultisample(Extents baseSize,
595 const Format &format,
596 GLsizei samples,
597 bool fixedSampleLocations,
598 InitState initState)
599 {
600 ASSERT(mType == TextureType::_2DMultisample || mType == TextureType::_2DMultisampleArray);
601 ImageDesc levelInfo(baseSize, format, samples, fixedSampleLocations, initState);
602 setImageDesc(NonCubeTextureTypeToTarget(mType), 0, levelInfo);
603 }
604
clearImageDesc(TextureTarget target,size_t level)605 void TextureState::clearImageDesc(TextureTarget target, size_t level)
606 {
607 setImageDesc(target, level, ImageDesc());
608 }
609
clearImageDescs()610 void TextureState::clearImageDescs()
611 {
612 for (size_t descIndex = 0; descIndex < mImageDescs.size(); descIndex++)
613 {
614 mImageDescs[descIndex] = ImageDesc();
615 }
616 }
617
Texture(rx::GLImplFactory * factory,TextureID id,TextureType type)618 Texture::Texture(rx::GLImplFactory *factory, TextureID id, TextureType type)
619 : RefCountObject(id.value),
620 mState(type),
621 mTexture(factory->createTexture(mState)),
622 mImplObserver(this, rx::kTextureImageImplObserverMessageIndex),
623 mLabel(),
624 mBoundSurface(nullptr),
625 mBoundStream(nullptr)
626 {
627 mImplObserver.bind(mTexture);
628
629 // Initially assume the implementation is dirty.
630 mDirtyBits.set(DIRTY_BIT_IMPLEMENTATION);
631 }
632
onDestroy(const Context * context)633 void Texture::onDestroy(const Context *context)
634 {
635 if (mBoundSurface)
636 {
637 ANGLE_SWALLOW_ERR(mBoundSurface->releaseTexImage(context, EGL_BACK_BUFFER));
638 mBoundSurface = nullptr;
639 }
640 if (mBoundStream)
641 {
642 mBoundStream->releaseTextures();
643 mBoundStream = nullptr;
644 }
645
646 (void)(orphanImages(context));
647
648 if (mTexture)
649 {
650 mTexture->onDestroy(context);
651 }
652 }
653
~Texture()654 Texture::~Texture()
655 {
656 SafeDelete(mTexture);
657 }
658
setLabel(const Context * context,const std::string & label)659 void Texture::setLabel(const Context *context, const std::string &label)
660 {
661 mLabel = label;
662 signalDirtyState(DIRTY_BIT_LABEL);
663 }
664
getLabel() const665 const std::string &Texture::getLabel() const
666 {
667 return mLabel;
668 }
669
setSwizzleRed(const Context * context,GLenum swizzleRed)670 void Texture::setSwizzleRed(const Context *context, GLenum swizzleRed)
671 {
672 mState.mSwizzleState.swizzleRed = swizzleRed;
673 signalDirtyState(DIRTY_BIT_SWIZZLE_RED);
674 }
675
getSwizzleRed() const676 GLenum Texture::getSwizzleRed() const
677 {
678 return mState.mSwizzleState.swizzleRed;
679 }
680
setSwizzleGreen(const Context * context,GLenum swizzleGreen)681 void Texture::setSwizzleGreen(const Context *context, GLenum swizzleGreen)
682 {
683 mState.mSwizzleState.swizzleGreen = swizzleGreen;
684 signalDirtyState(DIRTY_BIT_SWIZZLE_GREEN);
685 }
686
getSwizzleGreen() const687 GLenum Texture::getSwizzleGreen() const
688 {
689 return mState.mSwizzleState.swizzleGreen;
690 }
691
setSwizzleBlue(const Context * context,GLenum swizzleBlue)692 void Texture::setSwizzleBlue(const Context *context, GLenum swizzleBlue)
693 {
694 mState.mSwizzleState.swizzleBlue = swizzleBlue;
695 signalDirtyState(DIRTY_BIT_SWIZZLE_BLUE);
696 }
697
getSwizzleBlue() const698 GLenum Texture::getSwizzleBlue() const
699 {
700 return mState.mSwizzleState.swizzleBlue;
701 }
702
setSwizzleAlpha(const Context * context,GLenum swizzleAlpha)703 void Texture::setSwizzleAlpha(const Context *context, GLenum swizzleAlpha)
704 {
705 mState.mSwizzleState.swizzleAlpha = swizzleAlpha;
706 signalDirtyState(DIRTY_BIT_SWIZZLE_ALPHA);
707 }
708
getSwizzleAlpha() const709 GLenum Texture::getSwizzleAlpha() const
710 {
711 return mState.mSwizzleState.swizzleAlpha;
712 }
713
setMinFilter(const Context * context,GLenum minFilter)714 void Texture::setMinFilter(const Context *context, GLenum minFilter)
715 {
716 mState.mSamplerState.setMinFilter(minFilter);
717 signalDirtyState(DIRTY_BIT_MIN_FILTER);
718 }
719
getMinFilter() const720 GLenum Texture::getMinFilter() const
721 {
722 return mState.mSamplerState.getMinFilter();
723 }
724
setMagFilter(const Context * context,GLenum magFilter)725 void Texture::setMagFilter(const Context *context, GLenum magFilter)
726 {
727 mState.mSamplerState.setMagFilter(magFilter);
728 signalDirtyState(DIRTY_BIT_MAG_FILTER);
729 }
730
getMagFilter() const731 GLenum Texture::getMagFilter() const
732 {
733 return mState.mSamplerState.getMagFilter();
734 }
735
setWrapS(const Context * context,GLenum wrapS)736 void Texture::setWrapS(const Context *context, GLenum wrapS)
737 {
738 mState.mSamplerState.setWrapS(wrapS);
739 signalDirtyState(DIRTY_BIT_WRAP_S);
740 }
741
getWrapS() const742 GLenum Texture::getWrapS() const
743 {
744 return mState.mSamplerState.getWrapS();
745 }
746
setWrapT(const Context * context,GLenum wrapT)747 void Texture::setWrapT(const Context *context, GLenum wrapT)
748 {
749 mState.mSamplerState.setWrapT(wrapT);
750 signalDirtyState(DIRTY_BIT_WRAP_T);
751 }
752
getWrapT() const753 GLenum Texture::getWrapT() const
754 {
755 return mState.mSamplerState.getWrapT();
756 }
757
setWrapR(const Context * context,GLenum wrapR)758 void Texture::setWrapR(const Context *context, GLenum wrapR)
759 {
760 mState.mSamplerState.setWrapR(wrapR);
761 signalDirtyState(DIRTY_BIT_WRAP_R);
762 }
763
getWrapR() const764 GLenum Texture::getWrapR() const
765 {
766 return mState.mSamplerState.getWrapR();
767 }
768
setMaxAnisotropy(const Context * context,float maxAnisotropy)769 void Texture::setMaxAnisotropy(const Context *context, float maxAnisotropy)
770 {
771 mState.mSamplerState.setMaxAnisotropy(maxAnisotropy);
772 signalDirtyState(DIRTY_BIT_MAX_ANISOTROPY);
773 }
774
getMaxAnisotropy() const775 float Texture::getMaxAnisotropy() const
776 {
777 return mState.mSamplerState.getMaxAnisotropy();
778 }
779
setMinLod(const Context * context,GLfloat minLod)780 void Texture::setMinLod(const Context *context, GLfloat minLod)
781 {
782 mState.mSamplerState.setMinLod(minLod);
783 signalDirtyState(DIRTY_BIT_MIN_LOD);
784 }
785
getMinLod() const786 GLfloat Texture::getMinLod() const
787 {
788 return mState.mSamplerState.getMinLod();
789 }
790
setMaxLod(const Context * context,GLfloat maxLod)791 void Texture::setMaxLod(const Context *context, GLfloat maxLod)
792 {
793 mState.mSamplerState.setMaxLod(maxLod);
794 signalDirtyState(DIRTY_BIT_MAX_LOD);
795 }
796
getMaxLod() const797 GLfloat Texture::getMaxLod() const
798 {
799 return mState.mSamplerState.getMaxLod();
800 }
801
setCompareMode(const Context * context,GLenum compareMode)802 void Texture::setCompareMode(const Context *context, GLenum compareMode)
803 {
804 mState.mSamplerState.setCompareMode(compareMode);
805 signalDirtyState(DIRTY_BIT_COMPARE_MODE);
806 }
807
getCompareMode() const808 GLenum Texture::getCompareMode() const
809 {
810 return mState.mSamplerState.getCompareMode();
811 }
812
setCompareFunc(const Context * context,GLenum compareFunc)813 void Texture::setCompareFunc(const Context *context, GLenum compareFunc)
814 {
815 mState.mSamplerState.setCompareFunc(compareFunc);
816 signalDirtyState(DIRTY_BIT_COMPARE_FUNC);
817 }
818
getCompareFunc() const819 GLenum Texture::getCompareFunc() const
820 {
821 return mState.mSamplerState.getCompareFunc();
822 }
823
setSRGBDecode(const Context * context,GLenum sRGBDecode)824 void Texture::setSRGBDecode(const Context *context, GLenum sRGBDecode)
825 {
826 mState.mSamplerState.setSRGBDecode(sRGBDecode);
827 signalDirtyState(DIRTY_BIT_SRGB_DECODE);
828 }
829
getSRGBDecode() const830 GLenum Texture::getSRGBDecode() const
831 {
832 return mState.mSamplerState.getSRGBDecode();
833 }
834
getSamplerState() const835 const SamplerState &Texture::getSamplerState() const
836 {
837 return mState.mSamplerState;
838 }
839
setBaseLevel(const Context * context,GLuint baseLevel)840 angle::Result Texture::setBaseLevel(const Context *context, GLuint baseLevel)
841 {
842 if (mState.setBaseLevel(baseLevel))
843 {
844 ANGLE_TRY(mTexture->setBaseLevel(context, mState.getEffectiveBaseLevel()));
845 signalDirtyState(DIRTY_BIT_BASE_LEVEL);
846 }
847
848 return angle::Result::Continue;
849 }
850
getBaseLevel() const851 GLuint Texture::getBaseLevel() const
852 {
853 return mState.mBaseLevel;
854 }
855
setMaxLevel(const Context * context,GLuint maxLevel)856 void Texture::setMaxLevel(const Context *context, GLuint maxLevel)
857 {
858 if (mState.setMaxLevel(maxLevel))
859 {
860 signalDirtyState(DIRTY_BIT_MAX_LEVEL);
861 }
862 }
863
getMaxLevel() const864 GLuint Texture::getMaxLevel() const
865 {
866 return mState.mMaxLevel;
867 }
868
setDepthStencilTextureMode(const Context * context,GLenum mode)869 void Texture::setDepthStencilTextureMode(const Context *context, GLenum mode)
870 {
871 if (mState.mDepthStencilTextureMode != mode)
872 {
873 mState.mDepthStencilTextureMode = mode;
874 signalDirtyState(DIRTY_BIT_DEPTH_STENCIL_TEXTURE_MODE);
875 }
876 }
877
getDepthStencilTextureMode() const878 GLenum Texture::getDepthStencilTextureMode() const
879 {
880 return mState.mDepthStencilTextureMode;
881 }
882
getImmutableFormat() const883 bool Texture::getImmutableFormat() const
884 {
885 return mState.mImmutableFormat;
886 }
887
getImmutableLevels() const888 GLuint Texture::getImmutableLevels() const
889 {
890 return mState.mImmutableLevels;
891 }
892
setUsage(const Context * context,GLenum usage)893 void Texture::setUsage(const Context *context, GLenum usage)
894 {
895 mState.mUsage = usage;
896 signalDirtyState(DIRTY_BIT_USAGE);
897 }
898
getUsage() const899 GLenum Texture::getUsage() const
900 {
901 return mState.mUsage;
902 }
903
getTextureState() const904 const TextureState &Texture::getTextureState() const
905 {
906 return mState;
907 }
908
getWidth(TextureTarget target,size_t level) const909 size_t Texture::getWidth(TextureTarget target, size_t level) const
910 {
911 ASSERT(TextureTargetToType(target) == mState.mType);
912 return mState.getImageDesc(target, level).size.width;
913 }
914
getHeight(TextureTarget target,size_t level) const915 size_t Texture::getHeight(TextureTarget target, size_t level) const
916 {
917 ASSERT(TextureTargetToType(target) == mState.mType);
918 return mState.getImageDesc(target, level).size.height;
919 }
920
getDepth(TextureTarget target,size_t level) const921 size_t Texture::getDepth(TextureTarget target, size_t level) const
922 {
923 ASSERT(TextureTargetToType(target) == mState.mType);
924 return mState.getImageDesc(target, level).size.depth;
925 }
926
getFormat(TextureTarget target,size_t level) const927 const Format &Texture::getFormat(TextureTarget target, size_t level) const
928 {
929 ASSERT(TextureTargetToType(target) == mState.mType);
930 return mState.getImageDesc(target, level).format;
931 }
932
getSamples(TextureTarget target,size_t level) const933 GLsizei Texture::getSamples(TextureTarget target, size_t level) const
934 {
935 ASSERT(TextureTargetToType(target) == mState.mType);
936 return mState.getImageDesc(target, level).samples;
937 }
938
getFixedSampleLocations(TextureTarget target,size_t level) const939 bool Texture::getFixedSampleLocations(TextureTarget target, size_t level) const
940 {
941 ASSERT(TextureTargetToType(target) == mState.mType);
942 return mState.getImageDesc(target, level).fixedSampleLocations;
943 }
944
getMipmapMaxLevel() const945 GLuint Texture::getMipmapMaxLevel() const
946 {
947 return mState.getMipmapMaxLevel();
948 }
949
isMipmapComplete() const950 bool Texture::isMipmapComplete() const
951 {
952 return mState.computeMipmapCompleteness();
953 }
954
getBoundSurface() const955 egl::Surface *Texture::getBoundSurface() const
956 {
957 return mBoundSurface;
958 }
959
getBoundStream() const960 egl::Stream *Texture::getBoundStream() const
961 {
962 return mBoundStream;
963 }
964
getMemorySize() const965 GLint Texture::getMemorySize() const
966 {
967 GLint implSize = mTexture->getMemorySize();
968 if (implSize > 0)
969 {
970 return implSize;
971 }
972
973 angle::CheckedNumeric<GLint> size = 0;
974 for (const ImageDesc &imageDesc : mState.mImageDescs)
975 {
976 size += imageDesc.getMemorySize();
977 }
978 return size.ValueOrDefault(std::numeric_limits<GLint>::max());
979 }
980
getLevelMemorySize(TextureTarget target,GLint level) const981 GLint Texture::getLevelMemorySize(TextureTarget target, GLint level) const
982 {
983 GLint implSize = mTexture->getLevelMemorySize(target, level);
984 if (implSize > 0)
985 {
986 return implSize;
987 }
988
989 return mState.getImageDesc(target, level).getMemorySize();
990 }
991
signalDirtyStorage(InitState initState)992 void Texture::signalDirtyStorage(InitState initState)
993 {
994 mState.mInitState = initState;
995 invalidateCompletenessCache();
996 mState.mCachedSamplerFormatValid = false;
997 onStateChange(angle::SubjectMessage::SubjectChanged);
998 }
999
signalDirtyState(size_t dirtyBit)1000 void Texture::signalDirtyState(size_t dirtyBit)
1001 {
1002 mDirtyBits.set(dirtyBit);
1003 invalidateCompletenessCache();
1004 mState.mCachedSamplerFormatValid = false;
1005 onStateChange(angle::SubjectMessage::DirtyBitsFlagged);
1006 }
1007
setImage(Context * context,const PixelUnpackState & unpackState,TextureTarget target,GLint level,GLenum internalFormat,const Extents & size,GLenum format,GLenum type,const uint8_t * pixels)1008 angle::Result Texture::setImage(Context *context,
1009 const PixelUnpackState &unpackState,
1010 TextureTarget target,
1011 GLint level,
1012 GLenum internalFormat,
1013 const Extents &size,
1014 GLenum format,
1015 GLenum type,
1016 const uint8_t *pixels)
1017 {
1018 ASSERT(TextureTargetToType(target) == mState.mType);
1019
1020 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1021 ANGLE_TRY(releaseTexImageInternal(context));
1022 ANGLE_TRY(orphanImages(context));
1023
1024 ImageIndex index = ImageIndex::MakeFromTarget(target, level, size.depth);
1025
1026 ANGLE_TRY(mTexture->setImage(context, index, internalFormat, size, format, type, unpackState,
1027 pixels));
1028
1029 InitState initState = DetermineInitState(context, pixels);
1030 mState.setImageDesc(target, level, ImageDesc(size, Format(internalFormat, type), initState));
1031
1032 ANGLE_TRY(handleMipmapGenerationHint(context, level));
1033
1034 signalDirtyStorage(initState);
1035
1036 return angle::Result::Continue;
1037 }
1038
setSubImage(Context * context,const PixelUnpackState & unpackState,Buffer * unpackBuffer,TextureTarget target,GLint level,const Box & area,GLenum format,GLenum type,const uint8_t * pixels)1039 angle::Result Texture::setSubImage(Context *context,
1040 const PixelUnpackState &unpackState,
1041 Buffer *unpackBuffer,
1042 TextureTarget target,
1043 GLint level,
1044 const Box &area,
1045 GLenum format,
1046 GLenum type,
1047 const uint8_t *pixels)
1048 {
1049 ASSERT(TextureTargetToType(target) == mState.mType);
1050
1051 ANGLE_TRY(ensureSubImageInitialized(context, target, level, area));
1052
1053 ImageIndex index = ImageIndex::MakeFromTarget(target, level, area.depth);
1054
1055 ANGLE_TRY(mTexture->setSubImage(context, index, area, format, type, unpackState, unpackBuffer,
1056 pixels));
1057
1058 ANGLE_TRY(handleMipmapGenerationHint(context, level));
1059
1060 onStateChange(angle::SubjectMessage::ContentsChanged);
1061
1062 return angle::Result::Continue;
1063 }
1064
setCompressedImage(Context * context,const PixelUnpackState & unpackState,TextureTarget target,GLint level,GLenum internalFormat,const Extents & size,size_t imageSize,const uint8_t * pixels)1065 angle::Result Texture::setCompressedImage(Context *context,
1066 const PixelUnpackState &unpackState,
1067 TextureTarget target,
1068 GLint level,
1069 GLenum internalFormat,
1070 const Extents &size,
1071 size_t imageSize,
1072 const uint8_t *pixels)
1073 {
1074 ASSERT(TextureTargetToType(target) == mState.mType);
1075
1076 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1077 ANGLE_TRY(releaseTexImageInternal(context));
1078 ANGLE_TRY(orphanImages(context));
1079
1080 ImageIndex index = ImageIndex::MakeFromTarget(target, level, size.depth);
1081
1082 ANGLE_TRY(mTexture->setCompressedImage(context, index, internalFormat, size, unpackState,
1083 imageSize, pixels));
1084
1085 InitState initState = DetermineInitState(context, pixels);
1086 mState.setImageDesc(target, level, ImageDesc(size, Format(internalFormat), initState));
1087 signalDirtyStorage(initState);
1088
1089 return angle::Result::Continue;
1090 }
1091
setCompressedSubImage(const Context * context,const PixelUnpackState & unpackState,TextureTarget target,GLint level,const Box & area,GLenum format,size_t imageSize,const uint8_t * pixels)1092 angle::Result Texture::setCompressedSubImage(const Context *context,
1093 const PixelUnpackState &unpackState,
1094 TextureTarget target,
1095 GLint level,
1096 const Box &area,
1097 GLenum format,
1098 size_t imageSize,
1099 const uint8_t *pixels)
1100 {
1101 ASSERT(TextureTargetToType(target) == mState.mType);
1102
1103 ANGLE_TRY(ensureSubImageInitialized(context, target, level, area));
1104
1105 ImageIndex index = ImageIndex::MakeFromTarget(target, level, area.depth);
1106
1107 ANGLE_TRY(mTexture->setCompressedSubImage(context, index, area, format, unpackState, imageSize,
1108 pixels));
1109
1110 onStateChange(angle::SubjectMessage::ContentsChanged);
1111
1112 return angle::Result::Continue;
1113 }
1114
copyImage(Context * context,TextureTarget target,GLint level,const Rectangle & sourceArea,GLenum internalFormat,Framebuffer * source)1115 angle::Result Texture::copyImage(Context *context,
1116 TextureTarget target,
1117 GLint level,
1118 const Rectangle &sourceArea,
1119 GLenum internalFormat,
1120 Framebuffer *source)
1121 {
1122 ASSERT(TextureTargetToType(target) == mState.mType);
1123
1124 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1125 ANGLE_TRY(releaseTexImageInternal(context));
1126 ANGLE_TRY(orphanImages(context));
1127
1128 // Use the source FBO size as the init image area.
1129 Box destBox(0, 0, 0, sourceArea.width, sourceArea.height, 1);
1130 ANGLE_TRY(ensureSubImageInitialized(context, target, level, destBox));
1131
1132 ImageIndex index = ImageIndex::MakeFromTarget(target, level, 1);
1133
1134 ANGLE_TRY(mTexture->copyImage(context, index, sourceArea, internalFormat, source));
1135
1136 const InternalFormat &internalFormatInfo =
1137 GetInternalFormatInfo(internalFormat, GL_UNSIGNED_BYTE);
1138
1139 mState.setImageDesc(target, level,
1140 ImageDesc(Extents(sourceArea.width, sourceArea.height, 1),
1141 Format(internalFormatInfo), InitState::Initialized));
1142
1143 ANGLE_TRY(handleMipmapGenerationHint(context, level));
1144
1145 // We need to initialize this texture only if the source attachment is not initialized.
1146 signalDirtyStorage(InitState::Initialized);
1147
1148 return angle::Result::Continue;
1149 }
1150
copySubImage(Context * context,const ImageIndex & index,const Offset & destOffset,const Rectangle & sourceArea,Framebuffer * source)1151 angle::Result Texture::copySubImage(Context *context,
1152 const ImageIndex &index,
1153 const Offset &destOffset,
1154 const Rectangle &sourceArea,
1155 Framebuffer *source)
1156 {
1157 ASSERT(TextureTargetToType(index.getTarget()) == mState.mType);
1158
1159 Box destBox(destOffset.x, destOffset.y, destOffset.z, sourceArea.width, sourceArea.height, 1);
1160 ANGLE_TRY(
1161 ensureSubImageInitialized(context, index.getTarget(), index.getLevelIndex(), destBox));
1162
1163 ANGLE_TRY(mTexture->copySubImage(context, index, destOffset, sourceArea, source));
1164 ANGLE_TRY(handleMipmapGenerationHint(context, index.getLevelIndex()));
1165
1166 onStateChange(angle::SubjectMessage::ContentsChanged);
1167
1168 return angle::Result::Continue;
1169 }
1170
copyTexture(Context * context,TextureTarget target,GLint level,GLenum internalFormat,GLenum type,GLint sourceLevel,bool unpackFlipY,bool unpackPremultiplyAlpha,bool unpackUnmultiplyAlpha,Texture * source)1171 angle::Result Texture::copyTexture(Context *context,
1172 TextureTarget target,
1173 GLint level,
1174 GLenum internalFormat,
1175 GLenum type,
1176 GLint sourceLevel,
1177 bool unpackFlipY,
1178 bool unpackPremultiplyAlpha,
1179 bool unpackUnmultiplyAlpha,
1180 Texture *source)
1181 {
1182 ASSERT(TextureTargetToType(target) == mState.mType);
1183 ASSERT(source->getType() != TextureType::CubeMap);
1184
1185 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1186 ANGLE_TRY(releaseTexImageInternal(context));
1187 ANGLE_TRY(orphanImages(context));
1188
1189 // Initialize source texture.
1190 // Note: we don't have a way to notify which portions of the image changed currently.
1191 ANGLE_TRY(source->ensureInitialized(context));
1192
1193 ImageIndex index = ImageIndex::MakeFromTarget(target, level, ImageIndex::kEntireLevel);
1194
1195 ANGLE_TRY(mTexture->copyTexture(context, index, internalFormat, type, sourceLevel, unpackFlipY,
1196 unpackPremultiplyAlpha, unpackUnmultiplyAlpha, source));
1197
1198 const auto &sourceDesc =
1199 source->mState.getImageDesc(NonCubeTextureTypeToTarget(source->getType()), 0);
1200 const InternalFormat &internalFormatInfo = GetInternalFormatInfo(internalFormat, type);
1201 mState.setImageDesc(
1202 target, level,
1203 ImageDesc(sourceDesc.size, Format(internalFormatInfo), InitState::Initialized));
1204
1205 signalDirtyStorage(InitState::Initialized);
1206
1207 return angle::Result::Continue;
1208 }
1209
copySubTexture(const Context * context,TextureTarget target,GLint level,const Offset & destOffset,GLint sourceLevel,const Box & sourceBox,bool unpackFlipY,bool unpackPremultiplyAlpha,bool unpackUnmultiplyAlpha,Texture * source)1210 angle::Result Texture::copySubTexture(const Context *context,
1211 TextureTarget target,
1212 GLint level,
1213 const Offset &destOffset,
1214 GLint sourceLevel,
1215 const Box &sourceBox,
1216 bool unpackFlipY,
1217 bool unpackPremultiplyAlpha,
1218 bool unpackUnmultiplyAlpha,
1219 Texture *source)
1220 {
1221 ASSERT(TextureTargetToType(target) == mState.mType);
1222
1223 // Ensure source is initialized.
1224 ANGLE_TRY(source->ensureInitialized(context));
1225
1226 Box destBox(destOffset.x, destOffset.y, destOffset.z, sourceBox.width, sourceBox.height,
1227 sourceBox.depth);
1228 ANGLE_TRY(ensureSubImageInitialized(context, target, level, destBox));
1229
1230 ImageIndex index = ImageIndex::MakeFromTarget(target, level, sourceBox.depth);
1231
1232 ANGLE_TRY(mTexture->copySubTexture(context, index, destOffset, sourceLevel, sourceBox,
1233 unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha,
1234 source));
1235
1236 onStateChange(angle::SubjectMessage::ContentsChanged);
1237
1238 return angle::Result::Continue;
1239 }
1240
copyCompressedTexture(Context * context,const Texture * source)1241 angle::Result Texture::copyCompressedTexture(Context *context, const Texture *source)
1242 {
1243 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1244 ANGLE_TRY(releaseTexImageInternal(context));
1245 ANGLE_TRY(orphanImages(context));
1246
1247 ANGLE_TRY(mTexture->copyCompressedTexture(context, source));
1248
1249 ASSERT(source->getType() != TextureType::CubeMap && getType() != TextureType::CubeMap);
1250 const auto &sourceDesc =
1251 source->mState.getImageDesc(NonCubeTextureTypeToTarget(source->getType()), 0);
1252 mState.setImageDesc(NonCubeTextureTypeToTarget(getType()), 0, sourceDesc);
1253
1254 return angle::Result::Continue;
1255 }
1256
setStorage(Context * context,TextureType type,GLsizei levels,GLenum internalFormat,const Extents & size)1257 angle::Result Texture::setStorage(Context *context,
1258 TextureType type,
1259 GLsizei levels,
1260 GLenum internalFormat,
1261 const Extents &size)
1262 {
1263 ASSERT(type == mState.mType);
1264
1265 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1266 ANGLE_TRY(releaseTexImageInternal(context));
1267 ANGLE_TRY(orphanImages(context));
1268
1269 ANGLE_TRY(mTexture->setStorage(context, type, levels, internalFormat, size));
1270
1271 mState.mImmutableFormat = true;
1272 mState.mImmutableLevels = static_cast<GLuint>(levels);
1273 mState.clearImageDescs();
1274 mState.setImageDescChain(0, static_cast<GLuint>(levels - 1), size, Format(internalFormat),
1275 InitState::MayNeedInit);
1276
1277 // Changing the texture to immutable can trigger a change in the base and max levels:
1278 // GLES 3.0.4 section 3.8.10 pg 158:
1279 // "For immutable-format textures, levelbase is clamped to the range[0;levels],levelmax is then
1280 // clamped to the range[levelbase;levels].
1281 mDirtyBits.set(DIRTY_BIT_BASE_LEVEL);
1282 mDirtyBits.set(DIRTY_BIT_MAX_LEVEL);
1283
1284 signalDirtyStorage(InitState::MayNeedInit);
1285
1286 return angle::Result::Continue;
1287 }
1288
setImageExternal(Context * context,TextureTarget target,GLint level,GLenum internalFormat,const Extents & size,GLenum format,GLenum type)1289 angle::Result Texture::setImageExternal(Context *context,
1290 TextureTarget target,
1291 GLint level,
1292 GLenum internalFormat,
1293 const Extents &size,
1294 GLenum format,
1295 GLenum type)
1296 {
1297 ASSERT(TextureTargetToType(target) == mState.mType);
1298
1299 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1300 ANGLE_TRY(releaseTexImageInternal(context));
1301 ANGLE_TRY(orphanImages(context));
1302
1303 ImageIndex index = ImageIndex::MakeFromTarget(target, level, size.depth);
1304
1305 ANGLE_TRY(mTexture->setImageExternal(context, index, internalFormat, size, format, type));
1306
1307 InitState initState = InitState::Initialized;
1308 mState.setImageDesc(target, level, ImageDesc(size, Format(internalFormat, type), initState));
1309
1310 ANGLE_TRY(handleMipmapGenerationHint(context, level));
1311
1312 signalDirtyStorage(initState);
1313
1314 return angle::Result::Continue;
1315 }
1316
setStorageMultisample(Context * context,TextureType type,GLsizei samples,GLint internalFormat,const Extents & size,bool fixedSampleLocations)1317 angle::Result Texture::setStorageMultisample(Context *context,
1318 TextureType type,
1319 GLsizei samples,
1320 GLint internalFormat,
1321 const Extents &size,
1322 bool fixedSampleLocations)
1323 {
1324 ASSERT(type == mState.mType);
1325
1326 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1327 ANGLE_TRY(releaseTexImageInternal(context));
1328 ANGLE_TRY(orphanImages(context));
1329
1330 ANGLE_TRY(mTexture->setStorageMultisample(context, type, samples, internalFormat, size,
1331 fixedSampleLocations));
1332
1333 mState.mImmutableFormat = true;
1334 mState.mImmutableLevels = static_cast<GLuint>(1);
1335 mState.clearImageDescs();
1336 mState.setImageDescChainMultisample(size, Format(internalFormat), samples, fixedSampleLocations,
1337 InitState::MayNeedInit);
1338
1339 signalDirtyStorage(InitState::MayNeedInit);
1340
1341 return angle::Result::Continue;
1342 }
1343
setStorageExternalMemory(Context * context,TextureType type,GLsizei levels,GLenum internalFormat,const Extents & size,MemoryObject * memoryObject,GLuint64 offset)1344 angle::Result Texture::setStorageExternalMemory(Context *context,
1345 TextureType type,
1346 GLsizei levels,
1347 GLenum internalFormat,
1348 const Extents &size,
1349 MemoryObject *memoryObject,
1350 GLuint64 offset)
1351 {
1352 ASSERT(type == mState.mType);
1353
1354 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1355 ANGLE_TRY(releaseTexImageInternal(context));
1356 ANGLE_TRY(orphanImages(context));
1357
1358 ANGLE_TRY(mTexture->setStorageExternalMemory(context, type, levels, internalFormat, size,
1359 memoryObject, offset));
1360
1361 mState.mImmutableFormat = true;
1362 mState.mImmutableLevels = static_cast<GLuint>(levels);
1363 mState.clearImageDescs();
1364 mState.setImageDescChain(0, static_cast<GLuint>(levels - 1), size, Format(internalFormat),
1365 InitState::MayNeedInit);
1366
1367 // Changing the texture to immutable can trigger a change in the base and max levels:
1368 // GLES 3.0.4 section 3.8.10 pg 158:
1369 // "For immutable-format textures, levelbase is clamped to the range[0;levels],levelmax is then
1370 // clamped to the range[levelbase;levels].
1371 mDirtyBits.set(DIRTY_BIT_BASE_LEVEL);
1372 mDirtyBits.set(DIRTY_BIT_MAX_LEVEL);
1373
1374 signalDirtyStorage(InitState::Initialized);
1375
1376 return angle::Result::Continue;
1377 }
1378
generateMipmap(Context * context)1379 angle::Result Texture::generateMipmap(Context *context)
1380 {
1381 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1382 ANGLE_TRY(releaseTexImageInternal(context));
1383
1384 // EGL_KHR_gl_image states that images are only orphaned when generating mipmaps if the texture
1385 // is not mip complete.
1386 if (!isMipmapComplete())
1387 {
1388 ANGLE_TRY(orphanImages(context));
1389 }
1390
1391 const GLuint baseLevel = mState.getEffectiveBaseLevel();
1392 const GLuint maxLevel = mState.getMipmapMaxLevel();
1393
1394 if (maxLevel <= baseLevel)
1395 {
1396 return angle::Result::Continue;
1397 }
1398
1399 if (hasAnyDirtyBit())
1400 {
1401 ANGLE_TRY(syncState(context));
1402 }
1403
1404 // Clear the base image(s) immediately if needed
1405 if (context->isRobustResourceInitEnabled())
1406 {
1407 ImageIndexIterator it =
1408 ImageIndexIterator::MakeGeneric(mState.mType, baseLevel, baseLevel + 1,
1409 ImageIndex::kEntireLevel, ImageIndex::kEntireLevel);
1410 while (it.hasNext())
1411 {
1412 const ImageIndex index = it.next();
1413 const ImageDesc &desc = mState.getImageDesc(index.getTarget(), index.getLevelIndex());
1414
1415 if (desc.initState == InitState::MayNeedInit)
1416 {
1417 ANGLE_TRY(initializeContents(context, index));
1418 }
1419 }
1420 }
1421
1422 ANGLE_TRY(mTexture->generateMipmap(context));
1423
1424 // Propagate the format and size of the bsae mip to the smaller ones. Cube maps are guaranteed
1425 // to have faces of the same size and format so any faces can be picked.
1426 const ImageDesc &baseImageInfo = mState.getImageDesc(mState.getBaseImageTarget(), baseLevel);
1427 mState.setImageDescChain(baseLevel, maxLevel, baseImageInfo.size, baseImageInfo.format,
1428 InitState::Initialized);
1429
1430 signalDirtyStorage(InitState::Initialized);
1431
1432 return angle::Result::Continue;
1433 }
1434
bindTexImageFromSurface(Context * context,egl::Surface * surface)1435 angle::Result Texture::bindTexImageFromSurface(Context *context, egl::Surface *surface)
1436 {
1437 ASSERT(surface);
1438
1439 if (mBoundSurface)
1440 {
1441 ANGLE_TRY(releaseTexImageFromSurface(context));
1442 }
1443
1444 ANGLE_TRY(mTexture->bindTexImage(context, surface));
1445 mBoundSurface = surface;
1446
1447 // Set the image info to the size and format of the surface
1448 ASSERT(mState.mType == TextureType::_2D || mState.mType == TextureType::Rectangle);
1449 Extents size(surface->getWidth(), surface->getHeight(), 1);
1450 ImageDesc desc(size, surface->getBindTexImageFormat(), InitState::Initialized);
1451 mState.setImageDesc(NonCubeTextureTypeToTarget(mState.mType), 0, desc);
1452 signalDirtyStorage(InitState::Initialized);
1453 return angle::Result::Continue;
1454 }
1455
releaseTexImageFromSurface(const Context * context)1456 angle::Result Texture::releaseTexImageFromSurface(const Context *context)
1457 {
1458 ASSERT(mBoundSurface);
1459 mBoundSurface = nullptr;
1460 ANGLE_TRY(mTexture->releaseTexImage(context));
1461
1462 // Erase the image info for level 0
1463 ASSERT(mState.mType == TextureType::_2D || mState.mType == TextureType::Rectangle);
1464 mState.clearImageDesc(NonCubeTextureTypeToTarget(mState.mType), 0);
1465 signalDirtyStorage(InitState::Initialized);
1466 return angle::Result::Continue;
1467 }
1468
bindStream(egl::Stream * stream)1469 void Texture::bindStream(egl::Stream *stream)
1470 {
1471 ASSERT(stream);
1472
1473 // It should not be possible to bind a texture already bound to another stream
1474 ASSERT(mBoundStream == nullptr);
1475
1476 mBoundStream = stream;
1477
1478 ASSERT(mState.mType == TextureType::External);
1479 }
1480
releaseStream()1481 void Texture::releaseStream()
1482 {
1483 ASSERT(mBoundStream);
1484 mBoundStream = nullptr;
1485 }
1486
acquireImageFromStream(const Context * context,const egl::Stream::GLTextureDescription & desc)1487 angle::Result Texture::acquireImageFromStream(const Context *context,
1488 const egl::Stream::GLTextureDescription &desc)
1489 {
1490 ASSERT(mBoundStream != nullptr);
1491 ANGLE_TRY(mTexture->setImageExternal(context, mState.mType, mBoundStream, desc));
1492
1493 Extents size(desc.width, desc.height, 1);
1494 mState.setImageDesc(NonCubeTextureTypeToTarget(mState.mType), 0,
1495 ImageDesc(size, Format(desc.internalFormat), InitState::Initialized));
1496 signalDirtyStorage(InitState::Initialized);
1497 return angle::Result::Continue;
1498 }
1499
releaseImageFromStream(const Context * context)1500 angle::Result Texture::releaseImageFromStream(const Context *context)
1501 {
1502 ASSERT(mBoundStream != nullptr);
1503 ANGLE_TRY(mTexture->setImageExternal(context, mState.mType, nullptr,
1504 egl::Stream::GLTextureDescription()));
1505
1506 // Set to incomplete
1507 mState.clearImageDesc(NonCubeTextureTypeToTarget(mState.mType), 0);
1508 signalDirtyStorage(InitState::Initialized);
1509 return angle::Result::Continue;
1510 }
1511
releaseTexImageInternal(Context * context)1512 angle::Result Texture::releaseTexImageInternal(Context *context)
1513 {
1514 if (mBoundSurface)
1515 {
1516 // Notify the surface
1517 egl::Error eglErr = mBoundSurface->releaseTexImageFromTexture(context);
1518 // TODO(jmadill): Remove this once refactor is complete. http://anglebug.com/3041
1519 if (eglErr.isError())
1520 {
1521 context->handleError(GL_INVALID_OPERATION, "Error releasing tex image from texture",
1522 __FILE__, ANGLE_FUNCTION, __LINE__);
1523 }
1524
1525 // Then, call the same method as from the surface
1526 ANGLE_TRY(releaseTexImageFromSurface(context));
1527 }
1528 return angle::Result::Continue;
1529 }
1530
setEGLImageTarget(Context * context,TextureType type,egl::Image * imageTarget)1531 angle::Result Texture::setEGLImageTarget(Context *context,
1532 TextureType type,
1533 egl::Image *imageTarget)
1534 {
1535 ASSERT(type == mState.mType);
1536 ASSERT(type == TextureType::_2D || type == TextureType::External);
1537
1538 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1539 ANGLE_TRY(releaseTexImageInternal(context));
1540 ANGLE_TRY(orphanImages(context));
1541
1542 ANGLE_TRY(mTexture->setEGLImageTarget(context, type, imageTarget));
1543
1544 setTargetImage(context, imageTarget);
1545
1546 Extents size(static_cast<int>(imageTarget->getWidth()),
1547 static_cast<int>(imageTarget->getHeight()), 1);
1548
1549 auto initState = imageTarget->sourceInitState();
1550
1551 mState.clearImageDescs();
1552 mState.setImageDesc(NonCubeTextureTypeToTarget(type), 0,
1553 ImageDesc(size, imageTarget->getFormat(), initState));
1554 signalDirtyStorage(initState);
1555
1556 return angle::Result::Continue;
1557 }
1558
getAttachmentSize(const ImageIndex & imageIndex) const1559 Extents Texture::getAttachmentSize(const ImageIndex &imageIndex) const
1560 {
1561 // As an ImageIndex that represents an entire level of a cube map corresponds to 6 ImageDescs,
1562 // we only allow querying ImageDesc on a complete cube map, and this ImageDesc is exactly the
1563 // one that belongs to the first face of the cube map.
1564 if (imageIndex.isEntireLevelCubeMap())
1565 {
1566 // A cube map texture is cube complete if the following conditions all hold true:
1567 // - The levelbase arrays of each of the six texture images making up the cube map have
1568 // identical, positive, and square dimensions.
1569 if (!mState.isCubeComplete())
1570 {
1571 return Extents();
1572 }
1573 }
1574
1575 return mState.getImageDesc(imageIndex).size;
1576 }
1577
getAttachmentFormat(GLenum,const ImageIndex & imageIndex) const1578 Format Texture::getAttachmentFormat(GLenum /*binding*/, const ImageIndex &imageIndex) const
1579 {
1580 // As an ImageIndex that represents an entire level of a cube map corresponds to 6 ImageDescs,
1581 // we only allow querying ImageDesc on a complete cube map, and this ImageDesc is exactly the
1582 // one that belongs to the first face of the cube map.
1583 if (imageIndex.isEntireLevelCubeMap())
1584 {
1585 // A cube map texture is cube complete if the following conditions all hold true:
1586 // - The levelbase arrays were each specified with the same effective internal format.
1587 if (!mState.isCubeComplete())
1588 {
1589 return Format::Invalid();
1590 }
1591 }
1592 return mState.getImageDesc(imageIndex).format;
1593 }
1594
getAttachmentSamples(const ImageIndex & imageIndex) const1595 GLsizei Texture::getAttachmentSamples(const ImageIndex &imageIndex) const
1596 {
1597 // We do not allow querying TextureTarget by an ImageIndex that represents an entire level of a
1598 // cube map (See comments in function TextureTypeToTarget() in ImageIndex.cpp).
1599 if (imageIndex.isEntireLevelCubeMap())
1600 {
1601 return 0;
1602 }
1603
1604 return getSamples(imageIndex.getTarget(), imageIndex.getLevelIndex());
1605 }
1606
isRenderable(const Context * context,GLenum binding,const ImageIndex & imageIndex) const1607 bool Texture::isRenderable(const Context *context,
1608 GLenum binding,
1609 const ImageIndex &imageIndex) const
1610 {
1611 if (isEGLImageTarget())
1612 {
1613 return ImageSibling::isRenderable(context, binding, imageIndex);
1614 }
1615 return getAttachmentFormat(binding, imageIndex)
1616 .info->textureAttachmentSupport(context->getClientVersion(), context->getExtensions());
1617 }
1618
getAttachmentFixedSampleLocations(const ImageIndex & imageIndex) const1619 bool Texture::getAttachmentFixedSampleLocations(const ImageIndex &imageIndex) const
1620 {
1621 // We do not allow querying TextureTarget by an ImageIndex that represents an entire level of a
1622 // cube map (See comments in function TextureTypeToTarget() in ImageIndex.cpp).
1623 if (imageIndex.isEntireLevelCubeMap())
1624 {
1625 return true;
1626 }
1627
1628 // ES3.1 (section 9.4) requires that the value of TEXTURE_FIXED_SAMPLE_LOCATIONS should be
1629 // the same for all attached textures.
1630 return getFixedSampleLocations(imageIndex.getTarget(), imageIndex.getLevelIndex());
1631 }
1632
setBorderColor(const Context * context,const ColorGeneric & color)1633 void Texture::setBorderColor(const Context *context, const ColorGeneric &color)
1634 {
1635 mState.mSamplerState.setBorderColor(color);
1636 signalDirtyState(DIRTY_BIT_BORDER_COLOR);
1637 }
1638
getBorderColor() const1639 const ColorGeneric &Texture::getBorderColor() const
1640 {
1641 return mState.mSamplerState.getBorderColor();
1642 }
1643
setCrop(const gl::Rectangle & rect)1644 void Texture::setCrop(const gl::Rectangle &rect)
1645 {
1646 mState.setCrop(rect);
1647 }
1648
getCrop() const1649 const gl::Rectangle &Texture::getCrop() const
1650 {
1651 return mState.getCrop();
1652 }
1653
setGenerateMipmapHint(GLenum hint)1654 void Texture::setGenerateMipmapHint(GLenum hint)
1655 {
1656 mState.setGenerateMipmapHint(hint);
1657 }
1658
getGenerateMipmapHint() const1659 GLenum Texture::getGenerateMipmapHint() const
1660 {
1661 return mState.getGenerateMipmapHint();
1662 }
1663
onAttach(const Context * context)1664 void Texture::onAttach(const Context *context)
1665 {
1666 addRef();
1667 }
1668
onDetach(const Context * context)1669 void Texture::onDetach(const Context *context)
1670 {
1671 release(context);
1672 }
1673
getId() const1674 GLuint Texture::getId() const
1675 {
1676 return id();
1677 }
1678
getNativeID() const1679 GLuint Texture::getNativeID() const
1680 {
1681 return mTexture->getNativeID();
1682 }
1683
syncState(const Context * context)1684 angle::Result Texture::syncState(const Context *context)
1685 {
1686 ASSERT(hasAnyDirtyBit());
1687 ANGLE_TRY(mTexture->syncState(context, mDirtyBits));
1688 mDirtyBits.reset();
1689 return angle::Result::Continue;
1690 }
1691
getAttachmentImpl() const1692 rx::FramebufferAttachmentObjectImpl *Texture::getAttachmentImpl() const
1693 {
1694 return mTexture;
1695 }
1696
isSamplerComplete(const Context * context,const Sampler * optionalSampler)1697 bool Texture::isSamplerComplete(const Context *context, const Sampler *optionalSampler)
1698 {
1699 const auto &samplerState =
1700 optionalSampler ? optionalSampler->getSamplerState() : mState.mSamplerState;
1701 const auto &contextState = context->getState();
1702
1703 if (contextState.getContextID() != mCompletenessCache.context ||
1704 !mCompletenessCache.samplerState.sameCompleteness(samplerState))
1705 {
1706 mCompletenessCache.context = context->getState().getContextID();
1707 mCompletenessCache.samplerState = samplerState;
1708 mCompletenessCache.samplerComplete =
1709 mState.computeSamplerCompleteness(samplerState, contextState);
1710 }
1711
1712 return mCompletenessCache.samplerComplete;
1713 }
1714
SamplerCompletenessCache()1715 Texture::SamplerCompletenessCache::SamplerCompletenessCache()
1716 : context(0), samplerState(), samplerComplete(false)
1717 {}
1718
invalidateCompletenessCache() const1719 void Texture::invalidateCompletenessCache() const
1720 {
1721 mCompletenessCache.context = 0;
1722 }
1723
ensureInitialized(const Context * context)1724 angle::Result Texture::ensureInitialized(const Context *context)
1725 {
1726 if (!context->isRobustResourceInitEnabled() || mState.mInitState == InitState::Initialized)
1727 {
1728 return angle::Result::Continue;
1729 }
1730
1731 bool anyDirty = false;
1732
1733 ImageIndexIterator it =
1734 ImageIndexIterator::MakeGeneric(mState.mType, 0, IMPLEMENTATION_MAX_TEXTURE_LEVELS + 1,
1735 ImageIndex::kEntireLevel, ImageIndex::kEntireLevel);
1736 while (it.hasNext())
1737 {
1738 const ImageIndex index = it.next();
1739 ImageDesc &desc =
1740 mState.mImageDescs[GetImageDescIndex(index.getTarget(), index.getLevelIndex())];
1741 if (desc.initState == InitState::MayNeedInit)
1742 {
1743 ASSERT(mState.mInitState == InitState::MayNeedInit);
1744 ANGLE_TRY(initializeContents(context, index));
1745 desc.initState = InitState::Initialized;
1746 anyDirty = true;
1747 }
1748 }
1749 if (anyDirty)
1750 {
1751 signalDirtyStorage(InitState::Initialized);
1752 }
1753 mState.mInitState = InitState::Initialized;
1754
1755 return angle::Result::Continue;
1756 }
1757
initState(const ImageIndex & imageIndex) const1758 InitState Texture::initState(const ImageIndex &imageIndex) const
1759 {
1760 // As an ImageIndex that represents an entire level of a cube map corresponds to 6 ImageDescs,
1761 // we need to check all the related ImageDescs.
1762 if (imageIndex.isEntireLevelCubeMap())
1763 {
1764 const GLint levelIndex = imageIndex.getLevelIndex();
1765 for (TextureTarget cubeFaceTarget : AllCubeFaceTextureTargets())
1766 {
1767 if (mState.getImageDesc(cubeFaceTarget, levelIndex).initState == InitState::MayNeedInit)
1768 {
1769 return InitState::MayNeedInit;
1770 }
1771 }
1772 return InitState::Initialized;
1773 }
1774
1775 return mState.getImageDesc(imageIndex).initState;
1776 }
1777
setInitState(const ImageIndex & imageIndex,InitState initState)1778 void Texture::setInitState(const ImageIndex &imageIndex, InitState initState)
1779 {
1780 // As an ImageIndex that represents an entire level of a cube map corresponds to 6 ImageDescs,
1781 // we need to update all the related ImageDescs.
1782 if (imageIndex.isEntireLevelCubeMap())
1783 {
1784 const GLint levelIndex = imageIndex.getLevelIndex();
1785 for (TextureTarget cubeFaceTarget : AllCubeFaceTextureTargets())
1786 {
1787 setInitState(ImageIndex::MakeCubeMapFace(cubeFaceTarget, levelIndex), initState);
1788 }
1789 }
1790 else
1791 {
1792 ImageDesc newDesc = mState.getImageDesc(imageIndex);
1793 newDesc.initState = initState;
1794 mState.setImageDesc(imageIndex.getTarget(), imageIndex.getLevelIndex(), newDesc);
1795 }
1796 }
1797
ensureSubImageInitialized(const Context * context,TextureTarget target,size_t level,const gl::Box & area)1798 angle::Result Texture::ensureSubImageInitialized(const Context *context,
1799 TextureTarget target,
1800 size_t level,
1801 const gl::Box &area)
1802 {
1803 if (!context->isRobustResourceInitEnabled() || mState.mInitState == InitState::Initialized)
1804 {
1805 return angle::Result::Continue;
1806 }
1807
1808 // Pre-initialize the texture contents if necessary.
1809 // TODO(jmadill): Check if area overlaps the entire texture.
1810 ImageIndex imageIndex =
1811 ImageIndex::MakeFromTarget(target, static_cast<GLint>(level), area.depth);
1812 const auto &desc = mState.getImageDesc(imageIndex);
1813 if (desc.initState == InitState::MayNeedInit)
1814 {
1815 ASSERT(mState.mInitState == InitState::MayNeedInit);
1816 bool coversWholeImage = area.x == 0 && area.y == 0 && area.z == 0 &&
1817 area.width == desc.size.width && area.height == desc.size.height &&
1818 area.depth == desc.size.depth;
1819 if (!coversWholeImage)
1820 {
1821 ANGLE_TRY(initializeContents(context, imageIndex));
1822 }
1823 setInitState(imageIndex, InitState::Initialized);
1824 }
1825
1826 return angle::Result::Continue;
1827 }
1828
handleMipmapGenerationHint(Context * context,int level)1829 angle::Result Texture::handleMipmapGenerationHint(Context *context, int level)
1830 {
1831
1832 if (getGenerateMipmapHint() == GL_TRUE && level == 0)
1833 {
1834 ANGLE_TRY(generateMipmap(context));
1835 }
1836
1837 return angle::Result::Continue;
1838 }
1839
onSubjectStateChange(angle::SubjectIndex index,angle::SubjectMessage message)1840 void Texture::onSubjectStateChange(angle::SubjectIndex index, angle::SubjectMessage message)
1841 {
1842 ASSERT(message == angle::SubjectMessage::SubjectChanged);
1843 mDirtyBits.set(DIRTY_BIT_IMPLEMENTATION);
1844 signalDirtyState(DIRTY_BIT_IMPLEMENTATION);
1845
1846 // Notify siblings that we are dirty.
1847 if (index == rx::kTextureImageImplObserverMessageIndex)
1848 {
1849 notifySiblings(message);
1850 }
1851 }
1852 } // namespace gl
1853