blob: 75205757ffad1fd4d2ffd996ca68d6ee0e54fcb9 [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 Langcec35902014-04-16 10:52:36 -0400261 if ((isPow2(width) && isPow2(height) && isPow2(depth)) || mRenderer->getCaps().extensions.textureNPOT)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000262 {
Jamie Madill6b7440c2013-10-24 17:49:47 -0400263 // Maximum number of levels
Geoff Lang98705b72014-03-31 16:00:03 -0400264 return log2(std::max(std::max(width, height), depth)) + 1;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000265 }
266 else
267 {
268 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
269 return 1;
270 }
271}
272
Jamie Madill22f843a2013-10-24 17:49:36 -0400273int Texture::mipLevels() const
274{
Geoff Lang98705b72014-03-31 16:00:03 -0400275 return log2(std::max(std::max(getBaseLevelWidth(), getBaseLevelHeight()), getBaseLevelDepth())) + 1;
Jamie Madill22f843a2013-10-24 17:49:36 -0400276}
277
Geoff Lang4907f2c2013-07-25 12:53:57 -0400278Texture2D::Texture2D(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_2D)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000279{
280 mTexStorage = NULL;
281 mSurface = NULL;
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000282
283 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
284 {
daniel@transgaming.com244e1832012-12-20 20:52:35 +0000285 mImageArray[i] = renderer->createImage();
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000286 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000287}
288
289Texture2D::~Texture2D()
290{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000291 delete mTexStorage;
292 mTexStorage = NULL;
293
294 if (mSurface)
295 {
296 mSurface->setBoundTexture(NULL);
297 mSurface = NULL;
298 }
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000299
300 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
301 {
302 delete mImageArray[i];
303 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000304}
305
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000306GLsizei Texture2D::getWidth(GLint level) const
307{
308 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000309 return mImageArray[level]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000310 else
311 return 0;
312}
313
314GLsizei Texture2D::getHeight(GLint level) const
315{
316 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000317 return mImageArray[level]->getHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000318 else
319 return 0;
320}
321
322GLenum Texture2D::getInternalFormat(GLint level) const
323{
324 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000325 return mImageArray[level]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000326 else
327 return GL_NONE;
328}
329
daniel@transgaming.com20d36662012-10-31 19:51:43 +0000330GLenum Texture2D::getActualFormat(GLint level) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000331{
332 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000333 return mImageArray[level]->getActualFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000334 else
Geoff Langcbf727a2014-02-10 12:50:45 -0500335 return GL_NONE;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000336}
337
Geoff Lang005df412013-10-16 14:12:50 -0400338void Texture2D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000339{
340 releaseTexImage();
shannon.woods@transgaming.com8a406682013-02-28 23:15:26 +0000341
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000342 // If there currently is a corresponding storage texture image, it has these parameters
Jamie Madilld3d2a342013-10-07 10:46:35 -0400343 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
344 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
Geoff Lang005df412013-10-16 14:12:50 -0400345 const GLenum storageFormat = getBaseLevelInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000346
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000347 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, width, height, 1, false);
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000348
349 if (mTexStorage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000350 {
Nicolas Capensbf712d02014-03-31 14:23:35 -0400351 const int storageLevels = mTexStorage->getLevelCount();
352
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000353 if ((level >= storageLevels && storageLevels != 0) ||
354 width != storageWidth ||
355 height != storageHeight ||
356 internalformat != storageFormat) // Discard mismatched storage
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000357 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000358 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
359 {
360 mImageArray[i]->markDirty();
361 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000362
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000363 delete mTexStorage;
364 mTexStorage = NULL;
365 mDirtyImages = true;
366 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000367 }
368}
369
Geoff Lang005df412013-10-16 14:12:50 -0400370void 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 +0000371{
Geoff Lange4a492b2014-06-19 14:14:41 -0400372 GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat) ? internalFormat
373 : GetSizedInternalFormat(format, type);
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +0000374 redefineImage(level, sizedInternalFormat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000375
Jamie Madill8cc7d972013-10-10 15:51:55 -0400376 bool fastUnpacked = false;
377
Jamie Madill1beb1db2013-09-18 14:36:28 -0400378 // Attempt a fast gpu copy of the pixel data to the surface
Jamie Madill8cc7d972013-10-10 15:51:55 -0400379 if (isFastUnpackable(unpack, sizedInternalFormat) && isLevelComplete(level))
Jamie Madill1beb1db2013-09-18 14:36:28 -0400380 {
Jamie Madill8cc7d972013-10-10 15:51:55 -0400381 // Will try to create RT storage if it does not exist
382 rx::RenderTarget *destRenderTarget = getRenderTarget(level);
383 Box destArea(0, 0, 0, getWidth(level), getHeight(level), 1);
384
385 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget))
386 {
387 // Ensure we don't overwrite our newly initialized data
388 mImageArray[level]->markClean();
389
390 fastUnpacked = true;
391 }
Jamie Madill1beb1db2013-09-18 14:36:28 -0400392 }
Jamie Madill8cc7d972013-10-10 15:51:55 -0400393
394 if (!fastUnpacked)
Jamie Madill1beb1db2013-09-18 14:36:28 -0400395 {
396 Texture::setImage(unpack, type, pixels, mImageArray[level]);
397 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000398}
399
400void Texture2D::bindTexImage(egl::Surface *surface)
401{
402 releaseTexImage();
403
Geoff Lang005df412013-10-16 14:12:50 -0400404 GLenum internalformat = surface->getFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000405
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000406 mImageArray[0]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, surface->getWidth(), surface->getHeight(), 1, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000407
408 delete mTexStorage;
daniel@transgaming.comd8353dd2012-12-20 21:11:14 +0000409 mTexStorage = new rx::TextureStorageInterface2D(mRenderer, surface->getSwapChain());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000410
411 mDirtyImages = true;
412 mSurface = surface;
413 mSurface->setBoundTexture(this);
414}
415
416void Texture2D::releaseTexImage()
417{
418 if (mSurface)
419 {
420 mSurface->setBoundTexture(NULL);
421 mSurface = NULL;
422
423 if (mTexStorage)
424 {
425 delete mTexStorage;
426 mTexStorage = NULL;
427 }
428
429 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
430 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000431 mImageArray[i]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000432 }
433 }
434}
435
436void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
437{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000438 // 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 +0000439 redefineImage(level, format, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000440
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000441 Texture::setCompressedImage(imageSize, pixels, mImageArray[level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000442}
443
444void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
445{
Jamie Madill07bb8cf2013-10-24 17:49:44 -0400446 if (isValidLevel(level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000447 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000448 rx::Image *image = mImageArray[level];
Jamie Madill169d1112013-10-24 17:49:37 -0400449 if (image->copyToStorage(mTexStorage, level, xoffset, yoffset, width, height))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000450 {
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000451 image->markClean();
452 }
453 }
454}
455
Jamie Madill88f18f42013-09-18 14:36:19 -0400456void 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 +0000457{
Jamie Madill065e1a32013-10-10 15:11:50 -0400458 bool fastUnpacked = false;
459
460 if (isFastUnpackable(unpack, getInternalFormat(level)) && isLevelComplete(level))
461 {
462 rx::RenderTarget *renderTarget = getRenderTarget(level);
463 Box destArea(xoffset, yoffset, 0, width, height, 1);
464
465 if (renderTarget && fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, renderTarget))
466 {
467 // Ensure we don't overwrite our newly initialized data
468 mImageArray[level]->markClean();
469
470 fastUnpacked = true;
471 }
472 }
473
474 if (!fastUnpacked && Texture::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, mImageArray[level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000475 {
476 commitRect(level, xoffset, yoffset, width, height);
477 }
478}
479
480void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
481{
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000482 if (Texture::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000483 {
484 commitRect(level, xoffset, yoffset, width, height);
485 }
486}
487
488void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
489{
Geoff Lange4a492b2014-06-19 14:14:41 -0400490 GLenum sizedInternalFormat = IsSizedInternalFormat(format) ? format
491 : GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +0000492 redefineImage(level, sizedInternalFormat, width, height);
shannon.woods@transgaming.com8a406682013-02-28 23:15:26 +0000493
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000494 if (!mImageArray[level]->isRenderableFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000495 {
shannon.woods%transgaming.com@gtempaccount.come5dcce72013-04-13 03:44:33 +0000496 mImageArray[level]->copy(0, 0, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000497 mDirtyImages = true;
498 }
499 else
500 {
Jamie Madille83d1a92013-10-24 17:49:33 -0400501 ensureRenderTarget();
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000502 mImageArray[level]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000503
Jamie Madill07bb8cf2013-10-24 17:49:44 -0400504 if (width != 0 && height != 0 && isValidLevel(level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000505 {
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +0000506 gl::Rectangle sourceRect;
507 sourceRect.x = x;
508 sourceRect.width = width;
509 sourceRect.y = y;
510 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000511
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +0000512 mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000513 }
514 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000515}
516
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +0000517void 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 +0000518{
Jamie Madill07edd442013-07-19 16:36:58 -0400519 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
520 // the current level we're copying to is defined (with appropriate format, width & height)
521 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
522
523 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000524 {
shannon.woods%transgaming.com@gtempaccount.come5dcce72013-04-13 03:44:33 +0000525 mImageArray[level]->copy(xoffset, yoffset, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000526 mDirtyImages = true;
527 }
528 else
529 {
Jamie Madille83d1a92013-10-24 17:49:33 -0400530 ensureRenderTarget();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000531
Jamie Madill07bb8cf2013-10-24 17:49:44 -0400532 if (isValidLevel(level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000533 {
Jamie Madill169d1112013-10-24 17:49:37 -0400534 updateStorageLevel(level);
Jamie Madill07edd442013-07-19 16:36:58 -0400535
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +0000536 gl::Rectangle sourceRect;
537 sourceRect.x = x;
538 sourceRect.width = width;
539 sourceRect.y = y;
540 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000541
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +0000542 mRenderer->copyImage(source, sourceRect,
Geoff Lange4a492b2014-06-19 14:14:41 -0400543 gl::GetFormat(getBaseLevelInternalFormat()),
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +0000544 xoffset, yoffset, mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000545 }
546 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000547}
548
549void Texture2D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height)
550{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000551 for (int level = 0; level < levels; level++)
552 {
Jamie Madill73b5d062013-10-24 17:49:38 -0400553 GLsizei levelWidth = std::max(1, width >> level);
554 GLsizei levelHeight = std::max(1, height >> level);
555 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, levelWidth, levelHeight, 1, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000556 }
557
558 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
559 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000560 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000561 }
562
Jamie Madill73b5d062013-10-24 17:49:38 -0400563 mImmutable = true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000564
Nicolas Capensbf712d02014-03-31 14:23:35 -0400565 setCompleteTexStorage(new rx::TextureStorageInterface2D(mRenderer, internalformat, IsRenderTargetUsage(mUsage), width, height, levels));
Jamie Madill73b5d062013-10-24 17:49:38 -0400566}
567
568void Texture2D::setCompleteTexStorage(rx::TextureStorageInterface2D *newCompleteTexStorage)
569{
570 SafeDelete(mTexStorage);
571 mTexStorage = newCompleteTexStorage;
572
573 if (mTexStorage && mTexStorage->isManaged())
574 {
Nicolas Capensbf712d02014-03-31 14:23:35 -0400575 for (int level = 0; level < mTexStorage->getLevelCount(); level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000576 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000577 mImageArray[level]->setManagedSurface(mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000578 }
579 }
Jamie Madill73b5d062013-10-24 17:49:38 -0400580
581 mDirtyImages = true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000582}
583
584// Tests for 2D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85.
Jamie Madillf8989902013-07-19 16:36:58 -0400585bool Texture2D::isSamplerComplete(const SamplerState &samplerState) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000586{
Jamie Madilld3d2a342013-10-07 10:46:35 -0400587 GLsizei width = getBaseLevelWidth();
588 GLsizei height = getBaseLevelHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000589
590 if (width <= 0 || height <= 0)
591 {
592 return false;
593 }
594
Geoff Langcec35902014-04-16 10:52:36 -0400595 if (!mRenderer->getCaps().textureCaps.get(getInternalFormat(0)).filtering)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000596 {
Jamie Madillf8989902013-07-19 16:36:58 -0400597 if (samplerState.magFilter != GL_NEAREST ||
598 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000599 {
600 return false;
601 }
602 }
603
Geoff Langcec35902014-04-16 10:52:36 -0400604 bool npotSupport = mRenderer->getCaps().extensions.textureNPOT;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000605
606 if (!npotSupport)
607 {
Jamie Madillf8989902013-07-19 16:36:58 -0400608 if ((samplerState.wrapS != GL_CLAMP_TO_EDGE && !isPow2(width)) ||
609 (samplerState.wrapT != GL_CLAMP_TO_EDGE && !isPow2(height)))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000610 {
611 return false;
612 }
613 }
614
Jamie Madillf8989902013-07-19 16:36:58 -0400615 if (IsMipmapFiltered(samplerState))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000616 {
617 if (!npotSupport)
618 {
619 if (!isPow2(width) || !isPow2(height))
620 {
621 return false;
622 }
623 }
624
625 if (!isMipmapComplete())
626 {
627 return false;
628 }
629 }
630
Geoff Langc82fc412013-07-10 14:43:42 -0400631 // OpenGLES 3.0.2 spec section 3.8.13 states that a texture is not mipmap complete if:
632 // The internalformat specified for the texture arrays is a sized internal depth or
633 // depth and stencil format (see table 3.13), the value of TEXTURE_COMPARE_-
634 // MODE is NONE, and either the magnification filter is not NEAREST or the mini-
635 // fication filter is neither NEAREST nor NEAREST_MIPMAP_NEAREST.
Geoff Lange4a492b2014-06-19 14:14:41 -0400636 if (gl::GetDepthBits(getInternalFormat(0)) > 0 && mRenderer->getCurrentClientVersion() > 2)
Geoff Langc82fc412013-07-10 14:43:42 -0400637 {
638 if (mSamplerState.compareMode == GL_NONE)
639 {
640 if ((mSamplerState.minFilter != GL_NEAREST && mSamplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST) ||
641 mSamplerState.magFilter != GL_NEAREST)
642 {
643 return false;
644 }
645 }
646 }
647
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000648 return true;
649}
650
651// Tests for 2D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
652bool Texture2D::isMipmapComplete() const
653{
Geoff Lang98705b72014-03-31 16:00:03 -0400654 int levelCount = mipLevels();
Jamie Madill07edd442013-07-19 16:36:58 -0400655
Geoff Lang98705b72014-03-31 16:00:03 -0400656 for (int level = 0; level < levelCount; level++)
Jamie Madill07edd442013-07-19 16:36:58 -0400657 {
658 if (!isLevelComplete(level))
659 {
660 return false;
661 }
662 }
663
664 return true;
665}
666
667bool Texture2D::isLevelComplete(int level) const
668{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000669 if (isImmutable())
670 {
671 return true;
672 }
673
Jamie Madill648c9682014-01-21 16:50:58 -0500674 const rx::Image *baseImage = getBaseLevelImage();
675
676 GLsizei width = baseImage->getWidth();
677 GLsizei height = baseImage->getHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000678
679 if (width <= 0 || height <= 0)
680 {
681 return false;
682 }
683
Jamie Madill07edd442013-07-19 16:36:58 -0400684 // The base image level is complete if the width and height are positive
685 if (level == 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000686 {
Jamie Madill07edd442013-07-19 16:36:58 -0400687 return true;
688 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000689
Jamie Madill07edd442013-07-19 16:36:58 -0400690 ASSERT(level >= 1 && level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
691 rx::Image *image = mImageArray[level];
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000692
Jamie Madill648c9682014-01-21 16:50:58 -0500693 if (image->getInternalFormat() != baseImage->getInternalFormat())
Jamie Madill07edd442013-07-19 16:36:58 -0400694 {
695 return false;
696 }
697
698 if (image->getWidth() != std::max(1, width >> level))
699 {
700 return false;
701 }
702
703 if (image->getHeight() != std::max(1, height >> level))
704 {
705 return false;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000706 }
707
708 return true;
709}
710
711bool Texture2D::isCompressed(GLint level) const
712{
Geoff Lange4a492b2014-06-19 14:14:41 -0400713 return IsFormatCompressed(getInternalFormat(level));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000714}
715
716bool Texture2D::isDepth(GLint level) const
717{
Geoff Lange4a492b2014-06-19 14:14:41 -0400718 return GetDepthBits(getInternalFormat(level)) > 0;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000719}
720
daniel@transgaming.comf032cb82012-10-31 19:51:52 +0000721// Constructs a native texture resource from the texture images
Jamie Madill73b5d062013-10-24 17:49:38 -0400722void Texture2D::initializeStorage(bool renderTarget)
723{
724 // Only initialize the first time this texture is used as a render target or shader resource
725 if (mTexStorage)
726 {
727 return;
728 }
729
730 // do not attempt to create storage for nonexistant data
731 if (!isLevelComplete(0))
732 {
733 return;
734 }
735
736 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
737
738 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
739 ASSERT(mTexStorage);
740
741 // flush image data to the storage
742 updateStorage();
743}
744
745rx::TextureStorageInterface2D *Texture2D::createCompleteStorage(bool renderTarget) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000746{
Jamie Madilld3d2a342013-10-07 10:46:35 -0400747 GLsizei width = getBaseLevelWidth();
748 GLsizei height = getBaseLevelHeight();
daniel@transgaming.come6a09842012-09-17 21:28:55 +0000749
Jamie Madill73b5d062013-10-24 17:49:38 -0400750 ASSERT(width > 0 && height > 0);
daniel@transgaming.come6a09842012-09-17 21:28:55 +0000751
Jamie Madill73b5d062013-10-24 17:49:38 -0400752 // use existing storage level count, when previously specified by TexStorage*D
Nicolas Capensbf712d02014-03-31 14:23:35 -0400753 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000754
Nicolas Capensbf712d02014-03-31 14:23:35 -0400755 return new rx::TextureStorageInterface2D(mRenderer, getBaseLevelInternalFormat(), renderTarget, width, height, levels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000756}
757
Jamie Madill169d1112013-10-24 17:49:37 -0400758void Texture2D::updateStorage()
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000759{
Geoff Lang946b9482014-05-12 16:37:25 -0400760 ASSERT(mTexStorage != NULL);
761 GLint storageLevels = mTexStorage->getLevelCount();
762 for (int level = 0; level < storageLevels; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000763 {
Jamie Madill648c9682014-01-21 16:50:58 -0500764 if (mImageArray[level]->isDirty() && isLevelComplete(level))
Jamie Madilld9b9a502013-10-10 17:46:13 -0400765 {
Jamie Madill169d1112013-10-24 17:49:37 -0400766 updateStorageLevel(level);
Jamie Madilld9b9a502013-10-10 17:46:13 -0400767 }
Jamie Madill07edd442013-07-19 16:36:58 -0400768 }
769}
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000770
Jamie Madill169d1112013-10-24 17:49:37 -0400771void Texture2D::updateStorageLevel(int level)
Jamie Madill07edd442013-07-19 16:36:58 -0400772{
773 ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
Jamie Madillaee7ad82013-10-10 16:07:32 -0400774 ASSERT(isLevelComplete(level));
Jamie Madill07edd442013-07-19 16:36:58 -0400775
Jamie Madillaee7ad82013-10-10 16:07:32 -0400776 if (mImageArray[level]->isDirty())
Jamie Madill07edd442013-07-19 16:36:58 -0400777 {
Jamie Madillaee7ad82013-10-10 16:07:32 -0400778 commitRect(level, 0, 0, getWidth(level), getHeight(level));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000779 }
780}
781
Jamie Madille83d1a92013-10-24 17:49:33 -0400782bool Texture2D::ensureRenderTarget()
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000783{
Jamie Madill73b5d062013-10-24 17:49:38 -0400784 initializeStorage(true);
785
786 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0)
Jamie Madille83d1a92013-10-24 17:49:33 -0400787 {
Jamie Madill73b5d062013-10-24 17:49:38 -0400788 ASSERT(mTexStorage);
789 if (!mTexStorage->isRenderTarget())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000790 {
Jamie Madill73b5d062013-10-24 17:49:38 -0400791 rx::TextureStorageInterface2D *newRenderTargetStorage = createCompleteStorage(true);
792
793 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
794 {
795 delete newRenderTargetStorage;
Jamie Madille83d1a92013-10-24 17:49:33 -0400796 return gl::error(GL_OUT_OF_MEMORY, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000797 }
Jamie Madill73b5d062013-10-24 17:49:38 -0400798
799 setCompleteTexStorage(newRenderTargetStorage);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000800 }
801 }
802
Jamie Madille83d1a92013-10-24 17:49:33 -0400803 return (mTexStorage && mTexStorage->isRenderTarget());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000804}
805
806void Texture2D::generateMipmaps()
807{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000808 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Geoff Lang98705b72014-03-31 16:00:03 -0400809 int levelCount = mipLevels();
810 for (int level = 1; level < levelCount; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000811 {
Jamie Madill22f843a2013-10-24 17:49:36 -0400812 redefineImage(level, getBaseLevelInternalFormat(),
813 std::max(getBaseLevelWidth() >> level, 1),
814 std::max(getBaseLevelHeight() >> level, 1));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000815 }
816
817 if (mTexStorage && mTexStorage->isRenderTarget())
818 {
Geoff Lang98705b72014-03-31 16:00:03 -0400819 for (int level = 1; level < levelCount; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000820 {
Jamie Madill22f843a2013-10-24 17:49:36 -0400821 mTexStorage->generateMipmap(level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000822
Jamie Madill22f843a2013-10-24 17:49:36 -0400823 mImageArray[level]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000824 }
825 }
826 else
827 {
Geoff Lang98705b72014-03-31 16:00:03 -0400828 for (int level = 1; level < levelCount; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000829 {
Jamie Madill22f843a2013-10-24 17:49:36 -0400830 mRenderer->generateMipmap(mImageArray[level], mImageArray[level - 1]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000831 }
832 }
833}
834
Jamie Madilld3d2a342013-10-07 10:46:35 -0400835const rx::Image *Texture2D::getBaseLevelImage() const
836{
837 return mImageArray[0];
838}
839
Jamie Madill2ebab852013-10-24 17:49:42 -0400840rx::TextureStorageInterface *Texture2D::getBaseLevelStorage()
841{
842 return mTexStorage;
843}
844
Geoff Lang8040f572013-07-25 16:49:54 -0400845unsigned int Texture2D::getRenderTargetSerial(GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000846{
Jamie Madille83d1a92013-10-24 17:49:33 -0400847 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(level) : 0);
Geoff Lang8040f572013-07-25 16:49:54 -0400848}
849
850rx::RenderTarget *Texture2D::getRenderTarget(GLint level)
851{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000852 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -0400853 if (!ensureRenderTarget())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000854 {
855 return NULL;
856 }
857
Jamie Madill169d1112013-10-24 17:49:37 -0400858 updateStorageLevel(level);
Geoff Lang8040f572013-07-25 16:49:54 -0400859
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000860 // ensure this is NOT a depth texture
Geoff Lang8040f572013-07-25 16:49:54 -0400861 if (isDepth(level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000862 {
863 return NULL;
864 }
daniel@transgaming.com34da3972012-12-20 21:10:29 +0000865
Geoff Lang8040f572013-07-25 16:49:54 -0400866 return mTexStorage->getRenderTarget(level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000867}
868
Geoff Lang8040f572013-07-25 16:49:54 -0400869rx::RenderTarget *Texture2D::getDepthSencil(GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000870{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000871 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -0400872 if (!ensureRenderTarget())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000873 {
874 return NULL;
875 }
876
Jamie Madill169d1112013-10-24 17:49:37 -0400877 updateStorageLevel(level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000878
879 // ensure this is actually a depth texture
Geoff Lang8040f572013-07-25 16:49:54 -0400880 if (!isDepth(level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000881 {
882 return NULL;
883 }
Geoff Lang8040f572013-07-25 16:49:54 -0400884
885 return mTexStorage->getRenderTarget(level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000886}
887
Jamie Madill07bb8cf2013-10-24 17:49:44 -0400888bool Texture2D::isValidLevel(int level) const
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +0000889{
Nicolas Capensbf712d02014-03-31 14:23:35 -0400890 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : false);
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +0000891}
892
Geoff Lang4907f2c2013-07-25 12:53:57 -0400893TextureCubeMap::TextureCubeMap(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_CUBE_MAP)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000894{
895 mTexStorage = NULL;
896 for (int i = 0; i < 6; i++)
897 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000898 for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
899 {
daniel@transgaming.com244e1832012-12-20 20:52:35 +0000900 mImageArray[i][j] = renderer->createImage();
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000901 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000902 }
903}
904
905TextureCubeMap::~TextureCubeMap()
906{
907 for (int i = 0; i < 6; i++)
908 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000909 for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
910 {
911 delete mImageArray[i][j];
912 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000913 }
914
915 delete mTexStorage;
916 mTexStorage = NULL;
917}
918
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000919GLsizei TextureCubeMap::getWidth(GLenum target, GLint level) const
920{
921 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Jamie Madill2db197c2013-10-24 17:49:35 -0400922 return mImageArray[targetToIndex(target)][level]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000923 else
924 return 0;
925}
926
927GLsizei TextureCubeMap::getHeight(GLenum target, GLint level) const
928{
929 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Jamie Madill2db197c2013-10-24 17:49:35 -0400930 return mImageArray[targetToIndex(target)][level]->getHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000931 else
932 return 0;
933}
934
935GLenum TextureCubeMap::getInternalFormat(GLenum target, GLint level) const
936{
937 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Jamie Madill2db197c2013-10-24 17:49:35 -0400938 return mImageArray[targetToIndex(target)][level]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000939 else
940 return GL_NONE;
941}
942
daniel@transgaming.com20d36662012-10-31 19:51:43 +0000943GLenum TextureCubeMap::getActualFormat(GLenum target, GLint level) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000944{
945 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Jamie Madill2db197c2013-10-24 17:49:35 -0400946 return mImageArray[targetToIndex(target)][level]->getActualFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000947 else
Geoff Langcbf727a2014-02-10 12:50:45 -0500948 return GL_NONE;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000949}
950
Geoff Lang005df412013-10-16 14:12:50 -0400951void 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 +0000952{
Jamie Madill88f18f42013-09-18 14:36:19 -0400953 setImage(0, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000954}
955
Geoff Lang005df412013-10-16 14:12:50 -0400956void 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 +0000957{
Jamie Madill88f18f42013-09-18 14:36:19 -0400958 setImage(1, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000959}
960
Geoff Lang005df412013-10-16 14:12:50 -0400961void 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 +0000962{
Jamie Madill88f18f42013-09-18 14:36:19 -0400963 setImage(2, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000964}
965
Geoff Lang005df412013-10-16 14:12:50 -0400966void 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 +0000967{
Jamie Madill88f18f42013-09-18 14:36:19 -0400968 setImage(3, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000969}
970
Geoff Lang005df412013-10-16 14:12:50 -0400971void 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 +0000972{
Jamie Madill88f18f42013-09-18 14:36:19 -0400973 setImage(4, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000974}
975
Geoff Lang005df412013-10-16 14:12:50 -0400976void 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 +0000977{
Jamie Madill88f18f42013-09-18 14:36:19 -0400978 setImage(5, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000979}
980
Jamie Madill2db197c2013-10-24 17:49:35 -0400981void 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 +0000982{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000983 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
Jamie Madill2db197c2013-10-24 17:49:35 -0400984 int faceIndex = targetToIndex(target);
985 redefineImage(faceIndex, level, format, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000986
Jamie Madill2db197c2013-10-24 17:49:35 -0400987 Texture::setCompressedImage(imageSize, pixels, mImageArray[faceIndex][level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000988}
989
Jamie Madill2db197c2013-10-24 17:49:35 -0400990void TextureCubeMap::commitRect(int faceIndex, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000991{
Jamie Madill07bb8cf2013-10-24 17:49:44 -0400992 if (isValidFaceLevel(faceIndex, level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000993 {
Jamie Madill2db197c2013-10-24 17:49:35 -0400994 rx::Image *image = mImageArray[faceIndex][level];
Jamie Madill169d1112013-10-24 17:49:37 -0400995 if (image->copyToStorage(mTexStorage, faceIndex, level, xoffset, yoffset, width, height))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000996 image->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000997 }
998}
999
Jamie Madill88f18f42013-09-18 14:36:19 -04001000void 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 +00001001{
Jamie Madill2db197c2013-10-24 17:49:35 -04001002 int faceIndex = targetToIndex(target);
1003 if (Texture::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, mImageArray[faceIndex][level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001004 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001005 commitRect(faceIndex, level, xoffset, yoffset, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001006 }
1007}
1008
1009void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1010{
Jamie Madill2db197c2013-10-24 17:49:35 -04001011 int faceIndex = targetToIndex(target);
1012 if (Texture::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[faceIndex][level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001013 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001014 commitRect(faceIndex, level, xoffset, yoffset, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001015 }
1016}
1017
1018// Tests for cube map sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 86.
Jamie Madillf8989902013-07-19 16:36:58 -04001019bool TextureCubeMap::isSamplerComplete(const SamplerState &samplerState) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001020{
Jamie Madilld3d2a342013-10-07 10:46:35 -04001021 int size = getBaseLevelWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001022
Jamie Madillf8989902013-07-19 16:36:58 -04001023 bool mipmapping = IsMipmapFiltered(samplerState);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001024
Geoff Langcec35902014-04-16 10:52:36 -04001025 if (!mRenderer->getCaps().textureCaps.get(getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0)).filtering)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001026 {
Jamie Madillf8989902013-07-19 16:36:58 -04001027 if (samplerState.magFilter != GL_NEAREST ||
1028 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001029 {
1030 return false;
1031 }
1032 }
1033
Geoff Langcec35902014-04-16 10:52:36 -04001034 if (!isPow2(size) && !mRenderer->getCaps().extensions.textureNPOT)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001035 {
Jamie Madillf8989902013-07-19 16:36:58 -04001036 if (samplerState.wrapS != GL_CLAMP_TO_EDGE || samplerState.wrapT != GL_CLAMP_TO_EDGE || mipmapping)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001037 {
1038 return false;
1039 }
1040 }
1041
1042 if (!mipmapping)
1043 {
1044 if (!isCubeComplete())
1045 {
1046 return false;
1047 }
1048 }
1049 else
1050 {
1051 if (!isMipmapCubeComplete()) // Also tests for isCubeComplete()
1052 {
1053 return false;
1054 }
1055 }
1056
1057 return true;
1058}
1059
1060// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1061bool TextureCubeMap::isCubeComplete() const
1062{
Jamie Madillc1f8b162013-10-07 10:46:38 -04001063 int baseWidth = getBaseLevelWidth();
1064 int baseHeight = getBaseLevelHeight();
1065 GLenum baseFormat = getBaseLevelInternalFormat();
1066
1067 if (baseWidth <= 0 || baseWidth != baseHeight)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001068 {
1069 return false;
1070 }
1071
Jamie Madill2db197c2013-10-24 17:49:35 -04001072 for (int faceIndex = 1; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001073 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001074 const rx::Image &faceBaseImage = *mImageArray[faceIndex][0];
Jamie Madillc1f8b162013-10-07 10:46:38 -04001075
1076 if (faceBaseImage.getWidth() != baseWidth ||
1077 faceBaseImage.getHeight() != baseHeight ||
1078 faceBaseImage.getInternalFormat() != baseFormat )
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001079 {
1080 return false;
1081 }
1082 }
1083
1084 return true;
1085}
1086
1087bool TextureCubeMap::isMipmapCubeComplete() const
1088{
1089 if (isImmutable())
1090 {
1091 return true;
1092 }
1093
1094 if (!isCubeComplete())
1095 {
1096 return false;
1097 }
1098
Geoff Lang98705b72014-03-31 16:00:03 -04001099 int levelCount = mipLevels();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001100
1101 for (int face = 0; face < 6; face++)
1102 {
Geoff Lang98705b72014-03-31 16:00:03 -04001103 for (int level = 1; level < levelCount; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001104 {
Jamie Madill07edd442013-07-19 16:36:58 -04001105 if (!isFaceLevelComplete(face, level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001106 {
1107 return false;
1108 }
1109 }
1110 }
1111
1112 return true;
1113}
1114
Jamie Madill2db197c2013-10-24 17:49:35 -04001115bool TextureCubeMap::isFaceLevelComplete(int faceIndex, int level) const
Jamie Madill07edd442013-07-19 16:36:58 -04001116{
Jamie Madill2db197c2013-10-24 17:49:35 -04001117 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
Jamie Madill07edd442013-07-19 16:36:58 -04001118
1119 if (isImmutable())
1120 {
1121 return true;
1122 }
1123
Jamie Madilld3d2a342013-10-07 10:46:35 -04001124 int baseSize = getBaseLevelWidth();
Jamie Madill07edd442013-07-19 16:36:58 -04001125
Jamie Madilld3d2a342013-10-07 10:46:35 -04001126 if (baseSize <= 0)
Jamie Madill07edd442013-07-19 16:36:58 -04001127 {
1128 return false;
1129 }
1130
Jamie Madilld3d2a342013-10-07 10:46:35 -04001131 // "isCubeComplete" checks for base level completeness and we must call that
1132 // to determine if any face at level 0 is complete. We omit that check here
1133 // to avoid re-checking cube-completeness for every face at level 0.
Jamie Madill07edd442013-07-19 16:36:58 -04001134 if (level == 0)
1135 {
1136 return true;
1137 }
1138
Jamie Madilld3d2a342013-10-07 10:46:35 -04001139 // Check that non-zero levels are consistent with the base level.
Jamie Madill2db197c2013-10-24 17:49:35 -04001140 const rx::Image *faceLevelImage = mImageArray[faceIndex][level];
Jamie Madill07edd442013-07-19 16:36:58 -04001141
Jamie Madilld3d2a342013-10-07 10:46:35 -04001142 if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat())
Jamie Madill07edd442013-07-19 16:36:58 -04001143 {
1144 return false;
1145 }
1146
Jamie Madilld3d2a342013-10-07 10:46:35 -04001147 if (faceLevelImage->getWidth() != std::max(1, baseSize >> level))
Jamie Madill07edd442013-07-19 16:36:58 -04001148 {
1149 return false;
1150 }
1151
1152 return true;
1153}
1154
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001155bool TextureCubeMap::isCompressed(GLenum target, GLint level) const
1156{
Geoff Lange4a492b2014-06-19 14:14:41 -04001157 return IsFormatCompressed(getInternalFormat(target, level));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001158}
1159
Geoff Lang8040f572013-07-25 16:49:54 -04001160bool TextureCubeMap::isDepth(GLenum target, GLint level) const
1161{
Geoff Lange4a492b2014-06-19 14:14:41 -04001162 return GetDepthBits(getInternalFormat(target, level)) > 0;
Geoff Lang8040f572013-07-25 16:49:54 -04001163}
1164
Jamie Madill73b5d062013-10-24 17:49:38 -04001165void TextureCubeMap::initializeStorage(bool renderTarget)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001166{
Jamie Madill3c0989c2013-10-24 17:49:39 -04001167 // Only initialize the first time this texture is used as a render target or shader resource
1168 if (mTexStorage)
1169 {
1170 return;
1171 }
1172
1173 // do not attempt to create storage for nonexistant data
1174 if (!isFaceLevelComplete(0, 0))
1175 {
1176 return;
1177 }
1178
1179 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
1180
1181 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
1182 ASSERT(mTexStorage);
1183
1184 // flush image data to the storage
1185 updateStorage();
1186}
1187
1188rx::TextureStorageInterfaceCube *TextureCubeMap::createCompleteStorage(bool renderTarget) const
1189{
Jamie Madilld3d2a342013-10-07 10:46:35 -04001190 GLsizei size = getBaseLevelWidth();
daniel@transgaming.come6a09842012-09-17 21:28:55 +00001191
Jamie Madill3c0989c2013-10-24 17:49:39 -04001192 ASSERT(size > 0);
daniel@transgaming.come6a09842012-09-17 21:28:55 +00001193
Jamie Madill3c0989c2013-10-24 17:49:39 -04001194 // use existing storage level count, when previously specified by TexStorage*D
Nicolas Capensbf712d02014-03-31 14:23:35 -04001195 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(size, size, 1));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001196
Nicolas Capensbf712d02014-03-31 14:23:35 -04001197 return new rx::TextureStorageInterfaceCube(mRenderer, getBaseLevelInternalFormat(), renderTarget, size, levels);
Jamie Madill3c0989c2013-10-24 17:49:39 -04001198}
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001199
Jamie Madill3c0989c2013-10-24 17:49:39 -04001200void TextureCubeMap::setCompleteTexStorage(rx::TextureStorageInterfaceCube *newCompleteTexStorage)
1201{
1202 SafeDelete(mTexStorage);
1203 mTexStorage = newCompleteTexStorage;
1204
1205 if (mTexStorage && mTexStorage->isManaged())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001206 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001207 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001208 {
Nicolas Capensbf712d02014-03-31 14:23:35 -04001209 for (int level = 0; level < mTexStorage->getLevelCount(); level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001210 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001211 mImageArray[faceIndex][level]->setManagedSurface(mTexStorage, faceIndex, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001212 }
1213 }
1214 }
1215
1216 mDirtyImages = true;
1217}
1218
Jamie Madill169d1112013-10-24 17:49:37 -04001219void TextureCubeMap::updateStorage()
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001220{
Geoff Lang946b9482014-05-12 16:37:25 -04001221 ASSERT(mTexStorage != NULL);
1222 GLint storageLevels = mTexStorage->getLevelCount();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001223 for (int face = 0; face < 6; face++)
1224 {
Geoff Lang946b9482014-05-12 16:37:25 -04001225 for (int level = 0; level < storageLevels; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001226 {
Geoff Lang946b9482014-05-12 16:37:25 -04001227 if (mImageArray[face][level]->isDirty() && isFaceLevelComplete(face, level))
Jamie Madilld9b9a502013-10-10 17:46:13 -04001228 {
Jamie Madill169d1112013-10-24 17:49:37 -04001229 updateStorageFaceLevel(face, level);
Jamie Madilld9b9a502013-10-10 17:46:13 -04001230 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001231 }
1232 }
1233}
1234
Jamie Madill169d1112013-10-24 17:49:37 -04001235void TextureCubeMap::updateStorageFaceLevel(int faceIndex, int level)
Jamie Madill07edd442013-07-19 16:36:58 -04001236{
Jamie Madill2db197c2013-10-24 17:49:35 -04001237 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1238 rx::Image *image = mImageArray[faceIndex][level];
Jamie Madill07edd442013-07-19 16:36:58 -04001239
1240 if (image->isDirty())
1241 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001242 commitRect(faceIndex, level, 0, 0, image->getWidth(), image->getHeight());
Jamie Madill07edd442013-07-19 16:36:58 -04001243 }
1244}
1245
Jamie Madille83d1a92013-10-24 17:49:33 -04001246bool TextureCubeMap::ensureRenderTarget()
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001247{
Jamie Madill3c0989c2013-10-24 17:49:39 -04001248 initializeStorage(true);
1249
1250 if (getBaseLevelWidth() > 0)
Jamie Madille83d1a92013-10-24 17:49:33 -04001251 {
Jamie Madill3c0989c2013-10-24 17:49:39 -04001252 ASSERT(mTexStorage);
1253 if (!mTexStorage->isRenderTarget())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001254 {
Jamie Madill3c0989c2013-10-24 17:49:39 -04001255 rx::TextureStorageInterfaceCube *newRenderTargetStorage = createCompleteStorage(true);
1256
1257 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001258 {
Jamie Madill3c0989c2013-10-24 17:49:39 -04001259 delete newRenderTargetStorage;
Jamie Madille83d1a92013-10-24 17:49:33 -04001260 return gl::error(GL_OUT_OF_MEMORY, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001261 }
Jamie Madill3c0989c2013-10-24 17:49:39 -04001262
1263 setCompleteTexStorage(newRenderTargetStorage);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001264 }
1265 }
1266
Jamie Madille83d1a92013-10-24 17:49:33 -04001267 return (mTexStorage && mTexStorage->isRenderTarget());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001268}
1269
Geoff Lang005df412013-10-16 14:12:50 -04001270void 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 +00001271{
Geoff Lange4a492b2014-06-19 14:14:41 -04001272 GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat) ? internalFormat
1273 : GetSizedInternalFormat(format, type);
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001274
1275 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001276
Jamie Madill88f18f42013-09-18 14:36:19 -04001277 Texture::setImage(unpack, type, pixels, mImageArray[faceIndex][level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001278}
1279
Jamie Madill2db197c2013-10-24 17:49:35 -04001280int TextureCubeMap::targetToIndex(GLenum target)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001281{
1282 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
1283 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
1284 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
1285 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
1286 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
1287
Jamie Madill2db197c2013-10-24 17:49:35 -04001288 return target - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001289}
1290
Jamie Madill2db197c2013-10-24 17:49:35 -04001291void TextureCubeMap::redefineImage(int faceIndex, GLint level, GLenum internalformat, GLsizei width, GLsizei height)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001292{
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001293 // If there currently is a corresponding storage texture image, it has these parameters
Jamie Madilld3d2a342013-10-07 10:46:35 -04001294 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1295 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
Geoff Lang005df412013-10-16 14:12:50 -04001296 const GLenum storageFormat = getBaseLevelInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001297
Jamie Madill2db197c2013-10-24 17:49:35 -04001298 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, width, height, 1, false);
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001299
1300 if (mTexStorage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001301 {
Nicolas Capensbf712d02014-03-31 14:23:35 -04001302 const int storageLevels = mTexStorage->getLevelCount();
1303
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001304 if ((level >= storageLevels && storageLevels != 0) ||
1305 width != storageWidth ||
1306 height != storageHeight ||
1307 internalformat != storageFormat) // Discard mismatched storage
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001308 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001309 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001310 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001311 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001312 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001313 mImageArray[faceIndex][level]->markDirty();
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001314 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001315 }
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001316
1317 delete mTexStorage;
1318 mTexStorage = NULL;
1319
1320 mDirtyImages = true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001321 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001322 }
1323}
1324
1325void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1326{
Jamie Madill2db197c2013-10-24 17:49:35 -04001327 int faceIndex = targetToIndex(target);
Geoff Lange4a492b2014-06-19 14:14:41 -04001328 GLenum sizedInternalFormat = IsSizedInternalFormat(format) ? format
1329 : GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
Jamie Madill2db197c2013-10-24 17:49:35 -04001330 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001331
Jamie Madill2db197c2013-10-24 17:49:35 -04001332 if (!mImageArray[faceIndex][level]->isRenderableFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001333 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001334 mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001335 mDirtyImages = true;
1336 }
1337 else
1338 {
Jamie Madille83d1a92013-10-24 17:49:33 -04001339 ensureRenderTarget();
Jamie Madill2db197c2013-10-24 17:49:35 -04001340 mImageArray[faceIndex][level]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001341
1342 ASSERT(width == height);
1343
Jamie Madill07bb8cf2013-10-24 17:49:44 -04001344 if (width > 0 && isValidFaceLevel(faceIndex, level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001345 {
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +00001346 gl::Rectangle sourceRect;
1347 sourceRect.x = x;
1348 sourceRect.width = width;
1349 sourceRect.y = y;
1350 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001351
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +00001352 mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001353 }
1354 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001355}
1356
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001357void 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 +00001358{
Jamie Madill2db197c2013-10-24 17:49:35 -04001359 int faceIndex = targetToIndex(target);
1360
Jamie Madilld3d2a342013-10-07 10:46:35 -04001361 // We can only make our texture storage to a render target if the level we're copying *to* is complete
1362 // and the base level is cube-complete. The base level must be cube complete (common case) because we cannot
1363 // rely on the "getBaseLevel*" methods reliably otherwise.
Jamie Madill2db197c2013-10-24 17:49:35 -04001364 bool canCreateRenderTarget = isFaceLevelComplete(faceIndex, level) && isCubeComplete();
Jamie Madill07edd442013-07-19 16:36:58 -04001365
Jamie Madill2db197c2013-10-24 17:49:35 -04001366 if (!mImageArray[faceIndex][level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001367 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001368 mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001369 mDirtyImages = true;
1370 }
1371 else
1372 {
Jamie Madille83d1a92013-10-24 17:49:33 -04001373 ensureRenderTarget();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001374
Jamie Madill07bb8cf2013-10-24 17:49:44 -04001375 if (isValidFaceLevel(faceIndex, level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001376 {
Jamie Madill169d1112013-10-24 17:49:37 -04001377 updateStorageFaceLevel(faceIndex, level);
Jamie Madill07edd442013-07-19 16:36:58 -04001378
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +00001379 gl::Rectangle sourceRect;
1380 sourceRect.x = x;
1381 sourceRect.width = width;
1382 sourceRect.y = y;
1383 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001384
Geoff Lange4a492b2014-06-19 14:14:41 -04001385 mRenderer->copyImage(source, sourceRect, gl::GetFormat(getBaseLevelInternalFormat()),
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +00001386 xoffset, yoffset, mTexStorage, target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001387 }
1388 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001389}
1390
1391void TextureCubeMap::storage(GLsizei levels, GLenum internalformat, GLsizei size)
1392{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001393 for (int level = 0; level < levels; level++)
1394 {
Geoff Langd3110192013-09-24 11:52:47 -04001395 GLsizei mipSize = std::max(1, size >> level);
Jamie Madill2db197c2013-10-24 17:49:35 -04001396 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001397 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001398 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, mipSize, mipSize, 1, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001399 }
1400 }
1401
1402 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1403 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001404 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001405 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001406 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, GL_NONE, 0, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001407 }
1408 }
1409
Jamie Madill3c0989c2013-10-24 17:49:39 -04001410 mImmutable = true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001411
Nicolas Capensbf712d02014-03-31 14:23:35 -04001412 setCompleteTexStorage(new rx::TextureStorageInterfaceCube(mRenderer, internalformat, IsRenderTargetUsage(mUsage), size, levels));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001413}
1414
1415void TextureCubeMap::generateMipmaps()
1416{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001417 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Geoff Lang98705b72014-03-31 16:00:03 -04001418 int levelCount = mipLevels();
Jamie Madill2db197c2013-10-24 17:49:35 -04001419 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001420 {
Geoff Lang98705b72014-03-31 16:00:03 -04001421 for (int level = 1; level < levelCount; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001422 {
Jamie Madill22f843a2013-10-24 17:49:36 -04001423 int faceLevelSize = (std::max(mImageArray[faceIndex][0]->getWidth() >> level, 1));
1424 redefineImage(faceIndex, level, mImageArray[faceIndex][0]->getInternalFormat(), faceLevelSize, faceLevelSize);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001425 }
1426 }
1427
1428 if (mTexStorage && mTexStorage->isRenderTarget())
1429 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001430 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001431 {
Geoff Lang98705b72014-03-31 16:00:03 -04001432 for (int level = 1; level < levelCount; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001433 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001434 mTexStorage->generateMipmap(faceIndex, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001435
Jamie Madill2db197c2013-10-24 17:49:35 -04001436 mImageArray[faceIndex][level]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001437 }
1438 }
1439 }
1440 else
1441 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001442 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001443 {
Geoff Lang98705b72014-03-31 16:00:03 -04001444 for (int level = 1; level < levelCount; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001445 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001446 mRenderer->generateMipmap(mImageArray[faceIndex][level], mImageArray[faceIndex][level - 1]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001447 }
1448 }
1449 }
1450}
1451
Jamie Madilld3d2a342013-10-07 10:46:35 -04001452const rx::Image *TextureCubeMap::getBaseLevelImage() const
1453{
1454 // Note: if we are not cube-complete, there is no single base level image that can describe all
1455 // cube faces, so this method is only well-defined for a cube-complete base level.
1456 return mImageArray[0][0];
1457}
1458
Jamie Madill2ebab852013-10-24 17:49:42 -04001459rx::TextureStorageInterface *TextureCubeMap::getBaseLevelStorage()
1460{
1461 return mTexStorage;
1462}
1463
Jamie Madill2db197c2013-10-24 17:49:35 -04001464unsigned int TextureCubeMap::getRenderTargetSerial(GLenum target, GLint level)
Geoff Lang8040f572013-07-25 16:49:54 -04001465{
Jamie Madill2db197c2013-10-24 17:49:35 -04001466 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(target, level) : 0);
Geoff Lang8040f572013-07-25 16:49:54 -04001467}
1468
1469rx::RenderTarget *TextureCubeMap::getRenderTarget(GLenum target, GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001470{
1471 ASSERT(IsCubemapTextureTarget(target));
1472
1473 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04001474 if (!ensureRenderTarget())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001475 {
1476 return NULL;
1477 }
1478
Jamie Madill169d1112013-10-24 17:49:37 -04001479 updateStorageFaceLevel(targetToIndex(target), level);
Geoff Lang8040f572013-07-25 16:49:54 -04001480
1481 // ensure this is NOT a depth texture
1482 if (isDepth(target, level))
1483 {
1484 return NULL;
1485 }
1486
1487 return mTexStorage->getRenderTarget(target, level);
1488}
1489
1490rx::RenderTarget *TextureCubeMap::getDepthStencil(GLenum target, GLint level)
1491{
1492 ASSERT(IsCubemapTextureTarget(target));
1493
1494 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04001495 if (!ensureRenderTarget())
Geoff Lang8040f572013-07-25 16:49:54 -04001496 {
1497 return NULL;
1498 }
1499
Jamie Madill169d1112013-10-24 17:49:37 -04001500 updateStorageFaceLevel(targetToIndex(target), level);
Geoff Lang8040f572013-07-25 16:49:54 -04001501
1502 // ensure this is a depth texture
1503 if (!isDepth(target, level))
1504 {
1505 return NULL;
1506 }
1507
1508 return mTexStorage->getRenderTarget(target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001509}
1510
Jamie Madill07bb8cf2013-10-24 17:49:44 -04001511bool TextureCubeMap::isValidFaceLevel(int faceIndex, int level) const
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +00001512{
Nicolas Capensbf712d02014-03-31 14:23:35 -04001513 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +00001514}
1515
Geoff Lang4907f2c2013-07-25 12:53:57 -04001516Texture3D::Texture3D(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_3D)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001517{
1518 mTexStorage = NULL;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001519
1520 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1521 {
1522 mImageArray[i] = renderer->createImage();
1523 }
1524}
1525
1526Texture3D::~Texture3D()
1527{
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001528 delete mTexStorage;
1529 mTexStorage = NULL;
1530
1531 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1532 {
1533 delete mImageArray[i];
1534 }
1535}
1536
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001537GLsizei Texture3D::getWidth(GLint level) const
1538{
1539 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getWidth() : 0;
1540}
1541
1542GLsizei Texture3D::getHeight(GLint level) const
1543{
1544 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getHeight() : 0;
1545}
1546
1547GLsizei Texture3D::getDepth(GLint level) const
1548{
1549 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getDepth() : 0;
1550}
1551
1552GLenum Texture3D::getInternalFormat(GLint level) const
1553{
1554 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getInternalFormat() : GL_NONE;
1555}
1556
1557GLenum Texture3D::getActualFormat(GLint level) const
1558{
Geoff Langcbf727a2014-02-10 12:50:45 -05001559 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getActualFormat() : GL_NONE;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001560}
1561
1562bool Texture3D::isCompressed(GLint level) const
1563{
Geoff Lange4a492b2014-06-19 14:14:41 -04001564 return IsFormatCompressed(getInternalFormat(level));
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001565}
1566
1567bool Texture3D::isDepth(GLint level) const
1568{
Geoff Lange4a492b2014-06-19 14:14:41 -04001569 return GetDepthBits(getInternalFormat(level)) > 0;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001570}
1571
Geoff Lang005df412013-10-16 14:12:50 -04001572void 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 +00001573{
Geoff Lange4a492b2014-06-19 14:14:41 -04001574 GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat) ? internalFormat
1575 : GetSizedInternalFormat(format, type);
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001576 redefineImage(level, sizedInternalFormat, width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001577
Jamie Madilla2d4e552013-10-10 15:12:01 -04001578 bool fastUnpacked = false;
1579
1580 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1581 if (isFastUnpackable(unpack, sizedInternalFormat))
1582 {
1583 // Will try to create RT storage if it does not exist
1584 rx::RenderTarget *destRenderTarget = getRenderTarget(level);
1585 Box destArea(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1586
1587 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget))
1588 {
1589 // Ensure we don't overwrite our newly initialized data
1590 mImageArray[level]->markClean();
1591
1592 fastUnpacked = true;
1593 }
1594 }
1595
1596 if (!fastUnpacked)
1597 {
1598 Texture::setImage(unpack, type, pixels, mImageArray[level]);
1599 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001600}
1601
1602void Texture3D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
1603{
1604 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1605 redefineImage(level, format, width, height, depth);
1606
1607 Texture::setCompressedImage(imageSize, pixels, mImageArray[level]);
1608}
1609
Jamie Madill88f18f42013-09-18 14:36:19 -04001610void 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 +00001611{
Jamie Madillba4f10a2013-10-10 15:12:20 -04001612 bool fastUnpacked = false;
1613
1614 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1615 if (isFastUnpackable(unpack, getInternalFormat(level)))
1616 {
1617 rx::RenderTarget *destRenderTarget = getRenderTarget(level);
1618 Box destArea(xoffset, yoffset, zoffset, width, height, depth);
1619
1620 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, destRenderTarget))
1621 {
1622 // Ensure we don't overwrite our newly initialized data
1623 mImageArray[level]->markClean();
1624
1625 fastUnpacked = true;
1626 }
1627 }
1628
1629 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 +00001630 {
1631 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1632 }
1633}
1634
1635void Texture3D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
1636{
1637 if (Texture::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth, format, imageSize, pixels, mImageArray[level]))
1638 {
1639 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1640 }
1641}
1642
1643void Texture3D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
1644{
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001645 for (int level = 0; level < levels; level++)
1646 {
Jamie Madille664e202013-10-24 17:49:40 -04001647 GLsizei levelWidth = std::max(1, width >> level);
1648 GLsizei levelHeight = std::max(1, height >> level);
1649 GLsizei levelDepth = std::max(1, depth >> level);
1650 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, levelWidth, levelHeight, levelDepth, true);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001651 }
1652
1653 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1654 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001655 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, GL_NONE, 0, 0, 0, true);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001656 }
1657
Jamie Madille664e202013-10-24 17:49:40 -04001658 mImmutable = true;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001659
Nicolas Capensbf712d02014-03-31 14:23:35 -04001660 setCompleteTexStorage(new rx::TextureStorageInterface3D(mRenderer, internalformat, IsRenderTargetUsage(mUsage), width, height, depth, levels));
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001661}
1662
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001663void Texture3D::generateMipmaps()
1664{
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001665 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Geoff Lang98705b72014-03-31 16:00:03 -04001666 int levelCount = mipLevels();
1667 for (int level = 1; level < levelCount; level++)
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001668 {
Jamie Madill22f843a2013-10-24 17:49:36 -04001669 redefineImage(level, getBaseLevelInternalFormat(),
1670 std::max(getBaseLevelWidth() >> level, 1),
1671 std::max(getBaseLevelHeight() >> level, 1),
1672 std::max(getBaseLevelDepth() >> level, 1));
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001673 }
1674
1675 if (mTexStorage && mTexStorage->isRenderTarget())
1676 {
Geoff Lang98705b72014-03-31 16:00:03 -04001677 for (int level = 1; level < levelCount; level++)
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001678 {
Jamie Madill22f843a2013-10-24 17:49:36 -04001679 mTexStorage->generateMipmap(level);
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001680
Jamie Madill22f843a2013-10-24 17:49:36 -04001681 mImageArray[level]->markClean();
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001682 }
1683 }
1684 else
1685 {
Geoff Lang98705b72014-03-31 16:00:03 -04001686 for (int level = 1; level < levelCount; level++)
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001687 {
Jamie Madill22f843a2013-10-24 17:49:36 -04001688 mRenderer->generateMipmap(mImageArray[level], mImageArray[level - 1]);
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001689 }
1690 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001691}
1692
Jamie Madilld3d2a342013-10-07 10:46:35 -04001693const rx::Image *Texture3D::getBaseLevelImage() const
1694{
1695 return mImageArray[0];
1696}
1697
Jamie Madill2ebab852013-10-24 17:49:42 -04001698rx::TextureStorageInterface *Texture3D::getBaseLevelStorage()
1699{
1700 return mTexStorage;
1701}
1702
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001703void Texture3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1704{
Jamie Madill07edd442013-07-19 16:36:58 -04001705 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
1706 // the current level we're copying to is defined (with appropriate format, width & height)
1707 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
1708
1709 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001710 {
1711 mImageArray[level]->copy(xoffset, yoffset, zoffset, x, y, width, height, source);
1712 mDirtyImages = true;
1713 }
1714 else
1715 {
Jamie Madille83d1a92013-10-24 17:49:33 -04001716 ensureRenderTarget();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001717
Jamie Madill07bb8cf2013-10-24 17:49:44 -04001718 if (isValidLevel(level))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001719 {
Jamie Madill169d1112013-10-24 17:49:37 -04001720 updateStorageLevel(level);
Jamie Madill07edd442013-07-19 16:36:58 -04001721
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001722 gl::Rectangle sourceRect;
1723 sourceRect.x = x;
1724 sourceRect.width = width;
1725 sourceRect.y = y;
1726 sourceRect.height = height;
1727
1728 mRenderer->copyImage(source, sourceRect,
Geoff Lange4a492b2014-06-19 14:14:41 -04001729 gl::GetFormat(getBaseLevelInternalFormat()),
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001730 xoffset, yoffset, zoffset, mTexStorage, level);
1731 }
1732 }
1733}
1734
Jamie Madillf8989902013-07-19 16:36:58 -04001735bool Texture3D::isSamplerComplete(const SamplerState &samplerState) const
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001736{
Jamie Madilld3d2a342013-10-07 10:46:35 -04001737 GLsizei width = getBaseLevelWidth();
1738 GLsizei height = getBaseLevelHeight();
1739 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001740
1741 if (width <= 0 || height <= 0 || depth <= 0)
1742 {
1743 return false;
1744 }
1745
Geoff Langcec35902014-04-16 10:52:36 -04001746 if (!mRenderer->getCaps().textureCaps.get(getInternalFormat(0)).filtering)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001747 {
Jamie Madillf8989902013-07-19 16:36:58 -04001748 if (samplerState.magFilter != GL_NEAREST ||
1749 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001750 {
1751 return false;
1752 }
1753 }
1754
Jamie Madillf8989902013-07-19 16:36:58 -04001755 if (IsMipmapFiltered(samplerState) && !isMipmapComplete())
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001756 {
1757 return false;
1758 }
1759
1760 return true;
1761}
1762
1763bool Texture3D::isMipmapComplete() const
1764{
Geoff Lang98705b72014-03-31 16:00:03 -04001765 int levelCount = mipLevels();
Jamie Madill07edd442013-07-19 16:36:58 -04001766
Geoff Lang98705b72014-03-31 16:00:03 -04001767 for (int level = 0; level < levelCount; level++)
Jamie Madill07edd442013-07-19 16:36:58 -04001768 {
1769 if (!isLevelComplete(level))
1770 {
1771 return false;
1772 }
1773 }
1774
1775 return true;
1776}
1777
1778bool Texture3D::isLevelComplete(int level) const
1779{
1780 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1781
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001782 if (isImmutable())
1783 {
1784 return true;
1785 }
1786
Jamie Madilld3d2a342013-10-07 10:46:35 -04001787 GLsizei width = getBaseLevelWidth();
1788 GLsizei height = getBaseLevelHeight();
1789 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001790
1791 if (width <= 0 || height <= 0 || depth <= 0)
1792 {
1793 return false;
1794 }
1795
Jamie Madill07edd442013-07-19 16:36:58 -04001796 if (level == 0)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001797 {
Jamie Madill07edd442013-07-19 16:36:58 -04001798 return true;
1799 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001800
Jamie Madill07edd442013-07-19 16:36:58 -04001801 rx::Image *levelImage = mImageArray[level];
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001802
Jamie Madilld3d2a342013-10-07 10:46:35 -04001803 if (levelImage->getInternalFormat() != getBaseLevelInternalFormat())
Jamie Madill07edd442013-07-19 16:36:58 -04001804 {
1805 return false;
1806 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001807
Jamie Madill07edd442013-07-19 16:36:58 -04001808 if (levelImage->getWidth() != std::max(1, width >> level))
1809 {
1810 return false;
1811 }
1812
1813 if (levelImage->getHeight() != std::max(1, height >> level))
1814 {
1815 return false;
1816 }
1817
1818 if (levelImage->getDepth() != std::max(1, depth >> level))
1819 {
1820 return false;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001821 }
1822
1823 return true;
1824}
1825
Geoff Lang8040f572013-07-25 16:49:54 -04001826unsigned int Texture3D::getRenderTargetSerial(GLint level, GLint layer)
1827{
Jamie Madille83d1a92013-10-24 17:49:33 -04001828 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(level, layer) : 0);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001829}
1830
Jamie Madill07bb8cf2013-10-24 17:49:44 -04001831bool Texture3D::isValidLevel(int level) const
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001832{
Nicolas Capensbf712d02014-03-31 14:23:35 -04001833 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001834}
1835
Jamie Madill73b5d062013-10-24 17:49:38 -04001836void Texture3D::initializeStorage(bool renderTarget)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001837{
Jamie Madille664e202013-10-24 17:49:40 -04001838 // Only initialize the first time this texture is used as a render target or shader resource
1839 if (mTexStorage)
1840 {
1841 return;
1842 }
1843
1844 // do not attempt to create storage for nonexistant data
1845 if (!isLevelComplete(0))
1846 {
1847 return;
1848 }
1849
1850 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
1851
1852 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
1853 ASSERT(mTexStorage);
1854
1855 // flush image data to the storage
1856 updateStorage();
1857}
1858
1859rx::TextureStorageInterface3D *Texture3D::createCompleteStorage(bool renderTarget) const
1860{
Jamie Madilld3d2a342013-10-07 10:46:35 -04001861 GLsizei width = getBaseLevelWidth();
1862 GLsizei height = getBaseLevelHeight();
1863 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001864
Jamie Madille664e202013-10-24 17:49:40 -04001865 ASSERT(width > 0 && height > 0 && depth > 0);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001866
Jamie Madille664e202013-10-24 17:49:40 -04001867 // use existing storage level count, when previously specified by TexStorage*D
Nicolas Capensbf712d02014-03-31 14:23:35 -04001868 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, depth));
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001869
Nicolas Capensbf712d02014-03-31 14:23:35 -04001870 return new rx::TextureStorageInterface3D(mRenderer, getBaseLevelInternalFormat(), renderTarget, width, height, depth, levels);
Jamie Madille664e202013-10-24 17:49:40 -04001871}
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001872
Jamie Madille664e202013-10-24 17:49:40 -04001873void Texture3D::setCompleteTexStorage(rx::TextureStorageInterface3D *newCompleteTexStorage)
1874{
1875 SafeDelete(mTexStorage);
1876 mTexStorage = newCompleteTexStorage;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001877 mDirtyImages = true;
Jamie Madille664e202013-10-24 17:49:40 -04001878
1879 // We do not support managed 3D storage, as that is D3D9/ES2-only
1880 ASSERT(!mTexStorage->isManaged());
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001881}
1882
Jamie Madill169d1112013-10-24 17:49:37 -04001883void Texture3D::updateStorage()
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001884{
Geoff Lang946b9482014-05-12 16:37:25 -04001885 ASSERT(mTexStorage != NULL);
1886 GLint storageLevels = mTexStorage->getLevelCount();
1887 for (int level = 0; level < storageLevels; level++)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001888 {
Geoff Lang946b9482014-05-12 16:37:25 -04001889 if (mImageArray[level]->isDirty() && isLevelComplete(level))
Jamie Madilld9b9a502013-10-10 17:46:13 -04001890 {
Jamie Madill169d1112013-10-24 17:49:37 -04001891 updateStorageLevel(level);
Jamie Madilld9b9a502013-10-10 17:46:13 -04001892 }
Jamie Madill07edd442013-07-19 16:36:58 -04001893 }
1894}
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001895
Jamie Madill169d1112013-10-24 17:49:37 -04001896void Texture3D::updateStorageLevel(int level)
Jamie Madill07edd442013-07-19 16:36:58 -04001897{
1898 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
Jamie Madillaee7ad82013-10-10 16:07:32 -04001899 ASSERT(isLevelComplete(level));
Jamie Madill07edd442013-07-19 16:36:58 -04001900
Jamie Madillaee7ad82013-10-10 16:07:32 -04001901 if (mImageArray[level]->isDirty())
Jamie Madill07edd442013-07-19 16:36:58 -04001902 {
Jamie Madillaee7ad82013-10-10 16:07:32 -04001903 commitRect(level, 0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001904 }
1905}
1906
Jamie Madille83d1a92013-10-24 17:49:33 -04001907bool Texture3D::ensureRenderTarget()
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001908{
Jamie Madille664e202013-10-24 17:49:40 -04001909 initializeStorage(true);
1910
1911 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0 && getBaseLevelDepth() > 0)
Jamie Madille83d1a92013-10-24 17:49:33 -04001912 {
Jamie Madille664e202013-10-24 17:49:40 -04001913 ASSERT(mTexStorage);
1914 if (!mTexStorage->isRenderTarget())
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001915 {
Jamie Madille664e202013-10-24 17:49:40 -04001916 rx::TextureStorageInterface3D *newRenderTargetStorage = createCompleteStorage(true);
1917
1918 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001919 {
Jamie Madille664e202013-10-24 17:49:40 -04001920 delete newRenderTargetStorage;
Jamie Madille83d1a92013-10-24 17:49:33 -04001921 return gl::error(GL_OUT_OF_MEMORY, false);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001922 }
Jamie Madille664e202013-10-24 17:49:40 -04001923
1924 setCompleteTexStorage(newRenderTargetStorage);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001925 }
1926 }
1927
Jamie Madille83d1a92013-10-24 17:49:33 -04001928 return (mTexStorage && mTexStorage->isRenderTarget());
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001929}
1930
Jamie Madilla2d4e552013-10-10 15:12:01 -04001931rx::RenderTarget *Texture3D::getRenderTarget(GLint level)
1932{
1933 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04001934 if (!ensureRenderTarget())
Jamie Madilla2d4e552013-10-10 15:12:01 -04001935 {
1936 return NULL;
1937 }
1938
Jamie Madill169d1112013-10-24 17:49:37 -04001939 updateStorageLevel(level);
Jamie Madilla2d4e552013-10-10 15:12:01 -04001940
1941 // ensure this is NOT a depth texture
1942 if (isDepth(level))
1943 {
1944 return NULL;
1945 }
1946
1947 return mTexStorage->getRenderTarget(level);
1948}
1949
Geoff Lang8040f572013-07-25 16:49:54 -04001950rx::RenderTarget *Texture3D::getRenderTarget(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001951{
Geoff Lang8040f572013-07-25 16:49:54 -04001952 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04001953 if (!ensureRenderTarget())
Geoff Lang8040f572013-07-25 16:49:54 -04001954 {
1955 return NULL;
1956 }
1957
Jamie Madill169d1112013-10-24 17:49:37 -04001958 updateStorage();
Geoff Lang8040f572013-07-25 16:49:54 -04001959
1960 // ensure this is NOT a depth texture
1961 if (isDepth(level))
1962 {
1963 return NULL;
1964 }
1965
1966 return mTexStorage->getRenderTarget(level, layer);
1967}
1968
1969rx::RenderTarget *Texture3D::getDepthStencil(GLint level, GLint layer)
1970{
1971 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04001972 if (!ensureRenderTarget())
Geoff Lang8040f572013-07-25 16:49:54 -04001973 {
1974 return NULL;
1975 }
1976
Jamie Madill169d1112013-10-24 17:49:37 -04001977 updateStorageLevel(level);
Geoff Lang8040f572013-07-25 16:49:54 -04001978
1979 // ensure this is a depth texture
1980 if (!isDepth(level))
1981 {
1982 return NULL;
1983 }
1984
1985 return mTexStorage->getRenderTarget(level, layer);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001986}
1987
Geoff Lang005df412013-10-16 14:12:50 -04001988void Texture3D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001989{
1990 // If there currently is a corresponding storage texture image, it has these parameters
Jamie Madilld3d2a342013-10-07 10:46:35 -04001991 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1992 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1993 const int storageDepth = std::max(1, getBaseLevelDepth() >> level);
Geoff Lang005df412013-10-16 14:12:50 -04001994 const GLenum storageFormat = getBaseLevelInternalFormat();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001995
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001996 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, false);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001997
1998 if (mTexStorage)
1999 {
Nicolas Capensbf712d02014-03-31 14:23:35 -04002000 const int storageLevels = mTexStorage->getLevelCount();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002001
2002 if ((level >= storageLevels && storageLevels != 0) ||
2003 width != storageWidth ||
2004 height != storageHeight ||
2005 depth != storageDepth ||
2006 internalformat != storageFormat) // Discard mismatched storage
2007 {
2008 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
2009 {
2010 mImageArray[i]->markDirty();
2011 }
2012
2013 delete mTexStorage;
2014 mTexStorage = NULL;
2015 mDirtyImages = true;
2016 }
2017 }
2018}
2019
2020void Texture3D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth)
2021{
Jamie Madill07bb8cf2013-10-24 17:49:44 -04002022 if (isValidLevel(level))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002023 {
2024 rx::Image *image = mImageArray[level];
Jamie Madill169d1112013-10-24 17:49:37 -04002025 if (image->copyToStorage(mTexStorage, level, xoffset, yoffset, zoffset, width, height, depth))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002026 {
2027 image->markClean();
2028 }
2029 }
2030}
2031
Geoff Lang4907f2c2013-07-25 12:53:57 -04002032Texture2DArray::Texture2DArray(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_2D_ARRAY)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002033{
2034 mTexStorage = NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002035
2036 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2037 {
2038 mLayerCounts[level] = 0;
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002039 mImageArray[level] = NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002040 }
2041}
2042
2043Texture2DArray::~Texture2DArray()
2044{
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002045 delete mTexStorage;
2046 mTexStorage = NULL;
Jamie Madill884a4622013-10-24 17:49:41 -04002047
2048 deleteImages();
2049}
2050
2051void Texture2DArray::deleteImages()
2052{
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002053 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2054 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002055 for (int layer = 0; layer < mLayerCounts[level]; ++layer)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002056 {
2057 delete mImageArray[level][layer];
2058 }
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002059 delete[] mImageArray[level];
Jamie Madill884a4622013-10-24 17:49:41 -04002060 mImageArray[level] = NULL;
2061 mLayerCounts[level] = 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002062 }
2063}
2064
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002065GLsizei Texture2DArray::getWidth(GLint level) const
2066{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002067 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 +00002068}
2069
2070GLsizei Texture2DArray::getHeight(GLint level) const
2071{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002072 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 +00002073}
2074
Jamie Madillb8f8b892014-01-07 10:12:50 -05002075GLsizei Texture2DArray::getLayers(GLint level) const
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002076{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002077 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mLayerCounts[level] : 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002078}
2079
2080GLenum Texture2DArray::getInternalFormat(GLint level) const
2081{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002082 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 +00002083}
2084
2085GLenum Texture2DArray::getActualFormat(GLint level) const
2086{
Geoff Langcbf727a2014-02-10 12:50:45 -05002087 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 +00002088}
2089
2090bool Texture2DArray::isCompressed(GLint level) const
2091{
Geoff Lange4a492b2014-06-19 14:14:41 -04002092 return IsFormatCompressed(getInternalFormat(level));
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002093}
2094
2095bool Texture2DArray::isDepth(GLint level) const
2096{
Geoff Lange4a492b2014-06-19 14:14:41 -04002097 return GetDepthBits(getInternalFormat(level)) > 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002098}
2099
Geoff Lang005df412013-10-16 14:12:50 -04002100void 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 +00002101{
Geoff Lange4a492b2014-06-19 14:14:41 -04002102 GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat) ? internalFormat
2103 : GetSizedInternalFormat(format, type);
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00002104 redefineImage(level, sizedInternalFormat, width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002105
Geoff Lange4a492b2014-06-19 14:14:41 -04002106 GLsizei inputDepthPitch = gl::GetDepthPitch(sizedInternalFormat, type, width, height, unpack.alignment);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002107
2108 for (int i = 0; i < depth; i++)
2109 {
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002110 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
Jamie Madill88f18f42013-09-18 14:36:19 -04002111 Texture::setImage(unpack, type, layerPixels, mImageArray[level][i]);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002112 }
2113}
2114
2115void Texture2DArray::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
2116{
2117 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
2118 redefineImage(level, format, width, height, depth);
2119
Geoff Lange4a492b2014-06-19 14:14:41 -04002120 GLsizei inputDepthPitch = gl::GetDepthPitch(format, GL_UNSIGNED_BYTE, width, height, 1);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002121
2122 for (int i = 0; i < depth; i++)
2123 {
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002124 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002125 Texture::setCompressedImage(imageSize, layerPixels, mImageArray[level][i]);
2126 }
2127}
2128
Jamie Madill88f18f42013-09-18 14:36:19 -04002129void 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 +00002130{
Geoff Lang005df412013-10-16 14:12:50 -04002131 GLenum internalformat = getInternalFormat(level);
Geoff Lange4a492b2014-06-19 14:14:41 -04002132 GLsizei inputDepthPitch = gl::GetDepthPitch(internalformat, type, width, height, unpack.alignment);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002133
2134 for (int i = 0; i < depth; i++)
2135 {
2136 int layer = zoffset + i;
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002137 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002138
Jamie Madill88f18f42013-09-18 14:36:19 -04002139 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 +00002140 {
2141 commitRect(level, xoffset, yoffset, layer, width, height);
2142 }
2143 }
2144}
2145
2146void Texture2DArray::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
2147{
Geoff Lange4a492b2014-06-19 14:14:41 -04002148 GLsizei inputDepthPitch = gl::GetDepthPitch(format, GL_UNSIGNED_BYTE, width, height, 1);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002149
2150 for (int i = 0; i < depth; i++)
2151 {
2152 int layer = zoffset + i;
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002153 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002154
2155 if (Texture::subImageCompressed(xoffset, yoffset, zoffset, width, height, 1, format, imageSize, layerPixels, mImageArray[level][layer]))
2156 {
2157 commitRect(level, xoffset, yoffset, layer, width, height);
2158 }
2159 }
2160}
2161
2162void Texture2DArray::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2163{
Jamie Madill884a4622013-10-24 17:49:41 -04002164 deleteImages();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002165
2166 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2167 {
Jamie Madill884a4622013-10-24 17:49:41 -04002168 GLsizei levelWidth = std::max(1, width >> level);
2169 GLsizei levelHeight = std::max(1, height >> level);
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002170
Jamie Madill884a4622013-10-24 17:49:41 -04002171 mLayerCounts[level] = (level < levels ? depth : 0);
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002172
Jamie Madill884a4622013-10-24 17:49:41 -04002173 if (mLayerCounts[level] > 0)
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002174 {
2175 // Create new images for this level
Jamie Madill884a4622013-10-24 17:49:41 -04002176 mImageArray[level] = new rx::Image*[mLayerCounts[level]];
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002177
2178 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002179 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002180 mImageArray[level][layer] = mRenderer->createImage();
2181 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, levelWidth,
2182 levelHeight, 1, true);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002183 }
2184 }
2185 }
2186
Jamie Madill884a4622013-10-24 17:49:41 -04002187 mImmutable = true;
Nicolas Capensbf712d02014-03-31 14:23:35 -04002188 setCompleteTexStorage(new rx::TextureStorageInterface2DArray(mRenderer, internalformat, IsRenderTargetUsage(mUsage), width, height, depth, levels));
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002189}
2190
2191void Texture2DArray::generateMipmaps()
2192{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002193 int baseWidth = getBaseLevelWidth();
2194 int baseHeight = getBaseLevelHeight();
2195 int baseDepth = getBaseLevelDepth();
2196 GLenum baseFormat = getBaseLevelInternalFormat();
2197
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00002198 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Geoff Lang98705b72014-03-31 16:00:03 -04002199 int levelCount = mipLevels();
2200 for (int level = 1; level < levelCount; level++)
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00002201 {
Jamie Madill22f843a2013-10-24 17:49:36 -04002202 redefineImage(level, baseFormat, std::max(baseWidth >> level, 1), std::max(baseHeight >> level, 1), baseDepth);
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00002203 }
2204
2205 if (mTexStorage && mTexStorage->isRenderTarget())
2206 {
Geoff Lang98705b72014-03-31 16:00:03 -04002207 for (int level = 1; level < levelCount; level++)
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00002208 {
2209 mTexStorage->generateMipmap(level);
2210
2211 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2212 {
2213 mImageArray[level][layer]->markClean();
2214 }
2215 }
2216 }
2217 else
2218 {
Geoff Lang98705b72014-03-31 16:00:03 -04002219 for (int level = 1; level < levelCount; level++)
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00002220 {
2221 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2222 {
2223 mRenderer->generateMipmap(mImageArray[level][layer], mImageArray[level - 1][layer]);
2224 }
2225 }
2226 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002227}
2228
Jamie Madilld3d2a342013-10-07 10:46:35 -04002229const rx::Image *Texture2DArray::getBaseLevelImage() const
2230{
Jamie Madill152ed092013-10-09 17:01:15 -04002231 return (mLayerCounts[0] > 0 ? mImageArray[0][0] : NULL);
Jamie Madilld3d2a342013-10-07 10:46:35 -04002232}
2233
Jamie Madill2ebab852013-10-24 17:49:42 -04002234rx::TextureStorageInterface *Texture2DArray::getBaseLevelStorage()
2235{
2236 return mTexStorage;
2237}
2238
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002239void Texture2DArray::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
2240{
Jamie Madill07edd442013-07-19 16:36:58 -04002241 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
2242 // the current level we're copying to is defined (with appropriate format, width & height)
2243 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
2244
2245 if (!mImageArray[level][0]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002246 {
2247 mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, x, y, width, height, source);
2248 mDirtyImages = true;
2249 }
2250 else
2251 {
Jamie Madille83d1a92013-10-24 17:49:33 -04002252 ensureRenderTarget();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002253
Jamie Madill07bb8cf2013-10-24 17:49:44 -04002254 if (isValidLevel(level))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002255 {
Jamie Madill169d1112013-10-24 17:49:37 -04002256 updateStorageLevel(level);
Jamie Madill07edd442013-07-19 16:36:58 -04002257
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002258 gl::Rectangle sourceRect;
2259 sourceRect.x = x;
2260 sourceRect.width = width;
2261 sourceRect.y = y;
2262 sourceRect.height = height;
2263
Geoff Lange4a492b2014-06-19 14:14:41 -04002264 mRenderer->copyImage(source, sourceRect, gl::GetFormat(getInternalFormat(0)),
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002265 xoffset, yoffset, zoffset, mTexStorage, level);
2266 }
2267 }
2268}
2269
Jamie Madillf8989902013-07-19 16:36:58 -04002270bool Texture2DArray::isSamplerComplete(const SamplerState &samplerState) const
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002271{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002272 GLsizei width = getBaseLevelWidth();
2273 GLsizei height = getBaseLevelHeight();
Jamie Madillb8f8b892014-01-07 10:12:50 -05002274 GLsizei depth = getLayers(0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002275
2276 if (width <= 0 || height <= 0 || depth <= 0)
2277 {
2278 return false;
2279 }
2280
Geoff Langcec35902014-04-16 10:52:36 -04002281 if (!mRenderer->getCaps().textureCaps.get(getBaseLevelInternalFormat()).filtering)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002282 {
Jamie Madillf8989902013-07-19 16:36:58 -04002283 if (samplerState.magFilter != GL_NEAREST ||
2284 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002285 {
2286 return false;
2287 }
2288 }
2289
Jamie Madillf8989902013-07-19 16:36:58 -04002290 if (IsMipmapFiltered(samplerState) && !isMipmapComplete())
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002291 {
2292 return false;
2293 }
2294
2295 return true;
2296}
2297
2298bool Texture2DArray::isMipmapComplete() const
2299{
Geoff Lang98705b72014-03-31 16:00:03 -04002300 int levelCount = mipLevels();
Jamie Madill07edd442013-07-19 16:36:58 -04002301
Geoff Lang98705b72014-03-31 16:00:03 -04002302 for (int level = 1; level < levelCount; level++)
Jamie Madill07edd442013-07-19 16:36:58 -04002303 {
2304 if (!isLevelComplete(level))
2305 {
2306 return false;
2307 }
2308 }
2309
2310 return true;
2311}
2312
2313bool Texture2DArray::isLevelComplete(int level) const
2314{
Jamie Madillb8f8b892014-01-07 10:12:50 -05002315 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray));
Jamie Madill07edd442013-07-19 16:36:58 -04002316
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002317 if (isImmutable())
2318 {
2319 return true;
2320 }
2321
Jamie Madilld3d2a342013-10-07 10:46:35 -04002322 GLsizei width = getBaseLevelWidth();
2323 GLsizei height = getBaseLevelHeight();
Jamie Madillb8f8b892014-01-07 10:12:50 -05002324 GLsizei layers = getLayers(0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002325
Jamie Madillb8f8b892014-01-07 10:12:50 -05002326 if (width <= 0 || height <= 0 || layers <= 0)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002327 {
2328 return false;
2329 }
2330
Jamie Madill07edd442013-07-19 16:36:58 -04002331 if (level == 0)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002332 {
Jamie Madill07edd442013-07-19 16:36:58 -04002333 return true;
2334 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002335
Jamie Madill07edd442013-07-19 16:36:58 -04002336 if (getInternalFormat(level) != getInternalFormat(0))
2337 {
2338 return false;
2339 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002340
Jamie Madill07edd442013-07-19 16:36:58 -04002341 if (getWidth(level) != std::max(1, width >> level))
2342 {
2343 return false;
2344 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002345
Jamie Madill07edd442013-07-19 16:36:58 -04002346 if (getHeight(level) != std::max(1, height >> level))
2347 {
2348 return false;
2349 }
2350
Jamie Madillb8f8b892014-01-07 10:12:50 -05002351 if (getLayers(level) != layers)
Jamie Madill07edd442013-07-19 16:36:58 -04002352 {
2353 return false;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002354 }
2355
2356 return true;
2357}
2358
Jamie Madille83d1a92013-10-24 17:49:33 -04002359unsigned int Texture2DArray::getRenderTargetSerial(GLint level, GLint layer)
Geoff Lang8040f572013-07-25 16:49:54 -04002360{
Jamie Madille83d1a92013-10-24 17:49:33 -04002361 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(level, layer) : 0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002362}
2363
Jamie Madill07bb8cf2013-10-24 17:49:44 -04002364bool Texture2DArray::isValidLevel(int level) const
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002365{
Nicolas Capensbf712d02014-03-31 14:23:35 -04002366 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002367}
2368
Jamie Madill73b5d062013-10-24 17:49:38 -04002369void Texture2DArray::initializeStorage(bool renderTarget)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002370{
Jamie Madill884a4622013-10-24 17:49:41 -04002371 // Only initialize the first time this texture is used as a render target or shader resource
2372 if (mTexStorage)
2373 {
2374 return;
2375 }
2376
2377 // do not attempt to create storage for nonexistant data
2378 if (!isLevelComplete(0))
2379 {
2380 return;
2381 }
2382
2383 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
2384
2385 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
2386 ASSERT(mTexStorage);
2387
2388 // flush image data to the storage
2389 updateStorage();
2390}
2391
2392rx::TextureStorageInterface2DArray *Texture2DArray::createCompleteStorage(bool renderTarget) const
2393{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002394 GLsizei width = getBaseLevelWidth();
2395 GLsizei height = getBaseLevelHeight();
Jamie Madillb8f8b892014-01-07 10:12:50 -05002396 GLsizei depth = getLayers(0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002397
Jamie Madill884a4622013-10-24 17:49:41 -04002398 ASSERT(width > 0 && height > 0 && depth > 0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002399
Jamie Madill884a4622013-10-24 17:49:41 -04002400 // use existing storage level count, when previously specified by TexStorage*D
Nicolas Capensbf712d02014-03-31 14:23:35 -04002401 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002402
Nicolas Capensbf712d02014-03-31 14:23:35 -04002403 return new rx::TextureStorageInterface2DArray(mRenderer, getBaseLevelInternalFormat(), renderTarget, width, height, depth, levels);
Jamie Madill884a4622013-10-24 17:49:41 -04002404}
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002405
Jamie Madill884a4622013-10-24 17:49:41 -04002406void Texture2DArray::setCompleteTexStorage(rx::TextureStorageInterface2DArray *newCompleteTexStorage)
2407{
2408 SafeDelete(mTexStorage);
2409 mTexStorage = newCompleteTexStorage;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002410 mDirtyImages = true;
Jamie Madill884a4622013-10-24 17:49:41 -04002411
2412 // We do not support managed 2D array storage, as managed storage is ES2/D3D9 only
2413 ASSERT(!mTexStorage->isManaged());
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002414}
2415
Jamie Madill169d1112013-10-24 17:49:37 -04002416void Texture2DArray::updateStorage()
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002417{
Geoff Lang946b9482014-05-12 16:37:25 -04002418 ASSERT(mTexStorage != NULL);
2419 GLint storageLevels = mTexStorage->getLevelCount();
2420 for (int level = 0; level < storageLevels; level++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002421 {
Jamie Madilld9b9a502013-10-10 17:46:13 -04002422 if (isLevelComplete(level))
2423 {
Jamie Madill169d1112013-10-24 17:49:37 -04002424 updateStorageLevel(level);
Jamie Madilld9b9a502013-10-10 17:46:13 -04002425 }
Jamie Madill07edd442013-07-19 16:36:58 -04002426 }
2427}
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002428
Jamie Madill169d1112013-10-24 17:49:37 -04002429void Texture2DArray::updateStorageLevel(int level)
Jamie Madill07edd442013-07-19 16:36:58 -04002430{
Jamie Madillaee7ad82013-10-10 16:07:32 -04002431 ASSERT(level >= 0 && level < (int)ArraySize(mLayerCounts));
2432 ASSERT(isLevelComplete(level));
2433
Jamie Madill07edd442013-07-19 16:36:58 -04002434 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2435 {
Jamie Madillaee7ad82013-10-10 16:07:32 -04002436 ASSERT(mImageArray[level] != NULL && mImageArray[level][layer] != NULL);
2437 if (mImageArray[level][layer]->isDirty())
Jamie Madill07edd442013-07-19 16:36:58 -04002438 {
Jamie Madillaee7ad82013-10-10 16:07:32 -04002439 commitRect(level, 0, 0, layer, getWidth(level), getHeight(level));
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002440 }
2441 }
2442}
2443
Jamie Madille83d1a92013-10-24 17:49:33 -04002444bool Texture2DArray::ensureRenderTarget()
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002445{
Jamie Madill884a4622013-10-24 17:49:41 -04002446 initializeStorage(true);
2447
Jamie Madillb8f8b892014-01-07 10:12:50 -05002448 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0 && getLayers(0) > 0)
Jamie Madille83d1a92013-10-24 17:49:33 -04002449 {
Jamie Madill884a4622013-10-24 17:49:41 -04002450 ASSERT(mTexStorage);
2451 if (!mTexStorage->isRenderTarget())
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002452 {
Jamie Madill884a4622013-10-24 17:49:41 -04002453 rx::TextureStorageInterface2DArray *newRenderTargetStorage = createCompleteStorage(true);
2454
2455 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002456 {
Jamie Madill884a4622013-10-24 17:49:41 -04002457 delete newRenderTargetStorage;
Jamie Madille83d1a92013-10-24 17:49:33 -04002458 return gl::error(GL_OUT_OF_MEMORY, false);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002459 }
Jamie Madill884a4622013-10-24 17:49:41 -04002460
2461 setCompleteTexStorage(newRenderTargetStorage);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002462 }
2463 }
2464
Jamie Madille83d1a92013-10-24 17:49:33 -04002465 return (mTexStorage && mTexStorage->isRenderTarget());
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002466}
2467
Geoff Lang8040f572013-07-25 16:49:54 -04002468rx::RenderTarget *Texture2DArray::getRenderTarget(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002469{
Geoff Lang8040f572013-07-25 16:49:54 -04002470 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04002471 if (!ensureRenderTarget())
Geoff Lang8040f572013-07-25 16:49:54 -04002472 {
2473 return NULL;
2474 }
2475
Jamie Madill169d1112013-10-24 17:49:37 -04002476 updateStorageLevel(level);
Geoff Lang8040f572013-07-25 16:49:54 -04002477
2478 // ensure this is NOT a depth texture
2479 if (isDepth(level))
2480 {
2481 return NULL;
2482 }
2483
2484 return mTexStorage->getRenderTarget(level, layer);
2485}
2486
2487rx::RenderTarget *Texture2DArray::getDepthStencil(GLint level, GLint layer)
2488{
2489 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04002490 if (!ensureRenderTarget())
Geoff Lang8040f572013-07-25 16:49:54 -04002491 {
2492 return NULL;
2493 }
2494
Jamie Madill169d1112013-10-24 17:49:37 -04002495 updateStorageLevel(level);
Geoff Lang8040f572013-07-25 16:49:54 -04002496
2497 // ensure this is a depth texture
2498 if (!isDepth(level))
2499 {
2500 return NULL;
2501 }
2502
2503 return mTexStorage->getRenderTarget(level, layer);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002504}
2505
Geoff Lang005df412013-10-16 14:12:50 -04002506void Texture2DArray::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002507{
2508 // If there currently is a corresponding storage texture image, it has these parameters
Jamie Madilld3d2a342013-10-07 10:46:35 -04002509 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2510 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
Jamie Madillb8f8b892014-01-07 10:12:50 -05002511 const int storageDepth = getLayers(0);
Geoff Lang005df412013-10-16 14:12:50 -04002512 const GLenum storageFormat = getBaseLevelInternalFormat();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002513
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002514 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002515 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002516 delete mImageArray[level][layer];
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002517 }
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002518 delete[] mImageArray[level];
Jamie Madill152ed092013-10-09 17:01:15 -04002519 mImageArray[level] = NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002520 mLayerCounts[level] = depth;
2521
Jamie Madill152ed092013-10-09 17:01:15 -04002522 if (depth > 0)
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002523 {
Jamie Madill152ed092013-10-09 17:01:15 -04002524 mImageArray[level] = new rx::Image*[depth]();
2525
2526 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2527 {
2528 mImageArray[level][layer] = mRenderer->createImage();
2529 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, width, height, 1, false);
2530 }
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002531 }
2532
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002533 if (mTexStorage)
2534 {
Nicolas Capensbf712d02014-03-31 14:23:35 -04002535 const int storageLevels = mTexStorage->getLevelCount();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002536
2537 if ((level >= storageLevels && storageLevels != 0) ||
2538 width != storageWidth ||
2539 height != storageHeight ||
2540 depth != storageDepth ||
2541 internalformat != storageFormat) // Discard mismatched storage
2542 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002543 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002544 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002545 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002546 {
2547 mImageArray[level][layer]->markDirty();
2548 }
2549 }
2550
2551 delete mTexStorage;
2552 mTexStorage = NULL;
2553 mDirtyImages = true;
2554 }
2555 }
2556}
2557
2558void Texture2DArray::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint layerTarget, GLsizei width, GLsizei height)
2559{
Jamie Madillb8f8b892014-01-07 10:12:50 -05002560 if (isValidLevel(level) && layerTarget < getLayers(level))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002561 {
2562 rx::Image *image = mImageArray[level][layerTarget];
Jamie Madill169d1112013-10-24 17:49:37 -04002563 if (image->copyToStorage(mTexStorage, level, xoffset, yoffset, layerTarget, width, height))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002564 {
2565 image->markClean();
2566 }
2567 }
2568}
2569
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00002570}