blob: f5327974cce0e9c9cff8f0251fdb783807427634 [file] [log] [blame]
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001//
Geoff Langcec35902014-04-16 10:52:36 -04002// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00003// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
Geoff Lang691e58c2014-12-19 17:03:25 -05007// Texture.cpp: Implements the gl::Texture class. [OpenGL ES 2.0.24] section 3.7 page 63.
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00008
Geoff Lang2b5420c2014-11-19 14:20:15 -05009#include "libANGLE/Texture.h"
Geoff Lang0b7eef72014-06-12 14:10:47 -040010
11#include "common/mathutil.h"
12#include "common/utilities.h"
Jamie Madill79481d62015-04-14 08:13:47 -040013#include "libANGLE/Config.h"
Jamie Madill1b94d432015-08-07 13:23:23 -040014#include "libANGLE/Context.h"
Jamie Madill79481d62015-04-14 08:13:47 -040015#include "libANGLE/Data.h"
Geoff Langa8406172015-07-21 16:53:39 -040016#include "libANGLE/Image.h"
Jamie Madill79481d62015-04-14 08:13:47 -040017#include "libANGLE/Surface.h"
18#include "libANGLE/formatutils.h"
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000019
20namespace gl
21{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000022
Brandon Jones6053a522014-07-25 16:22:09 -070023bool IsMipmapFiltered(const gl::SamplerState &samplerState)
24{
25 switch (samplerState.minFilter)
26 {
27 case GL_NEAREST:
28 case GL_LINEAR:
29 return false;
30 case GL_NEAREST_MIPMAP_NEAREST:
31 case GL_LINEAR_MIPMAP_NEAREST:
32 case GL_NEAREST_MIPMAP_LINEAR:
33 case GL_LINEAR_MIPMAP_LINEAR:
34 return true;
35 default: UNREACHABLE();
36 return false;
37 }
38}
39
40bool IsPointSampled(const gl::SamplerState &samplerState)
41{
42 return (samplerState.magFilter == GL_NEAREST && (samplerState.minFilter == GL_NEAREST || samplerState.minFilter == GL_NEAREST_MIPMAP_NEAREST));
43}
44
Geoff Lang866dd2d2015-02-10 11:08:32 -050045static size_t GetImageDescIndex(GLenum target, size_t level)
46{
47 return IsCubeMapTextureTarget(target) ? ((level * 6) + CubeMapTextureTargetToLayerIndex(target)) : level;
48}
49
Brandon Jones6053a522014-07-25 16:22:09 -070050Texture::Texture(rx::TextureImpl *impl, GLuint id, GLenum target)
Geoff Langa8406172015-07-21 16:53:39 -040051 : egl::ImageSibling(id),
Brandon Jones6053a522014-07-25 16:22:09 -070052 mTexture(impl),
Brandon Jonesf47bebc2014-07-09 14:28:42 -070053 mUsage(GL_NONE),
Jamie Madill6948e302014-10-20 17:04:33 -040054 mImmutableLevelCount(0),
Geoff Lang7c973ea2014-12-19 15:58:28 -050055 mTarget(target),
Geoff Lang866dd2d2015-02-10 11:08:32 -050056 mImageDescs(IMPLEMENTATION_MAX_TEXTURE_LEVELS * (target == GL_TEXTURE_CUBE_MAP ? 6 : 1)),
Geoff Lang0fe40532015-02-10 12:01:27 -050057 mCompletenessCache(),
Geoff Lang7c973ea2014-12-19 15:58:28 -050058 mBoundSurface(NULL)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000059{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000060}
61
62Texture::~Texture()
63{
Geoff Lang7c973ea2014-12-19 15:58:28 -050064 if (mBoundSurface)
65 {
66 mBoundSurface->releaseTexImage(EGL_BACK_BUFFER);
67 mBoundSurface = NULL;
68 }
Brandon Jones6053a522014-07-25 16:22:09 -070069 SafeDelete(mTexture);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000070}
71
Geoff Lang4907f2c2013-07-25 12:53:57 -040072GLenum Texture::getTarget() const
73{
74 return mTarget;
75}
76
Geoff Lang63b5f1f2013-09-23 14:52:14 -040077void Texture::setUsage(GLenum usage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000078{
Geoff Lang63b5f1f2013-09-23 14:52:14 -040079 mUsage = usage;
Brandon Jonescef06ff2014-08-05 13:27:48 -070080 getImplementation()->setUsage(usage);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000081}
82
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000083GLenum Texture::getUsage() const
84{
85 return mUsage;
86}
87
Geoff Langa9be0dc2014-12-17 12:34:40 -050088size_t Texture::getWidth(GLenum target, size_t level) const
Jamie Madilld3d2a342013-10-07 10:46:35 -040089{
Geoff Lang691e58c2014-12-19 17:03:25 -050090 ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
Geoff Lang866dd2d2015-02-10 11:08:32 -050091 return getImageDesc(target, level).size.width;
Jamie Madilld3d2a342013-10-07 10:46:35 -040092}
93
Geoff Langa9be0dc2014-12-17 12:34:40 -050094size_t Texture::getHeight(GLenum target, size_t level) const
Jamie Madilld3d2a342013-10-07 10:46:35 -040095{
Geoff Lang691e58c2014-12-19 17:03:25 -050096 ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
Geoff Lang866dd2d2015-02-10 11:08:32 -050097 return getImageDesc(target, level).size.height;
Jamie Madilld3d2a342013-10-07 10:46:35 -040098}
99
Geoff Langa9be0dc2014-12-17 12:34:40 -0500100size_t Texture::getDepth(GLenum target, size_t level) const
Jamie Madilld3d2a342013-10-07 10:46:35 -0400101{
Geoff Lang691e58c2014-12-19 17:03:25 -0500102 ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
Geoff Lang866dd2d2015-02-10 11:08:32 -0500103 return getImageDesc(target, level).size.depth;
Jamie Madilld3d2a342013-10-07 10:46:35 -0400104}
105
Geoff Langa9be0dc2014-12-17 12:34:40 -0500106GLenum Texture::getInternalFormat(GLenum target, size_t level) const
Jamie Madilld3d2a342013-10-07 10:46:35 -0400107{
Geoff Lang691e58c2014-12-19 17:03:25 -0500108 ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
Geoff Lang866dd2d2015-02-10 11:08:32 -0500109 return getImageDesc(target, level).internalFormat;
Jamie Madill945f7322014-09-03 15:07:14 -0400110}
111
Geoff Lang691e58c2014-12-19 17:03:25 -0500112bool Texture::isSamplerComplete(const SamplerState &samplerState, const Data &data) const
113{
Geoff Langb0eecdf2015-02-10 11:09:12 -0500114 const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), samplerState.baseLevel);
Geoff Langb0eecdf2015-02-10 11:09:12 -0500115 const TextureCaps &textureCaps = data.textureCaps->get(baseImageDesc.internalFormat);
Geoff Lang0fe40532015-02-10 12:01:27 -0500116 if (!mCompletenessCache.cacheValid ||
117 mCompletenessCache.samplerState != samplerState ||
118 mCompletenessCache.filterable != textureCaps.filterable ||
119 mCompletenessCache.clientVersion != data.clientVersion ||
120 mCompletenessCache.supportsNPOT != data.extensions->textureNPOT)
Geoff Lang691e58c2014-12-19 17:03:25 -0500121 {
Geoff Lang0fe40532015-02-10 12:01:27 -0500122 mCompletenessCache.cacheValid = true;
123 mCompletenessCache.samplerState = samplerState;
124 mCompletenessCache.filterable = textureCaps.filterable;
125 mCompletenessCache.clientVersion = data.clientVersion;
126 mCompletenessCache.supportsNPOT = data.extensions->textureNPOT;
127 mCompletenessCache.samplerComplete = computeSamplerCompleteness(samplerState, data);
Geoff Lang691e58c2014-12-19 17:03:25 -0500128 }
Geoff Lang0fe40532015-02-10 12:01:27 -0500129 return mCompletenessCache.samplerComplete;
Geoff Lang691e58c2014-12-19 17:03:25 -0500130}
131
Geoff Langa8406172015-07-21 16:53:39 -0400132bool Texture::isMipmapComplete() const
133{
134 return computeMipmapCompleteness(mSamplerState);
135}
136
Geoff Lang691e58c2014-12-19 17:03:25 -0500137// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
138bool Texture::isCubeComplete() const
139{
140 ASSERT(mTarget == GL_TEXTURE_CUBE_MAP);
141
Geoff Langb0eecdf2015-02-10 11:09:12 -0500142 const ImageDesc &baseImageDesc = getImageDesc(FirstCubeMapTextureTarget, 0);
143 if (baseImageDesc.size.width == 0 || baseImageDesc.size.width != baseImageDesc.size.height)
Geoff Lang691e58c2014-12-19 17:03:25 -0500144 {
145 return false;
146 }
147
Geoff Langb0eecdf2015-02-10 11:09:12 -0500148 for (GLenum face = FirstCubeMapTextureTarget + 1; face <= LastCubeMapTextureTarget; face++)
Geoff Lang691e58c2014-12-19 17:03:25 -0500149 {
Geoff Langb0eecdf2015-02-10 11:09:12 -0500150 const ImageDesc &faceImageDesc = getImageDesc(face, 0);
151 if (faceImageDesc.size.width != baseImageDesc.size.width ||
152 faceImageDesc.size.height != baseImageDesc.size.height ||
153 faceImageDesc.internalFormat != baseImageDesc.internalFormat)
Geoff Lang691e58c2014-12-19 17:03:25 -0500154 {
155 return false;
156 }
157 }
158
159 return true;
160}
161
Geoff Langa8406172015-07-21 16:53:39 -0400162size_t Texture::getMipCompleteLevels() const
163{
164 const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), 0);
165 if (mTarget == GL_TEXTURE_3D)
166 {
167 const size_t maxDim =
168 std::max(std::max(baseImageDesc.size.width, baseImageDesc.size.height),
169 baseImageDesc.size.depth);
170 return log2(maxDim) + 1;
171 }
172 else
173 {
174 return log2(std::max(baseImageDesc.size.width, baseImageDesc.size.height)) + 1;
175 }
176}
177
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700178bool Texture::isImmutable() const
179{
Jamie Madill6948e302014-10-20 17:04:33 -0400180 return (mImmutableLevelCount > 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700181}
182
183int Texture::immutableLevelCount()
184{
Jamie Madill6948e302014-10-20 17:04:33 -0400185 return mImmutableLevelCount;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700186}
187
Geoff Langa8406172015-07-21 16:53:39 -0400188egl::Surface *Texture::getBoundSurface() const
189{
190 return mBoundSurface;
191}
192
Jamie Madill1b94d432015-08-07 13:23:23 -0400193Error Texture::setImage(Context *context,
194 GLenum target,
195 size_t level,
196 GLenum internalFormat,
197 const Extents &size,
198 GLenum format,
199 GLenum type,
200 const uint8_t *pixels)
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500201{
Geoff Lang691e58c2014-12-19 17:03:25 -0500202 ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500203
Jamie Madillbb714f72015-05-20 10:22:18 -0400204 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
205 releaseTexImageInternal();
Geoff Langa8406172015-07-21 16:53:39 -0400206 orphanImages();
Jamie Madillbb714f72015-05-20 10:22:18 -0400207
Jamie Madill1b94d432015-08-07 13:23:23 -0400208 // Hack: allow nullptr for testing
209 if (context != nullptr)
210 {
211 // Sync the unpack state
212 context->syncRendererState(context->getState().unpackStateBitMask());
213 }
214
215 const PixelUnpackState &unpack =
216 context ? context->getState().getUnpackState() : PixelUnpackState();
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500217 Error error = mTexture->setImage(target, level, internalFormat, size, format, type, unpack, pixels);
218 if (error.isError())
219 {
220 return error;
221 }
222
Geoff Lang866dd2d2015-02-10 11:08:32 -0500223 setImageDesc(target, level, ImageDesc(size, GetSizedInternalFormat(internalFormat, type)));
Geoff Langa9be0dc2014-12-17 12:34:40 -0500224
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500225 return Error(GL_NO_ERROR);
226}
227
Jamie Madill1b94d432015-08-07 13:23:23 -0400228Error Texture::setSubImage(Context *context,
229 GLenum target,
230 size_t level,
231 const Box &area,
232 GLenum format,
233 GLenum type,
234 const uint8_t *pixels)
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500235{
Geoff Lang691e58c2014-12-19 17:03:25 -0500236 ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500237
Jamie Madill1b94d432015-08-07 13:23:23 -0400238 // Sync the unpack state
239 context->syncRendererState(context->getState().unpackStateBitMask());
240
241 const PixelUnpackState &unpack = context->getState().getUnpackState();
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500242 return mTexture->setSubImage(target, level, area, format, type, unpack, pixels);
243}
244
Jamie Madill1b94d432015-08-07 13:23:23 -0400245Error Texture::setCompressedImage(Context *context,
246 GLenum target,
247 size_t level,
248 GLenum internalFormat,
249 const Extents &size,
250 size_t imageSize,
251 const uint8_t *pixels)
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500252{
Geoff Lang691e58c2014-12-19 17:03:25 -0500253 ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500254
Jamie Madillbb714f72015-05-20 10:22:18 -0400255 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
256 releaseTexImageInternal();
Geoff Langa8406172015-07-21 16:53:39 -0400257 orphanImages();
Jamie Madillbb714f72015-05-20 10:22:18 -0400258
Jamie Madill1b94d432015-08-07 13:23:23 -0400259 // Sync the unpack state
260 context->syncRendererState(context->getState().unpackStateBitMask());
261
262 const PixelUnpackState &unpack = context->getState().getUnpackState();
Geoff Lang8509d862015-05-20 14:06:13 -0400263 Error error = mTexture->setCompressedImage(target, level, internalFormat, size, unpack, imageSize, pixels);
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500264 if (error.isError())
265 {
266 return error;
267 }
268
Geoff Lang866dd2d2015-02-10 11:08:32 -0500269 setImageDesc(target, level, ImageDesc(size, GetSizedInternalFormat(internalFormat, GL_UNSIGNED_BYTE)));
Geoff Langa9be0dc2014-12-17 12:34:40 -0500270
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500271 return Error(GL_NO_ERROR);
272}
273
Jamie Madill1b94d432015-08-07 13:23:23 -0400274Error Texture::setCompressedSubImage(Context *context,
275 GLenum target,
276 size_t level,
277 const Box &area,
278 GLenum format,
279 size_t imageSize,
280 const uint8_t *pixels)
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500281{
Geoff Lang691e58c2014-12-19 17:03:25 -0500282 ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500283
Jamie Madill1b94d432015-08-07 13:23:23 -0400284 // Sync the unpack state
285 context->syncRendererState(context->getState().unpackStateBitMask());
286
287 const PixelUnpackState &unpack = context->getState().getUnpackState();
Geoff Lang8509d862015-05-20 14:06:13 -0400288 return mTexture->setCompressedSubImage(target, level, area, format, unpack, imageSize, pixels);
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500289}
290
291Error Texture::copyImage(GLenum target, size_t level, const Rectangle &sourceArea, GLenum internalFormat,
292 const Framebuffer *source)
293{
Geoff Lang691e58c2014-12-19 17:03:25 -0500294 ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500295
Jamie Madillbb714f72015-05-20 10:22:18 -0400296 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
297 releaseTexImageInternal();
Geoff Langa8406172015-07-21 16:53:39 -0400298 orphanImages();
Jamie Madillbb714f72015-05-20 10:22:18 -0400299
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500300 Error error = mTexture->copyImage(target, level, sourceArea, internalFormat, source);
301 if (error.isError())
302 {
303 return error;
304 }
305
Geoff Lang866dd2d2015-02-10 11:08:32 -0500306 setImageDesc(target, level, ImageDesc(Extents(sourceArea.width, sourceArea.height, 1),
307 GetSizedInternalFormat(internalFormat, GL_UNSIGNED_BYTE)));
Geoff Langa9be0dc2014-12-17 12:34:40 -0500308
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500309 return Error(GL_NO_ERROR);
310}
311
312Error Texture::copySubImage(GLenum target, size_t level, const Offset &destOffset, const Rectangle &sourceArea,
313 const Framebuffer *source)
314{
Geoff Lang691e58c2014-12-19 17:03:25 -0500315 ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500316
317 return mTexture->copySubImage(target, level, destOffset, sourceArea, source);
318}
319
320Error Texture::setStorage(GLenum target, size_t levels, GLenum internalFormat, const Extents &size)
321{
322 ASSERT(target == mTarget);
323
Jamie Madillbb714f72015-05-20 10:22:18 -0400324 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
325 releaseTexImageInternal();
Geoff Langa8406172015-07-21 16:53:39 -0400326 orphanImages();
Jamie Madillbb714f72015-05-20 10:22:18 -0400327
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500328 Error error = mTexture->setStorage(target, levels, internalFormat, size);
329 if (error.isError())
330 {
331 return error;
332 }
333
334 mImmutableLevelCount = levels;
Geoff Langa9be0dc2014-12-17 12:34:40 -0500335 clearImageDescs();
336 setImageDescChain(levels, size, internalFormat);
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500337
338 return Error(GL_NO_ERROR);
339}
340
341
342Error Texture::generateMipmaps()
343{
Jamie Madillbb714f72015-05-20 10:22:18 -0400344 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
345 releaseTexImageInternal();
346
Geoff Langa8406172015-07-21 16:53:39 -0400347 // EGL_KHR_gl_image states that images are only orphaned when generating mipmaps if the texture
348 // is not mip complete.
349 if (!isMipmapComplete())
350 {
351 orphanImages();
352 }
353
Gregoire Payen de La Garanderie752ce192015-04-14 11:11:12 +0100354 Error error = mTexture->generateMipmaps(getSamplerState());
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500355 if (error.isError())
356 {
357 return error;
358 }
359
Geoff Lang866dd2d2015-02-10 11:08:32 -0500360 const ImageDesc &baseImageInfo = getImageDesc(getBaseImageTarget(), 0);
Geoff Langa9be0dc2014-12-17 12:34:40 -0500361 size_t mipLevels = log2(std::max(std::max(baseImageInfo.size.width, baseImageInfo.size.height), baseImageInfo.size.depth)) + 1;
362 setImageDescChain(mipLevels, baseImageInfo.size, baseImageInfo.internalFormat);
363
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500364 return Error(GL_NO_ERROR);
365}
366
Geoff Langa9be0dc2014-12-17 12:34:40 -0500367void Texture::setImageDescChain(size_t levels, Extents baseSize, GLenum sizedInternalFormat)
368{
369 for (size_t level = 0; level < levels; level++)
370 {
371 Extents levelSize(std::max<size_t>(baseSize.width >> level, 1),
372 std::max<size_t>(baseSize.height >> level, 1),
373 (mTarget == GL_TEXTURE_2D_ARRAY) ? baseSize.depth : std::max<size_t>(baseSize.depth >> level, 1));
374 ImageDesc levelInfo(levelSize, sizedInternalFormat);
375
376 if (mTarget == GL_TEXTURE_CUBE_MAP)
377 {
Geoff Lang691e58c2014-12-19 17:03:25 -0500378 for (size_t face = FirstCubeMapTextureTarget; face <= LastCubeMapTextureTarget; face++)
Geoff Langa9be0dc2014-12-17 12:34:40 -0500379 {
Geoff Lang866dd2d2015-02-10 11:08:32 -0500380 setImageDesc(face, level, levelInfo);
Geoff Langa9be0dc2014-12-17 12:34:40 -0500381 }
382 }
383 else
384 {
Geoff Lang866dd2d2015-02-10 11:08:32 -0500385 setImageDesc(mTarget, level, levelInfo);
Geoff Langa9be0dc2014-12-17 12:34:40 -0500386 }
387 }
388}
389
Geoff Langa9be0dc2014-12-17 12:34:40 -0500390Texture::ImageDesc::ImageDesc()
391 : ImageDesc(Extents(0, 0, 0), GL_NONE)
392{
393}
394
395Texture::ImageDesc::ImageDesc(const Extents &size, GLenum internalFormat)
396 : size(size),
397 internalFormat(internalFormat)
398{
399}
400
Geoff Lang866dd2d2015-02-10 11:08:32 -0500401const Texture::ImageDesc &Texture::getImageDesc(GLenum target, size_t level) const
Geoff Langa9be0dc2014-12-17 12:34:40 -0500402{
Geoff Lang866dd2d2015-02-10 11:08:32 -0500403 size_t descIndex = GetImageDescIndex(target, level);
404 ASSERT(descIndex < mImageDescs.size());
405 return mImageDescs[descIndex];
Geoff Langa9be0dc2014-12-17 12:34:40 -0500406}
407
Geoff Lang866dd2d2015-02-10 11:08:32 -0500408void Texture::setImageDesc(GLenum target, size_t level, const ImageDesc &desc)
Geoff Langa9be0dc2014-12-17 12:34:40 -0500409{
Geoff Lang866dd2d2015-02-10 11:08:32 -0500410 size_t descIndex = GetImageDescIndex(target, level);
411 ASSERT(descIndex < mImageDescs.size());
412 mImageDescs[descIndex] = desc;
Geoff Lang0fe40532015-02-10 12:01:27 -0500413 mCompletenessCache.cacheValid = false;
Geoff Langa9be0dc2014-12-17 12:34:40 -0500414}
415
Geoff Lang866dd2d2015-02-10 11:08:32 -0500416void Texture::clearImageDesc(GLenum target, size_t level)
Geoff Langb9266272015-01-29 13:25:14 +0000417{
Geoff Lang866dd2d2015-02-10 11:08:32 -0500418 setImageDesc(target, level, ImageDesc());
Geoff Langb9266272015-01-29 13:25:14 +0000419}
420
Geoff Langa9be0dc2014-12-17 12:34:40 -0500421void Texture::clearImageDescs()
422{
Geoff Lang866dd2d2015-02-10 11:08:32 -0500423 for (size_t descIndex = 0; descIndex < mImageDescs.size(); descIndex++)
424 {
425 mImageDescs[descIndex] = ImageDesc();
426 }
Geoff Lang0fe40532015-02-10 12:01:27 -0500427 mCompletenessCache.cacheValid = false;
Geoff Langa9be0dc2014-12-17 12:34:40 -0500428}
429
Jamie Madillbb714f72015-05-20 10:22:18 -0400430void Texture::bindTexImageFromSurface(egl::Surface *surface)
Geoff Lang7c973ea2014-12-19 15:58:28 -0500431{
Geoff Langb9266272015-01-29 13:25:14 +0000432 ASSERT(surface);
433
Jamie Madillbb714f72015-05-20 10:22:18 -0400434 if (mBoundSurface)
435 {
436 releaseTexImageFromSurface();
437 }
438
Geoff Lang7c973ea2014-12-19 15:58:28 -0500439 mTexture->bindTexImage(surface);
440 mBoundSurface = surface;
Geoff Langb9266272015-01-29 13:25:14 +0000441
442 // Set the image info to the size and format of the surface
443 ASSERT(mTarget == GL_TEXTURE_2D);
444 Extents size(surface->getWidth(), surface->getHeight(), 1);
Geoff Langc223dc62015-01-09 13:10:01 -0500445 ImageDesc desc(size, surface->getConfig()->renderTargetFormat);
Geoff Lang866dd2d2015-02-10 11:08:32 -0500446 setImageDesc(mTarget, 0, desc);
Geoff Lang7c973ea2014-12-19 15:58:28 -0500447}
448
Jamie Madillbb714f72015-05-20 10:22:18 -0400449void Texture::releaseTexImageFromSurface()
450{
451 ASSERT(mBoundSurface);
452 mBoundSurface = nullptr;
453 mTexture->releaseTexImage();
454
455 // Erase the image info for level 0
456 ASSERT(mTarget == GL_TEXTURE_2D);
457 clearImageDesc(mTarget, 0);
458}
459
460void Texture::releaseTexImageInternal()
Geoff Lang7c973ea2014-12-19 15:58:28 -0500461{
462 if (mBoundSurface)
463 {
Jamie Madillbb714f72015-05-20 10:22:18 -0400464 // Notify the surface
465 mBoundSurface->releaseTexImageFromTexture();
Geoff Langb9266272015-01-29 13:25:14 +0000466
Jamie Madillbb714f72015-05-20 10:22:18 -0400467 // Then, call the same method as from the surface
468 releaseTexImageFromSurface();
Geoff Lang7c973ea2014-12-19 15:58:28 -0500469 }
470}
471
Geoff Langa8406172015-07-21 16:53:39 -0400472Error Texture::setEGLImageTarget(GLenum target, egl::Image *imageTarget)
473{
474 ASSERT(target == mTarget);
475 ASSERT(target == GL_TEXTURE_2D);
476
477 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
478 releaseTexImageInternal();
479 orphanImages();
480
481 Error error = mTexture->setEGLImageTarget(target, imageTarget);
482 if (error.isError())
483 {
484 return error;
485 }
486
487 setTargetImage(imageTarget);
488
489 Extents size(imageTarget->getWidth(), imageTarget->getHeight(), 1);
490 GLenum internalFormat = imageTarget->getInternalFormat();
491 GLenum type = GetInternalFormatInfo(internalFormat).type;
492
493 clearImageDescs();
494 setImageDesc(target, 0, ImageDesc(size, GetSizedInternalFormat(internalFormat, type)));
495
496 return Error(GL_NO_ERROR);
497}
498
Geoff Lang691e58c2014-12-19 17:03:25 -0500499GLenum Texture::getBaseImageTarget() const
Jamie Madill22f843a2013-10-24 17:49:36 -0400500{
Geoff Lang691e58c2014-12-19 17:03:25 -0500501 return mTarget == GL_TEXTURE_CUBE_MAP ? FirstCubeMapTextureTarget : mTarget;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000502}
503
Geoff Lang0fe40532015-02-10 12:01:27 -0500504bool Texture::computeSamplerCompleteness(const SamplerState &samplerState, const Data &data) const
505{
506 const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), samplerState.baseLevel);
507 if (baseImageDesc.size.width == 0 || baseImageDesc.size.height == 0 || baseImageDesc.size.depth == 0)
508 {
509 return false;
510 }
511
512 if (mTarget == GL_TEXTURE_CUBE_MAP && baseImageDesc.size.width != baseImageDesc.size.height)
513 {
514 return false;
515 }
516
517 const TextureCaps &textureCaps = data.textureCaps->get(baseImageDesc.internalFormat);
518 if (!textureCaps.filterable && !IsPointSampled(samplerState))
519 {
520 return false;
521 }
522
523 bool npotSupport = data.extensions->textureNPOT || data.clientVersion >= 3;
524 if (!npotSupport)
525 {
526 if ((samplerState.wrapS != GL_CLAMP_TO_EDGE && !gl::isPow2(baseImageDesc.size.width)) ||
527 (samplerState.wrapT != GL_CLAMP_TO_EDGE && !gl::isPow2(baseImageDesc.size.height)))
528 {
529 return false;
530 }
531 }
532
533 if (IsMipmapFiltered(samplerState))
534 {
535 if (!npotSupport)
536 {
537 if (!gl::isPow2(baseImageDesc.size.width) || !gl::isPow2(baseImageDesc.size.height))
538 {
539 return false;
540 }
541 }
542
543 if (!computeMipmapCompleteness(samplerState))
544 {
545 return false;
546 }
547 }
548 else
549 {
550 if (mTarget == GL_TEXTURE_CUBE_MAP && !isCubeComplete())
551 {
552 return false;
553 }
554 }
555
556 // OpenGLES 3.0.2 spec section 3.8.13 states that a texture is not mipmap complete if:
557 // The internalformat specified for the texture arrays is a sized internal depth or
558 // depth and stencil format (see table 3.13), the value of TEXTURE_COMPARE_-
559 // MODE is NONE, and either the magnification filter is not NEAREST or the mini-
560 // fication filter is neither NEAREST nor NEAREST_MIPMAP_NEAREST.
561 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(baseImageDesc.internalFormat);
562 if (formatInfo.depthBits > 0 && data.clientVersion > 2)
563 {
564 if (samplerState.compareMode == GL_NONE)
565 {
566 if ((samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST) ||
567 samplerState.magFilter != GL_NEAREST)
568 {
569 return false;
570 }
571 }
572 }
573
574 return true;
575}
576
577bool Texture::computeMipmapCompleteness(const gl::SamplerState &samplerState) const
Brandon Jones6053a522014-07-25 16:22:09 -0700578{
Geoff Langa8406172015-07-21 16:53:39 -0400579 size_t expectedMipLevels = getMipCompleteLevels();
Jamie Madill19d438d2015-01-19 13:42:12 -0500580
581 size_t maxLevel = std::min<size_t>(expectedMipLevels, samplerState.maxLevel + 1);
582
583 for (size_t level = samplerState.baseLevel; level < maxLevel; level++)
Brandon Jones6053a522014-07-25 16:22:09 -0700584 {
Geoff Lang691e58c2014-12-19 17:03:25 -0500585 if (mTarget == GL_TEXTURE_CUBE_MAP)
Brandon Jones6053a522014-07-25 16:22:09 -0700586 {
Geoff Lang691e58c2014-12-19 17:03:25 -0500587 for (GLenum face = FirstCubeMapTextureTarget; face <= LastCubeMapTextureTarget; face++)
588 {
Geoff Lang0fe40532015-02-10 12:01:27 -0500589 if (!computeLevelCompleteness(face, level, samplerState))
Geoff Lang691e58c2014-12-19 17:03:25 -0500590 {
591 return false;
592 }
593 }
594 }
595 else
596 {
Geoff Lang0fe40532015-02-10 12:01:27 -0500597 if (!computeLevelCompleteness(mTarget, level, samplerState))
Geoff Lang691e58c2014-12-19 17:03:25 -0500598 {
599 return false;
600 }
Brandon Jones6053a522014-07-25 16:22:09 -0700601 }
602 }
603
604 return true;
605}
606
Geoff Lang691e58c2014-12-19 17:03:25 -0500607
Geoff Lang0fe40532015-02-10 12:01:27 -0500608bool Texture::computeLevelCompleteness(GLenum target, size_t level, const gl::SamplerState &samplerState) const
Brandon Jones6053a522014-07-25 16:22:09 -0700609{
Geoff Langa9be0dc2014-12-17 12:34:40 -0500610 ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
611
Brandon Jones6053a522014-07-25 16:22:09 -0700612 if (isImmutable())
613 {
614 return true;
615 }
616
Geoff Langb0eecdf2015-02-10 11:09:12 -0500617 const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), samplerState.baseLevel);
618 if (baseImageDesc.size.width == 0 || baseImageDesc.size.height == 0 || baseImageDesc.size.depth == 0)
Brandon Jones6053a522014-07-25 16:22:09 -0700619 {
620 return false;
621 }
622
Geoff Langa8406172015-07-21 16:53:39 -0400623 const ImageDesc &levelImageDesc = getImageDesc(target, level);
624 if (levelImageDesc.size.width == 0 || levelImageDesc.size.height == 0 ||
625 levelImageDesc.size.depth == 0)
Brandon Jones6053a522014-07-25 16:22:09 -0700626 {
Geoff Langa8406172015-07-21 16:53:39 -0400627 return false;
Brandon Jones6053a522014-07-25 16:22:09 -0700628 }
629
Geoff Langb0eecdf2015-02-10 11:09:12 -0500630 if (levelImageDesc.internalFormat != baseImageDesc.internalFormat)
Brandon Jones6053a522014-07-25 16:22:09 -0700631 {
632 return false;
633 }
634
Geoff Langb0eecdf2015-02-10 11:09:12 -0500635 if (levelImageDesc.size.width != std::max(1, baseImageDesc.size.width >> level))
Brandon Jones6053a522014-07-25 16:22:09 -0700636 {
637 return false;
638 }
639
Geoff Langb0eecdf2015-02-10 11:09:12 -0500640 if (levelImageDesc.size.height != std::max(1, baseImageDesc.size.height >> level))
Brandon Jones6053a522014-07-25 16:22:09 -0700641 {
642 return false;
643 }
644
Geoff Lang691e58c2014-12-19 17:03:25 -0500645 if (mTarget == GL_TEXTURE_3D)
Brandon Jones6053a522014-07-25 16:22:09 -0700646 {
Geoff Langb0eecdf2015-02-10 11:09:12 -0500647 if (levelImageDesc.size.depth != std::max(1, baseImageDesc.size.depth >> level))
Brandon Jones6053a522014-07-25 16:22:09 -0700648 {
649 return false;
650 }
651 }
Geoff Lang691e58c2014-12-19 17:03:25 -0500652 else if (mTarget == GL_TEXTURE_2D_ARRAY)
Brandon Jones6053a522014-07-25 16:22:09 -0700653 {
Geoff Langb0eecdf2015-02-10 11:09:12 -0500654 if (levelImageDesc.size.depth != baseImageDesc.size.depth)
Brandon Jones6053a522014-07-25 16:22:09 -0700655 {
656 return false;
657 }
658 }
659
660 return true;
661}
662
Geoff Lang0fe40532015-02-10 12:01:27 -0500663Texture::SamplerCompletenessCache::SamplerCompletenessCache()
664 : cacheValid(false),
665 samplerState(),
666 filterable(false),
667 clientVersion(0),
668 supportsNPOT(false),
669 samplerComplete(false)
670{
671}
672
Jamie Madill79481d62015-04-14 08:13:47 -0400673GLsizei Texture::getAttachmentWidth(const gl::FramebufferAttachment::Target &target) const
674{
675 return getWidth(target.textureIndex().type, target.textureIndex().mipIndex);
676}
677
678GLsizei Texture::getAttachmentHeight(const gl::FramebufferAttachment::Target &target) const
679{
680 return getHeight(target.textureIndex().type, target.textureIndex().mipIndex);
681}
682
683GLenum Texture::getAttachmentInternalFormat(const gl::FramebufferAttachment::Target &target) const
684{
685 return getInternalFormat(target.textureIndex().type, target.textureIndex().mipIndex);
686}
687
688GLsizei Texture::getAttachmentSamples(const gl::FramebufferAttachment::Target &/*target*/) const
689{
690 // Multisample textures not currently supported
691 return 0;
692}
693
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000694}