blob: 2668478be488367f853762b8c540a43d8f5e219c [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"
Geoff Langa8406172015-07-21 16:53:39 -040015#include "libANGLE/Image.h"
Jamie Madill79481d62015-04-14 08:13:47 -040016#include "libANGLE/Surface.h"
17#include "libANGLE/formatutils.h"
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000018
19namespace gl
20{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000021
Brandon Jones6053a522014-07-25 16:22:09 -070022bool IsMipmapFiltered(const gl::SamplerState &samplerState)
23{
24 switch (samplerState.minFilter)
25 {
26 case GL_NEAREST:
27 case GL_LINEAR:
28 return false;
29 case GL_NEAREST_MIPMAP_NEAREST:
30 case GL_LINEAR_MIPMAP_NEAREST:
31 case GL_NEAREST_MIPMAP_LINEAR:
32 case GL_LINEAR_MIPMAP_LINEAR:
33 return true;
34 default: UNREACHABLE();
35 return false;
36 }
37}
38
39bool IsPointSampled(const gl::SamplerState &samplerState)
40{
41 return (samplerState.magFilter == GL_NEAREST && (samplerState.minFilter == GL_NEAREST || samplerState.minFilter == GL_NEAREST_MIPMAP_NEAREST));
42}
43
Geoff Lang866dd2d2015-02-10 11:08:32 -050044static size_t GetImageDescIndex(GLenum target, size_t level)
45{
46 return IsCubeMapTextureTarget(target) ? ((level * 6) + CubeMapTextureTargetToLayerIndex(target)) : level;
47}
48
Brandon Jones6053a522014-07-25 16:22:09 -070049Texture::Texture(rx::TextureImpl *impl, GLuint id, GLenum target)
Geoff Langa8406172015-07-21 16:53:39 -040050 : egl::ImageSibling(id),
Brandon Jones6053a522014-07-25 16:22:09 -070051 mTexture(impl),
Brandon Jonesf47bebc2014-07-09 14:28:42 -070052 mUsage(GL_NONE),
Jamie Madill6948e302014-10-20 17:04:33 -040053 mImmutableLevelCount(0),
Geoff Lang7c973ea2014-12-19 15:58:28 -050054 mTarget(target),
Geoff Lang866dd2d2015-02-10 11:08:32 -050055 mImageDescs(IMPLEMENTATION_MAX_TEXTURE_LEVELS * (target == GL_TEXTURE_CUBE_MAP ? 6 : 1)),
Geoff Lang0fe40532015-02-10 12:01:27 -050056 mCompletenessCache(),
Geoff Lang7c973ea2014-12-19 15:58:28 -050057 mBoundSurface(NULL)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000058{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000059}
60
61Texture::~Texture()
62{
Geoff Lang7c973ea2014-12-19 15:58:28 -050063 if (mBoundSurface)
64 {
65 mBoundSurface->releaseTexImage(EGL_BACK_BUFFER);
66 mBoundSurface = NULL;
67 }
Brandon Jones6053a522014-07-25 16:22:09 -070068 SafeDelete(mTexture);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000069}
70
Geoff Lang4907f2c2013-07-25 12:53:57 -040071GLenum Texture::getTarget() const
72{
73 return mTarget;
74}
75
Geoff Lang63b5f1f2013-09-23 14:52:14 -040076void Texture::setUsage(GLenum usage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000077{
Geoff Lang63b5f1f2013-09-23 14:52:14 -040078 mUsage = usage;
Brandon Jonescef06ff2014-08-05 13:27:48 -070079 getImplementation()->setUsage(usage);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000080}
81
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000082GLenum Texture::getUsage() const
83{
84 return mUsage;
85}
86
Geoff Langa9be0dc2014-12-17 12:34:40 -050087size_t Texture::getWidth(GLenum target, size_t level) const
Jamie Madilld3d2a342013-10-07 10:46:35 -040088{
Geoff Lang691e58c2014-12-19 17:03:25 -050089 ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
Geoff Lang866dd2d2015-02-10 11:08:32 -050090 return getImageDesc(target, level).size.width;
Jamie Madilld3d2a342013-10-07 10:46:35 -040091}
92
Geoff Langa9be0dc2014-12-17 12:34:40 -050093size_t Texture::getHeight(GLenum target, size_t level) const
Jamie Madilld3d2a342013-10-07 10:46:35 -040094{
Geoff Lang691e58c2014-12-19 17:03:25 -050095 ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
Geoff Lang866dd2d2015-02-10 11:08:32 -050096 return getImageDesc(target, level).size.height;
Jamie Madilld3d2a342013-10-07 10:46:35 -040097}
98
Geoff Langa9be0dc2014-12-17 12:34:40 -050099size_t Texture::getDepth(GLenum target, size_t level) const
Jamie Madilld3d2a342013-10-07 10:46:35 -0400100{
Geoff Lang691e58c2014-12-19 17:03:25 -0500101 ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
Geoff Lang866dd2d2015-02-10 11:08:32 -0500102 return getImageDesc(target, level).size.depth;
Jamie Madilld3d2a342013-10-07 10:46:35 -0400103}
104
Geoff Langa9be0dc2014-12-17 12:34:40 -0500105GLenum Texture::getInternalFormat(GLenum target, size_t level) const
Jamie Madilld3d2a342013-10-07 10:46:35 -0400106{
Geoff Lang691e58c2014-12-19 17:03:25 -0500107 ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
Geoff Lang866dd2d2015-02-10 11:08:32 -0500108 return getImageDesc(target, level).internalFormat;
Jamie Madill945f7322014-09-03 15:07:14 -0400109}
110
Geoff Lang691e58c2014-12-19 17:03:25 -0500111bool Texture::isSamplerComplete(const SamplerState &samplerState, const Data &data) const
112{
Geoff Langb0eecdf2015-02-10 11:09:12 -0500113 const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), samplerState.baseLevel);
Geoff Langb0eecdf2015-02-10 11:09:12 -0500114 const TextureCaps &textureCaps = data.textureCaps->get(baseImageDesc.internalFormat);
Geoff Lang0fe40532015-02-10 12:01:27 -0500115 if (!mCompletenessCache.cacheValid ||
116 mCompletenessCache.samplerState != samplerState ||
117 mCompletenessCache.filterable != textureCaps.filterable ||
118 mCompletenessCache.clientVersion != data.clientVersion ||
119 mCompletenessCache.supportsNPOT != data.extensions->textureNPOT)
Geoff Lang691e58c2014-12-19 17:03:25 -0500120 {
Geoff Lang0fe40532015-02-10 12:01:27 -0500121 mCompletenessCache.cacheValid = true;
122 mCompletenessCache.samplerState = samplerState;
123 mCompletenessCache.filterable = textureCaps.filterable;
124 mCompletenessCache.clientVersion = data.clientVersion;
125 mCompletenessCache.supportsNPOT = data.extensions->textureNPOT;
126 mCompletenessCache.samplerComplete = computeSamplerCompleteness(samplerState, data);
Geoff Lang691e58c2014-12-19 17:03:25 -0500127 }
Geoff Lang0fe40532015-02-10 12:01:27 -0500128 return mCompletenessCache.samplerComplete;
Geoff Lang691e58c2014-12-19 17:03:25 -0500129}
130
Geoff Langa8406172015-07-21 16:53:39 -0400131bool Texture::isMipmapComplete() const
132{
133 return computeMipmapCompleteness(mSamplerState);
134}
135
Geoff Lang691e58c2014-12-19 17:03:25 -0500136// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
137bool Texture::isCubeComplete() const
138{
139 ASSERT(mTarget == GL_TEXTURE_CUBE_MAP);
140
Geoff Langb0eecdf2015-02-10 11:09:12 -0500141 const ImageDesc &baseImageDesc = getImageDesc(FirstCubeMapTextureTarget, 0);
142 if (baseImageDesc.size.width == 0 || baseImageDesc.size.width != baseImageDesc.size.height)
Geoff Lang691e58c2014-12-19 17:03:25 -0500143 {
144 return false;
145 }
146
Geoff Langb0eecdf2015-02-10 11:09:12 -0500147 for (GLenum face = FirstCubeMapTextureTarget + 1; face <= LastCubeMapTextureTarget; face++)
Geoff Lang691e58c2014-12-19 17:03:25 -0500148 {
Geoff Langb0eecdf2015-02-10 11:09:12 -0500149 const ImageDesc &faceImageDesc = getImageDesc(face, 0);
150 if (faceImageDesc.size.width != baseImageDesc.size.width ||
151 faceImageDesc.size.height != baseImageDesc.size.height ||
152 faceImageDesc.internalFormat != baseImageDesc.internalFormat)
Geoff Lang691e58c2014-12-19 17:03:25 -0500153 {
154 return false;
155 }
156 }
157
158 return true;
159}
160
Geoff Langa8406172015-07-21 16:53:39 -0400161size_t Texture::getMipCompleteLevels() const
162{
163 const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), 0);
164 if (mTarget == GL_TEXTURE_3D)
165 {
166 const size_t maxDim =
167 std::max(std::max(baseImageDesc.size.width, baseImageDesc.size.height),
168 baseImageDesc.size.depth);
169 return log2(maxDim) + 1;
170 }
171 else
172 {
173 return log2(std::max(baseImageDesc.size.width, baseImageDesc.size.height)) + 1;
174 }
175}
176
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700177bool Texture::isImmutable() const
178{
Jamie Madill6948e302014-10-20 17:04:33 -0400179 return (mImmutableLevelCount > 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700180}
181
182int Texture::immutableLevelCount()
183{
Jamie Madill6948e302014-10-20 17:04:33 -0400184 return mImmutableLevelCount;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700185}
186
Geoff Langa8406172015-07-21 16:53:39 -0400187egl::Surface *Texture::getBoundSurface() const
188{
189 return mBoundSurface;
190}
191
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500192Error Texture::setImage(GLenum target, size_t level, GLenum internalFormat, const Extents &size, GLenum format, GLenum type,
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();
Geoff Langa8406172015-07-21 16:53:39 -0400199 orphanImages();
Jamie Madillbb714f72015-05-20 10:22:18 -0400200
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500201 Error error = mTexture->setImage(target, level, internalFormat, size, format, type, unpack, pixels);
202 if (error.isError())
203 {
204 return error;
205 }
206
Geoff Lang866dd2d2015-02-10 11:08:32 -0500207 setImageDesc(target, level, ImageDesc(size, GetSizedInternalFormat(internalFormat, type)));
Geoff Langa9be0dc2014-12-17 12:34:40 -0500208
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500209 return Error(GL_NO_ERROR);
210}
211
212Error Texture::setSubImage(GLenum target, size_t level, const Box &area, GLenum format, GLenum type,
213 const PixelUnpackState &unpack, const uint8_t *pixels)
214{
Geoff Lang691e58c2014-12-19 17:03:25 -0500215 ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500216
217 return mTexture->setSubImage(target, level, area, format, type, unpack, pixels);
218}
219
220Error Texture::setCompressedImage(GLenum target, size_t level, GLenum internalFormat, const Extents &size,
Geoff Lang8509d862015-05-20 14:06:13 -0400221 const PixelUnpackState &unpack, size_t imageSize, const uint8_t *pixels)
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500222{
Geoff Lang691e58c2014-12-19 17:03:25 -0500223 ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500224
Jamie Madillbb714f72015-05-20 10:22:18 -0400225 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
226 releaseTexImageInternal();
Geoff Langa8406172015-07-21 16:53:39 -0400227 orphanImages();
Jamie Madillbb714f72015-05-20 10:22:18 -0400228
Geoff Lang8509d862015-05-20 14:06:13 -0400229 Error error = mTexture->setCompressedImage(target, level, internalFormat, size, unpack, imageSize, pixels);
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500230 if (error.isError())
231 {
232 return error;
233 }
234
Geoff Lang866dd2d2015-02-10 11:08:32 -0500235 setImageDesc(target, level, ImageDesc(size, GetSizedInternalFormat(internalFormat, GL_UNSIGNED_BYTE)));
Geoff Langa9be0dc2014-12-17 12:34:40 -0500236
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500237 return Error(GL_NO_ERROR);
238}
239
240Error Texture::setCompressedSubImage(GLenum target, size_t level, const Box &area, GLenum format,
Geoff Lang8509d862015-05-20 14:06:13 -0400241 const PixelUnpackState &unpack, size_t imageSize, const uint8_t *pixels)
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500242{
Geoff Lang691e58c2014-12-19 17:03:25 -0500243 ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500244
Geoff Lang8509d862015-05-20 14:06:13 -0400245 return mTexture->setCompressedSubImage(target, level, area, format, unpack, imageSize, pixels);
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500246}
247
248Error Texture::copyImage(GLenum target, size_t level, const Rectangle &sourceArea, GLenum internalFormat,
249 const Framebuffer *source)
250{
Geoff Lang691e58c2014-12-19 17:03:25 -0500251 ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500252
Jamie Madillbb714f72015-05-20 10:22:18 -0400253 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
254 releaseTexImageInternal();
Geoff Langa8406172015-07-21 16:53:39 -0400255 orphanImages();
Jamie Madillbb714f72015-05-20 10:22:18 -0400256
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500257 Error error = mTexture->copyImage(target, level, sourceArea, internalFormat, source);
258 if (error.isError())
259 {
260 return error;
261 }
262
Geoff Lang866dd2d2015-02-10 11:08:32 -0500263 setImageDesc(target, level, ImageDesc(Extents(sourceArea.width, sourceArea.height, 1),
264 GetSizedInternalFormat(internalFormat, GL_UNSIGNED_BYTE)));
Geoff Langa9be0dc2014-12-17 12:34:40 -0500265
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500266 return Error(GL_NO_ERROR);
267}
268
269Error Texture::copySubImage(GLenum target, size_t level, const Offset &destOffset, const Rectangle &sourceArea,
270 const Framebuffer *source)
271{
Geoff Lang691e58c2014-12-19 17:03:25 -0500272 ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500273
274 return mTexture->copySubImage(target, level, destOffset, sourceArea, source);
275}
276
277Error Texture::setStorage(GLenum target, size_t levels, GLenum internalFormat, const Extents &size)
278{
279 ASSERT(target == mTarget);
280
Jamie Madillbb714f72015-05-20 10:22:18 -0400281 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
282 releaseTexImageInternal();
Geoff Langa8406172015-07-21 16:53:39 -0400283 orphanImages();
Jamie Madillbb714f72015-05-20 10:22:18 -0400284
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500285 Error error = mTexture->setStorage(target, levels, internalFormat, size);
286 if (error.isError())
287 {
288 return error;
289 }
290
291 mImmutableLevelCount = levels;
Geoff Langa9be0dc2014-12-17 12:34:40 -0500292 clearImageDescs();
293 setImageDescChain(levels, size, internalFormat);
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500294
295 return Error(GL_NO_ERROR);
296}
297
298
299Error Texture::generateMipmaps()
300{
Jamie Madillbb714f72015-05-20 10:22:18 -0400301 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
302 releaseTexImageInternal();
303
Geoff Langa8406172015-07-21 16:53:39 -0400304 // EGL_KHR_gl_image states that images are only orphaned when generating mipmaps if the texture
305 // is not mip complete.
306 if (!isMipmapComplete())
307 {
308 orphanImages();
309 }
310
Gregoire Payen de La Garanderie752ce192015-04-14 11:11:12 +0100311 Error error = mTexture->generateMipmaps(getSamplerState());
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500312 if (error.isError())
313 {
314 return error;
315 }
316
Geoff Lang866dd2d2015-02-10 11:08:32 -0500317 const ImageDesc &baseImageInfo = getImageDesc(getBaseImageTarget(), 0);
Geoff Langa9be0dc2014-12-17 12:34:40 -0500318 size_t mipLevels = log2(std::max(std::max(baseImageInfo.size.width, baseImageInfo.size.height), baseImageInfo.size.depth)) + 1;
319 setImageDescChain(mipLevels, baseImageInfo.size, baseImageInfo.internalFormat);
320
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500321 return Error(GL_NO_ERROR);
322}
323
Geoff Langa9be0dc2014-12-17 12:34:40 -0500324void Texture::setImageDescChain(size_t levels, Extents baseSize, GLenum sizedInternalFormat)
325{
326 for (size_t level = 0; level < levels; level++)
327 {
328 Extents levelSize(std::max<size_t>(baseSize.width >> level, 1),
329 std::max<size_t>(baseSize.height >> level, 1),
330 (mTarget == GL_TEXTURE_2D_ARRAY) ? baseSize.depth : std::max<size_t>(baseSize.depth >> level, 1));
331 ImageDesc levelInfo(levelSize, sizedInternalFormat);
332
333 if (mTarget == GL_TEXTURE_CUBE_MAP)
334 {
Geoff Lang691e58c2014-12-19 17:03:25 -0500335 for (size_t face = FirstCubeMapTextureTarget; face <= LastCubeMapTextureTarget; face++)
Geoff Langa9be0dc2014-12-17 12:34:40 -0500336 {
Geoff Lang866dd2d2015-02-10 11:08:32 -0500337 setImageDesc(face, level, levelInfo);
Geoff Langa9be0dc2014-12-17 12:34:40 -0500338 }
339 }
340 else
341 {
Geoff Lang866dd2d2015-02-10 11:08:32 -0500342 setImageDesc(mTarget, level, levelInfo);
Geoff Langa9be0dc2014-12-17 12:34:40 -0500343 }
344 }
345}
346
Geoff Langa9be0dc2014-12-17 12:34:40 -0500347Texture::ImageDesc::ImageDesc()
348 : ImageDesc(Extents(0, 0, 0), GL_NONE)
349{
350}
351
352Texture::ImageDesc::ImageDesc(const Extents &size, GLenum internalFormat)
353 : size(size),
354 internalFormat(internalFormat)
355{
356}
357
Geoff Lang866dd2d2015-02-10 11:08:32 -0500358const Texture::ImageDesc &Texture::getImageDesc(GLenum target, size_t level) const
Geoff Langa9be0dc2014-12-17 12:34:40 -0500359{
Geoff Lang866dd2d2015-02-10 11:08:32 -0500360 size_t descIndex = GetImageDescIndex(target, level);
361 ASSERT(descIndex < mImageDescs.size());
362 return mImageDescs[descIndex];
Geoff Langa9be0dc2014-12-17 12:34:40 -0500363}
364
Geoff Lang866dd2d2015-02-10 11:08:32 -0500365void Texture::setImageDesc(GLenum target, size_t level, const ImageDesc &desc)
Geoff Langa9be0dc2014-12-17 12:34:40 -0500366{
Geoff Lang866dd2d2015-02-10 11:08:32 -0500367 size_t descIndex = GetImageDescIndex(target, level);
368 ASSERT(descIndex < mImageDescs.size());
369 mImageDescs[descIndex] = desc;
Geoff Lang0fe40532015-02-10 12:01:27 -0500370 mCompletenessCache.cacheValid = false;
Geoff Langa9be0dc2014-12-17 12:34:40 -0500371}
372
Geoff Lang866dd2d2015-02-10 11:08:32 -0500373void Texture::clearImageDesc(GLenum target, size_t level)
Geoff Langb9266272015-01-29 13:25:14 +0000374{
Geoff Lang866dd2d2015-02-10 11:08:32 -0500375 setImageDesc(target, level, ImageDesc());
Geoff Langb9266272015-01-29 13:25:14 +0000376}
377
Geoff Langa9be0dc2014-12-17 12:34:40 -0500378void Texture::clearImageDescs()
379{
Geoff Lang866dd2d2015-02-10 11:08:32 -0500380 for (size_t descIndex = 0; descIndex < mImageDescs.size(); descIndex++)
381 {
382 mImageDescs[descIndex] = ImageDesc();
383 }
Geoff Lang0fe40532015-02-10 12:01:27 -0500384 mCompletenessCache.cacheValid = false;
Geoff Langa9be0dc2014-12-17 12:34:40 -0500385}
386
Jamie Madillbb714f72015-05-20 10:22:18 -0400387void Texture::bindTexImageFromSurface(egl::Surface *surface)
Geoff Lang7c973ea2014-12-19 15:58:28 -0500388{
Geoff Langb9266272015-01-29 13:25:14 +0000389 ASSERT(surface);
390
Jamie Madillbb714f72015-05-20 10:22:18 -0400391 if (mBoundSurface)
392 {
393 releaseTexImageFromSurface();
394 }
395
Geoff Lang7c973ea2014-12-19 15:58:28 -0500396 mTexture->bindTexImage(surface);
397 mBoundSurface = surface;
Geoff Langb9266272015-01-29 13:25:14 +0000398
399 // Set the image info to the size and format of the surface
400 ASSERT(mTarget == GL_TEXTURE_2D);
401 Extents size(surface->getWidth(), surface->getHeight(), 1);
Geoff Langc223dc62015-01-09 13:10:01 -0500402 ImageDesc desc(size, surface->getConfig()->renderTargetFormat);
Geoff Lang866dd2d2015-02-10 11:08:32 -0500403 setImageDesc(mTarget, 0, desc);
Geoff Lang7c973ea2014-12-19 15:58:28 -0500404}
405
Jamie Madillbb714f72015-05-20 10:22:18 -0400406void Texture::releaseTexImageFromSurface()
407{
408 ASSERT(mBoundSurface);
409 mBoundSurface = nullptr;
410 mTexture->releaseTexImage();
411
412 // Erase the image info for level 0
413 ASSERT(mTarget == GL_TEXTURE_2D);
414 clearImageDesc(mTarget, 0);
415}
416
417void Texture::releaseTexImageInternal()
Geoff Lang7c973ea2014-12-19 15:58:28 -0500418{
419 if (mBoundSurface)
420 {
Jamie Madillbb714f72015-05-20 10:22:18 -0400421 // Notify the surface
422 mBoundSurface->releaseTexImageFromTexture();
Geoff Langb9266272015-01-29 13:25:14 +0000423
Jamie Madillbb714f72015-05-20 10:22:18 -0400424 // Then, call the same method as from the surface
425 releaseTexImageFromSurface();
Geoff Lang7c973ea2014-12-19 15:58:28 -0500426 }
427}
428
Geoff Langa8406172015-07-21 16:53:39 -0400429Error Texture::setEGLImageTarget(GLenum target, egl::Image *imageTarget)
430{
431 ASSERT(target == mTarget);
432 ASSERT(target == GL_TEXTURE_2D);
433
434 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
435 releaseTexImageInternal();
436 orphanImages();
437
438 Error error = mTexture->setEGLImageTarget(target, imageTarget);
439 if (error.isError())
440 {
441 return error;
442 }
443
444 setTargetImage(imageTarget);
445
446 Extents size(imageTarget->getWidth(), imageTarget->getHeight(), 1);
447 GLenum internalFormat = imageTarget->getInternalFormat();
448 GLenum type = GetInternalFormatInfo(internalFormat).type;
449
450 clearImageDescs();
451 setImageDesc(target, 0, ImageDesc(size, GetSizedInternalFormat(internalFormat, type)));
452
453 return Error(GL_NO_ERROR);
454}
455
Geoff Lang691e58c2014-12-19 17:03:25 -0500456GLenum Texture::getBaseImageTarget() const
Jamie Madill22f843a2013-10-24 17:49:36 -0400457{
Geoff Lang691e58c2014-12-19 17:03:25 -0500458 return mTarget == GL_TEXTURE_CUBE_MAP ? FirstCubeMapTextureTarget : mTarget;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000459}
460
Geoff Lang0fe40532015-02-10 12:01:27 -0500461bool Texture::computeSamplerCompleteness(const SamplerState &samplerState, const Data &data) const
462{
463 const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), samplerState.baseLevel);
464 if (baseImageDesc.size.width == 0 || baseImageDesc.size.height == 0 || baseImageDesc.size.depth == 0)
465 {
466 return false;
467 }
468
469 if (mTarget == GL_TEXTURE_CUBE_MAP && baseImageDesc.size.width != baseImageDesc.size.height)
470 {
471 return false;
472 }
473
474 const TextureCaps &textureCaps = data.textureCaps->get(baseImageDesc.internalFormat);
475 if (!textureCaps.filterable && !IsPointSampled(samplerState))
476 {
477 return false;
478 }
479
480 bool npotSupport = data.extensions->textureNPOT || data.clientVersion >= 3;
481 if (!npotSupport)
482 {
483 if ((samplerState.wrapS != GL_CLAMP_TO_EDGE && !gl::isPow2(baseImageDesc.size.width)) ||
484 (samplerState.wrapT != GL_CLAMP_TO_EDGE && !gl::isPow2(baseImageDesc.size.height)))
485 {
486 return false;
487 }
488 }
489
490 if (IsMipmapFiltered(samplerState))
491 {
492 if (!npotSupport)
493 {
494 if (!gl::isPow2(baseImageDesc.size.width) || !gl::isPow2(baseImageDesc.size.height))
495 {
496 return false;
497 }
498 }
499
500 if (!computeMipmapCompleteness(samplerState))
501 {
502 return false;
503 }
504 }
505 else
506 {
507 if (mTarget == GL_TEXTURE_CUBE_MAP && !isCubeComplete())
508 {
509 return false;
510 }
511 }
512
513 // OpenGLES 3.0.2 spec section 3.8.13 states that a texture is not mipmap complete if:
514 // The internalformat specified for the texture arrays is a sized internal depth or
515 // depth and stencil format (see table 3.13), the value of TEXTURE_COMPARE_-
516 // MODE is NONE, and either the magnification filter is not NEAREST or the mini-
517 // fication filter is neither NEAREST nor NEAREST_MIPMAP_NEAREST.
518 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(baseImageDesc.internalFormat);
519 if (formatInfo.depthBits > 0 && data.clientVersion > 2)
520 {
521 if (samplerState.compareMode == GL_NONE)
522 {
523 if ((samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST) ||
524 samplerState.magFilter != GL_NEAREST)
525 {
526 return false;
527 }
528 }
529 }
530
531 return true;
532}
533
534bool Texture::computeMipmapCompleteness(const gl::SamplerState &samplerState) const
Brandon Jones6053a522014-07-25 16:22:09 -0700535{
Geoff Langa8406172015-07-21 16:53:39 -0400536 size_t expectedMipLevels = getMipCompleteLevels();
Jamie Madill19d438d2015-01-19 13:42:12 -0500537
538 size_t maxLevel = std::min<size_t>(expectedMipLevels, samplerState.maxLevel + 1);
539
540 for (size_t level = samplerState.baseLevel; level < maxLevel; level++)
Brandon Jones6053a522014-07-25 16:22:09 -0700541 {
Geoff Lang691e58c2014-12-19 17:03:25 -0500542 if (mTarget == GL_TEXTURE_CUBE_MAP)
Brandon Jones6053a522014-07-25 16:22:09 -0700543 {
Geoff Lang691e58c2014-12-19 17:03:25 -0500544 for (GLenum face = FirstCubeMapTextureTarget; face <= LastCubeMapTextureTarget; face++)
545 {
Geoff Lang0fe40532015-02-10 12:01:27 -0500546 if (!computeLevelCompleteness(face, level, samplerState))
Geoff Lang691e58c2014-12-19 17:03:25 -0500547 {
548 return false;
549 }
550 }
551 }
552 else
553 {
Geoff Lang0fe40532015-02-10 12:01:27 -0500554 if (!computeLevelCompleteness(mTarget, level, samplerState))
Geoff Lang691e58c2014-12-19 17:03:25 -0500555 {
556 return false;
557 }
Brandon Jones6053a522014-07-25 16:22:09 -0700558 }
559 }
560
561 return true;
562}
563
Geoff Lang691e58c2014-12-19 17:03:25 -0500564
Geoff Lang0fe40532015-02-10 12:01:27 -0500565bool Texture::computeLevelCompleteness(GLenum target, size_t level, const gl::SamplerState &samplerState) const
Brandon Jones6053a522014-07-25 16:22:09 -0700566{
Geoff Langa9be0dc2014-12-17 12:34:40 -0500567 ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
568
Brandon Jones6053a522014-07-25 16:22:09 -0700569 if (isImmutable())
570 {
571 return true;
572 }
573
Geoff Langb0eecdf2015-02-10 11:09:12 -0500574 const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), samplerState.baseLevel);
575 if (baseImageDesc.size.width == 0 || baseImageDesc.size.height == 0 || baseImageDesc.size.depth == 0)
Brandon Jones6053a522014-07-25 16:22:09 -0700576 {
577 return false;
578 }
579
Geoff Langa8406172015-07-21 16:53:39 -0400580 const ImageDesc &levelImageDesc = getImageDesc(target, level);
581 if (levelImageDesc.size.width == 0 || levelImageDesc.size.height == 0 ||
582 levelImageDesc.size.depth == 0)
Brandon Jones6053a522014-07-25 16:22:09 -0700583 {
Geoff Langa8406172015-07-21 16:53:39 -0400584 return false;
Brandon Jones6053a522014-07-25 16:22:09 -0700585 }
586
Geoff Langb0eecdf2015-02-10 11:09:12 -0500587 if (levelImageDesc.internalFormat != baseImageDesc.internalFormat)
Brandon Jones6053a522014-07-25 16:22:09 -0700588 {
589 return false;
590 }
591
Geoff Langb0eecdf2015-02-10 11:09:12 -0500592 if (levelImageDesc.size.width != std::max(1, baseImageDesc.size.width >> level))
Brandon Jones6053a522014-07-25 16:22:09 -0700593 {
594 return false;
595 }
596
Geoff Langb0eecdf2015-02-10 11:09:12 -0500597 if (levelImageDesc.size.height != std::max(1, baseImageDesc.size.height >> level))
Brandon Jones6053a522014-07-25 16:22:09 -0700598 {
599 return false;
600 }
601
Geoff Lang691e58c2014-12-19 17:03:25 -0500602 if (mTarget == GL_TEXTURE_3D)
Brandon Jones6053a522014-07-25 16:22:09 -0700603 {
Geoff Langb0eecdf2015-02-10 11:09:12 -0500604 if (levelImageDesc.size.depth != std::max(1, baseImageDesc.size.depth >> level))
Brandon Jones6053a522014-07-25 16:22:09 -0700605 {
606 return false;
607 }
608 }
Geoff Lang691e58c2014-12-19 17:03:25 -0500609 else if (mTarget == GL_TEXTURE_2D_ARRAY)
Brandon Jones6053a522014-07-25 16:22:09 -0700610 {
Geoff Langb0eecdf2015-02-10 11:09:12 -0500611 if (levelImageDesc.size.depth != baseImageDesc.size.depth)
Brandon Jones6053a522014-07-25 16:22:09 -0700612 {
613 return false;
614 }
615 }
616
617 return true;
618}
619
Geoff Lang0fe40532015-02-10 12:01:27 -0500620Texture::SamplerCompletenessCache::SamplerCompletenessCache()
621 : cacheValid(false),
622 samplerState(),
623 filterable(false),
624 clientVersion(0),
625 supportsNPOT(false),
626 samplerComplete(false)
627{
628}
629
Jamie Madill79481d62015-04-14 08:13:47 -0400630GLsizei Texture::getAttachmentWidth(const gl::FramebufferAttachment::Target &target) const
631{
632 return getWidth(target.textureIndex().type, target.textureIndex().mipIndex);
633}
634
635GLsizei Texture::getAttachmentHeight(const gl::FramebufferAttachment::Target &target) const
636{
637 return getHeight(target.textureIndex().type, target.textureIndex().mipIndex);
638}
639
640GLenum Texture::getAttachmentInternalFormat(const gl::FramebufferAttachment::Target &target) const
641{
642 return getInternalFormat(target.textureIndex().type, target.textureIndex().mipIndex);
643}
644
645GLsizei Texture::getAttachmentSamples(const gl::FramebufferAttachment::Target &/*target*/) const
646{
647 // Multisample textures not currently supported
648 return 0;
649}
650
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000651}