blob: a59cf684bde53bf19fa531d9089c4127636c8a0f [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"
10#include "libANGLE/Context.h"
11#include "libANGLE/formatutils.h"
12#include "libANGLE/ImageIndex.h"
13#include "libANGLE/Renderbuffer.h"
14#include "libANGLE/renderer/Image.h"
15#include "libANGLE/renderer/d3d/TextureStorage.h"
Geoff Lang0b7eef72014-06-12 14:10:47 -040016
Geoff Lang2b5420c2014-11-19 14:20:15 -050017#include "libANGLE/Surface.h"
Geoff Lang0b7eef72014-06-12 14:10:47 -040018
19#include "common/mathutil.h"
20#include "common/utilities.h"
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000021
22namespace gl
23{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000024
Brandon Jones6053a522014-07-25 16:22:09 -070025bool IsMipmapFiltered(const gl::SamplerState &samplerState)
26{
27 switch (samplerState.minFilter)
28 {
29 case GL_NEAREST:
30 case GL_LINEAR:
31 return false;
32 case GL_NEAREST_MIPMAP_NEAREST:
33 case GL_LINEAR_MIPMAP_NEAREST:
34 case GL_NEAREST_MIPMAP_LINEAR:
35 case GL_LINEAR_MIPMAP_LINEAR:
36 return true;
37 default: UNREACHABLE();
38 return false;
39 }
40}
41
42bool IsPointSampled(const gl::SamplerState &samplerState)
43{
44 return (samplerState.magFilter == GL_NEAREST && (samplerState.minFilter == GL_NEAREST || samplerState.minFilter == GL_NEAREST_MIPMAP_NEAREST));
45}
46
Jamie Madill10ef2152014-10-20 17:04:34 -040047unsigned int Texture::mCurrentTextureSerial = 1;
48
Brandon Jones6053a522014-07-25 16:22:09 -070049Texture::Texture(rx::TextureImpl *impl, GLuint id, GLenum target)
Brandon Jonesf47bebc2014-07-09 14:28:42 -070050 : RefCountObject(id),
Brandon Jones6053a522014-07-25 16:22:09 -070051 mTexture(impl),
Jamie Madill10ef2152014-10-20 17:04:34 -040052 mTextureSerial(issueTextureSerial()),
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),
56 mBoundSurface(NULL)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000057{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000058}
59
60Texture::~Texture()
61{
Geoff Lang7c973ea2014-12-19 15:58:28 -050062 if (mBoundSurface)
63 {
64 mBoundSurface->releaseTexImage(EGL_BACK_BUFFER);
65 mBoundSurface = NULL;
66 }
Brandon Jones6053a522014-07-25 16:22:09 -070067 SafeDelete(mTexture);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000068}
69
Geoff Lang4907f2c2013-07-25 12:53:57 -040070GLenum Texture::getTarget() const
71{
72 return mTarget;
73}
74
Geoff Lang63b5f1f2013-09-23 14:52:14 -040075void Texture::setUsage(GLenum usage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000076{
Geoff Lang63b5f1f2013-09-23 14:52:14 -040077 mUsage = usage;
Brandon Jonescef06ff2014-08-05 13:27:48 -070078 getImplementation()->setUsage(usage);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000079}
80
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000081GLenum Texture::getUsage() const
82{
83 return mUsage;
84}
85
Geoff Langa9be0dc2014-12-17 12:34:40 -050086size_t Texture::getWidth(GLenum target, size_t level) const
Jamie Madilld3d2a342013-10-07 10:46:35 -040087{
Geoff Lang691e58c2014-12-19 17:03:25 -050088 ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
Geoff Lang909b90c2015-01-12 14:07:26 -050089 return getImageDesc(ImageIndex::MakeGeneric(target, level)).size.width;
Jamie Madilld3d2a342013-10-07 10:46:35 -040090}
91
Geoff Langa9be0dc2014-12-17 12:34:40 -050092size_t Texture::getHeight(GLenum target, size_t level) const
Jamie Madilld3d2a342013-10-07 10:46:35 -040093{
Geoff Lang691e58c2014-12-19 17:03:25 -050094 ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
Geoff Lang909b90c2015-01-12 14:07:26 -050095 return getImageDesc(ImageIndex::MakeGeneric(target, level)).size.height;
Jamie Madilld3d2a342013-10-07 10:46:35 -040096}
97
Geoff Langa9be0dc2014-12-17 12:34:40 -050098size_t Texture::getDepth(GLenum target, size_t level) const
Jamie Madilld3d2a342013-10-07 10:46:35 -040099{
Geoff Lang691e58c2014-12-19 17:03:25 -0500100 ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
Geoff Lang909b90c2015-01-12 14:07:26 -0500101 return getImageDesc(ImageIndex::MakeGeneric(target, level)).size.depth;
Jamie Madilld3d2a342013-10-07 10:46:35 -0400102}
103
Geoff Langa9be0dc2014-12-17 12:34:40 -0500104GLenum Texture::getInternalFormat(GLenum target, size_t level) const
Jamie Madilld3d2a342013-10-07 10:46:35 -0400105{
Geoff Lang691e58c2014-12-19 17:03:25 -0500106 ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
Geoff Lang909b90c2015-01-12 14:07:26 -0500107 return getImageDesc(ImageIndex::MakeGeneric(target, level)).internalFormat;
Jamie Madill945f7322014-09-03 15:07:14 -0400108}
109
Geoff Lang691e58c2014-12-19 17:03:25 -0500110bool Texture::isSamplerComplete(const SamplerState &samplerState, const Data &data) const
111{
112 GLenum baseTarget = getBaseImageTarget();
113 size_t width = getWidth(baseTarget, 0);
114 size_t height = getHeight(baseTarget, 0);
115 size_t depth = getDepth(baseTarget, 0);
116 if (width == 0 || height == 0 || depth == 0)
117 {
118 return false;
119 }
120
121 if (mTarget == GL_TEXTURE_CUBE_MAP && width != height)
122 {
123 return false;
124 }
125
126 GLenum internalFormat = getInternalFormat(baseTarget, 0);
127 const TextureCaps &textureCaps = data.textureCaps->get(internalFormat);
128 if (!textureCaps.filterable && !IsPointSampled(samplerState))
129 {
130 return false;
131 }
132
133 bool npotSupport = data.extensions->textureNPOT || data.clientVersion >= 3;
134 if (!npotSupport)
135 {
136 if ((samplerState.wrapS != GL_CLAMP_TO_EDGE && !gl::isPow2(width)) ||
137 (samplerState.wrapT != GL_CLAMP_TO_EDGE && !gl::isPow2(height)))
138 {
139 return false;
140 }
141 }
142
143 if (IsMipmapFiltered(samplerState))
144 {
145 if (!npotSupport)
146 {
147 if (!gl::isPow2(width) || !gl::isPow2(height))
148 {
149 return false;
150 }
151 }
152
153 if (!isMipmapComplete())
154 {
155 return false;
156 }
157 }
158 else
159 {
160 if (mTarget == GL_TEXTURE_CUBE_MAP && !isCubeComplete())
161 {
162 return false;
163 }
164 }
165
166 // OpenGLES 3.0.2 spec section 3.8.13 states that a texture is not mipmap complete if:
167 // The internalformat specified for the texture arrays is a sized internal depth or
168 // depth and stencil format (see table 3.13), the value of TEXTURE_COMPARE_-
169 // MODE is NONE, and either the magnification filter is not NEAREST or the mini-
170 // fication filter is neither NEAREST nor NEAREST_MIPMAP_NEAREST.
171 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat);
172 if (formatInfo.depthBits > 0 && data.clientVersion > 2)
173 {
174 if (samplerState.compareMode == GL_NONE)
175 {
176 if ((samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST) ||
177 samplerState.magFilter != GL_NEAREST)
178 {
179 return false;
180 }
181 }
182 }
183
184 return true;
185}
186
187// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
188bool Texture::isCubeComplete() const
189{
190 ASSERT(mTarget == GL_TEXTURE_CUBE_MAP);
191
192 GLenum baseTarget = FirstCubeMapTextureTarget;
193 size_t width = getWidth(baseTarget, 0);
194 size_t height = getWidth(baseTarget, 0);
195 if (width == 0 || width != height)
196 {
197 return false;
198 }
199
200 GLenum internalFormat = getInternalFormat(baseTarget, 0);
201 for (GLenum face = baseTarget + 1; face <= LastCubeMapTextureTarget; face++)
202 {
203 if (getWidth(face, 0) != width ||
204 getHeight(face, 0) != height ||
205 getInternalFormat(face, 0) != internalFormat)
206 {
207 return false;
208 }
209 }
210
211 return true;
212}
213
Jamie Madill10ef2152014-10-20 17:04:34 -0400214unsigned int Texture::getTextureSerial() const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700215{
Jamie Madill10ef2152014-10-20 17:04:34 -0400216 return mTextureSerial;
217}
218
219unsigned int Texture::issueTextureSerial()
220{
221 return mCurrentTextureSerial++;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700222}
223
224bool Texture::isImmutable() const
225{
Jamie Madill6948e302014-10-20 17:04:33 -0400226 return (mImmutableLevelCount > 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700227}
228
229int Texture::immutableLevelCount()
230{
Jamie Madill6948e302014-10-20 17:04:33 -0400231 return mImmutableLevelCount;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700232}
233
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500234Error Texture::setImage(GLenum target, size_t level, GLenum internalFormat, const Extents &size, GLenum format, GLenum type,
235 const PixelUnpackState &unpack, const uint8_t *pixels)
236{
Geoff Lang691e58c2014-12-19 17:03:25 -0500237 ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500238
239 Error error = mTexture->setImage(target, level, internalFormat, size, format, type, unpack, pixels);
240 if (error.isError())
241 {
242 return error;
243 }
244
Geoff Lang7c973ea2014-12-19 15:58:28 -0500245 releaseTexImage();
246
Geoff Lang909b90c2015-01-12 14:07:26 -0500247 setImageDesc(ImageIndex::MakeGeneric(target, level), ImageDesc(size, GetSizedInternalFormat(internalFormat, type)));
Geoff Langa9be0dc2014-12-17 12:34:40 -0500248
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500249 return Error(GL_NO_ERROR);
250}
251
252Error Texture::setSubImage(GLenum target, size_t level, const Box &area, GLenum format, GLenum type,
253 const PixelUnpackState &unpack, const uint8_t *pixels)
254{
Geoff Lang691e58c2014-12-19 17:03:25 -0500255 ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500256
257 return mTexture->setSubImage(target, level, area, format, type, unpack, pixels);
258}
259
260Error Texture::setCompressedImage(GLenum target, size_t level, GLenum internalFormat, const Extents &size,
261 const PixelUnpackState &unpack, const uint8_t *pixels)
262{
Geoff Lang691e58c2014-12-19 17:03:25 -0500263 ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500264
265 Error error = mTexture->setCompressedImage(target, level, internalFormat, size, unpack, pixels);
266 if (error.isError())
267 {
268 return error;
269 }
270
Geoff Lang7c973ea2014-12-19 15:58:28 -0500271 releaseTexImage();
272
Geoff Lang909b90c2015-01-12 14:07:26 -0500273 setImageDesc(ImageIndex::MakeGeneric(target, level), ImageDesc(size, GetSizedInternalFormat(internalFormat, GL_UNSIGNED_BYTE)));
Geoff Langa9be0dc2014-12-17 12:34:40 -0500274
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500275 return Error(GL_NO_ERROR);
276}
277
278Error Texture::setCompressedSubImage(GLenum target, size_t level, const Box &area, GLenum format,
279 const PixelUnpackState &unpack, const uint8_t *pixels)
280{
Geoff Lang691e58c2014-12-19 17:03:25 -0500281 ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500282
283 return mTexture->setCompressedSubImage(target, level, area, format, unpack, pixels);
284}
285
286Error Texture::copyImage(GLenum target, size_t level, const Rectangle &sourceArea, GLenum internalFormat,
287 const Framebuffer *source)
288{
Geoff Lang691e58c2014-12-19 17:03:25 -0500289 ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500290
291 Error error = mTexture->copyImage(target, level, sourceArea, internalFormat, source);
292 if (error.isError())
293 {
294 return error;
295 }
296
Geoff Lang7c973ea2014-12-19 15:58:28 -0500297 releaseTexImage();
298
Geoff Lang909b90c2015-01-12 14:07:26 -0500299 setImageDesc(ImageIndex::MakeGeneric(target, level), ImageDesc(Extents(sourceArea.width, sourceArea.height, 1),
Geoff Langa9be0dc2014-12-17 12:34:40 -0500300 GetSizedInternalFormat(internalFormat, GL_UNSIGNED_BYTE)));
301
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500302 return Error(GL_NO_ERROR);
303}
304
305Error Texture::copySubImage(GLenum target, size_t level, const Offset &destOffset, const Rectangle &sourceArea,
306 const Framebuffer *source)
307{
Geoff Lang691e58c2014-12-19 17:03:25 -0500308 ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500309
310 return mTexture->copySubImage(target, level, destOffset, sourceArea, source);
311}
312
313Error Texture::setStorage(GLenum target, size_t levels, GLenum internalFormat, const Extents &size)
314{
315 ASSERT(target == mTarget);
316
317 Error error = mTexture->setStorage(target, levels, internalFormat, size);
318 if (error.isError())
319 {
320 return error;
321 }
322
Geoff Lang7c973ea2014-12-19 15:58:28 -0500323 releaseTexImage();
324
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500325 mImmutableLevelCount = levels;
Geoff Langa9be0dc2014-12-17 12:34:40 -0500326 clearImageDescs();
327 setImageDescChain(levels, size, internalFormat);
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500328
329 return Error(GL_NO_ERROR);
330}
331
332
333Error Texture::generateMipmaps()
334{
335 Error error = mTexture->generateMipmaps();
336 if (error.isError())
337 {
338 return error;
339 }
340
Geoff Lang7c973ea2014-12-19 15:58:28 -0500341 releaseTexImage();
342
Geoff Lang909b90c2015-01-12 14:07:26 -0500343 ImageIndex baseLevel = ImageIndex::MakeGeneric(getBaseImageTarget(), 0);
Geoff Langa9be0dc2014-12-17 12:34:40 -0500344 const ImageDesc &baseImageInfo = getImageDesc(baseLevel);
345 size_t mipLevels = log2(std::max(std::max(baseImageInfo.size.width, baseImageInfo.size.height), baseImageInfo.size.depth)) + 1;
346 setImageDescChain(mipLevels, baseImageInfo.size, baseImageInfo.internalFormat);
347
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500348 return Error(GL_NO_ERROR);
349}
350
Geoff Langa9be0dc2014-12-17 12:34:40 -0500351void Texture::setImageDescChain(size_t levels, Extents baseSize, GLenum sizedInternalFormat)
352{
353 for (size_t level = 0; level < levels; level++)
354 {
355 Extents levelSize(std::max<size_t>(baseSize.width >> level, 1),
356 std::max<size_t>(baseSize.height >> level, 1),
357 (mTarget == GL_TEXTURE_2D_ARRAY) ? baseSize.depth : std::max<size_t>(baseSize.depth >> level, 1));
358 ImageDesc levelInfo(levelSize, sizedInternalFormat);
359
360 if (mTarget == GL_TEXTURE_CUBE_MAP)
361 {
Geoff Lang691e58c2014-12-19 17:03:25 -0500362 for (size_t face = FirstCubeMapTextureTarget; face <= LastCubeMapTextureTarget; face++)
Geoff Langa9be0dc2014-12-17 12:34:40 -0500363 {
Geoff Lang909b90c2015-01-12 14:07:26 -0500364 setImageDesc(ImageIndex::MakeGeneric(face, level), levelInfo);
Geoff Langa9be0dc2014-12-17 12:34:40 -0500365 }
366 }
367 else
368 {
Geoff Lang909b90c2015-01-12 14:07:26 -0500369 setImageDesc(ImageIndex::MakeGeneric(mTarget, level), levelInfo);
Geoff Langa9be0dc2014-12-17 12:34:40 -0500370 }
371 }
372}
373
Geoff Langa9be0dc2014-12-17 12:34:40 -0500374Texture::ImageDesc::ImageDesc()
375 : ImageDesc(Extents(0, 0, 0), GL_NONE)
376{
377}
378
379Texture::ImageDesc::ImageDesc(const Extents &size, GLenum internalFormat)
380 : size(size),
381 internalFormat(internalFormat)
382{
383}
384
Geoff Lang909b90c2015-01-12 14:07:26 -0500385const Texture::ImageDesc &Texture::getImageDesc(const ImageIndex &index) const
Geoff Langa9be0dc2014-12-17 12:34:40 -0500386{
387 static const Texture::ImageDesc defaultDesc;
388 ImageDescMap::const_iterator iter = mImageDescs.find(index);
389 return (iter != mImageDescs.end()) ? iter->second : defaultDesc;
390}
391
Geoff Lang909b90c2015-01-12 14:07:26 -0500392void Texture::setImageDesc(const ImageIndex &index, const ImageDesc &desc)
Geoff Langa9be0dc2014-12-17 12:34:40 -0500393{
394 mImageDescs[index] = desc;
395}
396
397void Texture::clearImageDescs()
398{
399 mImageDescs.clear();
400}
401
Geoff Lang7c973ea2014-12-19 15:58:28 -0500402void Texture::bindTexImage(egl::Surface *surface)
403{
404 releaseTexImage();
405 mTexture->bindTexImage(surface);
406 mBoundSurface = surface;
407}
408
409void Texture::releaseTexImage()
410{
411 if (mBoundSurface)
412 {
413 mBoundSurface = NULL;
414 mTexture->releaseTexImage();
415 }
416}
417
Geoff Lang691e58c2014-12-19 17:03:25 -0500418GLenum Texture::getBaseImageTarget() const
Jamie Madill22f843a2013-10-24 17:49:36 -0400419{
Geoff Lang691e58c2014-12-19 17:03:25 -0500420 return mTarget == GL_TEXTURE_CUBE_MAP ? FirstCubeMapTextureTarget : mTarget;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000421}
422
Geoff Lang691e58c2014-12-19 17:03:25 -0500423size_t Texture::getExpectedMipLevels() const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000424{
Geoff Lang691e58c2014-12-19 17:03:25 -0500425 GLenum baseTarget = getBaseImageTarget();
426 size_t width = getWidth(baseTarget, 0);
427 size_t height = getHeight(baseTarget, 0);
428 if (mTarget == GL_TEXTURE_3D)
429 {
430 size_t depth = getDepth(baseTarget, 0);
431 return log2(std::max(std::max(width, height), depth)) + 1;
432 }
433 else
434 {
435 return log2(std::max(width, height)) + 1;
436 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000437}
438
Geoff Lang691e58c2014-12-19 17:03:25 -0500439bool Texture::isMipmapComplete() const
Brandon Jones6053a522014-07-25 16:22:09 -0700440{
Geoff Lang691e58c2014-12-19 17:03:25 -0500441 size_t expectedMipLevels = getExpectedMipLevels();
Geoff Langa9be0dc2014-12-17 12:34:40 -0500442 for (size_t level = 0; level < expectedMipLevels; level++)
Brandon Jones6053a522014-07-25 16:22:09 -0700443 {
Geoff Lang691e58c2014-12-19 17:03:25 -0500444 if (mTarget == GL_TEXTURE_CUBE_MAP)
Brandon Jones6053a522014-07-25 16:22:09 -0700445 {
Geoff Lang691e58c2014-12-19 17:03:25 -0500446 for (GLenum face = FirstCubeMapTextureTarget; face <= LastCubeMapTextureTarget; face++)
447 {
448 if (!isLevelComplete(face, level))
449 {
450 return false;
451 }
452 }
453 }
454 else
455 {
456 if (!isLevelComplete(mTarget, level))
457 {
458 return false;
459 }
Brandon Jones6053a522014-07-25 16:22:09 -0700460 }
461 }
462
463 return true;
464}
465
Geoff Lang691e58c2014-12-19 17:03:25 -0500466
467bool Texture::isLevelComplete(GLenum target, size_t level) const
Brandon Jones6053a522014-07-25 16:22:09 -0700468{
Geoff Langa9be0dc2014-12-17 12:34:40 -0500469 ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
470
Brandon Jones6053a522014-07-25 16:22:09 -0700471 if (isImmutable())
472 {
473 return true;
474 }
475
Geoff Lang691e58c2014-12-19 17:03:25 -0500476 size_t width = getWidth(target, 0);
477 size_t height = getHeight(target, 0);
478 size_t depth = getHeight(target, 0);
479 if (width == 0 || height == 0 || depth == 0)
Brandon Jones6053a522014-07-25 16:22:09 -0700480 {
481 return false;
482 }
483
484 // The base image level is complete if the width and height are positive
485 if (level == 0)
486 {
487 return true;
488 }
489
Geoff Langa9be0dc2014-12-17 12:34:40 -0500490 if (getInternalFormat(target, level) != getInternalFormat(target, 0))
Brandon Jones6053a522014-07-25 16:22:09 -0700491 {
492 return false;
493 }
494
Geoff Lang691e58c2014-12-19 17:03:25 -0500495 if (getWidth(target, level) != std::max<size_t>(1, width >> level))
Brandon Jones6053a522014-07-25 16:22:09 -0700496 {
497 return false;
498 }
499
Geoff Lang691e58c2014-12-19 17:03:25 -0500500 if (getHeight(target, level) != std::max<size_t>(1, height >> level))
Brandon Jones6053a522014-07-25 16:22:09 -0700501 {
502 return false;
503 }
504
Geoff Lang691e58c2014-12-19 17:03:25 -0500505 if (mTarget == GL_TEXTURE_3D)
Brandon Jones6053a522014-07-25 16:22:09 -0700506 {
Geoff Lang691e58c2014-12-19 17:03:25 -0500507 if (getDepth(target, level) != std::max<size_t>(1, depth >> level))
Brandon Jones6053a522014-07-25 16:22:09 -0700508 {
509 return false;
510 }
511 }
Geoff Lang691e58c2014-12-19 17:03:25 -0500512 else if (mTarget == GL_TEXTURE_2D_ARRAY)
Brandon Jones6053a522014-07-25 16:22:09 -0700513 {
Geoff Lang691e58c2014-12-19 17:03:25 -0500514 if (getDepth(target, level) != depth)
Brandon Jones6053a522014-07-25 16:22:09 -0700515 {
516 return false;
517 }
518 }
519
520 return true;
521}
522
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000523}