blob: cd86bee513bd81f1615e41f0da072213810ef605 [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
7// Texture.cpp: Implements the gl::Texture class and its derived classes
8// Texture2D and TextureCubeMap. Implements GL texture objects and related
9// functionality. [OpenGL ES 2.0.24] section 3.7 page 63.
10
Geoff Lang2b5420c2014-11-19 14:20:15 -050011#include "libANGLE/Texture.h"
12#include "libANGLE/Context.h"
13#include "libANGLE/formatutils.h"
14#include "libANGLE/ImageIndex.h"
15#include "libANGLE/Renderbuffer.h"
16#include "libANGLE/renderer/Image.h"
17#include "libANGLE/renderer/d3d/TextureStorage.h"
Geoff Lang0b7eef72014-06-12 14:10:47 -040018
Geoff Lang2b5420c2014-11-19 14:20:15 -050019#include "libANGLE/Surface.h"
Geoff Lang0b7eef72014-06-12 14:10:47 -040020
21#include "common/mathutil.h"
22#include "common/utilities.h"
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000023
24namespace gl
25{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000026
Brandon Jones6053a522014-07-25 16:22:09 -070027bool IsMipmapFiltered(const gl::SamplerState &samplerState)
28{
29 switch (samplerState.minFilter)
30 {
31 case GL_NEAREST:
32 case GL_LINEAR:
33 return false;
34 case GL_NEAREST_MIPMAP_NEAREST:
35 case GL_LINEAR_MIPMAP_NEAREST:
36 case GL_NEAREST_MIPMAP_LINEAR:
37 case GL_LINEAR_MIPMAP_LINEAR:
38 return true;
39 default: UNREACHABLE();
40 return false;
41 }
42}
43
44bool IsPointSampled(const gl::SamplerState &samplerState)
45{
46 return (samplerState.magFilter == GL_NEAREST && (samplerState.minFilter == GL_NEAREST || samplerState.minFilter == GL_NEAREST_MIPMAP_NEAREST));
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),
58 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 Langa9be0dc2014-12-17 12:34:40 -050090 ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubemapTextureTarget(target)));
91 return getImageDesc(ImageIdentifier(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 Langa9be0dc2014-12-17 12:34:40 -050096 ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubemapTextureTarget(target)));
97 return getImageDesc(ImageIdentifier(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 Langa9be0dc2014-12-17 12:34:40 -0500102 ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubemapTextureTarget(target)));
103 return getImageDesc(ImageIdentifier(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 Langa9be0dc2014-12-17 12:34:40 -0500108 ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubemapTextureTarget(target)));
109 return getImageDesc(ImageIdentifier(target, level)).internalFormat;
Jamie Madill945f7322014-09-03 15:07:14 -0400110}
111
Jamie Madill10ef2152014-10-20 17:04:34 -0400112unsigned int Texture::getTextureSerial() const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700113{
Jamie Madill10ef2152014-10-20 17:04:34 -0400114 return mTextureSerial;
115}
116
117unsigned int Texture::issueTextureSerial()
118{
119 return mCurrentTextureSerial++;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700120}
121
122bool Texture::isImmutable() const
123{
Jamie Madill6948e302014-10-20 17:04:33 -0400124 return (mImmutableLevelCount > 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700125}
126
127int Texture::immutableLevelCount()
128{
Jamie Madill6948e302014-10-20 17:04:33 -0400129 return mImmutableLevelCount;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700130}
131
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500132Error Texture::setImage(GLenum target, size_t level, GLenum internalFormat, const Extents &size, GLenum format, GLenum type,
133 const PixelUnpackState &unpack, const uint8_t *pixels)
134{
135 ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubemapTextureTarget(target)));
136
137 Error error = mTexture->setImage(target, level, internalFormat, size, format, type, unpack, pixels);
138 if (error.isError())
139 {
140 return error;
141 }
142
Geoff Lang7c973ea2014-12-19 15:58:28 -0500143 releaseTexImage();
144
Geoff Langa9be0dc2014-12-17 12:34:40 -0500145 setImageDesc(ImageIdentifier(target, level), ImageDesc(size, GetSizedInternalFormat(internalFormat, type)));
146
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500147 return Error(GL_NO_ERROR);
148}
149
150Error Texture::setSubImage(GLenum target, size_t level, const Box &area, GLenum format, GLenum type,
151 const PixelUnpackState &unpack, const uint8_t *pixels)
152{
153 ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubemapTextureTarget(target)));
154
155 return mTexture->setSubImage(target, level, area, format, type, unpack, pixels);
156}
157
158Error Texture::setCompressedImage(GLenum target, size_t level, GLenum internalFormat, const Extents &size,
159 const PixelUnpackState &unpack, const uint8_t *pixels)
160{
161 ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubemapTextureTarget(target)));
162
163 Error error = mTexture->setCompressedImage(target, level, internalFormat, size, unpack, pixels);
164 if (error.isError())
165 {
166 return error;
167 }
168
Geoff Lang7c973ea2014-12-19 15:58:28 -0500169 releaseTexImage();
170
Geoff Langa9be0dc2014-12-17 12:34:40 -0500171 setImageDesc(ImageIdentifier(target, level), ImageDesc(size, GetSizedInternalFormat(internalFormat, GL_UNSIGNED_BYTE)));
172
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500173 return Error(GL_NO_ERROR);
174}
175
176Error Texture::setCompressedSubImage(GLenum target, size_t level, const Box &area, GLenum format,
177 const PixelUnpackState &unpack, const uint8_t *pixels)
178{
179 ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubemapTextureTarget(target)));
180
181 return mTexture->setCompressedSubImage(target, level, area, format, unpack, pixels);
182}
183
184Error Texture::copyImage(GLenum target, size_t level, const Rectangle &sourceArea, GLenum internalFormat,
185 const Framebuffer *source)
186{
187 ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubemapTextureTarget(target)));
188
189 Error error = mTexture->copyImage(target, level, sourceArea, internalFormat, source);
190 if (error.isError())
191 {
192 return error;
193 }
194
Geoff Lang7c973ea2014-12-19 15:58:28 -0500195 releaseTexImage();
196
Geoff Langa9be0dc2014-12-17 12:34:40 -0500197 setImageDesc(ImageIdentifier(target, level), ImageDesc(Extents(sourceArea.width, sourceArea.height, 1),
198 GetSizedInternalFormat(internalFormat, GL_UNSIGNED_BYTE)));
199
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500200 return Error(GL_NO_ERROR);
201}
202
203Error Texture::copySubImage(GLenum target, size_t level, const Offset &destOffset, const Rectangle &sourceArea,
204 const Framebuffer *source)
205{
206 ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubemapTextureTarget(target)));
207
208 return mTexture->copySubImage(target, level, destOffset, sourceArea, source);
209}
210
211Error Texture::setStorage(GLenum target, size_t levels, GLenum internalFormat, const Extents &size)
212{
213 ASSERT(target == mTarget);
214
215 Error error = mTexture->setStorage(target, levels, internalFormat, size);
216 if (error.isError())
217 {
218 return error;
219 }
220
Geoff Lang7c973ea2014-12-19 15:58:28 -0500221 releaseTexImage();
222
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500223 mImmutableLevelCount = levels;
Geoff Langa9be0dc2014-12-17 12:34:40 -0500224 clearImageDescs();
225 setImageDescChain(levels, size, internalFormat);
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500226
227 return Error(GL_NO_ERROR);
228}
229
230
231Error Texture::generateMipmaps()
232{
233 Error error = mTexture->generateMipmaps();
234 if (error.isError())
235 {
236 return error;
237 }
238
Geoff Lang7c973ea2014-12-19 15:58:28 -0500239 releaseTexImage();
240
Geoff Langa9be0dc2014-12-17 12:34:40 -0500241 ImageIdentifier baseLevel(mTarget == GL_TEXTURE_CUBE_MAP ? GL_TEXTURE_CUBE_MAP_POSITIVE_X : mTarget, 0);
242 const ImageDesc &baseImageInfo = getImageDesc(baseLevel);
243 size_t mipLevels = log2(std::max(std::max(baseImageInfo.size.width, baseImageInfo.size.height), baseImageInfo.size.depth)) + 1;
244 setImageDescChain(mipLevels, baseImageInfo.size, baseImageInfo.internalFormat);
245
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500246 return Error(GL_NO_ERROR);
247}
248
Geoff Langa9be0dc2014-12-17 12:34:40 -0500249void Texture::setImageDescChain(size_t levels, Extents baseSize, GLenum sizedInternalFormat)
250{
251 for (size_t level = 0; level < levels; level++)
252 {
253 Extents levelSize(std::max<size_t>(baseSize.width >> level, 1),
254 std::max<size_t>(baseSize.height >> level, 1),
255 (mTarget == GL_TEXTURE_2D_ARRAY) ? baseSize.depth : std::max<size_t>(baseSize.depth >> level, 1));
256 ImageDesc levelInfo(levelSize, sizedInternalFormat);
257
258 if (mTarget == GL_TEXTURE_CUBE_MAP)
259 {
260 for (size_t face = GL_TEXTURE_CUBE_MAP_POSITIVE_X; face <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z; face++)
261 {
262 setImageDesc(ImageIdentifier(face, level), levelInfo);
263 }
264 }
265 else
266 {
267 setImageDesc(ImageIdentifier(mTarget, level), levelInfo);
268 }
269 }
270}
271
272Texture::ImageIdentifier::ImageIdentifier()
273 : ImageIdentifier(GL_TEXTURE_2D, 0)
274{
275}
276
277Texture::ImageIdentifier::ImageIdentifier(GLenum target, size_t level)
278 : target(target),
279 level(level)
280{
281}
282
283bool Texture::ImageIdentifier::operator<(const ImageIdentifier &other) const
284{
285 return (target != other.target) ? target < other.target : level < other.level;
286}
287
288Texture::ImageDesc::ImageDesc()
289 : ImageDesc(Extents(0, 0, 0), GL_NONE)
290{
291}
292
293Texture::ImageDesc::ImageDesc(const Extents &size, GLenum internalFormat)
294 : size(size),
295 internalFormat(internalFormat)
296{
297}
298
299const Texture::ImageDesc &Texture::getImageDesc(const ImageIdentifier& index) const
300{
301 static const Texture::ImageDesc defaultDesc;
302 ImageDescMap::const_iterator iter = mImageDescs.find(index);
303 return (iter != mImageDescs.end()) ? iter->second : defaultDesc;
304}
305
306void Texture::setImageDesc(const ImageIdentifier& index, const ImageDesc &desc)
307{
308 mImageDescs[index] = desc;
309}
310
311void Texture::clearImageDescs()
312{
313 mImageDescs.clear();
314}
315
Geoff Lang7c973ea2014-12-19 15:58:28 -0500316void Texture::bindTexImage(egl::Surface *surface)
317{
318 releaseTexImage();
319 mTexture->bindTexImage(surface);
320 mBoundSurface = surface;
321}
322
323void Texture::releaseTexImage()
324{
325 if (mBoundSurface)
326 {
327 mBoundSurface = NULL;
328 mTexture->releaseTexImage();
329 }
330}
331
Brandon Jones6053a522014-07-25 16:22:09 -0700332Texture2D::Texture2D(rx::TextureImpl *impl, GLuint id)
333 : Texture(impl, id, GL_TEXTURE_2D)
Jamie Madill22f843a2013-10-24 17:49:36 -0400334{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000335}
336
337Texture2D::~Texture2D()
338{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000339}
340
Brandon Jones6053a522014-07-25 16:22:09 -0700341// Tests for 2D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85.
Geoff Langf4134d22014-12-15 10:29:47 -0500342bool Texture2D::isSamplerComplete(const SamplerState &samplerState, const Data &data) const
Brandon Jones6053a522014-07-25 16:22:09 -0700343{
Geoff Langa9be0dc2014-12-17 12:34:40 -0500344 size_t width = getWidth(GL_TEXTURE_2D, 0);
345 size_t height = getHeight(GL_TEXTURE_2D, 0);
346 if (width == 0 || height == 0)
Brandon Jones6053a522014-07-25 16:22:09 -0700347 {
348 return false;
349 }
350
Geoff Langa9be0dc2014-12-17 12:34:40 -0500351 GLenum internalFormat = getInternalFormat(GL_TEXTURE_2D, 0);
352 if (!data.textureCaps->get(internalFormat).filterable && !IsPointSampled(samplerState))
Brandon Jones6053a522014-07-25 16:22:09 -0700353 {
354 return false;
355 }
356
Geoff Langf4134d22014-12-15 10:29:47 -0500357 bool npotSupport = data.extensions->textureNPOT;
Brandon Jones6053a522014-07-25 16:22:09 -0700358 if (!npotSupport)
359 {
360 if ((samplerState.wrapS != GL_CLAMP_TO_EDGE && !gl::isPow2(width)) ||
361 (samplerState.wrapT != GL_CLAMP_TO_EDGE && !gl::isPow2(height)))
362 {
363 return false;
364 }
365 }
366
367 if (IsMipmapFiltered(samplerState))
368 {
369 if (!npotSupport)
370 {
371 if (!gl::isPow2(width) || !gl::isPow2(height))
372 {
373 return false;
374 }
375 }
376
377 if (!isMipmapComplete())
378 {
379 return false;
380 }
381 }
382
383 // OpenGLES 3.0.2 spec section 3.8.13 states that a texture is not mipmap complete if:
384 // The internalformat specified for the texture arrays is a sized internal depth or
385 // depth and stencil format (see table 3.13), the value of TEXTURE_COMPARE_-
386 // MODE is NONE, and either the magnification filter is not NEAREST or the mini-
387 // fication filter is neither NEAREST nor NEAREST_MIPMAP_NEAREST.
Geoff Langa9be0dc2014-12-17 12:34:40 -0500388 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat);
Geoff Langf4134d22014-12-15 10:29:47 -0500389 if (formatInfo.depthBits > 0 && data.clientVersion > 2)
Brandon Jones6053a522014-07-25 16:22:09 -0700390 {
391 if (samplerState.compareMode == GL_NONE)
392 {
393 if ((samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST) ||
394 samplerState.magFilter != GL_NEAREST)
395 {
396 return false;
397 }
398 }
399 }
400
401 return true;
402}
403
Brandon Jones6053a522014-07-25 16:22:09 -0700404// Tests for 2D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
405bool Texture2D::isMipmapComplete() const
406{
Geoff Langa9be0dc2014-12-17 12:34:40 -0500407 size_t width = getWidth(GL_TEXTURE_2D, 0);
408 size_t height = getHeight(GL_TEXTURE_2D, 0);
Brandon Jones6053a522014-07-25 16:22:09 -0700409
Geoff Langa9be0dc2014-12-17 12:34:40 -0500410 size_t expectedMipLevels = log2(std::max(width, height)) + 1;
411 for (size_t level = 0; level < expectedMipLevels; level++)
Brandon Jones6053a522014-07-25 16:22:09 -0700412 {
413 if (!isLevelComplete(level))
414 {
415 return false;
416 }
417 }
418
419 return true;
420}
421
Geoff Langa9be0dc2014-12-17 12:34:40 -0500422bool Texture2D::isLevelComplete(size_t level) const
Brandon Jones6053a522014-07-25 16:22:09 -0700423{
Geoff Langa9be0dc2014-12-17 12:34:40 -0500424 ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
425
Brandon Jones6053a522014-07-25 16:22:09 -0700426 if (isImmutable())
427 {
428 return true;
429 }
430
Geoff Langa9be0dc2014-12-17 12:34:40 -0500431 size_t width = getWidth(GL_TEXTURE_2D, 0);
432 size_t height = getHeight(GL_TEXTURE_2D, 0);
433 if (width == 0 || height == 0)
Brandon Jones6053a522014-07-25 16:22:09 -0700434 {
435 return false;
436 }
437
438 // The base image level is complete if the width and height are positive
439 if (level == 0)
440 {
441 return true;
442 }
443
Geoff Langa9be0dc2014-12-17 12:34:40 -0500444 if (getInternalFormat(GL_TEXTURE_2D, level) != getInternalFormat(GL_TEXTURE_2D, 0))
Brandon Jones6053a522014-07-25 16:22:09 -0700445 {
446 return false;
447 }
448
Geoff Langa9be0dc2014-12-17 12:34:40 -0500449 if (getWidth(GL_TEXTURE_2D, level) != std::max<size_t>(1, width >> level))
Brandon Jones6053a522014-07-25 16:22:09 -0700450 {
451 return false;
452 }
453
Geoff Langa9be0dc2014-12-17 12:34:40 -0500454 if (getHeight(GL_TEXTURE_2D, level) != std::max<size_t>(1, height >> level))
Brandon Jones6053a522014-07-25 16:22:09 -0700455 {
456 return false;
457 }
458
459 return true;
460}
461
462TextureCubeMap::TextureCubeMap(rx::TextureImpl *impl, GLuint id)
463 : Texture(impl, id, GL_TEXTURE_CUBE_MAP)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000464{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000465}
466
467TextureCubeMap::~TextureCubeMap()
468{
Brandon Jones0511e802014-07-14 16:27:26 -0700469}
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000470
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000471// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
472bool TextureCubeMap::isCubeComplete() const
473{
Geoff Langa9be0dc2014-12-17 12:34:40 -0500474 size_t width = getWidth(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0);
475 size_t height = getWidth(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0);
476 if (width == 0 || width != height)
Brandon Jones6053a522014-07-25 16:22:09 -0700477 {
478 return false;
479 }
480
Geoff Langa9be0dc2014-12-17 12:34:40 -0500481 GLenum internalFormat = getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0);
482 for (GLenum face = GL_TEXTURE_CUBE_MAP_POSITIVE_X + 1; face <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z; face++)
Brandon Jones6053a522014-07-25 16:22:09 -0700483 {
Geoff Langa9be0dc2014-12-17 12:34:40 -0500484 if (getWidth(face, 0) != width ||
485 getHeight(face, 0) != height ||
486 getInternalFormat(face, 0) != internalFormat)
Brandon Jones6053a522014-07-25 16:22:09 -0700487 {
488 return false;
489 }
490 }
491
492 return true;
Jamie Madill07edd442013-07-19 16:36:58 -0400493}
494
Brandon Jones6053a522014-07-25 16:22:09 -0700495// Tests for texture sampling completeness
Geoff Langf4134d22014-12-15 10:29:47 -0500496bool TextureCubeMap::isSamplerComplete(const SamplerState &samplerState, const Data &data) const
Brandon Jones6053a522014-07-25 16:22:09 -0700497{
Brandon Jones6053a522014-07-25 16:22:09 -0700498 bool mipmapping = IsMipmapFiltered(samplerState);
499
Geoff Langa9be0dc2014-12-17 12:34:40 -0500500 GLenum internalFormat = getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0);
501 if (!data.textureCaps->get(internalFormat).filterable && !IsPointSampled(samplerState))
Brandon Jones6053a522014-07-25 16:22:09 -0700502 {
503 return false;
504 }
505
Geoff Langa9be0dc2014-12-17 12:34:40 -0500506 size_t size = getWidth(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0);
Geoff Langf4134d22014-12-15 10:29:47 -0500507 if (!gl::isPow2(size) && !data.extensions->textureNPOT)
Brandon Jones6053a522014-07-25 16:22:09 -0700508 {
509 if (samplerState.wrapS != GL_CLAMP_TO_EDGE || samplerState.wrapT != GL_CLAMP_TO_EDGE || mipmapping)
510 {
511 return false;
512 }
513 }
514
515 if (!mipmapping)
516 {
517 if (!isCubeComplete())
518 {
519 return false;
520 }
521 }
522 else
523 {
524 if (!isMipmapComplete()) // Also tests for isCubeComplete()
525 {
526 return false;
527 }
528 }
529
530 return true;
531}
532
Brandon Jonescef06ff2014-08-05 13:27:48 -0700533int TextureCubeMap::targetToLayerIndex(GLenum target)
534{
535 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
536 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
537 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
538 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
539 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
540
541 return target - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
542}
543
544GLenum TextureCubeMap::layerIndexToTarget(GLint layer)
545{
546 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
547 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
548 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
549 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
550 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
551
552 return GL_TEXTURE_CUBE_MAP_POSITIVE_X + layer;
Geoff Lang8040f572013-07-25 16:49:54 -0400553}
554
Brandon Jones6053a522014-07-25 16:22:09 -0700555bool TextureCubeMap::isMipmapComplete() const
556{
557 if (isImmutable())
558 {
559 return true;
560 }
561
562 if (!isCubeComplete())
563 {
564 return false;
565 }
566
Geoff Langa9be0dc2014-12-17 12:34:40 -0500567 size_t width = getWidth(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0);
568 size_t height = getHeight(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0);
Brandon Jones6053a522014-07-25 16:22:09 -0700569
Geoff Langa9be0dc2014-12-17 12:34:40 -0500570 size_t expectedMipLevels = log2(std::max(width, height)) + 1;
571 for (GLenum face = GL_TEXTURE_CUBE_MAP_NEGATIVE_X; face <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z; face++)
Brandon Jones6053a522014-07-25 16:22:09 -0700572 {
Geoff Langa9be0dc2014-12-17 12:34:40 -0500573 for (size_t level = 1; level < expectedMipLevels; level++)
Brandon Jones6053a522014-07-25 16:22:09 -0700574 {
575 if (!isFaceLevelComplete(face, level))
576 {
577 return false;
578 }
579 }
580 }
581
582 return true;
583}
584
Geoff Langa9be0dc2014-12-17 12:34:40 -0500585bool TextureCubeMap::isFaceLevelComplete(GLenum target, size_t level) const
Brandon Jones6053a522014-07-25 16:22:09 -0700586{
Geoff Langa9be0dc2014-12-17 12:34:40 -0500587 ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && IsCubemapTextureTarget(target));
Brandon Jones6053a522014-07-25 16:22:09 -0700588
589 if (isImmutable())
590 {
591 return true;
592 }
593
Geoff Langa9be0dc2014-12-17 12:34:40 -0500594 size_t baseSize = getWidth(target, 0);
595 if (baseSize == 0)
Brandon Jones6053a522014-07-25 16:22:09 -0700596 {
597 return false;
598 }
599
600 // "isCubeComplete" checks for base level completeness and we must call that
601 // to determine if any face at level 0 is complete. We omit that check here
602 // to avoid re-checking cube-completeness for every face at level 0.
603 if (level == 0)
604 {
605 return true;
606 }
607
608 // Check that non-zero levels are consistent with the base level.
Geoff Langa9be0dc2014-12-17 12:34:40 -0500609 if (getInternalFormat(target, level) != getInternalFormat(target, 0))
Brandon Jones6053a522014-07-25 16:22:09 -0700610 {
611 return false;
612 }
613
Geoff Langa9be0dc2014-12-17 12:34:40 -0500614 if (getWidth(target, level) != std::max<size_t>(1, baseSize >> level))
Brandon Jones6053a522014-07-25 16:22:09 -0700615 {
616 return false;
617 }
618
619 return true;
620}
621
622
623Texture3D::Texture3D(rx::TextureImpl *impl, GLuint id)
624 : Texture(impl, id, GL_TEXTURE_3D)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +0000625{
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +0000626}
627
628Texture3D::~Texture3D()
629{
Brandon Jones78b1acd2014-07-15 15:33:07 -0700630}
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +0000631
Geoff Langf4134d22014-12-15 10:29:47 -0500632bool Texture3D::isSamplerComplete(const SamplerState &samplerState, const Data &data) const
Brandon Jones6053a522014-07-25 16:22:09 -0700633{
Geoff Langa9be0dc2014-12-17 12:34:40 -0500634 size_t width = getWidth(GL_TEXTURE_3D, 0);
635 size_t height = getHeight(GL_TEXTURE_3D, 0);
636 size_t depth = getDepth(GL_TEXTURE_3D, 0);
637 if (width == 0 || height == 0 || depth == 0)
Brandon Jones6053a522014-07-25 16:22:09 -0700638 {
639 return false;
640 }
641
Geoff Langa9be0dc2014-12-17 12:34:40 -0500642 GLenum internalFormat = getInternalFormat(GL_TEXTURE_3D, 0);
643 if (!data.textureCaps->get(internalFormat).filterable && !IsPointSampled(samplerState))
Brandon Jones6053a522014-07-25 16:22:09 -0700644 {
645 return false;
646 }
647
648 if (IsMipmapFiltered(samplerState) && !isMipmapComplete())
649 {
650 return false;
651 }
652
653 return true;
654}
655
Brandon Jones6053a522014-07-25 16:22:09 -0700656bool Texture3D::isMipmapComplete() const
657{
Geoff Langa9be0dc2014-12-17 12:34:40 -0500658 size_t width = getWidth(GL_TEXTURE_2D_ARRAY, 0);
659 size_t height = getHeight(GL_TEXTURE_2D_ARRAY, 0);
660 size_t depth = getDepth(GL_TEXTURE_3D, 0);
Brandon Jones6053a522014-07-25 16:22:09 -0700661
Geoff Langa9be0dc2014-12-17 12:34:40 -0500662 size_t expectedMipLevels = log2(std::max(std::max(width, height), depth)) + 1;
663 for (size_t level = 0; level < expectedMipLevels; level++)
Brandon Jones6053a522014-07-25 16:22:09 -0700664 {
665 if (!isLevelComplete(level))
666 {
667 return false;
668 }
669 }
670
671 return true;
672}
673
Geoff Langa9be0dc2014-12-17 12:34:40 -0500674bool Texture3D::isLevelComplete(size_t level) const
Brandon Jones6053a522014-07-25 16:22:09 -0700675{
Geoff Langa9be0dc2014-12-17 12:34:40 -0500676 ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jones6053a522014-07-25 16:22:09 -0700677
678 if (isImmutable())
679 {
680 return true;
681 }
682
Geoff Langa9be0dc2014-12-17 12:34:40 -0500683 size_t width = getWidth(GL_TEXTURE_3D, level);
684 size_t height = getHeight(GL_TEXTURE_3D, level);
685 size_t depth = getDepth(GL_TEXTURE_3D, level);
686 if (width == 0 || height == 0 || depth == 0)
Brandon Jones6053a522014-07-25 16:22:09 -0700687 {
688 return false;
689 }
690
691 if (level == 0)
692 {
693 return true;
694 }
695
Geoff Langa9be0dc2014-12-17 12:34:40 -0500696 if (getInternalFormat(GL_TEXTURE_3D, level) != getInternalFormat(GL_TEXTURE_3D, 0))
Brandon Jones6053a522014-07-25 16:22:09 -0700697 {
698 return false;
699 }
700
Geoff Langa9be0dc2014-12-17 12:34:40 -0500701 if (getWidth(GL_TEXTURE_3D, level) != std::max<size_t>(1, width >> level))
Brandon Jones6053a522014-07-25 16:22:09 -0700702 {
703 return false;
704 }
705
Geoff Langa9be0dc2014-12-17 12:34:40 -0500706 if (getHeight(GL_TEXTURE_3D, level) != std::max<size_t>(1, height >> level))
Brandon Jones6053a522014-07-25 16:22:09 -0700707 {
708 return false;
709 }
710
Geoff Langa9be0dc2014-12-17 12:34:40 -0500711 if (getDepth(GL_TEXTURE_3D, level) != std::max<size_t>(1, depth >> level))
Brandon Jones6053a522014-07-25 16:22:09 -0700712 {
713 return false;
714 }
715
716 return true;
717}
718
719Texture2DArray::Texture2DArray(rx::TextureImpl *impl, GLuint id)
720 : Texture(impl, id, GL_TEXTURE_2D_ARRAY)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +0000721{
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +0000722}
723
724Texture2DArray::~Texture2DArray()
725{
Jamie Madill884a4622013-10-24 17:49:41 -0400726}
727
Geoff Langf4134d22014-12-15 10:29:47 -0500728bool Texture2DArray::isSamplerComplete(const SamplerState &samplerState, const Data &data) const
Brandon Jones6053a522014-07-25 16:22:09 -0700729{
Geoff Langa9be0dc2014-12-17 12:34:40 -0500730 size_t width = getWidth(GL_TEXTURE_2D_ARRAY, 0);
731 size_t height = getHeight(GL_TEXTURE_2D_ARRAY, 0);
732 size_t depth = getDepth(GL_TEXTURE_2D_ARRAY, 0);
733 if (width == 0 || height == 0 || depth == 0)
Brandon Jones6053a522014-07-25 16:22:09 -0700734 {
735 return false;
736 }
737
Geoff Langa9be0dc2014-12-17 12:34:40 -0500738 GLenum internalFormat = getInternalFormat(GL_TEXTURE_2D_ARRAY, 0);
739 if (!data.textureCaps->get(internalFormat).filterable && !IsPointSampled(samplerState))
Brandon Jones6053a522014-07-25 16:22:09 -0700740 {
741 return false;
742 }
743
744 if (IsMipmapFiltered(samplerState) && !isMipmapComplete())
745 {
746 return false;
747 }
748
749 return true;
750}
751
Brandon Jones6053a522014-07-25 16:22:09 -0700752bool Texture2DArray::isMipmapComplete() const
753{
Geoff Langa9be0dc2014-12-17 12:34:40 -0500754 size_t width = getWidth(GL_TEXTURE_2D_ARRAY, 0);
755 size_t height = getHeight(GL_TEXTURE_2D_ARRAY, 0);
Brandon Jones6053a522014-07-25 16:22:09 -0700756
Geoff Langa9be0dc2014-12-17 12:34:40 -0500757 size_t expectedMipLevels = log2(std::max(width, height)) + 1;
758 for (size_t level = 1; level < expectedMipLevels; level++)
Brandon Jones6053a522014-07-25 16:22:09 -0700759 {
760 if (!isLevelComplete(level))
761 {
762 return false;
763 }
764 }
765
766 return true;
767}
768
Geoff Langa9be0dc2014-12-17 12:34:40 -0500769bool Texture2DArray::isLevelComplete(size_t level) const
Brandon Jones6053a522014-07-25 16:22:09 -0700770{
Geoff Langa9be0dc2014-12-17 12:34:40 -0500771 ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jones6053a522014-07-25 16:22:09 -0700772
773 if (isImmutable())
774 {
775 return true;
776 }
777
Geoff Langa9be0dc2014-12-17 12:34:40 -0500778 size_t width = getWidth(GL_TEXTURE_2D_ARRAY, level);
779 size_t height = getHeight(GL_TEXTURE_2D_ARRAY, level);
780 size_t layers = getDepth(GL_TEXTURE_2D_ARRAY, 0);
781 if (width == 0 || height == 0 || layers == 0)
Brandon Jones6053a522014-07-25 16:22:09 -0700782 {
783 return false;
784 }
785
786 if (level == 0)
787 {
788 return true;
789 }
790
Geoff Langa9be0dc2014-12-17 12:34:40 -0500791 if (getInternalFormat(GL_TEXTURE_2D_ARRAY, level) != getInternalFormat(GL_TEXTURE_2D_ARRAY, 0))
Brandon Jones6053a522014-07-25 16:22:09 -0700792 {
793 return false;
794 }
795
Geoff Langa9be0dc2014-12-17 12:34:40 -0500796 if (getWidth(GL_TEXTURE_2D_ARRAY, level) != std::max<size_t>(1, width >> level))
Brandon Jones6053a522014-07-25 16:22:09 -0700797 {
798 return false;
799 }
800
Geoff Langa9be0dc2014-12-17 12:34:40 -0500801 if (getHeight(GL_TEXTURE_2D_ARRAY, level) != std::max<size_t>(1, height >> level))
Brandon Jones6053a522014-07-25 16:22:09 -0700802 {
803 return false;
804 }
805
Geoff Langa9be0dc2014-12-17 12:34:40 -0500806 if (getDepth(GL_TEXTURE_2D_ARRAY, level) != layers)
Brandon Jones6053a522014-07-25 16:22:09 -0700807 {
808 return false;
809 }
810
811 return true;
812}
813
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000814}