blob: e1e9d5d0f5210b97b6bc6483f81f6390ec557f9f [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),
Brandon Jonesf47bebc2014-07-09 14:28:42 -070057 mTarget(target)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000058{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000059}
60
61Texture::~Texture()
62{
Brandon Jones6053a522014-07-25 16:22:09 -070063 SafeDelete(mTexture);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000064}
65
Geoff Lang4907f2c2013-07-25 12:53:57 -040066GLenum Texture::getTarget() const
67{
68 return mTarget;
69}
70
Geoff Lang63b5f1f2013-09-23 14:52:14 -040071void Texture::setUsage(GLenum usage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000072{
Geoff Lang63b5f1f2013-09-23 14:52:14 -040073 mUsage = usage;
Brandon Jonescef06ff2014-08-05 13:27:48 -070074 getImplementation()->setUsage(usage);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000075}
76
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000077GLenum Texture::getUsage() const
78{
79 return mUsage;
80}
81
Geoff Langa9be0dc2014-12-17 12:34:40 -050082size_t Texture::getWidth(GLenum target, size_t level) const
Jamie Madilld3d2a342013-10-07 10:46:35 -040083{
Geoff Langa9be0dc2014-12-17 12:34:40 -050084 ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubemapTextureTarget(target)));
85 return getImageDesc(ImageIdentifier(target, level)).size.width;
Jamie Madilld3d2a342013-10-07 10:46:35 -040086}
87
Geoff Langa9be0dc2014-12-17 12:34:40 -050088size_t Texture::getHeight(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.height;
Jamie Madilld3d2a342013-10-07 10:46:35 -040092}
93
Geoff Langa9be0dc2014-12-17 12:34:40 -050094size_t Texture::getDepth(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.depth;
Jamie Madilld3d2a342013-10-07 10:46:35 -040098}
99
Geoff Langa9be0dc2014-12-17 12:34:40 -0500100GLenum Texture::getInternalFormat(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)).internalFormat;
Jamie Madill945f7322014-09-03 15:07:14 -0400104}
105
Jamie Madill10ef2152014-10-20 17:04:34 -0400106unsigned int Texture::getTextureSerial() const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700107{
Jamie Madill10ef2152014-10-20 17:04:34 -0400108 return mTextureSerial;
109}
110
111unsigned int Texture::issueTextureSerial()
112{
113 return mCurrentTextureSerial++;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700114}
115
116bool Texture::isImmutable() const
117{
Jamie Madill6948e302014-10-20 17:04:33 -0400118 return (mImmutableLevelCount > 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700119}
120
121int Texture::immutableLevelCount()
122{
Jamie Madill6948e302014-10-20 17:04:33 -0400123 return mImmutableLevelCount;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700124}
125
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500126Error Texture::setImage(GLenum target, size_t level, GLenum internalFormat, const Extents &size, GLenum format, GLenum type,
127 const PixelUnpackState &unpack, const uint8_t *pixels)
128{
129 ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubemapTextureTarget(target)));
130
131 Error error = mTexture->setImage(target, level, internalFormat, size, format, type, unpack, pixels);
132 if (error.isError())
133 {
134 return error;
135 }
136
Geoff Langa9be0dc2014-12-17 12:34:40 -0500137 setImageDesc(ImageIdentifier(target, level), ImageDesc(size, GetSizedInternalFormat(internalFormat, type)));
138
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500139 return Error(GL_NO_ERROR);
140}
141
142Error Texture::setSubImage(GLenum target, size_t level, const Box &area, GLenum format, GLenum type,
143 const PixelUnpackState &unpack, const uint8_t *pixels)
144{
145 ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubemapTextureTarget(target)));
146
147 return mTexture->setSubImage(target, level, area, format, type, unpack, pixels);
148}
149
150Error Texture::setCompressedImage(GLenum target, size_t level, GLenum internalFormat, const Extents &size,
151 const PixelUnpackState &unpack, const uint8_t *pixels)
152{
153 ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubemapTextureTarget(target)));
154
155 Error error = mTexture->setCompressedImage(target, level, internalFormat, size, unpack, pixels);
156 if (error.isError())
157 {
158 return error;
159 }
160
Geoff Langa9be0dc2014-12-17 12:34:40 -0500161 setImageDesc(ImageIdentifier(target, level), ImageDesc(size, GetSizedInternalFormat(internalFormat, GL_UNSIGNED_BYTE)));
162
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500163 return Error(GL_NO_ERROR);
164}
165
166Error Texture::setCompressedSubImage(GLenum target, size_t level, const Box &area, GLenum format,
167 const PixelUnpackState &unpack, const uint8_t *pixels)
168{
169 ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubemapTextureTarget(target)));
170
171 return mTexture->setCompressedSubImage(target, level, area, format, unpack, pixels);
172}
173
174Error Texture::copyImage(GLenum target, size_t level, const Rectangle &sourceArea, GLenum internalFormat,
175 const Framebuffer *source)
176{
177 ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubemapTextureTarget(target)));
178
179 Error error = mTexture->copyImage(target, level, sourceArea, internalFormat, source);
180 if (error.isError())
181 {
182 return error;
183 }
184
Geoff Langa9be0dc2014-12-17 12:34:40 -0500185 setImageDesc(ImageIdentifier(target, level), ImageDesc(Extents(sourceArea.width, sourceArea.height, 1),
186 GetSizedInternalFormat(internalFormat, GL_UNSIGNED_BYTE)));
187
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500188 return Error(GL_NO_ERROR);
189}
190
191Error Texture::copySubImage(GLenum target, size_t level, const Offset &destOffset, const Rectangle &sourceArea,
192 const Framebuffer *source)
193{
194 ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubemapTextureTarget(target)));
195
196 return mTexture->copySubImage(target, level, destOffset, sourceArea, source);
197}
198
199Error Texture::setStorage(GLenum target, size_t levels, GLenum internalFormat, const Extents &size)
200{
201 ASSERT(target == mTarget);
202
203 Error error = mTexture->setStorage(target, levels, internalFormat, size);
204 if (error.isError())
205 {
206 return error;
207 }
208
209 mImmutableLevelCount = levels;
Geoff Langa9be0dc2014-12-17 12:34:40 -0500210 clearImageDescs();
211 setImageDescChain(levels, size, internalFormat);
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500212
213 return Error(GL_NO_ERROR);
214}
215
216
217Error Texture::generateMipmaps()
218{
219 Error error = mTexture->generateMipmaps();
220 if (error.isError())
221 {
222 return error;
223 }
224
Geoff Langa9be0dc2014-12-17 12:34:40 -0500225 ImageIdentifier baseLevel(mTarget == GL_TEXTURE_CUBE_MAP ? GL_TEXTURE_CUBE_MAP_POSITIVE_X : mTarget, 0);
226 const ImageDesc &baseImageInfo = getImageDesc(baseLevel);
227 size_t mipLevels = log2(std::max(std::max(baseImageInfo.size.width, baseImageInfo.size.height), baseImageInfo.size.depth)) + 1;
228 setImageDescChain(mipLevels, baseImageInfo.size, baseImageInfo.internalFormat);
229
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500230 return Error(GL_NO_ERROR);
231}
232
Geoff Langa9be0dc2014-12-17 12:34:40 -0500233void Texture::setImageDescChain(size_t levels, Extents baseSize, GLenum sizedInternalFormat)
234{
235 for (size_t level = 0; level < levels; level++)
236 {
237 Extents levelSize(std::max<size_t>(baseSize.width >> level, 1),
238 std::max<size_t>(baseSize.height >> level, 1),
239 (mTarget == GL_TEXTURE_2D_ARRAY) ? baseSize.depth : std::max<size_t>(baseSize.depth >> level, 1));
240 ImageDesc levelInfo(levelSize, sizedInternalFormat);
241
242 if (mTarget == GL_TEXTURE_CUBE_MAP)
243 {
244 for (size_t face = GL_TEXTURE_CUBE_MAP_POSITIVE_X; face <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z; face++)
245 {
246 setImageDesc(ImageIdentifier(face, level), levelInfo);
247 }
248 }
249 else
250 {
251 setImageDesc(ImageIdentifier(mTarget, level), levelInfo);
252 }
253 }
254}
255
256Texture::ImageIdentifier::ImageIdentifier()
257 : ImageIdentifier(GL_TEXTURE_2D, 0)
258{
259}
260
261Texture::ImageIdentifier::ImageIdentifier(GLenum target, size_t level)
262 : target(target),
263 level(level)
264{
265}
266
267bool Texture::ImageIdentifier::operator<(const ImageIdentifier &other) const
268{
269 return (target != other.target) ? target < other.target : level < other.level;
270}
271
272Texture::ImageDesc::ImageDesc()
273 : ImageDesc(Extents(0, 0, 0), GL_NONE)
274{
275}
276
277Texture::ImageDesc::ImageDesc(const Extents &size, GLenum internalFormat)
278 : size(size),
279 internalFormat(internalFormat)
280{
281}
282
283const Texture::ImageDesc &Texture::getImageDesc(const ImageIdentifier& index) const
284{
285 static const Texture::ImageDesc defaultDesc;
286 ImageDescMap::const_iterator iter = mImageDescs.find(index);
287 return (iter != mImageDescs.end()) ? iter->second : defaultDesc;
288}
289
290void Texture::setImageDesc(const ImageIdentifier& index, const ImageDesc &desc)
291{
292 mImageDescs[index] = desc;
293}
294
295void Texture::clearImageDescs()
296{
297 mImageDescs.clear();
298}
299
Brandon Jones6053a522014-07-25 16:22:09 -0700300Texture2D::Texture2D(rx::TextureImpl *impl, GLuint id)
301 : Texture(impl, id, GL_TEXTURE_2D)
Jamie Madill22f843a2013-10-24 17:49:36 -0400302{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000303 mSurface = NULL;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000304}
305
306Texture2D::~Texture2D()
307{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000308 if (mSurface)
309 {
Jamie Madillfb0580a2014-11-27 14:03:52 -0500310 mSurface->releaseTexImage(EGL_BACK_BUFFER);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000311 mSurface = NULL;
312 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700313}
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000314
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500315Error Texture2D::setImage(GLenum target, size_t level, GLenum internalFormat, const Extents &size, GLenum format, GLenum type,
316 const PixelUnpackState &unpack, const uint8_t *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000317{
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500318 Error error = Texture::setImage(target, level, internalFormat, size, format, type, unpack, pixels);
319 if (error.isError())
320 {
321 return error;
322 }
323
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000324 releaseTexImage();
shannon.woods@transgaming.com8a406682013-02-28 23:15:26 +0000325
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500326 return Error(GL_NO_ERROR);
327}
328
329Error Texture2D::setCompressedImage(GLenum target, size_t level, GLenum internalFormat, const Extents &size,
330 const PixelUnpackState &unpack, const uint8_t *pixels)
331{
332 Error error = Texture::setCompressedImage(target, level, internalFormat, size, unpack, pixels);
333 if (error.isError())
334 {
335 return error;
336 }
337
338 releaseTexImage();
339
340 return Error(GL_NO_ERROR);
341}
342
343Error Texture2D::copyImage(GLenum target, size_t level, const Rectangle &sourceArea, GLenum internalFormat,
344 const Framebuffer *source)
345{
346 Error error = Texture::copyImage(target, level, sourceArea, internalFormat, source);
347 if (error.isError())
348 {
349 return error;
350 }
351
352 releaseTexImage();
353
354 return Error(GL_NO_ERROR);
355}
356
357Error Texture2D::setStorage(GLenum target, size_t levels, GLenum internalFormat, const Extents &size)
358{
359 Error error = Texture::setStorage(target, levels, internalFormat, size);
360 if (error.isError())
361 {
362 return error;
363 }
364
365 releaseTexImage();
366
367 return Error(GL_NO_ERROR);
368}
369
370Error Texture2D::generateMipmaps()
371{
372 Error error = Texture::generateMipmaps();
373 if (error.isError())
374 {
375 return error;
376 }
377
378 releaseTexImage();
379
380 return Error(GL_NO_ERROR);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000381}
382
383void Texture2D::bindTexImage(egl::Surface *surface)
384{
385 releaseTexImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700386 mTexture->bindTexImage(surface);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000387 mSurface = surface;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000388}
389
390void Texture2D::releaseTexImage()
391{
392 if (mSurface)
393 {
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000394 mSurface = NULL;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700395 mTexture->releaseTexImage();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000396 }
397}
398
Brandon Jones6053a522014-07-25 16:22:09 -0700399// Tests for 2D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85.
Geoff Langf4134d22014-12-15 10:29:47 -0500400bool Texture2D::isSamplerComplete(const SamplerState &samplerState, const Data &data) const
Brandon Jones6053a522014-07-25 16:22:09 -0700401{
Geoff Langa9be0dc2014-12-17 12:34:40 -0500402 size_t width = getWidth(GL_TEXTURE_2D, 0);
403 size_t height = getHeight(GL_TEXTURE_2D, 0);
404 if (width == 0 || height == 0)
Brandon Jones6053a522014-07-25 16:22:09 -0700405 {
406 return false;
407 }
408
Geoff Langa9be0dc2014-12-17 12:34:40 -0500409 GLenum internalFormat = getInternalFormat(GL_TEXTURE_2D, 0);
410 if (!data.textureCaps->get(internalFormat).filterable && !IsPointSampled(samplerState))
Brandon Jones6053a522014-07-25 16:22:09 -0700411 {
412 return false;
413 }
414
Geoff Langf4134d22014-12-15 10:29:47 -0500415 bool npotSupport = data.extensions->textureNPOT;
Brandon Jones6053a522014-07-25 16:22:09 -0700416 if (!npotSupport)
417 {
418 if ((samplerState.wrapS != GL_CLAMP_TO_EDGE && !gl::isPow2(width)) ||
419 (samplerState.wrapT != GL_CLAMP_TO_EDGE && !gl::isPow2(height)))
420 {
421 return false;
422 }
423 }
424
425 if (IsMipmapFiltered(samplerState))
426 {
427 if (!npotSupport)
428 {
429 if (!gl::isPow2(width) || !gl::isPow2(height))
430 {
431 return false;
432 }
433 }
434
435 if (!isMipmapComplete())
436 {
437 return false;
438 }
439 }
440
441 // OpenGLES 3.0.2 spec section 3.8.13 states that a texture is not mipmap complete if:
442 // The internalformat specified for the texture arrays is a sized internal depth or
443 // depth and stencil format (see table 3.13), the value of TEXTURE_COMPARE_-
444 // MODE is NONE, and either the magnification filter is not NEAREST or the mini-
445 // fication filter is neither NEAREST nor NEAREST_MIPMAP_NEAREST.
Geoff Langa9be0dc2014-12-17 12:34:40 -0500446 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat);
Geoff Langf4134d22014-12-15 10:29:47 -0500447 if (formatInfo.depthBits > 0 && data.clientVersion > 2)
Brandon Jones6053a522014-07-25 16:22:09 -0700448 {
449 if (samplerState.compareMode == GL_NONE)
450 {
451 if ((samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST) ||
452 samplerState.magFilter != GL_NEAREST)
453 {
454 return false;
455 }
456 }
457 }
458
459 return true;
460}
461
Brandon Jones6053a522014-07-25 16:22:09 -0700462// Tests for 2D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
463bool Texture2D::isMipmapComplete() const
464{
Geoff Langa9be0dc2014-12-17 12:34:40 -0500465 size_t width = getWidth(GL_TEXTURE_2D, 0);
466 size_t height = getHeight(GL_TEXTURE_2D, 0);
Brandon Jones6053a522014-07-25 16:22:09 -0700467
Geoff Langa9be0dc2014-12-17 12:34:40 -0500468 size_t expectedMipLevels = log2(std::max(width, height)) + 1;
469 for (size_t level = 0; level < expectedMipLevels; level++)
Brandon Jones6053a522014-07-25 16:22:09 -0700470 {
471 if (!isLevelComplete(level))
472 {
473 return false;
474 }
475 }
476
477 return true;
478}
479
Geoff Langa9be0dc2014-12-17 12:34:40 -0500480bool Texture2D::isLevelComplete(size_t level) const
Brandon Jones6053a522014-07-25 16:22:09 -0700481{
Geoff Langa9be0dc2014-12-17 12:34:40 -0500482 ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
483
Brandon Jones6053a522014-07-25 16:22:09 -0700484 if (isImmutable())
485 {
486 return true;
487 }
488
Geoff Langa9be0dc2014-12-17 12:34:40 -0500489 size_t width = getWidth(GL_TEXTURE_2D, 0);
490 size_t height = getHeight(GL_TEXTURE_2D, 0);
491 if (width == 0 || height == 0)
Brandon Jones6053a522014-07-25 16:22:09 -0700492 {
493 return false;
494 }
495
496 // The base image level is complete if the width and height are positive
497 if (level == 0)
498 {
499 return true;
500 }
501
Geoff Langa9be0dc2014-12-17 12:34:40 -0500502 if (getInternalFormat(GL_TEXTURE_2D, level) != getInternalFormat(GL_TEXTURE_2D, 0))
Brandon Jones6053a522014-07-25 16:22:09 -0700503 {
504 return false;
505 }
506
Geoff Langa9be0dc2014-12-17 12:34:40 -0500507 if (getWidth(GL_TEXTURE_2D, level) != std::max<size_t>(1, width >> level))
Brandon Jones6053a522014-07-25 16:22:09 -0700508 {
509 return false;
510 }
511
Geoff Langa9be0dc2014-12-17 12:34:40 -0500512 if (getHeight(GL_TEXTURE_2D, level) != std::max<size_t>(1, height >> level))
Brandon Jones6053a522014-07-25 16:22:09 -0700513 {
514 return false;
515 }
516
517 return true;
518}
519
520TextureCubeMap::TextureCubeMap(rx::TextureImpl *impl, GLuint id)
521 : Texture(impl, id, GL_TEXTURE_CUBE_MAP)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000522{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000523}
524
525TextureCubeMap::~TextureCubeMap()
526{
Brandon Jones0511e802014-07-14 16:27:26 -0700527}
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000528
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000529// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
530bool TextureCubeMap::isCubeComplete() const
531{
Geoff Langa9be0dc2014-12-17 12:34:40 -0500532 size_t width = getWidth(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0);
533 size_t height = getWidth(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0);
534 if (width == 0 || width != height)
Brandon Jones6053a522014-07-25 16:22:09 -0700535 {
536 return false;
537 }
538
Geoff Langa9be0dc2014-12-17 12:34:40 -0500539 GLenum internalFormat = getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0);
540 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 -0700541 {
Geoff Langa9be0dc2014-12-17 12:34:40 -0500542 if (getWidth(face, 0) != width ||
543 getHeight(face, 0) != height ||
544 getInternalFormat(face, 0) != internalFormat)
Brandon Jones6053a522014-07-25 16:22:09 -0700545 {
546 return false;
547 }
548 }
549
550 return true;
Jamie Madill07edd442013-07-19 16:36:58 -0400551}
552
Brandon Jones6053a522014-07-25 16:22:09 -0700553// Tests for texture sampling completeness
Geoff Langf4134d22014-12-15 10:29:47 -0500554bool TextureCubeMap::isSamplerComplete(const SamplerState &samplerState, const Data &data) const
Brandon Jones6053a522014-07-25 16:22:09 -0700555{
Brandon Jones6053a522014-07-25 16:22:09 -0700556 bool mipmapping = IsMipmapFiltered(samplerState);
557
Geoff Langa9be0dc2014-12-17 12:34:40 -0500558 GLenum internalFormat = getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0);
559 if (!data.textureCaps->get(internalFormat).filterable && !IsPointSampled(samplerState))
Brandon Jones6053a522014-07-25 16:22:09 -0700560 {
561 return false;
562 }
563
Geoff Langa9be0dc2014-12-17 12:34:40 -0500564 size_t size = getWidth(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0);
Geoff Langf4134d22014-12-15 10:29:47 -0500565 if (!gl::isPow2(size) && !data.extensions->textureNPOT)
Brandon Jones6053a522014-07-25 16:22:09 -0700566 {
567 if (samplerState.wrapS != GL_CLAMP_TO_EDGE || samplerState.wrapT != GL_CLAMP_TO_EDGE || mipmapping)
568 {
569 return false;
570 }
571 }
572
573 if (!mipmapping)
574 {
575 if (!isCubeComplete())
576 {
577 return false;
578 }
579 }
580 else
581 {
582 if (!isMipmapComplete()) // Also tests for isCubeComplete()
583 {
584 return false;
585 }
586 }
587
588 return true;
589}
590
Brandon Jonescef06ff2014-08-05 13:27:48 -0700591int TextureCubeMap::targetToLayerIndex(GLenum target)
592{
593 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
594 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
595 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
596 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
597 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
598
599 return target - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
600}
601
602GLenum TextureCubeMap::layerIndexToTarget(GLint layer)
603{
604 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
605 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
606 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
607 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
608 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
609
610 return GL_TEXTURE_CUBE_MAP_POSITIVE_X + layer;
Geoff Lang8040f572013-07-25 16:49:54 -0400611}
612
Brandon Jones6053a522014-07-25 16:22:09 -0700613bool TextureCubeMap::isMipmapComplete() const
614{
615 if (isImmutable())
616 {
617 return true;
618 }
619
620 if (!isCubeComplete())
621 {
622 return false;
623 }
624
Geoff Langa9be0dc2014-12-17 12:34:40 -0500625 size_t width = getWidth(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0);
626 size_t height = getHeight(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0);
Brandon Jones6053a522014-07-25 16:22:09 -0700627
Geoff Langa9be0dc2014-12-17 12:34:40 -0500628 size_t expectedMipLevels = log2(std::max(width, height)) + 1;
629 for (GLenum face = GL_TEXTURE_CUBE_MAP_NEGATIVE_X; face <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z; face++)
Brandon Jones6053a522014-07-25 16:22:09 -0700630 {
Geoff Langa9be0dc2014-12-17 12:34:40 -0500631 for (size_t level = 1; level < expectedMipLevels; level++)
Brandon Jones6053a522014-07-25 16:22:09 -0700632 {
633 if (!isFaceLevelComplete(face, level))
634 {
635 return false;
636 }
637 }
638 }
639
640 return true;
641}
642
Geoff Langa9be0dc2014-12-17 12:34:40 -0500643bool TextureCubeMap::isFaceLevelComplete(GLenum target, size_t level) const
Brandon Jones6053a522014-07-25 16:22:09 -0700644{
Geoff Langa9be0dc2014-12-17 12:34:40 -0500645 ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && IsCubemapTextureTarget(target));
Brandon Jones6053a522014-07-25 16:22:09 -0700646
647 if (isImmutable())
648 {
649 return true;
650 }
651
Geoff Langa9be0dc2014-12-17 12:34:40 -0500652 size_t baseSize = getWidth(target, 0);
653 if (baseSize == 0)
Brandon Jones6053a522014-07-25 16:22:09 -0700654 {
655 return false;
656 }
657
658 // "isCubeComplete" checks for base level completeness and we must call that
659 // to determine if any face at level 0 is complete. We omit that check here
660 // to avoid re-checking cube-completeness for every face at level 0.
661 if (level == 0)
662 {
663 return true;
664 }
665
666 // Check that non-zero levels are consistent with the base level.
Geoff Langa9be0dc2014-12-17 12:34:40 -0500667 if (getInternalFormat(target, level) != getInternalFormat(target, 0))
Brandon Jones6053a522014-07-25 16:22:09 -0700668 {
669 return false;
670 }
671
Geoff Langa9be0dc2014-12-17 12:34:40 -0500672 if (getWidth(target, level) != std::max<size_t>(1, baseSize >> level))
Brandon Jones6053a522014-07-25 16:22:09 -0700673 {
674 return false;
675 }
676
677 return true;
678}
679
680
681Texture3D::Texture3D(rx::TextureImpl *impl, GLuint id)
682 : Texture(impl, id, GL_TEXTURE_3D)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +0000683{
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +0000684}
685
686Texture3D::~Texture3D()
687{
Brandon Jones78b1acd2014-07-15 15:33:07 -0700688}
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +0000689
Geoff Langf4134d22014-12-15 10:29:47 -0500690bool Texture3D::isSamplerComplete(const SamplerState &samplerState, const Data &data) const
Brandon Jones6053a522014-07-25 16:22:09 -0700691{
Geoff Langa9be0dc2014-12-17 12:34:40 -0500692 size_t width = getWidth(GL_TEXTURE_3D, 0);
693 size_t height = getHeight(GL_TEXTURE_3D, 0);
694 size_t depth = getDepth(GL_TEXTURE_3D, 0);
695 if (width == 0 || height == 0 || depth == 0)
Brandon Jones6053a522014-07-25 16:22:09 -0700696 {
697 return false;
698 }
699
Geoff Langa9be0dc2014-12-17 12:34:40 -0500700 GLenum internalFormat = getInternalFormat(GL_TEXTURE_3D, 0);
701 if (!data.textureCaps->get(internalFormat).filterable && !IsPointSampled(samplerState))
Brandon Jones6053a522014-07-25 16:22:09 -0700702 {
703 return false;
704 }
705
706 if (IsMipmapFiltered(samplerState) && !isMipmapComplete())
707 {
708 return false;
709 }
710
711 return true;
712}
713
Brandon Jones6053a522014-07-25 16:22:09 -0700714bool Texture3D::isMipmapComplete() const
715{
Geoff Langa9be0dc2014-12-17 12:34:40 -0500716 size_t width = getWidth(GL_TEXTURE_2D_ARRAY, 0);
717 size_t height = getHeight(GL_TEXTURE_2D_ARRAY, 0);
718 size_t depth = getDepth(GL_TEXTURE_3D, 0);
Brandon Jones6053a522014-07-25 16:22:09 -0700719
Geoff Langa9be0dc2014-12-17 12:34:40 -0500720 size_t expectedMipLevels = log2(std::max(std::max(width, height), depth)) + 1;
721 for (size_t level = 0; level < expectedMipLevels; level++)
Brandon Jones6053a522014-07-25 16:22:09 -0700722 {
723 if (!isLevelComplete(level))
724 {
725 return false;
726 }
727 }
728
729 return true;
730}
731
Geoff Langa9be0dc2014-12-17 12:34:40 -0500732bool Texture3D::isLevelComplete(size_t level) const
Brandon Jones6053a522014-07-25 16:22:09 -0700733{
Geoff Langa9be0dc2014-12-17 12:34:40 -0500734 ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jones6053a522014-07-25 16:22:09 -0700735
736 if (isImmutable())
737 {
738 return true;
739 }
740
Geoff Langa9be0dc2014-12-17 12:34:40 -0500741 size_t width = getWidth(GL_TEXTURE_3D, level);
742 size_t height = getHeight(GL_TEXTURE_3D, level);
743 size_t depth = getDepth(GL_TEXTURE_3D, level);
744 if (width == 0 || height == 0 || depth == 0)
Brandon Jones6053a522014-07-25 16:22:09 -0700745 {
746 return false;
747 }
748
749 if (level == 0)
750 {
751 return true;
752 }
753
Geoff Langa9be0dc2014-12-17 12:34:40 -0500754 if (getInternalFormat(GL_TEXTURE_3D, level) != getInternalFormat(GL_TEXTURE_3D, 0))
Brandon Jones6053a522014-07-25 16:22:09 -0700755 {
756 return false;
757 }
758
Geoff Langa9be0dc2014-12-17 12:34:40 -0500759 if (getWidth(GL_TEXTURE_3D, level) != std::max<size_t>(1, width >> level))
Brandon Jones6053a522014-07-25 16:22:09 -0700760 {
761 return false;
762 }
763
Geoff Langa9be0dc2014-12-17 12:34:40 -0500764 if (getHeight(GL_TEXTURE_3D, level) != std::max<size_t>(1, height >> level))
Brandon Jones6053a522014-07-25 16:22:09 -0700765 {
766 return false;
767 }
768
Geoff Langa9be0dc2014-12-17 12:34:40 -0500769 if (getDepth(GL_TEXTURE_3D, level) != std::max<size_t>(1, depth >> level))
Brandon Jones6053a522014-07-25 16:22:09 -0700770 {
771 return false;
772 }
773
774 return true;
775}
776
777Texture2DArray::Texture2DArray(rx::TextureImpl *impl, GLuint id)
778 : Texture(impl, id, GL_TEXTURE_2D_ARRAY)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +0000779{
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +0000780}
781
782Texture2DArray::~Texture2DArray()
783{
Jamie Madill884a4622013-10-24 17:49:41 -0400784}
785
Geoff Langf4134d22014-12-15 10:29:47 -0500786bool Texture2DArray::isSamplerComplete(const SamplerState &samplerState, const Data &data) const
Brandon Jones6053a522014-07-25 16:22:09 -0700787{
Geoff Langa9be0dc2014-12-17 12:34:40 -0500788 size_t width = getWidth(GL_TEXTURE_2D_ARRAY, 0);
789 size_t height = getHeight(GL_TEXTURE_2D_ARRAY, 0);
790 size_t depth = getDepth(GL_TEXTURE_2D_ARRAY, 0);
791 if (width == 0 || height == 0 || depth == 0)
Brandon Jones6053a522014-07-25 16:22:09 -0700792 {
793 return false;
794 }
795
Geoff Langa9be0dc2014-12-17 12:34:40 -0500796 GLenum internalFormat = getInternalFormat(GL_TEXTURE_2D_ARRAY, 0);
797 if (!data.textureCaps->get(internalFormat).filterable && !IsPointSampled(samplerState))
Brandon Jones6053a522014-07-25 16:22:09 -0700798 {
799 return false;
800 }
801
802 if (IsMipmapFiltered(samplerState) && !isMipmapComplete())
803 {
804 return false;
805 }
806
807 return true;
808}
809
Brandon Jones6053a522014-07-25 16:22:09 -0700810bool Texture2DArray::isMipmapComplete() const
811{
Geoff Langa9be0dc2014-12-17 12:34:40 -0500812 size_t width = getWidth(GL_TEXTURE_2D_ARRAY, 0);
813 size_t height = getHeight(GL_TEXTURE_2D_ARRAY, 0);
Brandon Jones6053a522014-07-25 16:22:09 -0700814
Geoff Langa9be0dc2014-12-17 12:34:40 -0500815 size_t expectedMipLevels = log2(std::max(width, height)) + 1;
816 for (size_t level = 1; level < expectedMipLevels; level++)
Brandon Jones6053a522014-07-25 16:22:09 -0700817 {
818 if (!isLevelComplete(level))
819 {
820 return false;
821 }
822 }
823
824 return true;
825}
826
Geoff Langa9be0dc2014-12-17 12:34:40 -0500827bool Texture2DArray::isLevelComplete(size_t level) const
Brandon Jones6053a522014-07-25 16:22:09 -0700828{
Geoff Langa9be0dc2014-12-17 12:34:40 -0500829 ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jones6053a522014-07-25 16:22:09 -0700830
831 if (isImmutable())
832 {
833 return true;
834 }
835
Geoff Langa9be0dc2014-12-17 12:34:40 -0500836 size_t width = getWidth(GL_TEXTURE_2D_ARRAY, level);
837 size_t height = getHeight(GL_TEXTURE_2D_ARRAY, level);
838 size_t layers = getDepth(GL_TEXTURE_2D_ARRAY, 0);
839 if (width == 0 || height == 0 || layers == 0)
Brandon Jones6053a522014-07-25 16:22:09 -0700840 {
841 return false;
842 }
843
844 if (level == 0)
845 {
846 return true;
847 }
848
Geoff Langa9be0dc2014-12-17 12:34:40 -0500849 if (getInternalFormat(GL_TEXTURE_2D_ARRAY, level) != getInternalFormat(GL_TEXTURE_2D_ARRAY, 0))
Brandon Jones6053a522014-07-25 16:22:09 -0700850 {
851 return false;
852 }
853
Geoff Langa9be0dc2014-12-17 12:34:40 -0500854 if (getWidth(GL_TEXTURE_2D_ARRAY, level) != std::max<size_t>(1, width >> level))
Brandon Jones6053a522014-07-25 16:22:09 -0700855 {
856 return false;
857 }
858
Geoff Langa9be0dc2014-12-17 12:34:40 -0500859 if (getHeight(GL_TEXTURE_2D_ARRAY, level) != std::max<size_t>(1, height >> level))
Brandon Jones6053a522014-07-25 16:22:09 -0700860 {
861 return false;
862 }
863
Geoff Langa9be0dc2014-12-17 12:34:40 -0500864 if (getDepth(GL_TEXTURE_2D_ARRAY, level) != layers)
Brandon Jones6053a522014-07-25 16:22:09 -0700865 {
866 return false;
867 }
868
869 return true;
870}
871
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000872}