blob: 970cb30fbbfb005d502654f3bdc46287083a123e [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"
Jamie Madill1b94d432015-08-07 13:23:23 -040014#include "libANGLE/Context.h"
Jamie Madill79481d62015-04-14 08:13:47 -040015#include "libANGLE/Data.h"
Geoff Langa8406172015-07-21 16:53:39 -040016#include "libANGLE/Image.h"
Jamie Madill79481d62015-04-14 08:13:47 -040017#include "libANGLE/Surface.h"
18#include "libANGLE/formatutils.h"
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000019
20namespace gl
21{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000022
Brandon Jones6053a522014-07-25 16:22:09 -070023bool IsMipmapFiltered(const gl::SamplerState &samplerState)
24{
25 switch (samplerState.minFilter)
26 {
27 case GL_NEAREST:
28 case GL_LINEAR:
29 return false;
30 case GL_NEAREST_MIPMAP_NEAREST:
31 case GL_LINEAR_MIPMAP_NEAREST:
32 case GL_NEAREST_MIPMAP_LINEAR:
33 case GL_LINEAR_MIPMAP_LINEAR:
34 return true;
35 default: UNREACHABLE();
36 return false;
37 }
38}
39
40bool IsPointSampled(const gl::SamplerState &samplerState)
41{
42 return (samplerState.magFilter == GL_NEAREST && (samplerState.minFilter == GL_NEAREST || samplerState.minFilter == GL_NEAREST_MIPMAP_NEAREST));
43}
44
Geoff Lang866dd2d2015-02-10 11:08:32 -050045static size_t GetImageDescIndex(GLenum target, size_t level)
46{
47 return IsCubeMapTextureTarget(target) ? ((level * 6) + CubeMapTextureTargetToLayerIndex(target)) : level;
48}
49
Brandon Jones6053a522014-07-25 16:22:09 -070050Texture::Texture(rx::TextureImpl *impl, GLuint id, GLenum target)
Geoff Langa8406172015-07-21 16:53:39 -040051 : egl::ImageSibling(id),
Brandon Jones6053a522014-07-25 16:22:09 -070052 mTexture(impl),
Brandon Jonesf47bebc2014-07-09 14:28:42 -070053 mUsage(GL_NONE),
Jamie Madill6948e302014-10-20 17:04:33 -040054 mImmutableLevelCount(0),
Geoff Lang7c973ea2014-12-19 15:58:28 -050055 mTarget(target),
Geoff Lang866dd2d2015-02-10 11:08:32 -050056 mImageDescs(IMPLEMENTATION_MAX_TEXTURE_LEVELS * (target == GL_TEXTURE_CUBE_MAP ? 6 : 1)),
Geoff Lang0fe40532015-02-10 12:01:27 -050057 mCompletenessCache(),
Geoff Lang7c973ea2014-12-19 15:58:28 -050058 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 Lang691e58c2014-12-19 17:03:25 -050090 ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
Geoff Lang866dd2d2015-02-10 11:08:32 -050091 return getImageDesc(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 Lang691e58c2014-12-19 17:03:25 -050096 ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
Geoff Lang866dd2d2015-02-10 11:08:32 -050097 return getImageDesc(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 Lang691e58c2014-12-19 17:03:25 -0500102 ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
Geoff Lang866dd2d2015-02-10 11:08:32 -0500103 return getImageDesc(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 Lang691e58c2014-12-19 17:03:25 -0500108 ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
Geoff Lang866dd2d2015-02-10 11:08:32 -0500109 return getImageDesc(target, level).internalFormat;
Jamie Madill945f7322014-09-03 15:07:14 -0400110}
111
Geoff Lang691e58c2014-12-19 17:03:25 -0500112bool Texture::isSamplerComplete(const SamplerState &samplerState, const Data &data) const
113{
Geoff Langb0eecdf2015-02-10 11:09:12 -0500114 const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), samplerState.baseLevel);
Geoff Langb0eecdf2015-02-10 11:09:12 -0500115 const TextureCaps &textureCaps = data.textureCaps->get(baseImageDesc.internalFormat);
Geoff Lang0fe40532015-02-10 12:01:27 -0500116 if (!mCompletenessCache.cacheValid ||
117 mCompletenessCache.samplerState != samplerState ||
118 mCompletenessCache.filterable != textureCaps.filterable ||
119 mCompletenessCache.clientVersion != data.clientVersion ||
120 mCompletenessCache.supportsNPOT != data.extensions->textureNPOT)
Geoff Lang691e58c2014-12-19 17:03:25 -0500121 {
Geoff Lang0fe40532015-02-10 12:01:27 -0500122 mCompletenessCache.cacheValid = true;
123 mCompletenessCache.samplerState = samplerState;
124 mCompletenessCache.filterable = textureCaps.filterable;
125 mCompletenessCache.clientVersion = data.clientVersion;
126 mCompletenessCache.supportsNPOT = data.extensions->textureNPOT;
127 mCompletenessCache.samplerComplete = computeSamplerCompleteness(samplerState, data);
Geoff Lang691e58c2014-12-19 17:03:25 -0500128 }
Geoff Lang0fe40532015-02-10 12:01:27 -0500129 return mCompletenessCache.samplerComplete;
Geoff Lang691e58c2014-12-19 17:03:25 -0500130}
131
Geoff Langa8406172015-07-21 16:53:39 -0400132bool Texture::isMipmapComplete() const
133{
134 return computeMipmapCompleteness(mSamplerState);
135}
136
Geoff Lang691e58c2014-12-19 17:03:25 -0500137// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
138bool Texture::isCubeComplete() const
139{
140 ASSERT(mTarget == GL_TEXTURE_CUBE_MAP);
141
Geoff Langb0eecdf2015-02-10 11:09:12 -0500142 const ImageDesc &baseImageDesc = getImageDesc(FirstCubeMapTextureTarget, 0);
143 if (baseImageDesc.size.width == 0 || baseImageDesc.size.width != baseImageDesc.size.height)
Geoff Lang691e58c2014-12-19 17:03:25 -0500144 {
145 return false;
146 }
147
Geoff Langb0eecdf2015-02-10 11:09:12 -0500148 for (GLenum face = FirstCubeMapTextureTarget + 1; face <= LastCubeMapTextureTarget; face++)
Geoff Lang691e58c2014-12-19 17:03:25 -0500149 {
Geoff Langb0eecdf2015-02-10 11:09:12 -0500150 const ImageDesc &faceImageDesc = getImageDesc(face, 0);
151 if (faceImageDesc.size.width != baseImageDesc.size.width ||
152 faceImageDesc.size.height != baseImageDesc.size.height ||
153 faceImageDesc.internalFormat != baseImageDesc.internalFormat)
Geoff Lang691e58c2014-12-19 17:03:25 -0500154 {
155 return false;
156 }
157 }
158
159 return true;
160}
161
Geoff Langa8406172015-07-21 16:53:39 -0400162size_t Texture::getMipCompleteLevels() const
163{
164 const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), 0);
165 if (mTarget == GL_TEXTURE_3D)
166 {
Cooper Partinc5cf9bc2015-08-06 10:46:48 -0700167 const int maxDim = std::max(std::max(baseImageDesc.size.width, baseImageDesc.size.height),
168 baseImageDesc.size.depth);
Geoff Langa8406172015-07-21 16:53:39 -0400169 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
Jamie Madill1b94d432015-08-07 13:23:23 -0400192Error Texture::setImage(Context *context,
193 GLenum target,
194 size_t level,
195 GLenum internalFormat,
196 const Extents &size,
197 GLenum format,
198 GLenum type,
199 const uint8_t *pixels)
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500200{
Geoff Lang691e58c2014-12-19 17:03:25 -0500201 ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500202
Jamie Madillbb714f72015-05-20 10:22:18 -0400203 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
204 releaseTexImageInternal();
Geoff Langa8406172015-07-21 16:53:39 -0400205 orphanImages();
Jamie Madillbb714f72015-05-20 10:22:18 -0400206
Jamie Madill1b94d432015-08-07 13:23:23 -0400207 // Hack: allow nullptr for testing
208 if (context != nullptr)
209 {
210 // Sync the unpack state
211 context->syncRendererState(context->getState().unpackStateBitMask());
212 }
213
214 const PixelUnpackState &unpack =
215 context ? context->getState().getUnpackState() : PixelUnpackState();
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500216 Error error = mTexture->setImage(target, level, internalFormat, size, format, type, unpack, pixels);
217 if (error.isError())
218 {
219 return error;
220 }
221
Geoff Lang866dd2d2015-02-10 11:08:32 -0500222 setImageDesc(target, level, ImageDesc(size, GetSizedInternalFormat(internalFormat, type)));
Geoff Langa9be0dc2014-12-17 12:34:40 -0500223
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500224 return Error(GL_NO_ERROR);
225}
226
Jamie Madill1b94d432015-08-07 13:23:23 -0400227Error Texture::setSubImage(Context *context,
228 GLenum target,
229 size_t level,
230 const Box &area,
231 GLenum format,
232 GLenum type,
233 const uint8_t *pixels)
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500234{
Geoff Lang691e58c2014-12-19 17:03:25 -0500235 ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500236
Jamie Madill1b94d432015-08-07 13:23:23 -0400237 // Sync the unpack state
238 context->syncRendererState(context->getState().unpackStateBitMask());
239
240 const PixelUnpackState &unpack = context->getState().getUnpackState();
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500241 return mTexture->setSubImage(target, level, area, format, type, unpack, pixels);
242}
243
Jamie Madill1b94d432015-08-07 13:23:23 -0400244Error Texture::setCompressedImage(Context *context,
245 GLenum target,
246 size_t level,
247 GLenum internalFormat,
248 const Extents &size,
249 size_t imageSize,
250 const uint8_t *pixels)
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500251{
Geoff Lang691e58c2014-12-19 17:03:25 -0500252 ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500253
Jamie Madillbb714f72015-05-20 10:22:18 -0400254 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
255 releaseTexImageInternal();
Geoff Langa8406172015-07-21 16:53:39 -0400256 orphanImages();
Jamie Madillbb714f72015-05-20 10:22:18 -0400257
Jamie Madill1b94d432015-08-07 13:23:23 -0400258 // Sync the unpack state
259 context->syncRendererState(context->getState().unpackStateBitMask());
260
261 const PixelUnpackState &unpack = context->getState().getUnpackState();
Geoff Lang8509d862015-05-20 14:06:13 -0400262 Error error = mTexture->setCompressedImage(target, level, internalFormat, size, unpack, imageSize, pixels);
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500263 if (error.isError())
264 {
265 return error;
266 }
267
Geoff Lang866dd2d2015-02-10 11:08:32 -0500268 setImageDesc(target, level, ImageDesc(size, GetSizedInternalFormat(internalFormat, GL_UNSIGNED_BYTE)));
Geoff Langa9be0dc2014-12-17 12:34:40 -0500269
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500270 return Error(GL_NO_ERROR);
271}
272
Jamie Madill1b94d432015-08-07 13:23:23 -0400273Error Texture::setCompressedSubImage(Context *context,
274 GLenum target,
275 size_t level,
276 const Box &area,
277 GLenum format,
278 size_t imageSize,
279 const uint8_t *pixels)
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500280{
Geoff Lang691e58c2014-12-19 17:03:25 -0500281 ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500282
Jamie Madill1b94d432015-08-07 13:23:23 -0400283 // Sync the unpack state
284 context->syncRendererState(context->getState().unpackStateBitMask());
285
286 const PixelUnpackState &unpack = context->getState().getUnpackState();
Geoff Lang8509d862015-05-20 14:06:13 -0400287 return mTexture->setCompressedSubImage(target, level, area, format, unpack, imageSize, pixels);
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500288}
289
290Error Texture::copyImage(GLenum target, size_t level, const Rectangle &sourceArea, GLenum internalFormat,
291 const Framebuffer *source)
292{
Geoff Lang691e58c2014-12-19 17:03:25 -0500293 ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500294
Jamie Madillbb714f72015-05-20 10:22:18 -0400295 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
296 releaseTexImageInternal();
Geoff Langa8406172015-07-21 16:53:39 -0400297 orphanImages();
Jamie Madillbb714f72015-05-20 10:22:18 -0400298
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500299 Error error = mTexture->copyImage(target, level, sourceArea, internalFormat, source);
300 if (error.isError())
301 {
302 return error;
303 }
304
Geoff Lang866dd2d2015-02-10 11:08:32 -0500305 setImageDesc(target, level, ImageDesc(Extents(sourceArea.width, sourceArea.height, 1),
306 GetSizedInternalFormat(internalFormat, GL_UNSIGNED_BYTE)));
Geoff Langa9be0dc2014-12-17 12:34:40 -0500307
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500308 return Error(GL_NO_ERROR);
309}
310
311Error Texture::copySubImage(GLenum target, size_t level, const Offset &destOffset, const Rectangle &sourceArea,
312 const Framebuffer *source)
313{
Geoff Lang691e58c2014-12-19 17:03:25 -0500314 ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500315
316 return mTexture->copySubImage(target, level, destOffset, sourceArea, source);
317}
318
319Error Texture::setStorage(GLenum target, size_t levels, GLenum internalFormat, const Extents &size)
320{
321 ASSERT(target == mTarget);
322
Jamie Madillbb714f72015-05-20 10:22:18 -0400323 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
324 releaseTexImageInternal();
Geoff Langa8406172015-07-21 16:53:39 -0400325 orphanImages();
Jamie Madillbb714f72015-05-20 10:22:18 -0400326
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500327 Error error = mTexture->setStorage(target, levels, internalFormat, size);
328 if (error.isError())
329 {
330 return error;
331 }
332
Cooper Partinc5cf9bc2015-08-06 10:46:48 -0700333 mImmutableLevelCount = static_cast<GLsizei>(levels);
Geoff Langa9be0dc2014-12-17 12:34:40 -0500334 clearImageDescs();
335 setImageDescChain(levels, size, internalFormat);
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500336
337 return Error(GL_NO_ERROR);
338}
339
340
341Error Texture::generateMipmaps()
342{
Jamie Madillbb714f72015-05-20 10:22:18 -0400343 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
344 releaseTexImageInternal();
345
Geoff Langa8406172015-07-21 16:53:39 -0400346 // EGL_KHR_gl_image states that images are only orphaned when generating mipmaps if the texture
347 // is not mip complete.
348 if (!isMipmapComplete())
349 {
350 orphanImages();
351 }
352
Gregoire Payen de La Garanderie752ce192015-04-14 11:11:12 +0100353 Error error = mTexture->generateMipmaps(getSamplerState());
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500354 if (error.isError())
355 {
356 return error;
357 }
358
Geoff Lang866dd2d2015-02-10 11:08:32 -0500359 const ImageDesc &baseImageInfo = getImageDesc(getBaseImageTarget(), 0);
Geoff Langa9be0dc2014-12-17 12:34:40 -0500360 size_t mipLevels = log2(std::max(std::max(baseImageInfo.size.width, baseImageInfo.size.height), baseImageInfo.size.depth)) + 1;
361 setImageDescChain(mipLevels, baseImageInfo.size, baseImageInfo.internalFormat);
362
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500363 return Error(GL_NO_ERROR);
364}
365
Geoff Langa9be0dc2014-12-17 12:34:40 -0500366void Texture::setImageDescChain(size_t levels, Extents baseSize, GLenum sizedInternalFormat)
367{
Cooper Partinc5cf9bc2015-08-06 10:46:48 -0700368 for (int level = 0; level < static_cast<int>(levels); level++)
Geoff Langa9be0dc2014-12-17 12:34:40 -0500369 {
Cooper Partinc5cf9bc2015-08-06 10:46:48 -0700370 Extents levelSize(
371 std::max<int>(baseSize.width >> level, 1), std::max<int>(baseSize.height >> level, 1),
372 (mTarget == GL_TEXTURE_2D_ARRAY) ? baseSize.depth
373 : std::max<int>(baseSize.depth >> level, 1));
Geoff Langa9be0dc2014-12-17 12:34:40 -0500374 ImageDesc levelInfo(levelSize, sizedInternalFormat);
375
376 if (mTarget == GL_TEXTURE_CUBE_MAP)
377 {
Cooper Partinc5cf9bc2015-08-06 10:46:48 -0700378 for (GLenum face = FirstCubeMapTextureTarget; face <= LastCubeMapTextureTarget; face++)
Geoff Langa9be0dc2014-12-17 12:34:40 -0500379 {
Geoff Lang866dd2d2015-02-10 11:08:32 -0500380 setImageDesc(face, level, levelInfo);
Geoff Langa9be0dc2014-12-17 12:34:40 -0500381 }
382 }
383 else
384 {
Geoff Lang866dd2d2015-02-10 11:08:32 -0500385 setImageDesc(mTarget, level, levelInfo);
Geoff Langa9be0dc2014-12-17 12:34:40 -0500386 }
387 }
388}
389
Geoff Langa9be0dc2014-12-17 12:34:40 -0500390Texture::ImageDesc::ImageDesc()
391 : ImageDesc(Extents(0, 0, 0), GL_NONE)
392{
393}
394
395Texture::ImageDesc::ImageDesc(const Extents &size, GLenum internalFormat)
396 : size(size),
397 internalFormat(internalFormat)
398{
399}
400
Geoff Lang866dd2d2015-02-10 11:08:32 -0500401const Texture::ImageDesc &Texture::getImageDesc(GLenum target, size_t level) const
Geoff Langa9be0dc2014-12-17 12:34:40 -0500402{
Geoff Lang866dd2d2015-02-10 11:08:32 -0500403 size_t descIndex = GetImageDescIndex(target, level);
404 ASSERT(descIndex < mImageDescs.size());
405 return mImageDescs[descIndex];
Geoff Langa9be0dc2014-12-17 12:34:40 -0500406}
407
Geoff Lang866dd2d2015-02-10 11:08:32 -0500408void Texture::setImageDesc(GLenum target, size_t level, const ImageDesc &desc)
Geoff Langa9be0dc2014-12-17 12:34:40 -0500409{
Geoff Lang866dd2d2015-02-10 11:08:32 -0500410 size_t descIndex = GetImageDescIndex(target, level);
411 ASSERT(descIndex < mImageDescs.size());
412 mImageDescs[descIndex] = desc;
Geoff Lang0fe40532015-02-10 12:01:27 -0500413 mCompletenessCache.cacheValid = false;
Geoff Langa9be0dc2014-12-17 12:34:40 -0500414}
415
Geoff Lang866dd2d2015-02-10 11:08:32 -0500416void Texture::clearImageDesc(GLenum target, size_t level)
Geoff Langb9266272015-01-29 13:25:14 +0000417{
Geoff Lang866dd2d2015-02-10 11:08:32 -0500418 setImageDesc(target, level, ImageDesc());
Geoff Langb9266272015-01-29 13:25:14 +0000419}
420
Geoff Langa9be0dc2014-12-17 12:34:40 -0500421void Texture::clearImageDescs()
422{
Geoff Lang866dd2d2015-02-10 11:08:32 -0500423 for (size_t descIndex = 0; descIndex < mImageDescs.size(); descIndex++)
424 {
425 mImageDescs[descIndex] = ImageDesc();
426 }
Geoff Lang0fe40532015-02-10 12:01:27 -0500427 mCompletenessCache.cacheValid = false;
Geoff Langa9be0dc2014-12-17 12:34:40 -0500428}
429
Jamie Madillbb714f72015-05-20 10:22:18 -0400430void Texture::bindTexImageFromSurface(egl::Surface *surface)
Geoff Lang7c973ea2014-12-19 15:58:28 -0500431{
Geoff Langb9266272015-01-29 13:25:14 +0000432 ASSERT(surface);
433
Jamie Madillbb714f72015-05-20 10:22:18 -0400434 if (mBoundSurface)
435 {
436 releaseTexImageFromSurface();
437 }
438
Geoff Lang7c973ea2014-12-19 15:58:28 -0500439 mTexture->bindTexImage(surface);
440 mBoundSurface = surface;
Geoff Langb9266272015-01-29 13:25:14 +0000441
442 // Set the image info to the size and format of the surface
443 ASSERT(mTarget == GL_TEXTURE_2D);
444 Extents size(surface->getWidth(), surface->getHeight(), 1);
Geoff Langc223dc62015-01-09 13:10:01 -0500445 ImageDesc desc(size, surface->getConfig()->renderTargetFormat);
Geoff Lang866dd2d2015-02-10 11:08:32 -0500446 setImageDesc(mTarget, 0, desc);
Geoff Lang7c973ea2014-12-19 15:58:28 -0500447}
448
Jamie Madillbb714f72015-05-20 10:22:18 -0400449void Texture::releaseTexImageFromSurface()
450{
451 ASSERT(mBoundSurface);
452 mBoundSurface = nullptr;
453 mTexture->releaseTexImage();
454
455 // Erase the image info for level 0
456 ASSERT(mTarget == GL_TEXTURE_2D);
457 clearImageDesc(mTarget, 0);
458}
459
460void Texture::releaseTexImageInternal()
Geoff Lang7c973ea2014-12-19 15:58:28 -0500461{
462 if (mBoundSurface)
463 {
Jamie Madillbb714f72015-05-20 10:22:18 -0400464 // Notify the surface
465 mBoundSurface->releaseTexImageFromTexture();
Geoff Langb9266272015-01-29 13:25:14 +0000466
Jamie Madillbb714f72015-05-20 10:22:18 -0400467 // Then, call the same method as from the surface
468 releaseTexImageFromSurface();
Geoff Lang7c973ea2014-12-19 15:58:28 -0500469 }
470}
471
Geoff Langa8406172015-07-21 16:53:39 -0400472Error Texture::setEGLImageTarget(GLenum target, egl::Image *imageTarget)
473{
474 ASSERT(target == mTarget);
475 ASSERT(target == GL_TEXTURE_2D);
476
477 // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
478 releaseTexImageInternal();
479 orphanImages();
480
481 Error error = mTexture->setEGLImageTarget(target, imageTarget);
482 if (error.isError())
483 {
484 return error;
485 }
486
487 setTargetImage(imageTarget);
488
Cooper Partinc5cf9bc2015-08-06 10:46:48 -0700489 Extents size(static_cast<int>(imageTarget->getWidth()),
490 static_cast<int>(imageTarget->getHeight()), 1);
Geoff Langa8406172015-07-21 16:53:39 -0400491 GLenum internalFormat = imageTarget->getInternalFormat();
492 GLenum type = GetInternalFormatInfo(internalFormat).type;
493
494 clearImageDescs();
495 setImageDesc(target, 0, ImageDesc(size, GetSizedInternalFormat(internalFormat, type)));
496
497 return Error(GL_NO_ERROR);
498}
499
Geoff Lang691e58c2014-12-19 17:03:25 -0500500GLenum Texture::getBaseImageTarget() const
Jamie Madill22f843a2013-10-24 17:49:36 -0400501{
Geoff Lang691e58c2014-12-19 17:03:25 -0500502 return mTarget == GL_TEXTURE_CUBE_MAP ? FirstCubeMapTextureTarget : mTarget;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000503}
504
Geoff Lang0fe40532015-02-10 12:01:27 -0500505bool Texture::computeSamplerCompleteness(const SamplerState &samplerState, const Data &data) const
506{
507 const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), samplerState.baseLevel);
508 if (baseImageDesc.size.width == 0 || baseImageDesc.size.height == 0 || baseImageDesc.size.depth == 0)
509 {
510 return false;
511 }
512
513 if (mTarget == GL_TEXTURE_CUBE_MAP && baseImageDesc.size.width != baseImageDesc.size.height)
514 {
515 return false;
516 }
517
518 const TextureCaps &textureCaps = data.textureCaps->get(baseImageDesc.internalFormat);
519 if (!textureCaps.filterable && !IsPointSampled(samplerState))
520 {
521 return false;
522 }
523
524 bool npotSupport = data.extensions->textureNPOT || data.clientVersion >= 3;
525 if (!npotSupport)
526 {
527 if ((samplerState.wrapS != GL_CLAMP_TO_EDGE && !gl::isPow2(baseImageDesc.size.width)) ||
528 (samplerState.wrapT != GL_CLAMP_TO_EDGE && !gl::isPow2(baseImageDesc.size.height)))
529 {
530 return false;
531 }
532 }
533
534 if (IsMipmapFiltered(samplerState))
535 {
536 if (!npotSupport)
537 {
538 if (!gl::isPow2(baseImageDesc.size.width) || !gl::isPow2(baseImageDesc.size.height))
539 {
540 return false;
541 }
542 }
543
544 if (!computeMipmapCompleteness(samplerState))
545 {
546 return false;
547 }
548 }
549 else
550 {
551 if (mTarget == GL_TEXTURE_CUBE_MAP && !isCubeComplete())
552 {
553 return false;
554 }
555 }
556
557 // OpenGLES 3.0.2 spec section 3.8.13 states that a texture is not mipmap complete if:
558 // The internalformat specified for the texture arrays is a sized internal depth or
559 // depth and stencil format (see table 3.13), the value of TEXTURE_COMPARE_-
560 // MODE is NONE, and either the magnification filter is not NEAREST or the mini-
561 // fication filter is neither NEAREST nor NEAREST_MIPMAP_NEAREST.
562 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(baseImageDesc.internalFormat);
563 if (formatInfo.depthBits > 0 && data.clientVersion > 2)
564 {
565 if (samplerState.compareMode == GL_NONE)
566 {
567 if ((samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST) ||
568 samplerState.magFilter != GL_NEAREST)
569 {
570 return false;
571 }
572 }
573 }
574
575 return true;
576}
577
578bool Texture::computeMipmapCompleteness(const gl::SamplerState &samplerState) const
Brandon Jones6053a522014-07-25 16:22:09 -0700579{
Geoff Langa8406172015-07-21 16:53:39 -0400580 size_t expectedMipLevels = getMipCompleteLevels();
Jamie Madill19d438d2015-01-19 13:42:12 -0500581
582 size_t maxLevel = std::min<size_t>(expectedMipLevels, samplerState.maxLevel + 1);
583
584 for (size_t level = samplerState.baseLevel; level < maxLevel; level++)
Brandon Jones6053a522014-07-25 16:22:09 -0700585 {
Geoff Lang691e58c2014-12-19 17:03:25 -0500586 if (mTarget == GL_TEXTURE_CUBE_MAP)
Brandon Jones6053a522014-07-25 16:22:09 -0700587 {
Geoff Lang691e58c2014-12-19 17:03:25 -0500588 for (GLenum face = FirstCubeMapTextureTarget; face <= LastCubeMapTextureTarget; face++)
589 {
Geoff Lang0fe40532015-02-10 12:01:27 -0500590 if (!computeLevelCompleteness(face, level, samplerState))
Geoff Lang691e58c2014-12-19 17:03:25 -0500591 {
592 return false;
593 }
594 }
595 }
596 else
597 {
Geoff Lang0fe40532015-02-10 12:01:27 -0500598 if (!computeLevelCompleteness(mTarget, level, samplerState))
Geoff Lang691e58c2014-12-19 17:03:25 -0500599 {
600 return false;
601 }
Brandon Jones6053a522014-07-25 16:22:09 -0700602 }
603 }
604
605 return true;
606}
607
Geoff Lang691e58c2014-12-19 17:03:25 -0500608
Geoff Lang0fe40532015-02-10 12:01:27 -0500609bool Texture::computeLevelCompleteness(GLenum target, size_t level, const gl::SamplerState &samplerState) const
Brandon Jones6053a522014-07-25 16:22:09 -0700610{
Geoff Langa9be0dc2014-12-17 12:34:40 -0500611 ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
612
Brandon Jones6053a522014-07-25 16:22:09 -0700613 if (isImmutable())
614 {
615 return true;
616 }
617
Geoff Langb0eecdf2015-02-10 11:09:12 -0500618 const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), samplerState.baseLevel);
619 if (baseImageDesc.size.width == 0 || baseImageDesc.size.height == 0 || baseImageDesc.size.depth == 0)
Brandon Jones6053a522014-07-25 16:22:09 -0700620 {
621 return false;
622 }
623
Geoff Langa8406172015-07-21 16:53:39 -0400624 const ImageDesc &levelImageDesc = getImageDesc(target, level);
625 if (levelImageDesc.size.width == 0 || levelImageDesc.size.height == 0 ||
626 levelImageDesc.size.depth == 0)
Brandon Jones6053a522014-07-25 16:22:09 -0700627 {
Geoff Langa8406172015-07-21 16:53:39 -0400628 return false;
Brandon Jones6053a522014-07-25 16:22:09 -0700629 }
630
Geoff Langb0eecdf2015-02-10 11:09:12 -0500631 if (levelImageDesc.internalFormat != baseImageDesc.internalFormat)
Brandon Jones6053a522014-07-25 16:22:09 -0700632 {
633 return false;
634 }
635
Geoff Langb0eecdf2015-02-10 11:09:12 -0500636 if (levelImageDesc.size.width != std::max(1, baseImageDesc.size.width >> level))
Brandon Jones6053a522014-07-25 16:22:09 -0700637 {
638 return false;
639 }
640
Geoff Langb0eecdf2015-02-10 11:09:12 -0500641 if (levelImageDesc.size.height != std::max(1, baseImageDesc.size.height >> level))
Brandon Jones6053a522014-07-25 16:22:09 -0700642 {
643 return false;
644 }
645
Geoff Lang691e58c2014-12-19 17:03:25 -0500646 if (mTarget == GL_TEXTURE_3D)
Brandon Jones6053a522014-07-25 16:22:09 -0700647 {
Geoff Langb0eecdf2015-02-10 11:09:12 -0500648 if (levelImageDesc.size.depth != std::max(1, baseImageDesc.size.depth >> level))
Brandon Jones6053a522014-07-25 16:22:09 -0700649 {
650 return false;
651 }
652 }
Geoff Lang691e58c2014-12-19 17:03:25 -0500653 else if (mTarget == GL_TEXTURE_2D_ARRAY)
Brandon Jones6053a522014-07-25 16:22:09 -0700654 {
Geoff Langb0eecdf2015-02-10 11:09:12 -0500655 if (levelImageDesc.size.depth != baseImageDesc.size.depth)
Brandon Jones6053a522014-07-25 16:22:09 -0700656 {
657 return false;
658 }
659 }
660
661 return true;
662}
663
Geoff Lang0fe40532015-02-10 12:01:27 -0500664Texture::SamplerCompletenessCache::SamplerCompletenessCache()
665 : cacheValid(false),
666 samplerState(),
667 filterable(false),
668 clientVersion(0),
669 supportsNPOT(false),
670 samplerComplete(false)
671{
672}
673
Jamie Madill79481d62015-04-14 08:13:47 -0400674GLsizei Texture::getAttachmentWidth(const gl::FramebufferAttachment::Target &target) const
675{
Cooper Partinc5cf9bc2015-08-06 10:46:48 -0700676 return static_cast<GLsizei>(
677 getWidth(target.textureIndex().type, target.textureIndex().mipIndex));
Jamie Madill79481d62015-04-14 08:13:47 -0400678}
679
680GLsizei Texture::getAttachmentHeight(const gl::FramebufferAttachment::Target &target) const
681{
Cooper Partinc5cf9bc2015-08-06 10:46:48 -0700682 return static_cast<GLsizei>(
683 getHeight(target.textureIndex().type, target.textureIndex().mipIndex));
Jamie Madill79481d62015-04-14 08:13:47 -0400684}
685
686GLenum Texture::getAttachmentInternalFormat(const gl::FramebufferAttachment::Target &target) const
687{
688 return getInternalFormat(target.textureIndex().type, target.textureIndex().mipIndex);
689}
690
691GLsizei Texture::getAttachmentSamples(const gl::FramebufferAttachment::Target &/*target*/) const
692{
693 // Multisample textures not currently supported
694 return 0;
695}
696
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000697}