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 mSrgbOverride(SrgbOverride::Default),
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 Rectangle & rect)224 void TextureState::setCrop(const Rectangle &rect)
225 {
226 mCropRect = rect;
227 }
228
getCrop() const229 const 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 & state) const271 bool TextureState::computeSamplerCompleteness(const SamplerState &samplerState,
272 const State &state) 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(state.getClientVersion(),
300 state.getExtensions()) &&
301 !IsPointSampled(samplerState))
302 {
303 return false;
304 }
305 bool npotSupport = state.getExtensions().textureNPOTOES || state.getClientMajorVersion() >= 3;
306 if (!npotSupport)
307 {
308 if ((samplerState.getWrapS() != GL_CLAMP_TO_EDGE &&
309 samplerState.getWrapS() != GL_CLAMP_TO_BORDER && !isPow2(baseImageDesc.size.width)) ||
310 (samplerState.getWrapT() != GL_CLAMP_TO_EDGE &&
311 samplerState.getWrapT() != GL_CLAMP_TO_BORDER && !isPow2(baseImageDesc.size.height)))
312 {
313 return false;
314 }
315 }
316
317 if (mType != TextureType::_2DMultisample && IsMipmapFiltered(samplerState))
318 {
319 if (!npotSupport)
320 {
321 if (!isPow2(baseImageDesc.size.width) || !isPow2(baseImageDesc.size.height))
322 {
323 return false;
324 }
325 }
326
327 if (!computeMipmapCompleteness())
328 {
329 return false;
330 }
331 }
332 else
333 {
334 if (mType == TextureType::CubeMap && !isCubeComplete())
335 {
336 return false;
337 }
338 }
339
340 // From GL_OES_EGL_image_external_essl3: If state is present in a sampler object bound to a
341 // texture unit that would have been rejected by a call to TexParameter* for the texture bound
342 // to that unit, the behavior of the implementation is as if the texture were incomplete. For
343 // example, if TEXTURE_WRAP_S or TEXTURE_WRAP_T is set to anything but CLAMP_TO_EDGE on the
344 // sampler object bound to a texture unit and the texture bound to that unit is an external
345 // texture and EXT_EGL_image_external_wrap_modes is not enabled, the texture will be considered
346 // incomplete.
347 // Sampler object state which does not affect sampling for the type of texture bound
348 // to a texture unit, such as TEXTURE_WRAP_R for an external texture, does not affect
349 // completeness.
350 if (mType == TextureType::External)
351 {
352 if (!state.getExtensions().eglImageExternalWrapModesEXT)
353 {
354 if (samplerState.getWrapS() != GL_CLAMP_TO_EDGE ||
355 samplerState.getWrapT() != GL_CLAMP_TO_EDGE)
356 {
357 return false;
358 }
359 }
360
361 if (samplerState.getMinFilter() != GL_LINEAR && samplerState.getMinFilter() != GL_NEAREST)
362 {
363 return false;
364 }
365 }
366
367 // OpenGLES 3.0.2 spec section 3.8.13 states that a texture is not mipmap complete if:
368 // The internalformat specified for the texture arrays is a sized internal depth or
369 // depth and stencil format (see table 3.13), the value of TEXTURE_COMPARE_-
370 // MODE is NONE, and either the magnification filter is not NEAREST or the mini-
371 // fication filter is neither NEAREST nor NEAREST_MIPMAP_NEAREST.
372 if (!IsMultisampled(mType) && baseImageDesc.format.info->depthBits > 0 &&
373 state.getClientMajorVersion() >= 3)
374 {
375 // Note: we restrict this validation to sized types. For the OES_depth_textures
376 // extension, due to some underspecification problems, we must allow linear filtering
377 // for legacy compatibility with WebGL 1.
378 // See http://crbug.com/649200
379 if (samplerState.getCompareMode() == GL_NONE && baseImageDesc.format.info->sized)
380 {
381 if ((samplerState.getMinFilter() != GL_NEAREST &&
382 samplerState.getMinFilter() != GL_NEAREST_MIPMAP_NEAREST) ||
383 samplerState.getMagFilter() != GL_NEAREST)
384 {
385 return false;
386 }
387 }
388 }
389
390 // OpenGLES 3.1 spec section 8.16 states that a texture is not mipmap complete if:
391 // The internalformat specified for the texture is DEPTH_STENCIL format, the value of
392 // DEPTH_STENCIL_TEXTURE_MODE is STENCIL_INDEX, and either the magnification filter is
393 // not NEAREST or the minification filter is neither NEAREST nor NEAREST_MIPMAP_NEAREST.
394 // However, the ES 3.1 spec differs from the statement above, because it is incorrect.
395 // See the issue at https://github.com/KhronosGroup/OpenGL-API/issues/33.
396 // For multismaple texture, filter state of multisample texture is ignored(11.1.3.3).
397 // So it shouldn't be judged as incomplete texture. So, we ignore filtering for multisample
398 // texture completeness here.
399 if (!IsMultisampled(mType) && baseImageDesc.format.info->depthBits > 0 &&
400 mDepthStencilTextureMode == GL_STENCIL_INDEX)
401 {
402 if ((samplerState.getMinFilter() != GL_NEAREST &&
403 samplerState.getMinFilter() != GL_NEAREST_MIPMAP_NEAREST) ||
404 samplerState.getMagFilter() != GL_NEAREST)
405 {
406 return false;
407 }
408 }
409
410 return true;
411 }
412
computeMipmapCompleteness() const413 bool TextureState::computeMipmapCompleteness() const
414 {
415 const GLuint maxLevel = getMipmapMaxLevel();
416
417 for (GLuint level = getEffectiveBaseLevel(); level <= maxLevel; level++)
418 {
419 if (mType == TextureType::CubeMap)
420 {
421 for (TextureTarget face : AllCubeFaceTextureTargets())
422 {
423 if (!computeLevelCompleteness(face, level))
424 {
425 return false;
426 }
427 }
428 }
429 else
430 {
431 if (!computeLevelCompleteness(NonCubeTextureTypeToTarget(mType), level))
432 {
433 return false;
434 }
435 }
436 }
437
438 return true;
439 }
440
computeLevelCompleteness(TextureTarget target,size_t level) const441 bool TextureState::computeLevelCompleteness(TextureTarget target, size_t level) const
442 {
443 ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
444
445 if (mImmutableFormat)
446 {
447 return true;
448 }
449
450 const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), getEffectiveBaseLevel());
451 if (baseImageDesc.size.width == 0 || baseImageDesc.size.height == 0 ||
452 baseImageDesc.size.depth == 0)
453 {
454 return false;
455 }
456
457 const ImageDesc &levelImageDesc = getImageDesc(target, level);
458 if (levelImageDesc.size.width == 0 || levelImageDesc.size.height == 0 ||
459 levelImageDesc.size.depth == 0)
460 {
461 return false;
462 }
463
464 if (!Format::SameSized(levelImageDesc.format, baseImageDesc.format))
465 {
466 return false;
467 }
468
469 ASSERT(level >= getEffectiveBaseLevel());
470 const size_t relativeLevel = level - getEffectiveBaseLevel();
471 if (levelImageDesc.size.width != std::max(1, baseImageDesc.size.width >> relativeLevel))
472 {
473 return false;
474 }
475
476 if (levelImageDesc.size.height != std::max(1, baseImageDesc.size.height >> relativeLevel))
477 {
478 return false;
479 }
480
481 if (mType == TextureType::_3D)
482 {
483 if (levelImageDesc.size.depth != std::max(1, baseImageDesc.size.depth >> relativeLevel))
484 {
485 return false;
486 }
487 }
488 else if (IsArrayTextureType(mType))
489 {
490 if (levelImageDesc.size.depth != baseImageDesc.size.depth)
491 {
492 return false;
493 }
494 }
495
496 return true;
497 }
498
getBaseImageTarget() const499 TextureTarget TextureState::getBaseImageTarget() const
500 {
501 return mType == TextureType::CubeMap ? kCubeMapTextureTargetMin
502 : NonCubeTextureTypeToTarget(mType);
503 }
504
getEnabledLevelCount() const505 GLuint TextureState::getEnabledLevelCount() const
506 {
507 GLuint levelCount = 0;
508 const GLuint baseLevel = getEffectiveBaseLevel();
509 const GLuint maxLevel = std::min(getEffectiveMaxLevel(), getMipmapMaxLevel());
510
511 // The mip chain will have either one or more sequential levels, or max levels,
512 // but not a sparse one.
513 for (size_t descIndex = baseLevel; descIndex < mImageDescs.size();)
514 {
515 if (!mImageDescs[descIndex].size.empty())
516 {
517 levelCount++;
518 }
519 descIndex = (mType == TextureType::CubeMap) ? descIndex + 6 : descIndex + 1;
520 }
521 // The original image already takes account into the levelCount.
522 levelCount = std::min(maxLevel - baseLevel + 1, levelCount);
523
524 return levelCount;
525 }
526
ImageDesc()527 ImageDesc::ImageDesc()
528 : ImageDesc(Extents(0, 0, 0), Format::Invalid(), 0, GL_TRUE, InitState::MayNeedInit)
529 {}
530
ImageDesc(const Extents & size,const Format & format,const InitState initState)531 ImageDesc::ImageDesc(const Extents &size, const Format &format, const InitState initState)
532 : size(size), format(format), samples(0), fixedSampleLocations(GL_TRUE), initState(initState)
533 {}
534
ImageDesc(const Extents & size,const Format & format,const GLsizei samples,const bool fixedSampleLocations,const InitState initState)535 ImageDesc::ImageDesc(const Extents &size,
536 const Format &format,
537 const GLsizei samples,
538 const bool fixedSampleLocations,
539 const InitState initState)
540 : size(size),
541 format(format),
542 samples(samples),
543 fixedSampleLocations(fixedSampleLocations),
544 initState(initState)
545 {}
546
getMemorySize() const547 GLint ImageDesc::getMemorySize() const
548 {
549 // Assume allocated size is around width * height * depth * samples * pixelBytes
550 angle::CheckedNumeric<GLint> levelSize = 1;
551 levelSize *= format.info->pixelBytes;
552 levelSize *= size.width;
553 levelSize *= size.height;
554 levelSize *= size.depth;
555 levelSize *= std::max(samples, 1);
556 return levelSize.ValueOrDefault(std::numeric_limits<GLint>::max());
557 }
558
getImageDesc(TextureTarget target,size_t level) const559 const ImageDesc &TextureState::getImageDesc(TextureTarget target, size_t level) const
560 {
561 size_t descIndex = GetImageDescIndex(target, level);
562 ASSERT(descIndex < mImageDescs.size());
563 return mImageDescs[descIndex];
564 }
565
setImageDesc(TextureTarget target,size_t level,const ImageDesc & desc)566 void TextureState::setImageDesc(TextureTarget target, size_t level, const ImageDesc &desc)
567 {
568 size_t descIndex = GetImageDescIndex(target, level);
569 ASSERT(descIndex < mImageDescs.size());
570 mImageDescs[descIndex] = desc;
571 if (desc.initState == InitState::MayNeedInit)
572 {
573 mInitState = InitState::MayNeedInit;
574 }
575 }
576
577 // Note that an ImageIndex that represents an entire level of a cube map corresponds to 6
578 // ImageDescs, so if the cube map is cube complete, we return the ImageDesc of the first cube
579 // face, and we don't allow using this function when the cube map is not cube complete.
getImageDesc(const ImageIndex & imageIndex) const580 const ImageDesc &TextureState::getImageDesc(const ImageIndex &imageIndex) const
581 {
582 if (imageIndex.isEntireLevelCubeMap())
583 {
584 ASSERT(isCubeComplete());
585 const GLint levelIndex = imageIndex.getLevelIndex();
586 return getImageDesc(kCubeMapTextureTargetMin, levelIndex);
587 }
588
589 return getImageDesc(imageIndex.getTarget(), imageIndex.getLevelIndex());
590 }
591
setImageDescChain(GLuint baseLevel,GLuint maxLevel,Extents baseSize,const Format & format,InitState initState)592 void TextureState::setImageDescChain(GLuint baseLevel,
593 GLuint maxLevel,
594 Extents baseSize,
595 const Format &format,
596 InitState initState)
597 {
598 for (GLuint level = baseLevel; level <= maxLevel; level++)
599 {
600 int relativeLevel = (level - baseLevel);
601 Extents levelSize(std::max<int>(baseSize.width >> relativeLevel, 1),
602 std::max<int>(baseSize.height >> relativeLevel, 1),
603 (IsArrayTextureType(mType))
604 ? baseSize.depth
605 : std::max<int>(baseSize.depth >> relativeLevel, 1));
606 ImageDesc levelInfo(levelSize, format, initState);
607
608 if (mType == TextureType::CubeMap)
609 {
610 for (TextureTarget face : AllCubeFaceTextureTargets())
611 {
612 setImageDesc(face, level, levelInfo);
613 }
614 }
615 else
616 {
617 setImageDesc(NonCubeTextureTypeToTarget(mType), level, levelInfo);
618 }
619 }
620 }
621
setImageDescChainMultisample(Extents baseSize,const Format & format,GLsizei samples,bool fixedSampleLocations,InitState initState)622 void TextureState::setImageDescChainMultisample(Extents baseSize,
623 const Format &format,
624 GLsizei samples,
625 bool fixedSampleLocations,
626 InitState initState)
627 {
628 ASSERT(mType == TextureType::_2DMultisample || mType == TextureType::_2DMultisampleArray);
629 ImageDesc levelInfo(baseSize, format, samples, fixedSampleLocations, initState);
630 setImageDesc(NonCubeTextureTypeToTarget(mType), 0, levelInfo);
631 }
632
clearImageDesc(TextureTarget target,size_t level)633 void TextureState::clearImageDesc(TextureTarget target, size_t level)
634 {
635 setImageDesc(target, level, ImageDesc());
636 }
637
clearImageDescs()638 void TextureState::clearImageDescs()
639 {
640 for (size_t descIndex = 0; descIndex < mImageDescs.size(); descIndex++)
641 {
642 mImageDescs[descIndex] = ImageDesc();
643 }
644 }
645
Texture(rx::GLImplFactory * factory,TextureID id,TextureType type)646 Texture::Texture(rx::GLImplFactory *factory, TextureID id, TextureType type)
647 : RefCountObject(factory->generateSerial(), id),
648 mState(type),
649 mTexture(factory->createTexture(mState)),
650 mImplObserver(this, rx::kTextureImageImplObserverMessageIndex),
651 mLabel(),
652 mBoundSurface(nullptr),
653 mBoundStream(nullptr)
654 {
655 mImplObserver.bind(mTexture);
656
657 // Initially assume the implementation is dirty.
658 mDirtyBits.set(DIRTY_BIT_IMPLEMENTATION);
659 }
660
onDestroy(const Context * context)661 void Texture::onDestroy(const Context *context)
662 {
663 if (mBoundSurface)
664 {
665 ANGLE_SWALLOW_ERR(mBoundSurface->releaseTexImage(context, EGL_BACK_BUFFER));
666 mBoundSurface = nullptr;
667 }
668 if (mBoundStream)
669 {
670 mBoundStream->releaseTextures();
671 mBoundStream = nullptr;
672 }
673
674 (void)(orphanImages(context));
675
676 if (mTexture)
677 {
678 mTexture->onDestroy(context);
679 }
680 }
681
~Texture()682 Texture::~Texture()
683 {
684 SafeDelete(mTexture);
685 }
686
setLabel(const Context * context,const std::string & label)687 void Texture::setLabel(const Context *context, const std::string &label)
688 {
689 mLabel = label;
690 signalDirtyState(DIRTY_BIT_LABEL);
691 }
692
getLabel() const693 const std::string &Texture::getLabel() const
694 {
695 return mLabel;
696 }
697
setSwizzleRed(const Context * context,GLenum swizzleRed)698 void Texture::setSwizzleRed(const Context *context, GLenum swizzleRed)
699 {
700 mState.mSwizzleState.swizzleRed = swizzleRed;
701 signalDirtyState(DIRTY_BIT_SWIZZLE_RED);
702 }
703
getSwizzleRed() const704 GLenum Texture::getSwizzleRed() const
705 {
706 return mState.mSwizzleState.swizzleRed;
707 }
708
setSwizzleGreen(const Context * context,GLenum swizzleGreen)709 void Texture::setSwizzleGreen(const Context *context, GLenum swizzleGreen)
710 {
711 mState.mSwizzleState.swizzleGreen = swizzleGreen;
712 signalDirtyState(DIRTY_BIT_SWIZZLE_GREEN);
713 }
714
getSwizzleGreen() const715 GLenum Texture::getSwizzleGreen() const
716 {
717 return mState.mSwizzleState.swizzleGreen;
718 }
719
setSwizzleBlue(const Context * context,GLenum swizzleBlue)720 void Texture::setSwizzleBlue(const Context *context, GLenum swizzleBlue)
721 {
722 mState.mSwizzleState.swizzleBlue = swizzleBlue;
723 signalDirtyState(DIRTY_BIT_SWIZZLE_BLUE);
724 }
725
getSwizzleBlue() const726 GLenum Texture::getSwizzleBlue() const
727 {
728 return mState.mSwizzleState.swizzleBlue;
729 }
730
setSwizzleAlpha(const Context * context,GLenum swizzleAlpha)731 void Texture::setSwizzleAlpha(const Context *context, GLenum swizzleAlpha)
732 {
733 mState.mSwizzleState.swizzleAlpha = swizzleAlpha;
734 signalDirtyState(DIRTY_BIT_SWIZZLE_ALPHA);
735 }
736
getSwizzleAlpha() const737 GLenum Texture::getSwizzleAlpha() const
738 {
739 return mState.mSwizzleState.swizzleAlpha;
740 }
741
setMinFilter(const Context * context,GLenum minFilter)742 void Texture::setMinFilter(const Context *context, GLenum minFilter)
743 {
744 mState.mSamplerState.setMinFilter(minFilter);
745 signalDirtyState(DIRTY_BIT_MIN_FILTER);
746 }
747
getMinFilter() const748 GLenum Texture::getMinFilter() const
749 {
750 return mState.mSamplerState.getMinFilter();
751 }
752
setMagFilter(const Context * context,GLenum magFilter)753 void Texture::setMagFilter(const Context *context, GLenum magFilter)
754 {
755 mState.mSamplerState.setMagFilter(magFilter);
756 signalDirtyState(DIRTY_BIT_MAG_FILTER);
757 }
758
getMagFilter() const759 GLenum Texture::getMagFilter() const
760 {
761 return mState.mSamplerState.getMagFilter();
762 }
763
setWrapS(const Context * context,GLenum wrapS)764 void Texture::setWrapS(const Context *context, GLenum wrapS)
765 {
766 mState.mSamplerState.setWrapS(wrapS);
767 signalDirtyState(DIRTY_BIT_WRAP_S);
768 }
769
getWrapS() const770 GLenum Texture::getWrapS() const
771 {
772 return mState.mSamplerState.getWrapS();
773 }
774
setWrapT(const Context * context,GLenum wrapT)775 void Texture::setWrapT(const Context *context, GLenum wrapT)
776 {
777 mState.mSamplerState.setWrapT(wrapT);
778 signalDirtyState(DIRTY_BIT_WRAP_T);
779 }
780
getWrapT() const781 GLenum Texture::getWrapT() const
782 {
783 return mState.mSamplerState.getWrapT();
784 }
785
setWrapR(const Context * context,GLenum wrapR)786 void Texture::setWrapR(const Context *context, GLenum wrapR)
787 {
788 mState.mSamplerState.setWrapR(wrapR);
789 signalDirtyState(DIRTY_BIT_WRAP_R);
790 }
791
getWrapR() const792 GLenum Texture::getWrapR() const
793 {
794 return mState.mSamplerState.getWrapR();
795 }
796
setMaxAnisotropy(const Context * context,float maxAnisotropy)797 void Texture::setMaxAnisotropy(const Context *context, float maxAnisotropy)
798 {
799 mState.mSamplerState.setMaxAnisotropy(maxAnisotropy);
800 signalDirtyState(DIRTY_BIT_MAX_ANISOTROPY);
801 }
802
getMaxAnisotropy() const803 float Texture::getMaxAnisotropy() const
804 {
805 return mState.mSamplerState.getMaxAnisotropy();
806 }
807
setMinLod(const Context * context,GLfloat minLod)808 void Texture::setMinLod(const Context *context, GLfloat minLod)
809 {
810 mState.mSamplerState.setMinLod(minLod);
811 signalDirtyState(DIRTY_BIT_MIN_LOD);
812 }
813
getMinLod() const814 GLfloat Texture::getMinLod() const
815 {
816 return mState.mSamplerState.getMinLod();
817 }
818
setMaxLod(const Context * context,GLfloat maxLod)819 void Texture::setMaxLod(const Context *context, GLfloat maxLod)
820 {
821 mState.mSamplerState.setMaxLod(maxLod);
822 signalDirtyState(DIRTY_BIT_MAX_LOD);
823 }
824
getMaxLod() const825 GLfloat Texture::getMaxLod() const
826 {
827 return mState.mSamplerState.getMaxLod();
828 }
829
setCompareMode(const Context * context,GLenum compareMode)830 void Texture::setCompareMode(const Context *context, GLenum compareMode)
831 {
832 mState.mSamplerState.setCompareMode(compareMode);
833 signalDirtyState(DIRTY_BIT_COMPARE_MODE);
834 }
835
getCompareMode() const836 GLenum Texture::getCompareMode() const
837 {
838 return mState.mSamplerState.getCompareMode();
839 }
840
setCompareFunc(const Context * context,GLenum compareFunc)841 void Texture::setCompareFunc(const Context *context, GLenum compareFunc)
842 {
843 mState.mSamplerState.setCompareFunc(compareFunc);
844 signalDirtyState(DIRTY_BIT_COMPARE_FUNC);
845 }
846
getCompareFunc() const847 GLenum Texture::getCompareFunc() const
848 {
849 return mState.mSamplerState.getCompareFunc();
850 }
851
setSRGBDecode(const Context * context,GLenum sRGBDecode)852 void Texture::setSRGBDecode(const Context *context, GLenum sRGBDecode)
853 {
854 mState.mSamplerState.setSRGBDecode(sRGBDecode);
855 signalDirtyState(DIRTY_BIT_SRGB_DECODE);
856 }
857
getSRGBDecode() const858 GLenum Texture::getSRGBDecode() const
859 {
860 return mState.mSamplerState.getSRGBDecode();
861 }
862
setSRGBOverride(const Context * context,GLenum sRGBOverride)863 void Texture::setSRGBOverride(const Context *context, GLenum sRGBOverride)
864 {
865 SrgbOverride oldOverride = mState.mSrgbOverride;
866 mState.mSrgbOverride =
867 (sRGBOverride == GL_SRGB) ? SrgbOverride::Enabled : SrgbOverride::Default;
868 if (mState.mSrgbOverride != oldOverride)
869 {
870 signalDirtyState(DIRTY_BIT_SRGB_OVERRIDE);
871 }
872 }
873
getSRGBOverride() const874 GLenum Texture::getSRGBOverride() const
875 {
876 return (mState.mSrgbOverride == SrgbOverride::Enabled) ? GL_SRGB : GL_NONE;
877 }
878
getSamplerState() const879 const SamplerState &Texture::getSamplerState() const
880 {
881 return mState.mSamplerState;
882 }
883
setBaseLevel(const Context * context,GLuint baseLevel)884 angle::Result Texture::setBaseLevel(const Context *context, GLuint baseLevel)
885 {
886 if (mState.setBaseLevel(baseLevel))
887 {
888 ANGLE_TRY(mTexture->setBaseLevel(context, mState.getEffectiveBaseLevel()));
889 signalDirtyState(DIRTY_BIT_BASE_LEVEL);
890 }
891
892 return angle::Result::Continue;
893 }
894
getBaseLevel() const895 GLuint Texture::getBaseLevel() const
896 {
897 return mState.mBaseLevel;
898 }
899
setMaxLevel(const Context * context,GLuint maxLevel)900 void Texture::setMaxLevel(const Context *context, GLuint maxLevel)
901 {
902 if (mState.setMaxLevel(maxLevel))
903 {
904 signalDirtyState(DIRTY_BIT_MAX_LEVEL);
905 }
906 }
907
getMaxLevel() const908 GLuint Texture::getMaxLevel() const
909 {
910 return mState.mMaxLevel;
911 }
912
setDepthStencilTextureMode(const Context * context,GLenum mode)913 void Texture::setDepthStencilTextureMode(const Context *context, GLenum mode)
914 {
915 if (mState.mDepthStencilTextureMode != mode)
916 {
917 mState.mDepthStencilTextureMode = mode;
918 signalDirtyState(DIRTY_BIT_DEPTH_STENCIL_TEXTURE_MODE);
919 }
920 }
921
getDepthStencilTextureMode() const922 GLenum Texture::getDepthStencilTextureMode() const
923 {
924 return mState.mDepthStencilTextureMode;
925 }
926
getImmutableFormat() const927 bool Texture::getImmutableFormat() const
928 {
929 return mState.mImmutableFormat;
930 }
931
getImmutableLevels() const932 GLuint Texture::getImmutableLevels() const
933 {
934 return mState.mImmutableLevels;
935 }
936
setUsage(const Context * context,GLenum usage)937 void Texture::setUsage(const Context *context, GLenum usage)
938 {
939 mState.mUsage = usage;
940 signalDirtyState(DIRTY_BIT_USAGE);
941 }
942
getUsage() const943 GLenum Texture::getUsage() const
944 {
945 return mState.mUsage;
946 }
947
getTextureState() const948 const TextureState &Texture::getTextureState() const
949 {
950 return mState;
951 }
952
getExtents(TextureTarget target,size_t level) const953 const Extents &Texture::getExtents(TextureTarget target, size_t level) const
954 {
955 ASSERT(TextureTargetToType(target) == mState.mType);
956 return mState.getImageDesc(target, level).size;
957 }
958
getWidth(TextureTarget target,size_t level) const959 size_t Texture::getWidth(TextureTarget target, size_t level) const
960 {
961 ASSERT(TextureTargetToType(target) == mState.mType);
962 return mState.getImageDesc(target, level).size.width;
963 }
964
getHeight(TextureTarget target,size_t level) const965 size_t Texture::getHeight(TextureTarget target, size_t level) const
966 {
967 ASSERT(TextureTargetToType(target) == mState.mType);
968 return mState.getImageDesc(target, level).size.height;
969 }
970
getDepth(TextureTarget target,size_t level) const971 size_t Texture::getDepth(TextureTarget target, size_t level) const
972 {
973 ASSERT(TextureTargetToType(target) == mState.mType);
974 return mState.getImageDesc(target, level).size.depth;
975 }
976
getFormat(TextureTarget target,size_t level) const977 const Format &Texture::getFormat(TextureTarget target, size_t level) const
978 {
979 ASSERT(TextureTargetToType(target) == mState.mType);
980 return mState.getImageDesc(target, level).format;
981 }
982
getSamples(TextureTarget target,size_t level) const983 GLsizei Texture::getSamples(TextureTarget target, size_t level) const
984 {
985 ASSERT(TextureTargetToType(target) == mState.mType);
986 return mState.getImageDesc(target, level).samples;
987 }
988
getFixedSampleLocations(TextureTarget target,size_t level) const989 bool Texture::getFixedSampleLocations(TextureTarget target, size_t level) const
990 {
991 ASSERT(TextureTargetToType(target) == mState.mType);
992 return mState.getImageDesc(target, level).fixedSampleLocations;
993 }
994
getMipmapMaxLevel() const995 GLuint Texture::getMipmapMaxLevel() const
996 {
997 return mState.getMipmapMaxLevel();
998 }
999
isMipmapComplete() const1000 bool Texture::isMipmapComplete() const
1001 {
1002 return mState.computeMipmapCompleteness();
1003 }
1004
getBoundSurface() const1005 egl::Surface *Texture::getBoundSurface() const
1006 {
1007 return mBoundSurface;
1008 }
1009
getBoundStream() const1010 egl::Stream *Texture::getBoundStream() const
1011 {
1012 return mBoundStream;
1013 }
1014
getMemorySize() const1015 GLint Texture::getMemorySize() const
1016 {
1017 GLint implSize = mTexture->getMemorySize();
1018 if (implSize > 0)
1019 {
1020 return implSize;
1021 }
1022
1023 angle::CheckedNumeric<GLint> size = 0;
1024 for (const ImageDesc &imageDesc : mState.mImageDescs)
1025 {
1026 size += imageDesc.getMemorySize();
1027 }
1028 return size.ValueOrDefault(std::numeric_limits<GLint>::max());
1029 }
1030
getLevelMemorySize(TextureTarget target,GLint level) const1031 GLint Texture::getLevelMemorySize(TextureTarget target, GLint level) const
1032 {
1033 GLint implSize = mTexture->getLevelMemorySize(target, level);
1034 if (implSize > 0)
1035 {
1036 return implSize;
1037 }
1038
1039 return mState.getImageDesc(target, level).getMemorySize();
1040 }
1041
signalDirtyStorage(InitState initState)1042 void Texture::signalDirtyStorage(InitState initState)
1043 {
1044 mState.mInitState = initState;
1045 invalidateCompletenessCache();
1046 mState.mCachedSamplerFormatValid = false;
1047 onStateChange(angle::SubjectMessage::SubjectChanged);
1048 }
1049
signalDirtyState(size_t dirtyBit)1050 void Texture::signalDirtyState(size_t dirtyBit)
1051 {
1052 mDirtyBits.set(dirtyBit);
1053 invalidateCompletenessCache();
1054 mState.mCachedSamplerFormatValid = false;
1055 onStateChange(angle::SubjectMessage::DirtyBitsFlagged);
1056 }
1057
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)1058 angle::Result Texture::setImage(Context *context,
1059 const PixelUnpackState &unpackState,
1060 Buffer *unpackBuffer,
1061 TextureTarget target,
1062 GLint level,
1063 GLenum internalFormat,
1064 const Extents &size,
1065 GLenum format,
1066 GLenum type,
1067 const uint8_t *pixels)
1068 {
1069 ASSERT(TextureTargetToType(target) == mState.mType);
1070
1071 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1072 ANGLE_TRY(releaseTexImageInternal(context));
1073 ANGLE_TRY(orphanImages(context));
1074
1075 ImageIndex index = ImageIndex::MakeFromTarget(target, level, size.depth);
1076
1077 ANGLE_TRY(mTexture->setImage(context, index, internalFormat, size, format, type, unpackState,
1078 unpackBuffer, pixels));
1079
1080 InitState initState = DetermineInitState(context, unpackBuffer, pixels);
1081 mState.setImageDesc(target, level, ImageDesc(size, Format(internalFormat, type), initState));
1082
1083 ANGLE_TRY(handleMipmapGenerationHint(context, level));
1084
1085 signalDirtyStorage(initState);
1086
1087 return angle::Result::Continue;
1088 }
1089
setSubImage(Context * context,const PixelUnpackState & unpackState,Buffer * unpackBuffer,TextureTarget target,GLint level,const Box & area,GLenum format,GLenum type,const uint8_t * pixels)1090 angle::Result Texture::setSubImage(Context *context,
1091 const PixelUnpackState &unpackState,
1092 Buffer *unpackBuffer,
1093 TextureTarget target,
1094 GLint level,
1095 const Box &area,
1096 GLenum format,
1097 GLenum type,
1098 const uint8_t *pixels)
1099 {
1100 ASSERT(TextureTargetToType(target) == mState.mType);
1101
1102 ImageIndex index = ImageIndex::MakeFromTarget(target, level, area.depth);
1103 ANGLE_TRY(ensureSubImageInitialized(context, index, area));
1104
1105 ANGLE_TRY(mTexture->setSubImage(context, index, area, format, type, unpackState, unpackBuffer,
1106 pixels));
1107
1108 ANGLE_TRY(handleMipmapGenerationHint(context, level));
1109
1110 onStateChange(angle::SubjectMessage::ContentsChanged);
1111
1112 return angle::Result::Continue;
1113 }
1114
setCompressedImage(Context * context,const PixelUnpackState & unpackState,TextureTarget target,GLint level,GLenum internalFormat,const Extents & size,size_t imageSize,const uint8_t * pixels)1115 angle::Result Texture::setCompressedImage(Context *context,
1116 const PixelUnpackState &unpackState,
1117 TextureTarget target,
1118 GLint level,
1119 GLenum internalFormat,
1120 const Extents &size,
1121 size_t imageSize,
1122 const uint8_t *pixels)
1123 {
1124 ASSERT(TextureTargetToType(target) == mState.mType);
1125
1126 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1127 ANGLE_TRY(releaseTexImageInternal(context));
1128 ANGLE_TRY(orphanImages(context));
1129
1130 ImageIndex index = ImageIndex::MakeFromTarget(target, level, size.depth);
1131
1132 ANGLE_TRY(mTexture->setCompressedImage(context, index, internalFormat, size, unpackState,
1133 imageSize, pixels));
1134
1135 Buffer *unpackBuffer = context->getState().getTargetBuffer(BufferBinding::PixelUnpack);
1136
1137 InitState initState = DetermineInitState(context, unpackBuffer, pixels);
1138 mState.setImageDesc(target, level, ImageDesc(size, Format(internalFormat), initState));
1139 signalDirtyStorage(initState);
1140
1141 return angle::Result::Continue;
1142 }
1143
setCompressedSubImage(const Context * context,const PixelUnpackState & unpackState,TextureTarget target,GLint level,const Box & area,GLenum format,size_t imageSize,const uint8_t * pixels)1144 angle::Result Texture::setCompressedSubImage(const Context *context,
1145 const PixelUnpackState &unpackState,
1146 TextureTarget target,
1147 GLint level,
1148 const Box &area,
1149 GLenum format,
1150 size_t imageSize,
1151 const uint8_t *pixels)
1152 {
1153 ASSERT(TextureTargetToType(target) == mState.mType);
1154
1155 ImageIndex index = ImageIndex::MakeFromTarget(target, level, area.depth);
1156 ANGLE_TRY(ensureSubImageInitialized(context, index, area));
1157
1158 ANGLE_TRY(mTexture->setCompressedSubImage(context, index, area, format, unpackState, imageSize,
1159 pixels));
1160
1161 onStateChange(angle::SubjectMessage::ContentsChanged);
1162
1163 return angle::Result::Continue;
1164 }
1165
copyImage(Context * context,TextureTarget target,GLint level,const Rectangle & sourceArea,GLenum internalFormat,Framebuffer * source)1166 angle::Result Texture::copyImage(Context *context,
1167 TextureTarget target,
1168 GLint level,
1169 const Rectangle &sourceArea,
1170 GLenum internalFormat,
1171 Framebuffer *source)
1172 {
1173 ASSERT(TextureTargetToType(target) == mState.mType);
1174
1175 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1176 ANGLE_TRY(releaseTexImageInternal(context));
1177 ANGLE_TRY(orphanImages(context));
1178
1179 ImageIndex index = ImageIndex::MakeFromTarget(target, level, 1);
1180
1181 const InternalFormat &internalFormatInfo =
1182 GetInternalFormatInfo(internalFormat, GL_UNSIGNED_BYTE);
1183
1184 // Most if not all renderers clip these copies to the size of the source framebuffer, leaving
1185 // other pixels untouched. For safety in robust resource initialization, assume that that
1186 // clipping is going to occur when computing the region for which to ensure initialization. If
1187 // the copy lies entirely off the source framebuffer, initialize as though a zero-size box is
1188 // going to be set during the copy operation.
1189 Box destBox;
1190 if (context->isRobustResourceInitEnabled())
1191 {
1192 Extents fbSize = source->getReadColorAttachment()->getSize();
1193 Rectangle clippedArea;
1194 if (ClipRectangle(sourceArea, Rectangle(0, 0, fbSize.width, fbSize.height), &clippedArea))
1195 {
1196 const Offset clippedOffset(clippedArea.x - sourceArea.x, clippedArea.y - sourceArea.y,
1197 0);
1198 destBox = Box(clippedOffset.x, clippedOffset.y, clippedOffset.z, clippedArea.width,
1199 clippedArea.height, 1);
1200 }
1201 }
1202
1203 // If we need to initialize the destination texture we split the call into a create call,
1204 // an initializeContents call, and then a copySubImage call. This ensures the destination
1205 // texture exists before we try to clear it.
1206 Extents size(sourceArea.width, sourceArea.height, 1);
1207 if (doesSubImageNeedInit(context, index, destBox))
1208 {
1209 ANGLE_TRY(mTexture->setImage(context, index, internalFormat, size,
1210 internalFormatInfo.format, internalFormatInfo.type,
1211 PixelUnpackState(), nullptr, nullptr));
1212 mState.setImageDesc(target, level,
1213 ImageDesc(size, Format(internalFormatInfo), InitState::MayNeedInit));
1214 ANGLE_TRY(ensureSubImageInitialized(context, index, destBox));
1215 ANGLE_TRY(mTexture->copySubImage(context, index, Offset(), sourceArea, source));
1216 }
1217 else
1218 {
1219 ANGLE_TRY(mTexture->copyImage(context, index, sourceArea, internalFormat, source));
1220 }
1221
1222 mState.setImageDesc(target, level,
1223 ImageDesc(size, Format(internalFormatInfo), InitState::Initialized));
1224
1225 ANGLE_TRY(handleMipmapGenerationHint(context, level));
1226
1227 // Because this could affect the texture storage we might need to init other layers/levels.
1228 signalDirtyStorage(InitState::MayNeedInit);
1229
1230 return angle::Result::Continue;
1231 }
1232
copySubImage(Context * context,const ImageIndex & index,const Offset & destOffset,const Rectangle & sourceArea,Framebuffer * source)1233 angle::Result Texture::copySubImage(Context *context,
1234 const ImageIndex &index,
1235 const Offset &destOffset,
1236 const Rectangle &sourceArea,
1237 Framebuffer *source)
1238 {
1239 ASSERT(TextureTargetToType(index.getTarget()) == mState.mType);
1240
1241 // Most if not all renderers clip these copies to the size of the source framebuffer, leaving
1242 // other pixels untouched. For safety in robust resource initialization, assume that that
1243 // clipping is going to occur when computing the region for which to ensure initialization. If
1244 // the copy lies entirely off the source framebuffer, initialize as though a zero-size box is
1245 // going to be set during the copy operation. Note that this assumes that
1246 // ensureSubImageInitialized ensures initialization of the entire destination texture, and not
1247 // just a sub-region.
1248 Box destBox;
1249 if (context->isRobustResourceInitEnabled())
1250 {
1251 Extents fbSize = source->getReadColorAttachment()->getSize();
1252 Rectangle clippedArea;
1253 if (ClipRectangle(sourceArea, Rectangle(0, 0, fbSize.width, fbSize.height), &clippedArea))
1254 {
1255 const Offset clippedOffset(destOffset.x + clippedArea.x - sourceArea.x,
1256 destOffset.y + clippedArea.y - sourceArea.y, 0);
1257 destBox = Box(clippedOffset.x, clippedOffset.y, clippedOffset.z, clippedArea.width,
1258 clippedArea.height, 1);
1259 }
1260 }
1261
1262 ANGLE_TRY(ensureSubImageInitialized(context, index, destBox));
1263
1264 ANGLE_TRY(mTexture->copySubImage(context, index, destOffset, sourceArea, source));
1265 ANGLE_TRY(handleMipmapGenerationHint(context, index.getLevelIndex()));
1266
1267 onStateChange(angle::SubjectMessage::ContentsChanged);
1268
1269 return angle::Result::Continue;
1270 }
1271
copyTexture(Context * context,TextureTarget target,GLint level,GLenum internalFormat,GLenum type,GLint sourceLevel,bool unpackFlipY,bool unpackPremultiplyAlpha,bool unpackUnmultiplyAlpha,Texture * source)1272 angle::Result Texture::copyTexture(Context *context,
1273 TextureTarget target,
1274 GLint level,
1275 GLenum internalFormat,
1276 GLenum type,
1277 GLint sourceLevel,
1278 bool unpackFlipY,
1279 bool unpackPremultiplyAlpha,
1280 bool unpackUnmultiplyAlpha,
1281 Texture *source)
1282 {
1283 ASSERT(TextureTargetToType(target) == mState.mType);
1284 ASSERT(source->getType() != TextureType::CubeMap);
1285
1286 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1287 ANGLE_TRY(releaseTexImageInternal(context));
1288 ANGLE_TRY(orphanImages(context));
1289
1290 // Initialize source texture.
1291 // Note: we don't have a way to notify which portions of the image changed currently.
1292 ANGLE_TRY(source->ensureInitialized(context));
1293
1294 ImageIndex index = ImageIndex::MakeFromTarget(target, level, ImageIndex::kEntireLevel);
1295
1296 ANGLE_TRY(mTexture->copyTexture(context, index, internalFormat, type, sourceLevel, unpackFlipY,
1297 unpackPremultiplyAlpha, unpackUnmultiplyAlpha, source));
1298
1299 const auto &sourceDesc =
1300 source->mState.getImageDesc(NonCubeTextureTypeToTarget(source->getType()), 0);
1301 const InternalFormat &internalFormatInfo = GetInternalFormatInfo(internalFormat, type);
1302 mState.setImageDesc(
1303 target, level,
1304 ImageDesc(sourceDesc.size, Format(internalFormatInfo), InitState::Initialized));
1305
1306 signalDirtyStorage(InitState::Initialized);
1307
1308 return angle::Result::Continue;
1309 }
1310
copySubTexture(const Context * context,TextureTarget target,GLint level,const Offset & destOffset,GLint sourceLevel,const Box & sourceBox,bool unpackFlipY,bool unpackPremultiplyAlpha,bool unpackUnmultiplyAlpha,Texture * source)1311 angle::Result Texture::copySubTexture(const Context *context,
1312 TextureTarget target,
1313 GLint level,
1314 const Offset &destOffset,
1315 GLint sourceLevel,
1316 const Box &sourceBox,
1317 bool unpackFlipY,
1318 bool unpackPremultiplyAlpha,
1319 bool unpackUnmultiplyAlpha,
1320 Texture *source)
1321 {
1322 ASSERT(TextureTargetToType(target) == mState.mType);
1323
1324 // Ensure source is initialized.
1325 ANGLE_TRY(source->ensureInitialized(context));
1326
1327 Box destBox(destOffset.x, destOffset.y, destOffset.z, sourceBox.width, sourceBox.height,
1328 sourceBox.depth);
1329 ImageIndex index = ImageIndex::MakeFromTarget(target, level, sourceBox.depth);
1330 ANGLE_TRY(ensureSubImageInitialized(context, index, destBox));
1331
1332 ANGLE_TRY(mTexture->copySubTexture(context, index, destOffset, sourceLevel, sourceBox,
1333 unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha,
1334 source));
1335
1336 onStateChange(angle::SubjectMessage::ContentsChanged);
1337
1338 return angle::Result::Continue;
1339 }
1340
copyCompressedTexture(Context * context,const Texture * source)1341 angle::Result Texture::copyCompressedTexture(Context *context, const Texture *source)
1342 {
1343 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1344 ANGLE_TRY(releaseTexImageInternal(context));
1345 ANGLE_TRY(orphanImages(context));
1346
1347 ANGLE_TRY(mTexture->copyCompressedTexture(context, source));
1348
1349 ASSERT(source->getType() != TextureType::CubeMap && getType() != TextureType::CubeMap);
1350 const auto &sourceDesc =
1351 source->mState.getImageDesc(NonCubeTextureTypeToTarget(source->getType()), 0);
1352 mState.setImageDesc(NonCubeTextureTypeToTarget(getType()), 0, sourceDesc);
1353
1354 return angle::Result::Continue;
1355 }
1356
setStorage(Context * context,TextureType type,GLsizei levels,GLenum internalFormat,const Extents & size)1357 angle::Result Texture::setStorage(Context *context,
1358 TextureType type,
1359 GLsizei levels,
1360 GLenum internalFormat,
1361 const Extents &size)
1362 {
1363 ASSERT(type == mState.mType);
1364
1365 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1366 ANGLE_TRY(releaseTexImageInternal(context));
1367 ANGLE_TRY(orphanImages(context));
1368
1369 mState.mImmutableFormat = true;
1370 mState.mImmutableLevels = static_cast<GLuint>(levels);
1371
1372 ANGLE_TRY(mTexture->setStorage(context, type, levels, internalFormat, size));
1373
1374 mState.clearImageDescs();
1375 mState.setImageDescChain(0, static_cast<GLuint>(levels - 1), size, Format(internalFormat),
1376 InitState::MayNeedInit);
1377
1378 // Changing the texture to immutable can trigger a change in the base and max levels:
1379 // GLES 3.0.4 section 3.8.10 pg 158:
1380 // "For immutable-format textures, levelbase is clamped to the range[0;levels],levelmax is then
1381 // clamped to the range[levelbase;levels].
1382 mDirtyBits.set(DIRTY_BIT_BASE_LEVEL);
1383 mDirtyBits.set(DIRTY_BIT_MAX_LEVEL);
1384
1385 signalDirtyStorage(InitState::MayNeedInit);
1386
1387 return angle::Result::Continue;
1388 }
1389
setImageExternal(Context * context,TextureTarget target,GLint level,GLenum internalFormat,const Extents & size,GLenum format,GLenum type)1390 angle::Result Texture::setImageExternal(Context *context,
1391 TextureTarget target,
1392 GLint level,
1393 GLenum internalFormat,
1394 const Extents &size,
1395 GLenum format,
1396 GLenum type)
1397 {
1398 ASSERT(TextureTargetToType(target) == mState.mType);
1399
1400 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1401 ANGLE_TRY(releaseTexImageInternal(context));
1402 ANGLE_TRY(orphanImages(context));
1403
1404 ImageIndex index = ImageIndex::MakeFromTarget(target, level, size.depth);
1405
1406 ANGLE_TRY(mTexture->setImageExternal(context, index, internalFormat, size, format, type));
1407
1408 InitState initState = InitState::Initialized;
1409 mState.setImageDesc(target, level, ImageDesc(size, Format(internalFormat, type), initState));
1410
1411 ANGLE_TRY(handleMipmapGenerationHint(context, level));
1412
1413 signalDirtyStorage(initState);
1414
1415 return angle::Result::Continue;
1416 }
1417
setStorageMultisample(Context * context,TextureType type,GLsizei samples,GLint internalFormat,const Extents & size,bool fixedSampleLocations)1418 angle::Result Texture::setStorageMultisample(Context *context,
1419 TextureType type,
1420 GLsizei samples,
1421 GLint internalFormat,
1422 const Extents &size,
1423 bool fixedSampleLocations)
1424 {
1425 ASSERT(type == mState.mType);
1426
1427 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1428 ANGLE_TRY(releaseTexImageInternal(context));
1429 ANGLE_TRY(orphanImages(context));
1430
1431 // Potentially adjust "samples" to a supported value
1432 const TextureCaps &formatCaps = context->getTextureCaps().get(internalFormat);
1433 samples = formatCaps.getNearestSamples(samples);
1434
1435 ANGLE_TRY(mTexture->setStorageMultisample(context, type, samples, internalFormat, size,
1436 fixedSampleLocations));
1437
1438 mState.mImmutableFormat = true;
1439 mState.mImmutableLevels = static_cast<GLuint>(1);
1440 mState.clearImageDescs();
1441 mState.setImageDescChainMultisample(size, Format(internalFormat), samples, fixedSampleLocations,
1442 InitState::MayNeedInit);
1443
1444 signalDirtyStorage(InitState::MayNeedInit);
1445
1446 return angle::Result::Continue;
1447 }
1448
setStorageExternalMemory(Context * context,TextureType type,GLsizei levels,GLenum internalFormat,const Extents & size,MemoryObject * memoryObject,GLuint64 offset)1449 angle::Result Texture::setStorageExternalMemory(Context *context,
1450 TextureType type,
1451 GLsizei levels,
1452 GLenum internalFormat,
1453 const Extents &size,
1454 MemoryObject *memoryObject,
1455 GLuint64 offset)
1456 {
1457 ASSERT(type == mState.mType);
1458
1459 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1460 ANGLE_TRY(releaseTexImageInternal(context));
1461 ANGLE_TRY(orphanImages(context));
1462
1463 ANGLE_TRY(mTexture->setStorageExternalMemory(context, type, levels, internalFormat, size,
1464 memoryObject, offset));
1465
1466 mState.mImmutableFormat = true;
1467 mState.mImmutableLevels = static_cast<GLuint>(levels);
1468 mState.clearImageDescs();
1469 mState.setImageDescChain(0, static_cast<GLuint>(levels - 1), size, Format(internalFormat),
1470 InitState::MayNeedInit);
1471
1472 // Changing the texture to immutable can trigger a change in the base and max levels:
1473 // GLES 3.0.4 section 3.8.10 pg 158:
1474 // "For immutable-format textures, levelbase is clamped to the range[0;levels],levelmax is then
1475 // clamped to the range[levelbase;levels].
1476 mDirtyBits.set(DIRTY_BIT_BASE_LEVEL);
1477 mDirtyBits.set(DIRTY_BIT_MAX_LEVEL);
1478
1479 signalDirtyStorage(InitState::Initialized);
1480
1481 return angle::Result::Continue;
1482 }
1483
generateMipmap(Context * context)1484 angle::Result Texture::generateMipmap(Context *context)
1485 {
1486 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1487 ANGLE_TRY(releaseTexImageInternal(context));
1488
1489 // EGL_KHR_gl_image states that images are only orphaned when generating mipmaps if the texture
1490 // is not mip complete.
1491 if (!isMipmapComplete())
1492 {
1493 ANGLE_TRY(orphanImages(context));
1494 }
1495
1496 const GLuint baseLevel = mState.getEffectiveBaseLevel();
1497 const GLuint maxLevel = mState.getMipmapMaxLevel();
1498
1499 if (maxLevel <= baseLevel)
1500 {
1501 return angle::Result::Continue;
1502 }
1503
1504 if (hasAnyDirtyBit())
1505 {
1506 ANGLE_TRY(syncState(context));
1507 }
1508
1509 // Clear the base image(s) immediately if needed
1510 if (context->isRobustResourceInitEnabled())
1511 {
1512 ImageIndexIterator it =
1513 ImageIndexIterator::MakeGeneric(mState.mType, baseLevel, baseLevel + 1,
1514 ImageIndex::kEntireLevel, ImageIndex::kEntireLevel);
1515 while (it.hasNext())
1516 {
1517 const ImageIndex index = it.next();
1518 const ImageDesc &desc = mState.getImageDesc(index.getTarget(), index.getLevelIndex());
1519
1520 if (desc.initState == InitState::MayNeedInit)
1521 {
1522 ANGLE_TRY(initializeContents(context, index));
1523 }
1524 }
1525 }
1526
1527 ANGLE_TRY(mTexture->generateMipmap(context));
1528
1529 // Propagate the format and size of the bsae mip to the smaller ones. Cube maps are guaranteed
1530 // to have faces of the same size and format so any faces can be picked.
1531 const ImageDesc &baseImageInfo = mState.getImageDesc(mState.getBaseImageTarget(), baseLevel);
1532 mState.setImageDescChain(baseLevel, maxLevel, baseImageInfo.size, baseImageInfo.format,
1533 InitState::Initialized);
1534
1535 signalDirtyStorage(InitState::Initialized);
1536
1537 return angle::Result::Continue;
1538 }
1539
bindTexImageFromSurface(Context * context,egl::Surface * surface)1540 angle::Result Texture::bindTexImageFromSurface(Context *context, egl::Surface *surface)
1541 {
1542 ASSERT(surface);
1543
1544 if (mBoundSurface)
1545 {
1546 ANGLE_TRY(releaseTexImageFromSurface(context));
1547 }
1548
1549 ANGLE_TRY(mTexture->bindTexImage(context, surface));
1550 mBoundSurface = surface;
1551
1552 // Set the image info to the size and format of the surface
1553 ASSERT(mState.mType == TextureType::_2D || mState.mType == TextureType::Rectangle);
1554 Extents size(surface->getWidth(), surface->getHeight(), 1);
1555 ImageDesc desc(size, surface->getBindTexImageFormat(), InitState::Initialized);
1556 mState.setImageDesc(NonCubeTextureTypeToTarget(mState.mType), 0, desc);
1557 signalDirtyStorage(InitState::Initialized);
1558 return angle::Result::Continue;
1559 }
1560
releaseTexImageFromSurface(const Context * context)1561 angle::Result Texture::releaseTexImageFromSurface(const Context *context)
1562 {
1563 ASSERT(mBoundSurface);
1564 mBoundSurface = nullptr;
1565 ANGLE_TRY(mTexture->releaseTexImage(context));
1566
1567 // Erase the image info for level 0
1568 ASSERT(mState.mType == TextureType::_2D || mState.mType == TextureType::Rectangle);
1569 mState.clearImageDesc(NonCubeTextureTypeToTarget(mState.mType), 0);
1570 signalDirtyStorage(InitState::Initialized);
1571 return angle::Result::Continue;
1572 }
1573
bindStream(egl::Stream * stream)1574 void Texture::bindStream(egl::Stream *stream)
1575 {
1576 ASSERT(stream);
1577
1578 // It should not be possible to bind a texture already bound to another stream
1579 ASSERT(mBoundStream == nullptr);
1580
1581 mBoundStream = stream;
1582
1583 ASSERT(mState.mType == TextureType::External);
1584 }
1585
releaseStream()1586 void Texture::releaseStream()
1587 {
1588 ASSERT(mBoundStream);
1589 mBoundStream = nullptr;
1590 }
1591
acquireImageFromStream(const Context * context,const egl::Stream::GLTextureDescription & desc)1592 angle::Result Texture::acquireImageFromStream(const Context *context,
1593 const egl::Stream::GLTextureDescription &desc)
1594 {
1595 ASSERT(mBoundStream != nullptr);
1596 ANGLE_TRY(mTexture->setImageExternal(context, mState.mType, mBoundStream, desc));
1597
1598 Extents size(desc.width, desc.height, 1);
1599 mState.setImageDesc(NonCubeTextureTypeToTarget(mState.mType), 0,
1600 ImageDesc(size, Format(desc.internalFormat), InitState::Initialized));
1601 signalDirtyStorage(InitState::Initialized);
1602 return angle::Result::Continue;
1603 }
1604
releaseImageFromStream(const Context * context)1605 angle::Result Texture::releaseImageFromStream(const Context *context)
1606 {
1607 ASSERT(mBoundStream != nullptr);
1608 ANGLE_TRY(mTexture->setImageExternal(context, mState.mType, nullptr,
1609 egl::Stream::GLTextureDescription()));
1610
1611 // Set to incomplete
1612 mState.clearImageDesc(NonCubeTextureTypeToTarget(mState.mType), 0);
1613 signalDirtyStorage(InitState::Initialized);
1614 return angle::Result::Continue;
1615 }
1616
releaseTexImageInternal(Context * context)1617 angle::Result Texture::releaseTexImageInternal(Context *context)
1618 {
1619 if (mBoundSurface)
1620 {
1621 // Notify the surface
1622 egl::Error eglErr = mBoundSurface->releaseTexImageFromTexture(context);
1623 // TODO(jmadill): Remove this once refactor is complete. http://anglebug.com/3041
1624 if (eglErr.isError())
1625 {
1626 context->handleError(GL_INVALID_OPERATION, "Error releasing tex image from texture",
1627 __FILE__, ANGLE_FUNCTION, __LINE__);
1628 }
1629
1630 // Then, call the same method as from the surface
1631 ANGLE_TRY(releaseTexImageFromSurface(context));
1632 }
1633 return angle::Result::Continue;
1634 }
1635
setEGLImageTarget(Context * context,TextureType type,egl::Image * imageTarget)1636 angle::Result Texture::setEGLImageTarget(Context *context,
1637 TextureType type,
1638 egl::Image *imageTarget)
1639 {
1640 ASSERT(type == mState.mType);
1641 ASSERT(type == TextureType::_2D || type == TextureType::External ||
1642 type == TextureType::_2DArray);
1643
1644 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1645 ANGLE_TRY(releaseTexImageInternal(context));
1646 ANGLE_TRY(orphanImages(context));
1647
1648 ANGLE_TRY(mTexture->setEGLImageTarget(context, type, imageTarget));
1649
1650 setTargetImage(context, imageTarget);
1651
1652 Extents size(static_cast<int>(imageTarget->getWidth()),
1653 static_cast<int>(imageTarget->getHeight()), 1);
1654
1655 auto initState = imageTarget->sourceInitState();
1656
1657 mState.clearImageDescs();
1658 mState.setImageDesc(NonCubeTextureTypeToTarget(type), 0,
1659 ImageDesc(size, imageTarget->getFormat(), initState));
1660 signalDirtyStorage(initState);
1661
1662 return angle::Result::Continue;
1663 }
1664
getAttachmentSize(const ImageIndex & imageIndex) const1665 Extents Texture::getAttachmentSize(const ImageIndex &imageIndex) const
1666 {
1667 // As an ImageIndex that represents an entire level of a cube map corresponds to 6 ImageDescs,
1668 // we only allow querying ImageDesc on a complete cube map, and this ImageDesc is exactly the
1669 // one that belongs to the first face of the cube map.
1670 if (imageIndex.isEntireLevelCubeMap())
1671 {
1672 // A cube map texture is cube complete if the following conditions all hold true:
1673 // - The levelbase arrays of each of the six texture images making up the cube map have
1674 // identical, positive, and square dimensions.
1675 if (!mState.isCubeComplete())
1676 {
1677 return Extents();
1678 }
1679 }
1680
1681 return mState.getImageDesc(imageIndex).size;
1682 }
1683
getAttachmentFormat(GLenum,const ImageIndex & imageIndex) const1684 Format Texture::getAttachmentFormat(GLenum /*binding*/, const ImageIndex &imageIndex) const
1685 {
1686 // As an ImageIndex that represents an entire level of a cube map corresponds to 6 ImageDescs,
1687 // we only allow querying ImageDesc on a complete cube map, and this ImageDesc is exactly the
1688 // one that belongs to the first face of the cube map.
1689 if (imageIndex.isEntireLevelCubeMap())
1690 {
1691 // A cube map texture is cube complete if the following conditions all hold true:
1692 // - The levelbase arrays were each specified with the same effective internal format.
1693 if (!mState.isCubeComplete())
1694 {
1695 return Format::Invalid();
1696 }
1697 }
1698 return mState.getImageDesc(imageIndex).format;
1699 }
1700
getAttachmentSamples(const ImageIndex & imageIndex) const1701 GLsizei Texture::getAttachmentSamples(const ImageIndex &imageIndex) const
1702 {
1703 // We do not allow querying TextureTarget by an ImageIndex that represents an entire level of a
1704 // cube map (See comments in function TextureTypeToTarget() in ImageIndex.cpp).
1705 if (imageIndex.isEntireLevelCubeMap())
1706 {
1707 return 0;
1708 }
1709
1710 return getSamples(imageIndex.getTarget(), imageIndex.getLevelIndex());
1711 }
1712
isRenderable(const Context * context,GLenum binding,const ImageIndex & imageIndex) const1713 bool Texture::isRenderable(const Context *context,
1714 GLenum binding,
1715 const ImageIndex &imageIndex) const
1716 {
1717 if (isEGLImageTarget())
1718 {
1719 return ImageSibling::isRenderable(context, binding, imageIndex);
1720 }
1721 return getAttachmentFormat(binding, imageIndex)
1722 .info->textureAttachmentSupport(context->getClientVersion(), context->getExtensions());
1723 }
1724
getAttachmentFixedSampleLocations(const ImageIndex & imageIndex) const1725 bool Texture::getAttachmentFixedSampleLocations(const ImageIndex &imageIndex) const
1726 {
1727 // We do not allow querying TextureTarget by an ImageIndex that represents an entire level of a
1728 // cube map (See comments in function TextureTypeToTarget() in ImageIndex.cpp).
1729 if (imageIndex.isEntireLevelCubeMap())
1730 {
1731 return true;
1732 }
1733
1734 // ES3.1 (section 9.4) requires that the value of TEXTURE_FIXED_SAMPLE_LOCATIONS should be
1735 // the same for all attached textures.
1736 return getFixedSampleLocations(imageIndex.getTarget(), imageIndex.getLevelIndex());
1737 }
1738
setBorderColor(const Context * context,const ColorGeneric & color)1739 void Texture::setBorderColor(const Context *context, const ColorGeneric &color)
1740 {
1741 mState.mSamplerState.setBorderColor(color);
1742 signalDirtyState(DIRTY_BIT_BORDER_COLOR);
1743 }
1744
getBorderColor() const1745 const ColorGeneric &Texture::getBorderColor() const
1746 {
1747 return mState.mSamplerState.getBorderColor();
1748 }
1749
setCrop(const Rectangle & rect)1750 void Texture::setCrop(const Rectangle &rect)
1751 {
1752 mState.setCrop(rect);
1753 }
1754
getCrop() const1755 const Rectangle &Texture::getCrop() const
1756 {
1757 return mState.getCrop();
1758 }
1759
setGenerateMipmapHint(GLenum hint)1760 void Texture::setGenerateMipmapHint(GLenum hint)
1761 {
1762 mState.setGenerateMipmapHint(hint);
1763 }
1764
getGenerateMipmapHint() const1765 GLenum Texture::getGenerateMipmapHint() const
1766 {
1767 return mState.getGenerateMipmapHint();
1768 }
1769
onAttach(const Context * context)1770 void Texture::onAttach(const Context *context)
1771 {
1772 addRef();
1773 }
1774
onDetach(const Context * context)1775 void Texture::onDetach(const Context *context)
1776 {
1777 release(context);
1778 }
1779
getId() const1780 GLuint Texture::getId() const
1781 {
1782 return id().value;
1783 }
1784
getNativeID() const1785 GLuint Texture::getNativeID() const
1786 {
1787 return mTexture->getNativeID();
1788 }
1789
syncState(const Context * context)1790 angle::Result Texture::syncState(const Context *context)
1791 {
1792 ASSERT(hasAnyDirtyBit());
1793 ANGLE_TRY(mTexture->syncState(context, mDirtyBits));
1794 mDirtyBits.reset();
1795 return angle::Result::Continue;
1796 }
1797
getAttachmentImpl() const1798 rx::FramebufferAttachmentObjectImpl *Texture::getAttachmentImpl() const
1799 {
1800 return mTexture;
1801 }
1802
isSamplerComplete(const Context * context,const Sampler * optionalSampler)1803 bool Texture::isSamplerComplete(const Context *context, const Sampler *optionalSampler)
1804 {
1805 const auto &samplerState =
1806 optionalSampler ? optionalSampler->getSamplerState() : mState.mSamplerState;
1807 const auto &contextState = context->getState();
1808
1809 if (contextState.getContextID() != mCompletenessCache.context ||
1810 !mCompletenessCache.samplerState.sameCompleteness(samplerState))
1811 {
1812 mCompletenessCache.context = context->getState().getContextID();
1813 mCompletenessCache.samplerState = samplerState;
1814 mCompletenessCache.samplerComplete =
1815 mState.computeSamplerCompleteness(samplerState, contextState);
1816 }
1817
1818 return mCompletenessCache.samplerComplete;
1819 }
1820
SamplerCompletenessCache()1821 Texture::SamplerCompletenessCache::SamplerCompletenessCache()
1822 : context(0), samplerState(), samplerComplete(false)
1823 {}
1824
invalidateCompletenessCache() const1825 void Texture::invalidateCompletenessCache() const
1826 {
1827 mCompletenessCache.context = 0;
1828 }
1829
ensureInitialized(const Context * context)1830 angle::Result Texture::ensureInitialized(const Context *context)
1831 {
1832 if (!context->isRobustResourceInitEnabled() || mState.mInitState == InitState::Initialized)
1833 {
1834 return angle::Result::Continue;
1835 }
1836
1837 bool anyDirty = false;
1838
1839 ImageIndexIterator it =
1840 ImageIndexIterator::MakeGeneric(mState.mType, 0, IMPLEMENTATION_MAX_TEXTURE_LEVELS + 1,
1841 ImageIndex::kEntireLevel, ImageIndex::kEntireLevel);
1842 while (it.hasNext())
1843 {
1844 const ImageIndex index = it.next();
1845 ImageDesc &desc =
1846 mState.mImageDescs[GetImageDescIndex(index.getTarget(), index.getLevelIndex())];
1847 if (desc.initState == InitState::MayNeedInit && !desc.size.empty())
1848 {
1849 ASSERT(mState.mInitState == InitState::MayNeedInit);
1850 ANGLE_TRY(initializeContents(context, index));
1851 desc.initState = InitState::Initialized;
1852 anyDirty = true;
1853 }
1854 }
1855 if (anyDirty)
1856 {
1857 signalDirtyStorage(InitState::Initialized);
1858 }
1859 mState.mInitState = InitState::Initialized;
1860
1861 return angle::Result::Continue;
1862 }
1863
initState(const ImageIndex & imageIndex) const1864 InitState Texture::initState(const ImageIndex &imageIndex) const
1865 {
1866 // As an ImageIndex that represents an entire level of a cube map corresponds to 6 ImageDescs,
1867 // we need to check all the related ImageDescs.
1868 if (imageIndex.isEntireLevelCubeMap())
1869 {
1870 const GLint levelIndex = imageIndex.getLevelIndex();
1871 for (TextureTarget cubeFaceTarget : AllCubeFaceTextureTargets())
1872 {
1873 if (mState.getImageDesc(cubeFaceTarget, levelIndex).initState == InitState::MayNeedInit)
1874 {
1875 return InitState::MayNeedInit;
1876 }
1877 }
1878 return InitState::Initialized;
1879 }
1880
1881 return mState.getImageDesc(imageIndex).initState;
1882 }
1883
setInitState(const ImageIndex & imageIndex,InitState initState)1884 void Texture::setInitState(const ImageIndex &imageIndex, InitState initState)
1885 {
1886 // As an ImageIndex that represents an entire level of a cube map corresponds to 6 ImageDescs,
1887 // we need to update all the related ImageDescs.
1888 if (imageIndex.isEntireLevelCubeMap())
1889 {
1890 const GLint levelIndex = imageIndex.getLevelIndex();
1891 for (TextureTarget cubeFaceTarget : AllCubeFaceTextureTargets())
1892 {
1893 setInitState(ImageIndex::MakeCubeMapFace(cubeFaceTarget, levelIndex), initState);
1894 }
1895 }
1896 else
1897 {
1898 ImageDesc newDesc = mState.getImageDesc(imageIndex);
1899 newDesc.initState = initState;
1900 mState.setImageDesc(imageIndex.getTarget(), imageIndex.getLevelIndex(), newDesc);
1901 }
1902 }
1903
doesSubImageNeedInit(const Context * context,const ImageIndex & imageIndex,const Box & area) const1904 bool Texture::doesSubImageNeedInit(const Context *context,
1905 const ImageIndex &imageIndex,
1906 const Box &area) const
1907 {
1908 if (!context->isRobustResourceInitEnabled() || mState.mInitState == InitState::Initialized)
1909 {
1910 return false;
1911 }
1912
1913 // Pre-initialize the texture contents if necessary.
1914 const ImageDesc &desc = mState.getImageDesc(imageIndex);
1915 if (desc.initState != InitState::MayNeedInit)
1916 {
1917 return false;
1918 }
1919
1920 ASSERT(mState.mInitState == InitState::MayNeedInit);
1921 bool coversWholeImage = area.x == 0 && area.y == 0 && area.z == 0 &&
1922 area.width == desc.size.width && area.height == desc.size.height &&
1923 area.depth == desc.size.depth;
1924 return !coversWholeImage;
1925 }
1926
ensureSubImageInitialized(const Context * context,const ImageIndex & imageIndex,const Box & area)1927 angle::Result Texture::ensureSubImageInitialized(const Context *context,
1928 const ImageIndex &imageIndex,
1929 const Box &area)
1930 {
1931 if (doesSubImageNeedInit(context, imageIndex, area))
1932 {
1933 // NOTE: do not optimize this to only initialize the passed area of the texture, or the
1934 // initialization logic in copySubImage will be incorrect.
1935 ANGLE_TRY(initializeContents(context, imageIndex));
1936 }
1937 setInitState(imageIndex, InitState::Initialized);
1938 return angle::Result::Continue;
1939 }
1940
handleMipmapGenerationHint(Context * context,int level)1941 angle::Result Texture::handleMipmapGenerationHint(Context *context, int level)
1942 {
1943 if (getGenerateMipmapHint() == GL_TRUE && level == 0)
1944 {
1945 ANGLE_TRY(generateMipmap(context));
1946 }
1947
1948 return angle::Result::Continue;
1949 }
1950
onSubjectStateChange(angle::SubjectIndex index,angle::SubjectMessage message)1951 void Texture::onSubjectStateChange(angle::SubjectIndex index, angle::SubjectMessage message)
1952 {
1953 switch (message)
1954 {
1955 case angle::SubjectMessage::ContentsChanged:
1956 // ContentsChange is originates from TextureStorage11::resolveAndReleaseTexture
1957 // which resolves the underlying multisampled texture if it exists and so
1958 // Texture will signal dirty storage to invalidate its own cache and the
1959 // attached framebuffer's cache.
1960 signalDirtyStorage(InitState::Initialized);
1961 break;
1962 case angle::SubjectMessage::DirtyBitsFlagged:
1963 signalDirtyState(DIRTY_BIT_IMPLEMENTATION);
1964
1965 // Notify siblings that we are dirty.
1966 if (index == rx::kTextureImageImplObserverMessageIndex)
1967 {
1968 notifySiblings(message);
1969 }
1970 break;
1971 case angle::SubjectMessage::SubjectChanged:
1972 mState.mInitState = InitState::MayNeedInit;
1973 signalDirtyState(DIRTY_BIT_IMPLEMENTATION);
1974 onStateChange(angle::SubjectMessage::ContentsChanged);
1975
1976 // Notify siblings that we are dirty.
1977 if (index == rx::kTextureImageImplObserverMessageIndex)
1978 {
1979 notifySiblings(message);
1980 }
1981 break;
1982 default:
1983 UNREACHABLE();
1984 break;
1985 }
1986 }
1987
getImplementationColorReadFormat(const Context * context) const1988 GLenum Texture::getImplementationColorReadFormat(const Context *context) const
1989 {
1990 return mTexture->getColorReadFormat(context);
1991 }
1992
getImplementationColorReadType(const Context * context) const1993 GLenum Texture::getImplementationColorReadType(const Context *context) const
1994 {
1995 return mTexture->getColorReadType(context);
1996 }
1997
getTexImage(const Context * context,const PixelPackState & packState,Buffer * packBuffer,TextureTarget target,GLint level,GLenum format,GLenum type,void * pixels)1998 angle::Result Texture::getTexImage(const Context *context,
1999 const PixelPackState &packState,
2000 Buffer *packBuffer,
2001 TextureTarget target,
2002 GLint level,
2003 GLenum format,
2004 GLenum type,
2005 void *pixels)
2006 {
2007 if (hasAnyDirtyBit())
2008 {
2009 ANGLE_TRY(syncState(context));
2010 }
2011
2012 return mTexture->getTexImage(context, packState, packBuffer, target, level, format, type,
2013 pixels);
2014 }
2015
onBindAsImageTexture(ContextID contextID)2016 void Texture::onBindAsImageTexture(ContextID contextID)
2017 {
2018 ContextBindingCount &bindingCount = mState.getBindingCount(contextID);
2019
2020 ASSERT(bindingCount.imageBindingCount < std::numeric_limits<uint32_t>::max());
2021 mState.getBindingCount(contextID).imageBindingCount++;
2022 if (bindingCount.imageBindingCount == 1)
2023 {
2024 mDirtyBits.set(DIRTY_BIT_BOUND_AS_IMAGE);
2025 }
2026 }
2027
2028 } // namespace gl
2029