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(const SamplerState & samplerState)52 bool IsMipmapFiltered(const SamplerState &samplerState)
53 {
54 switch (samplerState.getMinFilter())
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
SwizzleState()70 SwizzleState::SwizzleState()
71 : swizzleRed(GL_RED), swizzleGreen(GL_GREEN), swizzleBlue(GL_BLUE), swizzleAlpha(GL_ALPHA)
72 {}
73
SwizzleState(GLenum red,GLenum green,GLenum blue,GLenum alpha)74 SwizzleState::SwizzleState(GLenum red, GLenum green, GLenum blue, GLenum alpha)
75 : swizzleRed(red), swizzleGreen(green), swizzleBlue(blue), swizzleAlpha(alpha)
76 {}
77
swizzleRequired() const78 bool SwizzleState::swizzleRequired() const
79 {
80 return swizzleRed != GL_RED || swizzleGreen != GL_GREEN || swizzleBlue != GL_BLUE ||
81 swizzleAlpha != GL_ALPHA;
82 }
83
operator ==(const SwizzleState & other) const84 bool SwizzleState::operator==(const SwizzleState &other) const
85 {
86 return swizzleRed == other.swizzleRed && swizzleGreen == other.swizzleGreen &&
87 swizzleBlue == other.swizzleBlue && swizzleAlpha == other.swizzleAlpha;
88 }
89
operator !=(const SwizzleState & other) const90 bool SwizzleState::operator!=(const SwizzleState &other) const
91 {
92 return !(*this == other);
93 }
94
TextureState(TextureType type)95 TextureState::TextureState(TextureType type)
96 : mType(type),
97 mSamplerState(SamplerState::CreateDefaultForTarget(type)),
98 mBaseLevel(0),
99 mMaxLevel(1000),
100 mDepthStencilTextureMode(GL_DEPTH_COMPONENT),
101 mImmutableFormat(false),
102 mImmutableLevels(0),
103 mUsage(GL_NONE),
104 mImageDescs((IMPLEMENTATION_MAX_TEXTURE_LEVELS + 1) * (type == TextureType::CubeMap ? 6 : 1)),
105 mCropRect(0, 0, 0, 0),
106 mGenerateMipmapHint(GL_FALSE),
107 mInitState(InitState::MayNeedInit),
108 mCachedSamplerFormat(SamplerFormat::InvalidEnum),
109 mCachedSamplerCompareMode(GL_NONE),
110 mCachedSamplerFormatValid(false)
111 {}
112
~TextureState()113 TextureState::~TextureState() {}
114
swizzleRequired() const115 bool TextureState::swizzleRequired() const
116 {
117 return mSwizzleState.swizzleRequired();
118 }
119
getEffectiveBaseLevel() const120 GLuint TextureState::getEffectiveBaseLevel() const
121 {
122 if (mImmutableFormat)
123 {
124 // GLES 3.0.4 section 3.8.10
125 return std::min(mBaseLevel, mImmutableLevels - 1);
126 }
127 // Some classes use the effective base level to index arrays with level data. By clamping the
128 // effective base level to max levels these arrays need just one extra item to store properties
129 // that should be returned for all out-of-range base level values, instead of needing special
130 // handling for out-of-range base levels.
131 return std::min(mBaseLevel, static_cast<GLuint>(IMPLEMENTATION_MAX_TEXTURE_LEVELS));
132 }
133
getEffectiveMaxLevel() const134 GLuint TextureState::getEffectiveMaxLevel() const
135 {
136 if (mImmutableFormat)
137 {
138 // GLES 3.0.4 section 3.8.10
139 GLuint clampedMaxLevel = std::max(mMaxLevel, getEffectiveBaseLevel());
140 clampedMaxLevel = std::min(clampedMaxLevel, mImmutableLevels - 1);
141 return clampedMaxLevel;
142 }
143 return mMaxLevel;
144 }
145
getMipmapMaxLevel() const146 GLuint TextureState::getMipmapMaxLevel() const
147 {
148 const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), getEffectiveBaseLevel());
149 GLuint expectedMipLevels = 0;
150 if (mType == TextureType::_3D)
151 {
152 const int maxDim = std::max(std::max(baseImageDesc.size.width, baseImageDesc.size.height),
153 baseImageDesc.size.depth);
154 expectedMipLevels = static_cast<GLuint>(log2(maxDim));
155 }
156 else
157 {
158 expectedMipLevels = static_cast<GLuint>(
159 log2(std::max(baseImageDesc.size.width, baseImageDesc.size.height)));
160 }
161
162 return std::min<GLuint>(getEffectiveBaseLevel() + expectedMipLevels, getEffectiveMaxLevel());
163 }
164
setBaseLevel(GLuint baseLevel)165 bool TextureState::setBaseLevel(GLuint baseLevel)
166 {
167 if (mBaseLevel != baseLevel)
168 {
169 mBaseLevel = baseLevel;
170 return true;
171 }
172 return false;
173 }
174
setMaxLevel(GLuint maxLevel)175 bool TextureState::setMaxLevel(GLuint maxLevel)
176 {
177 if (mMaxLevel != maxLevel)
178 {
179 mMaxLevel = maxLevel;
180 return true;
181 }
182
183 return false;
184 }
185
186 // Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
187 // According to [OpenGL ES 3.0.5] section 3.8.13 Texture Completeness page 160 any
188 // per-level checks begin at the base-level.
189 // For OpenGL ES2 the base level is always zero.
isCubeComplete() const190 bool TextureState::isCubeComplete() const
191 {
192 ASSERT(mType == TextureType::CubeMap);
193
194 angle::EnumIterator<TextureTarget> face = kCubeMapTextureTargetMin;
195 const ImageDesc &baseImageDesc = getImageDesc(*face, getEffectiveBaseLevel());
196 if (baseImageDesc.size.width == 0 || baseImageDesc.size.width != baseImageDesc.size.height)
197 {
198 return false;
199 }
200
201 ++face;
202
203 for (; face != kAfterCubeMapTextureTargetMax; ++face)
204 {
205 const ImageDesc &faceImageDesc = getImageDesc(*face, getEffectiveBaseLevel());
206 if (faceImageDesc.size.width != baseImageDesc.size.width ||
207 faceImageDesc.size.height != baseImageDesc.size.height ||
208 !Format::SameSized(faceImageDesc.format, baseImageDesc.format))
209 {
210 return false;
211 }
212 }
213
214 return true;
215 }
216
getBaseLevelDesc() const217 const ImageDesc &TextureState::getBaseLevelDesc() const
218 {
219 ASSERT(mType != TextureType::CubeMap || isCubeComplete());
220 return getImageDesc(getBaseImageTarget(), getEffectiveBaseLevel());
221 }
222
setCrop(const Rectangle & rect)223 void TextureState::setCrop(const Rectangle &rect)
224 {
225 mCropRect = rect;
226 }
227
getCrop() const228 const Rectangle &TextureState::getCrop() const
229 {
230 return mCropRect;
231 }
232
setGenerateMipmapHint(GLenum hint)233 void TextureState::setGenerateMipmapHint(GLenum hint)
234 {
235 mGenerateMipmapHint = hint;
236 }
237
getGenerateMipmapHint() const238 GLenum TextureState::getGenerateMipmapHint() const
239 {
240 return mGenerateMipmapHint;
241 }
242
computeRequiredSamplerFormat(const SamplerState & samplerState) const243 SamplerFormat TextureState::computeRequiredSamplerFormat(const SamplerState &samplerState) const
244 {
245 const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), getEffectiveBaseLevel());
246 if ((baseImageDesc.format.info->format == GL_DEPTH_COMPONENT ||
247 baseImageDesc.format.info->format == GL_DEPTH_STENCIL) &&
248 samplerState.getCompareMode() != GL_NONE)
249 {
250 return SamplerFormat::Shadow;
251 }
252 else
253 {
254 switch (baseImageDesc.format.info->componentType)
255 {
256 case GL_UNSIGNED_NORMALIZED:
257 case GL_SIGNED_NORMALIZED:
258 case GL_FLOAT:
259 return SamplerFormat::Float;
260 case GL_INT:
261 return SamplerFormat::Signed;
262 case GL_UNSIGNED_INT:
263 return SamplerFormat::Unsigned;
264 default:
265 return SamplerFormat::InvalidEnum;
266 }
267 }
268 }
269
computeSamplerCompleteness(const SamplerState & samplerState,const State & state) const270 bool TextureState::computeSamplerCompleteness(const SamplerState &samplerState,
271 const State &state) const
272 {
273 if (mBaseLevel > mMaxLevel)
274 {
275 return false;
276 }
277 const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), getEffectiveBaseLevel());
278 if (baseImageDesc.size.width == 0 || baseImageDesc.size.height == 0 ||
279 baseImageDesc.size.depth == 0)
280 {
281 return false;
282 }
283 // The cases where the texture is incomplete because base level is out of range should be
284 // handled by the above condition.
285 ASSERT(mBaseLevel < IMPLEMENTATION_MAX_TEXTURE_LEVELS || mImmutableFormat);
286
287 if (mType == TextureType::CubeMap && baseImageDesc.size.width != baseImageDesc.size.height)
288 {
289 return false;
290 }
291
292 // According to es 3.1 spec, texture is justified as incomplete if sized internalformat is
293 // unfilterable(table 20.11) and filter is not GL_NEAREST(8.16). The default value of minFilter
294 // is NEAREST_MIPMAP_LINEAR and magFilter is LINEAR(table 20.11,). For multismaple texture,
295 // filter state of multisample texture is ignored(11.1.3.3). So it shouldn't be judged as
296 // incomplete texture. So, we ignore filtering for multisample texture completeness here.
297 if (!IsMultisampled(mType) &&
298 !baseImageDesc.format.info->filterSupport(state.getClientVersion(),
299 state.getExtensions()) &&
300 !IsPointSampled(samplerState))
301 {
302 return false;
303 }
304 bool npotSupport = state.getExtensions().textureNPOTOES || state.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 and EXT_EGL_image_external_wrap_modes is not enabled, the texture will be considered
345 // incomplete.
346 // Sampler object state which does not affect sampling for the type of texture bound
347 // to a texture unit, such as TEXTURE_WRAP_R for an external texture, does not affect
348 // completeness.
349 if (mType == TextureType::External)
350 {
351 if (!state.getExtensions().eglImageExternalWrapModesEXT)
352 {
353 if (samplerState.getWrapS() != GL_CLAMP_TO_EDGE ||
354 samplerState.getWrapT() != GL_CLAMP_TO_EDGE)
355 {
356 return false;
357 }
358 }
359
360 if (samplerState.getMinFilter() != GL_LINEAR && samplerState.getMinFilter() != GL_NEAREST)
361 {
362 return false;
363 }
364 }
365
366 // OpenGLES 3.0.2 spec section 3.8.13 states that a texture is not mipmap complete if:
367 // The internalformat specified for the texture arrays is a sized internal depth or
368 // depth and stencil format (see table 3.13), the value of TEXTURE_COMPARE_-
369 // MODE is NONE, and either the magnification filter is not NEAREST or the mini-
370 // fication filter is neither NEAREST nor NEAREST_MIPMAP_NEAREST.
371 if (!IsMultisampled(mType) && baseImageDesc.format.info->depthBits > 0 &&
372 state.getClientMajorVersion() >= 3)
373 {
374 // Note: we restrict this validation to sized types. For the OES_depth_textures
375 // extension, due to some underspecification problems, we must allow linear filtering
376 // for legacy compatibility with WebGL 1.
377 // See http://crbug.com/649200
378 if (samplerState.getCompareMode() == GL_NONE && baseImageDesc.format.info->sized)
379 {
380 if ((samplerState.getMinFilter() != GL_NEAREST &&
381 samplerState.getMinFilter() != GL_NEAREST_MIPMAP_NEAREST) ||
382 samplerState.getMagFilter() != GL_NEAREST)
383 {
384 return false;
385 }
386 }
387 }
388
389 // OpenGLES 3.1 spec section 8.16 states that a texture is not mipmap complete if:
390 // The internalformat specified for the texture is DEPTH_STENCIL format, the value of
391 // DEPTH_STENCIL_TEXTURE_MODE is STENCIL_INDEX, and either the magnification filter is
392 // not NEAREST or the minification filter is neither NEAREST nor NEAREST_MIPMAP_NEAREST.
393 // However, the ES 3.1 spec differs from the statement above, because it is incorrect.
394 // See the issue at https://github.com/KhronosGroup/OpenGL-API/issues/33.
395 // For multismaple texture, filter state of multisample texture is ignored(11.1.3.3).
396 // So it shouldn't be judged as incomplete texture. So, we ignore filtering for multisample
397 // texture completeness here.
398 if (!IsMultisampled(mType) && baseImageDesc.format.info->depthBits > 0 &&
399 mDepthStencilTextureMode == GL_STENCIL_INDEX)
400 {
401 if ((samplerState.getMinFilter() != GL_NEAREST &&
402 samplerState.getMinFilter() != GL_NEAREST_MIPMAP_NEAREST) ||
403 samplerState.getMagFilter() != GL_NEAREST)
404 {
405 return false;
406 }
407 }
408
409 return true;
410 }
411
computeMipmapCompleteness() const412 bool TextureState::computeMipmapCompleteness() const
413 {
414 const GLuint maxLevel = getMipmapMaxLevel();
415
416 for (GLuint level = getEffectiveBaseLevel(); level <= maxLevel; level++)
417 {
418 if (mType == TextureType::CubeMap)
419 {
420 for (TextureTarget face : AllCubeFaceTextureTargets())
421 {
422 if (!computeLevelCompleteness(face, level))
423 {
424 return false;
425 }
426 }
427 }
428 else
429 {
430 if (!computeLevelCompleteness(NonCubeTextureTypeToTarget(mType), level))
431 {
432 return false;
433 }
434 }
435 }
436
437 return true;
438 }
439
computeLevelCompleteness(TextureTarget target,size_t level) const440 bool TextureState::computeLevelCompleteness(TextureTarget target, size_t level) const
441 {
442 ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
443
444 if (mImmutableFormat)
445 {
446 return true;
447 }
448
449 const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), getEffectiveBaseLevel());
450 if (baseImageDesc.size.width == 0 || baseImageDesc.size.height == 0 ||
451 baseImageDesc.size.depth == 0)
452 {
453 return false;
454 }
455
456 const ImageDesc &levelImageDesc = getImageDesc(target, level);
457 if (levelImageDesc.size.width == 0 || levelImageDesc.size.height == 0 ||
458 levelImageDesc.size.depth == 0)
459 {
460 return false;
461 }
462
463 if (!Format::SameSized(levelImageDesc.format, baseImageDesc.format))
464 {
465 return false;
466 }
467
468 ASSERT(level >= getEffectiveBaseLevel());
469 const size_t relativeLevel = level - getEffectiveBaseLevel();
470 if (levelImageDesc.size.width != std::max(1, baseImageDesc.size.width >> relativeLevel))
471 {
472 return false;
473 }
474
475 if (levelImageDesc.size.height != std::max(1, baseImageDesc.size.height >> relativeLevel))
476 {
477 return false;
478 }
479
480 if (mType == TextureType::_3D)
481 {
482 if (levelImageDesc.size.depth != std::max(1, baseImageDesc.size.depth >> relativeLevel))
483 {
484 return false;
485 }
486 }
487 else if (mType == TextureType::_2DArray)
488 {
489 if (levelImageDesc.size.depth != baseImageDesc.size.depth)
490 {
491 return false;
492 }
493 }
494
495 return true;
496 }
497
getBaseImageTarget() const498 TextureTarget TextureState::getBaseImageTarget() const
499 {
500 return mType == TextureType::CubeMap ? kCubeMapTextureTargetMin
501 : NonCubeTextureTypeToTarget(mType);
502 }
503
getEnabledLevelCount() const504 GLuint TextureState::getEnabledLevelCount() const
505 {
506 GLuint levelCount = 0;
507 const GLuint baseLevel = getEffectiveBaseLevel();
508 const GLuint maxLevel = std::min(getEffectiveMaxLevel(), getMipmapMaxLevel());
509
510 // The mip chain will have either one or more sequential levels, or max levels,
511 // but not a sparse one.
512 for (size_t descIndex = baseLevel; descIndex < mImageDescs.size();)
513 {
514 if (!mImageDescs[descIndex].size.empty())
515 {
516 levelCount++;
517 }
518 descIndex = (mType == TextureType::CubeMap) ? descIndex + 6 : descIndex + 1;
519 }
520 // The original image already takes account into the levelCount.
521 levelCount = std::min(maxLevel - baseLevel + 1, levelCount);
522
523 return levelCount;
524 }
525
ImageDesc()526 ImageDesc::ImageDesc()
527 : ImageDesc(Extents(0, 0, 0), Format::Invalid(), 0, GL_TRUE, InitState::MayNeedInit)
528 {}
529
ImageDesc(const Extents & size,const Format & format,const InitState initState)530 ImageDesc::ImageDesc(const Extents &size, const Format &format, const InitState initState)
531 : size(size), format(format), samples(0), fixedSampleLocations(GL_TRUE), initState(initState)
532 {}
533
ImageDesc(const Extents & size,const Format & format,const GLsizei samples,const bool fixedSampleLocations,const InitState initState)534 ImageDesc::ImageDesc(const Extents &size,
535 const Format &format,
536 const GLsizei samples,
537 const bool fixedSampleLocations,
538 const InitState initState)
539 : size(size),
540 format(format),
541 samples(samples),
542 fixedSampleLocations(fixedSampleLocations),
543 initState(initState)
544 {}
545
getMemorySize() const546 GLint ImageDesc::getMemorySize() const
547 {
548 // Assume allocated size is around width * height * depth * samples * pixelBytes
549 angle::CheckedNumeric<GLint> levelSize = 1;
550 levelSize *= format.info->pixelBytes;
551 levelSize *= size.width;
552 levelSize *= size.height;
553 levelSize *= size.depth;
554 levelSize *= std::max(samples, 1);
555 return levelSize.ValueOrDefault(std::numeric_limits<GLint>::max());
556 }
557
getImageDesc(TextureTarget target,size_t level) const558 const ImageDesc &TextureState::getImageDesc(TextureTarget target, size_t level) const
559 {
560 size_t descIndex = GetImageDescIndex(target, level);
561 ASSERT(descIndex < mImageDescs.size());
562 return mImageDescs[descIndex];
563 }
564
setImageDesc(TextureTarget target,size_t level,const ImageDesc & desc)565 void TextureState::setImageDesc(TextureTarget target, size_t level, const ImageDesc &desc)
566 {
567 size_t descIndex = GetImageDescIndex(target, level);
568 ASSERT(descIndex < mImageDescs.size());
569 mImageDescs[descIndex] = desc;
570 if (desc.initState == InitState::MayNeedInit)
571 {
572 mInitState = InitState::MayNeedInit;
573 }
574 }
575
576 // Note that an ImageIndex that represents an entire level of a cube map corresponds to 6
577 // ImageDescs, so if the cube map is cube complete, we return the ImageDesc of the first cube
578 // face, and we don't allow using this function when the cube map is not cube complete.
getImageDesc(const ImageIndex & imageIndex) const579 const ImageDesc &TextureState::getImageDesc(const ImageIndex &imageIndex) const
580 {
581 if (imageIndex.isEntireLevelCubeMap())
582 {
583 ASSERT(isCubeComplete());
584 const GLint levelIndex = imageIndex.getLevelIndex();
585 return getImageDesc(kCubeMapTextureTargetMin, levelIndex);
586 }
587
588 return getImageDesc(imageIndex.getTarget(), imageIndex.getLevelIndex());
589 }
590
setImageDescChain(GLuint baseLevel,GLuint maxLevel,Extents baseSize,const Format & format,InitState initState)591 void TextureState::setImageDescChain(GLuint baseLevel,
592 GLuint maxLevel,
593 Extents baseSize,
594 const Format &format,
595 InitState initState)
596 {
597 for (GLuint level = baseLevel; level <= maxLevel; level++)
598 {
599 int relativeLevel = (level - baseLevel);
600 Extents levelSize(std::max<int>(baseSize.width >> relativeLevel, 1),
601 std::max<int>(baseSize.height >> relativeLevel, 1),
602 (mType == TextureType::_2DArray)
603 ? baseSize.depth
604 : std::max<int>(baseSize.depth >> relativeLevel, 1));
605 ImageDesc levelInfo(levelSize, format, initState);
606
607 if (mType == TextureType::CubeMap)
608 {
609 for (TextureTarget face : AllCubeFaceTextureTargets())
610 {
611 setImageDesc(face, level, levelInfo);
612 }
613 }
614 else
615 {
616 setImageDesc(NonCubeTextureTypeToTarget(mType), level, levelInfo);
617 }
618 }
619 }
620
setImageDescChainMultisample(Extents baseSize,const Format & format,GLsizei samples,bool fixedSampleLocations,InitState initState)621 void TextureState::setImageDescChainMultisample(Extents baseSize,
622 const Format &format,
623 GLsizei samples,
624 bool fixedSampleLocations,
625 InitState initState)
626 {
627 ASSERT(mType == TextureType::_2DMultisample || mType == TextureType::_2DMultisampleArray);
628 ImageDesc levelInfo(baseSize, format, samples, fixedSampleLocations, initState);
629 setImageDesc(NonCubeTextureTypeToTarget(mType), 0, levelInfo);
630 }
631
clearImageDesc(TextureTarget target,size_t level)632 void TextureState::clearImageDesc(TextureTarget target, size_t level)
633 {
634 setImageDesc(target, level, ImageDesc());
635 }
636
clearImageDescs()637 void TextureState::clearImageDescs()
638 {
639 for (size_t descIndex = 0; descIndex < mImageDescs.size(); descIndex++)
640 {
641 mImageDescs[descIndex] = ImageDesc();
642 }
643 }
644
Texture(rx::GLImplFactory * factory,TextureID id,TextureType type)645 Texture::Texture(rx::GLImplFactory *factory, TextureID id, TextureType type)
646 : RefCountObject(factory->generateSerial(), id),
647 mState(type),
648 mTexture(factory->createTexture(mState)),
649 mImplObserver(this, rx::kTextureImageImplObserverMessageIndex),
650 mLabel(),
651 mBoundSurface(nullptr),
652 mBoundStream(nullptr)
653 {
654 mImplObserver.bind(mTexture);
655
656 // Initially assume the implementation is dirty.
657 mDirtyBits.set(DIRTY_BIT_IMPLEMENTATION);
658 }
659
onDestroy(const Context * context)660 void Texture::onDestroy(const Context *context)
661 {
662 if (mBoundSurface)
663 {
664 ANGLE_SWALLOW_ERR(mBoundSurface->releaseTexImage(context, EGL_BACK_BUFFER));
665 mBoundSurface = nullptr;
666 }
667 if (mBoundStream)
668 {
669 mBoundStream->releaseTextures();
670 mBoundStream = nullptr;
671 }
672
673 (void)(orphanImages(context));
674
675 if (mTexture)
676 {
677 mTexture->onDestroy(context);
678 }
679 }
680
~Texture()681 Texture::~Texture()
682 {
683 SafeDelete(mTexture);
684 }
685
setLabel(const Context * context,const std::string & label)686 void Texture::setLabel(const Context *context, const std::string &label)
687 {
688 mLabel = label;
689 signalDirtyState(DIRTY_BIT_LABEL);
690 }
691
getLabel() const692 const std::string &Texture::getLabel() const
693 {
694 return mLabel;
695 }
696
setSwizzleRed(const Context * context,GLenum swizzleRed)697 void Texture::setSwizzleRed(const Context *context, GLenum swizzleRed)
698 {
699 mState.mSwizzleState.swizzleRed = swizzleRed;
700 signalDirtyState(DIRTY_BIT_SWIZZLE_RED);
701 }
702
getSwizzleRed() const703 GLenum Texture::getSwizzleRed() const
704 {
705 return mState.mSwizzleState.swizzleRed;
706 }
707
setSwizzleGreen(const Context * context,GLenum swizzleGreen)708 void Texture::setSwizzleGreen(const Context *context, GLenum swizzleGreen)
709 {
710 mState.mSwizzleState.swizzleGreen = swizzleGreen;
711 signalDirtyState(DIRTY_BIT_SWIZZLE_GREEN);
712 }
713
getSwizzleGreen() const714 GLenum Texture::getSwizzleGreen() const
715 {
716 return mState.mSwizzleState.swizzleGreen;
717 }
718
setSwizzleBlue(const Context * context,GLenum swizzleBlue)719 void Texture::setSwizzleBlue(const Context *context, GLenum swizzleBlue)
720 {
721 mState.mSwizzleState.swizzleBlue = swizzleBlue;
722 signalDirtyState(DIRTY_BIT_SWIZZLE_BLUE);
723 }
724
getSwizzleBlue() const725 GLenum Texture::getSwizzleBlue() const
726 {
727 return mState.mSwizzleState.swizzleBlue;
728 }
729
setSwizzleAlpha(const Context * context,GLenum swizzleAlpha)730 void Texture::setSwizzleAlpha(const Context *context, GLenum swizzleAlpha)
731 {
732 mState.mSwizzleState.swizzleAlpha = swizzleAlpha;
733 signalDirtyState(DIRTY_BIT_SWIZZLE_ALPHA);
734 }
735
getSwizzleAlpha() const736 GLenum Texture::getSwizzleAlpha() const
737 {
738 return mState.mSwizzleState.swizzleAlpha;
739 }
740
setMinFilter(const Context * context,GLenum minFilter)741 void Texture::setMinFilter(const Context *context, GLenum minFilter)
742 {
743 mState.mSamplerState.setMinFilter(minFilter);
744 signalDirtyState(DIRTY_BIT_MIN_FILTER);
745 }
746
getMinFilter() const747 GLenum Texture::getMinFilter() const
748 {
749 return mState.mSamplerState.getMinFilter();
750 }
751
setMagFilter(const Context * context,GLenum magFilter)752 void Texture::setMagFilter(const Context *context, GLenum magFilter)
753 {
754 mState.mSamplerState.setMagFilter(magFilter);
755 signalDirtyState(DIRTY_BIT_MAG_FILTER);
756 }
757
getMagFilter() const758 GLenum Texture::getMagFilter() const
759 {
760 return mState.mSamplerState.getMagFilter();
761 }
762
setWrapS(const Context * context,GLenum wrapS)763 void Texture::setWrapS(const Context *context, GLenum wrapS)
764 {
765 mState.mSamplerState.setWrapS(wrapS);
766 signalDirtyState(DIRTY_BIT_WRAP_S);
767 }
768
getWrapS() const769 GLenum Texture::getWrapS() const
770 {
771 return mState.mSamplerState.getWrapS();
772 }
773
setWrapT(const Context * context,GLenum wrapT)774 void Texture::setWrapT(const Context *context, GLenum wrapT)
775 {
776 mState.mSamplerState.setWrapT(wrapT);
777 signalDirtyState(DIRTY_BIT_WRAP_T);
778 }
779
getWrapT() const780 GLenum Texture::getWrapT() const
781 {
782 return mState.mSamplerState.getWrapT();
783 }
784
setWrapR(const Context * context,GLenum wrapR)785 void Texture::setWrapR(const Context *context, GLenum wrapR)
786 {
787 mState.mSamplerState.setWrapR(wrapR);
788 signalDirtyState(DIRTY_BIT_WRAP_R);
789 }
790
getWrapR() const791 GLenum Texture::getWrapR() const
792 {
793 return mState.mSamplerState.getWrapR();
794 }
795
setMaxAnisotropy(const Context * context,float maxAnisotropy)796 void Texture::setMaxAnisotropy(const Context *context, float maxAnisotropy)
797 {
798 mState.mSamplerState.setMaxAnisotropy(maxAnisotropy);
799 signalDirtyState(DIRTY_BIT_MAX_ANISOTROPY);
800 }
801
getMaxAnisotropy() const802 float Texture::getMaxAnisotropy() const
803 {
804 return mState.mSamplerState.getMaxAnisotropy();
805 }
806
setMinLod(const Context * context,GLfloat minLod)807 void Texture::setMinLod(const Context *context, GLfloat minLod)
808 {
809 mState.mSamplerState.setMinLod(minLod);
810 signalDirtyState(DIRTY_BIT_MIN_LOD);
811 }
812
getMinLod() const813 GLfloat Texture::getMinLod() const
814 {
815 return mState.mSamplerState.getMinLod();
816 }
817
setMaxLod(const Context * context,GLfloat maxLod)818 void Texture::setMaxLod(const Context *context, GLfloat maxLod)
819 {
820 mState.mSamplerState.setMaxLod(maxLod);
821 signalDirtyState(DIRTY_BIT_MAX_LOD);
822 }
823
getMaxLod() const824 GLfloat Texture::getMaxLod() const
825 {
826 return mState.mSamplerState.getMaxLod();
827 }
828
setCompareMode(const Context * context,GLenum compareMode)829 void Texture::setCompareMode(const Context *context, GLenum compareMode)
830 {
831 mState.mSamplerState.setCompareMode(compareMode);
832 signalDirtyState(DIRTY_BIT_COMPARE_MODE);
833 }
834
getCompareMode() const835 GLenum Texture::getCompareMode() const
836 {
837 return mState.mSamplerState.getCompareMode();
838 }
839
setCompareFunc(const Context * context,GLenum compareFunc)840 void Texture::setCompareFunc(const Context *context, GLenum compareFunc)
841 {
842 mState.mSamplerState.setCompareFunc(compareFunc);
843 signalDirtyState(DIRTY_BIT_COMPARE_FUNC);
844 }
845
getCompareFunc() const846 GLenum Texture::getCompareFunc() const
847 {
848 return mState.mSamplerState.getCompareFunc();
849 }
850
setSRGBDecode(const Context * context,GLenum sRGBDecode)851 void Texture::setSRGBDecode(const Context *context, GLenum sRGBDecode)
852 {
853 mState.mSamplerState.setSRGBDecode(sRGBDecode);
854 signalDirtyState(DIRTY_BIT_SRGB_DECODE);
855 }
856
getSRGBDecode() const857 GLenum Texture::getSRGBDecode() const
858 {
859 return mState.mSamplerState.getSRGBDecode();
860 }
861
getSamplerState() const862 const SamplerState &Texture::getSamplerState() const
863 {
864 return mState.mSamplerState;
865 }
866
setBaseLevel(const Context * context,GLuint baseLevel)867 angle::Result Texture::setBaseLevel(const Context *context, GLuint baseLevel)
868 {
869 if (mState.setBaseLevel(baseLevel))
870 {
871 ANGLE_TRY(mTexture->setBaseLevel(context, mState.getEffectiveBaseLevel()));
872 signalDirtyState(DIRTY_BIT_BASE_LEVEL);
873 }
874
875 return angle::Result::Continue;
876 }
877
getBaseLevel() const878 GLuint Texture::getBaseLevel() const
879 {
880 return mState.mBaseLevel;
881 }
882
setMaxLevel(const Context * context,GLuint maxLevel)883 void Texture::setMaxLevel(const Context *context, GLuint maxLevel)
884 {
885 if (mState.setMaxLevel(maxLevel))
886 {
887 signalDirtyState(DIRTY_BIT_MAX_LEVEL);
888 }
889 }
890
getMaxLevel() const891 GLuint Texture::getMaxLevel() const
892 {
893 return mState.mMaxLevel;
894 }
895
setDepthStencilTextureMode(const Context * context,GLenum mode)896 void Texture::setDepthStencilTextureMode(const Context *context, GLenum mode)
897 {
898 if (mState.mDepthStencilTextureMode != mode)
899 {
900 mState.mDepthStencilTextureMode = mode;
901 signalDirtyState(DIRTY_BIT_DEPTH_STENCIL_TEXTURE_MODE);
902 }
903 }
904
getDepthStencilTextureMode() const905 GLenum Texture::getDepthStencilTextureMode() const
906 {
907 return mState.mDepthStencilTextureMode;
908 }
909
getImmutableFormat() const910 bool Texture::getImmutableFormat() const
911 {
912 return mState.mImmutableFormat;
913 }
914
getImmutableLevels() const915 GLuint Texture::getImmutableLevels() const
916 {
917 return mState.mImmutableLevels;
918 }
919
setUsage(const Context * context,GLenum usage)920 void Texture::setUsage(const Context *context, GLenum usage)
921 {
922 mState.mUsage = usage;
923 signalDirtyState(DIRTY_BIT_USAGE);
924 }
925
getUsage() const926 GLenum Texture::getUsage() const
927 {
928 return mState.mUsage;
929 }
930
getTextureState() const931 const TextureState &Texture::getTextureState() const
932 {
933 return mState;
934 }
935
getExtents(TextureTarget target,size_t level) const936 const Extents &Texture::getExtents(TextureTarget target, size_t level) const
937 {
938 ASSERT(TextureTargetToType(target) == mState.mType);
939 return mState.getImageDesc(target, level).size;
940 }
941
getWidth(TextureTarget target,size_t level) const942 size_t Texture::getWidth(TextureTarget target, size_t level) const
943 {
944 ASSERT(TextureTargetToType(target) == mState.mType);
945 return mState.getImageDesc(target, level).size.width;
946 }
947
getHeight(TextureTarget target,size_t level) const948 size_t Texture::getHeight(TextureTarget target, size_t level) const
949 {
950 ASSERT(TextureTargetToType(target) == mState.mType);
951 return mState.getImageDesc(target, level).size.height;
952 }
953
getDepth(TextureTarget target,size_t level) const954 size_t Texture::getDepth(TextureTarget target, size_t level) const
955 {
956 ASSERT(TextureTargetToType(target) == mState.mType);
957 return mState.getImageDesc(target, level).size.depth;
958 }
959
getFormat(TextureTarget target,size_t level) const960 const Format &Texture::getFormat(TextureTarget target, size_t level) const
961 {
962 ASSERT(TextureTargetToType(target) == mState.mType);
963 return mState.getImageDesc(target, level).format;
964 }
965
getSamples(TextureTarget target,size_t level) const966 GLsizei Texture::getSamples(TextureTarget target, size_t level) const
967 {
968 ASSERT(TextureTargetToType(target) == mState.mType);
969 return mState.getImageDesc(target, level).samples;
970 }
971
getFixedSampleLocations(TextureTarget target,size_t level) const972 bool Texture::getFixedSampleLocations(TextureTarget target, size_t level) const
973 {
974 ASSERT(TextureTargetToType(target) == mState.mType);
975 return mState.getImageDesc(target, level).fixedSampleLocations;
976 }
977
getMipmapMaxLevel() const978 GLuint Texture::getMipmapMaxLevel() const
979 {
980 return mState.getMipmapMaxLevel();
981 }
982
isMipmapComplete() const983 bool Texture::isMipmapComplete() const
984 {
985 return mState.computeMipmapCompleteness();
986 }
987
getBoundSurface() const988 egl::Surface *Texture::getBoundSurface() const
989 {
990 return mBoundSurface;
991 }
992
getBoundStream() const993 egl::Stream *Texture::getBoundStream() const
994 {
995 return mBoundStream;
996 }
997
getMemorySize() const998 GLint Texture::getMemorySize() const
999 {
1000 GLint implSize = mTexture->getMemorySize();
1001 if (implSize > 0)
1002 {
1003 return implSize;
1004 }
1005
1006 angle::CheckedNumeric<GLint> size = 0;
1007 for (const ImageDesc &imageDesc : mState.mImageDescs)
1008 {
1009 size += imageDesc.getMemorySize();
1010 }
1011 return size.ValueOrDefault(std::numeric_limits<GLint>::max());
1012 }
1013
getLevelMemorySize(TextureTarget target,GLint level) const1014 GLint Texture::getLevelMemorySize(TextureTarget target, GLint level) const
1015 {
1016 GLint implSize = mTexture->getLevelMemorySize(target, level);
1017 if (implSize > 0)
1018 {
1019 return implSize;
1020 }
1021
1022 return mState.getImageDesc(target, level).getMemorySize();
1023 }
1024
signalDirtyStorage(InitState initState)1025 void Texture::signalDirtyStorage(InitState initState)
1026 {
1027 mState.mInitState = initState;
1028 invalidateCompletenessCache();
1029 mState.mCachedSamplerFormatValid = false;
1030 onStateChange(angle::SubjectMessage::SubjectChanged);
1031 }
1032
signalDirtyState(size_t dirtyBit)1033 void Texture::signalDirtyState(size_t dirtyBit)
1034 {
1035 mDirtyBits.set(dirtyBit);
1036 invalidateCompletenessCache();
1037 mState.mCachedSamplerFormatValid = false;
1038 onStateChange(angle::SubjectMessage::DirtyBitsFlagged);
1039 }
1040
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)1041 angle::Result Texture::setImage(Context *context,
1042 const PixelUnpackState &unpackState,
1043 Buffer *unpackBuffer,
1044 TextureTarget target,
1045 GLint level,
1046 GLenum internalFormat,
1047 const Extents &size,
1048 GLenum format,
1049 GLenum type,
1050 const uint8_t *pixels)
1051 {
1052 ASSERT(TextureTargetToType(target) == mState.mType);
1053
1054 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1055 ANGLE_TRY(releaseTexImageInternal(context));
1056 ANGLE_TRY(orphanImages(context));
1057
1058 ImageIndex index = ImageIndex::MakeFromTarget(target, level, size.depth);
1059
1060 ANGLE_TRY(mTexture->setImage(context, index, internalFormat, size, format, type, unpackState,
1061 unpackBuffer, pixels));
1062
1063 InitState initState = DetermineInitState(context, unpackBuffer, pixels);
1064 mState.setImageDesc(target, level, ImageDesc(size, Format(internalFormat, type), initState));
1065
1066 ANGLE_TRY(handleMipmapGenerationHint(context, level));
1067
1068 signalDirtyStorage(initState);
1069
1070 return angle::Result::Continue;
1071 }
1072
setSubImage(Context * context,const PixelUnpackState & unpackState,Buffer * unpackBuffer,TextureTarget target,GLint level,const Box & area,GLenum format,GLenum type,const uint8_t * pixels)1073 angle::Result Texture::setSubImage(Context *context,
1074 const PixelUnpackState &unpackState,
1075 Buffer *unpackBuffer,
1076 TextureTarget target,
1077 GLint level,
1078 const Box &area,
1079 GLenum format,
1080 GLenum type,
1081 const uint8_t *pixels)
1082 {
1083 ASSERT(TextureTargetToType(target) == mState.mType);
1084
1085 ImageIndex index = ImageIndex::MakeFromTarget(target, level, area.depth);
1086 ANGLE_TRY(ensureSubImageInitialized(context, index, area));
1087
1088 ANGLE_TRY(mTexture->setSubImage(context, index, area, format, type, unpackState, unpackBuffer,
1089 pixels));
1090
1091 ANGLE_TRY(handleMipmapGenerationHint(context, level));
1092
1093 onStateChange(angle::SubjectMessage::ContentsChanged);
1094
1095 return angle::Result::Continue;
1096 }
1097
setCompressedImage(Context * context,const PixelUnpackState & unpackState,TextureTarget target,GLint level,GLenum internalFormat,const Extents & size,size_t imageSize,const uint8_t * pixels)1098 angle::Result Texture::setCompressedImage(Context *context,
1099 const PixelUnpackState &unpackState,
1100 TextureTarget target,
1101 GLint level,
1102 GLenum internalFormat,
1103 const Extents &size,
1104 size_t imageSize,
1105 const uint8_t *pixels)
1106 {
1107 ASSERT(TextureTargetToType(target) == mState.mType);
1108
1109 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1110 ANGLE_TRY(releaseTexImageInternal(context));
1111 ANGLE_TRY(orphanImages(context));
1112
1113 ImageIndex index = ImageIndex::MakeFromTarget(target, level, size.depth);
1114
1115 ANGLE_TRY(mTexture->setCompressedImage(context, index, internalFormat, size, unpackState,
1116 imageSize, pixels));
1117
1118 Buffer *unpackBuffer = context->getState().getTargetBuffer(BufferBinding::PixelUnpack);
1119
1120 InitState initState = DetermineInitState(context, unpackBuffer, pixels);
1121 mState.setImageDesc(target, level, ImageDesc(size, Format(internalFormat), initState));
1122 signalDirtyStorage(initState);
1123
1124 return angle::Result::Continue;
1125 }
1126
setCompressedSubImage(const Context * context,const PixelUnpackState & unpackState,TextureTarget target,GLint level,const Box & area,GLenum format,size_t imageSize,const uint8_t * pixels)1127 angle::Result Texture::setCompressedSubImage(const Context *context,
1128 const PixelUnpackState &unpackState,
1129 TextureTarget target,
1130 GLint level,
1131 const Box &area,
1132 GLenum format,
1133 size_t imageSize,
1134 const uint8_t *pixels)
1135 {
1136 ASSERT(TextureTargetToType(target) == mState.mType);
1137
1138 ImageIndex index = ImageIndex::MakeFromTarget(target, level, area.depth);
1139 ANGLE_TRY(ensureSubImageInitialized(context, index, area));
1140
1141 ANGLE_TRY(mTexture->setCompressedSubImage(context, index, area, format, unpackState, imageSize,
1142 pixels));
1143
1144 onStateChange(angle::SubjectMessage::ContentsChanged);
1145
1146 return angle::Result::Continue;
1147 }
1148
copyImage(Context * context,TextureTarget target,GLint level,const Rectangle & sourceArea,GLenum internalFormat,Framebuffer * source)1149 angle::Result Texture::copyImage(Context *context,
1150 TextureTarget target,
1151 GLint level,
1152 const Rectangle &sourceArea,
1153 GLenum internalFormat,
1154 Framebuffer *source)
1155 {
1156 ASSERT(TextureTargetToType(target) == mState.mType);
1157
1158 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1159 ANGLE_TRY(releaseTexImageInternal(context));
1160 ANGLE_TRY(orphanImages(context));
1161
1162 ImageIndex index = ImageIndex::MakeFromTarget(target, level, 1);
1163
1164 const InternalFormat &internalFormatInfo =
1165 GetInternalFormatInfo(internalFormat, GL_UNSIGNED_BYTE);
1166
1167 // Most if not all renderers clip these copies to the size of the source framebuffer, leaving
1168 // other pixels untouched. For safety in robust resource initialization, assume that that
1169 // clipping is going to occur when computing the region for which to ensure initialization. If
1170 // the copy lies entirely off the source framebuffer, initialize as though a zero-size box is
1171 // going to be set during the copy operation.
1172 Box destBox;
1173 if (context->isRobustResourceInitEnabled())
1174 {
1175 Extents fbSize = source->getReadColorAttachment()->getSize();
1176 Rectangle clippedArea;
1177 if (ClipRectangle(sourceArea, Rectangle(0, 0, fbSize.width, fbSize.height), &clippedArea))
1178 {
1179 const Offset clippedOffset(clippedArea.x - sourceArea.x, clippedArea.y - sourceArea.y,
1180 0);
1181 destBox = Box(clippedOffset.x, clippedOffset.y, clippedOffset.z, clippedArea.width,
1182 clippedArea.height, 1);
1183 }
1184 }
1185
1186 // If we need to initialize the destination texture we split the call into a create call,
1187 // an initializeContents call, and then a copySubImage call. This ensures the destination
1188 // texture exists before we try to clear it.
1189 Extents size(sourceArea.width, sourceArea.height, 1);
1190 if (doesSubImageNeedInit(context, index, destBox))
1191 {
1192 ANGLE_TRY(mTexture->setImage(context, index, internalFormat, size,
1193 internalFormatInfo.format, internalFormatInfo.type,
1194 PixelUnpackState(), nullptr, nullptr));
1195 mState.setImageDesc(target, level,
1196 ImageDesc(size, Format(internalFormatInfo), InitState::MayNeedInit));
1197 ANGLE_TRY(ensureSubImageInitialized(context, index, destBox));
1198 ANGLE_TRY(mTexture->copySubImage(context, index, Offset(), sourceArea, source));
1199 }
1200 else
1201 {
1202 ANGLE_TRY(mTexture->copyImage(context, index, sourceArea, internalFormat, source));
1203 }
1204
1205 mState.setImageDesc(target, level,
1206 ImageDesc(size, Format(internalFormatInfo), InitState::Initialized));
1207
1208 ANGLE_TRY(handleMipmapGenerationHint(context, level));
1209
1210 // Because this could affect the texture storage we might need to init other layers/levels.
1211 signalDirtyStorage(InitState::MayNeedInit);
1212
1213 return angle::Result::Continue;
1214 }
1215
copySubImage(Context * context,const ImageIndex & index,const Offset & destOffset,const Rectangle & sourceArea,Framebuffer * source)1216 angle::Result Texture::copySubImage(Context *context,
1217 const ImageIndex &index,
1218 const Offset &destOffset,
1219 const Rectangle &sourceArea,
1220 Framebuffer *source)
1221 {
1222 ASSERT(TextureTargetToType(index.getTarget()) == mState.mType);
1223
1224 // Most if not all renderers clip these copies to the size of the source framebuffer, leaving
1225 // other pixels untouched. For safety in robust resource initialization, assume that that
1226 // clipping is going to occur when computing the region for which to ensure initialization. If
1227 // the copy lies entirely off the source framebuffer, initialize as though a zero-size box is
1228 // going to be set during the copy operation. Note that this assumes that
1229 // ensureSubImageInitialized ensures initialization of the entire destination texture, and not
1230 // just a sub-region.
1231 Box destBox;
1232 if (context->isRobustResourceInitEnabled())
1233 {
1234 Extents fbSize = source->getReadColorAttachment()->getSize();
1235 Rectangle clippedArea;
1236 if (ClipRectangle(sourceArea, Rectangle(0, 0, fbSize.width, fbSize.height), &clippedArea))
1237 {
1238 const Offset clippedOffset(destOffset.x + clippedArea.x - sourceArea.x,
1239 destOffset.y + clippedArea.y - sourceArea.y, 0);
1240 destBox = Box(clippedOffset.x, clippedOffset.y, clippedOffset.z, clippedArea.width,
1241 clippedArea.height, 1);
1242 }
1243 }
1244
1245 ANGLE_TRY(ensureSubImageInitialized(context, index, destBox));
1246
1247 ANGLE_TRY(mTexture->copySubImage(context, index, destOffset, sourceArea, source));
1248 ANGLE_TRY(handleMipmapGenerationHint(context, index.getLevelIndex()));
1249
1250 onStateChange(angle::SubjectMessage::ContentsChanged);
1251
1252 return angle::Result::Continue;
1253 }
1254
copyTexture(Context * context,TextureTarget target,GLint level,GLenum internalFormat,GLenum type,GLint sourceLevel,bool unpackFlipY,bool unpackPremultiplyAlpha,bool unpackUnmultiplyAlpha,Texture * source)1255 angle::Result Texture::copyTexture(Context *context,
1256 TextureTarget target,
1257 GLint level,
1258 GLenum internalFormat,
1259 GLenum type,
1260 GLint sourceLevel,
1261 bool unpackFlipY,
1262 bool unpackPremultiplyAlpha,
1263 bool unpackUnmultiplyAlpha,
1264 Texture *source)
1265 {
1266 ASSERT(TextureTargetToType(target) == mState.mType);
1267 ASSERT(source->getType() != TextureType::CubeMap);
1268
1269 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1270 ANGLE_TRY(releaseTexImageInternal(context));
1271 ANGLE_TRY(orphanImages(context));
1272
1273 // Initialize source texture.
1274 // Note: we don't have a way to notify which portions of the image changed currently.
1275 ANGLE_TRY(source->ensureInitialized(context));
1276
1277 ImageIndex index = ImageIndex::MakeFromTarget(target, level, ImageIndex::kEntireLevel);
1278
1279 ANGLE_TRY(mTexture->copyTexture(context, index, internalFormat, type, sourceLevel, unpackFlipY,
1280 unpackPremultiplyAlpha, unpackUnmultiplyAlpha, source));
1281
1282 const auto &sourceDesc =
1283 source->mState.getImageDesc(NonCubeTextureTypeToTarget(source->getType()), 0);
1284 const InternalFormat &internalFormatInfo = GetInternalFormatInfo(internalFormat, type);
1285 mState.setImageDesc(
1286 target, level,
1287 ImageDesc(sourceDesc.size, Format(internalFormatInfo), InitState::Initialized));
1288
1289 signalDirtyStorage(InitState::Initialized);
1290
1291 return angle::Result::Continue;
1292 }
1293
copySubTexture(const Context * context,TextureTarget target,GLint level,const Offset & destOffset,GLint sourceLevel,const Box & sourceBox,bool unpackFlipY,bool unpackPremultiplyAlpha,bool unpackUnmultiplyAlpha,Texture * source)1294 angle::Result Texture::copySubTexture(const Context *context,
1295 TextureTarget target,
1296 GLint level,
1297 const Offset &destOffset,
1298 GLint sourceLevel,
1299 const Box &sourceBox,
1300 bool unpackFlipY,
1301 bool unpackPremultiplyAlpha,
1302 bool unpackUnmultiplyAlpha,
1303 Texture *source)
1304 {
1305 ASSERT(TextureTargetToType(target) == mState.mType);
1306
1307 // Ensure source is initialized.
1308 ANGLE_TRY(source->ensureInitialized(context));
1309
1310 Box destBox(destOffset.x, destOffset.y, destOffset.z, sourceBox.width, sourceBox.height,
1311 sourceBox.depth);
1312 ImageIndex index = ImageIndex::MakeFromTarget(target, level, sourceBox.depth);
1313 ANGLE_TRY(ensureSubImageInitialized(context, index, destBox));
1314
1315 ANGLE_TRY(mTexture->copySubTexture(context, index, destOffset, sourceLevel, sourceBox,
1316 unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha,
1317 source));
1318
1319 onStateChange(angle::SubjectMessage::ContentsChanged);
1320
1321 return angle::Result::Continue;
1322 }
1323
copyCompressedTexture(Context * context,const Texture * source)1324 angle::Result Texture::copyCompressedTexture(Context *context, const Texture *source)
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->copyCompressedTexture(context, source));
1331
1332 ASSERT(source->getType() != TextureType::CubeMap && getType() != TextureType::CubeMap);
1333 const auto &sourceDesc =
1334 source->mState.getImageDesc(NonCubeTextureTypeToTarget(source->getType()), 0);
1335 mState.setImageDesc(NonCubeTextureTypeToTarget(getType()), 0, sourceDesc);
1336
1337 return angle::Result::Continue;
1338 }
1339
setStorage(Context * context,TextureType type,GLsizei levels,GLenum internalFormat,const Extents & size)1340 angle::Result Texture::setStorage(Context *context,
1341 TextureType type,
1342 GLsizei levels,
1343 GLenum internalFormat,
1344 const Extents &size)
1345 {
1346 ASSERT(type == mState.mType);
1347
1348 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1349 ANGLE_TRY(releaseTexImageInternal(context));
1350 ANGLE_TRY(orphanImages(context));
1351
1352 mState.mImmutableFormat = true;
1353 mState.mImmutableLevels = static_cast<GLuint>(levels);
1354
1355 ANGLE_TRY(mTexture->setStorage(context, type, levels, internalFormat, size));
1356
1357 mState.clearImageDescs();
1358 mState.setImageDescChain(0, static_cast<GLuint>(levels - 1), size, Format(internalFormat),
1359 InitState::MayNeedInit);
1360
1361 // Changing the texture to immutable can trigger a change in the base and max levels:
1362 // GLES 3.0.4 section 3.8.10 pg 158:
1363 // "For immutable-format textures, levelbase is clamped to the range[0;levels],levelmax is then
1364 // clamped to the range[levelbase;levels].
1365 mDirtyBits.set(DIRTY_BIT_BASE_LEVEL);
1366 mDirtyBits.set(DIRTY_BIT_MAX_LEVEL);
1367
1368 signalDirtyStorage(InitState::MayNeedInit);
1369
1370 return angle::Result::Continue;
1371 }
1372
setImageExternal(Context * context,TextureTarget target,GLint level,GLenum internalFormat,const Extents & size,GLenum format,GLenum type)1373 angle::Result Texture::setImageExternal(Context *context,
1374 TextureTarget target,
1375 GLint level,
1376 GLenum internalFormat,
1377 const Extents &size,
1378 GLenum format,
1379 GLenum type)
1380 {
1381 ASSERT(TextureTargetToType(target) == mState.mType);
1382
1383 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1384 ANGLE_TRY(releaseTexImageInternal(context));
1385 ANGLE_TRY(orphanImages(context));
1386
1387 ImageIndex index = ImageIndex::MakeFromTarget(target, level, size.depth);
1388
1389 ANGLE_TRY(mTexture->setImageExternal(context, index, internalFormat, size, format, type));
1390
1391 InitState initState = InitState::Initialized;
1392 mState.setImageDesc(target, level, ImageDesc(size, Format(internalFormat, type), initState));
1393
1394 ANGLE_TRY(handleMipmapGenerationHint(context, level));
1395
1396 signalDirtyStorage(initState);
1397
1398 return angle::Result::Continue;
1399 }
1400
setStorageMultisample(Context * context,TextureType type,GLsizei samples,GLint internalFormat,const Extents & size,bool fixedSampleLocations)1401 angle::Result Texture::setStorageMultisample(Context *context,
1402 TextureType type,
1403 GLsizei samples,
1404 GLint internalFormat,
1405 const Extents &size,
1406 bool fixedSampleLocations)
1407 {
1408 ASSERT(type == mState.mType);
1409
1410 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1411 ANGLE_TRY(releaseTexImageInternal(context));
1412 ANGLE_TRY(orphanImages(context));
1413
1414 // Potentially adjust "samples" to a supported value
1415 const TextureCaps &formatCaps = context->getTextureCaps().get(internalFormat);
1416 samples = formatCaps.getNearestSamples(samples);
1417
1418 ANGLE_TRY(mTexture->setStorageMultisample(context, type, samples, internalFormat, size,
1419 fixedSampleLocations));
1420
1421 mState.mImmutableFormat = true;
1422 mState.mImmutableLevels = static_cast<GLuint>(1);
1423 mState.clearImageDescs();
1424 mState.setImageDescChainMultisample(size, Format(internalFormat), samples, fixedSampleLocations,
1425 InitState::MayNeedInit);
1426
1427 signalDirtyStorage(InitState::MayNeedInit);
1428
1429 return angle::Result::Continue;
1430 }
1431
setStorageExternalMemory(Context * context,TextureType type,GLsizei levels,GLenum internalFormat,const Extents & size,MemoryObject * memoryObject,GLuint64 offset)1432 angle::Result Texture::setStorageExternalMemory(Context *context,
1433 TextureType type,
1434 GLsizei levels,
1435 GLenum internalFormat,
1436 const Extents &size,
1437 MemoryObject *memoryObject,
1438 GLuint64 offset)
1439 {
1440 ASSERT(type == mState.mType);
1441
1442 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1443 ANGLE_TRY(releaseTexImageInternal(context));
1444 ANGLE_TRY(orphanImages(context));
1445
1446 ANGLE_TRY(mTexture->setStorageExternalMemory(context, type, levels, internalFormat, size,
1447 memoryObject, offset));
1448
1449 mState.mImmutableFormat = true;
1450 mState.mImmutableLevels = static_cast<GLuint>(levels);
1451 mState.clearImageDescs();
1452 mState.setImageDescChain(0, static_cast<GLuint>(levels - 1), size, Format(internalFormat),
1453 InitState::MayNeedInit);
1454
1455 // Changing the texture to immutable can trigger a change in the base and max levels:
1456 // GLES 3.0.4 section 3.8.10 pg 158:
1457 // "For immutable-format textures, levelbase is clamped to the range[0;levels],levelmax is then
1458 // clamped to the range[levelbase;levels].
1459 mDirtyBits.set(DIRTY_BIT_BASE_LEVEL);
1460 mDirtyBits.set(DIRTY_BIT_MAX_LEVEL);
1461
1462 signalDirtyStorage(InitState::Initialized);
1463
1464 return angle::Result::Continue;
1465 }
1466
generateMipmap(Context * context)1467 angle::Result Texture::generateMipmap(Context *context)
1468 {
1469 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1470 ANGLE_TRY(releaseTexImageInternal(context));
1471
1472 // EGL_KHR_gl_image states that images are only orphaned when generating mipmaps if the texture
1473 // is not mip complete.
1474 if (!isMipmapComplete())
1475 {
1476 ANGLE_TRY(orphanImages(context));
1477 }
1478
1479 const GLuint baseLevel = mState.getEffectiveBaseLevel();
1480 const GLuint maxLevel = mState.getMipmapMaxLevel();
1481
1482 if (maxLevel <= baseLevel)
1483 {
1484 return angle::Result::Continue;
1485 }
1486
1487 if (hasAnyDirtyBit())
1488 {
1489 ANGLE_TRY(syncState(context));
1490 }
1491
1492 // Clear the base image(s) immediately if needed
1493 if (context->isRobustResourceInitEnabled())
1494 {
1495 ImageIndexIterator it =
1496 ImageIndexIterator::MakeGeneric(mState.mType, baseLevel, baseLevel + 1,
1497 ImageIndex::kEntireLevel, ImageIndex::kEntireLevel);
1498 while (it.hasNext())
1499 {
1500 const ImageIndex index = it.next();
1501 const ImageDesc &desc = mState.getImageDesc(index.getTarget(), index.getLevelIndex());
1502
1503 if (desc.initState == InitState::MayNeedInit)
1504 {
1505 ANGLE_TRY(initializeContents(context, index));
1506 }
1507 }
1508 }
1509
1510 ANGLE_TRY(mTexture->generateMipmap(context));
1511
1512 // Propagate the format and size of the bsae mip to the smaller ones. Cube maps are guaranteed
1513 // to have faces of the same size and format so any faces can be picked.
1514 const ImageDesc &baseImageInfo = mState.getImageDesc(mState.getBaseImageTarget(), baseLevel);
1515 mState.setImageDescChain(baseLevel, maxLevel, baseImageInfo.size, baseImageInfo.format,
1516 InitState::Initialized);
1517
1518 signalDirtyStorage(InitState::Initialized);
1519
1520 return angle::Result::Continue;
1521 }
1522
bindTexImageFromSurface(Context * context,egl::Surface * surface)1523 angle::Result Texture::bindTexImageFromSurface(Context *context, egl::Surface *surface)
1524 {
1525 ASSERT(surface);
1526
1527 if (mBoundSurface)
1528 {
1529 ANGLE_TRY(releaseTexImageFromSurface(context));
1530 }
1531
1532 ANGLE_TRY(mTexture->bindTexImage(context, surface));
1533 mBoundSurface = surface;
1534
1535 // Set the image info to the size and format of the surface
1536 ASSERT(mState.mType == TextureType::_2D || mState.mType == TextureType::Rectangle);
1537 Extents size(surface->getWidth(), surface->getHeight(), 1);
1538 ImageDesc desc(size, surface->getBindTexImageFormat(), InitState::Initialized);
1539 mState.setImageDesc(NonCubeTextureTypeToTarget(mState.mType), 0, desc);
1540 signalDirtyStorage(InitState::Initialized);
1541 return angle::Result::Continue;
1542 }
1543
releaseTexImageFromSurface(const Context * context)1544 angle::Result Texture::releaseTexImageFromSurface(const Context *context)
1545 {
1546 ASSERT(mBoundSurface);
1547 mBoundSurface = nullptr;
1548 ANGLE_TRY(mTexture->releaseTexImage(context));
1549
1550 // Erase the image info for level 0
1551 ASSERT(mState.mType == TextureType::_2D || mState.mType == TextureType::Rectangle);
1552 mState.clearImageDesc(NonCubeTextureTypeToTarget(mState.mType), 0);
1553 signalDirtyStorage(InitState::Initialized);
1554 return angle::Result::Continue;
1555 }
1556
bindStream(egl::Stream * stream)1557 void Texture::bindStream(egl::Stream *stream)
1558 {
1559 ASSERT(stream);
1560
1561 // It should not be possible to bind a texture already bound to another stream
1562 ASSERT(mBoundStream == nullptr);
1563
1564 mBoundStream = stream;
1565
1566 ASSERT(mState.mType == TextureType::External);
1567 }
1568
releaseStream()1569 void Texture::releaseStream()
1570 {
1571 ASSERT(mBoundStream);
1572 mBoundStream = nullptr;
1573 }
1574
acquireImageFromStream(const Context * context,const egl::Stream::GLTextureDescription & desc)1575 angle::Result Texture::acquireImageFromStream(const Context *context,
1576 const egl::Stream::GLTextureDescription &desc)
1577 {
1578 ASSERT(mBoundStream != nullptr);
1579 ANGLE_TRY(mTexture->setImageExternal(context, mState.mType, mBoundStream, desc));
1580
1581 Extents size(desc.width, desc.height, 1);
1582 mState.setImageDesc(NonCubeTextureTypeToTarget(mState.mType), 0,
1583 ImageDesc(size, Format(desc.internalFormat), InitState::Initialized));
1584 signalDirtyStorage(InitState::Initialized);
1585 return angle::Result::Continue;
1586 }
1587
releaseImageFromStream(const Context * context)1588 angle::Result Texture::releaseImageFromStream(const Context *context)
1589 {
1590 ASSERT(mBoundStream != nullptr);
1591 ANGLE_TRY(mTexture->setImageExternal(context, mState.mType, nullptr,
1592 egl::Stream::GLTextureDescription()));
1593
1594 // Set to incomplete
1595 mState.clearImageDesc(NonCubeTextureTypeToTarget(mState.mType), 0);
1596 signalDirtyStorage(InitState::Initialized);
1597 return angle::Result::Continue;
1598 }
1599
releaseTexImageInternal(Context * context)1600 angle::Result Texture::releaseTexImageInternal(Context *context)
1601 {
1602 if (mBoundSurface)
1603 {
1604 // Notify the surface
1605 egl::Error eglErr = mBoundSurface->releaseTexImageFromTexture(context);
1606 // TODO(jmadill): Remove this once refactor is complete. http://anglebug.com/3041
1607 if (eglErr.isError())
1608 {
1609 context->handleError(GL_INVALID_OPERATION, "Error releasing tex image from texture",
1610 __FILE__, ANGLE_FUNCTION, __LINE__);
1611 }
1612
1613 // Then, call the same method as from the surface
1614 ANGLE_TRY(releaseTexImageFromSurface(context));
1615 }
1616 return angle::Result::Continue;
1617 }
1618
setEGLImageTarget(Context * context,TextureType type,egl::Image * imageTarget)1619 angle::Result Texture::setEGLImageTarget(Context *context,
1620 TextureType type,
1621 egl::Image *imageTarget)
1622 {
1623 ASSERT(type == mState.mType);
1624 ASSERT(type == TextureType::_2D || type == TextureType::External);
1625
1626 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1627 ANGLE_TRY(releaseTexImageInternal(context));
1628 ANGLE_TRY(orphanImages(context));
1629
1630 ANGLE_TRY(mTexture->setEGLImageTarget(context, type, imageTarget));
1631
1632 setTargetImage(context, imageTarget);
1633
1634 Extents size(static_cast<int>(imageTarget->getWidth()),
1635 static_cast<int>(imageTarget->getHeight()), 1);
1636
1637 auto initState = imageTarget->sourceInitState();
1638
1639 mState.clearImageDescs();
1640 mState.setImageDesc(NonCubeTextureTypeToTarget(type), 0,
1641 ImageDesc(size, imageTarget->getFormat(), initState));
1642 signalDirtyStorage(initState);
1643
1644 return angle::Result::Continue;
1645 }
1646
getAttachmentSize(const ImageIndex & imageIndex) const1647 Extents Texture::getAttachmentSize(const ImageIndex &imageIndex) const
1648 {
1649 // As an ImageIndex that represents an entire level of a cube map corresponds to 6 ImageDescs,
1650 // we only allow querying ImageDesc on a complete cube map, and this ImageDesc is exactly the
1651 // one that belongs to the first face of the cube map.
1652 if (imageIndex.isEntireLevelCubeMap())
1653 {
1654 // A cube map texture is cube complete if the following conditions all hold true:
1655 // - The levelbase arrays of each of the six texture images making up the cube map have
1656 // identical, positive, and square dimensions.
1657 if (!mState.isCubeComplete())
1658 {
1659 return Extents();
1660 }
1661 }
1662
1663 return mState.getImageDesc(imageIndex).size;
1664 }
1665
getAttachmentFormat(GLenum,const ImageIndex & imageIndex) const1666 Format Texture::getAttachmentFormat(GLenum /*binding*/, const ImageIndex &imageIndex) const
1667 {
1668 // As an ImageIndex that represents an entire level of a cube map corresponds to 6 ImageDescs,
1669 // we only allow querying ImageDesc on a complete cube map, and this ImageDesc is exactly the
1670 // one that belongs to the first face of the cube map.
1671 if (imageIndex.isEntireLevelCubeMap())
1672 {
1673 // A cube map texture is cube complete if the following conditions all hold true:
1674 // - The levelbase arrays were each specified with the same effective internal format.
1675 if (!mState.isCubeComplete())
1676 {
1677 return Format::Invalid();
1678 }
1679 }
1680 return mState.getImageDesc(imageIndex).format;
1681 }
1682
getAttachmentSamples(const ImageIndex & imageIndex) const1683 GLsizei Texture::getAttachmentSamples(const ImageIndex &imageIndex) const
1684 {
1685 // We do not allow querying TextureTarget by an ImageIndex that represents an entire level of a
1686 // cube map (See comments in function TextureTypeToTarget() in ImageIndex.cpp).
1687 if (imageIndex.isEntireLevelCubeMap())
1688 {
1689 return 0;
1690 }
1691
1692 return getSamples(imageIndex.getTarget(), imageIndex.getLevelIndex());
1693 }
1694
isRenderable(const Context * context,GLenum binding,const ImageIndex & imageIndex) const1695 bool Texture::isRenderable(const Context *context,
1696 GLenum binding,
1697 const ImageIndex &imageIndex) const
1698 {
1699 if (isEGLImageTarget())
1700 {
1701 return ImageSibling::isRenderable(context, binding, imageIndex);
1702 }
1703 return getAttachmentFormat(binding, imageIndex)
1704 .info->textureAttachmentSupport(context->getClientVersion(), context->getExtensions());
1705 }
1706
getAttachmentFixedSampleLocations(const ImageIndex & imageIndex) const1707 bool Texture::getAttachmentFixedSampleLocations(const ImageIndex &imageIndex) const
1708 {
1709 // We do not allow querying TextureTarget by an ImageIndex that represents an entire level of a
1710 // cube map (See comments in function TextureTypeToTarget() in ImageIndex.cpp).
1711 if (imageIndex.isEntireLevelCubeMap())
1712 {
1713 return true;
1714 }
1715
1716 // ES3.1 (section 9.4) requires that the value of TEXTURE_FIXED_SAMPLE_LOCATIONS should be
1717 // the same for all attached textures.
1718 return getFixedSampleLocations(imageIndex.getTarget(), imageIndex.getLevelIndex());
1719 }
1720
setBorderColor(const Context * context,const ColorGeneric & color)1721 void Texture::setBorderColor(const Context *context, const ColorGeneric &color)
1722 {
1723 mState.mSamplerState.setBorderColor(color);
1724 signalDirtyState(DIRTY_BIT_BORDER_COLOR);
1725 }
1726
getBorderColor() const1727 const ColorGeneric &Texture::getBorderColor() const
1728 {
1729 return mState.mSamplerState.getBorderColor();
1730 }
1731
setCrop(const Rectangle & rect)1732 void Texture::setCrop(const Rectangle &rect)
1733 {
1734 mState.setCrop(rect);
1735 }
1736
getCrop() const1737 const Rectangle &Texture::getCrop() const
1738 {
1739 return mState.getCrop();
1740 }
1741
setGenerateMipmapHint(GLenum hint)1742 void Texture::setGenerateMipmapHint(GLenum hint)
1743 {
1744 mState.setGenerateMipmapHint(hint);
1745 }
1746
getGenerateMipmapHint() const1747 GLenum Texture::getGenerateMipmapHint() const
1748 {
1749 return mState.getGenerateMipmapHint();
1750 }
1751
onAttach(const Context * context)1752 void Texture::onAttach(const Context *context)
1753 {
1754 addRef();
1755 }
1756
onDetach(const Context * context)1757 void Texture::onDetach(const Context *context)
1758 {
1759 release(context);
1760 }
1761
getId() const1762 GLuint Texture::getId() const
1763 {
1764 return id().value;
1765 }
1766
getNativeID() const1767 GLuint Texture::getNativeID() const
1768 {
1769 return mTexture->getNativeID();
1770 }
1771
syncState(const Context * context)1772 angle::Result Texture::syncState(const Context *context)
1773 {
1774 ASSERT(hasAnyDirtyBit());
1775 ANGLE_TRY(mTexture->syncState(context, mDirtyBits));
1776 mDirtyBits.reset();
1777 return angle::Result::Continue;
1778 }
1779
getAttachmentImpl() const1780 rx::FramebufferAttachmentObjectImpl *Texture::getAttachmentImpl() const
1781 {
1782 return mTexture;
1783 }
1784
isSamplerComplete(const Context * context,const Sampler * optionalSampler)1785 bool Texture::isSamplerComplete(const Context *context, const Sampler *optionalSampler)
1786 {
1787 const auto &samplerState =
1788 optionalSampler ? optionalSampler->getSamplerState() : mState.mSamplerState;
1789 const auto &contextState = context->getState();
1790
1791 if (contextState.getContextID() != mCompletenessCache.context ||
1792 !mCompletenessCache.samplerState.sameCompleteness(samplerState))
1793 {
1794 mCompletenessCache.context = context->getState().getContextID();
1795 mCompletenessCache.samplerState = samplerState;
1796 mCompletenessCache.samplerComplete =
1797 mState.computeSamplerCompleteness(samplerState, contextState);
1798 }
1799
1800 return mCompletenessCache.samplerComplete;
1801 }
1802
SamplerCompletenessCache()1803 Texture::SamplerCompletenessCache::SamplerCompletenessCache()
1804 : context(0), samplerState(), samplerComplete(false)
1805 {}
1806
invalidateCompletenessCache() const1807 void Texture::invalidateCompletenessCache() const
1808 {
1809 mCompletenessCache.context = 0;
1810 }
1811
ensureInitialized(const Context * context)1812 angle::Result Texture::ensureInitialized(const Context *context)
1813 {
1814 if (!context->isRobustResourceInitEnabled() || mState.mInitState == InitState::Initialized)
1815 {
1816 return angle::Result::Continue;
1817 }
1818
1819 bool anyDirty = false;
1820
1821 ImageIndexIterator it =
1822 ImageIndexIterator::MakeGeneric(mState.mType, 0, IMPLEMENTATION_MAX_TEXTURE_LEVELS + 1,
1823 ImageIndex::kEntireLevel, ImageIndex::kEntireLevel);
1824 while (it.hasNext())
1825 {
1826 const ImageIndex index = it.next();
1827 ImageDesc &desc =
1828 mState.mImageDescs[GetImageDescIndex(index.getTarget(), index.getLevelIndex())];
1829 if (desc.initState == InitState::MayNeedInit && !desc.size.empty())
1830 {
1831 ASSERT(mState.mInitState == InitState::MayNeedInit);
1832 ANGLE_TRY(initializeContents(context, index));
1833 desc.initState = InitState::Initialized;
1834 anyDirty = true;
1835 }
1836 }
1837 if (anyDirty)
1838 {
1839 signalDirtyStorage(InitState::Initialized);
1840 }
1841 mState.mInitState = InitState::Initialized;
1842
1843 return angle::Result::Continue;
1844 }
1845
initState(const ImageIndex & imageIndex) const1846 InitState Texture::initState(const ImageIndex &imageIndex) const
1847 {
1848 // As an ImageIndex that represents an entire level of a cube map corresponds to 6 ImageDescs,
1849 // we need to check all the related ImageDescs.
1850 if (imageIndex.isEntireLevelCubeMap())
1851 {
1852 const GLint levelIndex = imageIndex.getLevelIndex();
1853 for (TextureTarget cubeFaceTarget : AllCubeFaceTextureTargets())
1854 {
1855 if (mState.getImageDesc(cubeFaceTarget, levelIndex).initState == InitState::MayNeedInit)
1856 {
1857 return InitState::MayNeedInit;
1858 }
1859 }
1860 return InitState::Initialized;
1861 }
1862
1863 return mState.getImageDesc(imageIndex).initState;
1864 }
1865
setInitState(const ImageIndex & imageIndex,InitState initState)1866 void Texture::setInitState(const ImageIndex &imageIndex, InitState initState)
1867 {
1868 // As an ImageIndex that represents an entire level of a cube map corresponds to 6 ImageDescs,
1869 // we need to update all the related ImageDescs.
1870 if (imageIndex.isEntireLevelCubeMap())
1871 {
1872 const GLint levelIndex = imageIndex.getLevelIndex();
1873 for (TextureTarget cubeFaceTarget : AllCubeFaceTextureTargets())
1874 {
1875 setInitState(ImageIndex::MakeCubeMapFace(cubeFaceTarget, levelIndex), initState);
1876 }
1877 }
1878 else
1879 {
1880 ImageDesc newDesc = mState.getImageDesc(imageIndex);
1881 newDesc.initState = initState;
1882 mState.setImageDesc(imageIndex.getTarget(), imageIndex.getLevelIndex(), newDesc);
1883 }
1884 }
1885
doesSubImageNeedInit(const Context * context,const ImageIndex & imageIndex,const Box & area) const1886 bool Texture::doesSubImageNeedInit(const Context *context,
1887 const ImageIndex &imageIndex,
1888 const Box &area) const
1889 {
1890 if (!context->isRobustResourceInitEnabled() || mState.mInitState == InitState::Initialized)
1891 {
1892 return false;
1893 }
1894
1895 // Pre-initialize the texture contents if necessary.
1896 const ImageDesc &desc = mState.getImageDesc(imageIndex);
1897 if (desc.initState != InitState::MayNeedInit)
1898 {
1899 return false;
1900 }
1901
1902 ASSERT(mState.mInitState == InitState::MayNeedInit);
1903 bool coversWholeImage = area.x == 0 && area.y == 0 && area.z == 0 &&
1904 area.width == desc.size.width && area.height == desc.size.height &&
1905 area.depth == desc.size.depth;
1906 return !coversWholeImage;
1907 }
1908
ensureSubImageInitialized(const Context * context,const ImageIndex & imageIndex,const Box & area)1909 angle::Result Texture::ensureSubImageInitialized(const Context *context,
1910 const ImageIndex &imageIndex,
1911 const Box &area)
1912 {
1913 if (doesSubImageNeedInit(context, imageIndex, area))
1914 {
1915 // NOTE: do not optimize this to only initialize the passed area of the texture, or the
1916 // initialization logic in copySubImage will be incorrect.
1917 ANGLE_TRY(initializeContents(context, imageIndex));
1918 }
1919 setInitState(imageIndex, InitState::Initialized);
1920 return angle::Result::Continue;
1921 }
1922
handleMipmapGenerationHint(Context * context,int level)1923 angle::Result Texture::handleMipmapGenerationHint(Context *context, int level)
1924 {
1925 if (getGenerateMipmapHint() == GL_TRUE && level == 0)
1926 {
1927 ANGLE_TRY(generateMipmap(context));
1928 }
1929
1930 return angle::Result::Continue;
1931 }
1932
onSubjectStateChange(angle::SubjectIndex index,angle::SubjectMessage message)1933 void Texture::onSubjectStateChange(angle::SubjectIndex index, angle::SubjectMessage message)
1934 {
1935 switch (message)
1936 {
1937 case angle::SubjectMessage::ContentsChanged:
1938 // ContentsChange is originates from TextureStorage11::resolveAndReleaseTexture
1939 // which resolves the underlying multisampled texture if it exists and so
1940 // Texture will signal dirty storage to invalidate its own cache and the
1941 // attached framebuffer's cache.
1942 signalDirtyStorage(InitState::Initialized);
1943 break;
1944 case angle::SubjectMessage::DirtyBitsFlagged:
1945 signalDirtyState(DIRTY_BIT_IMPLEMENTATION);
1946
1947 // Notify siblings that we are dirty.
1948 if (index == rx::kTextureImageImplObserverMessageIndex)
1949 {
1950 notifySiblings(message);
1951 }
1952 break;
1953 case angle::SubjectMessage::SubjectChanged:
1954 mState.mInitState = InitState::MayNeedInit;
1955 signalDirtyState(DIRTY_BIT_IMPLEMENTATION);
1956 onStateChange(angle::SubjectMessage::ContentsChanged);
1957
1958 // Notify siblings that we are dirty.
1959 if (index == rx::kTextureImageImplObserverMessageIndex)
1960 {
1961 notifySiblings(message);
1962 }
1963 break;
1964 default:
1965 UNREACHABLE();
1966 break;
1967 }
1968 }
1969
getImplementationColorReadFormat(const Context * context) const1970 GLenum Texture::getImplementationColorReadFormat(const Context *context) const
1971 {
1972 return mTexture->getColorReadFormat(context);
1973 }
1974
getImplementationColorReadType(const Context * context) const1975 GLenum Texture::getImplementationColorReadType(const Context *context) const
1976 {
1977 return mTexture->getColorReadType(context);
1978 }
1979
getTexImage(const Context * context,const PixelPackState & packState,Buffer * packBuffer,TextureTarget target,GLint level,GLenum format,GLenum type,void * pixels) const1980 angle::Result Texture::getTexImage(const Context *context,
1981 const PixelPackState &packState,
1982 Buffer *packBuffer,
1983 TextureTarget target,
1984 GLint level,
1985 GLenum format,
1986 GLenum type,
1987 void *pixels) const
1988 {
1989 return mTexture->getTexImage(context, packState, packBuffer, target, level, format, type,
1990 pixels);
1991 }
1992
onBindAsImageTexture(ContextID contextID)1993 void Texture::onBindAsImageTexture(ContextID contextID)
1994 {
1995 ContextBindingCount &bindingCount = mState.getBindingCount(contextID);
1996
1997 ASSERT(bindingCount.imageBindingCount < std::numeric_limits<uint32_t>::max());
1998 mState.getBindingCount(contextID).imageBindingCount++;
1999 if (bindingCount.imageBindingCount == 1)
2000 {
2001 mDirtyBits.set(DIRTY_BIT_BOUND_AS_IMAGE);
2002 }
2003 }
2004
2005 } // namespace gl
2006