blob: 2d68bec917526ea9542017956d369f178595c5a3 [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 Langb4dedf32015-01-05 14:08:53 -050010#include "libANGLE/Data.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050011#include "libANGLE/formatutils.h"
Geoff Lang0b7eef72014-06-12 14:10:47 -040012
Geoff Langb9266272015-01-29 13:25:14 +000013#include "libANGLE/Config.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050014#include "libANGLE/Surface.h"
Geoff Lang0b7eef72014-06-12 14:10:47 -040015
16#include "common/mathutil.h"
17#include "common/utilities.h"
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000018
19namespace gl
20{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000021
Brandon Jones6053a522014-07-25 16:22:09 -070022bool IsMipmapFiltered(const gl::SamplerState &samplerState)
23{
24 switch (samplerState.minFilter)
25 {
26 case GL_NEAREST:
27 case GL_LINEAR:
28 return false;
29 case GL_NEAREST_MIPMAP_NEAREST:
30 case GL_LINEAR_MIPMAP_NEAREST:
31 case GL_NEAREST_MIPMAP_LINEAR:
32 case GL_LINEAR_MIPMAP_LINEAR:
33 return true;
34 default: UNREACHABLE();
35 return false;
36 }
37}
38
39bool IsPointSampled(const gl::SamplerState &samplerState)
40{
41 return (samplerState.magFilter == GL_NEAREST && (samplerState.minFilter == GL_NEAREST || samplerState.minFilter == GL_NEAREST_MIPMAP_NEAREST));
42}
43
Geoff Lang866dd2d2015-02-10 11:08:32 -050044static size_t GetImageDescIndex(GLenum target, size_t level)
45{
46 return IsCubeMapTextureTarget(target) ? ((level * 6) + CubeMapTextureTargetToLayerIndex(target)) : level;
47}
48
Jamie Madill10ef2152014-10-20 17:04:34 -040049unsigned int Texture::mCurrentTextureSerial = 1;
50
Brandon Jones6053a522014-07-25 16:22:09 -070051Texture::Texture(rx::TextureImpl *impl, GLuint id, GLenum target)
Brandon Jonesf47bebc2014-07-09 14:28:42 -070052 : RefCountObject(id),
Brandon Jones6053a522014-07-25 16:22:09 -070053 mTexture(impl),
Jamie Madill10ef2152014-10-20 17:04:34 -040054 mTextureSerial(issueTextureSerial()),
Brandon Jonesf47bebc2014-07-09 14:28:42 -070055 mUsage(GL_NONE),
Jamie Madill6948e302014-10-20 17:04:33 -040056 mImmutableLevelCount(0),
Geoff Lang7c973ea2014-12-19 15:58:28 -050057 mTarget(target),
Geoff Lang866dd2d2015-02-10 11:08:32 -050058 mImageDescs(IMPLEMENTATION_MAX_TEXTURE_LEVELS * (target == GL_TEXTURE_CUBE_MAP ? 6 : 1)),
Geoff Lang0fe40532015-02-10 12:01:27 -050059 mCompletenessCache(),
Geoff Lang7c973ea2014-12-19 15:58:28 -050060 mBoundSurface(NULL)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000061{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000062}
63
64Texture::~Texture()
65{
Geoff Lang7c973ea2014-12-19 15:58:28 -050066 if (mBoundSurface)
67 {
68 mBoundSurface->releaseTexImage(EGL_BACK_BUFFER);
69 mBoundSurface = NULL;
70 }
Brandon Jones6053a522014-07-25 16:22:09 -070071 SafeDelete(mTexture);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000072}
73
Geoff Lang4907f2c2013-07-25 12:53:57 -040074GLenum Texture::getTarget() const
75{
76 return mTarget;
77}
78
Geoff Lang63b5f1f2013-09-23 14:52:14 -040079void Texture::setUsage(GLenum usage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000080{
Geoff Lang63b5f1f2013-09-23 14:52:14 -040081 mUsage = usage;
Brandon Jonescef06ff2014-08-05 13:27:48 -070082 getImplementation()->setUsage(usage);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000083}
84
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000085GLenum Texture::getUsage() const
86{
87 return mUsage;
88}
89
Geoff Langa9be0dc2014-12-17 12:34:40 -050090size_t Texture::getWidth(GLenum target, size_t level) const
Jamie Madilld3d2a342013-10-07 10:46:35 -040091{
Geoff Lang691e58c2014-12-19 17:03:25 -050092 ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
Geoff Lang866dd2d2015-02-10 11:08:32 -050093 return getImageDesc(target, level).size.width;
Jamie Madilld3d2a342013-10-07 10:46:35 -040094}
95
Geoff Langa9be0dc2014-12-17 12:34:40 -050096size_t Texture::getHeight(GLenum target, size_t level) const
Jamie Madilld3d2a342013-10-07 10:46:35 -040097{
Geoff Lang691e58c2014-12-19 17:03:25 -050098 ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
Geoff Lang866dd2d2015-02-10 11:08:32 -050099 return getImageDesc(target, level).size.height;
Jamie Madilld3d2a342013-10-07 10:46:35 -0400100}
101
Geoff Langa9be0dc2014-12-17 12:34:40 -0500102size_t Texture::getDepth(GLenum target, size_t level) const
Jamie Madilld3d2a342013-10-07 10:46:35 -0400103{
Geoff Lang691e58c2014-12-19 17:03:25 -0500104 ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
Geoff Lang866dd2d2015-02-10 11:08:32 -0500105 return getImageDesc(target, level).size.depth;
Jamie Madilld3d2a342013-10-07 10:46:35 -0400106}
107
Geoff Langa9be0dc2014-12-17 12:34:40 -0500108GLenum Texture::getInternalFormat(GLenum target, size_t level) const
Jamie Madilld3d2a342013-10-07 10:46:35 -0400109{
Geoff Lang691e58c2014-12-19 17:03:25 -0500110 ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
Geoff Lang866dd2d2015-02-10 11:08:32 -0500111 return getImageDesc(target, level).internalFormat;
Jamie Madill945f7322014-09-03 15:07:14 -0400112}
113
Geoff Lang691e58c2014-12-19 17:03:25 -0500114bool Texture::isSamplerComplete(const SamplerState &samplerState, const Data &data) const
115{
Geoff Langb0eecdf2015-02-10 11:09:12 -0500116 const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), samplerState.baseLevel);
Geoff Langb0eecdf2015-02-10 11:09:12 -0500117 const TextureCaps &textureCaps = data.textureCaps->get(baseImageDesc.internalFormat);
Geoff Lang0fe40532015-02-10 12:01:27 -0500118 if (!mCompletenessCache.cacheValid ||
119 mCompletenessCache.samplerState != samplerState ||
120 mCompletenessCache.filterable != textureCaps.filterable ||
121 mCompletenessCache.clientVersion != data.clientVersion ||
122 mCompletenessCache.supportsNPOT != data.extensions->textureNPOT)
Geoff Lang691e58c2014-12-19 17:03:25 -0500123 {
Geoff Lang0fe40532015-02-10 12:01:27 -0500124 mCompletenessCache.cacheValid = true;
125 mCompletenessCache.samplerState = samplerState;
126 mCompletenessCache.filterable = textureCaps.filterable;
127 mCompletenessCache.clientVersion = data.clientVersion;
128 mCompletenessCache.supportsNPOT = data.extensions->textureNPOT;
129 mCompletenessCache.samplerComplete = computeSamplerCompleteness(samplerState, data);
Geoff Lang691e58c2014-12-19 17:03:25 -0500130 }
Geoff Lang0fe40532015-02-10 12:01:27 -0500131 return mCompletenessCache.samplerComplete;
Geoff Lang691e58c2014-12-19 17:03:25 -0500132}
133
134// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
135bool Texture::isCubeComplete() const
136{
137 ASSERT(mTarget == GL_TEXTURE_CUBE_MAP);
138
Geoff Langb0eecdf2015-02-10 11:09:12 -0500139 const ImageDesc &baseImageDesc = getImageDesc(FirstCubeMapTextureTarget, 0);
140 if (baseImageDesc.size.width == 0 || baseImageDesc.size.width != baseImageDesc.size.height)
Geoff Lang691e58c2014-12-19 17:03:25 -0500141 {
142 return false;
143 }
144
Geoff Langb0eecdf2015-02-10 11:09:12 -0500145 for (GLenum face = FirstCubeMapTextureTarget + 1; face <= LastCubeMapTextureTarget; face++)
Geoff Lang691e58c2014-12-19 17:03:25 -0500146 {
Geoff Langb0eecdf2015-02-10 11:09:12 -0500147 const ImageDesc &faceImageDesc = getImageDesc(face, 0);
148 if (faceImageDesc.size.width != baseImageDesc.size.width ||
149 faceImageDesc.size.height != baseImageDesc.size.height ||
150 faceImageDesc.internalFormat != baseImageDesc.internalFormat)
Geoff Lang691e58c2014-12-19 17:03:25 -0500151 {
152 return false;
153 }
154 }
155
156 return true;
157}
158
Jamie Madill10ef2152014-10-20 17:04:34 -0400159unsigned int Texture::getTextureSerial() const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700160{
Jamie Madill10ef2152014-10-20 17:04:34 -0400161 return mTextureSerial;
162}
163
164unsigned int Texture::issueTextureSerial()
165{
166 return mCurrentTextureSerial++;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700167}
168
169bool Texture::isImmutable() const
170{
Jamie Madill6948e302014-10-20 17:04:33 -0400171 return (mImmutableLevelCount > 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700172}
173
174int Texture::immutableLevelCount()
175{
Jamie Madill6948e302014-10-20 17:04:33 -0400176 return mImmutableLevelCount;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700177}
178
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500179Error Texture::setImage(GLenum target, size_t level, GLenum internalFormat, const Extents &size, GLenum format, GLenum type,
180 const PixelUnpackState &unpack, const uint8_t *pixels)
181{
Geoff Lang691e58c2014-12-19 17:03:25 -0500182 ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500183
184 Error error = mTexture->setImage(target, level, internalFormat, size, format, type, unpack, pixels);
185 if (error.isError())
186 {
187 return error;
188 }
189
Geoff Lang7c973ea2014-12-19 15:58:28 -0500190 releaseTexImage();
191
Geoff Lang866dd2d2015-02-10 11:08:32 -0500192 setImageDesc(target, level, ImageDesc(size, GetSizedInternalFormat(internalFormat, type)));
Geoff Langa9be0dc2014-12-17 12:34:40 -0500193
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500194 return Error(GL_NO_ERROR);
195}
196
197Error Texture::setSubImage(GLenum target, size_t level, const Box &area, GLenum format, GLenum type,
198 const PixelUnpackState &unpack, const uint8_t *pixels)
199{
Geoff Lang691e58c2014-12-19 17:03:25 -0500200 ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500201
202 return mTexture->setSubImage(target, level, area, format, type, unpack, pixels);
203}
204
205Error Texture::setCompressedImage(GLenum target, size_t level, GLenum internalFormat, const Extents &size,
206 const PixelUnpackState &unpack, const uint8_t *pixels)
207{
Geoff Lang691e58c2014-12-19 17:03:25 -0500208 ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500209
210 Error error = mTexture->setCompressedImage(target, level, internalFormat, size, unpack, pixels);
211 if (error.isError())
212 {
213 return error;
214 }
215
Geoff Lang7c973ea2014-12-19 15:58:28 -0500216 releaseTexImage();
217
Geoff Lang866dd2d2015-02-10 11:08:32 -0500218 setImageDesc(target, level, ImageDesc(size, GetSizedInternalFormat(internalFormat, GL_UNSIGNED_BYTE)));
Geoff Langa9be0dc2014-12-17 12:34:40 -0500219
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500220 return Error(GL_NO_ERROR);
221}
222
223Error Texture::setCompressedSubImage(GLenum target, size_t level, const Box &area, GLenum format,
224 const PixelUnpackState &unpack, const uint8_t *pixels)
225{
Geoff Lang691e58c2014-12-19 17:03:25 -0500226 ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500227
228 return mTexture->setCompressedSubImage(target, level, area, format, unpack, pixels);
229}
230
231Error Texture::copyImage(GLenum target, size_t level, const Rectangle &sourceArea, GLenum internalFormat,
232 const Framebuffer *source)
233{
Geoff Lang691e58c2014-12-19 17:03:25 -0500234 ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500235
236 Error error = mTexture->copyImage(target, level, sourceArea, internalFormat, source);
237 if (error.isError())
238 {
239 return error;
240 }
241
Geoff Lang7c973ea2014-12-19 15:58:28 -0500242 releaseTexImage();
243
Geoff Lang866dd2d2015-02-10 11:08:32 -0500244 setImageDesc(target, level, ImageDesc(Extents(sourceArea.width, sourceArea.height, 1),
245 GetSizedInternalFormat(internalFormat, GL_UNSIGNED_BYTE)));
Geoff Langa9be0dc2014-12-17 12:34:40 -0500246
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500247 return Error(GL_NO_ERROR);
248}
249
250Error Texture::copySubImage(GLenum target, size_t level, const Offset &destOffset, const Rectangle &sourceArea,
251 const Framebuffer *source)
252{
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
255 return mTexture->copySubImage(target, level, destOffset, sourceArea, source);
256}
257
258Error Texture::setStorage(GLenum target, size_t levels, GLenum internalFormat, const Extents &size)
259{
260 ASSERT(target == mTarget);
261
262 Error error = mTexture->setStorage(target, levels, internalFormat, size);
263 if (error.isError())
264 {
265 return error;
266 }
267
Geoff Lang7c973ea2014-12-19 15:58:28 -0500268 releaseTexImage();
269
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500270 mImmutableLevelCount = levels;
Geoff Langa9be0dc2014-12-17 12:34:40 -0500271 clearImageDescs();
272 setImageDescChain(levels, size, internalFormat);
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500273
274 return Error(GL_NO_ERROR);
275}
276
277
278Error Texture::generateMipmaps()
279{
280 Error error = mTexture->generateMipmaps();
281 if (error.isError())
282 {
283 return error;
284 }
285
Geoff Lang7c973ea2014-12-19 15:58:28 -0500286 releaseTexImage();
287
Geoff Lang866dd2d2015-02-10 11:08:32 -0500288 const ImageDesc &baseImageInfo = getImageDesc(getBaseImageTarget(), 0);
Geoff Langa9be0dc2014-12-17 12:34:40 -0500289 size_t mipLevels = log2(std::max(std::max(baseImageInfo.size.width, baseImageInfo.size.height), baseImageInfo.size.depth)) + 1;
290 setImageDescChain(mipLevels, baseImageInfo.size, baseImageInfo.internalFormat);
291
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500292 return Error(GL_NO_ERROR);
293}
294
Geoff Langa9be0dc2014-12-17 12:34:40 -0500295void Texture::setImageDescChain(size_t levels, Extents baseSize, GLenum sizedInternalFormat)
296{
297 for (size_t level = 0; level < levels; level++)
298 {
299 Extents levelSize(std::max<size_t>(baseSize.width >> level, 1),
300 std::max<size_t>(baseSize.height >> level, 1),
301 (mTarget == GL_TEXTURE_2D_ARRAY) ? baseSize.depth : std::max<size_t>(baseSize.depth >> level, 1));
302 ImageDesc levelInfo(levelSize, sizedInternalFormat);
303
304 if (mTarget == GL_TEXTURE_CUBE_MAP)
305 {
Geoff Lang691e58c2014-12-19 17:03:25 -0500306 for (size_t face = FirstCubeMapTextureTarget; face <= LastCubeMapTextureTarget; face++)
Geoff Langa9be0dc2014-12-17 12:34:40 -0500307 {
Geoff Lang866dd2d2015-02-10 11:08:32 -0500308 setImageDesc(face, level, levelInfo);
Geoff Langa9be0dc2014-12-17 12:34:40 -0500309 }
310 }
311 else
312 {
Geoff Lang866dd2d2015-02-10 11:08:32 -0500313 setImageDesc(mTarget, level, levelInfo);
Geoff Langa9be0dc2014-12-17 12:34:40 -0500314 }
315 }
316}
317
Geoff Langa9be0dc2014-12-17 12:34:40 -0500318Texture::ImageDesc::ImageDesc()
319 : ImageDesc(Extents(0, 0, 0), GL_NONE)
320{
321}
322
323Texture::ImageDesc::ImageDesc(const Extents &size, GLenum internalFormat)
324 : size(size),
325 internalFormat(internalFormat)
326{
327}
328
Geoff Lang866dd2d2015-02-10 11:08:32 -0500329const Texture::ImageDesc &Texture::getImageDesc(GLenum target, size_t level) const
Geoff Langa9be0dc2014-12-17 12:34:40 -0500330{
Geoff Lang866dd2d2015-02-10 11:08:32 -0500331 size_t descIndex = GetImageDescIndex(target, level);
332 ASSERT(descIndex < mImageDescs.size());
333 return mImageDescs[descIndex];
Geoff Langa9be0dc2014-12-17 12:34:40 -0500334}
335
Geoff Lang866dd2d2015-02-10 11:08:32 -0500336void Texture::setImageDesc(GLenum target, size_t level, const ImageDesc &desc)
Geoff Langa9be0dc2014-12-17 12:34:40 -0500337{
Geoff Lang866dd2d2015-02-10 11:08:32 -0500338 size_t descIndex = GetImageDescIndex(target, level);
339 ASSERT(descIndex < mImageDescs.size());
340 mImageDescs[descIndex] = desc;
Geoff Lang0fe40532015-02-10 12:01:27 -0500341 mCompletenessCache.cacheValid = false;
Geoff Langa9be0dc2014-12-17 12:34:40 -0500342}
343
Geoff Lang866dd2d2015-02-10 11:08:32 -0500344void Texture::clearImageDesc(GLenum target, size_t level)
Geoff Langb9266272015-01-29 13:25:14 +0000345{
Geoff Lang866dd2d2015-02-10 11:08:32 -0500346 setImageDesc(target, level, ImageDesc());
Geoff Langb9266272015-01-29 13:25:14 +0000347}
348
Geoff Langa9be0dc2014-12-17 12:34:40 -0500349void Texture::clearImageDescs()
350{
Geoff Lang866dd2d2015-02-10 11:08:32 -0500351 for (size_t descIndex = 0; descIndex < mImageDescs.size(); descIndex++)
352 {
353 mImageDescs[descIndex] = ImageDesc();
354 }
Geoff Lang0fe40532015-02-10 12:01:27 -0500355 mCompletenessCache.cacheValid = false;
Geoff Langa9be0dc2014-12-17 12:34:40 -0500356}
357
Geoff Lang7c973ea2014-12-19 15:58:28 -0500358void Texture::bindTexImage(egl::Surface *surface)
359{
Geoff Langb9266272015-01-29 13:25:14 +0000360 ASSERT(surface);
361
Geoff Lang7c973ea2014-12-19 15:58:28 -0500362 releaseTexImage();
363 mTexture->bindTexImage(surface);
364 mBoundSurface = surface;
Geoff Langb9266272015-01-29 13:25:14 +0000365
366 // Set the image info to the size and format of the surface
367 ASSERT(mTarget == GL_TEXTURE_2D);
368 Extents size(surface->getWidth(), surface->getHeight(), 1);
Geoff Langc223dc62015-01-09 13:10:01 -0500369 ImageDesc desc(size, surface->getConfig()->renderTargetFormat);
Geoff Lang866dd2d2015-02-10 11:08:32 -0500370 setImageDesc(mTarget, 0, desc);
Geoff Lang7c973ea2014-12-19 15:58:28 -0500371}
372
373void Texture::releaseTexImage()
374{
375 if (mBoundSurface)
376 {
377 mBoundSurface = NULL;
378 mTexture->releaseTexImage();
Geoff Langb9266272015-01-29 13:25:14 +0000379
380 // Erase the image info for level 0
381 ASSERT(mTarget == GL_TEXTURE_2D);
Geoff Lang866dd2d2015-02-10 11:08:32 -0500382 clearImageDesc(mTarget, 0);
Geoff Lang7c973ea2014-12-19 15:58:28 -0500383 }
384}
385
Geoff Lang691e58c2014-12-19 17:03:25 -0500386GLenum Texture::getBaseImageTarget() const
Jamie Madill22f843a2013-10-24 17:49:36 -0400387{
Geoff Lang691e58c2014-12-19 17:03:25 -0500388 return mTarget == GL_TEXTURE_CUBE_MAP ? FirstCubeMapTextureTarget : mTarget;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000389}
390
Geoff Lang691e58c2014-12-19 17:03:25 -0500391size_t Texture::getExpectedMipLevels() const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000392{
Geoff Langb0eecdf2015-02-10 11:09:12 -0500393 const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), 0);
Geoff Lang691e58c2014-12-19 17:03:25 -0500394 if (mTarget == GL_TEXTURE_3D)
395 {
Geoff Langb0eecdf2015-02-10 11:09:12 -0500396 return log2(std::max(std::max(baseImageDesc.size.width, baseImageDesc.size.height), baseImageDesc.size.depth)) + 1;
Geoff Lang691e58c2014-12-19 17:03:25 -0500397 }
398 else
399 {
Geoff Langb0eecdf2015-02-10 11:09:12 -0500400 return log2(std::max(baseImageDesc.size.width, baseImageDesc.size.height)) + 1;
Geoff Lang691e58c2014-12-19 17:03:25 -0500401 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000402}
403
Geoff Lang0fe40532015-02-10 12:01:27 -0500404bool Texture::computeSamplerCompleteness(const SamplerState &samplerState, const Data &data) const
405{
406 const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), samplerState.baseLevel);
407 if (baseImageDesc.size.width == 0 || baseImageDesc.size.height == 0 || baseImageDesc.size.depth == 0)
408 {
409 return false;
410 }
411
412 if (mTarget == GL_TEXTURE_CUBE_MAP && baseImageDesc.size.width != baseImageDesc.size.height)
413 {
414 return false;
415 }
416
417 const TextureCaps &textureCaps = data.textureCaps->get(baseImageDesc.internalFormat);
418 if (!textureCaps.filterable && !IsPointSampled(samplerState))
419 {
420 return false;
421 }
422
423 bool npotSupport = data.extensions->textureNPOT || data.clientVersion >= 3;
424 if (!npotSupport)
425 {
426 if ((samplerState.wrapS != GL_CLAMP_TO_EDGE && !gl::isPow2(baseImageDesc.size.width)) ||
427 (samplerState.wrapT != GL_CLAMP_TO_EDGE && !gl::isPow2(baseImageDesc.size.height)))
428 {
429 return false;
430 }
431 }
432
433 if (IsMipmapFiltered(samplerState))
434 {
435 if (!npotSupport)
436 {
437 if (!gl::isPow2(baseImageDesc.size.width) || !gl::isPow2(baseImageDesc.size.height))
438 {
439 return false;
440 }
441 }
442
443 if (!computeMipmapCompleteness(samplerState))
444 {
445 return false;
446 }
447 }
448 else
449 {
450 if (mTarget == GL_TEXTURE_CUBE_MAP && !isCubeComplete())
451 {
452 return false;
453 }
454 }
455
456 // OpenGLES 3.0.2 spec section 3.8.13 states that a texture is not mipmap complete if:
457 // The internalformat specified for the texture arrays is a sized internal depth or
458 // depth and stencil format (see table 3.13), the value of TEXTURE_COMPARE_-
459 // MODE is NONE, and either the magnification filter is not NEAREST or the mini-
460 // fication filter is neither NEAREST nor NEAREST_MIPMAP_NEAREST.
461 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(baseImageDesc.internalFormat);
462 if (formatInfo.depthBits > 0 && data.clientVersion > 2)
463 {
464 if (samplerState.compareMode == GL_NONE)
465 {
466 if ((samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST) ||
467 samplerState.magFilter != GL_NEAREST)
468 {
469 return false;
470 }
471 }
472 }
473
474 return true;
475}
476
477bool Texture::computeMipmapCompleteness(const gl::SamplerState &samplerState) const
Brandon Jones6053a522014-07-25 16:22:09 -0700478{
Geoff Lang691e58c2014-12-19 17:03:25 -0500479 size_t expectedMipLevels = getExpectedMipLevels();
Jamie Madill19d438d2015-01-19 13:42:12 -0500480
481 size_t maxLevel = std::min<size_t>(expectedMipLevels, samplerState.maxLevel + 1);
482
483 for (size_t level = samplerState.baseLevel; level < maxLevel; level++)
Brandon Jones6053a522014-07-25 16:22:09 -0700484 {
Geoff Lang691e58c2014-12-19 17:03:25 -0500485 if (mTarget == GL_TEXTURE_CUBE_MAP)
Brandon Jones6053a522014-07-25 16:22:09 -0700486 {
Geoff Lang691e58c2014-12-19 17:03:25 -0500487 for (GLenum face = FirstCubeMapTextureTarget; face <= LastCubeMapTextureTarget; face++)
488 {
Geoff Lang0fe40532015-02-10 12:01:27 -0500489 if (!computeLevelCompleteness(face, level, samplerState))
Geoff Lang691e58c2014-12-19 17:03:25 -0500490 {
491 return false;
492 }
493 }
494 }
495 else
496 {
Geoff Lang0fe40532015-02-10 12:01:27 -0500497 if (!computeLevelCompleteness(mTarget, level, samplerState))
Geoff Lang691e58c2014-12-19 17:03:25 -0500498 {
499 return false;
500 }
Brandon Jones6053a522014-07-25 16:22:09 -0700501 }
502 }
503
504 return true;
505}
506
Geoff Lang691e58c2014-12-19 17:03:25 -0500507
Geoff Lang0fe40532015-02-10 12:01:27 -0500508bool Texture::computeLevelCompleteness(GLenum target, size_t level, const gl::SamplerState &samplerState) const
Brandon Jones6053a522014-07-25 16:22:09 -0700509{
Geoff Langa9be0dc2014-12-17 12:34:40 -0500510 ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
511
Brandon Jones6053a522014-07-25 16:22:09 -0700512 if (isImmutable())
513 {
514 return true;
515 }
516
Geoff Langb0eecdf2015-02-10 11:09:12 -0500517 const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), samplerState.baseLevel);
518 if (baseImageDesc.size.width == 0 || baseImageDesc.size.height == 0 || baseImageDesc.size.depth == 0)
Brandon Jones6053a522014-07-25 16:22:09 -0700519 {
520 return false;
521 }
522
523 // The base image level is complete if the width and height are positive
524 if (level == 0)
525 {
526 return true;
527 }
528
Geoff Langb0eecdf2015-02-10 11:09:12 -0500529 const ImageDesc &levelImageDesc = getImageDesc(target, level);
530 if (levelImageDesc.internalFormat != baseImageDesc.internalFormat)
Brandon Jones6053a522014-07-25 16:22:09 -0700531 {
532 return false;
533 }
534
Geoff Langb0eecdf2015-02-10 11:09:12 -0500535 if (levelImageDesc.size.width != std::max(1, baseImageDesc.size.width >> level))
Brandon Jones6053a522014-07-25 16:22:09 -0700536 {
537 return false;
538 }
539
Geoff Langb0eecdf2015-02-10 11:09:12 -0500540 if (levelImageDesc.size.height != std::max(1, baseImageDesc.size.height >> level))
Brandon Jones6053a522014-07-25 16:22:09 -0700541 {
542 return false;
543 }
544
Geoff Lang691e58c2014-12-19 17:03:25 -0500545 if (mTarget == GL_TEXTURE_3D)
Brandon Jones6053a522014-07-25 16:22:09 -0700546 {
Geoff Langb0eecdf2015-02-10 11:09:12 -0500547 if (levelImageDesc.size.depth != std::max(1, baseImageDesc.size.depth >> level))
Brandon Jones6053a522014-07-25 16:22:09 -0700548 {
549 return false;
550 }
551 }
Geoff Lang691e58c2014-12-19 17:03:25 -0500552 else if (mTarget == GL_TEXTURE_2D_ARRAY)
Brandon Jones6053a522014-07-25 16:22:09 -0700553 {
Geoff Langb0eecdf2015-02-10 11:09:12 -0500554 if (levelImageDesc.size.depth != baseImageDesc.size.depth)
Brandon Jones6053a522014-07-25 16:22:09 -0700555 {
556 return false;
557 }
558 }
559
560 return true;
561}
562
Geoff Lang0fe40532015-02-10 12:01:27 -0500563Texture::SamplerCompletenessCache::SamplerCompletenessCache()
564 : cacheValid(false),
565 samplerState(),
566 filterable(false),
567 clientVersion(0),
568 supportsNPOT(false),
569 samplerComplete(false)
570{
571}
572
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000573}