blob: 87327eab15dc5f7c58630f63efe37d601abafbbb [file] [log] [blame]
shannon.woods@transgaming.combdf2d802013-02-28 23:16:20 +00001#include "precompiled.h"
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00002//
Geoff Langcec35902014-04-16 10:52:36 -04003// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00004// Use of this source code is governed by a BSD-style license that can be
5// found in the LICENSE file.
6//
7
8// Texture.cpp: Implements the gl::Texture class and its derived classes
9// Texture2D and TextureCubeMap. Implements GL texture objects and related
10// functionality. [OpenGL ES 2.0.24] section 3.7 page 63.
11
12#include "libGLESv2/Texture.h"
13
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000014#include "libGLESv2/main.h"
shannonwoods@chromium.orga2ecfcc2013-05-30 00:11:59 +000015#include "common/mathutil.h"
16#include "common/utilities.h"
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +000017#include "libGLESv2/formatutils.h"
shannon.woods@transgaming.com486d9e92013-02-28 23:15:41 +000018#include "libGLESv2/Renderbuffer.h"
19#include "libGLESv2/renderer/Image.h"
20#include "libGLESv2/renderer/Renderer.h"
21#include "libGLESv2/renderer/TextureStorage.h"
22#include "libEGL/Surface.h"
Jamie Madill1beb1db2013-09-18 14:36:28 -040023#include "libGLESv2/Buffer.h"
Brandon Jonesd38f9262014-06-18 16:26:45 -070024#include "libGLESv2/renderer/BufferImpl.h"
Jamie Madill0e0510f2013-10-10 15:46:23 -040025#include "libGLESv2/renderer/RenderTarget.h"
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000026
27namespace gl
28{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000029
Jamie Madillf8989902013-07-19 16:36:58 -040030bool IsMipmapFiltered(const SamplerState &samplerState)
31{
32 switch (samplerState.minFilter)
33 {
34 case GL_NEAREST:
35 case GL_LINEAR:
36 return false;
37 case GL_NEAREST_MIPMAP_NEAREST:
38 case GL_LINEAR_MIPMAP_NEAREST:
39 case GL_NEAREST_MIPMAP_LINEAR:
40 case GL_LINEAR_MIPMAP_LINEAR:
41 return true;
42 default: UNREACHABLE();
43 return false;
44 }
45}
46
Jamie Madilld4589c92013-10-24 17:49:34 -040047bool IsRenderTargetUsage(GLenum usage)
48{
49 return (usage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
50}
51
Geoff Lang4907f2c2013-07-25 12:53:57 -040052Texture::Texture(rx::Renderer *renderer, GLuint id, GLenum target) : RefCountObject(id)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000053{
daniel@transgaming.com370482e2012-11-28 19:32:13 +000054 mRenderer = renderer;
55
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000056 mUsage = GL_NONE;
Geoff Langc82fc412013-07-10 14:43:42 -040057
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000058 mDirtyImages = true;
59
60 mImmutable = false;
Geoff Lang4907f2c2013-07-25 12:53:57 -040061
62 mTarget = target;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000063}
64
65Texture::~Texture()
66{
67}
68
Geoff Lang4907f2c2013-07-25 12:53:57 -040069GLenum Texture::getTarget() const
70{
71 return mTarget;
72}
73
Geoff Lang63b5f1f2013-09-23 14:52:14 -040074void Texture::setUsage(GLenum usage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000075{
Geoff Lang63b5f1f2013-09-23 14:52:14 -040076 mUsage = usage;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000077}
78
Brandon Jonesa328d562014-07-01 13:52:40 -070079void Texture::getSamplerStateWithNativeOffset(SamplerState *sampler)
daniel@transgaming.comebf139f2012-10-31 18:07:32 +000080{
81 *sampler = mSamplerState;
Nicolas Capens8de68282014-04-04 11:10:27 -040082
83 // Offset the effective base level by the texture storage's top level
84 rx::TextureStorageInterface *texture = getNativeTexture();
85 int topLevel = texture ? texture->getTopLevel() : 0;
86 sampler->baseLevel = topLevel + mSamplerState.baseLevel;
daniel@transgaming.com07ab8412012-07-12 15:17:09 +000087}
88
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000089GLenum Texture::getUsage() const
90{
91 return mUsage;
92}
93
Jamie Madilld3d2a342013-10-07 10:46:35 -040094GLint Texture::getBaseLevelWidth() const
95{
96 const rx::Image *baseImage = getBaseLevelImage();
97 return (baseImage ? baseImage->getWidth() : 0);
98}
99
100GLint Texture::getBaseLevelHeight() const
101{
102 const rx::Image *baseImage = getBaseLevelImage();
103 return (baseImage ? baseImage->getHeight() : 0);
104}
105
106GLint Texture::getBaseLevelDepth() const
107{
108 const rx::Image *baseImage = getBaseLevelImage();
109 return (baseImage ? baseImage->getDepth() : 0);
110}
111
Jamie Madillb8f8b892014-01-07 10:12:50 -0500112// Note: "base level image" is loosely defined to be any image from the base level,
113// where in the base of 2D array textures and cube maps there are several. Don't use
114// the base level image for anything except querying texture format and size.
Jamie Madilld3d2a342013-10-07 10:46:35 -0400115GLenum Texture::getBaseLevelInternalFormat() const
116{
117 const rx::Image *baseImage = getBaseLevelImage();
118 return (baseImage ? baseImage->getInternalFormat() : GL_NONE);
119}
120
Jamie Madill88f18f42013-09-18 14:36:19 -0400121void Texture::setImage(const PixelUnpackState &unpack, GLenum type, const void *pixels, rx::Image *image)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000122{
Jamie Madillc30003d2014-01-10 12:51:23 -0500123 // No-op
124 if (image->getWidth() == 0 || image->getHeight() == 0 || image->getDepth() == 0)
125 {
126 return;
127 }
128
Jamie Madillabef6802013-09-05 16:54:19 -0400129 // We no longer need the "GLenum format" parameter to TexImage to determine what data format "pixels" contains.
130 // From our image internal format we know how many channels to expect, and "type" gives the format of pixel's components.
Jamie Madill1beb1db2013-09-18 14:36:28 -0400131 const void *pixelData = pixels;
132
133 if (unpack.pixelBuffer.id() != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000134 {
Jamie Madill1beb1db2013-09-18 14:36:28 -0400135 // Do a CPU readback here, if we have an unpack buffer bound and the fast GPU path is not supported
136 Buffer *pixelBuffer = unpack.pixelBuffer.get();
137 ptrdiff_t offset = reinterpret_cast<ptrdiff_t>(pixels);
Brandon Jonesd38f9262014-06-18 16:26:45 -0700138 // TODO: setImage/subImage is the only place outside of renderer that asks for a buffers raw data.
139 // This functionality should be moved into renderer and the getData method of BufferImpl removed.
140 const void *bufferData = pixelBuffer->getImplementation()->getData();
Jamie Madill1beb1db2013-09-18 14:36:28 -0400141 pixelData = static_cast<const unsigned char *>(bufferData) + offset;
142 }
143
144 if (pixelData != NULL)
145 {
146 image->loadData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), unpack.alignment, type, pixelData);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000147 mDirtyImages = true;
148 }
149}
150
Geoff Lang005df412013-10-16 14:12:50 -0400151bool Texture::isFastUnpackable(const PixelUnpackState &unpack, GLenum sizedInternalFormat)
Jamie Madill8cc7d972013-10-10 15:51:55 -0400152{
153 return unpack.pixelBuffer.id() != 0 && mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat);
154}
155
Jamie Madill1beb1db2013-09-18 14:36:28 -0400156bool Texture::fastUnpackPixels(const PixelUnpackState &unpack, const void *pixels, const Box &destArea,
Jamie Madill8cc7d972013-10-10 15:51:55 -0400157 GLenum sizedInternalFormat, GLenum type, rx::RenderTarget *destRenderTarget)
Jamie Madill1beb1db2013-09-18 14:36:28 -0400158{
159 if (destArea.width <= 0 && destArea.height <= 0 && destArea.depth <= 0)
160 {
161 return true;
162 }
163
164 // In order to perform the fast copy through the shader, we must have the right format, and be able
165 // to create a render target.
Jamie Madill8cc7d972013-10-10 15:51:55 -0400166 ASSERT(mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat));
Jamie Madill1beb1db2013-09-18 14:36:28 -0400167
Jamie Madill8cc7d972013-10-10 15:51:55 -0400168 unsigned int offset = reinterpret_cast<unsigned int>(pixels);
Jamie Madill1beb1db2013-09-18 14:36:28 -0400169
Jamie Madill8cc7d972013-10-10 15:51:55 -0400170 return mRenderer->fastCopyBufferToTexture(unpack, offset, destRenderTarget, sizedInternalFormat, type, destArea);
Jamie Madill1beb1db2013-09-18 14:36:28 -0400171}
172
daniel@transgaming.com31b13e12012-11-28 19:34:30 +0000173void Texture::setCompressedImage(GLsizei imageSize, const void *pixels, rx::Image *image)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000174{
175 if (pixels != NULL)
176 {
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000177 image->loadCompressedData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000178 mDirtyImages = true;
179 }
180}
181
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000182bool Texture::subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
Jamie Madill88f18f42013-09-18 14:36:19 -0400183 GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels, rx::Image *image)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000184{
Jamie Madill065e1a32013-10-10 15:11:50 -0400185 const void *pixelData = pixels;
186
187 // CPU readback & copy where direct GPU copy is not supported
188 if (unpack.pixelBuffer.id() != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000189 {
Jamie Madill065e1a32013-10-10 15:11:50 -0400190 Buffer *pixelBuffer = unpack.pixelBuffer.get();
191 unsigned int offset = reinterpret_cast<unsigned int>(pixels);
Brandon Jonesd38f9262014-06-18 16:26:45 -0700192 // TODO: setImage/subImage is the only place outside of renderer that asks for a buffers raw data.
193 // This functionality should be moved into renderer and the getData method of BufferImpl removed.
194 const void *bufferData = pixelBuffer->getImplementation()->getData();
Jamie Madill065e1a32013-10-10 15:11:50 -0400195 pixelData = static_cast<const unsigned char *>(bufferData) + offset;
196 }
197
198 if (pixelData != NULL)
199 {
200 image->loadData(xoffset, yoffset, zoffset, width, height, depth, unpack.alignment, type, pixelData);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000201 mDirtyImages = true;
202 }
203
204 return true;
205}
206
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000207bool Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
208 GLenum format, GLsizei imageSize, const void *pixels, rx::Image *image)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000209{
210 if (pixels != NULL)
211 {
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000212 image->loadCompressedData(xoffset, yoffset, zoffset, width, height, depth, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000213 mDirtyImages = true;
214 }
215
216 return true;
217}
218
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000219rx::TextureStorageInterface *Texture::getNativeTexture()
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000220{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000221 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -0400222 initializeStorage(false);
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000223
Jamie Madill2ebab852013-10-24 17:49:42 -0400224 rx::TextureStorageInterface *storage = getBaseLevelStorage();
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000225 if (storage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000226 {
Jamie Madill169d1112013-10-24 17:49:37 -0400227 updateStorage();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000228 }
229
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000230 return storage;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000231}
232
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000233bool Texture::hasDirtyImages() const
234{
235 return mDirtyImages;
236}
237
238void Texture::resetDirty()
239{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000240 mDirtyImages = false;
241}
242
243unsigned int Texture::getTextureSerial()
244{
Jamie Madill2ebab852013-10-24 17:49:42 -0400245 rx::TextureStorageInterface *texture = getNativeTexture();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000246 return texture ? texture->getTextureSerial() : 0;
247}
248
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000249bool Texture::isImmutable() const
250{
251 return mImmutable;
252}
253
Jamie Madill51a94372013-10-24 17:49:43 -0400254int Texture::immutableLevelCount()
255{
Nicolas Capensbf712d02014-03-31 14:23:35 -0400256 return (mImmutable ? getNativeTexture()->getStorageInstance()->getLevelCount() : 0);
Jamie Madill51a94372013-10-24 17:49:43 -0400257}
258
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +0000259GLint Texture::creationLevels(GLsizei width, GLsizei height, GLsizei depth) const
260{
Geoff Langc0b9ef42014-07-02 10:02:37 -0400261 // TODO(geofflang): use context's extensions
262 if ((isPow2(width) && isPow2(height) && isPow2(depth)) || mRenderer->getRendererExtensions().textureNPOT)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000263 {
Jamie Madill6b7440c2013-10-24 17:49:47 -0400264 // Maximum number of levels
Geoff Lang98705b72014-03-31 16:00:03 -0400265 return log2(std::max(std::max(width, height), depth)) + 1;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000266 }
267 else
268 {
269 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
270 return 1;
271 }
272}
273
Jamie Madill22f843a2013-10-24 17:49:36 -0400274int Texture::mipLevels() const
275{
Geoff Lang98705b72014-03-31 16:00:03 -0400276 return log2(std::max(std::max(getBaseLevelWidth(), getBaseLevelHeight()), getBaseLevelDepth())) + 1;
Jamie Madill22f843a2013-10-24 17:49:36 -0400277}
278
Geoff Lang4907f2c2013-07-25 12:53:57 -0400279Texture2D::Texture2D(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_2D)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000280{
281 mTexStorage = NULL;
282 mSurface = NULL;
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000283
284 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
285 {
daniel@transgaming.com244e1832012-12-20 20:52:35 +0000286 mImageArray[i] = renderer->createImage();
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000287 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000288}
289
290Texture2D::~Texture2D()
291{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000292 delete mTexStorage;
293 mTexStorage = NULL;
294
295 if (mSurface)
296 {
297 mSurface->setBoundTexture(NULL);
298 mSurface = NULL;
299 }
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000300
301 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
302 {
303 delete mImageArray[i];
304 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000305}
306
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000307GLsizei Texture2D::getWidth(GLint level) const
308{
309 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000310 return mImageArray[level]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000311 else
312 return 0;
313}
314
315GLsizei Texture2D::getHeight(GLint level) const
316{
317 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000318 return mImageArray[level]->getHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000319 else
320 return 0;
321}
322
323GLenum Texture2D::getInternalFormat(GLint level) const
324{
325 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000326 return mImageArray[level]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000327 else
328 return GL_NONE;
329}
330
daniel@transgaming.com20d36662012-10-31 19:51:43 +0000331GLenum Texture2D::getActualFormat(GLint level) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000332{
333 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000334 return mImageArray[level]->getActualFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000335 else
Geoff Langcbf727a2014-02-10 12:50:45 -0500336 return GL_NONE;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000337}
338
Geoff Lang005df412013-10-16 14:12:50 -0400339void Texture2D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000340{
341 releaseTexImage();
shannon.woods@transgaming.com8a406682013-02-28 23:15:26 +0000342
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000343 // If there currently is a corresponding storage texture image, it has these parameters
Jamie Madilld3d2a342013-10-07 10:46:35 -0400344 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
345 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
Geoff Lang005df412013-10-16 14:12:50 -0400346 const GLenum storageFormat = getBaseLevelInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000347
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000348 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, width, height, 1, false);
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000349
350 if (mTexStorage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000351 {
Nicolas Capensbf712d02014-03-31 14:23:35 -0400352 const int storageLevels = mTexStorage->getLevelCount();
353
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000354 if ((level >= storageLevels && storageLevels != 0) ||
355 width != storageWidth ||
356 height != storageHeight ||
357 internalformat != storageFormat) // Discard mismatched storage
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000358 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000359 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
360 {
361 mImageArray[i]->markDirty();
362 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000363
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000364 delete mTexStorage;
365 mTexStorage = NULL;
366 mDirtyImages = true;
367 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000368 }
369}
370
Geoff Lang005df412013-10-16 14:12:50 -0400371void Texture2D::setImage(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000372{
Geoff Lange4a492b2014-06-19 14:14:41 -0400373 GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat) ? internalFormat
374 : GetSizedInternalFormat(format, type);
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +0000375 redefineImage(level, sizedInternalFormat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000376
Jamie Madill8cc7d972013-10-10 15:51:55 -0400377 bool fastUnpacked = false;
378
Jamie Madill1beb1db2013-09-18 14:36:28 -0400379 // Attempt a fast gpu copy of the pixel data to the surface
Jamie Madill8cc7d972013-10-10 15:51:55 -0400380 if (isFastUnpackable(unpack, sizedInternalFormat) && isLevelComplete(level))
Jamie Madill1beb1db2013-09-18 14:36:28 -0400381 {
Jamie Madill8cc7d972013-10-10 15:51:55 -0400382 // Will try to create RT storage if it does not exist
383 rx::RenderTarget *destRenderTarget = getRenderTarget(level);
384 Box destArea(0, 0, 0, getWidth(level), getHeight(level), 1);
385
386 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget))
387 {
388 // Ensure we don't overwrite our newly initialized data
389 mImageArray[level]->markClean();
390
391 fastUnpacked = true;
392 }
Jamie Madill1beb1db2013-09-18 14:36:28 -0400393 }
Jamie Madill8cc7d972013-10-10 15:51:55 -0400394
395 if (!fastUnpacked)
Jamie Madill1beb1db2013-09-18 14:36:28 -0400396 {
397 Texture::setImage(unpack, type, pixels, mImageArray[level]);
398 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000399}
400
401void Texture2D::bindTexImage(egl::Surface *surface)
402{
403 releaseTexImage();
404
Geoff Lang005df412013-10-16 14:12:50 -0400405 GLenum internalformat = surface->getFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000406
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000407 mImageArray[0]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, surface->getWidth(), surface->getHeight(), 1, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000408
409 delete mTexStorage;
daniel@transgaming.comd8353dd2012-12-20 21:11:14 +0000410 mTexStorage = new rx::TextureStorageInterface2D(mRenderer, surface->getSwapChain());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000411
412 mDirtyImages = true;
413 mSurface = surface;
414 mSurface->setBoundTexture(this);
415}
416
417void Texture2D::releaseTexImage()
418{
419 if (mSurface)
420 {
421 mSurface->setBoundTexture(NULL);
422 mSurface = NULL;
423
424 if (mTexStorage)
425 {
426 delete mTexStorage;
427 mTexStorage = NULL;
428 }
429
430 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
431 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000432 mImageArray[i]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000433 }
434 }
435}
436
437void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
438{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000439 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000440 redefineImage(level, format, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000441
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000442 Texture::setCompressedImage(imageSize, pixels, mImageArray[level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000443}
444
445void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
446{
Jamie Madill07bb8cf2013-10-24 17:49:44 -0400447 if (isValidLevel(level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000448 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000449 rx::Image *image = mImageArray[level];
Jamie Madill169d1112013-10-24 17:49:37 -0400450 if (image->copyToStorage(mTexStorage, level, xoffset, yoffset, width, height))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000451 {
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000452 image->markClean();
453 }
454 }
455}
456
Jamie Madill88f18f42013-09-18 14:36:19 -0400457void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000458{
Jamie Madill065e1a32013-10-10 15:11:50 -0400459 bool fastUnpacked = false;
460
461 if (isFastUnpackable(unpack, getInternalFormat(level)) && isLevelComplete(level))
462 {
463 rx::RenderTarget *renderTarget = getRenderTarget(level);
464 Box destArea(xoffset, yoffset, 0, width, height, 1);
465
466 if (renderTarget && fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, renderTarget))
467 {
468 // Ensure we don't overwrite our newly initialized data
469 mImageArray[level]->markClean();
470
471 fastUnpacked = true;
472 }
473 }
474
475 if (!fastUnpacked && Texture::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, mImageArray[level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000476 {
477 commitRect(level, xoffset, yoffset, width, height);
478 }
479}
480
481void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
482{
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000483 if (Texture::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000484 {
485 commitRect(level, xoffset, yoffset, width, height);
486 }
487}
488
489void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
490{
Geoff Lange4a492b2014-06-19 14:14:41 -0400491 GLenum sizedInternalFormat = IsSizedInternalFormat(format) ? format
492 : GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +0000493 redefineImage(level, sizedInternalFormat, width, height);
shannon.woods@transgaming.com8a406682013-02-28 23:15:26 +0000494
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000495 if (!mImageArray[level]->isRenderableFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000496 {
shannon.woods%transgaming.com@gtempaccount.come5dcce72013-04-13 03:44:33 +0000497 mImageArray[level]->copy(0, 0, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000498 mDirtyImages = true;
499 }
500 else
501 {
Jamie Madille83d1a92013-10-24 17:49:33 -0400502 ensureRenderTarget();
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000503 mImageArray[level]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000504
Jamie Madill07bb8cf2013-10-24 17:49:44 -0400505 if (width != 0 && height != 0 && isValidLevel(level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000506 {
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +0000507 gl::Rectangle sourceRect;
508 sourceRect.x = x;
509 sourceRect.width = width;
510 sourceRect.y = y;
511 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000512
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +0000513 mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000514 }
515 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000516}
517
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +0000518void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000519{
Jamie Madill07edd442013-07-19 16:36:58 -0400520 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
521 // the current level we're copying to is defined (with appropriate format, width & height)
522 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
523
524 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000525 {
shannon.woods%transgaming.com@gtempaccount.come5dcce72013-04-13 03:44:33 +0000526 mImageArray[level]->copy(xoffset, yoffset, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000527 mDirtyImages = true;
528 }
529 else
530 {
Jamie Madille83d1a92013-10-24 17:49:33 -0400531 ensureRenderTarget();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000532
Jamie Madill07bb8cf2013-10-24 17:49:44 -0400533 if (isValidLevel(level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000534 {
Jamie Madill169d1112013-10-24 17:49:37 -0400535 updateStorageLevel(level);
Jamie Madill07edd442013-07-19 16:36:58 -0400536
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +0000537 gl::Rectangle sourceRect;
538 sourceRect.x = x;
539 sourceRect.width = width;
540 sourceRect.y = y;
541 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000542
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +0000543 mRenderer->copyImage(source, sourceRect,
Geoff Lange4a492b2014-06-19 14:14:41 -0400544 gl::GetFormat(getBaseLevelInternalFormat()),
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +0000545 xoffset, yoffset, mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000546 }
547 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000548}
549
550void Texture2D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height)
551{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000552 for (int level = 0; level < levels; level++)
553 {
Jamie Madill73b5d062013-10-24 17:49:38 -0400554 GLsizei levelWidth = std::max(1, width >> level);
555 GLsizei levelHeight = std::max(1, height >> level);
556 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, levelWidth, levelHeight, 1, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000557 }
558
559 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
560 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000561 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000562 }
563
Jamie Madill73b5d062013-10-24 17:49:38 -0400564 mImmutable = true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000565
Nicolas Capensbf712d02014-03-31 14:23:35 -0400566 setCompleteTexStorage(new rx::TextureStorageInterface2D(mRenderer, internalformat, IsRenderTargetUsage(mUsage), width, height, levels));
Jamie Madill73b5d062013-10-24 17:49:38 -0400567}
568
569void Texture2D::setCompleteTexStorage(rx::TextureStorageInterface2D *newCompleteTexStorage)
570{
571 SafeDelete(mTexStorage);
572 mTexStorage = newCompleteTexStorage;
573
574 if (mTexStorage && mTexStorage->isManaged())
575 {
Nicolas Capensbf712d02014-03-31 14:23:35 -0400576 for (int level = 0; level < mTexStorage->getLevelCount(); level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000577 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000578 mImageArray[level]->setManagedSurface(mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000579 }
580 }
Jamie Madill73b5d062013-10-24 17:49:38 -0400581
582 mDirtyImages = true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000583}
584
585// Tests for 2D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85.
Jamie Madillf8989902013-07-19 16:36:58 -0400586bool Texture2D::isSamplerComplete(const SamplerState &samplerState) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000587{
Jamie Madilld3d2a342013-10-07 10:46:35 -0400588 GLsizei width = getBaseLevelWidth();
589 GLsizei height = getBaseLevelHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000590
591 if (width <= 0 || height <= 0)
592 {
593 return false;
594 }
595
Geoff Langc0b9ef42014-07-02 10:02:37 -0400596 // TODO(geofflang): use context's texture caps
597 if (!mRenderer->getRendererTextureCaps().get(getInternalFormat(0)).filtering)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000598 {
Jamie Madillf8989902013-07-19 16:36:58 -0400599 if (samplerState.magFilter != GL_NEAREST ||
600 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000601 {
602 return false;
603 }
604 }
605
Geoff Langc0b9ef42014-07-02 10:02:37 -0400606 // TODO(geofflang): use context's extensions
607 bool npotSupport = mRenderer->getRendererExtensions().textureNPOT;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000608
609 if (!npotSupport)
610 {
Jamie Madillf8989902013-07-19 16:36:58 -0400611 if ((samplerState.wrapS != GL_CLAMP_TO_EDGE && !isPow2(width)) ||
612 (samplerState.wrapT != GL_CLAMP_TO_EDGE && !isPow2(height)))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000613 {
614 return false;
615 }
616 }
617
Jamie Madillf8989902013-07-19 16:36:58 -0400618 if (IsMipmapFiltered(samplerState))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000619 {
620 if (!npotSupport)
621 {
622 if (!isPow2(width) || !isPow2(height))
623 {
624 return false;
625 }
626 }
627
628 if (!isMipmapComplete())
629 {
630 return false;
631 }
632 }
633
Geoff Langc82fc412013-07-10 14:43:42 -0400634 // OpenGLES 3.0.2 spec section 3.8.13 states that a texture is not mipmap complete if:
635 // The internalformat specified for the texture arrays is a sized internal depth or
636 // depth and stencil format (see table 3.13), the value of TEXTURE_COMPARE_-
637 // MODE is NONE, and either the magnification filter is not NEAREST or the mini-
638 // fication filter is neither NEAREST nor NEAREST_MIPMAP_NEAREST.
Geoff Lange4a492b2014-06-19 14:14:41 -0400639 if (gl::GetDepthBits(getInternalFormat(0)) > 0 && mRenderer->getCurrentClientVersion() > 2)
Geoff Langc82fc412013-07-10 14:43:42 -0400640 {
641 if (mSamplerState.compareMode == GL_NONE)
642 {
643 if ((mSamplerState.minFilter != GL_NEAREST && mSamplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST) ||
644 mSamplerState.magFilter != GL_NEAREST)
645 {
646 return false;
647 }
648 }
649 }
650
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000651 return true;
652}
653
654// Tests for 2D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
655bool Texture2D::isMipmapComplete() const
656{
Geoff Lang98705b72014-03-31 16:00:03 -0400657 int levelCount = mipLevels();
Jamie Madill07edd442013-07-19 16:36:58 -0400658
Geoff Lang98705b72014-03-31 16:00:03 -0400659 for (int level = 0; level < levelCount; level++)
Jamie Madill07edd442013-07-19 16:36:58 -0400660 {
661 if (!isLevelComplete(level))
662 {
663 return false;
664 }
665 }
666
667 return true;
668}
669
670bool Texture2D::isLevelComplete(int level) const
671{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000672 if (isImmutable())
673 {
674 return true;
675 }
676
Jamie Madill648c9682014-01-21 16:50:58 -0500677 const rx::Image *baseImage = getBaseLevelImage();
678
679 GLsizei width = baseImage->getWidth();
680 GLsizei height = baseImage->getHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000681
682 if (width <= 0 || height <= 0)
683 {
684 return false;
685 }
686
Jamie Madill07edd442013-07-19 16:36:58 -0400687 // The base image level is complete if the width and height are positive
688 if (level == 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000689 {
Jamie Madill07edd442013-07-19 16:36:58 -0400690 return true;
691 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000692
Jamie Madill07edd442013-07-19 16:36:58 -0400693 ASSERT(level >= 1 && level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
694 rx::Image *image = mImageArray[level];
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000695
Jamie Madill648c9682014-01-21 16:50:58 -0500696 if (image->getInternalFormat() != baseImage->getInternalFormat())
Jamie Madill07edd442013-07-19 16:36:58 -0400697 {
698 return false;
699 }
700
701 if (image->getWidth() != std::max(1, width >> level))
702 {
703 return false;
704 }
705
706 if (image->getHeight() != std::max(1, height >> level))
707 {
708 return false;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000709 }
710
711 return true;
712}
713
714bool Texture2D::isCompressed(GLint level) const
715{
Geoff Lange4a492b2014-06-19 14:14:41 -0400716 return IsFormatCompressed(getInternalFormat(level));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000717}
718
719bool Texture2D::isDepth(GLint level) const
720{
Geoff Lange4a492b2014-06-19 14:14:41 -0400721 return GetDepthBits(getInternalFormat(level)) > 0;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000722}
723
daniel@transgaming.comf032cb82012-10-31 19:51:52 +0000724// Constructs a native texture resource from the texture images
Jamie Madill73b5d062013-10-24 17:49:38 -0400725void Texture2D::initializeStorage(bool renderTarget)
726{
727 // Only initialize the first time this texture is used as a render target or shader resource
728 if (mTexStorage)
729 {
730 return;
731 }
732
733 // do not attempt to create storage for nonexistant data
734 if (!isLevelComplete(0))
735 {
736 return;
737 }
738
739 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
740
741 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
742 ASSERT(mTexStorage);
743
744 // flush image data to the storage
745 updateStorage();
746}
747
748rx::TextureStorageInterface2D *Texture2D::createCompleteStorage(bool renderTarget) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000749{
Jamie Madilld3d2a342013-10-07 10:46:35 -0400750 GLsizei width = getBaseLevelWidth();
751 GLsizei height = getBaseLevelHeight();
daniel@transgaming.come6a09842012-09-17 21:28:55 +0000752
Jamie Madill73b5d062013-10-24 17:49:38 -0400753 ASSERT(width > 0 && height > 0);
daniel@transgaming.come6a09842012-09-17 21:28:55 +0000754
Jamie Madill73b5d062013-10-24 17:49:38 -0400755 // use existing storage level count, when previously specified by TexStorage*D
Nicolas Capensbf712d02014-03-31 14:23:35 -0400756 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000757
Nicolas Capensbf712d02014-03-31 14:23:35 -0400758 return new rx::TextureStorageInterface2D(mRenderer, getBaseLevelInternalFormat(), renderTarget, width, height, levels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000759}
760
Jamie Madill169d1112013-10-24 17:49:37 -0400761void Texture2D::updateStorage()
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000762{
Geoff Lang946b9482014-05-12 16:37:25 -0400763 ASSERT(mTexStorage != NULL);
764 GLint storageLevels = mTexStorage->getLevelCount();
765 for (int level = 0; level < storageLevels; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000766 {
Jamie Madill648c9682014-01-21 16:50:58 -0500767 if (mImageArray[level]->isDirty() && isLevelComplete(level))
Jamie Madilld9b9a502013-10-10 17:46:13 -0400768 {
Jamie Madill169d1112013-10-24 17:49:37 -0400769 updateStorageLevel(level);
Jamie Madilld9b9a502013-10-10 17:46:13 -0400770 }
Jamie Madill07edd442013-07-19 16:36:58 -0400771 }
772}
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000773
Jamie Madill169d1112013-10-24 17:49:37 -0400774void Texture2D::updateStorageLevel(int level)
Jamie Madill07edd442013-07-19 16:36:58 -0400775{
776 ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
Jamie Madillaee7ad82013-10-10 16:07:32 -0400777 ASSERT(isLevelComplete(level));
Jamie Madill07edd442013-07-19 16:36:58 -0400778
Jamie Madillaee7ad82013-10-10 16:07:32 -0400779 if (mImageArray[level]->isDirty())
Jamie Madill07edd442013-07-19 16:36:58 -0400780 {
Jamie Madillaee7ad82013-10-10 16:07:32 -0400781 commitRect(level, 0, 0, getWidth(level), getHeight(level));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000782 }
783}
784
Jamie Madille83d1a92013-10-24 17:49:33 -0400785bool Texture2D::ensureRenderTarget()
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000786{
Jamie Madill73b5d062013-10-24 17:49:38 -0400787 initializeStorage(true);
788
789 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0)
Jamie Madille83d1a92013-10-24 17:49:33 -0400790 {
Jamie Madill73b5d062013-10-24 17:49:38 -0400791 ASSERT(mTexStorage);
792 if (!mTexStorage->isRenderTarget())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000793 {
Jamie Madill73b5d062013-10-24 17:49:38 -0400794 rx::TextureStorageInterface2D *newRenderTargetStorage = createCompleteStorage(true);
795
796 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
797 {
798 delete newRenderTargetStorage;
Jamie Madille83d1a92013-10-24 17:49:33 -0400799 return gl::error(GL_OUT_OF_MEMORY, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000800 }
Jamie Madill73b5d062013-10-24 17:49:38 -0400801
802 setCompleteTexStorage(newRenderTargetStorage);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000803 }
804 }
805
Jamie Madille83d1a92013-10-24 17:49:33 -0400806 return (mTexStorage && mTexStorage->isRenderTarget());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000807}
808
809void Texture2D::generateMipmaps()
810{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000811 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Geoff Lang98705b72014-03-31 16:00:03 -0400812 int levelCount = mipLevels();
813 for (int level = 1; level < levelCount; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000814 {
Jamie Madill22f843a2013-10-24 17:49:36 -0400815 redefineImage(level, getBaseLevelInternalFormat(),
816 std::max(getBaseLevelWidth() >> level, 1),
817 std::max(getBaseLevelHeight() >> level, 1));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000818 }
819
820 if (mTexStorage && mTexStorage->isRenderTarget())
821 {
Geoff Lang98705b72014-03-31 16:00:03 -0400822 for (int level = 1; level < levelCount; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000823 {
Jamie Madill22f843a2013-10-24 17:49:36 -0400824 mTexStorage->generateMipmap(level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000825
Jamie Madill22f843a2013-10-24 17:49:36 -0400826 mImageArray[level]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000827 }
828 }
829 else
830 {
Geoff Lang98705b72014-03-31 16:00:03 -0400831 for (int level = 1; level < levelCount; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000832 {
Jamie Madill22f843a2013-10-24 17:49:36 -0400833 mRenderer->generateMipmap(mImageArray[level], mImageArray[level - 1]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000834 }
835 }
836}
837
Jamie Madilld3d2a342013-10-07 10:46:35 -0400838const rx::Image *Texture2D::getBaseLevelImage() const
839{
840 return mImageArray[0];
841}
842
Jamie Madill2ebab852013-10-24 17:49:42 -0400843rx::TextureStorageInterface *Texture2D::getBaseLevelStorage()
844{
845 return mTexStorage;
846}
847
Geoff Lang8040f572013-07-25 16:49:54 -0400848unsigned int Texture2D::getRenderTargetSerial(GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000849{
Jamie Madille83d1a92013-10-24 17:49:33 -0400850 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(level) : 0);
Geoff Lang8040f572013-07-25 16:49:54 -0400851}
852
853rx::RenderTarget *Texture2D::getRenderTarget(GLint level)
854{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000855 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -0400856 if (!ensureRenderTarget())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000857 {
858 return NULL;
859 }
860
Jamie Madill169d1112013-10-24 17:49:37 -0400861 updateStorageLevel(level);
Geoff Lang8040f572013-07-25 16:49:54 -0400862
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000863 // ensure this is NOT a depth texture
Geoff Lang8040f572013-07-25 16:49:54 -0400864 if (isDepth(level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000865 {
866 return NULL;
867 }
daniel@transgaming.com34da3972012-12-20 21:10:29 +0000868
Geoff Lang8040f572013-07-25 16:49:54 -0400869 return mTexStorage->getRenderTarget(level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000870}
871
Geoff Lang8040f572013-07-25 16:49:54 -0400872rx::RenderTarget *Texture2D::getDepthSencil(GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000873{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000874 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -0400875 if (!ensureRenderTarget())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000876 {
877 return NULL;
878 }
879
Jamie Madill169d1112013-10-24 17:49:37 -0400880 updateStorageLevel(level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000881
882 // ensure this is actually a depth texture
Geoff Lang8040f572013-07-25 16:49:54 -0400883 if (!isDepth(level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000884 {
885 return NULL;
886 }
Geoff Lang8040f572013-07-25 16:49:54 -0400887
888 return mTexStorage->getRenderTarget(level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000889}
890
Jamie Madill07bb8cf2013-10-24 17:49:44 -0400891bool Texture2D::isValidLevel(int level) const
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +0000892{
Nicolas Capensbf712d02014-03-31 14:23:35 -0400893 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : false);
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +0000894}
895
Geoff Lang4907f2c2013-07-25 12:53:57 -0400896TextureCubeMap::TextureCubeMap(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_CUBE_MAP)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000897{
898 mTexStorage = NULL;
899 for (int i = 0; i < 6; i++)
900 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000901 for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
902 {
daniel@transgaming.com244e1832012-12-20 20:52:35 +0000903 mImageArray[i][j] = renderer->createImage();
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000904 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000905 }
906}
907
908TextureCubeMap::~TextureCubeMap()
909{
910 for (int i = 0; i < 6; i++)
911 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000912 for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
913 {
914 delete mImageArray[i][j];
915 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000916 }
917
918 delete mTexStorage;
919 mTexStorage = NULL;
920}
921
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000922GLsizei TextureCubeMap::getWidth(GLenum target, GLint level) const
923{
924 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Jamie Madill2db197c2013-10-24 17:49:35 -0400925 return mImageArray[targetToIndex(target)][level]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000926 else
927 return 0;
928}
929
930GLsizei TextureCubeMap::getHeight(GLenum target, GLint level) const
931{
932 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Jamie Madill2db197c2013-10-24 17:49:35 -0400933 return mImageArray[targetToIndex(target)][level]->getHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000934 else
935 return 0;
936}
937
938GLenum TextureCubeMap::getInternalFormat(GLenum target, GLint level) const
939{
940 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Jamie Madill2db197c2013-10-24 17:49:35 -0400941 return mImageArray[targetToIndex(target)][level]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000942 else
943 return GL_NONE;
944}
945
daniel@transgaming.com20d36662012-10-31 19:51:43 +0000946GLenum TextureCubeMap::getActualFormat(GLenum target, GLint level) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000947{
948 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Jamie Madill2db197c2013-10-24 17:49:35 -0400949 return mImageArray[targetToIndex(target)][level]->getActualFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000950 else
Geoff Langcbf727a2014-02-10 12:50:45 -0500951 return GL_NONE;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000952}
953
Geoff Lang005df412013-10-16 14:12:50 -0400954void TextureCubeMap::setImagePosX(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000955{
Jamie Madill88f18f42013-09-18 14:36:19 -0400956 setImage(0, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000957}
958
Geoff Lang005df412013-10-16 14:12:50 -0400959void TextureCubeMap::setImageNegX(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000960{
Jamie Madill88f18f42013-09-18 14:36:19 -0400961 setImage(1, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000962}
963
Geoff Lang005df412013-10-16 14:12:50 -0400964void TextureCubeMap::setImagePosY(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000965{
Jamie Madill88f18f42013-09-18 14:36:19 -0400966 setImage(2, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000967}
968
Geoff Lang005df412013-10-16 14:12:50 -0400969void TextureCubeMap::setImageNegY(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000970{
Jamie Madill88f18f42013-09-18 14:36:19 -0400971 setImage(3, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000972}
973
Geoff Lang005df412013-10-16 14:12:50 -0400974void TextureCubeMap::setImagePosZ(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000975{
Jamie Madill88f18f42013-09-18 14:36:19 -0400976 setImage(4, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000977}
978
Geoff Lang005df412013-10-16 14:12:50 -0400979void TextureCubeMap::setImageNegZ(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000980{
Jamie Madill88f18f42013-09-18 14:36:19 -0400981 setImage(5, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000982}
983
Jamie Madill2db197c2013-10-24 17:49:35 -0400984void TextureCubeMap::setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000985{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000986 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
Jamie Madill2db197c2013-10-24 17:49:35 -0400987 int faceIndex = targetToIndex(target);
988 redefineImage(faceIndex, level, format, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000989
Jamie Madill2db197c2013-10-24 17:49:35 -0400990 Texture::setCompressedImage(imageSize, pixels, mImageArray[faceIndex][level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000991}
992
Jamie Madill2db197c2013-10-24 17:49:35 -0400993void TextureCubeMap::commitRect(int faceIndex, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000994{
Jamie Madill07bb8cf2013-10-24 17:49:44 -0400995 if (isValidFaceLevel(faceIndex, level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000996 {
Jamie Madill2db197c2013-10-24 17:49:35 -0400997 rx::Image *image = mImageArray[faceIndex][level];
Jamie Madill169d1112013-10-24 17:49:37 -0400998 if (image->copyToStorage(mTexStorage, faceIndex, level, xoffset, yoffset, width, height))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000999 image->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001000 }
1001}
1002
Jamie Madill88f18f42013-09-18 14:36:19 -04001003void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001004{
Jamie Madill2db197c2013-10-24 17:49:35 -04001005 int faceIndex = targetToIndex(target);
1006 if (Texture::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, mImageArray[faceIndex][level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001007 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001008 commitRect(faceIndex, level, xoffset, yoffset, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001009 }
1010}
1011
1012void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1013{
Jamie Madill2db197c2013-10-24 17:49:35 -04001014 int faceIndex = targetToIndex(target);
1015 if (Texture::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[faceIndex][level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001016 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001017 commitRect(faceIndex, level, xoffset, yoffset, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001018 }
1019}
1020
1021// Tests for cube map sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 86.
Jamie Madillf8989902013-07-19 16:36:58 -04001022bool TextureCubeMap::isSamplerComplete(const SamplerState &samplerState) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001023{
Jamie Madilld3d2a342013-10-07 10:46:35 -04001024 int size = getBaseLevelWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001025
Jamie Madillf8989902013-07-19 16:36:58 -04001026 bool mipmapping = IsMipmapFiltered(samplerState);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001027
Geoff Langc0b9ef42014-07-02 10:02:37 -04001028 // TODO(geofflang): use context's texture caps
1029 if (!mRenderer->getRendererTextureCaps().get(getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0)).filtering)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001030 {
Jamie Madillf8989902013-07-19 16:36:58 -04001031 if (samplerState.magFilter != GL_NEAREST ||
1032 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001033 {
1034 return false;
1035 }
1036 }
1037
Geoff Langc0b9ef42014-07-02 10:02:37 -04001038 // TODO(geofflang): use context's extensions
1039 if (!isPow2(size) && !mRenderer->getRendererExtensions().textureNPOT)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001040 {
Jamie Madillf8989902013-07-19 16:36:58 -04001041 if (samplerState.wrapS != GL_CLAMP_TO_EDGE || samplerState.wrapT != GL_CLAMP_TO_EDGE || mipmapping)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001042 {
1043 return false;
1044 }
1045 }
1046
1047 if (!mipmapping)
1048 {
1049 if (!isCubeComplete())
1050 {
1051 return false;
1052 }
1053 }
1054 else
1055 {
1056 if (!isMipmapCubeComplete()) // Also tests for isCubeComplete()
1057 {
1058 return false;
1059 }
1060 }
1061
1062 return true;
1063}
1064
1065// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1066bool TextureCubeMap::isCubeComplete() const
1067{
Jamie Madillc1f8b162013-10-07 10:46:38 -04001068 int baseWidth = getBaseLevelWidth();
1069 int baseHeight = getBaseLevelHeight();
1070 GLenum baseFormat = getBaseLevelInternalFormat();
1071
1072 if (baseWidth <= 0 || baseWidth != baseHeight)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001073 {
1074 return false;
1075 }
1076
Jamie Madill2db197c2013-10-24 17:49:35 -04001077 for (int faceIndex = 1; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001078 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001079 const rx::Image &faceBaseImage = *mImageArray[faceIndex][0];
Jamie Madillc1f8b162013-10-07 10:46:38 -04001080
1081 if (faceBaseImage.getWidth() != baseWidth ||
1082 faceBaseImage.getHeight() != baseHeight ||
1083 faceBaseImage.getInternalFormat() != baseFormat )
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001084 {
1085 return false;
1086 }
1087 }
1088
1089 return true;
1090}
1091
1092bool TextureCubeMap::isMipmapCubeComplete() const
1093{
1094 if (isImmutable())
1095 {
1096 return true;
1097 }
1098
1099 if (!isCubeComplete())
1100 {
1101 return false;
1102 }
1103
Geoff Lang98705b72014-03-31 16:00:03 -04001104 int levelCount = mipLevels();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001105
1106 for (int face = 0; face < 6; face++)
1107 {
Geoff Lang98705b72014-03-31 16:00:03 -04001108 for (int level = 1; level < levelCount; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001109 {
Jamie Madill07edd442013-07-19 16:36:58 -04001110 if (!isFaceLevelComplete(face, level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001111 {
1112 return false;
1113 }
1114 }
1115 }
1116
1117 return true;
1118}
1119
Jamie Madill2db197c2013-10-24 17:49:35 -04001120bool TextureCubeMap::isFaceLevelComplete(int faceIndex, int level) const
Jamie Madill07edd442013-07-19 16:36:58 -04001121{
Jamie Madill2db197c2013-10-24 17:49:35 -04001122 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
Jamie Madill07edd442013-07-19 16:36:58 -04001123
1124 if (isImmutable())
1125 {
1126 return true;
1127 }
1128
Jamie Madilld3d2a342013-10-07 10:46:35 -04001129 int baseSize = getBaseLevelWidth();
Jamie Madill07edd442013-07-19 16:36:58 -04001130
Jamie Madilld3d2a342013-10-07 10:46:35 -04001131 if (baseSize <= 0)
Jamie Madill07edd442013-07-19 16:36:58 -04001132 {
1133 return false;
1134 }
1135
Jamie Madilld3d2a342013-10-07 10:46:35 -04001136 // "isCubeComplete" checks for base level completeness and we must call that
1137 // to determine if any face at level 0 is complete. We omit that check here
1138 // to avoid re-checking cube-completeness for every face at level 0.
Jamie Madill07edd442013-07-19 16:36:58 -04001139 if (level == 0)
1140 {
1141 return true;
1142 }
1143
Jamie Madilld3d2a342013-10-07 10:46:35 -04001144 // Check that non-zero levels are consistent with the base level.
Jamie Madill2db197c2013-10-24 17:49:35 -04001145 const rx::Image *faceLevelImage = mImageArray[faceIndex][level];
Jamie Madill07edd442013-07-19 16:36:58 -04001146
Jamie Madilld3d2a342013-10-07 10:46:35 -04001147 if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat())
Jamie Madill07edd442013-07-19 16:36:58 -04001148 {
1149 return false;
1150 }
1151
Jamie Madilld3d2a342013-10-07 10:46:35 -04001152 if (faceLevelImage->getWidth() != std::max(1, baseSize >> level))
Jamie Madill07edd442013-07-19 16:36:58 -04001153 {
1154 return false;
1155 }
1156
1157 return true;
1158}
1159
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001160bool TextureCubeMap::isCompressed(GLenum target, GLint level) const
1161{
Geoff Lange4a492b2014-06-19 14:14:41 -04001162 return IsFormatCompressed(getInternalFormat(target, level));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001163}
1164
Geoff Lang8040f572013-07-25 16:49:54 -04001165bool TextureCubeMap::isDepth(GLenum target, GLint level) const
1166{
Geoff Lange4a492b2014-06-19 14:14:41 -04001167 return GetDepthBits(getInternalFormat(target, level)) > 0;
Geoff Lang8040f572013-07-25 16:49:54 -04001168}
1169
Jamie Madill73b5d062013-10-24 17:49:38 -04001170void TextureCubeMap::initializeStorage(bool renderTarget)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001171{
Jamie Madill3c0989c2013-10-24 17:49:39 -04001172 // Only initialize the first time this texture is used as a render target or shader resource
1173 if (mTexStorage)
1174 {
1175 return;
1176 }
1177
1178 // do not attempt to create storage for nonexistant data
1179 if (!isFaceLevelComplete(0, 0))
1180 {
1181 return;
1182 }
1183
1184 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
1185
1186 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
1187 ASSERT(mTexStorage);
1188
1189 // flush image data to the storage
1190 updateStorage();
1191}
1192
1193rx::TextureStorageInterfaceCube *TextureCubeMap::createCompleteStorage(bool renderTarget) const
1194{
Jamie Madilld3d2a342013-10-07 10:46:35 -04001195 GLsizei size = getBaseLevelWidth();
daniel@transgaming.come6a09842012-09-17 21:28:55 +00001196
Jamie Madill3c0989c2013-10-24 17:49:39 -04001197 ASSERT(size > 0);
daniel@transgaming.come6a09842012-09-17 21:28:55 +00001198
Jamie Madill3c0989c2013-10-24 17:49:39 -04001199 // use existing storage level count, when previously specified by TexStorage*D
Nicolas Capensbf712d02014-03-31 14:23:35 -04001200 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(size, size, 1));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001201
Nicolas Capensbf712d02014-03-31 14:23:35 -04001202 return new rx::TextureStorageInterfaceCube(mRenderer, getBaseLevelInternalFormat(), renderTarget, size, levels);
Jamie Madill3c0989c2013-10-24 17:49:39 -04001203}
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001204
Jamie Madill3c0989c2013-10-24 17:49:39 -04001205void TextureCubeMap::setCompleteTexStorage(rx::TextureStorageInterfaceCube *newCompleteTexStorage)
1206{
1207 SafeDelete(mTexStorage);
1208 mTexStorage = newCompleteTexStorage;
1209
1210 if (mTexStorage && mTexStorage->isManaged())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001211 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001212 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001213 {
Nicolas Capensbf712d02014-03-31 14:23:35 -04001214 for (int level = 0; level < mTexStorage->getLevelCount(); level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001215 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001216 mImageArray[faceIndex][level]->setManagedSurface(mTexStorage, faceIndex, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001217 }
1218 }
1219 }
1220
1221 mDirtyImages = true;
1222}
1223
Jamie Madill169d1112013-10-24 17:49:37 -04001224void TextureCubeMap::updateStorage()
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001225{
Geoff Lang946b9482014-05-12 16:37:25 -04001226 ASSERT(mTexStorage != NULL);
1227 GLint storageLevels = mTexStorage->getLevelCount();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001228 for (int face = 0; face < 6; face++)
1229 {
Geoff Lang946b9482014-05-12 16:37:25 -04001230 for (int level = 0; level < storageLevels; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001231 {
Geoff Lang946b9482014-05-12 16:37:25 -04001232 if (mImageArray[face][level]->isDirty() && isFaceLevelComplete(face, level))
Jamie Madilld9b9a502013-10-10 17:46:13 -04001233 {
Jamie Madill169d1112013-10-24 17:49:37 -04001234 updateStorageFaceLevel(face, level);
Jamie Madilld9b9a502013-10-10 17:46:13 -04001235 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001236 }
1237 }
1238}
1239
Jamie Madill169d1112013-10-24 17:49:37 -04001240void TextureCubeMap::updateStorageFaceLevel(int faceIndex, int level)
Jamie Madill07edd442013-07-19 16:36:58 -04001241{
Jamie Madill2db197c2013-10-24 17:49:35 -04001242 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1243 rx::Image *image = mImageArray[faceIndex][level];
Jamie Madill07edd442013-07-19 16:36:58 -04001244
1245 if (image->isDirty())
1246 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001247 commitRect(faceIndex, level, 0, 0, image->getWidth(), image->getHeight());
Jamie Madill07edd442013-07-19 16:36:58 -04001248 }
1249}
1250
Jamie Madille83d1a92013-10-24 17:49:33 -04001251bool TextureCubeMap::ensureRenderTarget()
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001252{
Jamie Madill3c0989c2013-10-24 17:49:39 -04001253 initializeStorage(true);
1254
1255 if (getBaseLevelWidth() > 0)
Jamie Madille83d1a92013-10-24 17:49:33 -04001256 {
Jamie Madill3c0989c2013-10-24 17:49:39 -04001257 ASSERT(mTexStorage);
1258 if (!mTexStorage->isRenderTarget())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001259 {
Jamie Madill3c0989c2013-10-24 17:49:39 -04001260 rx::TextureStorageInterfaceCube *newRenderTargetStorage = createCompleteStorage(true);
1261
1262 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001263 {
Jamie Madill3c0989c2013-10-24 17:49:39 -04001264 delete newRenderTargetStorage;
Jamie Madille83d1a92013-10-24 17:49:33 -04001265 return gl::error(GL_OUT_OF_MEMORY, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001266 }
Jamie Madill3c0989c2013-10-24 17:49:39 -04001267
1268 setCompleteTexStorage(newRenderTargetStorage);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001269 }
1270 }
1271
Jamie Madille83d1a92013-10-24 17:49:33 -04001272 return (mTexStorage && mTexStorage->isRenderTarget());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001273}
1274
Geoff Lang005df412013-10-16 14:12:50 -04001275void TextureCubeMap::setImage(int faceIndex, GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001276{
Geoff Lange4a492b2014-06-19 14:14:41 -04001277 GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat) ? internalFormat
1278 : GetSizedInternalFormat(format, type);
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001279
1280 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001281
Jamie Madill88f18f42013-09-18 14:36:19 -04001282 Texture::setImage(unpack, type, pixels, mImageArray[faceIndex][level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001283}
1284
Jamie Madill2db197c2013-10-24 17:49:35 -04001285int TextureCubeMap::targetToIndex(GLenum target)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001286{
1287 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
1288 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
1289 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
1290 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
1291 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
1292
Jamie Madill2db197c2013-10-24 17:49:35 -04001293 return target - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001294}
1295
Jamie Madill2db197c2013-10-24 17:49:35 -04001296void TextureCubeMap::redefineImage(int faceIndex, GLint level, GLenum internalformat, GLsizei width, GLsizei height)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001297{
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001298 // If there currently is a corresponding storage texture image, it has these parameters
Jamie Madilld3d2a342013-10-07 10:46:35 -04001299 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1300 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
Geoff Lang005df412013-10-16 14:12:50 -04001301 const GLenum storageFormat = getBaseLevelInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001302
Jamie Madill2db197c2013-10-24 17:49:35 -04001303 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, width, height, 1, false);
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001304
1305 if (mTexStorage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001306 {
Nicolas Capensbf712d02014-03-31 14:23:35 -04001307 const int storageLevels = mTexStorage->getLevelCount();
1308
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001309 if ((level >= storageLevels && storageLevels != 0) ||
1310 width != storageWidth ||
1311 height != storageHeight ||
1312 internalformat != storageFormat) // Discard mismatched storage
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001313 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001314 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001315 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001316 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001317 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001318 mImageArray[faceIndex][level]->markDirty();
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001319 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001320 }
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001321
1322 delete mTexStorage;
1323 mTexStorage = NULL;
1324
1325 mDirtyImages = true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001326 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001327 }
1328}
1329
1330void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1331{
Jamie Madill2db197c2013-10-24 17:49:35 -04001332 int faceIndex = targetToIndex(target);
Geoff Lange4a492b2014-06-19 14:14:41 -04001333 GLenum sizedInternalFormat = IsSizedInternalFormat(format) ? format
1334 : GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
Jamie Madill2db197c2013-10-24 17:49:35 -04001335 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001336
Jamie Madill2db197c2013-10-24 17:49:35 -04001337 if (!mImageArray[faceIndex][level]->isRenderableFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001338 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001339 mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001340 mDirtyImages = true;
1341 }
1342 else
1343 {
Jamie Madille83d1a92013-10-24 17:49:33 -04001344 ensureRenderTarget();
Jamie Madill2db197c2013-10-24 17:49:35 -04001345 mImageArray[faceIndex][level]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001346
1347 ASSERT(width == height);
1348
Jamie Madill07bb8cf2013-10-24 17:49:44 -04001349 if (width > 0 && isValidFaceLevel(faceIndex, level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001350 {
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +00001351 gl::Rectangle sourceRect;
1352 sourceRect.x = x;
1353 sourceRect.width = width;
1354 sourceRect.y = y;
1355 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001356
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +00001357 mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001358 }
1359 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001360}
1361
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001362void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001363{
Jamie Madill2db197c2013-10-24 17:49:35 -04001364 int faceIndex = targetToIndex(target);
1365
Jamie Madilld3d2a342013-10-07 10:46:35 -04001366 // We can only make our texture storage to a render target if the level we're copying *to* is complete
1367 // and the base level is cube-complete. The base level must be cube complete (common case) because we cannot
1368 // rely on the "getBaseLevel*" methods reliably otherwise.
Jamie Madill2db197c2013-10-24 17:49:35 -04001369 bool canCreateRenderTarget = isFaceLevelComplete(faceIndex, level) && isCubeComplete();
Jamie Madill07edd442013-07-19 16:36:58 -04001370
Jamie Madill2db197c2013-10-24 17:49:35 -04001371 if (!mImageArray[faceIndex][level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001372 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001373 mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001374 mDirtyImages = true;
1375 }
1376 else
1377 {
Jamie Madille83d1a92013-10-24 17:49:33 -04001378 ensureRenderTarget();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001379
Jamie Madill07bb8cf2013-10-24 17:49:44 -04001380 if (isValidFaceLevel(faceIndex, level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001381 {
Jamie Madill169d1112013-10-24 17:49:37 -04001382 updateStorageFaceLevel(faceIndex, level);
Jamie Madill07edd442013-07-19 16:36:58 -04001383
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +00001384 gl::Rectangle sourceRect;
1385 sourceRect.x = x;
1386 sourceRect.width = width;
1387 sourceRect.y = y;
1388 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001389
Geoff Lange4a492b2014-06-19 14:14:41 -04001390 mRenderer->copyImage(source, sourceRect, gl::GetFormat(getBaseLevelInternalFormat()),
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +00001391 xoffset, yoffset, mTexStorage, target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001392 }
1393 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001394}
1395
1396void TextureCubeMap::storage(GLsizei levels, GLenum internalformat, GLsizei size)
1397{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001398 for (int level = 0; level < levels; level++)
1399 {
Geoff Langd3110192013-09-24 11:52:47 -04001400 GLsizei mipSize = std::max(1, size >> level);
Jamie Madill2db197c2013-10-24 17:49:35 -04001401 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001402 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001403 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, mipSize, mipSize, 1, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001404 }
1405 }
1406
1407 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1408 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001409 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001410 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001411 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, GL_NONE, 0, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001412 }
1413 }
1414
Jamie Madill3c0989c2013-10-24 17:49:39 -04001415 mImmutable = true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001416
Nicolas Capensbf712d02014-03-31 14:23:35 -04001417 setCompleteTexStorage(new rx::TextureStorageInterfaceCube(mRenderer, internalformat, IsRenderTargetUsage(mUsage), size, levels));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001418}
1419
1420void TextureCubeMap::generateMipmaps()
1421{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001422 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Geoff Lang98705b72014-03-31 16:00:03 -04001423 int levelCount = mipLevels();
Jamie Madill2db197c2013-10-24 17:49:35 -04001424 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001425 {
Geoff Lang98705b72014-03-31 16:00:03 -04001426 for (int level = 1; level < levelCount; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001427 {
Jamie Madill22f843a2013-10-24 17:49:36 -04001428 int faceLevelSize = (std::max(mImageArray[faceIndex][0]->getWidth() >> level, 1));
1429 redefineImage(faceIndex, level, mImageArray[faceIndex][0]->getInternalFormat(), faceLevelSize, faceLevelSize);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001430 }
1431 }
1432
1433 if (mTexStorage && mTexStorage->isRenderTarget())
1434 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001435 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001436 {
Geoff Lang98705b72014-03-31 16:00:03 -04001437 for (int level = 1; level < levelCount; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001438 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001439 mTexStorage->generateMipmap(faceIndex, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001440
Jamie Madill2db197c2013-10-24 17:49:35 -04001441 mImageArray[faceIndex][level]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001442 }
1443 }
1444 }
1445 else
1446 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001447 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001448 {
Geoff Lang98705b72014-03-31 16:00:03 -04001449 for (int level = 1; level < levelCount; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001450 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001451 mRenderer->generateMipmap(mImageArray[faceIndex][level], mImageArray[faceIndex][level - 1]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001452 }
1453 }
1454 }
1455}
1456
Jamie Madilld3d2a342013-10-07 10:46:35 -04001457const rx::Image *TextureCubeMap::getBaseLevelImage() const
1458{
1459 // Note: if we are not cube-complete, there is no single base level image that can describe all
1460 // cube faces, so this method is only well-defined for a cube-complete base level.
1461 return mImageArray[0][0];
1462}
1463
Jamie Madill2ebab852013-10-24 17:49:42 -04001464rx::TextureStorageInterface *TextureCubeMap::getBaseLevelStorage()
1465{
1466 return mTexStorage;
1467}
1468
Jamie Madill2db197c2013-10-24 17:49:35 -04001469unsigned int TextureCubeMap::getRenderTargetSerial(GLenum target, GLint level)
Geoff Lang8040f572013-07-25 16:49:54 -04001470{
Jamie Madill2db197c2013-10-24 17:49:35 -04001471 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(target, level) : 0);
Geoff Lang8040f572013-07-25 16:49:54 -04001472}
1473
1474rx::RenderTarget *TextureCubeMap::getRenderTarget(GLenum target, GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001475{
1476 ASSERT(IsCubemapTextureTarget(target));
1477
1478 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04001479 if (!ensureRenderTarget())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001480 {
1481 return NULL;
1482 }
1483
Jamie Madill169d1112013-10-24 17:49:37 -04001484 updateStorageFaceLevel(targetToIndex(target), level);
Geoff Lang8040f572013-07-25 16:49:54 -04001485
1486 // ensure this is NOT a depth texture
1487 if (isDepth(target, level))
1488 {
1489 return NULL;
1490 }
1491
1492 return mTexStorage->getRenderTarget(target, level);
1493}
1494
1495rx::RenderTarget *TextureCubeMap::getDepthStencil(GLenum target, GLint level)
1496{
1497 ASSERT(IsCubemapTextureTarget(target));
1498
1499 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04001500 if (!ensureRenderTarget())
Geoff Lang8040f572013-07-25 16:49:54 -04001501 {
1502 return NULL;
1503 }
1504
Jamie Madill169d1112013-10-24 17:49:37 -04001505 updateStorageFaceLevel(targetToIndex(target), level);
Geoff Lang8040f572013-07-25 16:49:54 -04001506
1507 // ensure this is a depth texture
1508 if (!isDepth(target, level))
1509 {
1510 return NULL;
1511 }
1512
1513 return mTexStorage->getRenderTarget(target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001514}
1515
Jamie Madill07bb8cf2013-10-24 17:49:44 -04001516bool TextureCubeMap::isValidFaceLevel(int faceIndex, int level) const
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +00001517{
Nicolas Capensbf712d02014-03-31 14:23:35 -04001518 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +00001519}
1520
Geoff Lang4907f2c2013-07-25 12:53:57 -04001521Texture3D::Texture3D(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_3D)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001522{
1523 mTexStorage = NULL;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001524
1525 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1526 {
1527 mImageArray[i] = renderer->createImage();
1528 }
1529}
1530
1531Texture3D::~Texture3D()
1532{
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001533 delete mTexStorage;
1534 mTexStorage = NULL;
1535
1536 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1537 {
1538 delete mImageArray[i];
1539 }
1540}
1541
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001542GLsizei Texture3D::getWidth(GLint level) const
1543{
1544 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getWidth() : 0;
1545}
1546
1547GLsizei Texture3D::getHeight(GLint level) const
1548{
1549 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getHeight() : 0;
1550}
1551
1552GLsizei Texture3D::getDepth(GLint level) const
1553{
1554 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getDepth() : 0;
1555}
1556
1557GLenum Texture3D::getInternalFormat(GLint level) const
1558{
1559 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getInternalFormat() : GL_NONE;
1560}
1561
1562GLenum Texture3D::getActualFormat(GLint level) const
1563{
Geoff Langcbf727a2014-02-10 12:50:45 -05001564 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getActualFormat() : GL_NONE;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001565}
1566
1567bool Texture3D::isCompressed(GLint level) const
1568{
Geoff Lange4a492b2014-06-19 14:14:41 -04001569 return IsFormatCompressed(getInternalFormat(level));
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001570}
1571
1572bool Texture3D::isDepth(GLint level) const
1573{
Geoff Lange4a492b2014-06-19 14:14:41 -04001574 return GetDepthBits(getInternalFormat(level)) > 0;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001575}
1576
Geoff Lang005df412013-10-16 14:12:50 -04001577void Texture3D::setImage(GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001578{
Geoff Lange4a492b2014-06-19 14:14:41 -04001579 GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat) ? internalFormat
1580 : GetSizedInternalFormat(format, type);
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001581 redefineImage(level, sizedInternalFormat, width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001582
Jamie Madilla2d4e552013-10-10 15:12:01 -04001583 bool fastUnpacked = false;
1584
1585 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1586 if (isFastUnpackable(unpack, sizedInternalFormat))
1587 {
1588 // Will try to create RT storage if it does not exist
1589 rx::RenderTarget *destRenderTarget = getRenderTarget(level);
1590 Box destArea(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1591
1592 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget))
1593 {
1594 // Ensure we don't overwrite our newly initialized data
1595 mImageArray[level]->markClean();
1596
1597 fastUnpacked = true;
1598 }
1599 }
1600
1601 if (!fastUnpacked)
1602 {
1603 Texture::setImage(unpack, type, pixels, mImageArray[level]);
1604 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001605}
1606
1607void Texture3D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
1608{
1609 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1610 redefineImage(level, format, width, height, depth);
1611
1612 Texture::setCompressedImage(imageSize, pixels, mImageArray[level]);
1613}
1614
Jamie Madill88f18f42013-09-18 14:36:19 -04001615void Texture3D::subImage(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001616{
Jamie Madillba4f10a2013-10-10 15:12:20 -04001617 bool fastUnpacked = false;
1618
1619 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1620 if (isFastUnpackable(unpack, getInternalFormat(level)))
1621 {
1622 rx::RenderTarget *destRenderTarget = getRenderTarget(level);
1623 Box destArea(xoffset, yoffset, zoffset, width, height, depth);
1624
1625 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, destRenderTarget))
1626 {
1627 // Ensure we don't overwrite our newly initialized data
1628 mImageArray[level]->markClean();
1629
1630 fastUnpacked = true;
1631 }
1632 }
1633
1634 if (!fastUnpacked && Texture::subImage(xoffset, yoffset, zoffset, width, height, depth, format, type, unpack, pixels, mImageArray[level]))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001635 {
1636 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1637 }
1638}
1639
1640void Texture3D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
1641{
1642 if (Texture::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth, format, imageSize, pixels, mImageArray[level]))
1643 {
1644 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1645 }
1646}
1647
1648void Texture3D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
1649{
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001650 for (int level = 0; level < levels; level++)
1651 {
Jamie Madille664e202013-10-24 17:49:40 -04001652 GLsizei levelWidth = std::max(1, width >> level);
1653 GLsizei levelHeight = std::max(1, height >> level);
1654 GLsizei levelDepth = std::max(1, depth >> level);
1655 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, levelWidth, levelHeight, levelDepth, true);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001656 }
1657
1658 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1659 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001660 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, GL_NONE, 0, 0, 0, true);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001661 }
1662
Jamie Madille664e202013-10-24 17:49:40 -04001663 mImmutable = true;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001664
Nicolas Capensbf712d02014-03-31 14:23:35 -04001665 setCompleteTexStorage(new rx::TextureStorageInterface3D(mRenderer, internalformat, IsRenderTargetUsage(mUsage), width, height, depth, levels));
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001666}
1667
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001668void Texture3D::generateMipmaps()
1669{
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001670 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Geoff Lang98705b72014-03-31 16:00:03 -04001671 int levelCount = mipLevels();
1672 for (int level = 1; level < levelCount; level++)
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001673 {
Jamie Madill22f843a2013-10-24 17:49:36 -04001674 redefineImage(level, getBaseLevelInternalFormat(),
1675 std::max(getBaseLevelWidth() >> level, 1),
1676 std::max(getBaseLevelHeight() >> level, 1),
1677 std::max(getBaseLevelDepth() >> level, 1));
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001678 }
1679
1680 if (mTexStorage && mTexStorage->isRenderTarget())
1681 {
Geoff Lang98705b72014-03-31 16:00:03 -04001682 for (int level = 1; level < levelCount; level++)
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001683 {
Jamie Madill22f843a2013-10-24 17:49:36 -04001684 mTexStorage->generateMipmap(level);
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001685
Jamie Madill22f843a2013-10-24 17:49:36 -04001686 mImageArray[level]->markClean();
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001687 }
1688 }
1689 else
1690 {
Geoff Lang98705b72014-03-31 16:00:03 -04001691 for (int level = 1; level < levelCount; level++)
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001692 {
Jamie Madill22f843a2013-10-24 17:49:36 -04001693 mRenderer->generateMipmap(mImageArray[level], mImageArray[level - 1]);
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001694 }
1695 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001696}
1697
Jamie Madilld3d2a342013-10-07 10:46:35 -04001698const rx::Image *Texture3D::getBaseLevelImage() const
1699{
1700 return mImageArray[0];
1701}
1702
Jamie Madill2ebab852013-10-24 17:49:42 -04001703rx::TextureStorageInterface *Texture3D::getBaseLevelStorage()
1704{
1705 return mTexStorage;
1706}
1707
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001708void Texture3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1709{
Jamie Madill07edd442013-07-19 16:36:58 -04001710 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
1711 // the current level we're copying to is defined (with appropriate format, width & height)
1712 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
1713
1714 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001715 {
1716 mImageArray[level]->copy(xoffset, yoffset, zoffset, x, y, width, height, source);
1717 mDirtyImages = true;
1718 }
1719 else
1720 {
Jamie Madille83d1a92013-10-24 17:49:33 -04001721 ensureRenderTarget();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001722
Jamie Madill07bb8cf2013-10-24 17:49:44 -04001723 if (isValidLevel(level))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001724 {
Jamie Madill169d1112013-10-24 17:49:37 -04001725 updateStorageLevel(level);
Jamie Madill07edd442013-07-19 16:36:58 -04001726
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001727 gl::Rectangle sourceRect;
1728 sourceRect.x = x;
1729 sourceRect.width = width;
1730 sourceRect.y = y;
1731 sourceRect.height = height;
1732
1733 mRenderer->copyImage(source, sourceRect,
Geoff Lange4a492b2014-06-19 14:14:41 -04001734 gl::GetFormat(getBaseLevelInternalFormat()),
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001735 xoffset, yoffset, zoffset, mTexStorage, level);
1736 }
1737 }
1738}
1739
Jamie Madillf8989902013-07-19 16:36:58 -04001740bool Texture3D::isSamplerComplete(const SamplerState &samplerState) const
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001741{
Jamie Madilld3d2a342013-10-07 10:46:35 -04001742 GLsizei width = getBaseLevelWidth();
1743 GLsizei height = getBaseLevelHeight();
1744 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001745
1746 if (width <= 0 || height <= 0 || depth <= 0)
1747 {
1748 return false;
1749 }
1750
Geoff Langc0b9ef42014-07-02 10:02:37 -04001751 // TODO(geofflang): use context's texture caps
1752 if (!mRenderer->getRendererTextureCaps().get(getInternalFormat(0)).filtering)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001753 {
Jamie Madillf8989902013-07-19 16:36:58 -04001754 if (samplerState.magFilter != GL_NEAREST ||
1755 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001756 {
1757 return false;
1758 }
1759 }
1760
Jamie Madillf8989902013-07-19 16:36:58 -04001761 if (IsMipmapFiltered(samplerState) && !isMipmapComplete())
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001762 {
1763 return false;
1764 }
1765
1766 return true;
1767}
1768
1769bool Texture3D::isMipmapComplete() const
1770{
Geoff Lang98705b72014-03-31 16:00:03 -04001771 int levelCount = mipLevels();
Jamie Madill07edd442013-07-19 16:36:58 -04001772
Geoff Lang98705b72014-03-31 16:00:03 -04001773 for (int level = 0; level < levelCount; level++)
Jamie Madill07edd442013-07-19 16:36:58 -04001774 {
1775 if (!isLevelComplete(level))
1776 {
1777 return false;
1778 }
1779 }
1780
1781 return true;
1782}
1783
1784bool Texture3D::isLevelComplete(int level) const
1785{
1786 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1787
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001788 if (isImmutable())
1789 {
1790 return true;
1791 }
1792
Jamie Madilld3d2a342013-10-07 10:46:35 -04001793 GLsizei width = getBaseLevelWidth();
1794 GLsizei height = getBaseLevelHeight();
1795 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001796
1797 if (width <= 0 || height <= 0 || depth <= 0)
1798 {
1799 return false;
1800 }
1801
Jamie Madill07edd442013-07-19 16:36:58 -04001802 if (level == 0)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001803 {
Jamie Madill07edd442013-07-19 16:36:58 -04001804 return true;
1805 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001806
Jamie Madill07edd442013-07-19 16:36:58 -04001807 rx::Image *levelImage = mImageArray[level];
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001808
Jamie Madilld3d2a342013-10-07 10:46:35 -04001809 if (levelImage->getInternalFormat() != getBaseLevelInternalFormat())
Jamie Madill07edd442013-07-19 16:36:58 -04001810 {
1811 return false;
1812 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001813
Jamie Madill07edd442013-07-19 16:36:58 -04001814 if (levelImage->getWidth() != std::max(1, width >> level))
1815 {
1816 return false;
1817 }
1818
1819 if (levelImage->getHeight() != std::max(1, height >> level))
1820 {
1821 return false;
1822 }
1823
1824 if (levelImage->getDepth() != std::max(1, depth >> level))
1825 {
1826 return false;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001827 }
1828
1829 return true;
1830}
1831
Geoff Lang8040f572013-07-25 16:49:54 -04001832unsigned int Texture3D::getRenderTargetSerial(GLint level, GLint layer)
1833{
Jamie Madille83d1a92013-10-24 17:49:33 -04001834 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(level, layer) : 0);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001835}
1836
Jamie Madill07bb8cf2013-10-24 17:49:44 -04001837bool Texture3D::isValidLevel(int level) const
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001838{
Nicolas Capensbf712d02014-03-31 14:23:35 -04001839 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001840}
1841
Jamie Madill73b5d062013-10-24 17:49:38 -04001842void Texture3D::initializeStorage(bool renderTarget)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001843{
Jamie Madille664e202013-10-24 17:49:40 -04001844 // Only initialize the first time this texture is used as a render target or shader resource
1845 if (mTexStorage)
1846 {
1847 return;
1848 }
1849
1850 // do not attempt to create storage for nonexistant data
1851 if (!isLevelComplete(0))
1852 {
1853 return;
1854 }
1855
1856 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
1857
1858 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
1859 ASSERT(mTexStorage);
1860
1861 // flush image data to the storage
1862 updateStorage();
1863}
1864
1865rx::TextureStorageInterface3D *Texture3D::createCompleteStorage(bool renderTarget) const
1866{
Jamie Madilld3d2a342013-10-07 10:46:35 -04001867 GLsizei width = getBaseLevelWidth();
1868 GLsizei height = getBaseLevelHeight();
1869 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001870
Jamie Madille664e202013-10-24 17:49:40 -04001871 ASSERT(width > 0 && height > 0 && depth > 0);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001872
Jamie Madille664e202013-10-24 17:49:40 -04001873 // use existing storage level count, when previously specified by TexStorage*D
Nicolas Capensbf712d02014-03-31 14:23:35 -04001874 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, depth));
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001875
Nicolas Capensbf712d02014-03-31 14:23:35 -04001876 return new rx::TextureStorageInterface3D(mRenderer, getBaseLevelInternalFormat(), renderTarget, width, height, depth, levels);
Jamie Madille664e202013-10-24 17:49:40 -04001877}
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001878
Jamie Madille664e202013-10-24 17:49:40 -04001879void Texture3D::setCompleteTexStorage(rx::TextureStorageInterface3D *newCompleteTexStorage)
1880{
1881 SafeDelete(mTexStorage);
1882 mTexStorage = newCompleteTexStorage;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001883 mDirtyImages = true;
Jamie Madille664e202013-10-24 17:49:40 -04001884
1885 // We do not support managed 3D storage, as that is D3D9/ES2-only
1886 ASSERT(!mTexStorage->isManaged());
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001887}
1888
Jamie Madill169d1112013-10-24 17:49:37 -04001889void Texture3D::updateStorage()
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001890{
Geoff Lang946b9482014-05-12 16:37:25 -04001891 ASSERT(mTexStorage != NULL);
1892 GLint storageLevels = mTexStorage->getLevelCount();
1893 for (int level = 0; level < storageLevels; level++)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001894 {
Geoff Lang946b9482014-05-12 16:37:25 -04001895 if (mImageArray[level]->isDirty() && isLevelComplete(level))
Jamie Madilld9b9a502013-10-10 17:46:13 -04001896 {
Jamie Madill169d1112013-10-24 17:49:37 -04001897 updateStorageLevel(level);
Jamie Madilld9b9a502013-10-10 17:46:13 -04001898 }
Jamie Madill07edd442013-07-19 16:36:58 -04001899 }
1900}
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001901
Jamie Madill169d1112013-10-24 17:49:37 -04001902void Texture3D::updateStorageLevel(int level)
Jamie Madill07edd442013-07-19 16:36:58 -04001903{
1904 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
Jamie Madillaee7ad82013-10-10 16:07:32 -04001905 ASSERT(isLevelComplete(level));
Jamie Madill07edd442013-07-19 16:36:58 -04001906
Jamie Madillaee7ad82013-10-10 16:07:32 -04001907 if (mImageArray[level]->isDirty())
Jamie Madill07edd442013-07-19 16:36:58 -04001908 {
Jamie Madillaee7ad82013-10-10 16:07:32 -04001909 commitRect(level, 0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001910 }
1911}
1912
Jamie Madille83d1a92013-10-24 17:49:33 -04001913bool Texture3D::ensureRenderTarget()
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001914{
Jamie Madille664e202013-10-24 17:49:40 -04001915 initializeStorage(true);
1916
1917 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0 && getBaseLevelDepth() > 0)
Jamie Madille83d1a92013-10-24 17:49:33 -04001918 {
Jamie Madille664e202013-10-24 17:49:40 -04001919 ASSERT(mTexStorage);
1920 if (!mTexStorage->isRenderTarget())
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001921 {
Jamie Madille664e202013-10-24 17:49:40 -04001922 rx::TextureStorageInterface3D *newRenderTargetStorage = createCompleteStorage(true);
1923
1924 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001925 {
Jamie Madille664e202013-10-24 17:49:40 -04001926 delete newRenderTargetStorage;
Jamie Madille83d1a92013-10-24 17:49:33 -04001927 return gl::error(GL_OUT_OF_MEMORY, false);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001928 }
Jamie Madille664e202013-10-24 17:49:40 -04001929
1930 setCompleteTexStorage(newRenderTargetStorage);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001931 }
1932 }
1933
Jamie Madille83d1a92013-10-24 17:49:33 -04001934 return (mTexStorage && mTexStorage->isRenderTarget());
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001935}
1936
Jamie Madilla2d4e552013-10-10 15:12:01 -04001937rx::RenderTarget *Texture3D::getRenderTarget(GLint level)
1938{
1939 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04001940 if (!ensureRenderTarget())
Jamie Madilla2d4e552013-10-10 15:12:01 -04001941 {
1942 return NULL;
1943 }
1944
Jamie Madill169d1112013-10-24 17:49:37 -04001945 updateStorageLevel(level);
Jamie Madilla2d4e552013-10-10 15:12:01 -04001946
1947 // ensure this is NOT a depth texture
1948 if (isDepth(level))
1949 {
1950 return NULL;
1951 }
1952
1953 return mTexStorage->getRenderTarget(level);
1954}
1955
Geoff Lang8040f572013-07-25 16:49:54 -04001956rx::RenderTarget *Texture3D::getRenderTarget(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001957{
Geoff Lang8040f572013-07-25 16:49:54 -04001958 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04001959 if (!ensureRenderTarget())
Geoff Lang8040f572013-07-25 16:49:54 -04001960 {
1961 return NULL;
1962 }
1963
Jamie Madill169d1112013-10-24 17:49:37 -04001964 updateStorage();
Geoff Lang8040f572013-07-25 16:49:54 -04001965
1966 // ensure this is NOT a depth texture
1967 if (isDepth(level))
1968 {
1969 return NULL;
1970 }
1971
1972 return mTexStorage->getRenderTarget(level, layer);
1973}
1974
1975rx::RenderTarget *Texture3D::getDepthStencil(GLint level, GLint layer)
1976{
1977 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04001978 if (!ensureRenderTarget())
Geoff Lang8040f572013-07-25 16:49:54 -04001979 {
1980 return NULL;
1981 }
1982
Jamie Madill169d1112013-10-24 17:49:37 -04001983 updateStorageLevel(level);
Geoff Lang8040f572013-07-25 16:49:54 -04001984
1985 // ensure this is a depth texture
1986 if (!isDepth(level))
1987 {
1988 return NULL;
1989 }
1990
1991 return mTexStorage->getRenderTarget(level, layer);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001992}
1993
Geoff Lang005df412013-10-16 14:12:50 -04001994void Texture3D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001995{
1996 // If there currently is a corresponding storage texture image, it has these parameters
Jamie Madilld3d2a342013-10-07 10:46:35 -04001997 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1998 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1999 const int storageDepth = std::max(1, getBaseLevelDepth() >> level);
Geoff Lang005df412013-10-16 14:12:50 -04002000 const GLenum storageFormat = getBaseLevelInternalFormat();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002001
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00002002 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, false);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002003
2004 if (mTexStorage)
2005 {
Nicolas Capensbf712d02014-03-31 14:23:35 -04002006 const int storageLevels = mTexStorage->getLevelCount();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002007
2008 if ((level >= storageLevels && storageLevels != 0) ||
2009 width != storageWidth ||
2010 height != storageHeight ||
2011 depth != storageDepth ||
2012 internalformat != storageFormat) // Discard mismatched storage
2013 {
2014 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
2015 {
2016 mImageArray[i]->markDirty();
2017 }
2018
2019 delete mTexStorage;
2020 mTexStorage = NULL;
2021 mDirtyImages = true;
2022 }
2023 }
2024}
2025
2026void Texture3D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth)
2027{
Jamie Madill07bb8cf2013-10-24 17:49:44 -04002028 if (isValidLevel(level))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002029 {
2030 rx::Image *image = mImageArray[level];
Jamie Madill169d1112013-10-24 17:49:37 -04002031 if (image->copyToStorage(mTexStorage, level, xoffset, yoffset, zoffset, width, height, depth))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002032 {
2033 image->markClean();
2034 }
2035 }
2036}
2037
Geoff Lang4907f2c2013-07-25 12:53:57 -04002038Texture2DArray::Texture2DArray(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_2D_ARRAY)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002039{
2040 mTexStorage = NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002041
2042 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2043 {
2044 mLayerCounts[level] = 0;
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002045 mImageArray[level] = NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002046 }
2047}
2048
2049Texture2DArray::~Texture2DArray()
2050{
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002051 delete mTexStorage;
2052 mTexStorage = NULL;
Jamie Madill884a4622013-10-24 17:49:41 -04002053
2054 deleteImages();
2055}
2056
2057void Texture2DArray::deleteImages()
2058{
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002059 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2060 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002061 for (int layer = 0; layer < mLayerCounts[level]; ++layer)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002062 {
2063 delete mImageArray[level][layer];
2064 }
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002065 delete[] mImageArray[level];
Jamie Madill884a4622013-10-24 17:49:41 -04002066 mImageArray[level] = NULL;
2067 mLayerCounts[level] = 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002068 }
2069}
2070
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002071GLsizei Texture2DArray::getWidth(GLint level) const
2072{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002073 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getWidth() : 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002074}
2075
2076GLsizei Texture2DArray::getHeight(GLint level) const
2077{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002078 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getHeight() : 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002079}
2080
Jamie Madillb8f8b892014-01-07 10:12:50 -05002081GLsizei Texture2DArray::getLayers(GLint level) const
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002082{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002083 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mLayerCounts[level] : 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002084}
2085
2086GLenum Texture2DArray::getInternalFormat(GLint level) const
2087{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002088 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getInternalFormat() : GL_NONE;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002089}
2090
2091GLenum Texture2DArray::getActualFormat(GLint level) const
2092{
Geoff Langcbf727a2014-02-10 12:50:45 -05002093 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getActualFormat() : GL_NONE;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002094}
2095
2096bool Texture2DArray::isCompressed(GLint level) const
2097{
Geoff Lange4a492b2014-06-19 14:14:41 -04002098 return IsFormatCompressed(getInternalFormat(level));
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002099}
2100
2101bool Texture2DArray::isDepth(GLint level) const
2102{
Geoff Lange4a492b2014-06-19 14:14:41 -04002103 return GetDepthBits(getInternalFormat(level)) > 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002104}
2105
Geoff Lang005df412013-10-16 14:12:50 -04002106void Texture2DArray::setImage(GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002107{
Geoff Lange4a492b2014-06-19 14:14:41 -04002108 GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat) ? internalFormat
2109 : GetSizedInternalFormat(format, type);
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00002110 redefineImage(level, sizedInternalFormat, width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002111
Geoff Lange4a492b2014-06-19 14:14:41 -04002112 GLsizei inputDepthPitch = gl::GetDepthPitch(sizedInternalFormat, type, width, height, unpack.alignment);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002113
2114 for (int i = 0; i < depth; i++)
2115 {
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002116 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
Jamie Madill88f18f42013-09-18 14:36:19 -04002117 Texture::setImage(unpack, type, layerPixels, mImageArray[level][i]);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002118 }
2119}
2120
2121void Texture2DArray::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
2122{
2123 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
2124 redefineImage(level, format, width, height, depth);
2125
Geoff Lange4a492b2014-06-19 14:14:41 -04002126 GLsizei inputDepthPitch = gl::GetDepthPitch(format, GL_UNSIGNED_BYTE, width, height, 1);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002127
2128 for (int i = 0; i < depth; i++)
2129 {
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002130 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002131 Texture::setCompressedImage(imageSize, layerPixels, mImageArray[level][i]);
2132 }
2133}
2134
Jamie Madill88f18f42013-09-18 14:36:19 -04002135void Texture2DArray::subImage(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002136{
Geoff Lang005df412013-10-16 14:12:50 -04002137 GLenum internalformat = getInternalFormat(level);
Geoff Lange4a492b2014-06-19 14:14:41 -04002138 GLsizei inputDepthPitch = gl::GetDepthPitch(internalformat, type, width, height, unpack.alignment);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002139
2140 for (int i = 0; i < depth; i++)
2141 {
2142 int layer = zoffset + i;
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002143 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002144
Jamie Madill88f18f42013-09-18 14:36:19 -04002145 if (Texture::subImage(xoffset, yoffset, zoffset, width, height, 1, format, type, unpack, layerPixels, mImageArray[level][layer]))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002146 {
2147 commitRect(level, xoffset, yoffset, layer, width, height);
2148 }
2149 }
2150}
2151
2152void Texture2DArray::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
2153{
Geoff Lange4a492b2014-06-19 14:14:41 -04002154 GLsizei inputDepthPitch = gl::GetDepthPitch(format, GL_UNSIGNED_BYTE, width, height, 1);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002155
2156 for (int i = 0; i < depth; i++)
2157 {
2158 int layer = zoffset + i;
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002159 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002160
2161 if (Texture::subImageCompressed(xoffset, yoffset, zoffset, width, height, 1, format, imageSize, layerPixels, mImageArray[level][layer]))
2162 {
2163 commitRect(level, xoffset, yoffset, layer, width, height);
2164 }
2165 }
2166}
2167
2168void Texture2DArray::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2169{
Jamie Madill884a4622013-10-24 17:49:41 -04002170 deleteImages();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002171
2172 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2173 {
Jamie Madill884a4622013-10-24 17:49:41 -04002174 GLsizei levelWidth = std::max(1, width >> level);
2175 GLsizei levelHeight = std::max(1, height >> level);
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002176
Jamie Madill884a4622013-10-24 17:49:41 -04002177 mLayerCounts[level] = (level < levels ? depth : 0);
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002178
Jamie Madill884a4622013-10-24 17:49:41 -04002179 if (mLayerCounts[level] > 0)
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002180 {
2181 // Create new images for this level
Jamie Madill884a4622013-10-24 17:49:41 -04002182 mImageArray[level] = new rx::Image*[mLayerCounts[level]];
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002183
2184 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002185 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002186 mImageArray[level][layer] = mRenderer->createImage();
2187 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, levelWidth,
2188 levelHeight, 1, true);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002189 }
2190 }
2191 }
2192
Jamie Madill884a4622013-10-24 17:49:41 -04002193 mImmutable = true;
Nicolas Capensbf712d02014-03-31 14:23:35 -04002194 setCompleteTexStorage(new rx::TextureStorageInterface2DArray(mRenderer, internalformat, IsRenderTargetUsage(mUsage), width, height, depth, levels));
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002195}
2196
2197void Texture2DArray::generateMipmaps()
2198{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002199 int baseWidth = getBaseLevelWidth();
2200 int baseHeight = getBaseLevelHeight();
2201 int baseDepth = getBaseLevelDepth();
2202 GLenum baseFormat = getBaseLevelInternalFormat();
2203
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00002204 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Geoff Lang98705b72014-03-31 16:00:03 -04002205 int levelCount = mipLevels();
2206 for (int level = 1; level < levelCount; level++)
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00002207 {
Jamie Madill22f843a2013-10-24 17:49:36 -04002208 redefineImage(level, baseFormat, std::max(baseWidth >> level, 1), std::max(baseHeight >> level, 1), baseDepth);
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00002209 }
2210
2211 if (mTexStorage && mTexStorage->isRenderTarget())
2212 {
Geoff Lang98705b72014-03-31 16:00:03 -04002213 for (int level = 1; level < levelCount; level++)
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00002214 {
2215 mTexStorage->generateMipmap(level);
2216
2217 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2218 {
2219 mImageArray[level][layer]->markClean();
2220 }
2221 }
2222 }
2223 else
2224 {
Geoff Lang98705b72014-03-31 16:00:03 -04002225 for (int level = 1; level < levelCount; level++)
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00002226 {
2227 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2228 {
2229 mRenderer->generateMipmap(mImageArray[level][layer], mImageArray[level - 1][layer]);
2230 }
2231 }
2232 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002233}
2234
Jamie Madilld3d2a342013-10-07 10:46:35 -04002235const rx::Image *Texture2DArray::getBaseLevelImage() const
2236{
Jamie Madill152ed092013-10-09 17:01:15 -04002237 return (mLayerCounts[0] > 0 ? mImageArray[0][0] : NULL);
Jamie Madilld3d2a342013-10-07 10:46:35 -04002238}
2239
Jamie Madill2ebab852013-10-24 17:49:42 -04002240rx::TextureStorageInterface *Texture2DArray::getBaseLevelStorage()
2241{
2242 return mTexStorage;
2243}
2244
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002245void Texture2DArray::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
2246{
Jamie Madill07edd442013-07-19 16:36:58 -04002247 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
2248 // the current level we're copying to is defined (with appropriate format, width & height)
2249 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
2250
2251 if (!mImageArray[level][0]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002252 {
2253 mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, x, y, width, height, source);
2254 mDirtyImages = true;
2255 }
2256 else
2257 {
Jamie Madille83d1a92013-10-24 17:49:33 -04002258 ensureRenderTarget();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002259
Jamie Madill07bb8cf2013-10-24 17:49:44 -04002260 if (isValidLevel(level))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002261 {
Jamie Madill169d1112013-10-24 17:49:37 -04002262 updateStorageLevel(level);
Jamie Madill07edd442013-07-19 16:36:58 -04002263
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002264 gl::Rectangle sourceRect;
2265 sourceRect.x = x;
2266 sourceRect.width = width;
2267 sourceRect.y = y;
2268 sourceRect.height = height;
2269
Geoff Lange4a492b2014-06-19 14:14:41 -04002270 mRenderer->copyImage(source, sourceRect, gl::GetFormat(getInternalFormat(0)),
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002271 xoffset, yoffset, zoffset, mTexStorage, level);
2272 }
2273 }
2274}
2275
Jamie Madillf8989902013-07-19 16:36:58 -04002276bool Texture2DArray::isSamplerComplete(const SamplerState &samplerState) const
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002277{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002278 GLsizei width = getBaseLevelWidth();
2279 GLsizei height = getBaseLevelHeight();
Jamie Madillb8f8b892014-01-07 10:12:50 -05002280 GLsizei depth = getLayers(0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002281
2282 if (width <= 0 || height <= 0 || depth <= 0)
2283 {
2284 return false;
2285 }
2286
Geoff Langc0b9ef42014-07-02 10:02:37 -04002287 // TODO(geofflang): use context's texture caps
2288 if (!mRenderer->getRendererTextureCaps().get(getBaseLevelInternalFormat()).filtering)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002289 {
Jamie Madillf8989902013-07-19 16:36:58 -04002290 if (samplerState.magFilter != GL_NEAREST ||
2291 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002292 {
2293 return false;
2294 }
2295 }
2296
Jamie Madillf8989902013-07-19 16:36:58 -04002297 if (IsMipmapFiltered(samplerState) && !isMipmapComplete())
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002298 {
2299 return false;
2300 }
2301
2302 return true;
2303}
2304
2305bool Texture2DArray::isMipmapComplete() const
2306{
Geoff Lang98705b72014-03-31 16:00:03 -04002307 int levelCount = mipLevels();
Jamie Madill07edd442013-07-19 16:36:58 -04002308
Geoff Lang98705b72014-03-31 16:00:03 -04002309 for (int level = 1; level < levelCount; level++)
Jamie Madill07edd442013-07-19 16:36:58 -04002310 {
2311 if (!isLevelComplete(level))
2312 {
2313 return false;
2314 }
2315 }
2316
2317 return true;
2318}
2319
2320bool Texture2DArray::isLevelComplete(int level) const
2321{
Jamie Madillb8f8b892014-01-07 10:12:50 -05002322 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray));
Jamie Madill07edd442013-07-19 16:36:58 -04002323
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002324 if (isImmutable())
2325 {
2326 return true;
2327 }
2328
Jamie Madilld3d2a342013-10-07 10:46:35 -04002329 GLsizei width = getBaseLevelWidth();
2330 GLsizei height = getBaseLevelHeight();
Jamie Madillb8f8b892014-01-07 10:12:50 -05002331 GLsizei layers = getLayers(0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002332
Jamie Madillb8f8b892014-01-07 10:12:50 -05002333 if (width <= 0 || height <= 0 || layers <= 0)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002334 {
2335 return false;
2336 }
2337
Jamie Madill07edd442013-07-19 16:36:58 -04002338 if (level == 0)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002339 {
Jamie Madill07edd442013-07-19 16:36:58 -04002340 return true;
2341 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002342
Jamie Madill07edd442013-07-19 16:36:58 -04002343 if (getInternalFormat(level) != getInternalFormat(0))
2344 {
2345 return false;
2346 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002347
Jamie Madill07edd442013-07-19 16:36:58 -04002348 if (getWidth(level) != std::max(1, width >> level))
2349 {
2350 return false;
2351 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002352
Jamie Madill07edd442013-07-19 16:36:58 -04002353 if (getHeight(level) != std::max(1, height >> level))
2354 {
2355 return false;
2356 }
2357
Jamie Madillb8f8b892014-01-07 10:12:50 -05002358 if (getLayers(level) != layers)
Jamie Madill07edd442013-07-19 16:36:58 -04002359 {
2360 return false;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002361 }
2362
2363 return true;
2364}
2365
Jamie Madille83d1a92013-10-24 17:49:33 -04002366unsigned int Texture2DArray::getRenderTargetSerial(GLint level, GLint layer)
Geoff Lang8040f572013-07-25 16:49:54 -04002367{
Jamie Madille83d1a92013-10-24 17:49:33 -04002368 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(level, layer) : 0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002369}
2370
Jamie Madill07bb8cf2013-10-24 17:49:44 -04002371bool Texture2DArray::isValidLevel(int level) const
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002372{
Nicolas Capensbf712d02014-03-31 14:23:35 -04002373 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002374}
2375
Jamie Madill73b5d062013-10-24 17:49:38 -04002376void Texture2DArray::initializeStorage(bool renderTarget)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002377{
Jamie Madill884a4622013-10-24 17:49:41 -04002378 // Only initialize the first time this texture is used as a render target or shader resource
2379 if (mTexStorage)
2380 {
2381 return;
2382 }
2383
2384 // do not attempt to create storage for nonexistant data
2385 if (!isLevelComplete(0))
2386 {
2387 return;
2388 }
2389
2390 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
2391
2392 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
2393 ASSERT(mTexStorage);
2394
2395 // flush image data to the storage
2396 updateStorage();
2397}
2398
2399rx::TextureStorageInterface2DArray *Texture2DArray::createCompleteStorage(bool renderTarget) const
2400{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002401 GLsizei width = getBaseLevelWidth();
2402 GLsizei height = getBaseLevelHeight();
Jamie Madillb8f8b892014-01-07 10:12:50 -05002403 GLsizei depth = getLayers(0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002404
Jamie Madill884a4622013-10-24 17:49:41 -04002405 ASSERT(width > 0 && height > 0 && depth > 0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002406
Jamie Madill884a4622013-10-24 17:49:41 -04002407 // use existing storage level count, when previously specified by TexStorage*D
Nicolas Capensbf712d02014-03-31 14:23:35 -04002408 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002409
Nicolas Capensbf712d02014-03-31 14:23:35 -04002410 return new rx::TextureStorageInterface2DArray(mRenderer, getBaseLevelInternalFormat(), renderTarget, width, height, depth, levels);
Jamie Madill884a4622013-10-24 17:49:41 -04002411}
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002412
Jamie Madill884a4622013-10-24 17:49:41 -04002413void Texture2DArray::setCompleteTexStorage(rx::TextureStorageInterface2DArray *newCompleteTexStorage)
2414{
2415 SafeDelete(mTexStorage);
2416 mTexStorage = newCompleteTexStorage;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002417 mDirtyImages = true;
Jamie Madill884a4622013-10-24 17:49:41 -04002418
2419 // We do not support managed 2D array storage, as managed storage is ES2/D3D9 only
2420 ASSERT(!mTexStorage->isManaged());
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002421}
2422
Jamie Madill169d1112013-10-24 17:49:37 -04002423void Texture2DArray::updateStorage()
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002424{
Geoff Lang946b9482014-05-12 16:37:25 -04002425 ASSERT(mTexStorage != NULL);
2426 GLint storageLevels = mTexStorage->getLevelCount();
2427 for (int level = 0; level < storageLevels; level++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002428 {
Jamie Madilld9b9a502013-10-10 17:46:13 -04002429 if (isLevelComplete(level))
2430 {
Jamie Madill169d1112013-10-24 17:49:37 -04002431 updateStorageLevel(level);
Jamie Madilld9b9a502013-10-10 17:46:13 -04002432 }
Jamie Madill07edd442013-07-19 16:36:58 -04002433 }
2434}
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002435
Jamie Madill169d1112013-10-24 17:49:37 -04002436void Texture2DArray::updateStorageLevel(int level)
Jamie Madill07edd442013-07-19 16:36:58 -04002437{
Jamie Madillaee7ad82013-10-10 16:07:32 -04002438 ASSERT(level >= 0 && level < (int)ArraySize(mLayerCounts));
2439 ASSERT(isLevelComplete(level));
2440
Jamie Madill07edd442013-07-19 16:36:58 -04002441 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2442 {
Jamie Madillaee7ad82013-10-10 16:07:32 -04002443 ASSERT(mImageArray[level] != NULL && mImageArray[level][layer] != NULL);
2444 if (mImageArray[level][layer]->isDirty())
Jamie Madill07edd442013-07-19 16:36:58 -04002445 {
Jamie Madillaee7ad82013-10-10 16:07:32 -04002446 commitRect(level, 0, 0, layer, getWidth(level), getHeight(level));
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002447 }
2448 }
2449}
2450
Jamie Madille83d1a92013-10-24 17:49:33 -04002451bool Texture2DArray::ensureRenderTarget()
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002452{
Jamie Madill884a4622013-10-24 17:49:41 -04002453 initializeStorage(true);
2454
Jamie Madillb8f8b892014-01-07 10:12:50 -05002455 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0 && getLayers(0) > 0)
Jamie Madille83d1a92013-10-24 17:49:33 -04002456 {
Jamie Madill884a4622013-10-24 17:49:41 -04002457 ASSERT(mTexStorage);
2458 if (!mTexStorage->isRenderTarget())
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002459 {
Jamie Madill884a4622013-10-24 17:49:41 -04002460 rx::TextureStorageInterface2DArray *newRenderTargetStorage = createCompleteStorage(true);
2461
2462 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002463 {
Jamie Madill884a4622013-10-24 17:49:41 -04002464 delete newRenderTargetStorage;
Jamie Madille83d1a92013-10-24 17:49:33 -04002465 return gl::error(GL_OUT_OF_MEMORY, false);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002466 }
Jamie Madill884a4622013-10-24 17:49:41 -04002467
2468 setCompleteTexStorage(newRenderTargetStorage);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002469 }
2470 }
2471
Jamie Madille83d1a92013-10-24 17:49:33 -04002472 return (mTexStorage && mTexStorage->isRenderTarget());
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002473}
2474
Geoff Lang8040f572013-07-25 16:49:54 -04002475rx::RenderTarget *Texture2DArray::getRenderTarget(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002476{
Geoff Lang8040f572013-07-25 16:49:54 -04002477 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04002478 if (!ensureRenderTarget())
Geoff Lang8040f572013-07-25 16:49:54 -04002479 {
2480 return NULL;
2481 }
2482
Jamie Madill169d1112013-10-24 17:49:37 -04002483 updateStorageLevel(level);
Geoff Lang8040f572013-07-25 16:49:54 -04002484
2485 // ensure this is NOT a depth texture
2486 if (isDepth(level))
2487 {
2488 return NULL;
2489 }
2490
2491 return mTexStorage->getRenderTarget(level, layer);
2492}
2493
2494rx::RenderTarget *Texture2DArray::getDepthStencil(GLint level, GLint layer)
2495{
2496 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04002497 if (!ensureRenderTarget())
Geoff Lang8040f572013-07-25 16:49:54 -04002498 {
2499 return NULL;
2500 }
2501
Jamie Madill169d1112013-10-24 17:49:37 -04002502 updateStorageLevel(level);
Geoff Lang8040f572013-07-25 16:49:54 -04002503
2504 // ensure this is a depth texture
2505 if (!isDepth(level))
2506 {
2507 return NULL;
2508 }
2509
2510 return mTexStorage->getRenderTarget(level, layer);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002511}
2512
Geoff Lang005df412013-10-16 14:12:50 -04002513void Texture2DArray::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002514{
2515 // If there currently is a corresponding storage texture image, it has these parameters
Jamie Madilld3d2a342013-10-07 10:46:35 -04002516 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2517 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
Jamie Madillb8f8b892014-01-07 10:12:50 -05002518 const int storageDepth = getLayers(0);
Geoff Lang005df412013-10-16 14:12:50 -04002519 const GLenum storageFormat = getBaseLevelInternalFormat();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002520
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002521 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002522 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002523 delete mImageArray[level][layer];
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002524 }
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002525 delete[] mImageArray[level];
Jamie Madill152ed092013-10-09 17:01:15 -04002526 mImageArray[level] = NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002527 mLayerCounts[level] = depth;
2528
Jamie Madill152ed092013-10-09 17:01:15 -04002529 if (depth > 0)
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002530 {
Jamie Madill152ed092013-10-09 17:01:15 -04002531 mImageArray[level] = new rx::Image*[depth]();
2532
2533 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2534 {
2535 mImageArray[level][layer] = mRenderer->createImage();
2536 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, width, height, 1, false);
2537 }
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002538 }
2539
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002540 if (mTexStorage)
2541 {
Nicolas Capensbf712d02014-03-31 14:23:35 -04002542 const int storageLevels = mTexStorage->getLevelCount();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002543
2544 if ((level >= storageLevels && storageLevels != 0) ||
2545 width != storageWidth ||
2546 height != storageHeight ||
2547 depth != storageDepth ||
2548 internalformat != storageFormat) // Discard mismatched storage
2549 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002550 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002551 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002552 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002553 {
2554 mImageArray[level][layer]->markDirty();
2555 }
2556 }
2557
2558 delete mTexStorage;
2559 mTexStorage = NULL;
2560 mDirtyImages = true;
2561 }
2562 }
2563}
2564
2565void Texture2DArray::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint layerTarget, GLsizei width, GLsizei height)
2566{
Jamie Madillb8f8b892014-01-07 10:12:50 -05002567 if (isValidLevel(level) && layerTarget < getLayers(level))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002568 {
2569 rx::Image *image = mImageArray[level][layerTarget];
Jamie Madill169d1112013-10-24 17:49:37 -04002570 if (image->copyToStorage(mTexStorage, level, xoffset, yoffset, layerTarget, width, height))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002571 {
2572 image->markClean();
2573 }
2574 }
2575}
2576
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00002577}