blob: 4d4c32a70c144dd1c24fa193696c8f665f2ccd2c [file] [log] [blame]
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001//
Geoff Langcec35902014-04-16 10:52:36 -04002// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00003// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
Geoff Lang691e58c2014-12-19 17:03:25 -05007// Texture.cpp: Implements the gl::Texture class. [OpenGL ES 2.0.24] section 3.7 page 63.
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00008
Geoff Lang2b5420c2014-11-19 14:20:15 -05009#include "libANGLE/Texture.h"
Geoff Lang0b7eef72014-06-12 14:10:47 -040010
11#include "common/mathutil.h"
12#include "common/utilities.h"
Jamie Madill79481d62015-04-14 08:13:47 -040013#include "libANGLE/Config.h"
14#include "libANGLE/Data.h"
15#include "libANGLE/Surface.h"
16#include "libANGLE/formatutils.h"
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000017
18namespace gl
19{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000020
Brandon Jones6053a522014-07-25 16:22:09 -070021bool IsMipmapFiltered(const gl::SamplerState &samplerState)
22{
23 switch (samplerState.minFilter)
24 {
25 case GL_NEAREST:
26 case GL_LINEAR:
27 return false;
28 case GL_NEAREST_MIPMAP_NEAREST:
29 case GL_LINEAR_MIPMAP_NEAREST:
30 case GL_NEAREST_MIPMAP_LINEAR:
31 case GL_LINEAR_MIPMAP_LINEAR:
32 return true;
33 default: UNREACHABLE();
34 return false;
35 }
36}
37
38bool IsPointSampled(const gl::SamplerState &samplerState)
39{
40 return (samplerState.magFilter == GL_NEAREST && (samplerState.minFilter == GL_NEAREST || samplerState.minFilter == GL_NEAREST_MIPMAP_NEAREST));
41}
42
Geoff Lang866dd2d2015-02-10 11:08:32 -050043static size_t GetImageDescIndex(GLenum target, size_t level)
44{
45 return IsCubeMapTextureTarget(target) ? ((level * 6) + CubeMapTextureTargetToLayerIndex(target)) : level;
46}
47
Brandon Jones6053a522014-07-25 16:22:09 -070048Texture::Texture(rx::TextureImpl *impl, GLuint id, GLenum target)
Jamie Madill79481d62015-04-14 08:13:47 -040049 : FramebufferAttachmentObject(id),
Brandon Jones6053a522014-07-25 16:22:09 -070050 mTexture(impl),
Brandon Jonesf47bebc2014-07-09 14:28:42 -070051 mUsage(GL_NONE),
Jamie Madill6948e302014-10-20 17:04:33 -040052 mImmutableLevelCount(0),
Geoff Lang7c973ea2014-12-19 15:58:28 -050053 mTarget(target),
Geoff Lang866dd2d2015-02-10 11:08:32 -050054 mImageDescs(IMPLEMENTATION_MAX_TEXTURE_LEVELS * (target == GL_TEXTURE_CUBE_MAP ? 6 : 1)),
Geoff Lang0fe40532015-02-10 12:01:27 -050055 mCompletenessCache(),
Geoff Lang7c973ea2014-12-19 15:58:28 -050056 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 Lang866dd2d2015-02-10 11:08:32 -050089 return getImageDesc(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 Lang866dd2d2015-02-10 11:08:32 -050095 return getImageDesc(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 Lang866dd2d2015-02-10 11:08:32 -0500101 return getImageDesc(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 Lang866dd2d2015-02-10 11:08:32 -0500107 return getImageDesc(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{
Geoff Langb0eecdf2015-02-10 11:09:12 -0500112 const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), samplerState.baseLevel);
Geoff Langb0eecdf2015-02-10 11:09:12 -0500113 const TextureCaps &textureCaps = data.textureCaps->get(baseImageDesc.internalFormat);
Geoff Lang0fe40532015-02-10 12:01:27 -0500114 if (!mCompletenessCache.cacheValid ||
115 mCompletenessCache.samplerState != samplerState ||
116 mCompletenessCache.filterable != textureCaps.filterable ||
117 mCompletenessCache.clientVersion != data.clientVersion ||
118 mCompletenessCache.supportsNPOT != data.extensions->textureNPOT)
Geoff Lang691e58c2014-12-19 17:03:25 -0500119 {
Geoff Lang0fe40532015-02-10 12:01:27 -0500120 mCompletenessCache.cacheValid = true;
121 mCompletenessCache.samplerState = samplerState;
122 mCompletenessCache.filterable = textureCaps.filterable;
123 mCompletenessCache.clientVersion = data.clientVersion;
124 mCompletenessCache.supportsNPOT = data.extensions->textureNPOT;
125 mCompletenessCache.samplerComplete = computeSamplerCompleteness(samplerState, data);
Geoff Lang691e58c2014-12-19 17:03:25 -0500126 }
Geoff Lang0fe40532015-02-10 12:01:27 -0500127 return mCompletenessCache.samplerComplete;
Geoff Lang691e58c2014-12-19 17:03:25 -0500128}
129
130// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
131bool Texture::isCubeComplete() const
132{
133 ASSERT(mTarget == GL_TEXTURE_CUBE_MAP);
134
Geoff Langb0eecdf2015-02-10 11:09:12 -0500135 const ImageDesc &baseImageDesc = getImageDesc(FirstCubeMapTextureTarget, 0);
136 if (baseImageDesc.size.width == 0 || baseImageDesc.size.width != baseImageDesc.size.height)
Geoff Lang691e58c2014-12-19 17:03:25 -0500137 {
138 return false;
139 }
140
Geoff Langb0eecdf2015-02-10 11:09:12 -0500141 for (GLenum face = FirstCubeMapTextureTarget + 1; face <= LastCubeMapTextureTarget; face++)
Geoff Lang691e58c2014-12-19 17:03:25 -0500142 {
Geoff Langb0eecdf2015-02-10 11:09:12 -0500143 const ImageDesc &faceImageDesc = getImageDesc(face, 0);
144 if (faceImageDesc.size.width != baseImageDesc.size.width ||
145 faceImageDesc.size.height != baseImageDesc.size.height ||
146 faceImageDesc.internalFormat != baseImageDesc.internalFormat)
Geoff Lang691e58c2014-12-19 17:03:25 -0500147 {
148 return false;
149 }
150 }
151
152 return true;
153}
154
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700155bool Texture::isImmutable() const
156{
Jamie Madill6948e302014-10-20 17:04:33 -0400157 return (mImmutableLevelCount > 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700158}
159
160int Texture::immutableLevelCount()
161{
Jamie Madill6948e302014-10-20 17:04:33 -0400162 return mImmutableLevelCount;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700163}
164
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500165Error Texture::setImage(GLenum target, size_t level, GLenum internalFormat, const Extents &size, GLenum format, GLenum type,
166 const PixelUnpackState &unpack, const uint8_t *pixels)
167{
Geoff Lang691e58c2014-12-19 17:03:25 -0500168 ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500169
Jamie Madillbb714f72015-05-20 10:22:18 -0400170 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
171 releaseTexImageInternal();
172
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500173 Error error = mTexture->setImage(target, level, internalFormat, size, format, type, unpack, pixels);
174 if (error.isError())
175 {
176 return error;
177 }
178
Geoff Lang866dd2d2015-02-10 11:08:32 -0500179 setImageDesc(target, level, ImageDesc(size, GetSizedInternalFormat(internalFormat, type)));
Geoff Langa9be0dc2014-12-17 12:34:40 -0500180
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500181 return Error(GL_NO_ERROR);
182}
183
184Error Texture::setSubImage(GLenum target, size_t level, const Box &area, GLenum format, GLenum type,
185 const PixelUnpackState &unpack, const uint8_t *pixels)
186{
Geoff Lang691e58c2014-12-19 17:03:25 -0500187 ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500188
189 return mTexture->setSubImage(target, level, area, format, type, unpack, pixels);
190}
191
192Error Texture::setCompressedImage(GLenum target, size_t level, GLenum internalFormat, const Extents &size,
193 const PixelUnpackState &unpack, const uint8_t *pixels)
194{
Geoff Lang691e58c2014-12-19 17:03:25 -0500195 ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500196
Jamie Madillbb714f72015-05-20 10:22:18 -0400197 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
198 releaseTexImageInternal();
199
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500200 Error error = mTexture->setCompressedImage(target, level, internalFormat, size, unpack, pixels);
201 if (error.isError())
202 {
203 return error;
204 }
205
Geoff Lang866dd2d2015-02-10 11:08:32 -0500206 setImageDesc(target, level, ImageDesc(size, GetSizedInternalFormat(internalFormat, GL_UNSIGNED_BYTE)));
Geoff Langa9be0dc2014-12-17 12:34:40 -0500207
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500208 return Error(GL_NO_ERROR);
209}
210
211Error Texture::setCompressedSubImage(GLenum target, size_t level, const Box &area, GLenum format,
212 const PixelUnpackState &unpack, const uint8_t *pixels)
213{
Geoff Lang691e58c2014-12-19 17:03:25 -0500214 ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500215
216 return mTexture->setCompressedSubImage(target, level, area, format, unpack, pixels);
217}
218
219Error Texture::copyImage(GLenum target, size_t level, const Rectangle &sourceArea, GLenum internalFormat,
220 const Framebuffer *source)
221{
Geoff Lang691e58c2014-12-19 17:03:25 -0500222 ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500223
Jamie Madillbb714f72015-05-20 10:22:18 -0400224 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
225 releaseTexImageInternal();
226
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500227 Error error = mTexture->copyImage(target, level, sourceArea, internalFormat, source);
228 if (error.isError())
229 {
230 return error;
231 }
232
Geoff Lang866dd2d2015-02-10 11:08:32 -0500233 setImageDesc(target, level, ImageDesc(Extents(sourceArea.width, sourceArea.height, 1),
234 GetSizedInternalFormat(internalFormat, GL_UNSIGNED_BYTE)));
Geoff Langa9be0dc2014-12-17 12:34:40 -0500235
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500236 return Error(GL_NO_ERROR);
237}
238
239Error Texture::copySubImage(GLenum target, size_t level, const Offset &destOffset, const Rectangle &sourceArea,
240 const Framebuffer *source)
241{
Geoff Lang691e58c2014-12-19 17:03:25 -0500242 ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500243
244 return mTexture->copySubImage(target, level, destOffset, sourceArea, source);
245}
246
247Error Texture::setStorage(GLenum target, size_t levels, GLenum internalFormat, const Extents &size)
248{
249 ASSERT(target == mTarget);
250
Jamie Madillbb714f72015-05-20 10:22:18 -0400251 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
252 releaseTexImageInternal();
253
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500254 Error error = mTexture->setStorage(target, levels, internalFormat, size);
255 if (error.isError())
256 {
257 return error;
258 }
259
260 mImmutableLevelCount = levels;
Geoff Langa9be0dc2014-12-17 12:34:40 -0500261 clearImageDescs();
262 setImageDescChain(levels, size, internalFormat);
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500263
264 return Error(GL_NO_ERROR);
265}
266
267
268Error Texture::generateMipmaps()
269{
Jamie Madillbb714f72015-05-20 10:22:18 -0400270 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
271 releaseTexImageInternal();
272
Gregoire Payen de La Garanderie752ce192015-04-14 11:11:12 +0100273 Error error = mTexture->generateMipmaps(getSamplerState());
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500274 if (error.isError())
275 {
276 return error;
277 }
278
Geoff Lang866dd2d2015-02-10 11:08:32 -0500279 const ImageDesc &baseImageInfo = getImageDesc(getBaseImageTarget(), 0);
Geoff Langa9be0dc2014-12-17 12:34:40 -0500280 size_t mipLevels = log2(std::max(std::max(baseImageInfo.size.width, baseImageInfo.size.height), baseImageInfo.size.depth)) + 1;
281 setImageDescChain(mipLevels, baseImageInfo.size, baseImageInfo.internalFormat);
282
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500283 return Error(GL_NO_ERROR);
284}
285
Geoff Langa9be0dc2014-12-17 12:34:40 -0500286void Texture::setImageDescChain(size_t levels, Extents baseSize, GLenum sizedInternalFormat)
287{
288 for (size_t level = 0; level < levels; level++)
289 {
290 Extents levelSize(std::max<size_t>(baseSize.width >> level, 1),
291 std::max<size_t>(baseSize.height >> level, 1),
292 (mTarget == GL_TEXTURE_2D_ARRAY) ? baseSize.depth : std::max<size_t>(baseSize.depth >> level, 1));
293 ImageDesc levelInfo(levelSize, sizedInternalFormat);
294
295 if (mTarget == GL_TEXTURE_CUBE_MAP)
296 {
Geoff Lang691e58c2014-12-19 17:03:25 -0500297 for (size_t face = FirstCubeMapTextureTarget; face <= LastCubeMapTextureTarget; face++)
Geoff Langa9be0dc2014-12-17 12:34:40 -0500298 {
Geoff Lang866dd2d2015-02-10 11:08:32 -0500299 setImageDesc(face, level, levelInfo);
Geoff Langa9be0dc2014-12-17 12:34:40 -0500300 }
301 }
302 else
303 {
Geoff Lang866dd2d2015-02-10 11:08:32 -0500304 setImageDesc(mTarget, level, levelInfo);
Geoff Langa9be0dc2014-12-17 12:34:40 -0500305 }
306 }
307}
308
Geoff Langa9be0dc2014-12-17 12:34:40 -0500309Texture::ImageDesc::ImageDesc()
310 : ImageDesc(Extents(0, 0, 0), GL_NONE)
311{
312}
313
314Texture::ImageDesc::ImageDesc(const Extents &size, GLenum internalFormat)
315 : size(size),
316 internalFormat(internalFormat)
317{
318}
319
Geoff Lang866dd2d2015-02-10 11:08:32 -0500320const Texture::ImageDesc &Texture::getImageDesc(GLenum target, size_t level) const
Geoff Langa9be0dc2014-12-17 12:34:40 -0500321{
Geoff Lang866dd2d2015-02-10 11:08:32 -0500322 size_t descIndex = GetImageDescIndex(target, level);
323 ASSERT(descIndex < mImageDescs.size());
324 return mImageDescs[descIndex];
Geoff Langa9be0dc2014-12-17 12:34:40 -0500325}
326
Geoff Lang866dd2d2015-02-10 11:08:32 -0500327void Texture::setImageDesc(GLenum target, size_t level, const ImageDesc &desc)
Geoff Langa9be0dc2014-12-17 12:34:40 -0500328{
Geoff Lang866dd2d2015-02-10 11:08:32 -0500329 size_t descIndex = GetImageDescIndex(target, level);
330 ASSERT(descIndex < mImageDescs.size());
331 mImageDescs[descIndex] = desc;
Geoff Lang0fe40532015-02-10 12:01:27 -0500332 mCompletenessCache.cacheValid = false;
Geoff Langa9be0dc2014-12-17 12:34:40 -0500333}
334
Geoff Lang866dd2d2015-02-10 11:08:32 -0500335void Texture::clearImageDesc(GLenum target, size_t level)
Geoff Langb9266272015-01-29 13:25:14 +0000336{
Geoff Lang866dd2d2015-02-10 11:08:32 -0500337 setImageDesc(target, level, ImageDesc());
Geoff Langb9266272015-01-29 13:25:14 +0000338}
339
Geoff Langa9be0dc2014-12-17 12:34:40 -0500340void Texture::clearImageDescs()
341{
Geoff Lang866dd2d2015-02-10 11:08:32 -0500342 for (size_t descIndex = 0; descIndex < mImageDescs.size(); descIndex++)
343 {
344 mImageDescs[descIndex] = ImageDesc();
345 }
Geoff Lang0fe40532015-02-10 12:01:27 -0500346 mCompletenessCache.cacheValid = false;
Geoff Langa9be0dc2014-12-17 12:34:40 -0500347}
348
Jamie Madillbb714f72015-05-20 10:22:18 -0400349void Texture::bindTexImageFromSurface(egl::Surface *surface)
Geoff Lang7c973ea2014-12-19 15:58:28 -0500350{
Geoff Langb9266272015-01-29 13:25:14 +0000351 ASSERT(surface);
352
Jamie Madillbb714f72015-05-20 10:22:18 -0400353 if (mBoundSurface)
354 {
355 releaseTexImageFromSurface();
356 }
357
Geoff Lang7c973ea2014-12-19 15:58:28 -0500358 mTexture->bindTexImage(surface);
359 mBoundSurface = surface;
Geoff Langb9266272015-01-29 13:25:14 +0000360
361 // Set the image info to the size and format of the surface
362 ASSERT(mTarget == GL_TEXTURE_2D);
363 Extents size(surface->getWidth(), surface->getHeight(), 1);
Geoff Langc223dc62015-01-09 13:10:01 -0500364 ImageDesc desc(size, surface->getConfig()->renderTargetFormat);
Geoff Lang866dd2d2015-02-10 11:08:32 -0500365 setImageDesc(mTarget, 0, desc);
Geoff Lang7c973ea2014-12-19 15:58:28 -0500366}
367
Jamie Madillbb714f72015-05-20 10:22:18 -0400368void Texture::releaseTexImageFromSurface()
369{
370 ASSERT(mBoundSurface);
371 mBoundSurface = nullptr;
372 mTexture->releaseTexImage();
373
374 // Erase the image info for level 0
375 ASSERT(mTarget == GL_TEXTURE_2D);
376 clearImageDesc(mTarget, 0);
377}
378
379void Texture::releaseTexImageInternal()
Geoff Lang7c973ea2014-12-19 15:58:28 -0500380{
381 if (mBoundSurface)
382 {
Jamie Madillbb714f72015-05-20 10:22:18 -0400383 // Notify the surface
384 mBoundSurface->releaseTexImageFromTexture();
Geoff Langb9266272015-01-29 13:25:14 +0000385
Jamie Madillbb714f72015-05-20 10:22:18 -0400386 // Then, call the same method as from the surface
387 releaseTexImageFromSurface();
Geoff Lang7c973ea2014-12-19 15:58:28 -0500388 }
389}
390
Geoff Lang691e58c2014-12-19 17:03:25 -0500391GLenum Texture::getBaseImageTarget() const
Jamie Madill22f843a2013-10-24 17:49:36 -0400392{
Geoff Lang691e58c2014-12-19 17:03:25 -0500393 return mTarget == GL_TEXTURE_CUBE_MAP ? FirstCubeMapTextureTarget : mTarget;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000394}
395
Geoff Lang691e58c2014-12-19 17:03:25 -0500396size_t Texture::getExpectedMipLevels() const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000397{
Geoff Langb0eecdf2015-02-10 11:09:12 -0500398 const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), 0);
Geoff Lang691e58c2014-12-19 17:03:25 -0500399 if (mTarget == GL_TEXTURE_3D)
400 {
Geoff Langb0eecdf2015-02-10 11:09:12 -0500401 return log2(std::max(std::max(baseImageDesc.size.width, baseImageDesc.size.height), baseImageDesc.size.depth)) + 1;
Geoff Lang691e58c2014-12-19 17:03:25 -0500402 }
403 else
404 {
Geoff Langb0eecdf2015-02-10 11:09:12 -0500405 return log2(std::max(baseImageDesc.size.width, baseImageDesc.size.height)) + 1;
Geoff Lang691e58c2014-12-19 17:03:25 -0500406 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000407}
408
Geoff Lang0fe40532015-02-10 12:01:27 -0500409bool Texture::computeSamplerCompleteness(const SamplerState &samplerState, const Data &data) const
410{
411 const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), samplerState.baseLevel);
412 if (baseImageDesc.size.width == 0 || baseImageDesc.size.height == 0 || baseImageDesc.size.depth == 0)
413 {
414 return false;
415 }
416
417 if (mTarget == GL_TEXTURE_CUBE_MAP && baseImageDesc.size.width != baseImageDesc.size.height)
418 {
419 return false;
420 }
421
422 const TextureCaps &textureCaps = data.textureCaps->get(baseImageDesc.internalFormat);
423 if (!textureCaps.filterable && !IsPointSampled(samplerState))
424 {
425 return false;
426 }
427
428 bool npotSupport = data.extensions->textureNPOT || data.clientVersion >= 3;
429 if (!npotSupport)
430 {
431 if ((samplerState.wrapS != GL_CLAMP_TO_EDGE && !gl::isPow2(baseImageDesc.size.width)) ||
432 (samplerState.wrapT != GL_CLAMP_TO_EDGE && !gl::isPow2(baseImageDesc.size.height)))
433 {
434 return false;
435 }
436 }
437
438 if (IsMipmapFiltered(samplerState))
439 {
440 if (!npotSupport)
441 {
442 if (!gl::isPow2(baseImageDesc.size.width) || !gl::isPow2(baseImageDesc.size.height))
443 {
444 return false;
445 }
446 }
447
448 if (!computeMipmapCompleteness(samplerState))
449 {
450 return false;
451 }
452 }
453 else
454 {
455 if (mTarget == GL_TEXTURE_CUBE_MAP && !isCubeComplete())
456 {
457 return false;
458 }
459 }
460
461 // OpenGLES 3.0.2 spec section 3.8.13 states that a texture is not mipmap complete if:
462 // The internalformat specified for the texture arrays is a sized internal depth or
463 // depth and stencil format (see table 3.13), the value of TEXTURE_COMPARE_-
464 // MODE is NONE, and either the magnification filter is not NEAREST or the mini-
465 // fication filter is neither NEAREST nor NEAREST_MIPMAP_NEAREST.
466 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(baseImageDesc.internalFormat);
467 if (formatInfo.depthBits > 0 && data.clientVersion > 2)
468 {
469 if (samplerState.compareMode == GL_NONE)
470 {
471 if ((samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST) ||
472 samplerState.magFilter != GL_NEAREST)
473 {
474 return false;
475 }
476 }
477 }
478
479 return true;
480}
481
482bool Texture::computeMipmapCompleteness(const gl::SamplerState &samplerState) const
Brandon Jones6053a522014-07-25 16:22:09 -0700483{
Geoff Lang691e58c2014-12-19 17:03:25 -0500484 size_t expectedMipLevels = getExpectedMipLevels();
Jamie Madill19d438d2015-01-19 13:42:12 -0500485
486 size_t maxLevel = std::min<size_t>(expectedMipLevels, samplerState.maxLevel + 1);
487
488 for (size_t level = samplerState.baseLevel; level < maxLevel; level++)
Brandon Jones6053a522014-07-25 16:22:09 -0700489 {
Geoff Lang691e58c2014-12-19 17:03:25 -0500490 if (mTarget == GL_TEXTURE_CUBE_MAP)
Brandon Jones6053a522014-07-25 16:22:09 -0700491 {
Geoff Lang691e58c2014-12-19 17:03:25 -0500492 for (GLenum face = FirstCubeMapTextureTarget; face <= LastCubeMapTextureTarget; face++)
493 {
Geoff Lang0fe40532015-02-10 12:01:27 -0500494 if (!computeLevelCompleteness(face, level, samplerState))
Geoff Lang691e58c2014-12-19 17:03:25 -0500495 {
496 return false;
497 }
498 }
499 }
500 else
501 {
Geoff Lang0fe40532015-02-10 12:01:27 -0500502 if (!computeLevelCompleteness(mTarget, level, samplerState))
Geoff Lang691e58c2014-12-19 17:03:25 -0500503 {
504 return false;
505 }
Brandon Jones6053a522014-07-25 16:22:09 -0700506 }
507 }
508
509 return true;
510}
511
Geoff Lang691e58c2014-12-19 17:03:25 -0500512
Geoff Lang0fe40532015-02-10 12:01:27 -0500513bool Texture::computeLevelCompleteness(GLenum target, size_t level, const gl::SamplerState &samplerState) const
Brandon Jones6053a522014-07-25 16:22:09 -0700514{
Geoff Langa9be0dc2014-12-17 12:34:40 -0500515 ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
516
Brandon Jones6053a522014-07-25 16:22:09 -0700517 if (isImmutable())
518 {
519 return true;
520 }
521
Geoff Langb0eecdf2015-02-10 11:09:12 -0500522 const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), samplerState.baseLevel);
523 if (baseImageDesc.size.width == 0 || baseImageDesc.size.height == 0 || baseImageDesc.size.depth == 0)
Brandon Jones6053a522014-07-25 16:22:09 -0700524 {
525 return false;
526 }
527
528 // The base image level is complete if the width and height are positive
529 if (level == 0)
530 {
531 return true;
532 }
533
Geoff Langb0eecdf2015-02-10 11:09:12 -0500534 const ImageDesc &levelImageDesc = getImageDesc(target, level);
535 if (levelImageDesc.internalFormat != baseImageDesc.internalFormat)
Brandon Jones6053a522014-07-25 16:22:09 -0700536 {
537 return false;
538 }
539
Geoff Langb0eecdf2015-02-10 11:09:12 -0500540 if (levelImageDesc.size.width != std::max(1, baseImageDesc.size.width >> level))
Brandon Jones6053a522014-07-25 16:22:09 -0700541 {
542 return false;
543 }
544
Geoff Langb0eecdf2015-02-10 11:09:12 -0500545 if (levelImageDesc.size.height != std::max(1, baseImageDesc.size.height >> level))
Brandon Jones6053a522014-07-25 16:22:09 -0700546 {
547 return false;
548 }
549
Geoff Lang691e58c2014-12-19 17:03:25 -0500550 if (mTarget == GL_TEXTURE_3D)
Brandon Jones6053a522014-07-25 16:22:09 -0700551 {
Geoff Langb0eecdf2015-02-10 11:09:12 -0500552 if (levelImageDesc.size.depth != std::max(1, baseImageDesc.size.depth >> level))
Brandon Jones6053a522014-07-25 16:22:09 -0700553 {
554 return false;
555 }
556 }
Geoff Lang691e58c2014-12-19 17:03:25 -0500557 else if (mTarget == GL_TEXTURE_2D_ARRAY)
Brandon Jones6053a522014-07-25 16:22:09 -0700558 {
Geoff Langb0eecdf2015-02-10 11:09:12 -0500559 if (levelImageDesc.size.depth != baseImageDesc.size.depth)
Brandon Jones6053a522014-07-25 16:22:09 -0700560 {
561 return false;
562 }
563 }
564
565 return true;
566}
567
Geoff Lang0fe40532015-02-10 12:01:27 -0500568Texture::SamplerCompletenessCache::SamplerCompletenessCache()
569 : cacheValid(false),
570 samplerState(),
571 filterable(false),
572 clientVersion(0),
573 supportsNPOT(false),
574 samplerComplete(false)
575{
576}
577
Jamie Madill79481d62015-04-14 08:13:47 -0400578GLsizei Texture::getAttachmentWidth(const gl::FramebufferAttachment::Target &target) const
579{
580 return getWidth(target.textureIndex().type, target.textureIndex().mipIndex);
581}
582
583GLsizei Texture::getAttachmentHeight(const gl::FramebufferAttachment::Target &target) const
584{
585 return getHeight(target.textureIndex().type, target.textureIndex().mipIndex);
586}
587
588GLenum Texture::getAttachmentInternalFormat(const gl::FramebufferAttachment::Target &target) const
589{
590 return getInternalFormat(target.textureIndex().type, target.textureIndex().mipIndex);
591}
592
593GLsizei Texture::getAttachmentSamples(const gl::FramebufferAttachment::Target &/*target*/) const
594{
595 // Multisample textures not currently supported
596 return 0;
597}
598
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000599}