blob: 4a9fab259f30c4f93c28da4c8abf829aca255711 [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//
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00003// Copyright (c) 2002-2013 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"
Geoff Langdce735c2013-06-04 10:21:18 -040018#include "libGLESv2/renderer/Blit9.h"
shannon.woods@transgaming.com486d9e92013-02-28 23:15:41 +000019#include "libGLESv2/Renderbuffer.h"
20#include "libGLESv2/renderer/Image.h"
21#include "libGLESv2/renderer/Renderer.h"
22#include "libGLESv2/renderer/TextureStorage.h"
23#include "libEGL/Surface.h"
Jamie Madill1beb1db2013-09-18 14:36:28 -040024#include "libGLESv2/Buffer.h"
25#include "libGLESv2/renderer/BufferStorage.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
Geoff Lang4907f2c2013-07-25 12:53:57 -040047Texture::Texture(rx::Renderer *renderer, GLuint id, GLenum target) : RefCountObject(id)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000048{
daniel@transgaming.com370482e2012-11-28 19:32:13 +000049 mRenderer = renderer;
50
daniel@transgaming.comebf139f2012-10-31 18:07:32 +000051 mSamplerState.minFilter = GL_NEAREST_MIPMAP_LINEAR;
52 mSamplerState.magFilter = GL_LINEAR;
53 mSamplerState.wrapS = GL_REPEAT;
54 mSamplerState.wrapT = GL_REPEAT;
shannon.woods%transgaming.com@gtempaccount.com0b3a8df2013-04-13 03:44:51 +000055 mSamplerState.wrapR = GL_REPEAT;
daniel@transgaming.comebf139f2012-10-31 18:07:32 +000056 mSamplerState.maxAnisotropy = 1.0f;
57 mSamplerState.lodOffset = 0;
Geoff Langc82fc412013-07-10 14:43:42 -040058 mSamplerState.compareMode = GL_NONE;
59 mSamplerState.compareFunc = GL_LEQUAL;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000060 mUsage = GL_NONE;
Geoff Langc82fc412013-07-10 14:43:42 -040061
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000062 mDirtyImages = true;
63
64 mImmutable = false;
Geoff Lang4907f2c2013-07-25 12:53:57 -040065
66 mTarget = target;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000067}
68
69Texture::~Texture()
70{
71}
72
Geoff Lang4907f2c2013-07-25 12:53:57 -040073GLenum Texture::getTarget() const
74{
75 return mTarget;
76}
77
Geoff Lang8040f572013-07-25 16:49:54 -040078void Texture::addProxyRef(const Renderbuffer *proxy)
79{
80 mRenderbufferProxies.addRef(proxy);
81}
82
83void Texture::releaseProxy(const Renderbuffer *proxy)
84{
85 mRenderbufferProxies.release(proxy);
86}
87
Geoff Lang63b5f1f2013-09-23 14:52:14 -040088void Texture::setMinFilter(GLenum filter)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000089{
Geoff Lang63b5f1f2013-09-23 14:52:14 -040090 mSamplerState.minFilter = filter;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000091}
92
Geoff Lang63b5f1f2013-09-23 14:52:14 -040093void Texture::setMagFilter(GLenum filter)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000094{
Geoff Lang63b5f1f2013-09-23 14:52:14 -040095 mSamplerState.magFilter = filter;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000096}
97
Geoff Lang63b5f1f2013-09-23 14:52:14 -040098void Texture::setWrapS(GLenum wrap)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000099{
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400100 mSamplerState.wrapS = wrap;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000101}
102
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400103void Texture::setWrapT(GLenum wrap)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000104{
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400105 mSamplerState.wrapT = wrap;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000106}
107
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400108void Texture::setWrapR(GLenum wrap)
shannon.woods%transgaming.com@gtempaccount.com0b3a8df2013-04-13 03:44:51 +0000109{
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400110 mSamplerState.wrapR = wrap;
shannon.woods%transgaming.com@gtempaccount.com0b3a8df2013-04-13 03:44:51 +0000111}
112
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400113void Texture::setMaxAnisotropy(float textureMaxAnisotropy, float contextMaxAnisotropy)
daniel@transgaming.com07ab8412012-07-12 15:17:09 +0000114{
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400115 mSamplerState.maxAnisotropy = std::min(textureMaxAnisotropy, contextMaxAnisotropy);
daniel@transgaming.com07ab8412012-07-12 15:17:09 +0000116}
117
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400118void Texture::setCompareMode(GLenum mode)
Geoff Langc82fc412013-07-10 14:43:42 -0400119{
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400120 mSamplerState.compareMode = mode;
Geoff Langc82fc412013-07-10 14:43:42 -0400121}
122
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400123void Texture::setCompareFunc(GLenum func)
Geoff Langc82fc412013-07-10 14:43:42 -0400124{
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400125 mSamplerState.compareFunc = func;
Geoff Langc82fc412013-07-10 14:43:42 -0400126}
127
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400128void Texture::setUsage(GLenum usage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000129{
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400130 mUsage = usage;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000131}
132
133GLenum Texture::getMinFilter() const
134{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000135 return mSamplerState.minFilter;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000136}
137
138GLenum Texture::getMagFilter() const
139{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000140 return mSamplerState.magFilter;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000141}
142
143GLenum Texture::getWrapS() const
144{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000145 return mSamplerState.wrapS;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000146}
147
148GLenum Texture::getWrapT() const
149{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000150 return mSamplerState.wrapT;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000151}
152
shannon.woods%transgaming.com@gtempaccount.com0b3a8df2013-04-13 03:44:51 +0000153GLenum Texture::getWrapR() const
154{
155 return mSamplerState.wrapR;
156}
157
daniel@transgaming.com07ab8412012-07-12 15:17:09 +0000158float Texture::getMaxAnisotropy() const
159{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000160 return mSamplerState.maxAnisotropy;
161}
162
163int Texture::getLodOffset()
164{
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000165 rx::TextureStorageInterface *texture = getStorage(false);
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000166 return texture ? texture->getLodOffset() : 0;
167}
168
169void Texture::getSamplerState(SamplerState *sampler)
170{
171 *sampler = mSamplerState;
172 sampler->lodOffset = getLodOffset();
daniel@transgaming.com07ab8412012-07-12 15:17:09 +0000173}
174
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000175GLenum Texture::getUsage() const
176{
177 return mUsage;
178}
179
Jamie Madill88f18f42013-09-18 14:36:19 -0400180void Texture::setImage(const PixelUnpackState &unpack, GLenum type, const void *pixels, rx::Image *image)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000181{
Jamie Madillabef6802013-09-05 16:54:19 -0400182 // We no longer need the "GLenum format" parameter to TexImage to determine what data format "pixels" contains.
183 // 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 -0400184 const void *pixelData = pixels;
185
186 if (unpack.pixelBuffer.id() != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000187 {
Jamie Madill1beb1db2013-09-18 14:36:28 -0400188 // Do a CPU readback here, if we have an unpack buffer bound and the fast GPU path is not supported
189 Buffer *pixelBuffer = unpack.pixelBuffer.get();
190 ptrdiff_t offset = reinterpret_cast<ptrdiff_t>(pixels);
191 const void *bufferData = pixelBuffer->getStorage()->getData();
192 pixelData = static_cast<const unsigned char *>(bufferData) + offset;
193 }
194
195 if (pixelData != NULL)
196 {
197 image->loadData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), unpack.alignment, type, pixelData);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000198 mDirtyImages = true;
199 }
200}
201
Jamie Madill1beb1db2013-09-18 14:36:28 -0400202bool Texture::fastUnpackPixels(const PixelUnpackState &unpack, const void *pixels, const Box &destArea,
203 GLenum sizedInternalFormat, GLenum type, GLint level)
204{
205 if (destArea.width <= 0 && destArea.height <= 0 && destArea.depth <= 0)
206 {
207 return true;
208 }
209
210 // In order to perform the fast copy through the shader, we must have the right format, and be able
211 // to create a render target.
212 if (IsFastCopyBufferToTextureSupported(sizedInternalFormat, mRenderer->getCurrentClientVersion()))
213 {
214 unsigned int offset = reinterpret_cast<unsigned int>(pixels);
215 rx::RenderTarget *destRenderTarget = getStorage(true)->getStorageInstance()->getRenderTarget(level);
216
217 return mRenderer->fastCopyBufferToTexture(unpack, offset, destRenderTarget, sizedInternalFormat, type, destArea);
218 }
219
220 // Return false if we do not support fast unpack
221 return false;
222}
223
daniel@transgaming.com31b13e12012-11-28 19:34:30 +0000224void Texture::setCompressedImage(GLsizei imageSize, const void *pixels, rx::Image *image)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000225{
226 if (pixels != NULL)
227 {
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000228 image->loadCompressedData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000229 mDirtyImages = true;
230 }
231}
232
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000233bool Texture::subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
Jamie Madill88f18f42013-09-18 14:36:19 -0400234 GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels, rx::Image *image)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000235{
236 if (pixels != NULL)
237 {
Jamie Madill88f18f42013-09-18 14:36:19 -0400238 image->loadData(xoffset, yoffset, zoffset, width, height, depth, unpack.alignment, type, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000239 mDirtyImages = true;
240 }
241
242 return true;
243}
244
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000245bool Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
246 GLenum format, GLsizei imageSize, const void *pixels, rx::Image *image)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000247{
248 if (pixels != NULL)
249 {
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000250 image->loadCompressedData(xoffset, yoffset, zoffset, width, height, depth, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000251 mDirtyImages = true;
252 }
253
254 return true;
255}
256
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000257rx::TextureStorageInterface *Texture::getNativeTexture()
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000258{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000259 // ensure the underlying texture is created
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000260
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000261 rx::TextureStorageInterface *storage = getStorage(false);
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000262 if (storage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000263 {
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000264 updateTexture();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000265 }
266
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000267 return storage;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000268}
269
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000270bool Texture::hasDirtyImages() const
271{
272 return mDirtyImages;
273}
274
275void Texture::resetDirty()
276{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000277 mDirtyImages = false;
278}
279
280unsigned int Texture::getTextureSerial()
281{
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000282 rx::TextureStorageInterface *texture = getStorage(false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000283 return texture ? texture->getTextureSerial() : 0;
284}
285
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000286bool Texture::isImmutable() const
287{
288 return mImmutable;
289}
290
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +0000291GLint Texture::creationLevels(GLsizei width, GLsizei height, GLsizei depth) const
292{
293 // NPOT checks are not required in ES 3.0, NPOT texture support is assumed.
294 return 0; // Maximum number of levels
295}
296
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000297GLint Texture::creationLevels(GLsizei width, GLsizei height) const
298{
daniel@transgaming.comea32d482012-11-28 19:33:18 +0000299 if ((isPow2(width) && isPow2(height)) || mRenderer->getNonPower2TextureSupport())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000300 {
301 return 0; // Maximum number of levels
302 }
303 else
304 {
305 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
306 return 1;
307 }
308}
309
310GLint Texture::creationLevels(GLsizei size) const
311{
312 return creationLevels(size, size);
313}
314
Geoff Lang4907f2c2013-07-25 12:53:57 -0400315Texture2D::Texture2D(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_2D)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000316{
317 mTexStorage = NULL;
318 mSurface = NULL;
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000319
320 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
321 {
daniel@transgaming.com244e1832012-12-20 20:52:35 +0000322 mImageArray[i] = renderer->createImage();
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000323 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000324}
325
326Texture2D::~Texture2D()
327{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000328 delete mTexStorage;
329 mTexStorage = NULL;
330
331 if (mSurface)
332 {
333 mSurface->setBoundTexture(NULL);
334 mSurface = NULL;
335 }
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000336
337 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
338 {
339 delete mImageArray[i];
340 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000341}
342
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000343GLsizei Texture2D::getWidth(GLint level) const
344{
345 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000346 return mImageArray[level]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000347 else
348 return 0;
349}
350
351GLsizei Texture2D::getHeight(GLint level) const
352{
353 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000354 return mImageArray[level]->getHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000355 else
356 return 0;
357}
358
359GLenum Texture2D::getInternalFormat(GLint level) const
360{
361 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000362 return mImageArray[level]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000363 else
364 return GL_NONE;
365}
366
daniel@transgaming.com20d36662012-10-31 19:51:43 +0000367GLenum Texture2D::getActualFormat(GLint level) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000368{
369 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000370 return mImageArray[level]->getActualFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000371 else
372 return D3DFMT_UNKNOWN;
373}
374
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000375void Texture2D::redefineImage(GLint level, GLint internalformat, GLsizei width, GLsizei height)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000376{
377 releaseTexImage();
shannon.woods@transgaming.com8a406682013-02-28 23:15:26 +0000378
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000379 // If there currently is a corresponding storage texture image, it has these parameters
380 const int storageWidth = std::max(1, mImageArray[0]->getWidth() >> level);
381 const int storageHeight = std::max(1, mImageArray[0]->getHeight() >> level);
382 const int storageFormat = mImageArray[0]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000383
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000384 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, width, height, 1, false);
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000385
386 if (mTexStorage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000387 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000388 const int storageLevels = mTexStorage->levelCount();
389
390 if ((level >= storageLevels && storageLevels != 0) ||
391 width != storageWidth ||
392 height != storageHeight ||
393 internalformat != storageFormat) // Discard mismatched storage
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000394 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000395 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
396 {
397 mImageArray[i]->markDirty();
398 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000399
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000400 delete mTexStorage;
401 mTexStorage = NULL;
402 mDirtyImages = true;
403 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000404 }
405}
406
Jamie Madill88f18f42013-09-18 14:36:19 -0400407void Texture2D::setImage(GLint level, GLsizei width, GLsizei height, GLint internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000408{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +0000409 GLuint clientVersion = mRenderer->getCurrentClientVersion();
410 GLint sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
411 : GetSizedInternalFormat(format, type, clientVersion);
412 redefineImage(level, sizedInternalFormat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000413
Jamie Madill1beb1db2013-09-18 14:36:28 -0400414 // Attempt a fast gpu copy of the pixel data to the surface
415 // If we want to support rendering (which is necessary for GPU unpack buffers), level 0 must be complete
416 Box destArea(0, 0, 0, getWidth(level), getHeight(level), 1);
417 if (unpack.pixelBuffer.id() != 0 && isLevelComplete(0) && fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, level))
418 {
419 // Ensure we don't overwrite our newly initialized data
420 mImageArray[level]->markClean();
421 }
422 else
423 {
424 Texture::setImage(unpack, type, pixels, mImageArray[level]);
425 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000426}
427
428void Texture2D::bindTexImage(egl::Surface *surface)
429{
430 releaseTexImage();
431
daniel@transgaming.com106e1f72012-10-31 18:38:36 +0000432 GLint internalformat = surface->getFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000433
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000434 mImageArray[0]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, surface->getWidth(), surface->getHeight(), 1, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000435
436 delete mTexStorage;
daniel@transgaming.comd8353dd2012-12-20 21:11:14 +0000437 mTexStorage = new rx::TextureStorageInterface2D(mRenderer, surface->getSwapChain());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000438
439 mDirtyImages = true;
440 mSurface = surface;
441 mSurface->setBoundTexture(this);
442}
443
444void Texture2D::releaseTexImage()
445{
446 if (mSurface)
447 {
448 mSurface->setBoundTexture(NULL);
449 mSurface = NULL;
450
451 if (mTexStorage)
452 {
453 delete mTexStorage;
454 mTexStorage = NULL;
455 }
456
457 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
458 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000459 mImageArray[i]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000460 }
461 }
462}
463
464void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
465{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000466 // 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 +0000467 redefineImage(level, format, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000468
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000469 Texture::setCompressedImage(imageSize, pixels, mImageArray[level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000470}
471
472void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
473{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000474 if (level < levelCount())
475 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000476 rx::Image *image = mImageArray[level];
daniel@transgaming.com0f195ad2012-10-31 19:51:59 +0000477 if (image->updateSurface(mTexStorage, level, xoffset, yoffset, width, height))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000478 {
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000479 image->markClean();
480 }
481 }
482}
483
Jamie Madill88f18f42013-09-18 14:36:19 -0400484void 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 +0000485{
Jamie Madill88f18f42013-09-18 14:36:19 -0400486 if (Texture::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, mImageArray[level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000487 {
488 commitRect(level, xoffset, yoffset, width, height);
489 }
490}
491
492void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
493{
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000494 if (Texture::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000495 {
496 commitRect(level, xoffset, yoffset, width, height);
497 }
498}
499
500void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
501{
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +0000502 GLuint clientVersion = mRenderer->getCurrentClientVersion();
503 GLint sizedInternalFormat = IsSizedInternalFormat(format, clientVersion) ? format
504 : GetSizedInternalFormat(format, GL_UNSIGNED_BYTE, clientVersion);
505 redefineImage(level, sizedInternalFormat, width, height);
shannon.woods@transgaming.com8a406682013-02-28 23:15:26 +0000506
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000507 if (!mImageArray[level]->isRenderableFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000508 {
shannon.woods%transgaming.com@gtempaccount.come5dcce72013-04-13 03:44:33 +0000509 mImageArray[level]->copy(0, 0, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000510 mDirtyImages = true;
511 }
512 else
513 {
514 if (!mTexStorage || !mTexStorage->isRenderTarget())
515 {
516 convertToRenderTarget();
517 }
518
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000519 mImageArray[level]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000520
521 if (width != 0 && height != 0 && level < levelCount())
522 {
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +0000523 gl::Rectangle sourceRect;
524 sourceRect.x = x;
525 sourceRect.width = width;
526 sourceRect.y = y;
527 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000528
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +0000529 mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000530 }
531 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000532}
533
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +0000534void 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 +0000535{
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +0000536 if (xoffset + width > mImageArray[level]->getWidth() || yoffset + height > mImageArray[level]->getHeight() || zoffset != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000537 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +0000538 return gl::error(GL_INVALID_VALUE);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000539 }
540
Jamie Madill07edd442013-07-19 16:36:58 -0400541 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
542 // the current level we're copying to is defined (with appropriate format, width & height)
543 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
544
545 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000546 {
shannon.woods%transgaming.com@gtempaccount.come5dcce72013-04-13 03:44:33 +0000547 mImageArray[level]->copy(xoffset, yoffset, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000548 mDirtyImages = true;
549 }
550 else
551 {
552 if (!mTexStorage || !mTexStorage->isRenderTarget())
553 {
554 convertToRenderTarget();
555 }
556
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000557 if (level < levelCount())
558 {
Jamie Madill07edd442013-07-19 16:36:58 -0400559 updateTextureLevel(level);
560
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +0000561 GLuint clientVersion = mRenderer->getCurrentClientVersion();
562
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +0000563 gl::Rectangle sourceRect;
564 sourceRect.x = x;
565 sourceRect.width = width;
566 sourceRect.y = y;
567 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000568
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +0000569 mRenderer->copyImage(source, sourceRect,
570 gl::GetFormat(mImageArray[0]->getInternalFormat(), clientVersion),
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +0000571 xoffset, yoffset, mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000572 }
573 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000574}
575
576void Texture2D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height)
577{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000578 delete mTexStorage;
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000579 mTexStorage = new rx::TextureStorageInterface2D(mRenderer, levels, internalformat, mUsage, false, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000580 mImmutable = true;
581
582 for (int level = 0; level < levels; level++)
583 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000584 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, width, height, 1, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000585 width = std::max(1, width >> 1);
586 height = std::max(1, height >> 1);
587 }
588
589 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
590 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000591 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000592 }
593
594 if (mTexStorage->isManaged())
595 {
596 int levels = levelCount();
597
598 for (int level = 0; level < levels; level++)
599 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000600 mImageArray[level]->setManagedSurface(mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000601 }
602 }
603}
604
605// Tests for 2D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85.
Jamie Madillf8989902013-07-19 16:36:58 -0400606bool Texture2D::isSamplerComplete(const SamplerState &samplerState) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000607{
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000608 GLsizei width = mImageArray[0]->getWidth();
609 GLsizei height = mImageArray[0]->getHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000610
611 if (width <= 0 || height <= 0)
612 {
613 return false;
614 }
615
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000616 if (!IsTextureFilteringSupported(getInternalFormat(0), mRenderer))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000617 {
Jamie Madillf8989902013-07-19 16:36:58 -0400618 if (samplerState.magFilter != GL_NEAREST ||
619 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000620 {
621 return false;
622 }
623 }
624
daniel@transgaming.comea32d482012-11-28 19:33:18 +0000625 bool npotSupport = mRenderer->getNonPower2TextureSupport();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000626
627 if (!npotSupport)
628 {
Jamie Madillf8989902013-07-19 16:36:58 -0400629 if ((samplerState.wrapS != GL_CLAMP_TO_EDGE && !isPow2(width)) ||
630 (samplerState.wrapT != GL_CLAMP_TO_EDGE && !isPow2(height)))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000631 {
632 return false;
633 }
634 }
635
Jamie Madillf8989902013-07-19 16:36:58 -0400636 if (IsMipmapFiltered(samplerState))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000637 {
638 if (!npotSupport)
639 {
640 if (!isPow2(width) || !isPow2(height))
641 {
642 return false;
643 }
644 }
645
646 if (!isMipmapComplete())
647 {
648 return false;
649 }
650 }
651
Geoff Langc82fc412013-07-10 14:43:42 -0400652 // OpenGLES 3.0.2 spec section 3.8.13 states that a texture is not mipmap complete if:
653 // The internalformat specified for the texture arrays is a sized internal depth or
654 // depth and stencil format (see table 3.13), the value of TEXTURE_COMPARE_-
655 // MODE is NONE, and either the magnification filter is not NEAREST or the mini-
656 // fication filter is neither NEAREST nor NEAREST_MIPMAP_NEAREST.
657 if (gl::GetDepthBits(getInternalFormat(0), mRenderer->getCurrentClientVersion()) > 0)
658 {
659 if (mSamplerState.compareMode == GL_NONE)
660 {
661 if ((mSamplerState.minFilter != GL_NEAREST && mSamplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST) ||
662 mSamplerState.magFilter != GL_NEAREST)
663 {
664 return false;
665 }
666 }
667 }
668
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000669 return true;
670}
671
672// Tests for 2D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
673bool Texture2D::isMipmapComplete() const
674{
Jamie Madill07edd442013-07-19 16:36:58 -0400675 GLsizei width = mImageArray[0]->getWidth();
676 GLsizei height = mImageArray[0]->getHeight();
677
678 int q = log2(std::max(width, height));
679
680 for (int level = 0; level <= q; level++)
681 {
682 if (!isLevelComplete(level))
683 {
684 return false;
685 }
686 }
687
688 return true;
689}
690
691bool Texture2D::isLevelComplete(int level) const
692{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000693 if (isImmutable())
694 {
695 return true;
696 }
697
Jamie Madill07edd442013-07-19 16:36:58 -0400698 const rx::Image *baseImage = mImageArray[0];
699 GLsizei width = baseImage->getWidth();
700 GLsizei height = baseImage->getHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000701
702 if (width <= 0 || height <= 0)
703 {
704 return false;
705 }
706
Jamie Madill07edd442013-07-19 16:36:58 -0400707 // The base image level is complete if the width and height are positive
708 if (level == 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000709 {
Jamie Madill07edd442013-07-19 16:36:58 -0400710 return true;
711 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000712
Jamie Madill07edd442013-07-19 16:36:58 -0400713 ASSERT(level >= 1 && level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
714 rx::Image *image = mImageArray[level];
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000715
Jamie Madill07edd442013-07-19 16:36:58 -0400716 if (image->getInternalFormat() != baseImage->getInternalFormat())
717 {
718 return false;
719 }
720
721 if (image->getWidth() != std::max(1, width >> level))
722 {
723 return false;
724 }
725
726 if (image->getHeight() != std::max(1, height >> level))
727 {
728 return false;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000729 }
730
731 return true;
732}
733
734bool Texture2D::isCompressed(GLint level) const
735{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000736 return IsFormatCompressed(getInternalFormat(level), mRenderer->getCurrentClientVersion());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000737}
738
739bool Texture2D::isDepth(GLint level) const
740{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000741 return GetDepthBits(getInternalFormat(level), mRenderer->getCurrentClientVersion()) > 0;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000742}
743
daniel@transgaming.comf032cb82012-10-31 19:51:52 +0000744// Constructs a native texture resource from the texture images
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000745void Texture2D::createTexture()
746{
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000747 GLsizei width = mImageArray[0]->getWidth();
748 GLsizei height = mImageArray[0]->getHeight();
daniel@transgaming.come6a09842012-09-17 21:28:55 +0000749
750 if (!(width > 0 && height > 0))
daniel@transgaming.comf032cb82012-10-31 19:51:52 +0000751 return; // do not attempt to create native textures for nonexistant data
daniel@transgaming.come6a09842012-09-17 21:28:55 +0000752
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000753 GLint levels = creationLevels(width, height);
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000754 GLenum internalformat = mImageArray[0]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000755
756 delete mTexStorage;
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000757 mTexStorage = new rx::TextureStorageInterface2D(mRenderer, levels, internalformat, mUsage, false, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000758
759 if (mTexStorage->isManaged())
760 {
761 int levels = levelCount();
762
763 for (int level = 0; level < levels; level++)
764 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000765 mImageArray[level]->setManagedSurface(mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000766 }
767 }
768
769 mDirtyImages = true;
770}
771
772void Texture2D::updateTexture()
773{
Jamie Madilleb3665c2013-07-19 16:36:57 -0400774 int levels = (isMipmapComplete() ? levelCount() : 1);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000775
776 for (int level = 0; level < levels; level++)
777 {
Jamie Madill07edd442013-07-19 16:36:58 -0400778 updateTextureLevel(level);
779 }
780}
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000781
Jamie Madill07edd442013-07-19 16:36:58 -0400782void Texture2D::updateTextureLevel(int level)
783{
784 ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
785 rx::Image *image = mImageArray[level];
786
787 if (image->isDirty())
788 {
789 commitRect(level, 0, 0, mImageArray[level]->getWidth(), mImageArray[level]->getHeight());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000790 }
791}
792
793void Texture2D::convertToRenderTarget()
794{
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000795 rx::TextureStorageInterface2D *newTexStorage = NULL;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000796
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000797 if (mImageArray[0]->getWidth() != 0 && mImageArray[0]->getHeight() != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000798 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000799 GLsizei width = mImageArray[0]->getWidth();
800 GLsizei height = mImageArray[0]->getHeight();
shannon.woods@transgaming.com6bb48862013-02-28 23:09:34 +0000801 GLint levels = mTexStorage != NULL ? mTexStorage->levelCount() : creationLevels(width, height);
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000802 GLenum internalformat = mImageArray[0]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000803
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000804 newTexStorage = new rx::TextureStorageInterface2D(mRenderer, levels, internalformat, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, true, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000805
806 if (mTexStorage != NULL)
807 {
daniel@transgaming.com1d80eee2012-11-28 19:33:31 +0000808 if (!mRenderer->copyToRenderTarget(newTexStorage, mTexStorage))
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +0000809 {
810 delete newTexStorage;
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +0000811 return gl::error(GL_OUT_OF_MEMORY);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000812 }
813 }
814 }
815
816 delete mTexStorage;
817 mTexStorage = newTexStorage;
818
819 mDirtyImages = true;
820}
821
822void Texture2D::generateMipmaps()
823{
daniel@transgaming.comea32d482012-11-28 19:33:18 +0000824 if (!mRenderer->getNonPower2TextureSupport())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000825 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000826 if (!isPow2(mImageArray[0]->getWidth()) || !isPow2(mImageArray[0]->getHeight()))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000827 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +0000828 return gl::error(GL_INVALID_OPERATION);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000829 }
830 }
831
832 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000833 unsigned int q = log2(std::max(mImageArray[0]->getWidth(), mImageArray[0]->getHeight()));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000834 for (unsigned int i = 1; i <= q; i++)
835 {
shannon.woods@transgaming.com8a406682013-02-28 23:15:26 +0000836 redefineImage(i, mImageArray[0]->getInternalFormat(),
837 std::max(mImageArray[0]->getWidth() >> i, 1),
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000838 std::max(mImageArray[0]->getHeight() >> i, 1));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000839 }
840
841 if (mTexStorage && mTexStorage->isRenderTarget())
842 {
843 for (unsigned int i = 1; i <= q; i++)
844 {
daniel@transgaming.com0ad830b2012-10-31 19:52:12 +0000845 mTexStorage->generateMipmap(i);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000846
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000847 mImageArray[i]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000848 }
849 }
850 else
851 {
852 for (unsigned int i = 1; i <= q; i++)
853 {
daniel@transgaming.com4ba24062012-12-20 20:54:24 +0000854 mRenderer->generateMipmap(mImageArray[i], mImageArray[i - 1]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000855 }
856 }
857}
858
Geoff Lang8040f572013-07-25 16:49:54 -0400859Renderbuffer *Texture2D::getRenderbuffer(GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000860{
Geoff Lang8040f572013-07-25 16:49:54 -0400861 Renderbuffer *renderBuffer = mRenderbufferProxies.get(level, 0);
862 if (!renderBuffer)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000863 {
Geoff Lang8040f572013-07-25 16:49:54 -0400864 renderBuffer = new Renderbuffer(mRenderer, id(), new RenderbufferTexture2D(this, level));
865 mRenderbufferProxies.add(level, 0, renderBuffer);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000866 }
867
Geoff Lang8040f572013-07-25 16:49:54 -0400868 return renderBuffer;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000869}
870
Geoff Lang8040f572013-07-25 16:49:54 -0400871unsigned int Texture2D::getRenderTargetSerial(GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000872{
Geoff Lang8040f572013-07-25 16:49:54 -0400873 if (!mTexStorage || !mTexStorage->isRenderTarget())
874 {
875 convertToRenderTarget();
876 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000877
Geoff Lang8040f572013-07-25 16:49:54 -0400878 return mTexStorage ? mTexStorage->getRenderTargetSerial(level) : 0;
879}
880
881rx::RenderTarget *Texture2D::getRenderTarget(GLint level)
882{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000883 // ensure the underlying texture is created
884 if (getStorage(true) == NULL)
885 {
886 return NULL;
887 }
888
889 updateTexture();
Geoff Lang8040f572013-07-25 16:49:54 -0400890
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000891 // ensure this is NOT a depth texture
Geoff Lang8040f572013-07-25 16:49:54 -0400892 if (isDepth(level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000893 {
894 return NULL;
895 }
daniel@transgaming.com34da3972012-12-20 21:10:29 +0000896
Geoff Lang8040f572013-07-25 16:49:54 -0400897 return mTexStorage->getRenderTarget(level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000898}
899
Geoff Lang8040f572013-07-25 16:49:54 -0400900rx::RenderTarget *Texture2D::getDepthSencil(GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000901{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000902 // ensure the underlying texture is created
903 if (getStorage(true) == NULL)
904 {
905 return NULL;
906 }
907
908 updateTexture();
909
910 // ensure this is actually a depth texture
Geoff Lang8040f572013-07-25 16:49:54 -0400911 if (!isDepth(level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000912 {
913 return NULL;
914 }
Geoff Lang8040f572013-07-25 16:49:54 -0400915
916 return mTexStorage->getRenderTarget(level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000917}
918
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +0000919int Texture2D::levelCount()
920{
shannon.woods@transgaming.com5016f8e2013-02-28 23:20:57 +0000921 return mTexStorage ? mTexStorage->levelCount() : 0;
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +0000922}
923
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000924rx::TextureStorageInterface *Texture2D::getStorage(bool renderTarget)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000925{
926 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
927 {
928 if (renderTarget)
929 {
930 convertToRenderTarget();
931 }
932 else
933 {
934 createTexture();
935 }
936 }
937
938 return mTexStorage;
939}
940
Geoff Lang4907f2c2013-07-25 12:53:57 -0400941TextureCubeMap::TextureCubeMap(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_CUBE_MAP)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000942{
943 mTexStorage = NULL;
944 for (int i = 0; i < 6; i++)
945 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000946 for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
947 {
daniel@transgaming.com244e1832012-12-20 20:52:35 +0000948 mImageArray[i][j] = renderer->createImage();
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000949 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000950 }
951}
952
953TextureCubeMap::~TextureCubeMap()
954{
955 for (int i = 0; i < 6; i++)
956 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000957 for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
958 {
959 delete mImageArray[i][j];
960 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000961 }
962
963 delete mTexStorage;
964 mTexStorage = NULL;
965}
966
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000967GLsizei TextureCubeMap::getWidth(GLenum target, GLint level) const
968{
969 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000970 return mImageArray[faceIndex(target)][level]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000971 else
972 return 0;
973}
974
975GLsizei TextureCubeMap::getHeight(GLenum target, GLint level) const
976{
977 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000978 return mImageArray[faceIndex(target)][level]->getHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000979 else
980 return 0;
981}
982
983GLenum TextureCubeMap::getInternalFormat(GLenum target, GLint level) const
984{
985 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000986 return mImageArray[faceIndex(target)][level]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000987 else
988 return GL_NONE;
989}
990
daniel@transgaming.com20d36662012-10-31 19:51:43 +0000991GLenum TextureCubeMap::getActualFormat(GLenum target, GLint level) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000992{
993 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000994 return mImageArray[faceIndex(target)][level]->getActualFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000995 else
996 return D3DFMT_UNKNOWN;
997}
998
Jamie Madill88f18f42013-09-18 14:36:19 -0400999void TextureCubeMap::setImagePosX(GLint level, GLsizei width, GLsizei height, GLint internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001000{
Jamie Madill88f18f42013-09-18 14:36:19 -04001001 setImage(0, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001002}
1003
Jamie Madill88f18f42013-09-18 14:36:19 -04001004void TextureCubeMap::setImageNegX(GLint level, GLsizei width, GLsizei height, GLint internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001005{
Jamie Madill88f18f42013-09-18 14:36:19 -04001006 setImage(1, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001007}
1008
Jamie Madill88f18f42013-09-18 14:36:19 -04001009void TextureCubeMap::setImagePosY(GLint level, GLsizei width, GLsizei height, GLint internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001010{
Jamie Madill88f18f42013-09-18 14:36:19 -04001011 setImage(2, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001012}
1013
Jamie Madill88f18f42013-09-18 14:36:19 -04001014void TextureCubeMap::setImageNegY(GLint level, GLsizei width, GLsizei height, GLint internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001015{
Jamie Madill88f18f42013-09-18 14:36:19 -04001016 setImage(3, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001017}
1018
Jamie Madill88f18f42013-09-18 14:36:19 -04001019void TextureCubeMap::setImagePosZ(GLint level, GLsizei width, GLsizei height, GLint internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001020{
Jamie Madill88f18f42013-09-18 14:36:19 -04001021 setImage(4, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001022}
1023
Jamie Madill88f18f42013-09-18 14:36:19 -04001024void TextureCubeMap::setImageNegZ(GLint level, GLsizei width, GLsizei height, GLint internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001025{
Jamie Madill88f18f42013-09-18 14:36:19 -04001026 setImage(5, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001027}
1028
1029void TextureCubeMap::setCompressedImage(GLenum face, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
1030{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001031 // 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 +00001032 redefineImage(faceIndex(face), level, format, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001033
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001034 Texture::setCompressedImage(imageSize, pixels, mImageArray[faceIndex(face)][level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001035}
1036
1037void TextureCubeMap::commitRect(int face, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1038{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001039 if (level < levelCount())
1040 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001041 rx::Image *image = mImageArray[face][level];
daniel@transgaming.com0f195ad2012-10-31 19:51:59 +00001042 if (image->updateSurface(mTexStorage, face, level, xoffset, yoffset, width, height))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001043 image->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001044 }
1045}
1046
Jamie Madill88f18f42013-09-18 14:36:19 -04001047void 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 +00001048{
Jamie Madill88f18f42013-09-18 14:36:19 -04001049 if (Texture::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, mImageArray[faceIndex(target)][level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001050 {
1051 commitRect(faceIndex(target), level, xoffset, yoffset, width, height);
1052 }
1053}
1054
1055void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1056{
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +00001057 if (Texture::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[faceIndex(target)][level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001058 {
1059 commitRect(faceIndex(target), level, xoffset, yoffset, width, height);
1060 }
1061}
1062
1063// Tests for cube map sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 86.
Jamie Madillf8989902013-07-19 16:36:58 -04001064bool TextureCubeMap::isSamplerComplete(const SamplerState &samplerState) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001065{
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001066 int size = mImageArray[0][0]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001067
Jamie Madillf8989902013-07-19 16:36:58 -04001068 bool mipmapping = IsMipmapFiltered(samplerState);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001069
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001070 if (!IsTextureFilteringSupported(getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0), mRenderer))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001071 {
Jamie Madillf8989902013-07-19 16:36:58 -04001072 if (samplerState.magFilter != GL_NEAREST ||
1073 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001074 {
1075 return false;
1076 }
1077 }
1078
daniel@transgaming.comea32d482012-11-28 19:33:18 +00001079 if (!isPow2(size) && !mRenderer->getNonPower2TextureSupport())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001080 {
Jamie Madillf8989902013-07-19 16:36:58 -04001081 if (samplerState.wrapS != GL_CLAMP_TO_EDGE || samplerState.wrapT != GL_CLAMP_TO_EDGE || mipmapping)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001082 {
1083 return false;
1084 }
1085 }
1086
1087 if (!mipmapping)
1088 {
1089 if (!isCubeComplete())
1090 {
1091 return false;
1092 }
1093 }
1094 else
1095 {
1096 if (!isMipmapCubeComplete()) // Also tests for isCubeComplete()
1097 {
1098 return false;
1099 }
1100 }
1101
1102 return true;
1103}
1104
1105// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1106bool TextureCubeMap::isCubeComplete() const
1107{
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001108 if (mImageArray[0][0]->getWidth() <= 0 || mImageArray[0][0]->getHeight() != mImageArray[0][0]->getWidth())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001109 {
1110 return false;
1111 }
1112
1113 for (unsigned int face = 1; face < 6; face++)
1114 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001115 if (mImageArray[face][0]->getWidth() != mImageArray[0][0]->getWidth() ||
1116 mImageArray[face][0]->getWidth() != mImageArray[0][0]->getHeight() ||
1117 mImageArray[face][0]->getInternalFormat() != mImageArray[0][0]->getInternalFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001118 {
1119 return false;
1120 }
1121 }
1122
1123 return true;
1124}
1125
1126bool TextureCubeMap::isMipmapCubeComplete() const
1127{
1128 if (isImmutable())
1129 {
1130 return true;
1131 }
1132
1133 if (!isCubeComplete())
1134 {
1135 return false;
1136 }
1137
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001138 GLsizei size = mImageArray[0][0]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001139 int q = log2(size);
1140
1141 for (int face = 0; face < 6; face++)
1142 {
1143 for (int level = 1; level <= q; level++)
1144 {
Jamie Madill07edd442013-07-19 16:36:58 -04001145 if (!isFaceLevelComplete(face, level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001146 {
1147 return false;
1148 }
1149 }
1150 }
1151
1152 return true;
1153}
1154
Jamie Madill07edd442013-07-19 16:36:58 -04001155bool TextureCubeMap::isFaceLevelComplete(int face, int level) const
1156{
1157 ASSERT(level >= 0 && face < 6 && level < (int)ArraySize(mImageArray[face]) && mImageArray[face][level] != NULL);
1158
1159 if (isImmutable())
1160 {
1161 return true;
1162 }
1163
1164 const rx::Image *baseImage = mImageArray[face][0];
1165 GLsizei size = baseImage->getWidth();
1166
1167 if (size <= 0)
1168 {
1169 return false;
1170 }
1171
1172 // The base image level is complete if the width and height are positive
1173 if (level == 0)
1174 {
1175 return true;
1176 }
1177
1178 rx::Image *image = mImageArray[face][level];
1179
1180 if (image->getInternalFormat() != baseImage->getInternalFormat())
1181 {
1182 return false;
1183 }
1184
1185 if (mImageArray[face][level]->getWidth() != std::max(1, size >> level))
1186 {
1187 return false;
1188 }
1189
1190 return true;
1191}
1192
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001193bool TextureCubeMap::isCompressed(GLenum target, GLint level) const
1194{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001195 return IsFormatCompressed(getInternalFormat(target, level), mRenderer->getCurrentClientVersion());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001196}
1197
Geoff Lang8040f572013-07-25 16:49:54 -04001198bool TextureCubeMap::isDepth(GLenum target, GLint level) const
1199{
1200 return GetDepthBits(getInternalFormat(target, level), mRenderer->getCurrentClientVersion()) > 0;
1201}
1202
daniel@transgaming.comf032cb82012-10-31 19:51:52 +00001203// Constructs a native texture resource from the texture images, or returns an existing one
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001204void TextureCubeMap::createTexture()
1205{
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001206 GLsizei size = mImageArray[0][0]->getWidth();
daniel@transgaming.come6a09842012-09-17 21:28:55 +00001207
1208 if (!(size > 0))
daniel@transgaming.comf032cb82012-10-31 19:51:52 +00001209 return; // do not attempt to create native textures for nonexistant data
daniel@transgaming.come6a09842012-09-17 21:28:55 +00001210
sminns@adobe.comce1189b2012-09-18 20:06:35 +00001211 GLint levels = creationLevels(size);
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001212 GLenum internalformat = mImageArray[0][0]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001213
1214 delete mTexStorage;
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001215 mTexStorage = new rx::TextureStorageInterfaceCube(mRenderer, levels, internalformat, mUsage, false, size);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001216
1217 if (mTexStorage->isManaged())
1218 {
1219 int levels = levelCount();
1220
1221 for (int face = 0; face < 6; face++)
1222 {
1223 for (int level = 0; level < levels; level++)
1224 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001225 mImageArray[face][level]->setManagedSurface(mTexStorage, face, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001226 }
1227 }
1228 }
1229
1230 mDirtyImages = true;
1231}
1232
1233void TextureCubeMap::updateTexture()
1234{
Jamie Madilleb3665c2013-07-19 16:36:57 -04001235 int levels = (isMipmapCubeComplete() ? levelCount() : 1);
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +00001236
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001237 for (int face = 0; face < 6; face++)
1238 {
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001239 for (int level = 0; level < levels; level++)
1240 {
Jamie Madill07edd442013-07-19 16:36:58 -04001241 updateTextureFaceLevel(face, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001242 }
1243 }
1244}
1245
Jamie Madill07edd442013-07-19 16:36:58 -04001246void TextureCubeMap::updateTextureFaceLevel(int face, int level)
1247{
1248 ASSERT(level >= 0 && face < 6 && level < (int)ArraySize(mImageArray[face]) && mImageArray[face][level] != NULL);
1249 rx::Image *image = mImageArray[face][level];
1250
1251 if (image->isDirty())
1252 {
1253 commitRect(face, level, 0, 0, image->getWidth(), image->getHeight());
1254 }
1255}
1256
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001257void TextureCubeMap::convertToRenderTarget()
1258{
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001259 rx::TextureStorageInterfaceCube *newTexStorage = NULL;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001260
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001261 if (mImageArray[0][0]->getWidth() != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001262 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001263 GLsizei size = mImageArray[0][0]->getWidth();
shannon.woods@transgaming.com6bb48862013-02-28 23:09:34 +00001264 GLint levels = mTexStorage != NULL ? mTexStorage->levelCount() : creationLevels(size);
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001265 GLenum internalformat = mImageArray[0][0]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001266
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001267 newTexStorage = new rx::TextureStorageInterfaceCube(mRenderer, levels, internalformat, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, true, size);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001268
1269 if (mTexStorage != NULL)
1270 {
daniel@transgaming.com1d80eee2012-11-28 19:33:31 +00001271 if (!mRenderer->copyToRenderTarget(newTexStorage, mTexStorage))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001272 {
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +00001273 delete newTexStorage;
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +00001274 return gl::error(GL_OUT_OF_MEMORY);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001275 }
1276 }
1277 }
1278
1279 delete mTexStorage;
1280 mTexStorage = newTexStorage;
1281
1282 mDirtyImages = true;
1283}
1284
Jamie Madill88f18f42013-09-18 14:36:19 -04001285void TextureCubeMap::setImage(int faceIndex, GLint level, GLsizei width, GLsizei height, GLint internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001286{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001287 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1288 GLint sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
1289 : GetSizedInternalFormat(format, type, clientVersion);
1290
1291 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001292
Jamie Madill88f18f42013-09-18 14:36:19 -04001293 Texture::setImage(unpack, type, pixels, mImageArray[faceIndex][level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001294}
1295
1296unsigned int TextureCubeMap::faceIndex(GLenum face)
1297{
1298 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
1299 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
1300 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
1301 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
1302 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
1303
1304 return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
1305}
1306
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001307void TextureCubeMap::redefineImage(int face, GLint level, GLint internalformat, GLsizei width, GLsizei height)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001308{
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001309 // If there currently is a corresponding storage texture image, it has these parameters
1310 const int storageWidth = std::max(1, mImageArray[0][0]->getWidth() >> level);
1311 const int storageHeight = std::max(1, mImageArray[0][0]->getHeight() >> level);
1312 const int storageFormat = mImageArray[0][0]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001313
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001314 mImageArray[face][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, width, height, 1, false);
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001315
1316 if (mTexStorage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001317 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001318 const int storageLevels = mTexStorage->levelCount();
1319
1320 if ((level >= storageLevels && storageLevels != 0) ||
1321 width != storageWidth ||
1322 height != storageHeight ||
1323 internalformat != storageFormat) // Discard mismatched storage
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001324 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001325 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001326 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001327 for (int f = 0; f < 6; f++)
1328 {
1329 mImageArray[f][i]->markDirty();
1330 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001331 }
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001332
1333 delete mTexStorage;
1334 mTexStorage = NULL;
1335
1336 mDirtyImages = true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001337 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001338 }
1339}
1340
1341void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1342{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001343 unsigned int faceindex = faceIndex(target);
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001344 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1345 GLint sizedInternalFormat = IsSizedInternalFormat(format, clientVersion) ? format
1346 : GetSizedInternalFormat(format, GL_UNSIGNED_BYTE, clientVersion);
1347 redefineImage(faceindex, level, sizedInternalFormat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001348
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001349 if (!mImageArray[faceindex][level]->isRenderableFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001350 {
shannon.woods%transgaming.com@gtempaccount.come5dcce72013-04-13 03:44:33 +00001351 mImageArray[faceindex][level]->copy(0, 0, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001352 mDirtyImages = true;
1353 }
1354 else
1355 {
1356 if (!mTexStorage || !mTexStorage->isRenderTarget())
1357 {
1358 convertToRenderTarget();
1359 }
1360
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001361 mImageArray[faceindex][level]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001362
1363 ASSERT(width == height);
1364
1365 if (width > 0 && level < levelCount())
1366 {
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +00001367 gl::Rectangle sourceRect;
1368 sourceRect.x = x;
1369 sourceRect.width = width;
1370 sourceRect.y = y;
1371 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001372
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +00001373 mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001374 }
1375 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001376}
1377
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001378void 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 +00001379{
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001380 GLsizei size = mImageArray[faceIndex(target)][level]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001381
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001382 if (xoffset + width > size || yoffset + height > size || zoffset != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001383 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +00001384 return gl::error(GL_INVALID_VALUE);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001385 }
1386
Jamie Madill07edd442013-07-19 16:36:58 -04001387 unsigned int face = faceIndex(target);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001388
Jamie Madill07edd442013-07-19 16:36:58 -04001389 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
1390 // the current level we're copying to is defined (with appropriate format, width & height)
1391 bool canCreateRenderTarget = isFaceLevelComplete(face, level) && isFaceLevelComplete(face, 0);
1392
1393 if (!mImageArray[face][level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001394 {
Jamie Madill07edd442013-07-19 16:36:58 -04001395 mImageArray[face][level]->copy(0, 0, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001396 mDirtyImages = true;
1397 }
1398 else
1399 {
1400 if (!mTexStorage || !mTexStorage->isRenderTarget())
1401 {
1402 convertToRenderTarget();
1403 }
1404
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001405 if (level < levelCount())
1406 {
Jamie Madill07edd442013-07-19 16:36:58 -04001407 updateTextureFaceLevel(face, level);
1408
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001409 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1410
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +00001411 gl::Rectangle sourceRect;
1412 sourceRect.x = x;
1413 sourceRect.width = width;
1414 sourceRect.y = y;
1415 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001416
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001417 mRenderer->copyImage(source, sourceRect, gl::GetFormat(mImageArray[0][0]->getInternalFormat(), clientVersion),
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +00001418 xoffset, yoffset, mTexStorage, target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001419 }
1420 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001421}
1422
1423void TextureCubeMap::storage(GLsizei levels, GLenum internalformat, GLsizei size)
1424{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001425 delete mTexStorage;
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001426 mTexStorage = new rx::TextureStorageInterfaceCube(mRenderer, levels, internalformat, mUsage, false, size);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001427 mImmutable = true;
1428
1429 for (int level = 0; level < levels; level++)
1430 {
1431 for (int face = 0; face < 6; face++)
1432 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001433 mImageArray[face][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, size, size, 1, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001434 size = std::max(1, size >> 1);
1435 }
1436 }
1437
1438 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1439 {
1440 for (int face = 0; face < 6; face++)
1441 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001442 mImageArray[face][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, GL_NONE, 0, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001443 }
1444 }
1445
1446 if (mTexStorage->isManaged())
1447 {
1448 int levels = levelCount();
1449
1450 for (int face = 0; face < 6; face++)
1451 {
1452 for (int level = 0; level < levels; level++)
1453 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001454 mImageArray[face][level]->setManagedSurface(mTexStorage, face, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001455 }
1456 }
1457 }
1458}
1459
1460void TextureCubeMap::generateMipmaps()
1461{
1462 if (!isCubeComplete())
1463 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +00001464 return gl::error(GL_INVALID_OPERATION);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001465 }
1466
daniel@transgaming.comea32d482012-11-28 19:33:18 +00001467 if (!mRenderer->getNonPower2TextureSupport())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001468 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001469 if (!isPow2(mImageArray[0][0]->getWidth()))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001470 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +00001471 return gl::error(GL_INVALID_OPERATION);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001472 }
1473 }
1474
1475 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001476 unsigned int q = log2(mImageArray[0][0]->getWidth());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001477 for (unsigned int f = 0; f < 6; f++)
1478 {
1479 for (unsigned int i = 1; i <= q; i++)
1480 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001481 redefineImage(f, i, mImageArray[f][0]->getInternalFormat(),
shannon.woods@transgaming.com8a406682013-02-28 23:15:26 +00001482 std::max(mImageArray[f][0]->getWidth() >> i, 1),
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001483 std::max(mImageArray[f][0]->getWidth() >> i, 1));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001484 }
1485 }
1486
1487 if (mTexStorage && mTexStorage->isRenderTarget())
1488 {
1489 for (unsigned int f = 0; f < 6; f++)
1490 {
1491 for (unsigned int i = 1; i <= q; i++)
1492 {
daniel@transgaming.com0ad830b2012-10-31 19:52:12 +00001493 mTexStorage->generateMipmap(f, i);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001494
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001495 mImageArray[f][i]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001496 }
1497 }
1498 }
1499 else
1500 {
1501 for (unsigned int f = 0; f < 6; f++)
1502 {
1503 for (unsigned int i = 1; i <= q; i++)
1504 {
daniel@transgaming.com4ba24062012-12-20 20:54:24 +00001505 mRenderer->generateMipmap(mImageArray[f][i], mImageArray[f][i - 1]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001506 }
1507 }
1508 }
1509}
1510
Geoff Lang8040f572013-07-25 16:49:54 -04001511Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target, GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001512{
1513 if (!IsCubemapTextureTarget(target))
1514 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +00001515 return gl::error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001516 }
1517
1518 unsigned int face = faceIndex(target);
1519
Geoff Lang8040f572013-07-25 16:49:54 -04001520 Renderbuffer *renderBuffer = mRenderbufferProxies.get(level, face);
1521 if (!renderBuffer)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001522 {
Geoff Lang8040f572013-07-25 16:49:54 -04001523 renderBuffer = new Renderbuffer(mRenderer, id(), new RenderbufferTextureCubeMap(this, target, level));
1524 mRenderbufferProxies.add(level, face, renderBuffer);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001525 }
1526
Geoff Lang8040f572013-07-25 16:49:54 -04001527 return renderBuffer;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001528}
1529
Geoff Lang8040f572013-07-25 16:49:54 -04001530unsigned int TextureCubeMap::getRenderTargetSerial(GLenum faceTarget, GLint level)
1531{
1532 if (!mTexStorage || !mTexStorage->isRenderTarget())
1533 {
1534 convertToRenderTarget();
1535 }
1536
1537 return mTexStorage ? mTexStorage->getRenderTargetSerial(faceTarget, level) : 0;
1538}
1539
1540rx::RenderTarget *TextureCubeMap::getRenderTarget(GLenum target, GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001541{
1542 ASSERT(IsCubemapTextureTarget(target));
1543
1544 // ensure the underlying texture is created
1545 if (getStorage(true) == NULL)
1546 {
1547 return NULL;
1548 }
1549
1550 updateTexture();
Geoff Lang8040f572013-07-25 16:49:54 -04001551
1552 // ensure this is NOT a depth texture
1553 if (isDepth(target, level))
1554 {
1555 return NULL;
1556 }
1557
1558 return mTexStorage->getRenderTarget(target, level);
1559}
1560
1561rx::RenderTarget *TextureCubeMap::getDepthStencil(GLenum target, GLint level)
1562{
1563 ASSERT(IsCubemapTextureTarget(target));
1564
1565 // ensure the underlying texture is created
1566 if (getStorage(true) == NULL)
1567 {
1568 return NULL;
1569 }
1570
1571 updateTexture();
1572
1573 // ensure this is a depth texture
1574 if (!isDepth(target, level))
1575 {
1576 return NULL;
1577 }
1578
1579 return mTexStorage->getRenderTarget(target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001580}
1581
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +00001582int TextureCubeMap::levelCount()
1583{
1584 return mTexStorage ? mTexStorage->levelCount() - getLodOffset() : 0;
1585}
1586
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001587rx::TextureStorageInterface *TextureCubeMap::getStorage(bool renderTarget)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001588{
1589 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
1590 {
1591 if (renderTarget)
1592 {
1593 convertToRenderTarget();
1594 }
1595 else
1596 {
1597 createTexture();
1598 }
1599 }
1600
1601 return mTexStorage;
1602}
1603
Geoff Lang4907f2c2013-07-25 12:53:57 -04001604Texture3D::Texture3D(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_3D)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001605{
1606 mTexStorage = NULL;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001607
1608 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1609 {
1610 mImageArray[i] = renderer->createImage();
1611 }
1612}
1613
1614Texture3D::~Texture3D()
1615{
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001616 delete mTexStorage;
1617 mTexStorage = NULL;
1618
1619 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1620 {
1621 delete mImageArray[i];
1622 }
1623}
1624
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001625GLsizei Texture3D::getWidth(GLint level) const
1626{
1627 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getWidth() : 0;
1628}
1629
1630GLsizei Texture3D::getHeight(GLint level) const
1631{
1632 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getHeight() : 0;
1633}
1634
1635GLsizei Texture3D::getDepth(GLint level) const
1636{
1637 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getDepth() : 0;
1638}
1639
1640GLenum Texture3D::getInternalFormat(GLint level) const
1641{
1642 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getInternalFormat() : GL_NONE;
1643}
1644
1645GLenum Texture3D::getActualFormat(GLint level) const
1646{
1647 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getActualFormat() : D3DFMT_UNKNOWN;
1648}
1649
1650bool Texture3D::isCompressed(GLint level) const
1651{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001652 return IsFormatCompressed(getInternalFormat(level), mRenderer->getCurrentClientVersion());
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001653}
1654
1655bool Texture3D::isDepth(GLint level) const
1656{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001657 return GetDepthBits(getInternalFormat(level), mRenderer->getCurrentClientVersion()) > 0;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001658}
1659
Jamie Madill88f18f42013-09-18 14:36:19 -04001660void Texture3D::setImage(GLint level, GLsizei width, GLsizei height, GLsizei depth, GLint internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001661{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001662 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1663 GLint sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
1664 : GetSizedInternalFormat(format, type, clientVersion);
1665 redefineImage(level, sizedInternalFormat, width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001666
Jamie Madill88f18f42013-09-18 14:36:19 -04001667 Texture::setImage(unpack, type, pixels, mImageArray[level]);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001668}
1669
1670void Texture3D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
1671{
1672 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1673 redefineImage(level, format, width, height, depth);
1674
1675 Texture::setCompressedImage(imageSize, pixels, mImageArray[level]);
1676}
1677
Jamie Madill88f18f42013-09-18 14:36:19 -04001678void 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 +00001679{
Jamie Madill88f18f42013-09-18 14:36:19 -04001680 if (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 +00001681 {
1682 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1683 }
1684}
1685
1686void Texture3D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
1687{
1688 if (Texture::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth, format, imageSize, pixels, mImageArray[level]))
1689 {
1690 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1691 }
1692}
1693
1694void Texture3D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
1695{
1696 delete mTexStorage;
1697 mTexStorage = new rx::TextureStorageInterface3D(mRenderer, levels, internalformat, mUsage, width, height, depth);
1698 mImmutable = true;
1699
1700 for (int level = 0; level < levels; level++)
1701 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001702 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, true);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001703 width = std::max(1, width >> 1);
1704 height = std::max(1, height >> 1);
1705 depth = std::max(1, depth >> 1);
1706 }
1707
1708 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1709 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001710 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, GL_NONE, 0, 0, 0, true);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001711 }
1712
1713 if (mTexStorage->isManaged())
1714 {
1715 int levels = levelCount();
1716
1717 for (int level = 0; level < levels; level++)
1718 {
1719 mImageArray[level]->setManagedSurface(mTexStorage, level);
1720 }
1721 }
1722}
1723
1724
1725void Texture3D::generateMipmaps()
1726{
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001727 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1728 unsigned int q = log2(std::max(mImageArray[0]->getWidth(), mImageArray[0]->getHeight()));
1729 for (unsigned int i = 1; i <= q; i++)
1730 {
1731 redefineImage(i, mImageArray[0]->getInternalFormat(),
1732 std::max(mImageArray[0]->getWidth() >> i, 1),
1733 std::max(mImageArray[0]->getHeight() >> i, 1),
1734 std::max(mImageArray[0]->getDepth() >> i, 1));
1735 }
1736
1737 if (mTexStorage && mTexStorage->isRenderTarget())
1738 {
1739 for (unsigned int i = 1; i <= q; i++)
1740 {
1741 mTexStorage->generateMipmap(i);
1742
1743 mImageArray[i]->markClean();
1744 }
1745 }
1746 else
1747 {
1748 for (unsigned int i = 1; i <= q; i++)
1749 {
1750 mRenderer->generateMipmap(mImageArray[i], mImageArray[i - 1]);
1751 }
1752 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001753}
1754
1755void Texture3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1756{
1757 if (xoffset + width > mImageArray[level]->getWidth() || yoffset + height > mImageArray[level]->getHeight() || zoffset >= mImageArray[level]->getDepth())
1758 {
1759 return gl::error(GL_INVALID_VALUE);
1760 }
1761
Jamie Madill07edd442013-07-19 16:36:58 -04001762 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
1763 // the current level we're copying to is defined (with appropriate format, width & height)
1764 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
1765
1766 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001767 {
1768 mImageArray[level]->copy(xoffset, yoffset, zoffset, x, y, width, height, source);
1769 mDirtyImages = true;
1770 }
1771 else
1772 {
1773 if (!mTexStorage || !mTexStorage->isRenderTarget())
1774 {
1775 convertToRenderTarget();
1776 }
1777
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001778 if (level < levelCount())
1779 {
Jamie Madill07edd442013-07-19 16:36:58 -04001780 updateTextureLevel(level);
1781
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001782 gl::Rectangle sourceRect;
1783 sourceRect.x = x;
1784 sourceRect.width = width;
1785 sourceRect.y = y;
1786 sourceRect.height = height;
1787
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001788 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1789
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001790 mRenderer->copyImage(source, sourceRect,
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001791 gl::GetFormat(mImageArray[0]->getInternalFormat(), clientVersion),
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001792 xoffset, yoffset, zoffset, mTexStorage, level);
1793 }
1794 }
1795}
1796
Jamie Madillf8989902013-07-19 16:36:58 -04001797bool Texture3D::isSamplerComplete(const SamplerState &samplerState) const
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001798{
1799 GLsizei width = mImageArray[0]->getWidth();
1800 GLsizei height = mImageArray[0]->getHeight();
1801 GLsizei depth = mImageArray[0]->getDepth();
1802
1803 if (width <= 0 || height <= 0 || depth <= 0)
1804 {
1805 return false;
1806 }
1807
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001808 if (!IsTextureFilteringSupported(getInternalFormat(0), mRenderer))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001809 {
Jamie Madillf8989902013-07-19 16:36:58 -04001810 if (samplerState.magFilter != GL_NEAREST ||
1811 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001812 {
1813 return false;
1814 }
1815 }
1816
Jamie Madillf8989902013-07-19 16:36:58 -04001817 if (IsMipmapFiltered(samplerState) && !isMipmapComplete())
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001818 {
1819 return false;
1820 }
1821
1822 return true;
1823}
1824
1825bool Texture3D::isMipmapComplete() const
1826{
Jamie Madill07edd442013-07-19 16:36:58 -04001827 GLsizei width = mImageArray[0]->getWidth();
1828 GLsizei height = mImageArray[0]->getHeight();
1829 GLsizei depth = mImageArray[0]->getDepth();
1830
1831 int q = log2(std::max(std::max(width, height), depth));
1832
1833 for (int level = 0; level <= q; level++)
1834 {
1835 if (!isLevelComplete(level))
1836 {
1837 return false;
1838 }
1839 }
1840
1841 return true;
1842}
1843
1844bool Texture3D::isLevelComplete(int level) const
1845{
1846 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1847
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001848 if (isImmutable())
1849 {
1850 return true;
1851 }
1852
Jamie Madill07edd442013-07-19 16:36:58 -04001853 rx::Image *baseImage = mImageArray[0];
1854
1855 GLsizei width = baseImage->getWidth();
1856 GLsizei height = baseImage->getHeight();
1857 GLsizei depth = baseImage->getDepth();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001858
1859 if (width <= 0 || height <= 0 || depth <= 0)
1860 {
1861 return false;
1862 }
1863
Jamie Madill07edd442013-07-19 16:36:58 -04001864 if (level == 0)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001865 {
Jamie Madill07edd442013-07-19 16:36:58 -04001866 return true;
1867 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001868
Jamie Madill07edd442013-07-19 16:36:58 -04001869 rx::Image *levelImage = mImageArray[level];
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001870
Jamie Madill07edd442013-07-19 16:36:58 -04001871 if (levelImage->getInternalFormat() != baseImage->getInternalFormat())
1872 {
1873 return false;
1874 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001875
Jamie Madill07edd442013-07-19 16:36:58 -04001876 if (levelImage->getWidth() != std::max(1, width >> level))
1877 {
1878 return false;
1879 }
1880
1881 if (levelImage->getHeight() != std::max(1, height >> level))
1882 {
1883 return false;
1884 }
1885
1886 if (levelImage->getDepth() != std::max(1, depth >> level))
1887 {
1888 return false;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001889 }
1890
1891 return true;
1892}
1893
Geoff Lang8040f572013-07-25 16:49:54 -04001894Renderbuffer *Texture3D::getRenderbuffer(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001895{
Geoff Lang8040f572013-07-25 16:49:54 -04001896 Renderbuffer *renderBuffer = mRenderbufferProxies.get(level, layer);
1897 if (!renderBuffer)
1898 {
Geoff Langd5d8e392013-07-25 16:53:03 -04001899 renderBuffer = new Renderbuffer(mRenderer, id(), new RenderbufferTexture3DLayer(this, level, layer));
1900 mRenderbufferProxies.add(level, 0, renderBuffer);
Geoff Lang8040f572013-07-25 16:49:54 -04001901 }
1902
1903 return renderBuffer;
1904}
1905
1906unsigned int Texture3D::getRenderTargetSerial(GLint level, GLint layer)
1907{
1908 if (!mTexStorage || !mTexStorage->isRenderTarget())
1909 {
1910 convertToRenderTarget();
1911 }
1912
1913 return mTexStorage ? mTexStorage->getRenderTargetSerial(level, layer) : 0;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001914}
1915
1916int Texture3D::levelCount()
1917{
1918 return mTexStorage ? mTexStorage->levelCount() : 0;
1919}
1920
1921void Texture3D::createTexture()
1922{
1923 GLsizei width = mImageArray[0]->getWidth();
1924 GLsizei height = mImageArray[0]->getHeight();
1925 GLsizei depth = mImageArray[0]->getDepth();
1926
1927 if (!(width > 0 && height > 0 && depth > 0))
1928 return; // do not attempt to create native textures for nonexistant data
1929
1930 GLint levels = creationLevels(width, height, depth);
1931 GLenum internalformat = mImageArray[0]->getInternalFormat();
1932
1933 delete mTexStorage;
1934 mTexStorage = new rx::TextureStorageInterface3D(mRenderer, levels, internalformat, mUsage, width, height, depth);
1935
1936 if (mTexStorage->isManaged())
1937 {
1938 int levels = levelCount();
1939
1940 for (int level = 0; level < levels; level++)
1941 {
1942 mImageArray[level]->setManagedSurface(mTexStorage, level);
1943 }
1944 }
1945
1946 mDirtyImages = true;
1947}
1948
1949void Texture3D::updateTexture()
1950{
Jamie Madilleb3665c2013-07-19 16:36:57 -04001951 int levels = (isMipmapComplete() ? levelCount() : 1);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001952
1953 for (int level = 0; level < levels; level++)
1954 {
Jamie Madill07edd442013-07-19 16:36:58 -04001955 updateTextureLevel(level);
1956 }
1957}
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001958
Jamie Madill07edd442013-07-19 16:36:58 -04001959void Texture3D::updateTextureLevel(int level)
1960{
1961 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1962
1963 rx::Image *image = mImageArray[level];
1964
1965 if (image->isDirty())
1966 {
1967 commitRect(level, 0, 0, 0, mImageArray[level]->getWidth(), mImageArray[level]->getHeight(), mImageArray[level]->getDepth());
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001968 }
1969}
1970
1971void Texture3D::convertToRenderTarget()
1972{
1973 rx::TextureStorageInterface3D *newTexStorage = NULL;
1974
1975 if (mImageArray[0]->getWidth() != 0 && mImageArray[0]->getHeight() != 0 && mImageArray[0]->getDepth() != 0)
1976 {
1977 GLsizei width = mImageArray[0]->getWidth();
1978 GLsizei height = mImageArray[0]->getHeight();
1979 GLsizei depth = mImageArray[0]->getDepth();
1980 GLint levels = mTexStorage != NULL ? mTexStorage->levelCount() : creationLevels(width, height, depth);
1981 GLenum internalformat = mImageArray[0]->getInternalFormat();
1982
1983 newTexStorage = new rx::TextureStorageInterface3D(mRenderer, levels, internalformat, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, width, height, depth);
1984
1985 if (mTexStorage != NULL)
1986 {
1987 if (!mRenderer->copyToRenderTarget(newTexStorage, mTexStorage))
1988 {
1989 delete newTexStorage;
1990 return gl::error(GL_OUT_OF_MEMORY);
1991 }
1992 }
1993 }
1994
1995 delete mTexStorage;
1996 mTexStorage = newTexStorage;
1997
1998 mDirtyImages = true;
1999}
2000
Geoff Lang8040f572013-07-25 16:49:54 -04002001rx::RenderTarget *Texture3D::getRenderTarget(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002002{
Geoff Lang8040f572013-07-25 16:49:54 -04002003 // ensure the underlying texture is created
2004 if (getStorage(true) == NULL)
2005 {
2006 return NULL;
2007 }
2008
2009 updateTexture();
2010
2011 // ensure this is NOT a depth texture
2012 if (isDepth(level))
2013 {
2014 return NULL;
2015 }
2016
2017 return mTexStorage->getRenderTarget(level, layer);
2018}
2019
2020rx::RenderTarget *Texture3D::getDepthStencil(GLint level, GLint layer)
2021{
2022 // ensure the underlying texture is created
2023 if (getStorage(true) == NULL)
2024 {
2025 return NULL;
2026 }
2027
2028 updateTexture();
2029
2030 // ensure this is a depth texture
2031 if (!isDepth(level))
2032 {
2033 return NULL;
2034 }
2035
2036 return mTexStorage->getRenderTarget(level, layer);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002037}
2038
2039rx::TextureStorageInterface *Texture3D::getStorage(bool renderTarget)
2040{
2041 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
2042 {
2043 if (renderTarget)
2044 {
2045 convertToRenderTarget();
2046 }
2047 else
2048 {
2049 createTexture();
2050 }
2051 }
2052
2053 return mTexStorage;
2054}
2055
2056void Texture3D::redefineImage(GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth)
2057{
2058 // If there currently is a corresponding storage texture image, it has these parameters
2059 const int storageWidth = std::max(1, mImageArray[0]->getWidth() >> level);
2060 const int storageHeight = std::max(1, mImageArray[0]->getHeight() >> level);
2061 const int storageDepth = std::max(1, mImageArray[0]->getDepth() >> level);
2062 const int storageFormat = mImageArray[0]->getInternalFormat();
2063
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00002064 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, false);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002065
2066 if (mTexStorage)
2067 {
2068 const int storageLevels = mTexStorage->levelCount();
2069
2070 if ((level >= storageLevels && storageLevels != 0) ||
2071 width != storageWidth ||
2072 height != storageHeight ||
2073 depth != storageDepth ||
2074 internalformat != storageFormat) // Discard mismatched storage
2075 {
2076 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
2077 {
2078 mImageArray[i]->markDirty();
2079 }
2080
2081 delete mTexStorage;
2082 mTexStorage = NULL;
2083 mDirtyImages = true;
2084 }
2085 }
2086}
2087
2088void Texture3D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth)
2089{
2090 if (level < levelCount())
2091 {
2092 rx::Image *image = mImageArray[level];
2093 if (image->updateSurface(mTexStorage, level, xoffset, yoffset, zoffset, width, height, depth))
2094 {
2095 image->markClean();
2096 }
2097 }
2098}
2099
Geoff Lang4907f2c2013-07-25 12:53:57 -04002100Texture2DArray::Texture2DArray(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_2D_ARRAY)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002101{
2102 mTexStorage = NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002103
2104 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2105 {
2106 mLayerCounts[level] = 0;
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002107 mImageArray[level] = NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002108 }
2109}
2110
2111Texture2DArray::~Texture2DArray()
2112{
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002113 delete mTexStorage;
2114 mTexStorage = NULL;
2115 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2116 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002117 for (int layer = 0; layer < mLayerCounts[level]; ++layer)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002118 {
2119 delete mImageArray[level][layer];
2120 }
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002121 delete[] mImageArray[level];
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002122 }
2123}
2124
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002125GLsizei Texture2DArray::getWidth(GLint level) const
2126{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002127 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 +00002128}
2129
2130GLsizei Texture2DArray::getHeight(GLint level) const
2131{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002132 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 +00002133}
2134
2135GLsizei Texture2DArray::getDepth(GLint level) const
2136{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002137 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mLayerCounts[level] : 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002138}
2139
2140GLenum Texture2DArray::getInternalFormat(GLint level) const
2141{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002142 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 +00002143}
2144
2145GLenum Texture2DArray::getActualFormat(GLint level) const
2146{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002147 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getActualFormat() : D3DFMT_UNKNOWN;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002148}
2149
2150bool Texture2DArray::isCompressed(GLint level) const
2151{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00002152 return IsFormatCompressed(getInternalFormat(level), mRenderer->getCurrentClientVersion());
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002153}
2154
2155bool Texture2DArray::isDepth(GLint level) const
2156{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00002157 return GetDepthBits(getInternalFormat(level), mRenderer->getCurrentClientVersion()) > 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002158}
2159
Jamie Madill88f18f42013-09-18 14:36:19 -04002160void Texture2DArray::setImage(GLint level, GLsizei width, GLsizei height, GLsizei depth, GLint internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002161{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00002162 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2163 GLint sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
2164 : GetSizedInternalFormat(format, type, clientVersion);
2165 redefineImage(level, sizedInternalFormat, width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002166
Jamie Madill88f18f42013-09-18 14:36:19 -04002167 GLsizei inputDepthPitch = gl::GetDepthPitch(sizedInternalFormat, type, clientVersion, width, height, unpack.alignment);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002168
2169 for (int i = 0; i < depth; i++)
2170 {
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002171 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
Jamie Madill88f18f42013-09-18 14:36:19 -04002172 Texture::setImage(unpack, type, layerPixels, mImageArray[level][i]);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002173 }
2174}
2175
2176void Texture2DArray::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
2177{
2178 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
2179 redefineImage(level, format, width, height, depth);
2180
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002181 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2182 GLsizei inputDepthPitch = gl::GetDepthPitch(format, GL_UNSIGNED_BYTE, clientVersion, width, height, 1);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002183
2184 for (int i = 0; i < depth; i++)
2185 {
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002186 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002187 Texture::setCompressedImage(imageSize, layerPixels, mImageArray[level][i]);
2188 }
2189}
2190
Jamie Madill88f18f42013-09-18 14:36:19 -04002191void 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 +00002192{
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002193 GLint internalformat = getInternalFormat(level);
2194 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Jamie Madill88f18f42013-09-18 14:36:19 -04002195 GLsizei inputDepthPitch = gl::GetDepthPitch(internalformat, type, clientVersion, width, height, unpack.alignment);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002196
2197 for (int i = 0; i < depth; i++)
2198 {
2199 int layer = zoffset + i;
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002200 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002201
Jamie Madill88f18f42013-09-18 14:36:19 -04002202 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 +00002203 {
2204 commitRect(level, xoffset, yoffset, layer, width, height);
2205 }
2206 }
2207}
2208
2209void Texture2DArray::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
2210{
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002211 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2212 GLsizei inputDepthPitch = gl::GetDepthPitch(format, GL_UNSIGNED_BYTE, clientVersion, width, height, 1);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002213
2214 for (int i = 0; i < depth; i++)
2215 {
2216 int layer = zoffset + i;
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002217 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002218
2219 if (Texture::subImageCompressed(xoffset, yoffset, zoffset, width, height, 1, format, imageSize, layerPixels, mImageArray[level][layer]))
2220 {
2221 commitRect(level, xoffset, yoffset, layer, width, height);
2222 }
2223 }
2224}
2225
2226void Texture2DArray::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2227{
2228 delete mTexStorage;
2229 mTexStorage = new rx::TextureStorageInterface2DArray(mRenderer, levels, internalformat, mUsage, width, height, depth);
2230 mImmutable = true;
2231
2232 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2233 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002234 GLsizei levelWidth = std::max(width >> level, 1);
Geoff Lange836cf22013-08-05 14:12:37 -04002235 GLsizei levelHeight = std::max(height >> level, 1);
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002236
2237 // Clear this level
2238 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002239 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002240 delete mImageArray[level][layer];
2241 }
2242 delete[] mImageArray[level];
2243 mImageArray[level] = NULL;
2244 mLayerCounts[level] = 0;
2245
2246 if (level < levels)
2247 {
2248 // Create new images for this level
2249 mImageArray[level] = new rx::Image*[depth]();
2250 mLayerCounts[level] = depth;
2251
2252 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002253 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002254 mImageArray[level][layer] = mRenderer->createImage();
2255 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, levelWidth,
2256 levelHeight, 1, true);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002257 }
2258 }
2259 }
2260
2261 if (mTexStorage->isManaged())
2262 {
2263 int levels = levelCount();
2264
2265 for (int level = 0; level < levels; level++)
2266 {
2267 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2268 {
2269 mImageArray[level][layer]->setManagedSurface(mTexStorage, layer, level);
2270 }
2271 }
2272 }
2273}
2274
2275void Texture2DArray::generateMipmaps()
2276{
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00002277 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
2278 int q = log2(std::max(getWidth(0), getHeight(0)));
2279 for (int i = 1; i <= q; i++)
2280 {
2281 redefineImage(i, getInternalFormat(0), std::max(getWidth(0) >> i, 1), std::max(getHeight(0) >> i, 1), getDepth(0));
2282 }
2283
2284 if (mTexStorage && mTexStorage->isRenderTarget())
2285 {
2286 for (int level = 1; level <= q; level++)
2287 {
2288 mTexStorage->generateMipmap(level);
2289
2290 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2291 {
2292 mImageArray[level][layer]->markClean();
2293 }
2294 }
2295 }
2296 else
2297 {
2298 for (int level = 1; level <= q; level++)
2299 {
2300 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2301 {
2302 mRenderer->generateMipmap(mImageArray[level][layer], mImageArray[level - 1][layer]);
2303 }
2304 }
2305 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002306}
2307
2308void Texture2DArray::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
2309{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002310 if (xoffset + width > getWidth(level) || yoffset + height > getHeight(level) || zoffset >= getDepth(level) || getDepth(level) == 0)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002311 {
2312 return gl::error(GL_INVALID_VALUE);
2313 }
2314
Jamie Madill07edd442013-07-19 16:36:58 -04002315 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
2316 // the current level we're copying to is defined (with appropriate format, width & height)
2317 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
2318
2319 if (!mImageArray[level][0]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002320 {
2321 mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, x, y, width, height, source);
2322 mDirtyImages = true;
2323 }
2324 else
2325 {
2326 if (!mTexStorage || !mTexStorage->isRenderTarget())
2327 {
2328 convertToRenderTarget();
2329 }
2330
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002331 if (level < levelCount())
2332 {
Jamie Madill07edd442013-07-19 16:36:58 -04002333 updateTextureLevel(level);
2334
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002335 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2336
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002337 gl::Rectangle sourceRect;
2338 sourceRect.x = x;
2339 sourceRect.width = width;
2340 sourceRect.y = y;
2341 sourceRect.height = height;
2342
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002343 mRenderer->copyImage(source, sourceRect, gl::GetFormat(getInternalFormat(0), clientVersion),
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002344 xoffset, yoffset, zoffset, mTexStorage, level);
2345 }
2346 }
2347}
2348
Jamie Madillf8989902013-07-19 16:36:58 -04002349bool Texture2DArray::isSamplerComplete(const SamplerState &samplerState) const
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002350{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002351 GLsizei width = getWidth(0);
2352 GLsizei height = getHeight(0);
2353 GLsizei depth = getDepth(0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002354
2355 if (width <= 0 || height <= 0 || depth <= 0)
2356 {
2357 return false;
2358 }
2359
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00002360 if (!IsTextureFilteringSupported(getInternalFormat(0), mRenderer))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002361 {
Jamie Madillf8989902013-07-19 16:36:58 -04002362 if (samplerState.magFilter != GL_NEAREST ||
2363 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002364 {
2365 return false;
2366 }
2367 }
2368
Jamie Madillf8989902013-07-19 16:36:58 -04002369 if (IsMipmapFiltered(samplerState) && !isMipmapComplete())
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002370 {
2371 return false;
2372 }
2373
2374 return true;
2375}
2376
2377bool Texture2DArray::isMipmapComplete() const
2378{
Jamie Madill07edd442013-07-19 16:36:58 -04002379 GLsizei width = getWidth(0);
2380 GLsizei height = getHeight(0);
2381
2382 int q = log2(std::max(width, height));
2383
2384 for (int level = 1; level <= q; level++)
2385 {
2386 if (!isLevelComplete(level))
2387 {
2388 return false;
2389 }
2390 }
2391
2392 return true;
2393}
2394
2395bool Texture2DArray::isLevelComplete(int level) const
2396{
2397 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
2398
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002399 if (isImmutable())
2400 {
2401 return true;
2402 }
2403
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002404 GLsizei width = getWidth(0);
2405 GLsizei height = getHeight(0);
2406 GLsizei depth = getDepth(0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002407
2408 if (width <= 0 || height <= 0 || depth <= 0)
2409 {
2410 return false;
2411 }
2412
Jamie Madill07edd442013-07-19 16:36:58 -04002413 if (level == 0)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002414 {
Jamie Madill07edd442013-07-19 16:36:58 -04002415 return true;
2416 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002417
Jamie Madill07edd442013-07-19 16:36:58 -04002418 if (getInternalFormat(level) != getInternalFormat(0))
2419 {
2420 return false;
2421 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002422
Jamie Madill07edd442013-07-19 16:36:58 -04002423 if (getWidth(level) != std::max(1, width >> level))
2424 {
2425 return false;
2426 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002427
Jamie Madill07edd442013-07-19 16:36:58 -04002428 if (getHeight(level) != std::max(1, height >> level))
2429 {
2430 return false;
2431 }
2432
2433 if (getDepth(level) != depth)
2434 {
2435 return false;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002436 }
2437
2438 return true;
2439}
2440
Geoff Lang8040f572013-07-25 16:49:54 -04002441Renderbuffer *Texture2DArray::getRenderbuffer(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002442{
Geoff Lang8040f572013-07-25 16:49:54 -04002443 Renderbuffer *renderBuffer = mRenderbufferProxies.get(level, layer);
2444 if (!renderBuffer)
2445 {
Geoff Langd5d8e392013-07-25 16:53:03 -04002446 renderBuffer = new Renderbuffer(mRenderer, id(), new RenderbufferTexture2DArrayLayer(this, level, layer));
2447 mRenderbufferProxies.add(level, 0, renderBuffer);
Geoff Lang8040f572013-07-25 16:49:54 -04002448 }
2449
2450 return renderBuffer;
2451}
2452
2453unsigned int Texture2DArray::getRenderTargetSerial( GLint level, GLint layer )
2454{
2455 if (!mTexStorage || !mTexStorage->isRenderTarget())
2456 {
2457 convertToRenderTarget();
2458 }
2459
2460 return mTexStorage ? mTexStorage->getRenderTargetSerial(level, layer) : 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002461}
2462
2463int Texture2DArray::levelCount()
2464{
2465 return mTexStorage ? mTexStorage->levelCount() : 0;
2466}
2467
2468void Texture2DArray::createTexture()
2469{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002470 GLsizei width = getWidth(0);
2471 GLsizei height = getHeight(0);
2472 GLsizei depth = getDepth(0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002473
2474 if (width <= 0 || height <= 0 || depth <= 0)
2475 {
2476 return; // do not attempt to create native textures for nonexistant data
2477 }
2478
2479 GLint levels = creationLevels(width, height);
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002480 GLenum internalformat = getInternalFormat(0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002481
2482 delete mTexStorage;
2483 mTexStorage = new rx::TextureStorageInterface2DArray(mRenderer, levels, internalformat, mUsage, width, height, depth);
2484
2485 if (mTexStorage->isManaged())
2486 {
2487 int levels = levelCount();
2488 for (int level = 0; level < levels; level++)
2489 {
2490 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2491 {
2492 mImageArray[level][layer]->setManagedSurface(mTexStorage, layer, level);
2493 }
2494 }
2495 }
2496
2497 mDirtyImages = true;
2498}
2499
2500void Texture2DArray::updateTexture()
2501{
Jamie Madilleb3665c2013-07-19 16:36:57 -04002502 int levels = (isMipmapComplete() ? levelCount() : 1);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002503 for (int level = 0; level < levels; level++)
2504 {
Jamie Madill07edd442013-07-19 16:36:58 -04002505 updateTextureLevel(level);
2506 }
2507}
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002508
Jamie Madill07edd442013-07-19 16:36:58 -04002509void Texture2DArray::updateTextureLevel(int level)
2510{
2511 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2512 {
2513 rx::Image *image = mImageArray[level][layer];
2514
2515 if (image->isDirty())
2516 {
2517 commitRect(level, 0, 0, layer, image->getWidth(), image->getHeight());
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002518 }
2519 }
2520}
2521
2522void Texture2DArray::convertToRenderTarget()
2523{
2524 rx::TextureStorageInterface2DArray *newTexStorage = NULL;
2525
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002526 GLsizei width = getWidth(0);
2527 GLsizei height = getHeight(0);
2528 GLsizei depth = getDepth(0);
2529
2530 if (width != 0 && height != 0 && depth != 0)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002531 {
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002532 GLint levels = mTexStorage != NULL ? mTexStorage->levelCount() : creationLevels(width, height);
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002533 GLenum internalformat = getInternalFormat(0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002534
2535 newTexStorage = new rx::TextureStorageInterface2DArray(mRenderer, levels, internalformat, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, width, height, depth);
2536
2537 if (mTexStorage != NULL)
2538 {
2539 if (!mRenderer->copyToRenderTarget(newTexStorage, mTexStorage))
2540 {
2541 delete newTexStorage;
2542 return gl::error(GL_OUT_OF_MEMORY);
2543 }
2544 }
2545 }
2546
2547 delete mTexStorage;
2548 mTexStorage = newTexStorage;
2549
2550 mDirtyImages = true;
2551}
2552
Geoff Lang8040f572013-07-25 16:49:54 -04002553rx::RenderTarget *Texture2DArray::getRenderTarget(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002554{
Geoff Lang8040f572013-07-25 16:49:54 -04002555 // ensure the underlying texture is created
2556 if (getStorage(true) == NULL)
2557 {
2558 return NULL;
2559 }
2560
2561 updateTexture();
2562
2563 // ensure this is NOT a depth texture
2564 if (isDepth(level))
2565 {
2566 return NULL;
2567 }
2568
2569 return mTexStorage->getRenderTarget(level, layer);
2570}
2571
2572rx::RenderTarget *Texture2DArray::getDepthStencil(GLint level, GLint layer)
2573{
2574 // ensure the underlying texture is created
2575 if (getStorage(true) == NULL)
2576 {
2577 return NULL;
2578 }
2579
2580 updateTexture();
2581
2582 // ensure this is a depth texture
2583 if (!isDepth(level))
2584 {
2585 return NULL;
2586 }
2587
2588 return mTexStorage->getRenderTarget(level, layer);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002589}
2590
2591rx::TextureStorageInterface *Texture2DArray::getStorage(bool renderTarget)
2592{
2593 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
2594 {
2595 if (renderTarget)
2596 {
2597 convertToRenderTarget();
2598 }
2599 else
2600 {
2601 createTexture();
2602 }
2603 }
2604
2605 return mTexStorage;
2606}
2607
2608void Texture2DArray::redefineImage(GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth)
2609{
2610 // If there currently is a corresponding storage texture image, it has these parameters
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002611 const int storageWidth = std::max(1, getWidth(0) >> level);
2612 const int storageHeight = std::max(1, getHeight(0) >> level);
2613 const int storageDepth = getDepth(0);
2614 const int storageFormat = getInternalFormat(0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002615
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002616 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002617 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002618 delete mImageArray[level][layer];
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002619 }
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002620 delete[] mImageArray[level];
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002621
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002622 mImageArray[level] = new rx::Image*[depth]();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002623 mLayerCounts[level] = depth;
2624
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002625 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2626 {
2627 mImageArray[level][layer] = mRenderer->createImage();
2628 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, width, height, 1, false);
2629 }
2630
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002631 if (mTexStorage)
2632 {
2633 const int storageLevels = mTexStorage->levelCount();
2634
2635 if ((level >= storageLevels && storageLevels != 0) ||
2636 width != storageWidth ||
2637 height != storageHeight ||
2638 depth != storageDepth ||
2639 internalformat != storageFormat) // Discard mismatched storage
2640 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002641 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002642 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002643 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002644 {
2645 mImageArray[level][layer]->markDirty();
2646 }
2647 }
2648
2649 delete mTexStorage;
2650 mTexStorage = NULL;
2651 mDirtyImages = true;
2652 }
2653 }
2654}
2655
2656void Texture2DArray::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint layerTarget, GLsizei width, GLsizei height)
2657{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002658 if (level < levelCount() && layerTarget < getDepth(level))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002659 {
2660 rx::Image *image = mImageArray[level][layerTarget];
2661 if (image->updateSurface(mTexStorage, level, xoffset, yoffset, layerTarget, width, height))
2662 {
2663 image->markClean();
2664 }
2665 }
2666}
2667
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00002668}