1 //
2 // Copyright (c) 2002-2014 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/ContextState.h"
16 #include "libANGLE/Image.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.magFilter == GL_NEAREST &&
30 (samplerState.minFilter == GL_NEAREST ||
31 samplerState.minFilter == GL_NEAREST_MIPMAP_NEAREST));
32 }
33
GetImageDescIndex(GLenum target,size_t level)34 size_t GetImageDescIndex(GLenum target, size_t level)
35 {
36 return IsCubeMapTextureTarget(target) ? ((level * 6) + CubeMapTextureTargetToLayerIndex(target))
37 : level;
38 }
39
GetImageIndexFromDescIndex(GLenum target,size_t descIndex)40 ImageIndex GetImageIndexFromDescIndex(GLenum target, size_t descIndex)
41 {
42 if (target == GL_TEXTURE_CUBE_MAP)
43 {
44 size_t faceIndex = descIndex % 6;
45 size_t mipIndex = descIndex / 6;
46 return ImageIndex::MakeCube(LayerIndexToCubeMapTextureTarget(faceIndex),
47 static_cast<GLint>(mipIndex));
48 }
49
50 return ImageIndex::MakeGeneric(target, static_cast<GLint>(descIndex));
51 }
52
DetermineInitState(const Context * context,const uint8_t * pixels)53 InitState DetermineInitState(const Context *context, const uint8_t *pixels)
54 {
55 // Can happen in tests.
56 if (!context || !context->isRobustResourceInitEnabled())
57 return InitState::Initialized;
58
59 const auto &glState = context->getGLState();
60 return (pixels == nullptr && glState.getTargetBuffer(gl::BufferBinding::PixelUnpack) == nullptr)
61 ? InitState::MayNeedInit
62 : InitState::Initialized;
63 }
64
65 } // namespace
66
IsMipmapFiltered(const SamplerState & samplerState)67 bool IsMipmapFiltered(const SamplerState &samplerState)
68 {
69 switch (samplerState.minFilter)
70 {
71 case GL_NEAREST:
72 case GL_LINEAR:
73 return false;
74 case GL_NEAREST_MIPMAP_NEAREST:
75 case GL_LINEAR_MIPMAP_NEAREST:
76 case GL_NEAREST_MIPMAP_LINEAR:
77 case GL_LINEAR_MIPMAP_LINEAR:
78 return true;
79 default:
80 UNREACHABLE();
81 return false;
82 }
83 }
84
SwizzleState()85 SwizzleState::SwizzleState()
86 : swizzleRed(GL_INVALID_INDEX),
87 swizzleGreen(GL_INVALID_INDEX),
88 swizzleBlue(GL_INVALID_INDEX),
89 swizzleAlpha(GL_INVALID_INDEX)
90 {
91 }
92
SwizzleState(GLenum red,GLenum green,GLenum blue,GLenum alpha)93 SwizzleState::SwizzleState(GLenum red, GLenum green, GLenum blue, GLenum alpha)
94 : swizzleRed(red), swizzleGreen(green), swizzleBlue(blue), swizzleAlpha(alpha)
95 {
96 }
97
swizzleRequired() const98 bool SwizzleState::swizzleRequired() const
99 {
100 return swizzleRed != GL_RED || swizzleGreen != GL_GREEN || swizzleBlue != GL_BLUE ||
101 swizzleAlpha != GL_ALPHA;
102 }
103
operator ==(const SwizzleState & other) const104 bool SwizzleState::operator==(const SwizzleState &other) const
105 {
106 return swizzleRed == other.swizzleRed && swizzleGreen == other.swizzleGreen &&
107 swizzleBlue == other.swizzleBlue && swizzleAlpha == other.swizzleAlpha;
108 }
109
operator !=(const SwizzleState & other) const110 bool SwizzleState::operator!=(const SwizzleState &other) const
111 {
112 return !(*this == other);
113 }
114
TextureState(GLenum target)115 TextureState::TextureState(GLenum target)
116 : mTarget(target),
117 mSwizzleState(GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA),
118 mSamplerState(SamplerState::CreateDefaultForTarget(target)),
119 mBaseLevel(0),
120 mMaxLevel(1000),
121 mDepthStencilTextureMode(GL_DEPTH_COMPONENT),
122 mImmutableFormat(false),
123 mImmutableLevels(0),
124 mUsage(GL_NONE),
125 mImageDescs((IMPLEMENTATION_MAX_TEXTURE_LEVELS + 1) *
126 (target == GL_TEXTURE_CUBE_MAP ? 6 : 1)),
127 mInitState(InitState::MayNeedInit)
128 {
129 }
130
~TextureState()131 TextureState::~TextureState()
132 {
133 }
134
swizzleRequired() const135 bool TextureState::swizzleRequired() const
136 {
137 return mSwizzleState.swizzleRequired();
138 }
139
getEffectiveBaseLevel() const140 GLuint TextureState::getEffectiveBaseLevel() const
141 {
142 if (mImmutableFormat)
143 {
144 // GLES 3.0.4 section 3.8.10
145 return std::min(mBaseLevel, mImmutableLevels - 1);
146 }
147 // Some classes use the effective base level to index arrays with level data. By clamping the
148 // effective base level to max levels these arrays need just one extra item to store properties
149 // that should be returned for all out-of-range base level values, instead of needing special
150 // handling for out-of-range base levels.
151 return std::min(mBaseLevel, static_cast<GLuint>(IMPLEMENTATION_MAX_TEXTURE_LEVELS));
152 }
153
getEffectiveMaxLevel() const154 GLuint TextureState::getEffectiveMaxLevel() const
155 {
156 if (mImmutableFormat)
157 {
158 // GLES 3.0.4 section 3.8.10
159 GLuint clampedMaxLevel = std::max(mMaxLevel, getEffectiveBaseLevel());
160 clampedMaxLevel = std::min(clampedMaxLevel, mImmutableLevels - 1);
161 return clampedMaxLevel;
162 }
163 return mMaxLevel;
164 }
165
getMipmapMaxLevel() const166 GLuint TextureState::getMipmapMaxLevel() const
167 {
168 const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), getEffectiveBaseLevel());
169 GLuint expectedMipLevels = 0;
170 if (mTarget == GL_TEXTURE_3D)
171 {
172 const int maxDim = std::max(std::max(baseImageDesc.size.width, baseImageDesc.size.height),
173 baseImageDesc.size.depth);
174 expectedMipLevels = static_cast<GLuint>(log2(maxDim));
175 }
176 else
177 {
178 expectedMipLevels = static_cast<GLuint>(
179 log2(std::max(baseImageDesc.size.width, baseImageDesc.size.height)));
180 }
181
182 return std::min<GLuint>(getEffectiveBaseLevel() + expectedMipLevels, getEffectiveMaxLevel());
183 }
184
setBaseLevel(GLuint baseLevel)185 bool TextureState::setBaseLevel(GLuint baseLevel)
186 {
187 if (mBaseLevel != baseLevel)
188 {
189 mBaseLevel = baseLevel;
190 return true;
191 }
192 return false;
193 }
194
setMaxLevel(GLuint maxLevel)195 bool TextureState::setMaxLevel(GLuint maxLevel)
196 {
197 if (mMaxLevel != maxLevel)
198 {
199 mMaxLevel = maxLevel;
200 return true;
201 }
202
203 return false;
204 }
205
206 // Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
207 // According to [OpenGL ES 3.0.5] section 3.8.13 Texture Completeness page 160 any
208 // per-level checks begin at the base-level.
209 // For OpenGL ES2 the base level is always zero.
isCubeComplete() const210 bool TextureState::isCubeComplete() const
211 {
212 ASSERT(mTarget == GL_TEXTURE_CUBE_MAP);
213
214 const ImageDesc &baseImageDesc =
215 getImageDesc(FirstCubeMapTextureTarget, getEffectiveBaseLevel());
216 if (baseImageDesc.size.width == 0 || baseImageDesc.size.width != baseImageDesc.size.height)
217 {
218 return false;
219 }
220
221 for (GLenum face = FirstCubeMapTextureTarget + 1; face <= LastCubeMapTextureTarget; face++)
222 {
223 const ImageDesc &faceImageDesc = getImageDesc(face, getEffectiveBaseLevel());
224 if (faceImageDesc.size.width != baseImageDesc.size.width ||
225 faceImageDesc.size.height != baseImageDesc.size.height ||
226 !Format::SameSized(faceImageDesc.format, baseImageDesc.format))
227 {
228 return false;
229 }
230 }
231
232 return true;
233 }
234
computeSamplerCompleteness(const SamplerState & samplerState,const ContextState & data) const235 bool TextureState::computeSamplerCompleteness(const SamplerState &samplerState,
236 const ContextState &data) const
237 {
238 if (mBaseLevel > mMaxLevel)
239 {
240 return false;
241 }
242 const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), getEffectiveBaseLevel());
243 if (baseImageDesc.size.width == 0 || baseImageDesc.size.height == 0 ||
244 baseImageDesc.size.depth == 0)
245 {
246 return false;
247 }
248 // The cases where the texture is incomplete because base level is out of range should be
249 // handled by the above condition.
250 ASSERT(mBaseLevel < IMPLEMENTATION_MAX_TEXTURE_LEVELS || mImmutableFormat);
251
252 if (mTarget == GL_TEXTURE_CUBE_MAP && baseImageDesc.size.width != baseImageDesc.size.height)
253 {
254 return false;
255 }
256
257 // According to es 3.1 spec, texture is justified as incomplete if sized internalformat is
258 // unfilterable(table 20.11) and filter is not GL_NEAREST(8.16). The default value of minFilter
259 // is NEAREST_MIPMAP_LINEAR and magFilter is LINEAR(table 20.11,). For multismaple texture,
260 // filter state of multisample texture is ignored(11.1.3.3). So it shouldn't be judged as
261 // incomplete texture. So, we ignore filtering for multisample texture completeness here.
262 if (mTarget != GL_TEXTURE_2D_MULTISAMPLE &&
263 !baseImageDesc.format.info->filterSupport(data.getClientVersion(), data.getExtensions()) &&
264 !IsPointSampled(samplerState))
265 {
266 return false;
267 }
268 bool npotSupport = data.getExtensions().textureNPOT || data.getClientMajorVersion() >= 3;
269 if (!npotSupport)
270 {
271 if ((samplerState.wrapS != GL_CLAMP_TO_EDGE && !isPow2(baseImageDesc.size.width)) ||
272 (samplerState.wrapT != GL_CLAMP_TO_EDGE && !isPow2(baseImageDesc.size.height)))
273 {
274 return false;
275 }
276 }
277
278 if (mTarget != GL_TEXTURE_2D_MULTISAMPLE && IsMipmapFiltered(samplerState))
279 {
280 if (!npotSupport)
281 {
282 if (!isPow2(baseImageDesc.size.width) || !isPow2(baseImageDesc.size.height))
283 {
284 return false;
285 }
286 }
287
288 if (!computeMipmapCompleteness())
289 {
290 return false;
291 }
292 }
293 else
294 {
295 if (mTarget == GL_TEXTURE_CUBE_MAP && !isCubeComplete())
296 {
297 return false;
298 }
299 }
300
301 // From GL_OES_EGL_image_external_essl3: If state is present in a sampler object bound to a
302 // texture unit that would have been rejected by a call to TexParameter* for the texture bound
303 // to that unit, the behavior of the implementation is as if the texture were incomplete. For
304 // example, if TEXTURE_WRAP_S or TEXTURE_WRAP_T is set to anything but CLAMP_TO_EDGE on the
305 // sampler object bound to a texture unit and the texture bound to that unit is an external
306 // texture, the texture will be considered incomplete.
307 // Sampler object state which does not affect sampling for the type of texture bound to a
308 // texture unit, such as TEXTURE_WRAP_R for an external texture, does not affect completeness.
309 if (mTarget == GL_TEXTURE_EXTERNAL_OES)
310 {
311 if (samplerState.wrapS != GL_CLAMP_TO_EDGE || samplerState.wrapT != GL_CLAMP_TO_EDGE)
312 {
313 return false;
314 }
315
316 if (samplerState.minFilter != GL_LINEAR && samplerState.minFilter != GL_NEAREST)
317 {
318 return false;
319 }
320 }
321
322 // OpenGLES 3.0.2 spec section 3.8.13 states that a texture is not mipmap complete if:
323 // The internalformat specified for the texture arrays is a sized internal depth or
324 // depth and stencil format (see table 3.13), the value of TEXTURE_COMPARE_-
325 // MODE is NONE, and either the magnification filter is not NEAREST or the mini-
326 // fication filter is neither NEAREST nor NEAREST_MIPMAP_NEAREST.
327 if (mTarget != GL_TEXTURE_2D_MULTISAMPLE && baseImageDesc.format.info->depthBits > 0 &&
328 data.getClientMajorVersion() >= 3)
329 {
330 // Note: we restrict this validation to sized types. For the OES_depth_textures
331 // extension, due to some underspecification problems, we must allow linear filtering
332 // for legacy compatibility with WebGL 1.
333 // See http://crbug.com/649200
334 if (samplerState.compareMode == GL_NONE && baseImageDesc.format.info->sized)
335 {
336 if ((samplerState.minFilter != GL_NEAREST &&
337 samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST) ||
338 samplerState.magFilter != GL_NEAREST)
339 {
340 return false;
341 }
342 }
343 }
344
345 return true;
346 }
347
computeMipmapCompleteness() const348 bool TextureState::computeMipmapCompleteness() const
349 {
350 const GLuint maxLevel = getMipmapMaxLevel();
351
352 for (GLuint level = getEffectiveBaseLevel(); level <= maxLevel; level++)
353 {
354 if (mTarget == GL_TEXTURE_CUBE_MAP)
355 {
356 for (GLenum face = FirstCubeMapTextureTarget; face <= LastCubeMapTextureTarget; face++)
357 {
358 if (!computeLevelCompleteness(face, level))
359 {
360 return false;
361 }
362 }
363 }
364 else
365 {
366 if (!computeLevelCompleteness(mTarget, level))
367 {
368 return false;
369 }
370 }
371 }
372
373 return true;
374 }
375
computeLevelCompleteness(GLenum target,size_t level) const376 bool TextureState::computeLevelCompleteness(GLenum target, size_t level) const
377 {
378 ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
379
380 if (mImmutableFormat)
381 {
382 return true;
383 }
384
385 const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), getEffectiveBaseLevel());
386 if (baseImageDesc.size.width == 0 || baseImageDesc.size.height == 0 ||
387 baseImageDesc.size.depth == 0)
388 {
389 return false;
390 }
391
392 const ImageDesc &levelImageDesc = getImageDesc(target, level);
393 if (levelImageDesc.size.width == 0 || levelImageDesc.size.height == 0 ||
394 levelImageDesc.size.depth == 0)
395 {
396 return false;
397 }
398
399 if (!Format::SameSized(levelImageDesc.format, baseImageDesc.format))
400 {
401 return false;
402 }
403
404 ASSERT(level >= getEffectiveBaseLevel());
405 const size_t relativeLevel = level - getEffectiveBaseLevel();
406 if (levelImageDesc.size.width != std::max(1, baseImageDesc.size.width >> relativeLevel))
407 {
408 return false;
409 }
410
411 if (levelImageDesc.size.height != std::max(1, baseImageDesc.size.height >> relativeLevel))
412 {
413 return false;
414 }
415
416 if (mTarget == GL_TEXTURE_3D)
417 {
418 if (levelImageDesc.size.depth != std::max(1, baseImageDesc.size.depth >> relativeLevel))
419 {
420 return false;
421 }
422 }
423 else if (mTarget == GL_TEXTURE_2D_ARRAY)
424 {
425 if (levelImageDesc.size.depth != baseImageDesc.size.depth)
426 {
427 return false;
428 }
429 }
430
431 return true;
432 }
433
getBaseImageTarget() const434 GLenum TextureState::getBaseImageTarget() const
435 {
436 return mTarget == GL_TEXTURE_CUBE_MAP ? FirstCubeMapTextureTarget : mTarget;
437 }
438
ImageDesc()439 ImageDesc::ImageDesc()
440 : ImageDesc(Extents(0, 0, 0), Format::Invalid(), 0, GL_TRUE, InitState::Initialized)
441 {
442 }
443
ImageDesc(const Extents & size,const Format & format,const InitState initState)444 ImageDesc::ImageDesc(const Extents &size, const Format &format, const InitState initState)
445 : size(size), format(format), samples(0), fixedSampleLocations(GL_TRUE), initState(initState)
446 {
447 }
448
ImageDesc(const Extents & size,const Format & format,const GLsizei samples,const bool fixedSampleLocations,const InitState initState)449 ImageDesc::ImageDesc(const Extents &size,
450 const Format &format,
451 const GLsizei samples,
452 const bool fixedSampleLocations,
453 const InitState initState)
454 : size(size),
455 format(format),
456 samples(samples),
457 fixedSampleLocations(fixedSampleLocations),
458 initState(initState)
459 {
460 }
461
getImageDesc(GLenum target,size_t level) const462 const ImageDesc &TextureState::getImageDesc(GLenum target, size_t level) const
463 {
464 size_t descIndex = GetImageDescIndex(target, level);
465 ASSERT(descIndex < mImageDescs.size());
466 return mImageDescs[descIndex];
467 }
468
setImageDesc(GLenum target,size_t level,const ImageDesc & desc)469 void TextureState::setImageDesc(GLenum target, size_t level, const ImageDesc &desc)
470 {
471 size_t descIndex = GetImageDescIndex(target, level);
472 ASSERT(descIndex < mImageDescs.size());
473 mImageDescs[descIndex] = desc;
474 if (desc.initState == InitState::MayNeedInit)
475 {
476 mInitState = InitState::MayNeedInit;
477 }
478 }
479
getImageDesc(const ImageIndex & imageIndex) const480 const ImageDesc &TextureState::getImageDesc(const ImageIndex &imageIndex) const
481 {
482 return getImageDesc(imageIndex.type, imageIndex.mipIndex);
483 }
484
setImageDescChain(GLuint baseLevel,GLuint maxLevel,Extents baseSize,const Format & format,InitState initState)485 void TextureState::setImageDescChain(GLuint baseLevel,
486 GLuint maxLevel,
487 Extents baseSize,
488 const Format &format,
489 InitState initState)
490 {
491 for (GLuint level = baseLevel; level <= maxLevel; level++)
492 {
493 int relativeLevel = (level - baseLevel);
494 Extents levelSize(std::max<int>(baseSize.width >> relativeLevel, 1),
495 std::max<int>(baseSize.height >> relativeLevel, 1),
496 (mTarget == GL_TEXTURE_2D_ARRAY)
497 ? baseSize.depth
498 : std::max<int>(baseSize.depth >> relativeLevel, 1));
499 ImageDesc levelInfo(levelSize, format, initState);
500
501 if (mTarget == GL_TEXTURE_CUBE_MAP)
502 {
503 for (GLenum face = FirstCubeMapTextureTarget; face <= LastCubeMapTextureTarget; face++)
504 {
505 setImageDesc(face, level, levelInfo);
506 }
507 }
508 else
509 {
510 setImageDesc(mTarget, level, levelInfo);
511 }
512 }
513 }
514
setImageDescChainMultisample(Extents baseSize,const Format & format,GLsizei samples,bool fixedSampleLocations,InitState initState)515 void TextureState::setImageDescChainMultisample(Extents baseSize,
516 const Format &format,
517 GLsizei samples,
518 bool fixedSampleLocations,
519 InitState initState)
520 {
521 ASSERT(mTarget == GL_TEXTURE_2D_MULTISAMPLE);
522 ImageDesc levelInfo(baseSize, format, samples, fixedSampleLocations, initState);
523 setImageDesc(mTarget, 0, levelInfo);
524 }
525
clearImageDesc(GLenum target,size_t level)526 void TextureState::clearImageDesc(GLenum target, size_t level)
527 {
528 setImageDesc(target, level, ImageDesc());
529 }
530
clearImageDescs()531 void TextureState::clearImageDescs()
532 {
533 for (size_t descIndex = 0; descIndex < mImageDescs.size(); descIndex++)
534 {
535 mImageDescs[descIndex] = ImageDesc();
536 }
537 }
538
Texture(rx::GLImplFactory * factory,GLuint id,GLenum target)539 Texture::Texture(rx::GLImplFactory *factory, GLuint id, GLenum target)
540 : egl::ImageSibling(id),
541 mState(target),
542 mTexture(factory->createTexture(mState)),
543 mLabel(),
544 mBoundSurface(nullptr),
545 mBoundStream(nullptr)
546 {
547 }
548
onDestroy(const Context * context)549 Error Texture::onDestroy(const Context *context)
550 {
551 if (mBoundSurface)
552 {
553 ANGLE_TRY(mBoundSurface->releaseTexImage(context, EGL_BACK_BUFFER));
554 mBoundSurface = nullptr;
555 }
556 if (mBoundStream)
557 {
558 mBoundStream->releaseTextures();
559 mBoundStream = nullptr;
560 }
561
562 ANGLE_TRY(orphanImages(context));
563
564 if (mTexture)
565 {
566 ANGLE_TRY(mTexture->onDestroy(context));
567 }
568 return NoError();
569 }
570
~Texture()571 Texture::~Texture()
572 {
573 SafeDelete(mTexture);
574 }
575
setLabel(const std::string & label)576 void Texture::setLabel(const std::string &label)
577 {
578 mLabel = label;
579 mDirtyBits.set(DIRTY_BIT_LABEL);
580 }
581
getLabel() const582 const std::string &Texture::getLabel() const
583 {
584 return mLabel;
585 }
586
getTarget() const587 GLenum Texture::getTarget() const
588 {
589 return mState.mTarget;
590 }
591
setSwizzleRed(GLenum swizzleRed)592 void Texture::setSwizzleRed(GLenum swizzleRed)
593 {
594 mState.mSwizzleState.swizzleRed = swizzleRed;
595 mDirtyBits.set(DIRTY_BIT_SWIZZLE_RED);
596 }
597
getSwizzleRed() const598 GLenum Texture::getSwizzleRed() const
599 {
600 return mState.mSwizzleState.swizzleRed;
601 }
602
setSwizzleGreen(GLenum swizzleGreen)603 void Texture::setSwizzleGreen(GLenum swizzleGreen)
604 {
605 mState.mSwizzleState.swizzleGreen = swizzleGreen;
606 mDirtyBits.set(DIRTY_BIT_SWIZZLE_GREEN);
607 }
608
getSwizzleGreen() const609 GLenum Texture::getSwizzleGreen() const
610 {
611 return mState.mSwizzleState.swizzleGreen;
612 }
613
setSwizzleBlue(GLenum swizzleBlue)614 void Texture::setSwizzleBlue(GLenum swizzleBlue)
615 {
616 mState.mSwizzleState.swizzleBlue = swizzleBlue;
617 mDirtyBits.set(DIRTY_BIT_SWIZZLE_BLUE);
618 }
619
getSwizzleBlue() const620 GLenum Texture::getSwizzleBlue() const
621 {
622 return mState.mSwizzleState.swizzleBlue;
623 }
624
setSwizzleAlpha(GLenum swizzleAlpha)625 void Texture::setSwizzleAlpha(GLenum swizzleAlpha)
626 {
627 mState.mSwizzleState.swizzleAlpha = swizzleAlpha;
628 mDirtyBits.set(DIRTY_BIT_SWIZZLE_ALPHA);
629 }
630
getSwizzleAlpha() const631 GLenum Texture::getSwizzleAlpha() const
632 {
633 return mState.mSwizzleState.swizzleAlpha;
634 }
635
setMinFilter(GLenum minFilter)636 void Texture::setMinFilter(GLenum minFilter)
637 {
638 mState.mSamplerState.minFilter = minFilter;
639 mDirtyBits.set(DIRTY_BIT_MIN_FILTER);
640 }
641
getMinFilter() const642 GLenum Texture::getMinFilter() const
643 {
644 return mState.mSamplerState.minFilter;
645 }
646
setMagFilter(GLenum magFilter)647 void Texture::setMagFilter(GLenum magFilter)
648 {
649 mState.mSamplerState.magFilter = magFilter;
650 mDirtyBits.set(DIRTY_BIT_MAG_FILTER);
651 }
652
getMagFilter() const653 GLenum Texture::getMagFilter() const
654 {
655 return mState.mSamplerState.magFilter;
656 }
657
setWrapS(GLenum wrapS)658 void Texture::setWrapS(GLenum wrapS)
659 {
660 mState.mSamplerState.wrapS = wrapS;
661 mDirtyBits.set(DIRTY_BIT_WRAP_S);
662 }
663
getWrapS() const664 GLenum Texture::getWrapS() const
665 {
666 return mState.mSamplerState.wrapS;
667 }
668
setWrapT(GLenum wrapT)669 void Texture::setWrapT(GLenum wrapT)
670 {
671 mState.mSamplerState.wrapT = wrapT;
672 mDirtyBits.set(DIRTY_BIT_WRAP_T);
673 }
674
getWrapT() const675 GLenum Texture::getWrapT() const
676 {
677 return mState.mSamplerState.wrapT;
678 }
679
setWrapR(GLenum wrapR)680 void Texture::setWrapR(GLenum wrapR)
681 {
682 mState.mSamplerState.wrapR = wrapR;
683 mDirtyBits.set(DIRTY_BIT_WRAP_R);
684 }
685
getWrapR() const686 GLenum Texture::getWrapR() const
687 {
688 return mState.mSamplerState.wrapR;
689 }
690
setMaxAnisotropy(float maxAnisotropy)691 void Texture::setMaxAnisotropy(float maxAnisotropy)
692 {
693 mState.mSamplerState.maxAnisotropy = maxAnisotropy;
694 mDirtyBits.set(DIRTY_BIT_MAX_ANISOTROPY);
695 }
696
getMaxAnisotropy() const697 float Texture::getMaxAnisotropy() const
698 {
699 return mState.mSamplerState.maxAnisotropy;
700 }
701
setMinLod(GLfloat minLod)702 void Texture::setMinLod(GLfloat minLod)
703 {
704 mState.mSamplerState.minLod = minLod;
705 mDirtyBits.set(DIRTY_BIT_MIN_LOD);
706 }
707
getMinLod() const708 GLfloat Texture::getMinLod() const
709 {
710 return mState.mSamplerState.minLod;
711 }
712
setMaxLod(GLfloat maxLod)713 void Texture::setMaxLod(GLfloat maxLod)
714 {
715 mState.mSamplerState.maxLod = maxLod;
716 mDirtyBits.set(DIRTY_BIT_MAX_LOD);
717 }
718
getMaxLod() const719 GLfloat Texture::getMaxLod() const
720 {
721 return mState.mSamplerState.maxLod;
722 }
723
setCompareMode(GLenum compareMode)724 void Texture::setCompareMode(GLenum compareMode)
725 {
726 mState.mSamplerState.compareMode = compareMode;
727 mDirtyBits.set(DIRTY_BIT_COMPARE_MODE);
728 }
729
getCompareMode() const730 GLenum Texture::getCompareMode() const
731 {
732 return mState.mSamplerState.compareMode;
733 }
734
setCompareFunc(GLenum compareFunc)735 void Texture::setCompareFunc(GLenum compareFunc)
736 {
737 mState.mSamplerState.compareFunc = compareFunc;
738 mDirtyBits.set(DIRTY_BIT_COMPARE_FUNC);
739 }
740
getCompareFunc() const741 GLenum Texture::getCompareFunc() const
742 {
743 return mState.mSamplerState.compareFunc;
744 }
745
setSRGBDecode(GLenum sRGBDecode)746 void Texture::setSRGBDecode(GLenum sRGBDecode)
747 {
748 mState.mSamplerState.sRGBDecode = sRGBDecode;
749 mDirtyBits.set(DIRTY_BIT_SRGB_DECODE);
750 }
751
getSRGBDecode() const752 GLenum Texture::getSRGBDecode() const
753 {
754 return mState.mSamplerState.sRGBDecode;
755 }
756
getSamplerState() const757 const SamplerState &Texture::getSamplerState() const
758 {
759 return mState.mSamplerState;
760 }
761
setBaseLevel(const Context * context,GLuint baseLevel)762 Error Texture::setBaseLevel(const Context *context, GLuint baseLevel)
763 {
764 if (mState.setBaseLevel(baseLevel))
765 {
766 ANGLE_TRY(mTexture->setBaseLevel(context, mState.getEffectiveBaseLevel()));
767 mDirtyBits.set(DIRTY_BIT_BASE_LEVEL);
768 invalidateCompletenessCache();
769 }
770
771 return NoError();
772 }
773
getBaseLevel() const774 GLuint Texture::getBaseLevel() const
775 {
776 return mState.mBaseLevel;
777 }
778
setMaxLevel(GLuint maxLevel)779 void Texture::setMaxLevel(GLuint maxLevel)
780 {
781 if (mState.setMaxLevel(maxLevel))
782 {
783 mDirtyBits.set(DIRTY_BIT_MAX_LEVEL);
784 invalidateCompletenessCache();
785 }
786 }
787
getMaxLevel() const788 GLuint Texture::getMaxLevel() const
789 {
790 return mState.mMaxLevel;
791 }
792
setDepthStencilTextureMode(GLenum mode)793 void Texture::setDepthStencilTextureMode(GLenum mode)
794 {
795 if (mode != mState.mDepthStencilTextureMode)
796 {
797 // Changing the mode from the default state (GL_DEPTH_COMPONENT) is not implemented yet
798 UNIMPLEMENTED();
799 }
800
801 // TODO(geofflang): add dirty bits
802 mState.mDepthStencilTextureMode = mode;
803 }
804
getDepthStencilTextureMode() const805 GLenum Texture::getDepthStencilTextureMode() const
806 {
807 return mState.mDepthStencilTextureMode;
808 }
809
getImmutableFormat() const810 bool Texture::getImmutableFormat() const
811 {
812 return mState.mImmutableFormat;
813 }
814
getImmutableLevels() const815 GLuint Texture::getImmutableLevels() const
816 {
817 return mState.mImmutableLevels;
818 }
819
setUsage(GLenum usage)820 void Texture::setUsage(GLenum usage)
821 {
822 mState.mUsage = usage;
823 mDirtyBits.set(DIRTY_BIT_USAGE);
824 }
825
getUsage() const826 GLenum Texture::getUsage() const
827 {
828 return mState.mUsage;
829 }
830
getTextureState() const831 const TextureState &Texture::getTextureState() const
832 {
833 return mState;
834 }
835
getWidth(GLenum target,size_t level) const836 size_t Texture::getWidth(GLenum target, size_t level) const
837 {
838 ASSERT(target == mState.mTarget ||
839 (mState.mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
840 return mState.getImageDesc(target, level).size.width;
841 }
842
getHeight(GLenum target,size_t level) const843 size_t Texture::getHeight(GLenum target, size_t level) const
844 {
845 ASSERT(target == mState.mTarget ||
846 (mState.mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
847 return mState.getImageDesc(target, level).size.height;
848 }
849
getDepth(GLenum target,size_t level) const850 size_t Texture::getDepth(GLenum target, size_t level) const
851 {
852 ASSERT(target == mState.mTarget ||
853 (mState.mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
854 return mState.getImageDesc(target, level).size.depth;
855 }
856
getFormat(GLenum target,size_t level) const857 const Format &Texture::getFormat(GLenum target, size_t level) const
858 {
859 ASSERT(target == mState.mTarget ||
860 (mState.mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
861 return mState.getImageDesc(target, level).format;
862 }
863
getSamples(GLenum target,size_t level) const864 GLsizei Texture::getSamples(GLenum target, size_t level) const
865 {
866 ASSERT(target == mState.mTarget ||
867 (mState.mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
868 return mState.getImageDesc(target, level).samples;
869 }
870
getFixedSampleLocations(GLenum target,size_t level) const871 bool Texture::getFixedSampleLocations(GLenum target, size_t level) const
872 {
873 ASSERT(target == mState.mTarget ||
874 (mState.mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
875 return mState.getImageDesc(target, level).fixedSampleLocations;
876 }
877
getMipmapMaxLevel() const878 GLuint Texture::getMipmapMaxLevel() const
879 {
880 return mState.getMipmapMaxLevel();
881 }
882
isMipmapComplete() const883 bool Texture::isMipmapComplete() const
884 {
885 return mState.computeMipmapCompleteness();
886 }
887
getBoundSurface() const888 egl::Surface *Texture::getBoundSurface() const
889 {
890 return mBoundSurface;
891 }
892
getBoundStream() const893 egl::Stream *Texture::getBoundStream() const
894 {
895 return mBoundStream;
896 }
897
signalDirty(InitState initState) const898 void Texture::signalDirty(InitState initState) const
899 {
900 mDirtyChannel.signal(initState);
901 invalidateCompletenessCache();
902 }
903
setImage(const Context * context,const PixelUnpackState & unpackState,GLenum target,size_t level,GLenum internalFormat,const Extents & size,GLenum format,GLenum type,const uint8_t * pixels)904 Error Texture::setImage(const Context *context,
905 const PixelUnpackState &unpackState,
906 GLenum target,
907 size_t level,
908 GLenum internalFormat,
909 const Extents &size,
910 GLenum format,
911 GLenum type,
912 const uint8_t *pixels)
913 {
914 ASSERT(target == mState.mTarget ||
915 (mState.mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
916
917 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
918 ANGLE_TRY(releaseTexImageInternal(context));
919 ANGLE_TRY(orphanImages(context));
920
921 ANGLE_TRY(mTexture->setImage(context, target, level, internalFormat, size, format, type,
922 unpackState, pixels));
923
924 InitState initState = DetermineInitState(context, pixels);
925 mState.setImageDesc(target, level, ImageDesc(size, Format(internalFormat, type), initState));
926 signalDirty(initState);
927
928 return NoError();
929 }
930
setSubImage(const Context * context,const PixelUnpackState & unpackState,GLenum target,size_t level,const Box & area,GLenum format,GLenum type,const uint8_t * pixels)931 Error Texture::setSubImage(const Context *context,
932 const PixelUnpackState &unpackState,
933 GLenum target,
934 size_t level,
935 const Box &area,
936 GLenum format,
937 GLenum type,
938 const uint8_t *pixels)
939 {
940 ASSERT(target == mState.mTarget ||
941 (mState.mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
942
943 ANGLE_TRY(ensureSubImageInitialized(context, target, level, area));
944
945 return mTexture->setSubImage(context, target, level, area, format, type, unpackState, pixels);
946 }
947
setCompressedImage(const Context * context,const PixelUnpackState & unpackState,GLenum target,size_t level,GLenum internalFormat,const Extents & size,size_t imageSize,const uint8_t * pixels)948 Error Texture::setCompressedImage(const Context *context,
949 const PixelUnpackState &unpackState,
950 GLenum target,
951 size_t level,
952 GLenum internalFormat,
953 const Extents &size,
954 size_t imageSize,
955 const uint8_t *pixels)
956 {
957 ASSERT(target == mState.mTarget ||
958 (mState.mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
959
960 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
961 ANGLE_TRY(releaseTexImageInternal(context));
962 ANGLE_TRY(orphanImages(context));
963
964 ANGLE_TRY(mTexture->setCompressedImage(context, target, level, internalFormat, size,
965 unpackState, imageSize, pixels));
966
967 InitState initState = DetermineInitState(context, pixels);
968 mState.setImageDesc(target, level, ImageDesc(size, Format(internalFormat), initState));
969 signalDirty(initState);
970
971 return NoError();
972 }
973
setCompressedSubImage(const Context * context,const PixelUnpackState & unpackState,GLenum target,size_t level,const Box & area,GLenum format,size_t imageSize,const uint8_t * pixels)974 Error Texture::setCompressedSubImage(const Context *context,
975 const PixelUnpackState &unpackState,
976 GLenum target,
977 size_t level,
978 const Box &area,
979 GLenum format,
980 size_t imageSize,
981 const uint8_t *pixels)
982 {
983 ASSERT(target == mState.mTarget ||
984 (mState.mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
985
986 ANGLE_TRY(ensureSubImageInitialized(context, target, level, area));
987
988 return mTexture->setCompressedSubImage(context, target, level, area, format, unpackState,
989 imageSize, pixels);
990 }
991
copyImage(const Context * context,GLenum target,size_t level,const Rectangle & sourceArea,GLenum internalFormat,Framebuffer * source)992 Error Texture::copyImage(const Context *context,
993 GLenum target,
994 size_t level,
995 const Rectangle &sourceArea,
996 GLenum internalFormat,
997 Framebuffer *source)
998 {
999 ASSERT(target == mState.mTarget ||
1000 (mState.mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
1001
1002 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1003 ANGLE_TRY(releaseTexImageInternal(context));
1004 ANGLE_TRY(orphanImages(context));
1005
1006 // Ensure source FBO is initialized.
1007 ANGLE_TRY(source->ensureReadAttachmentInitialized(context, GL_COLOR_BUFFER_BIT));
1008
1009 // Use the source FBO size as the init image area.
1010 Box destBox(0, 0, 0, sourceArea.width, sourceArea.height, 1);
1011 ANGLE_TRY(ensureSubImageInitialized(context, target, level, destBox));
1012
1013 ANGLE_TRY(mTexture->copyImage(context, target, level, sourceArea, internalFormat, source));
1014
1015 const InternalFormat &internalFormatInfo =
1016 GetInternalFormatInfo(internalFormat, GL_UNSIGNED_BYTE);
1017
1018 mState.setImageDesc(target, level,
1019 ImageDesc(Extents(sourceArea.width, sourceArea.height, 1),
1020 Format(internalFormatInfo), InitState::Initialized));
1021
1022 // We need to initialize this texture only if the source attachment is not initialized.
1023 signalDirty(InitState::Initialized);
1024
1025 return NoError();
1026 }
1027
copySubImage(const Context * context,GLenum target,size_t level,const Offset & destOffset,const Rectangle & sourceArea,Framebuffer * source)1028 Error Texture::copySubImage(const Context *context,
1029 GLenum target,
1030 size_t level,
1031 const Offset &destOffset,
1032 const Rectangle &sourceArea,
1033 Framebuffer *source)
1034 {
1035 ASSERT(target == mState.mTarget ||
1036 (mState.mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
1037
1038 // Ensure source FBO is initialized.
1039 ANGLE_TRY(source->ensureReadAttachmentInitialized(context, GL_COLOR_BUFFER_BIT));
1040
1041 Box destBox(destOffset.x, destOffset.y, destOffset.y, sourceArea.width, sourceArea.height, 1);
1042 ANGLE_TRY(ensureSubImageInitialized(context, target, level, destBox));
1043
1044 return mTexture->copySubImage(context, target, level, destOffset, sourceArea, source);
1045 }
1046
copyTexture(const Context * context,GLenum target,size_t level,GLenum internalFormat,GLenum type,size_t sourceLevel,bool unpackFlipY,bool unpackPremultiplyAlpha,bool unpackUnmultiplyAlpha,Texture * source)1047 Error Texture::copyTexture(const Context *context,
1048 GLenum target,
1049 size_t level,
1050 GLenum internalFormat,
1051 GLenum type,
1052 size_t sourceLevel,
1053 bool unpackFlipY,
1054 bool unpackPremultiplyAlpha,
1055 bool unpackUnmultiplyAlpha,
1056 Texture *source)
1057 {
1058 ASSERT(target == mState.mTarget ||
1059 (mState.mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
1060
1061 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1062 ANGLE_TRY(releaseTexImageInternal(context));
1063 ANGLE_TRY(orphanImages(context));
1064
1065 // Initialize source texture.
1066 // Note: we don't have a way to notify which portions of the image changed currently.
1067 ANGLE_TRY(source->ensureInitialized(context));
1068
1069 ANGLE_TRY(mTexture->copyTexture(context, target, level, internalFormat, type, sourceLevel,
1070 unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha,
1071 source));
1072
1073 const auto &sourceDesc = source->mState.getImageDesc(source->getTarget(), 0);
1074 const InternalFormat &internalFormatInfo = GetInternalFormatInfo(internalFormat, type);
1075 mState.setImageDesc(
1076 target, level,
1077 ImageDesc(sourceDesc.size, Format(internalFormatInfo), InitState::Initialized));
1078
1079 signalDirty(InitState::Initialized);
1080
1081 return NoError();
1082 }
1083
copySubTexture(const Context * context,GLenum target,size_t level,const Offset & destOffset,size_t sourceLevel,const Rectangle & sourceArea,bool unpackFlipY,bool unpackPremultiplyAlpha,bool unpackUnmultiplyAlpha,Texture * source)1084 Error Texture::copySubTexture(const Context *context,
1085 GLenum target,
1086 size_t level,
1087 const Offset &destOffset,
1088 size_t sourceLevel,
1089 const Rectangle &sourceArea,
1090 bool unpackFlipY,
1091 bool unpackPremultiplyAlpha,
1092 bool unpackUnmultiplyAlpha,
1093 Texture *source)
1094 {
1095 ASSERT(target == mState.mTarget ||
1096 (mState.mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
1097
1098 // Ensure source is initialized.
1099 ANGLE_TRY(source->ensureInitialized(context));
1100
1101 Box destBox(destOffset.x, destOffset.y, destOffset.y, sourceArea.width, sourceArea.height, 1);
1102 ANGLE_TRY(ensureSubImageInitialized(context, target, level, destBox));
1103
1104 return mTexture->copySubTexture(context, target, level, destOffset, sourceLevel, sourceArea,
1105 unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha,
1106 source);
1107 }
1108
copyCompressedTexture(const Context * context,const Texture * source)1109 Error Texture::copyCompressedTexture(const Context *context, const Texture *source)
1110 {
1111 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1112 ANGLE_TRY(releaseTexImageInternal(context));
1113 ANGLE_TRY(orphanImages(context));
1114
1115 ANGLE_TRY(mTexture->copyCompressedTexture(context, source));
1116
1117 ASSERT(source->getTarget() != GL_TEXTURE_CUBE_MAP && getTarget() != GL_TEXTURE_CUBE_MAP);
1118 const auto &sourceDesc = source->mState.getImageDesc(source->getTarget(), 0);
1119 mState.setImageDesc(getTarget(), 0, sourceDesc);
1120
1121 return NoError();
1122 }
1123
setStorage(const Context * context,GLenum target,GLsizei levels,GLenum internalFormat,const Extents & size)1124 Error Texture::setStorage(const Context *context,
1125 GLenum target,
1126 GLsizei levels,
1127 GLenum internalFormat,
1128 const Extents &size)
1129 {
1130 ASSERT(target == mState.mTarget);
1131
1132 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1133 ANGLE_TRY(releaseTexImageInternal(context));
1134 ANGLE_TRY(orphanImages(context));
1135
1136 ANGLE_TRY(mTexture->setStorage(context, target, levels, internalFormat, size));
1137
1138 mState.mImmutableFormat = true;
1139 mState.mImmutableLevels = static_cast<GLuint>(levels);
1140 mState.clearImageDescs();
1141 mState.setImageDescChain(0, static_cast<GLuint>(levels - 1), size, Format(internalFormat),
1142 InitState::MayNeedInit);
1143
1144 // Changing the texture to immutable can trigger a change in the base and max levels:
1145 // GLES 3.0.4 section 3.8.10 pg 158:
1146 // "For immutable-format textures, levelbase is clamped to the range[0;levels],levelmax is then
1147 // clamped to the range[levelbase;levels].
1148 mDirtyBits.set(DIRTY_BIT_BASE_LEVEL);
1149 mDirtyBits.set(DIRTY_BIT_MAX_LEVEL);
1150
1151 signalDirty(InitState::MayNeedInit);
1152
1153 return NoError();
1154 }
1155
setStorageMultisample(const Context * context,GLenum target,GLsizei samples,GLint internalFormat,const Extents & size,bool fixedSampleLocations)1156 Error Texture::setStorageMultisample(const Context *context,
1157 GLenum target,
1158 GLsizei samples,
1159 GLint internalFormat,
1160 const Extents &size,
1161 bool fixedSampleLocations)
1162 {
1163 ASSERT(target == mState.mTarget);
1164
1165 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1166 ANGLE_TRY(releaseTexImageInternal(context));
1167 ANGLE_TRY(orphanImages(context));
1168
1169 ANGLE_TRY(mTexture->setStorageMultisample(context, target, samples, internalFormat, size,
1170 fixedSampleLocations));
1171
1172 mState.mImmutableFormat = true;
1173 mState.mImmutableLevels = static_cast<GLuint>(1);
1174 mState.clearImageDescs();
1175 mState.setImageDescChainMultisample(size, Format(internalFormat), samples, fixedSampleLocations,
1176 InitState::MayNeedInit);
1177
1178 signalDirty(InitState::MayNeedInit);
1179
1180 return NoError();
1181 }
1182
generateMipmap(const Context * context)1183 Error Texture::generateMipmap(const Context *context)
1184 {
1185 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1186 ANGLE_TRY(releaseTexImageInternal(context));
1187
1188 // EGL_KHR_gl_image states that images are only orphaned when generating mipmaps if the texture
1189 // is not mip complete.
1190 if (!isMipmapComplete())
1191 {
1192 ANGLE_TRY(orphanImages(context));
1193 }
1194
1195 const GLuint baseLevel = mState.getEffectiveBaseLevel();
1196 const GLuint maxLevel = mState.getMipmapMaxLevel();
1197
1198 if (maxLevel > baseLevel)
1199 {
1200 syncState();
1201 const ImageDesc &baseImageInfo =
1202 mState.getImageDesc(mState.getBaseImageTarget(), baseLevel);
1203
1204 // Clear the base image immediately if necessary.
1205 if (context->isRobustResourceInitEnabled() &&
1206 baseImageInfo.initState == InitState::MayNeedInit)
1207 {
1208 ANGLE_TRY(initializeContents(
1209 context, GetImageIndexFromDescIndex(mState.getBaseImageTarget(), baseLevel)));
1210 }
1211
1212 ANGLE_TRY(mTexture->generateMipmap(context));
1213
1214 mState.setImageDescChain(baseLevel, maxLevel, baseImageInfo.size, baseImageInfo.format,
1215 InitState::Initialized);
1216 }
1217
1218 signalDirty(InitState::Initialized);
1219
1220 return NoError();
1221 }
1222
bindTexImageFromSurface(const Context * context,egl::Surface * surface)1223 Error Texture::bindTexImageFromSurface(const Context *context, egl::Surface *surface)
1224 {
1225 ASSERT(surface);
1226
1227 if (mBoundSurface)
1228 {
1229 ANGLE_TRY(releaseTexImageFromSurface(context));
1230 }
1231
1232 ANGLE_TRY(mTexture->bindTexImage(context, surface));
1233 mBoundSurface = surface;
1234
1235 // Set the image info to the size and format of the surface
1236 ASSERT(mState.mTarget == GL_TEXTURE_2D || mState.mTarget == GL_TEXTURE_RECTANGLE_ANGLE);
1237 Extents size(surface->getWidth(), surface->getHeight(), 1);
1238 ImageDesc desc(size, Format(surface->getConfig()->renderTargetFormat), InitState::Initialized);
1239 mState.setImageDesc(mState.mTarget, 0, desc);
1240 signalDirty(InitState::Initialized);
1241 return NoError();
1242 }
1243
releaseTexImageFromSurface(const Context * context)1244 Error Texture::releaseTexImageFromSurface(const Context *context)
1245 {
1246 ASSERT(mBoundSurface);
1247 mBoundSurface = nullptr;
1248 ANGLE_TRY(mTexture->releaseTexImage(context));
1249
1250 // Erase the image info for level 0
1251 ASSERT(mState.mTarget == GL_TEXTURE_2D || mState.mTarget == GL_TEXTURE_RECTANGLE_ANGLE);
1252 mState.clearImageDesc(mState.mTarget, 0);
1253 signalDirty(InitState::Initialized);
1254 return NoError();
1255 }
1256
bindStream(egl::Stream * stream)1257 void Texture::bindStream(egl::Stream *stream)
1258 {
1259 ASSERT(stream);
1260
1261 // It should not be possible to bind a texture already bound to another stream
1262 ASSERT(mBoundStream == nullptr);
1263
1264 mBoundStream = stream;
1265
1266 ASSERT(mState.mTarget == GL_TEXTURE_EXTERNAL_OES);
1267 }
1268
releaseStream()1269 void Texture::releaseStream()
1270 {
1271 ASSERT(mBoundStream);
1272 mBoundStream = nullptr;
1273 }
1274
acquireImageFromStream(const Context * context,const egl::Stream::GLTextureDescription & desc)1275 Error Texture::acquireImageFromStream(const Context *context,
1276 const egl::Stream::GLTextureDescription &desc)
1277 {
1278 ASSERT(mBoundStream != nullptr);
1279 ANGLE_TRY(mTexture->setImageExternal(context, mState.mTarget, mBoundStream, desc));
1280
1281 Extents size(desc.width, desc.height, 1);
1282 mState.setImageDesc(mState.mTarget, 0,
1283 ImageDesc(size, Format(desc.internalFormat), InitState::Initialized));
1284 signalDirty(InitState::Initialized);
1285 return NoError();
1286 }
1287
releaseImageFromStream(const Context * context)1288 Error Texture::releaseImageFromStream(const Context *context)
1289 {
1290 ASSERT(mBoundStream != nullptr);
1291 ANGLE_TRY(mTexture->setImageExternal(context, mState.mTarget, nullptr,
1292 egl::Stream::GLTextureDescription()));
1293
1294 // Set to incomplete
1295 mState.clearImageDesc(mState.mTarget, 0);
1296 signalDirty(InitState::Initialized);
1297 return NoError();
1298 }
1299
releaseTexImageInternal(const Context * context)1300 Error Texture::releaseTexImageInternal(const Context *context)
1301 {
1302 if (mBoundSurface)
1303 {
1304 // Notify the surface
1305 mBoundSurface->releaseTexImageFromTexture(context);
1306
1307 // Then, call the same method as from the surface
1308 ANGLE_TRY(releaseTexImageFromSurface(context));
1309 }
1310 return NoError();
1311 }
1312
setEGLImageTarget(const Context * context,GLenum target,egl::Image * imageTarget)1313 Error Texture::setEGLImageTarget(const Context *context, GLenum target, egl::Image *imageTarget)
1314 {
1315 ASSERT(target == mState.mTarget);
1316 ASSERT(target == GL_TEXTURE_2D || target == GL_TEXTURE_EXTERNAL_OES);
1317
1318 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1319 ANGLE_TRY(releaseTexImageInternal(context));
1320 ANGLE_TRY(orphanImages(context));
1321
1322 ANGLE_TRY(mTexture->setEGLImageTarget(context, target, imageTarget));
1323
1324 setTargetImage(context, imageTarget);
1325
1326 Extents size(static_cast<int>(imageTarget->getWidth()),
1327 static_cast<int>(imageTarget->getHeight()), 1);
1328
1329 auto initState = imageTarget->sourceInitState();
1330
1331 mState.clearImageDescs();
1332 mState.setImageDesc(target, 0, ImageDesc(size, imageTarget->getFormat(), initState));
1333 signalDirty(initState);
1334
1335 return NoError();
1336 }
1337
getAttachmentSize(const ImageIndex & imageIndex) const1338 Extents Texture::getAttachmentSize(const ImageIndex &imageIndex) const
1339 {
1340 return mState.getImageDesc(imageIndex).size;
1341 }
1342
getAttachmentFormat(GLenum,const ImageIndex & imageIndex) const1343 const Format &Texture::getAttachmentFormat(GLenum /*binding*/, const ImageIndex &imageIndex) const
1344 {
1345 return mState.getImageDesc(imageIndex).format;
1346 }
1347
getAttachmentSamples(const ImageIndex & imageIndex) const1348 GLsizei Texture::getAttachmentSamples(const ImageIndex &imageIndex) const
1349 {
1350 return getSamples(imageIndex.type, 0);
1351 }
1352
onAttach(const Context * context)1353 void Texture::onAttach(const Context *context)
1354 {
1355 addRef();
1356 }
1357
onDetach(const Context * context)1358 void Texture::onDetach(const Context *context)
1359 {
1360 release(context);
1361 }
1362
getId() const1363 GLuint Texture::getId() const
1364 {
1365 return id();
1366 }
1367
syncState()1368 void Texture::syncState()
1369 {
1370 mTexture->syncState(mDirtyBits);
1371 mDirtyBits.reset();
1372 }
1373
getAttachmentImpl() const1374 rx::FramebufferAttachmentObjectImpl *Texture::getAttachmentImpl() const
1375 {
1376 return mTexture;
1377 }
1378
isSamplerComplete(const Context * context,const Sampler * optionalSampler)1379 bool Texture::isSamplerComplete(const Context *context, const Sampler *optionalSampler)
1380 {
1381 const auto &samplerState =
1382 optionalSampler ? optionalSampler->getSamplerState() : mState.mSamplerState;
1383 const auto &contextState = context->getContextState();
1384
1385 if (contextState.getContextID() != mCompletenessCache.context ||
1386 mCompletenessCache.samplerState != samplerState)
1387 {
1388 mCompletenessCache.context = context->getContextState().getContextID();
1389 mCompletenessCache.samplerState = samplerState;
1390 mCompletenessCache.samplerComplete =
1391 mState.computeSamplerCompleteness(samplerState, contextState);
1392 }
1393
1394 return mCompletenessCache.samplerComplete;
1395 }
1396
SamplerCompletenessCache()1397 Texture::SamplerCompletenessCache::SamplerCompletenessCache()
1398 : context(0), samplerState(), samplerComplete(false)
1399 {
1400 }
1401
invalidateCompletenessCache() const1402 void Texture::invalidateCompletenessCache() const
1403 {
1404 mCompletenessCache.context = 0;
1405 }
1406
ensureInitialized(const Context * context)1407 Error Texture::ensureInitialized(const Context *context)
1408 {
1409 if (!context->isRobustResourceInitEnabled() || mState.mInitState == InitState::Initialized)
1410 {
1411 return NoError();
1412 }
1413
1414 bool anyDirty = false;
1415
1416 for (size_t descIndex = 0; descIndex < mState.mImageDescs.size(); ++descIndex)
1417 {
1418 auto &imageDesc = mState.mImageDescs[descIndex];
1419 if (imageDesc.initState == InitState::MayNeedInit)
1420 {
1421 ASSERT(mState.mInitState == InitState::MayNeedInit);
1422 const auto &imageIndex = GetImageIndexFromDescIndex(mState.mTarget, descIndex);
1423 ANGLE_TRY(initializeContents(context, imageIndex));
1424 imageDesc.initState = InitState::Initialized;
1425 anyDirty = true;
1426 }
1427 }
1428 if (anyDirty)
1429 {
1430 signalDirty(InitState::Initialized);
1431 }
1432 mState.mInitState = InitState::Initialized;
1433
1434 return NoError();
1435 }
1436
initState(const ImageIndex & imageIndex) const1437 InitState Texture::initState(const ImageIndex &imageIndex) const
1438 {
1439 return mState.getImageDesc(imageIndex).initState;
1440 }
1441
initState() const1442 InitState Texture::initState() const
1443 {
1444 return mState.mInitState;
1445 }
1446
setInitState(const ImageIndex & imageIndex,InitState initState)1447 void Texture::setInitState(const ImageIndex &imageIndex, InitState initState)
1448 {
1449 ImageDesc newDesc = mState.getImageDesc(imageIndex);
1450 newDesc.initState = initState;
1451 mState.setImageDesc(imageIndex.type, imageIndex.mipIndex, newDesc);
1452 }
1453
ensureSubImageInitialized(const Context * context,GLenum target,size_t level,const gl::Box & area)1454 Error Texture::ensureSubImageInitialized(const Context *context,
1455 GLenum target,
1456 size_t level,
1457 const gl::Box &area)
1458 {
1459 if (!context->isRobustResourceInitEnabled() || mState.mInitState == InitState::Initialized)
1460 {
1461 return NoError();
1462 }
1463
1464 // Pre-initialize the texture contents if necessary.
1465 // TODO(jmadill): Check if area overlaps the entire texture.
1466 const auto &imageIndex = GetImageIndexFromDescIndex(target, level);
1467 const auto &desc = mState.getImageDesc(imageIndex);
1468 if (desc.initState == InitState::MayNeedInit)
1469 {
1470 ASSERT(mState.mInitState == InitState::MayNeedInit);
1471 bool coversWholeImage = area.x == 0 && area.y == 0 && area.z == 0 &&
1472 area.width == desc.size.width && area.height == desc.size.height &&
1473 area.depth == desc.size.depth;
1474 if (!coversWholeImage)
1475 {
1476 ANGLE_TRY(initializeContents(context, imageIndex));
1477 }
1478 setInitState(imageIndex, InitState::Initialized);
1479 }
1480
1481 return NoError();
1482 }
1483
1484 } // namespace gl
1485