blob: 167ceabccb78ae36951eb4ca749770f6996a37a7 [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"
shannon.woods@transgaming.com486d9e92013-02-28 23:15:41 +000018#include "libGLESv2/Renderbuffer.h"
19#include "libGLESv2/renderer/Image.h"
20#include "libGLESv2/renderer/Renderer.h"
21#include "libGLESv2/renderer/TextureStorage.h"
22#include "libEGL/Surface.h"
Jamie Madill1beb1db2013-09-18 14:36:28 -040023#include "libGLESv2/Buffer.h"
24#include "libGLESv2/renderer/BufferStorage.h"
Jamie Madill0e0510f2013-10-10 15:46:23 -040025#include "libGLESv2/renderer/RenderTarget.h"
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000026
27namespace gl
28{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000029
Jamie Madillf8989902013-07-19 16:36:58 -040030bool IsMipmapFiltered(const SamplerState &samplerState)
31{
32 switch (samplerState.minFilter)
33 {
34 case GL_NEAREST:
35 case GL_LINEAR:
36 return false;
37 case GL_NEAREST_MIPMAP_NEAREST:
38 case GL_LINEAR_MIPMAP_NEAREST:
39 case GL_NEAREST_MIPMAP_LINEAR:
40 case GL_LINEAR_MIPMAP_LINEAR:
41 return true;
42 default: UNREACHABLE();
43 return false;
44 }
45}
46
Jamie Madilld4589c92013-10-24 17:49:34 -040047bool IsRenderTargetUsage(GLenum usage)
48{
49 return (usage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
50}
51
Geoff Lang4907f2c2013-07-25 12:53:57 -040052Texture::Texture(rx::Renderer *renderer, GLuint id, GLenum target) : RefCountObject(id)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000053{
daniel@transgaming.com370482e2012-11-28 19:32:13 +000054 mRenderer = renderer;
55
daniel@transgaming.comebf139f2012-10-31 18:07:32 +000056 mSamplerState.minFilter = GL_NEAREST_MIPMAP_LINEAR;
57 mSamplerState.magFilter = GL_LINEAR;
58 mSamplerState.wrapS = GL_REPEAT;
59 mSamplerState.wrapT = GL_REPEAT;
shannon.woods%transgaming.com@gtempaccount.com0b3a8df2013-04-13 03:44:51 +000060 mSamplerState.wrapR = GL_REPEAT;
daniel@transgaming.comebf139f2012-10-31 18:07:32 +000061 mSamplerState.maxAnisotropy = 1.0f;
62 mSamplerState.lodOffset = 0;
Geoff Langc82fc412013-07-10 14:43:42 -040063 mSamplerState.compareMode = GL_NONE;
64 mSamplerState.compareFunc = GL_LEQUAL;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000065 mUsage = GL_NONE;
Geoff Langc82fc412013-07-10 14:43:42 -040066
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000067 mDirtyImages = true;
68
69 mImmutable = false;
Geoff Lang4907f2c2013-07-25 12:53:57 -040070
71 mTarget = target;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000072}
73
74Texture::~Texture()
75{
76}
77
Geoff Lang4907f2c2013-07-25 12:53:57 -040078GLenum Texture::getTarget() const
79{
80 return mTarget;
81}
82
Geoff Lang8040f572013-07-25 16:49:54 -040083void Texture::addProxyRef(const Renderbuffer *proxy)
84{
85 mRenderbufferProxies.addRef(proxy);
86}
87
88void Texture::releaseProxy(const Renderbuffer *proxy)
89{
90 mRenderbufferProxies.release(proxy);
91}
92
Geoff Lang63b5f1f2013-09-23 14:52:14 -040093void Texture::setMinFilter(GLenum filter)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000094{
Geoff Lang63b5f1f2013-09-23 14:52:14 -040095 mSamplerState.minFilter = filter;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000096}
97
Geoff Lang63b5f1f2013-09-23 14:52:14 -040098void Texture::setMagFilter(GLenum filter)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000099{
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400100 mSamplerState.magFilter = filter;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000101}
102
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400103void Texture::setWrapS(GLenum wrap)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000104{
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400105 mSamplerState.wrapS = wrap;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000106}
107
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400108void Texture::setWrapT(GLenum wrap)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000109{
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400110 mSamplerState.wrapT = wrap;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000111}
112
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400113void Texture::setWrapR(GLenum wrap)
shannon.woods%transgaming.com@gtempaccount.com0b3a8df2013-04-13 03:44:51 +0000114{
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400115 mSamplerState.wrapR = wrap;
shannon.woods%transgaming.com@gtempaccount.com0b3a8df2013-04-13 03:44:51 +0000116}
117
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400118void Texture::setMaxAnisotropy(float textureMaxAnisotropy, float contextMaxAnisotropy)
daniel@transgaming.com07ab8412012-07-12 15:17:09 +0000119{
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400120 mSamplerState.maxAnisotropy = std::min(textureMaxAnisotropy, contextMaxAnisotropy);
daniel@transgaming.com07ab8412012-07-12 15:17:09 +0000121}
122
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400123void Texture::setCompareMode(GLenum mode)
Geoff Langc82fc412013-07-10 14:43:42 -0400124{
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400125 mSamplerState.compareMode = mode;
Geoff Langc82fc412013-07-10 14:43:42 -0400126}
127
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400128void Texture::setCompareFunc(GLenum func)
Geoff Langc82fc412013-07-10 14:43:42 -0400129{
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400130 mSamplerState.compareFunc = func;
Geoff Langc82fc412013-07-10 14:43:42 -0400131}
132
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400133void Texture::setUsage(GLenum usage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000134{
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400135 mUsage = usage;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000136}
137
138GLenum Texture::getMinFilter() const
139{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000140 return mSamplerState.minFilter;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000141}
142
143GLenum Texture::getMagFilter() const
144{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000145 return mSamplerState.magFilter;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000146}
147
148GLenum Texture::getWrapS() const
149{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000150 return mSamplerState.wrapS;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000151}
152
153GLenum Texture::getWrapT() const
154{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000155 return mSamplerState.wrapT;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000156}
157
shannon.woods%transgaming.com@gtempaccount.com0b3a8df2013-04-13 03:44:51 +0000158GLenum Texture::getWrapR() const
159{
160 return mSamplerState.wrapR;
161}
162
daniel@transgaming.com07ab8412012-07-12 15:17:09 +0000163float Texture::getMaxAnisotropy() const
164{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000165 return mSamplerState.maxAnisotropy;
166}
167
168int Texture::getLodOffset()
169{
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000170 rx::TextureStorageInterface *texture = getStorage(false);
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000171 return texture ? texture->getLodOffset() : 0;
172}
173
174void Texture::getSamplerState(SamplerState *sampler)
175{
176 *sampler = mSamplerState;
177 sampler->lodOffset = getLodOffset();
daniel@transgaming.com07ab8412012-07-12 15:17:09 +0000178}
179
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000180GLenum Texture::getUsage() const
181{
182 return mUsage;
183}
184
Jamie Madilld3d2a342013-10-07 10:46:35 -0400185GLint Texture::getBaseLevelWidth() const
186{
187 const rx::Image *baseImage = getBaseLevelImage();
188 return (baseImage ? baseImage->getWidth() : 0);
189}
190
191GLint Texture::getBaseLevelHeight() const
192{
193 const rx::Image *baseImage = getBaseLevelImage();
194 return (baseImage ? baseImage->getHeight() : 0);
195}
196
197GLint Texture::getBaseLevelDepth() const
198{
199 const rx::Image *baseImage = getBaseLevelImage();
200 return (baseImage ? baseImage->getDepth() : 0);
201}
202
203GLenum Texture::getBaseLevelInternalFormat() const
204{
205 const rx::Image *baseImage = getBaseLevelImage();
206 return (baseImage ? baseImage->getInternalFormat() : GL_NONE);
207}
208
Jamie Madill88f18f42013-09-18 14:36:19 -0400209void Texture::setImage(const PixelUnpackState &unpack, GLenum type, const void *pixels, rx::Image *image)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000210{
Jamie Madillabef6802013-09-05 16:54:19 -0400211 // We no longer need the "GLenum format" parameter to TexImage to determine what data format "pixels" contains.
212 // 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 -0400213 const void *pixelData = pixels;
214
215 if (unpack.pixelBuffer.id() != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000216 {
Jamie Madill1beb1db2013-09-18 14:36:28 -0400217 // Do a CPU readback here, if we have an unpack buffer bound and the fast GPU path is not supported
218 Buffer *pixelBuffer = unpack.pixelBuffer.get();
219 ptrdiff_t offset = reinterpret_cast<ptrdiff_t>(pixels);
220 const void *bufferData = pixelBuffer->getStorage()->getData();
221 pixelData = static_cast<const unsigned char *>(bufferData) + offset;
222 }
223
224 if (pixelData != NULL)
225 {
226 image->loadData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), unpack.alignment, type, pixelData);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000227 mDirtyImages = true;
228 }
229}
230
Geoff Lang005df412013-10-16 14:12:50 -0400231bool Texture::isFastUnpackable(const PixelUnpackState &unpack, GLenum sizedInternalFormat)
Jamie Madill8cc7d972013-10-10 15:51:55 -0400232{
233 return unpack.pixelBuffer.id() != 0 && mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat);
234}
235
Jamie Madill1beb1db2013-09-18 14:36:28 -0400236bool Texture::fastUnpackPixels(const PixelUnpackState &unpack, const void *pixels, const Box &destArea,
Jamie Madill8cc7d972013-10-10 15:51:55 -0400237 GLenum sizedInternalFormat, GLenum type, rx::RenderTarget *destRenderTarget)
Jamie Madill1beb1db2013-09-18 14:36:28 -0400238{
239 if (destArea.width <= 0 && destArea.height <= 0 && destArea.depth <= 0)
240 {
241 return true;
242 }
243
244 // In order to perform the fast copy through the shader, we must have the right format, and be able
245 // to create a render target.
Jamie Madill8cc7d972013-10-10 15:51:55 -0400246 ASSERT(mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat));
Jamie Madill1beb1db2013-09-18 14:36:28 -0400247
Jamie Madill8cc7d972013-10-10 15:51:55 -0400248 unsigned int offset = reinterpret_cast<unsigned int>(pixels);
Jamie Madill1beb1db2013-09-18 14:36:28 -0400249
Jamie Madill8cc7d972013-10-10 15:51:55 -0400250 return mRenderer->fastCopyBufferToTexture(unpack, offset, destRenderTarget, sizedInternalFormat, type, destArea);
Jamie Madill1beb1db2013-09-18 14:36:28 -0400251}
252
daniel@transgaming.com31b13e12012-11-28 19:34:30 +0000253void Texture::setCompressedImage(GLsizei imageSize, const void *pixels, rx::Image *image)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000254{
255 if (pixels != NULL)
256 {
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000257 image->loadCompressedData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000258 mDirtyImages = true;
259 }
260}
261
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000262bool Texture::subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
Jamie Madill88f18f42013-09-18 14:36:19 -0400263 GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels, rx::Image *image)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000264{
Jamie Madill065e1a32013-10-10 15:11:50 -0400265 const void *pixelData = pixels;
266
267 // CPU readback & copy where direct GPU copy is not supported
268 if (unpack.pixelBuffer.id() != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000269 {
Jamie Madill065e1a32013-10-10 15:11:50 -0400270 Buffer *pixelBuffer = unpack.pixelBuffer.get();
271 unsigned int offset = reinterpret_cast<unsigned int>(pixels);
272 const void *bufferData = pixelBuffer->getStorage()->getData();
273 pixelData = static_cast<const unsigned char *>(bufferData) + offset;
274 }
275
276 if (pixelData != NULL)
277 {
278 image->loadData(xoffset, yoffset, zoffset, width, height, depth, unpack.alignment, type, pixelData);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000279 mDirtyImages = true;
280 }
281
282 return true;
283}
284
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000285bool Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
286 GLenum format, GLsizei imageSize, const void *pixels, rx::Image *image)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000287{
288 if (pixels != NULL)
289 {
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000290 image->loadCompressedData(xoffset, yoffset, zoffset, width, height, depth, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000291 mDirtyImages = true;
292 }
293
294 return true;
295}
296
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000297rx::TextureStorageInterface *Texture::getNativeTexture()
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000298{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000299 // ensure the underlying texture is created
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000300
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000301 rx::TextureStorageInterface *storage = getStorage(false);
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000302 if (storage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000303 {
Jamie Madill169d1112013-10-24 17:49:37 -0400304 updateStorage();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000305 }
306
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000307 return storage;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000308}
309
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000310bool Texture::hasDirtyImages() const
311{
312 return mDirtyImages;
313}
314
315void Texture::resetDirty()
316{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000317 mDirtyImages = false;
318}
319
320unsigned int Texture::getTextureSerial()
321{
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000322 rx::TextureStorageInterface *texture = getStorage(false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000323 return texture ? texture->getTextureSerial() : 0;
324}
325
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000326bool Texture::isImmutable() const
327{
328 return mImmutable;
329}
330
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +0000331GLint Texture::creationLevels(GLsizei width, GLsizei height, GLsizei depth) const
332{
333 // NPOT checks are not required in ES 3.0, NPOT texture support is assumed.
334 return 0; // Maximum number of levels
335}
336
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000337GLint Texture::creationLevels(GLsizei width, GLsizei height) const
338{
daniel@transgaming.comea32d482012-11-28 19:33:18 +0000339 if ((isPow2(width) && isPow2(height)) || mRenderer->getNonPower2TextureSupport())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000340 {
341 return 0; // Maximum number of levels
342 }
343 else
344 {
345 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
346 return 1;
347 }
348}
349
350GLint Texture::creationLevels(GLsizei size) const
351{
352 return creationLevels(size, size);
353}
354
Jamie Madill22f843a2013-10-24 17:49:36 -0400355int Texture::mipLevels() const
356{
357 return log2(std::max(std::max(getBaseLevelWidth(), getBaseLevelHeight()), getBaseLevelDepth()));
358}
359
Geoff Lang4907f2c2013-07-25 12:53:57 -0400360Texture2D::Texture2D(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_2D)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000361{
362 mTexStorage = NULL;
363 mSurface = NULL;
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000364
365 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
366 {
daniel@transgaming.com244e1832012-12-20 20:52:35 +0000367 mImageArray[i] = renderer->createImage();
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000368 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000369}
370
371Texture2D::~Texture2D()
372{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000373 delete mTexStorage;
374 mTexStorage = NULL;
375
376 if (mSurface)
377 {
378 mSurface->setBoundTexture(NULL);
379 mSurface = NULL;
380 }
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000381
382 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
383 {
384 delete mImageArray[i];
385 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000386}
387
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000388GLsizei Texture2D::getWidth(GLint level) const
389{
390 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000391 return mImageArray[level]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000392 else
393 return 0;
394}
395
396GLsizei Texture2D::getHeight(GLint level) const
397{
398 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000399 return mImageArray[level]->getHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000400 else
401 return 0;
402}
403
404GLenum Texture2D::getInternalFormat(GLint level) const
405{
406 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000407 return mImageArray[level]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000408 else
409 return GL_NONE;
410}
411
daniel@transgaming.com20d36662012-10-31 19:51:43 +0000412GLenum Texture2D::getActualFormat(GLint level) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000413{
414 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000415 return mImageArray[level]->getActualFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000416 else
417 return D3DFMT_UNKNOWN;
418}
419
Geoff Lang005df412013-10-16 14:12:50 -0400420void Texture2D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000421{
422 releaseTexImage();
shannon.woods@transgaming.com8a406682013-02-28 23:15:26 +0000423
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000424 // If there currently is a corresponding storage texture image, it has these parameters
Jamie Madilld3d2a342013-10-07 10:46:35 -0400425 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
426 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
Geoff Lang005df412013-10-16 14:12:50 -0400427 const GLenum storageFormat = getBaseLevelInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000428
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000429 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, width, height, 1, false);
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000430
431 if (mTexStorage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000432 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000433 const int storageLevels = mTexStorage->levelCount();
434
435 if ((level >= storageLevels && storageLevels != 0) ||
436 width != storageWidth ||
437 height != storageHeight ||
438 internalformat != storageFormat) // Discard mismatched storage
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000439 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000440 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
441 {
442 mImageArray[i]->markDirty();
443 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000444
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000445 delete mTexStorage;
446 mTexStorage = NULL;
447 mDirtyImages = true;
448 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000449 }
450}
451
Geoff Lang005df412013-10-16 14:12:50 -0400452void Texture2D::setImage(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000453{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +0000454 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Geoff Lang005df412013-10-16 14:12:50 -0400455 GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
456 : GetSizedInternalFormat(format, type, clientVersion);
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +0000457 redefineImage(level, sizedInternalFormat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000458
Jamie Madill8cc7d972013-10-10 15:51:55 -0400459 bool fastUnpacked = false;
460
Jamie Madill1beb1db2013-09-18 14:36:28 -0400461 // Attempt a fast gpu copy of the pixel data to the surface
Jamie Madill8cc7d972013-10-10 15:51:55 -0400462 if (isFastUnpackable(unpack, sizedInternalFormat) && isLevelComplete(level))
Jamie Madill1beb1db2013-09-18 14:36:28 -0400463 {
Jamie Madill8cc7d972013-10-10 15:51:55 -0400464 // Will try to create RT storage if it does not exist
465 rx::RenderTarget *destRenderTarget = getRenderTarget(level);
466 Box destArea(0, 0, 0, getWidth(level), getHeight(level), 1);
467
468 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget))
469 {
470 // Ensure we don't overwrite our newly initialized data
471 mImageArray[level]->markClean();
472
473 fastUnpacked = true;
474 }
Jamie Madill1beb1db2013-09-18 14:36:28 -0400475 }
Jamie Madill8cc7d972013-10-10 15:51:55 -0400476
477 if (!fastUnpacked)
Jamie Madill1beb1db2013-09-18 14:36:28 -0400478 {
479 Texture::setImage(unpack, type, pixels, mImageArray[level]);
480 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000481}
482
483void Texture2D::bindTexImage(egl::Surface *surface)
484{
485 releaseTexImage();
486
Geoff Lang005df412013-10-16 14:12:50 -0400487 GLenum internalformat = surface->getFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000488
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000489 mImageArray[0]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, surface->getWidth(), surface->getHeight(), 1, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000490
491 delete mTexStorage;
daniel@transgaming.comd8353dd2012-12-20 21:11:14 +0000492 mTexStorage = new rx::TextureStorageInterface2D(mRenderer, surface->getSwapChain());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000493
494 mDirtyImages = true;
495 mSurface = surface;
496 mSurface->setBoundTexture(this);
497}
498
499void Texture2D::releaseTexImage()
500{
501 if (mSurface)
502 {
503 mSurface->setBoundTexture(NULL);
504 mSurface = NULL;
505
506 if (mTexStorage)
507 {
508 delete mTexStorage;
509 mTexStorage = NULL;
510 }
511
512 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
513 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000514 mImageArray[i]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000515 }
516 }
517}
518
519void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
520{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000521 // 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 +0000522 redefineImage(level, format, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000523
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000524 Texture::setCompressedImage(imageSize, pixels, mImageArray[level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000525}
526
527void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
528{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000529 if (level < levelCount())
530 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000531 rx::Image *image = mImageArray[level];
Jamie Madill169d1112013-10-24 17:49:37 -0400532 if (image->copyToStorage(mTexStorage, level, xoffset, yoffset, width, height))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000533 {
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000534 image->markClean();
535 }
536 }
537}
538
Jamie Madill88f18f42013-09-18 14:36:19 -0400539void 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 +0000540{
Jamie Madill065e1a32013-10-10 15:11:50 -0400541 bool fastUnpacked = false;
542
543 if (isFastUnpackable(unpack, getInternalFormat(level)) && isLevelComplete(level))
544 {
545 rx::RenderTarget *renderTarget = getRenderTarget(level);
546 Box destArea(xoffset, yoffset, 0, width, height, 1);
547
548 if (renderTarget && fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, renderTarget))
549 {
550 // Ensure we don't overwrite our newly initialized data
551 mImageArray[level]->markClean();
552
553 fastUnpacked = true;
554 }
555 }
556
557 if (!fastUnpacked && Texture::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, mImageArray[level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000558 {
559 commitRect(level, xoffset, yoffset, width, height);
560 }
561}
562
563void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
564{
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000565 if (Texture::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000566 {
567 commitRect(level, xoffset, yoffset, width, height);
568 }
569}
570
571void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
572{
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +0000573 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Geoff Lang005df412013-10-16 14:12:50 -0400574 GLenum sizedInternalFormat = IsSizedInternalFormat(format, clientVersion) ? format
575 : GetSizedInternalFormat(format, GL_UNSIGNED_BYTE, clientVersion);
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +0000576 redefineImage(level, sizedInternalFormat, width, height);
shannon.woods@transgaming.com8a406682013-02-28 23:15:26 +0000577
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000578 if (!mImageArray[level]->isRenderableFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000579 {
shannon.woods%transgaming.com@gtempaccount.come5dcce72013-04-13 03:44:33 +0000580 mImageArray[level]->copy(0, 0, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000581 mDirtyImages = true;
582 }
583 else
584 {
Jamie Madille83d1a92013-10-24 17:49:33 -0400585 ensureRenderTarget();
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000586 mImageArray[level]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000587
588 if (width != 0 && height != 0 && level < levelCount())
589 {
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +0000590 gl::Rectangle sourceRect;
591 sourceRect.x = x;
592 sourceRect.width = width;
593 sourceRect.y = y;
594 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000595
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +0000596 mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000597 }
598 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000599}
600
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +0000601void 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 +0000602{
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +0000603 if (xoffset + width > mImageArray[level]->getWidth() || yoffset + height > mImageArray[level]->getHeight() || zoffset != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000604 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +0000605 return gl::error(GL_INVALID_VALUE);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000606 }
607
Jamie Madill07edd442013-07-19 16:36:58 -0400608 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
609 // the current level we're copying to is defined (with appropriate format, width & height)
610 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
611
612 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000613 {
shannon.woods%transgaming.com@gtempaccount.come5dcce72013-04-13 03:44:33 +0000614 mImageArray[level]->copy(xoffset, yoffset, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000615 mDirtyImages = true;
616 }
617 else
618 {
Jamie Madille83d1a92013-10-24 17:49:33 -0400619 ensureRenderTarget();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000620
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000621 if (level < levelCount())
622 {
Jamie Madill169d1112013-10-24 17:49:37 -0400623 updateStorageLevel(level);
Jamie Madill07edd442013-07-19 16:36:58 -0400624
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +0000625 GLuint clientVersion = mRenderer->getCurrentClientVersion();
626
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +0000627 gl::Rectangle sourceRect;
628 sourceRect.x = x;
629 sourceRect.width = width;
630 sourceRect.y = y;
631 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000632
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +0000633 mRenderer->copyImage(source, sourceRect,
Jamie Madilld3d2a342013-10-07 10:46:35 -0400634 gl::GetFormat(getBaseLevelInternalFormat(), clientVersion),
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +0000635 xoffset, yoffset, mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000636 }
637 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000638}
639
640void Texture2D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height)
641{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000642 for (int level = 0; level < levels; level++)
643 {
Jamie Madill73b5d062013-10-24 17:49:38 -0400644 GLsizei levelWidth = std::max(1, width >> level);
645 GLsizei levelHeight = std::max(1, height >> level);
646 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, levelWidth, levelHeight, 1, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000647 }
648
649 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
650 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000651 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000652 }
653
Jamie Madill73b5d062013-10-24 17:49:38 -0400654 mImmutable = true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000655
Jamie Madill73b5d062013-10-24 17:49:38 -0400656 setCompleteTexStorage(new rx::TextureStorageInterface2D(mRenderer, levels, internalformat, IsRenderTargetUsage(mUsage), width, height));
657}
658
659void Texture2D::setCompleteTexStorage(rx::TextureStorageInterface2D *newCompleteTexStorage)
660{
661 SafeDelete(mTexStorage);
662 mTexStorage = newCompleteTexStorage;
663
664 if (mTexStorage && mTexStorage->isManaged())
665 {
666 for (int level = 0; level < mTexStorage->levelCount(); level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000667 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000668 mImageArray[level]->setManagedSurface(mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000669 }
670 }
Jamie Madill73b5d062013-10-24 17:49:38 -0400671
672 mDirtyImages = true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000673}
674
675// Tests for 2D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85.
Jamie Madillf8989902013-07-19 16:36:58 -0400676bool Texture2D::isSamplerComplete(const SamplerState &samplerState) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000677{
Jamie Madilld3d2a342013-10-07 10:46:35 -0400678 GLsizei width = getBaseLevelWidth();
679 GLsizei height = getBaseLevelHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000680
681 if (width <= 0 || height <= 0)
682 {
683 return false;
684 }
685
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000686 if (!IsTextureFilteringSupported(getInternalFormat(0), mRenderer))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000687 {
Jamie Madillf8989902013-07-19 16:36:58 -0400688 if (samplerState.magFilter != GL_NEAREST ||
689 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000690 {
691 return false;
692 }
693 }
694
daniel@transgaming.comea32d482012-11-28 19:33:18 +0000695 bool npotSupport = mRenderer->getNonPower2TextureSupport();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000696
697 if (!npotSupport)
698 {
Jamie Madillf8989902013-07-19 16:36:58 -0400699 if ((samplerState.wrapS != GL_CLAMP_TO_EDGE && !isPow2(width)) ||
700 (samplerState.wrapT != GL_CLAMP_TO_EDGE && !isPow2(height)))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000701 {
702 return false;
703 }
704 }
705
Jamie Madillf8989902013-07-19 16:36:58 -0400706 if (IsMipmapFiltered(samplerState))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000707 {
708 if (!npotSupport)
709 {
710 if (!isPow2(width) || !isPow2(height))
711 {
712 return false;
713 }
714 }
715
716 if (!isMipmapComplete())
717 {
718 return false;
719 }
720 }
721
Geoff Langc82fc412013-07-10 14:43:42 -0400722 // OpenGLES 3.0.2 spec section 3.8.13 states that a texture is not mipmap complete if:
723 // The internalformat specified for the texture arrays is a sized internal depth or
724 // depth and stencil format (see table 3.13), the value of TEXTURE_COMPARE_-
725 // MODE is NONE, and either the magnification filter is not NEAREST or the mini-
726 // fication filter is neither NEAREST nor NEAREST_MIPMAP_NEAREST.
727 if (gl::GetDepthBits(getInternalFormat(0), mRenderer->getCurrentClientVersion()) > 0)
728 {
729 if (mSamplerState.compareMode == GL_NONE)
730 {
731 if ((mSamplerState.minFilter != GL_NEAREST && mSamplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST) ||
732 mSamplerState.magFilter != GL_NEAREST)
733 {
734 return false;
735 }
736 }
737 }
738
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000739 return true;
740}
741
742// Tests for 2D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
743bool Texture2D::isMipmapComplete() const
744{
Jamie Madill22f843a2013-10-24 17:49:36 -0400745 int q = mipLevels();
Jamie Madill07edd442013-07-19 16:36:58 -0400746
747 for (int level = 0; level <= q; level++)
748 {
749 if (!isLevelComplete(level))
750 {
751 return false;
752 }
753 }
754
755 return true;
756}
757
758bool Texture2D::isLevelComplete(int level) const
759{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000760 if (isImmutable())
761 {
762 return true;
763 }
764
Jamie Madilld3d2a342013-10-07 10:46:35 -0400765 GLsizei width = getBaseLevelWidth();
766 GLsizei height = getBaseLevelHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000767
768 if (width <= 0 || height <= 0)
769 {
770 return false;
771 }
772
Jamie Madill07edd442013-07-19 16:36:58 -0400773 // The base image level is complete if the width and height are positive
774 if (level == 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000775 {
Jamie Madill07edd442013-07-19 16:36:58 -0400776 return true;
777 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000778
Jamie Madill07edd442013-07-19 16:36:58 -0400779 ASSERT(level >= 1 && level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
780 rx::Image *image = mImageArray[level];
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000781
Jamie Madilld3d2a342013-10-07 10:46:35 -0400782 if (image->getInternalFormat() != getBaseLevelInternalFormat())
Jamie Madill07edd442013-07-19 16:36:58 -0400783 {
784 return false;
785 }
786
787 if (image->getWidth() != std::max(1, width >> level))
788 {
789 return false;
790 }
791
792 if (image->getHeight() != std::max(1, height >> level))
793 {
794 return false;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000795 }
796
797 return true;
798}
799
800bool Texture2D::isCompressed(GLint level) const
801{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000802 return IsFormatCompressed(getInternalFormat(level), mRenderer->getCurrentClientVersion());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000803}
804
805bool Texture2D::isDepth(GLint level) const
806{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000807 return GetDepthBits(getInternalFormat(level), mRenderer->getCurrentClientVersion()) > 0;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000808}
809
daniel@transgaming.comf032cb82012-10-31 19:51:52 +0000810// Constructs a native texture resource from the texture images
Jamie Madill73b5d062013-10-24 17:49:38 -0400811void Texture2D::initializeStorage(bool renderTarget)
812{
813 // Only initialize the first time this texture is used as a render target or shader resource
814 if (mTexStorage)
815 {
816 return;
817 }
818
819 // do not attempt to create storage for nonexistant data
820 if (!isLevelComplete(0))
821 {
822 return;
823 }
824
825 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
826
827 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
828 ASSERT(mTexStorage);
829
830 // flush image data to the storage
831 updateStorage();
832}
833
834rx::TextureStorageInterface2D *Texture2D::createCompleteStorage(bool renderTarget) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000835{
Jamie Madilld3d2a342013-10-07 10:46:35 -0400836 GLsizei width = getBaseLevelWidth();
837 GLsizei height = getBaseLevelHeight();
daniel@transgaming.come6a09842012-09-17 21:28:55 +0000838
Jamie Madill73b5d062013-10-24 17:49:38 -0400839 ASSERT(width > 0 && height > 0);
daniel@transgaming.come6a09842012-09-17 21:28:55 +0000840
Jamie Madill73b5d062013-10-24 17:49:38 -0400841 // use existing storage level count, when previously specified by TexStorage*D
842 GLint levels = (mTexStorage ? mTexStorage->levelCount() : creationLevels(width, height));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000843
Jamie Madill73b5d062013-10-24 17:49:38 -0400844 return new rx::TextureStorageInterface2D(mRenderer, levels, getBaseLevelInternalFormat(), renderTarget, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000845}
846
Jamie Madill169d1112013-10-24 17:49:37 -0400847void Texture2D::updateStorage()
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000848{
Jamie Madilld9b9a502013-10-10 17:46:13 -0400849 int storageLevels = levelCount();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000850
Jamie Madilld9b9a502013-10-10 17:46:13 -0400851 for (int level = 0; level < storageLevels; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000852 {
Jamie Madilld9b9a502013-10-10 17:46:13 -0400853 if (isLevelComplete(level))
854 {
Jamie Madill169d1112013-10-24 17:49:37 -0400855 updateStorageLevel(level);
Jamie Madilld9b9a502013-10-10 17:46:13 -0400856 }
Jamie Madill07edd442013-07-19 16:36:58 -0400857 }
858}
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000859
Jamie Madill169d1112013-10-24 17:49:37 -0400860void Texture2D::updateStorageLevel(int level)
Jamie Madill07edd442013-07-19 16:36:58 -0400861{
862 ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
Jamie Madillaee7ad82013-10-10 16:07:32 -0400863 ASSERT(isLevelComplete(level));
Jamie Madill07edd442013-07-19 16:36:58 -0400864
Jamie Madillaee7ad82013-10-10 16:07:32 -0400865 if (mImageArray[level]->isDirty())
Jamie Madill07edd442013-07-19 16:36:58 -0400866 {
Jamie Madillaee7ad82013-10-10 16:07:32 -0400867 commitRect(level, 0, 0, getWidth(level), getHeight(level));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000868 }
869}
870
Jamie Madille83d1a92013-10-24 17:49:33 -0400871bool Texture2D::ensureRenderTarget()
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000872{
Jamie Madill73b5d062013-10-24 17:49:38 -0400873 initializeStorage(true);
874
875 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0)
Jamie Madille83d1a92013-10-24 17:49:33 -0400876 {
Jamie Madill73b5d062013-10-24 17:49:38 -0400877 ASSERT(mTexStorage);
878 if (!mTexStorage->isRenderTarget())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000879 {
Jamie Madill73b5d062013-10-24 17:49:38 -0400880 rx::TextureStorageInterface2D *newRenderTargetStorage = createCompleteStorage(true);
881
882 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
883 {
884 delete newRenderTargetStorage;
Jamie Madille83d1a92013-10-24 17:49:33 -0400885 return gl::error(GL_OUT_OF_MEMORY, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000886 }
Jamie Madill73b5d062013-10-24 17:49:38 -0400887
888 setCompleteTexStorage(newRenderTargetStorage);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000889 }
890 }
891
Jamie Madille83d1a92013-10-24 17:49:33 -0400892 return (mTexStorage && mTexStorage->isRenderTarget());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000893}
894
895void Texture2D::generateMipmaps()
896{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000897 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Jamie Madill22f843a2013-10-24 17:49:36 -0400898 int q = mipLevels();
899 for (int level = 1; level <= q; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000900 {
Jamie Madill22f843a2013-10-24 17:49:36 -0400901 redefineImage(level, getBaseLevelInternalFormat(),
902 std::max(getBaseLevelWidth() >> level, 1),
903 std::max(getBaseLevelHeight() >> level, 1));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000904 }
905
906 if (mTexStorage && mTexStorage->isRenderTarget())
907 {
Jamie Madill22f843a2013-10-24 17:49:36 -0400908 for (int level = 1; level <= q; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000909 {
Jamie Madill22f843a2013-10-24 17:49:36 -0400910 mTexStorage->generateMipmap(level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000911
Jamie Madill22f843a2013-10-24 17:49:36 -0400912 mImageArray[level]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000913 }
914 }
915 else
916 {
Jamie Madill22f843a2013-10-24 17:49:36 -0400917 for (int level = 1; level <= q; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000918 {
Jamie Madill22f843a2013-10-24 17:49:36 -0400919 mRenderer->generateMipmap(mImageArray[level], mImageArray[level - 1]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000920 }
921 }
922}
923
Jamie Madilld3d2a342013-10-07 10:46:35 -0400924const rx::Image *Texture2D::getBaseLevelImage() const
925{
926 return mImageArray[0];
927}
928
Geoff Lang8040f572013-07-25 16:49:54 -0400929Renderbuffer *Texture2D::getRenderbuffer(GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000930{
Geoff Lang8040f572013-07-25 16:49:54 -0400931 Renderbuffer *renderBuffer = mRenderbufferProxies.get(level, 0);
932 if (!renderBuffer)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000933 {
Geoff Lang8040f572013-07-25 16:49:54 -0400934 renderBuffer = new Renderbuffer(mRenderer, id(), new RenderbufferTexture2D(this, level));
935 mRenderbufferProxies.add(level, 0, renderBuffer);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000936 }
937
Geoff Lang8040f572013-07-25 16:49:54 -0400938 return renderBuffer;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000939}
940
Geoff Lang8040f572013-07-25 16:49:54 -0400941unsigned int Texture2D::getRenderTargetSerial(GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000942{
Jamie Madille83d1a92013-10-24 17:49:33 -0400943 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(level) : 0);
Geoff Lang8040f572013-07-25 16:49:54 -0400944}
945
946rx::RenderTarget *Texture2D::getRenderTarget(GLint level)
947{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000948 // ensure the underlying texture is created
949 if (getStorage(true) == NULL)
950 {
951 return NULL;
952 }
953
Jamie Madill169d1112013-10-24 17:49:37 -0400954 updateStorageLevel(level);
Geoff Lang8040f572013-07-25 16:49:54 -0400955
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000956 // ensure this is NOT a depth texture
Geoff Lang8040f572013-07-25 16:49:54 -0400957 if (isDepth(level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000958 {
959 return NULL;
960 }
daniel@transgaming.com34da3972012-12-20 21:10:29 +0000961
Geoff Lang8040f572013-07-25 16:49:54 -0400962 return mTexStorage->getRenderTarget(level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000963}
964
Geoff Lang8040f572013-07-25 16:49:54 -0400965rx::RenderTarget *Texture2D::getDepthSencil(GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000966{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000967 // ensure the underlying texture is created
968 if (getStorage(true) == NULL)
969 {
970 return NULL;
971 }
972
Jamie Madill169d1112013-10-24 17:49:37 -0400973 updateStorageLevel(level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000974
975 // ensure this is actually a depth texture
Geoff Lang8040f572013-07-25 16:49:54 -0400976 if (!isDepth(level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000977 {
978 return NULL;
979 }
Geoff Lang8040f572013-07-25 16:49:54 -0400980
981 return mTexStorage->getRenderTarget(level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000982}
983
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +0000984int Texture2D::levelCount()
985{
shannon.woods@transgaming.com5016f8e2013-02-28 23:20:57 +0000986 return mTexStorage ? mTexStorage->levelCount() : 0;
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +0000987}
988
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000989rx::TextureStorageInterface *Texture2D::getStorage(bool renderTarget)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000990{
991 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
992 {
993 if (renderTarget)
994 {
Jamie Madille83d1a92013-10-24 17:49:33 -0400995 ensureRenderTarget();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000996 }
997 else
998 {
Jamie Madill73b5d062013-10-24 17:49:38 -0400999 initializeStorage(false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001000 }
1001 }
1002
1003 return mTexStorage;
1004}
1005
Geoff Lang4907f2c2013-07-25 12:53:57 -04001006TextureCubeMap::TextureCubeMap(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_CUBE_MAP)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001007{
1008 mTexStorage = NULL;
1009 for (int i = 0; i < 6; i++)
1010 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001011 for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
1012 {
daniel@transgaming.com244e1832012-12-20 20:52:35 +00001013 mImageArray[i][j] = renderer->createImage();
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001014 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001015 }
1016}
1017
1018TextureCubeMap::~TextureCubeMap()
1019{
1020 for (int i = 0; i < 6; i++)
1021 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001022 for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
1023 {
1024 delete mImageArray[i][j];
1025 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001026 }
1027
1028 delete mTexStorage;
1029 mTexStorage = NULL;
1030}
1031
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001032GLsizei TextureCubeMap::getWidth(GLenum target, GLint level) const
1033{
1034 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Jamie Madill2db197c2013-10-24 17:49:35 -04001035 return mImageArray[targetToIndex(target)][level]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001036 else
1037 return 0;
1038}
1039
1040GLsizei TextureCubeMap::getHeight(GLenum target, GLint level) const
1041{
1042 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Jamie Madill2db197c2013-10-24 17:49:35 -04001043 return mImageArray[targetToIndex(target)][level]->getHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001044 else
1045 return 0;
1046}
1047
1048GLenum TextureCubeMap::getInternalFormat(GLenum target, GLint level) const
1049{
1050 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Jamie Madill2db197c2013-10-24 17:49:35 -04001051 return mImageArray[targetToIndex(target)][level]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001052 else
1053 return GL_NONE;
1054}
1055
daniel@transgaming.com20d36662012-10-31 19:51:43 +00001056GLenum TextureCubeMap::getActualFormat(GLenum target, GLint level) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001057{
1058 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Jamie Madill2db197c2013-10-24 17:49:35 -04001059 return mImageArray[targetToIndex(target)][level]->getActualFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001060 else
1061 return D3DFMT_UNKNOWN;
1062}
1063
Geoff Lang005df412013-10-16 14:12:50 -04001064void TextureCubeMap::setImagePosX(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001065{
Jamie Madill88f18f42013-09-18 14:36:19 -04001066 setImage(0, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001067}
1068
Geoff Lang005df412013-10-16 14:12:50 -04001069void TextureCubeMap::setImageNegX(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001070{
Jamie Madill88f18f42013-09-18 14:36:19 -04001071 setImage(1, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001072}
1073
Geoff Lang005df412013-10-16 14:12:50 -04001074void TextureCubeMap::setImagePosY(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001075{
Jamie Madill88f18f42013-09-18 14:36:19 -04001076 setImage(2, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001077}
1078
Geoff Lang005df412013-10-16 14:12:50 -04001079void TextureCubeMap::setImageNegY(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001080{
Jamie Madill88f18f42013-09-18 14:36:19 -04001081 setImage(3, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001082}
1083
Geoff Lang005df412013-10-16 14:12:50 -04001084void TextureCubeMap::setImagePosZ(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001085{
Jamie Madill88f18f42013-09-18 14:36:19 -04001086 setImage(4, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001087}
1088
Geoff Lang005df412013-10-16 14:12:50 -04001089void TextureCubeMap::setImageNegZ(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001090{
Jamie Madill88f18f42013-09-18 14:36:19 -04001091 setImage(5, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001092}
1093
Jamie Madill2db197c2013-10-24 17:49:35 -04001094void TextureCubeMap::setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001095{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001096 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
Jamie Madill2db197c2013-10-24 17:49:35 -04001097 int faceIndex = targetToIndex(target);
1098 redefineImage(faceIndex, level, format, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001099
Jamie Madill2db197c2013-10-24 17:49:35 -04001100 Texture::setCompressedImage(imageSize, pixels, mImageArray[faceIndex][level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001101}
1102
Jamie Madill2db197c2013-10-24 17:49:35 -04001103void TextureCubeMap::commitRect(int faceIndex, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001104{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001105 if (level < levelCount())
1106 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001107 rx::Image *image = mImageArray[faceIndex][level];
Jamie Madill169d1112013-10-24 17:49:37 -04001108 if (image->copyToStorage(mTexStorage, faceIndex, level, xoffset, yoffset, width, height))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001109 image->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001110 }
1111}
1112
Jamie Madill88f18f42013-09-18 14:36:19 -04001113void 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 +00001114{
Jamie Madill2db197c2013-10-24 17:49:35 -04001115 int faceIndex = targetToIndex(target);
1116 if (Texture::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, mImageArray[faceIndex][level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001117 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001118 commitRect(faceIndex, level, xoffset, yoffset, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001119 }
1120}
1121
1122void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1123{
Jamie Madill2db197c2013-10-24 17:49:35 -04001124 int faceIndex = targetToIndex(target);
1125 if (Texture::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[faceIndex][level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001126 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001127 commitRect(faceIndex, level, xoffset, yoffset, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001128 }
1129}
1130
1131// Tests for cube map sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 86.
Jamie Madillf8989902013-07-19 16:36:58 -04001132bool TextureCubeMap::isSamplerComplete(const SamplerState &samplerState) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001133{
Jamie Madilld3d2a342013-10-07 10:46:35 -04001134 int size = getBaseLevelWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001135
Jamie Madillf8989902013-07-19 16:36:58 -04001136 bool mipmapping = IsMipmapFiltered(samplerState);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001137
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001138 if (!IsTextureFilteringSupported(getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0), mRenderer))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001139 {
Jamie Madillf8989902013-07-19 16:36:58 -04001140 if (samplerState.magFilter != GL_NEAREST ||
1141 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001142 {
1143 return false;
1144 }
1145 }
1146
daniel@transgaming.comea32d482012-11-28 19:33:18 +00001147 if (!isPow2(size) && !mRenderer->getNonPower2TextureSupport())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001148 {
Jamie Madillf8989902013-07-19 16:36:58 -04001149 if (samplerState.wrapS != GL_CLAMP_TO_EDGE || samplerState.wrapT != GL_CLAMP_TO_EDGE || mipmapping)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001150 {
1151 return false;
1152 }
1153 }
1154
1155 if (!mipmapping)
1156 {
1157 if (!isCubeComplete())
1158 {
1159 return false;
1160 }
1161 }
1162 else
1163 {
1164 if (!isMipmapCubeComplete()) // Also tests for isCubeComplete()
1165 {
1166 return false;
1167 }
1168 }
1169
1170 return true;
1171}
1172
1173// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1174bool TextureCubeMap::isCubeComplete() const
1175{
Jamie Madillc1f8b162013-10-07 10:46:38 -04001176 int baseWidth = getBaseLevelWidth();
1177 int baseHeight = getBaseLevelHeight();
1178 GLenum baseFormat = getBaseLevelInternalFormat();
1179
1180 if (baseWidth <= 0 || baseWidth != baseHeight)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001181 {
1182 return false;
1183 }
1184
Jamie Madill2db197c2013-10-24 17:49:35 -04001185 for (int faceIndex = 1; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001186 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001187 const rx::Image &faceBaseImage = *mImageArray[faceIndex][0];
Jamie Madillc1f8b162013-10-07 10:46:38 -04001188
1189 if (faceBaseImage.getWidth() != baseWidth ||
1190 faceBaseImage.getHeight() != baseHeight ||
1191 faceBaseImage.getInternalFormat() != baseFormat )
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001192 {
1193 return false;
1194 }
1195 }
1196
1197 return true;
1198}
1199
1200bool TextureCubeMap::isMipmapCubeComplete() const
1201{
1202 if (isImmutable())
1203 {
1204 return true;
1205 }
1206
1207 if (!isCubeComplete())
1208 {
1209 return false;
1210 }
1211
Jamie Madill22f843a2013-10-24 17:49:36 -04001212 int q = mipLevels();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001213
1214 for (int face = 0; face < 6; face++)
1215 {
1216 for (int level = 1; level <= q; level++)
1217 {
Jamie Madill07edd442013-07-19 16:36:58 -04001218 if (!isFaceLevelComplete(face, level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001219 {
1220 return false;
1221 }
1222 }
1223 }
1224
1225 return true;
1226}
1227
Jamie Madill2db197c2013-10-24 17:49:35 -04001228bool TextureCubeMap::isFaceLevelComplete(int faceIndex, int level) const
Jamie Madill07edd442013-07-19 16:36:58 -04001229{
Jamie Madill2db197c2013-10-24 17:49:35 -04001230 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
Jamie Madill07edd442013-07-19 16:36:58 -04001231
1232 if (isImmutable())
1233 {
1234 return true;
1235 }
1236
Jamie Madilld3d2a342013-10-07 10:46:35 -04001237 int baseSize = getBaseLevelWidth();
Jamie Madill07edd442013-07-19 16:36:58 -04001238
Jamie Madilld3d2a342013-10-07 10:46:35 -04001239 if (baseSize <= 0)
Jamie Madill07edd442013-07-19 16:36:58 -04001240 {
1241 return false;
1242 }
1243
Jamie Madilld3d2a342013-10-07 10:46:35 -04001244 // "isCubeComplete" checks for base level completeness and we must call that
1245 // to determine if any face at level 0 is complete. We omit that check here
1246 // to avoid re-checking cube-completeness for every face at level 0.
Jamie Madill07edd442013-07-19 16:36:58 -04001247 if (level == 0)
1248 {
1249 return true;
1250 }
1251
Jamie Madilld3d2a342013-10-07 10:46:35 -04001252 // Check that non-zero levels are consistent with the base level.
Jamie Madill2db197c2013-10-24 17:49:35 -04001253 const rx::Image *faceLevelImage = mImageArray[faceIndex][level];
Jamie Madill07edd442013-07-19 16:36:58 -04001254
Jamie Madilld3d2a342013-10-07 10:46:35 -04001255 if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat())
Jamie Madill07edd442013-07-19 16:36:58 -04001256 {
1257 return false;
1258 }
1259
Jamie Madilld3d2a342013-10-07 10:46:35 -04001260 if (faceLevelImage->getWidth() != std::max(1, baseSize >> level))
Jamie Madill07edd442013-07-19 16:36:58 -04001261 {
1262 return false;
1263 }
1264
1265 return true;
1266}
1267
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001268bool TextureCubeMap::isCompressed(GLenum target, GLint level) const
1269{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001270 return IsFormatCompressed(getInternalFormat(target, level), mRenderer->getCurrentClientVersion());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001271}
1272
Geoff Lang8040f572013-07-25 16:49:54 -04001273bool TextureCubeMap::isDepth(GLenum target, GLint level) const
1274{
1275 return GetDepthBits(getInternalFormat(target, level), mRenderer->getCurrentClientVersion()) > 0;
1276}
1277
Jamie Madill73b5d062013-10-24 17:49:38 -04001278void TextureCubeMap::initializeStorage(bool renderTarget)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001279{
Jamie Madill3c0989c2013-10-24 17:49:39 -04001280 // Only initialize the first time this texture is used as a render target or shader resource
1281 if (mTexStorage)
1282 {
1283 return;
1284 }
1285
1286 // do not attempt to create storage for nonexistant data
1287 if (!isFaceLevelComplete(0, 0))
1288 {
1289 return;
1290 }
1291
1292 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
1293
1294 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
1295 ASSERT(mTexStorage);
1296
1297 // flush image data to the storage
1298 updateStorage();
1299}
1300
1301rx::TextureStorageInterfaceCube *TextureCubeMap::createCompleteStorage(bool renderTarget) const
1302{
Jamie Madilld3d2a342013-10-07 10:46:35 -04001303 GLsizei size = getBaseLevelWidth();
daniel@transgaming.come6a09842012-09-17 21:28:55 +00001304
Jamie Madill3c0989c2013-10-24 17:49:39 -04001305 ASSERT(size > 0);
daniel@transgaming.come6a09842012-09-17 21:28:55 +00001306
Jamie Madill3c0989c2013-10-24 17:49:39 -04001307 // use existing storage level count, when previously specified by TexStorage*D
1308 GLint levels = (mTexStorage ? mTexStorage->levelCount() : creationLevels(size));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001309
Jamie Madill3c0989c2013-10-24 17:49:39 -04001310 return new rx::TextureStorageInterfaceCube(mRenderer, levels, getBaseLevelInternalFormat(), renderTarget, size);
1311}
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001312
Jamie Madill3c0989c2013-10-24 17:49:39 -04001313void TextureCubeMap::setCompleteTexStorage(rx::TextureStorageInterfaceCube *newCompleteTexStorage)
1314{
1315 SafeDelete(mTexStorage);
1316 mTexStorage = newCompleteTexStorage;
1317
1318 if (mTexStorage && mTexStorage->isManaged())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001319 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001320 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001321 {
Jamie Madill3c0989c2013-10-24 17:49:39 -04001322 for (int level = 0; level < mTexStorage->levelCount(); level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001323 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001324 mImageArray[faceIndex][level]->setManagedSurface(mTexStorage, faceIndex, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001325 }
1326 }
1327 }
1328
1329 mDirtyImages = true;
1330}
1331
Jamie Madill169d1112013-10-24 17:49:37 -04001332void TextureCubeMap::updateStorage()
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001333{
Jamie Madilld9b9a502013-10-10 17:46:13 -04001334 int storageLevels = levelCount();
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +00001335
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001336 for (int face = 0; face < 6; face++)
1337 {
Jamie Madilld9b9a502013-10-10 17:46:13 -04001338 for (int level = 0; level < storageLevels; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001339 {
Jamie Madilld9b9a502013-10-10 17:46:13 -04001340 if (isFaceLevelComplete(face, level))
1341 {
Jamie Madill169d1112013-10-24 17:49:37 -04001342 updateStorageFaceLevel(face, level);
Jamie Madilld9b9a502013-10-10 17:46:13 -04001343 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001344 }
1345 }
1346}
1347
Jamie Madill169d1112013-10-24 17:49:37 -04001348void TextureCubeMap::updateStorageFaceLevel(int faceIndex, int level)
Jamie Madill07edd442013-07-19 16:36:58 -04001349{
Jamie Madill2db197c2013-10-24 17:49:35 -04001350 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1351 rx::Image *image = mImageArray[faceIndex][level];
Jamie Madill07edd442013-07-19 16:36:58 -04001352
1353 if (image->isDirty())
1354 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001355 commitRect(faceIndex, level, 0, 0, image->getWidth(), image->getHeight());
Jamie Madill07edd442013-07-19 16:36:58 -04001356 }
1357}
1358
Jamie Madille83d1a92013-10-24 17:49:33 -04001359bool TextureCubeMap::ensureRenderTarget()
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001360{
Jamie Madill3c0989c2013-10-24 17:49:39 -04001361 initializeStorage(true);
1362
1363 if (getBaseLevelWidth() > 0)
Jamie Madille83d1a92013-10-24 17:49:33 -04001364 {
Jamie Madill3c0989c2013-10-24 17:49:39 -04001365 ASSERT(mTexStorage);
1366 if (!mTexStorage->isRenderTarget())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001367 {
Jamie Madill3c0989c2013-10-24 17:49:39 -04001368 rx::TextureStorageInterfaceCube *newRenderTargetStorage = createCompleteStorage(true);
1369
1370 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001371 {
Jamie Madill3c0989c2013-10-24 17:49:39 -04001372 delete newRenderTargetStorage;
Jamie Madille83d1a92013-10-24 17:49:33 -04001373 return gl::error(GL_OUT_OF_MEMORY, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001374 }
Jamie Madill3c0989c2013-10-24 17:49:39 -04001375
1376 setCompleteTexStorage(newRenderTargetStorage);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001377 }
1378 }
1379
Jamie Madille83d1a92013-10-24 17:49:33 -04001380 return (mTexStorage && mTexStorage->isRenderTarget());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001381}
1382
Geoff Lang005df412013-10-16 14:12:50 -04001383void TextureCubeMap::setImage(int faceIndex, GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001384{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001385 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Geoff Lang005df412013-10-16 14:12:50 -04001386 GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
1387 : GetSizedInternalFormat(format, type, clientVersion);
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001388
1389 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001390
Jamie Madill88f18f42013-09-18 14:36:19 -04001391 Texture::setImage(unpack, type, pixels, mImageArray[faceIndex][level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001392}
1393
Jamie Madill2db197c2013-10-24 17:49:35 -04001394int TextureCubeMap::targetToIndex(GLenum target)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001395{
1396 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
1397 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
1398 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
1399 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
1400 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
1401
Jamie Madill2db197c2013-10-24 17:49:35 -04001402 return target - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001403}
1404
Jamie Madill2db197c2013-10-24 17:49:35 -04001405void TextureCubeMap::redefineImage(int faceIndex, GLint level, GLenum internalformat, GLsizei width, GLsizei height)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001406{
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001407 // If there currently is a corresponding storage texture image, it has these parameters
Jamie Madilld3d2a342013-10-07 10:46:35 -04001408 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1409 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
Geoff Lang005df412013-10-16 14:12:50 -04001410 const GLenum storageFormat = getBaseLevelInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001411
Jamie Madill2db197c2013-10-24 17:49:35 -04001412 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, width, height, 1, false);
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001413
1414 if (mTexStorage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001415 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001416 const int storageLevels = mTexStorage->levelCount();
1417
1418 if ((level >= storageLevels && storageLevels != 0) ||
1419 width != storageWidth ||
1420 height != storageHeight ||
1421 internalformat != storageFormat) // Discard mismatched storage
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001422 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001423 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001424 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001425 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001426 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001427 mImageArray[faceIndex][level]->markDirty();
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001428 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001429 }
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001430
1431 delete mTexStorage;
1432 mTexStorage = NULL;
1433
1434 mDirtyImages = true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001435 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001436 }
1437}
1438
1439void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1440{
Jamie Madill2db197c2013-10-24 17:49:35 -04001441 int faceIndex = targetToIndex(target);
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001442 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Geoff Lang005df412013-10-16 14:12:50 -04001443 GLenum sizedInternalFormat = IsSizedInternalFormat(format, clientVersion) ? format
1444 : GetSizedInternalFormat(format, GL_UNSIGNED_BYTE, clientVersion);
Jamie Madill2db197c2013-10-24 17:49:35 -04001445 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001446
Jamie Madill2db197c2013-10-24 17:49:35 -04001447 if (!mImageArray[faceIndex][level]->isRenderableFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001448 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001449 mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001450 mDirtyImages = true;
1451 }
1452 else
1453 {
Jamie Madille83d1a92013-10-24 17:49:33 -04001454 ensureRenderTarget();
Jamie Madill2db197c2013-10-24 17:49:35 -04001455 mImageArray[faceIndex][level]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001456
1457 ASSERT(width == height);
1458
1459 if (width > 0 && level < levelCount())
1460 {
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +00001461 gl::Rectangle sourceRect;
1462 sourceRect.x = x;
1463 sourceRect.width = width;
1464 sourceRect.y = y;
1465 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001466
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +00001467 mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001468 }
1469 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001470}
1471
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001472void 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 +00001473{
Jamie Madill2db197c2013-10-24 17:49:35 -04001474 int faceIndex = targetToIndex(target);
1475
1476 GLsizei size = mImageArray[faceIndex][level]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001477
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001478 if (xoffset + width > size || yoffset + height > size || zoffset != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001479 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +00001480 return gl::error(GL_INVALID_VALUE);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001481 }
1482
Jamie Madilld3d2a342013-10-07 10:46:35 -04001483 // We can only make our texture storage to a render target if the level we're copying *to* is complete
1484 // and the base level is cube-complete. The base level must be cube complete (common case) because we cannot
1485 // rely on the "getBaseLevel*" methods reliably otherwise.
Jamie Madill2db197c2013-10-24 17:49:35 -04001486 bool canCreateRenderTarget = isFaceLevelComplete(faceIndex, level) && isCubeComplete();
Jamie Madill07edd442013-07-19 16:36:58 -04001487
Jamie Madill2db197c2013-10-24 17:49:35 -04001488 if (!mImageArray[faceIndex][level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001489 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001490 mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001491 mDirtyImages = true;
1492 }
1493 else
1494 {
Jamie Madille83d1a92013-10-24 17:49:33 -04001495 ensureRenderTarget();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001496
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001497 if (level < levelCount())
1498 {
Jamie Madill169d1112013-10-24 17:49:37 -04001499 updateStorageFaceLevel(faceIndex, level);
Jamie Madill07edd442013-07-19 16:36:58 -04001500
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001501 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1502
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +00001503 gl::Rectangle sourceRect;
1504 sourceRect.x = x;
1505 sourceRect.width = width;
1506 sourceRect.y = y;
1507 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001508
Jamie Madilld3d2a342013-10-07 10:46:35 -04001509 mRenderer->copyImage(source, sourceRect, gl::GetFormat(getBaseLevelInternalFormat(), clientVersion),
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +00001510 xoffset, yoffset, mTexStorage, target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001511 }
1512 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001513}
1514
1515void TextureCubeMap::storage(GLsizei levels, GLenum internalformat, GLsizei size)
1516{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001517 for (int level = 0; level < levels; level++)
1518 {
Geoff Langd3110192013-09-24 11:52:47 -04001519 GLsizei mipSize = std::max(1, size >> level);
Jamie Madill2db197c2013-10-24 17:49:35 -04001520 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001521 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001522 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, mipSize, mipSize, 1, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001523 }
1524 }
1525
1526 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1527 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001528 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001529 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001530 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, GL_NONE, 0, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001531 }
1532 }
1533
Jamie Madill3c0989c2013-10-24 17:49:39 -04001534 mImmutable = true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001535
Jamie Madill3c0989c2013-10-24 17:49:39 -04001536 setCompleteTexStorage(new rx::TextureStorageInterfaceCube(mRenderer, levels, internalformat, IsRenderTargetUsage(mUsage), size));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001537}
1538
1539void TextureCubeMap::generateMipmaps()
1540{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001541 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Jamie Madill22f843a2013-10-24 17:49:36 -04001542 int q = mipLevels();
Jamie Madill2db197c2013-10-24 17:49:35 -04001543 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001544 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001545 for (int level = 1; level <= q; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001546 {
Jamie Madill22f843a2013-10-24 17:49:36 -04001547 int faceLevelSize = (std::max(mImageArray[faceIndex][0]->getWidth() >> level, 1));
1548 redefineImage(faceIndex, level, mImageArray[faceIndex][0]->getInternalFormat(), faceLevelSize, faceLevelSize);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001549 }
1550 }
1551
1552 if (mTexStorage && mTexStorage->isRenderTarget())
1553 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001554 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001555 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001556 for (int level = 1; level <= q; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001557 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001558 mTexStorage->generateMipmap(faceIndex, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001559
Jamie Madill2db197c2013-10-24 17:49:35 -04001560 mImageArray[faceIndex][level]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001561 }
1562 }
1563 }
1564 else
1565 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001566 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001567 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001568 for (int level = 1; level <= q; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001569 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001570 mRenderer->generateMipmap(mImageArray[faceIndex][level], mImageArray[faceIndex][level - 1]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001571 }
1572 }
1573 }
1574}
1575
Jamie Madilld3d2a342013-10-07 10:46:35 -04001576const rx::Image *TextureCubeMap::getBaseLevelImage() const
1577{
1578 // Note: if we are not cube-complete, there is no single base level image that can describe all
1579 // cube faces, so this method is only well-defined for a cube-complete base level.
1580 return mImageArray[0][0];
1581}
1582
Geoff Lang8040f572013-07-25 16:49:54 -04001583Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target, GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001584{
1585 if (!IsCubemapTextureTarget(target))
1586 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +00001587 return gl::error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001588 }
1589
Jamie Madill2db197c2013-10-24 17:49:35 -04001590 int faceIndex = targetToIndex(target);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001591
Jamie Madill2db197c2013-10-24 17:49:35 -04001592 Renderbuffer *renderBuffer = mRenderbufferProxies.get(level, faceIndex);
Geoff Lang8040f572013-07-25 16:49:54 -04001593 if (!renderBuffer)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001594 {
Geoff Lang8040f572013-07-25 16:49:54 -04001595 renderBuffer = new Renderbuffer(mRenderer, id(), new RenderbufferTextureCubeMap(this, target, level));
Jamie Madill2db197c2013-10-24 17:49:35 -04001596 mRenderbufferProxies.add(level, faceIndex, renderBuffer);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001597 }
1598
Geoff Lang8040f572013-07-25 16:49:54 -04001599 return renderBuffer;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001600}
1601
Jamie Madill2db197c2013-10-24 17:49:35 -04001602unsigned int TextureCubeMap::getRenderTargetSerial(GLenum target, GLint level)
Geoff Lang8040f572013-07-25 16:49:54 -04001603{
Jamie Madill2db197c2013-10-24 17:49:35 -04001604 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(target, level) : 0);
Geoff Lang8040f572013-07-25 16:49:54 -04001605}
1606
1607rx::RenderTarget *TextureCubeMap::getRenderTarget(GLenum target, GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001608{
1609 ASSERT(IsCubemapTextureTarget(target));
1610
1611 // ensure the underlying texture is created
1612 if (getStorage(true) == NULL)
1613 {
1614 return NULL;
1615 }
1616
Jamie Madill169d1112013-10-24 17:49:37 -04001617 updateStorageFaceLevel(targetToIndex(target), level);
Geoff Lang8040f572013-07-25 16:49:54 -04001618
1619 // ensure this is NOT a depth texture
1620 if (isDepth(target, level))
1621 {
1622 return NULL;
1623 }
1624
1625 return mTexStorage->getRenderTarget(target, level);
1626}
1627
1628rx::RenderTarget *TextureCubeMap::getDepthStencil(GLenum target, GLint level)
1629{
1630 ASSERT(IsCubemapTextureTarget(target));
1631
1632 // ensure the underlying texture is created
1633 if (getStorage(true) == NULL)
1634 {
1635 return NULL;
1636 }
1637
Jamie Madill169d1112013-10-24 17:49:37 -04001638 updateStorageFaceLevel(targetToIndex(target), level);
Geoff Lang8040f572013-07-25 16:49:54 -04001639
1640 // ensure this is a depth texture
1641 if (!isDepth(target, level))
1642 {
1643 return NULL;
1644 }
1645
1646 return mTexStorage->getRenderTarget(target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001647}
1648
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +00001649int TextureCubeMap::levelCount()
1650{
1651 return mTexStorage ? mTexStorage->levelCount() - getLodOffset() : 0;
1652}
1653
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001654rx::TextureStorageInterface *TextureCubeMap::getStorage(bool renderTarget)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001655{
1656 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
1657 {
1658 if (renderTarget)
1659 {
Jamie Madille83d1a92013-10-24 17:49:33 -04001660 ensureRenderTarget();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001661 }
1662 else
1663 {
Jamie Madill73b5d062013-10-24 17:49:38 -04001664 initializeStorage(false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001665 }
1666 }
1667
1668 return mTexStorage;
1669}
1670
Geoff Lang4907f2c2013-07-25 12:53:57 -04001671Texture3D::Texture3D(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_3D)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001672{
1673 mTexStorage = NULL;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001674
1675 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1676 {
1677 mImageArray[i] = renderer->createImage();
1678 }
1679}
1680
1681Texture3D::~Texture3D()
1682{
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001683 delete mTexStorage;
1684 mTexStorage = NULL;
1685
1686 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1687 {
1688 delete mImageArray[i];
1689 }
1690}
1691
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001692GLsizei Texture3D::getWidth(GLint level) const
1693{
1694 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getWidth() : 0;
1695}
1696
1697GLsizei Texture3D::getHeight(GLint level) const
1698{
1699 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getHeight() : 0;
1700}
1701
1702GLsizei Texture3D::getDepth(GLint level) const
1703{
1704 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getDepth() : 0;
1705}
1706
1707GLenum Texture3D::getInternalFormat(GLint level) const
1708{
1709 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getInternalFormat() : GL_NONE;
1710}
1711
1712GLenum Texture3D::getActualFormat(GLint level) const
1713{
1714 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getActualFormat() : D3DFMT_UNKNOWN;
1715}
1716
1717bool Texture3D::isCompressed(GLint level) const
1718{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001719 return IsFormatCompressed(getInternalFormat(level), mRenderer->getCurrentClientVersion());
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001720}
1721
1722bool Texture3D::isDepth(GLint level) const
1723{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001724 return GetDepthBits(getInternalFormat(level), mRenderer->getCurrentClientVersion()) > 0;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001725}
1726
Geoff Lang005df412013-10-16 14:12:50 -04001727void Texture3D::setImage(GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001728{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001729 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Geoff Lang005df412013-10-16 14:12:50 -04001730 GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
1731 : GetSizedInternalFormat(format, type, clientVersion);
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001732 redefineImage(level, sizedInternalFormat, width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001733
Jamie Madilla2d4e552013-10-10 15:12:01 -04001734 bool fastUnpacked = false;
1735
1736 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1737 if (isFastUnpackable(unpack, sizedInternalFormat))
1738 {
1739 // Will try to create RT storage if it does not exist
1740 rx::RenderTarget *destRenderTarget = getRenderTarget(level);
1741 Box destArea(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1742
1743 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget))
1744 {
1745 // Ensure we don't overwrite our newly initialized data
1746 mImageArray[level]->markClean();
1747
1748 fastUnpacked = true;
1749 }
1750 }
1751
1752 if (!fastUnpacked)
1753 {
1754 Texture::setImage(unpack, type, pixels, mImageArray[level]);
1755 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001756}
1757
1758void Texture3D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
1759{
1760 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1761 redefineImage(level, format, width, height, depth);
1762
1763 Texture::setCompressedImage(imageSize, pixels, mImageArray[level]);
1764}
1765
Jamie Madill88f18f42013-09-18 14:36:19 -04001766void 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 +00001767{
Jamie Madillba4f10a2013-10-10 15:12:20 -04001768 bool fastUnpacked = false;
1769
1770 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1771 if (isFastUnpackable(unpack, getInternalFormat(level)))
1772 {
1773 rx::RenderTarget *destRenderTarget = getRenderTarget(level);
1774 Box destArea(xoffset, yoffset, zoffset, width, height, depth);
1775
1776 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, destRenderTarget))
1777 {
1778 // Ensure we don't overwrite our newly initialized data
1779 mImageArray[level]->markClean();
1780
1781 fastUnpacked = true;
1782 }
1783 }
1784
1785 if (!fastUnpacked && Texture::subImage(xoffset, yoffset, zoffset, width, height, depth, format, type, unpack, pixels, mImageArray[level]))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001786 {
1787 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1788 }
1789}
1790
1791void Texture3D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
1792{
1793 if (Texture::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth, format, imageSize, pixels, mImageArray[level]))
1794 {
1795 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1796 }
1797}
1798
1799void Texture3D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
1800{
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001801 for (int level = 0; level < levels; level++)
1802 {
Jamie Madille664e202013-10-24 17:49:40 -04001803 GLsizei levelWidth = std::max(1, width >> level);
1804 GLsizei levelHeight = std::max(1, height >> level);
1805 GLsizei levelDepth = std::max(1, depth >> level);
1806 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, levelWidth, levelHeight, levelDepth, true);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001807 }
1808
1809 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1810 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001811 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, GL_NONE, 0, 0, 0, true);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001812 }
1813
Jamie Madille664e202013-10-24 17:49:40 -04001814 mImmutable = true;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001815
Jamie Madille664e202013-10-24 17:49:40 -04001816 setCompleteTexStorage(new rx::TextureStorageInterface3D(mRenderer, levels, internalformat, IsRenderTargetUsage(mUsage), width, height, depth));
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001817}
1818
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001819void Texture3D::generateMipmaps()
1820{
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001821 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Jamie Madill22f843a2013-10-24 17:49:36 -04001822 int q = mipLevels();
1823 for (int level = 1; level <= q; level++)
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001824 {
Jamie Madill22f843a2013-10-24 17:49:36 -04001825 redefineImage(level, getBaseLevelInternalFormat(),
1826 std::max(getBaseLevelWidth() >> level, 1),
1827 std::max(getBaseLevelHeight() >> level, 1),
1828 std::max(getBaseLevelDepth() >> level, 1));
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001829 }
1830
1831 if (mTexStorage && mTexStorage->isRenderTarget())
1832 {
Jamie Madill22f843a2013-10-24 17:49:36 -04001833 for (int level = 1; level <= q; level++)
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001834 {
Jamie Madill22f843a2013-10-24 17:49:36 -04001835 mTexStorage->generateMipmap(level);
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001836
Jamie Madill22f843a2013-10-24 17:49:36 -04001837 mImageArray[level]->markClean();
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001838 }
1839 }
1840 else
1841 {
Jamie Madill22f843a2013-10-24 17:49:36 -04001842 for (int level = 1; level <= q; level++)
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001843 {
Jamie Madill22f843a2013-10-24 17:49:36 -04001844 mRenderer->generateMipmap(mImageArray[level], mImageArray[level - 1]);
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001845 }
1846 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001847}
1848
Jamie Madilld3d2a342013-10-07 10:46:35 -04001849const rx::Image *Texture3D::getBaseLevelImage() const
1850{
1851 return mImageArray[0];
1852}
1853
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001854void Texture3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1855{
1856 if (xoffset + width > mImageArray[level]->getWidth() || yoffset + height > mImageArray[level]->getHeight() || zoffset >= mImageArray[level]->getDepth())
1857 {
1858 return gl::error(GL_INVALID_VALUE);
1859 }
1860
Jamie Madill07edd442013-07-19 16:36:58 -04001861 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
1862 // the current level we're copying to is defined (with appropriate format, width & height)
1863 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
1864
1865 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001866 {
1867 mImageArray[level]->copy(xoffset, yoffset, zoffset, x, y, width, height, source);
1868 mDirtyImages = true;
1869 }
1870 else
1871 {
Jamie Madille83d1a92013-10-24 17:49:33 -04001872 ensureRenderTarget();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001873
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001874 if (level < levelCount())
1875 {
Jamie Madill169d1112013-10-24 17:49:37 -04001876 updateStorageLevel(level);
Jamie Madill07edd442013-07-19 16:36:58 -04001877
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001878 gl::Rectangle sourceRect;
1879 sourceRect.x = x;
1880 sourceRect.width = width;
1881 sourceRect.y = y;
1882 sourceRect.height = height;
1883
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001884 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1885
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001886 mRenderer->copyImage(source, sourceRect,
Jamie Madilld3d2a342013-10-07 10:46:35 -04001887 gl::GetFormat(getBaseLevelInternalFormat(), clientVersion),
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001888 xoffset, yoffset, zoffset, mTexStorage, level);
1889 }
1890 }
1891}
1892
Jamie Madillf8989902013-07-19 16:36:58 -04001893bool Texture3D::isSamplerComplete(const SamplerState &samplerState) const
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001894{
Jamie Madilld3d2a342013-10-07 10:46:35 -04001895 GLsizei width = getBaseLevelWidth();
1896 GLsizei height = getBaseLevelHeight();
1897 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001898
1899 if (width <= 0 || height <= 0 || depth <= 0)
1900 {
1901 return false;
1902 }
1903
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001904 if (!IsTextureFilteringSupported(getInternalFormat(0), mRenderer))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001905 {
Jamie Madillf8989902013-07-19 16:36:58 -04001906 if (samplerState.magFilter != GL_NEAREST ||
1907 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001908 {
1909 return false;
1910 }
1911 }
1912
Jamie Madillf8989902013-07-19 16:36:58 -04001913 if (IsMipmapFiltered(samplerState) && !isMipmapComplete())
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001914 {
1915 return false;
1916 }
1917
1918 return true;
1919}
1920
1921bool Texture3D::isMipmapComplete() const
1922{
Jamie Madill22f843a2013-10-24 17:49:36 -04001923 int q = mipLevels();
Jamie Madill07edd442013-07-19 16:36:58 -04001924
1925 for (int level = 0; level <= q; level++)
1926 {
1927 if (!isLevelComplete(level))
1928 {
1929 return false;
1930 }
1931 }
1932
1933 return true;
1934}
1935
1936bool Texture3D::isLevelComplete(int level) const
1937{
1938 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1939
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001940 if (isImmutable())
1941 {
1942 return true;
1943 }
1944
Jamie Madilld3d2a342013-10-07 10:46:35 -04001945 GLsizei width = getBaseLevelWidth();
1946 GLsizei height = getBaseLevelHeight();
1947 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001948
1949 if (width <= 0 || height <= 0 || depth <= 0)
1950 {
1951 return false;
1952 }
1953
Jamie Madill07edd442013-07-19 16:36:58 -04001954 if (level == 0)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001955 {
Jamie Madill07edd442013-07-19 16:36:58 -04001956 return true;
1957 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001958
Jamie Madill07edd442013-07-19 16:36:58 -04001959 rx::Image *levelImage = mImageArray[level];
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001960
Jamie Madilld3d2a342013-10-07 10:46:35 -04001961 if (levelImage->getInternalFormat() != getBaseLevelInternalFormat())
Jamie Madill07edd442013-07-19 16:36:58 -04001962 {
1963 return false;
1964 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001965
Jamie Madill07edd442013-07-19 16:36:58 -04001966 if (levelImage->getWidth() != std::max(1, width >> level))
1967 {
1968 return false;
1969 }
1970
1971 if (levelImage->getHeight() != std::max(1, height >> level))
1972 {
1973 return false;
1974 }
1975
1976 if (levelImage->getDepth() != std::max(1, depth >> level))
1977 {
1978 return false;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001979 }
1980
1981 return true;
1982}
1983
Geoff Lang8040f572013-07-25 16:49:54 -04001984Renderbuffer *Texture3D::getRenderbuffer(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001985{
Geoff Lang8040f572013-07-25 16:49:54 -04001986 Renderbuffer *renderBuffer = mRenderbufferProxies.get(level, layer);
1987 if (!renderBuffer)
1988 {
Geoff Langd5d8e392013-07-25 16:53:03 -04001989 renderBuffer = new Renderbuffer(mRenderer, id(), new RenderbufferTexture3DLayer(this, level, layer));
1990 mRenderbufferProxies.add(level, 0, renderBuffer);
Geoff Lang8040f572013-07-25 16:49:54 -04001991 }
1992
1993 return renderBuffer;
1994}
1995
1996unsigned int Texture3D::getRenderTargetSerial(GLint level, GLint layer)
1997{
Jamie Madille83d1a92013-10-24 17:49:33 -04001998 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(level, layer) : 0);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001999}
2000
2001int Texture3D::levelCount()
2002{
2003 return mTexStorage ? mTexStorage->levelCount() : 0;
2004}
2005
Jamie Madill73b5d062013-10-24 17:49:38 -04002006void Texture3D::initializeStorage(bool renderTarget)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002007{
Jamie Madille664e202013-10-24 17:49:40 -04002008 // Only initialize the first time this texture is used as a render target or shader resource
2009 if (mTexStorage)
2010 {
2011 return;
2012 }
2013
2014 // do not attempt to create storage for nonexistant data
2015 if (!isLevelComplete(0))
2016 {
2017 return;
2018 }
2019
2020 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
2021
2022 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
2023 ASSERT(mTexStorage);
2024
2025 // flush image data to the storage
2026 updateStorage();
2027}
2028
2029rx::TextureStorageInterface3D *Texture3D::createCompleteStorage(bool renderTarget) const
2030{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002031 GLsizei width = getBaseLevelWidth();
2032 GLsizei height = getBaseLevelHeight();
2033 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002034
Jamie Madille664e202013-10-24 17:49:40 -04002035 ASSERT(width > 0 && height > 0 && depth > 0);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002036
Jamie Madille664e202013-10-24 17:49:40 -04002037 // use existing storage level count, when previously specified by TexStorage*D
2038 GLint levels = (mTexStorage ? mTexStorage->levelCount() : creationLevels(width, height, depth));
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002039
Jamie Madille664e202013-10-24 17:49:40 -04002040 return new rx::TextureStorageInterface3D(mRenderer, levels, getBaseLevelInternalFormat(), renderTarget, width, height, depth);
2041}
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002042
Jamie Madille664e202013-10-24 17:49:40 -04002043void Texture3D::setCompleteTexStorage(rx::TextureStorageInterface3D *newCompleteTexStorage)
2044{
2045 SafeDelete(mTexStorage);
2046 mTexStorage = newCompleteTexStorage;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002047 mDirtyImages = true;
Jamie Madille664e202013-10-24 17:49:40 -04002048
2049 // We do not support managed 3D storage, as that is D3D9/ES2-only
2050 ASSERT(!mTexStorage->isManaged());
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002051}
2052
Jamie Madill169d1112013-10-24 17:49:37 -04002053void Texture3D::updateStorage()
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002054{
Jamie Madilld9b9a502013-10-10 17:46:13 -04002055 int storageLevels = levelCount();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002056
Jamie Madilld9b9a502013-10-10 17:46:13 -04002057 for (int level = 0; level < storageLevels; level++)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002058 {
Jamie Madilld9b9a502013-10-10 17:46:13 -04002059 if (isLevelComplete(level))
2060 {
Jamie Madill169d1112013-10-24 17:49:37 -04002061 updateStorageLevel(level);
Jamie Madilld9b9a502013-10-10 17:46:13 -04002062 }
Jamie Madill07edd442013-07-19 16:36:58 -04002063 }
2064}
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002065
Jamie Madill169d1112013-10-24 17:49:37 -04002066void Texture3D::updateStorageLevel(int level)
Jamie Madill07edd442013-07-19 16:36:58 -04002067{
2068 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
Jamie Madillaee7ad82013-10-10 16:07:32 -04002069 ASSERT(isLevelComplete(level));
Jamie Madill07edd442013-07-19 16:36:58 -04002070
Jamie Madillaee7ad82013-10-10 16:07:32 -04002071 if (mImageArray[level]->isDirty())
Jamie Madill07edd442013-07-19 16:36:58 -04002072 {
Jamie Madillaee7ad82013-10-10 16:07:32 -04002073 commitRect(level, 0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002074 }
2075}
2076
Jamie Madille83d1a92013-10-24 17:49:33 -04002077bool Texture3D::ensureRenderTarget()
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002078{
Jamie Madille664e202013-10-24 17:49:40 -04002079 initializeStorage(true);
2080
2081 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0 && getBaseLevelDepth() > 0)
Jamie Madille83d1a92013-10-24 17:49:33 -04002082 {
Jamie Madille664e202013-10-24 17:49:40 -04002083 ASSERT(mTexStorage);
2084 if (!mTexStorage->isRenderTarget())
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002085 {
Jamie Madille664e202013-10-24 17:49:40 -04002086 rx::TextureStorageInterface3D *newRenderTargetStorage = createCompleteStorage(true);
2087
2088 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002089 {
Jamie Madille664e202013-10-24 17:49:40 -04002090 delete newRenderTargetStorage;
Jamie Madille83d1a92013-10-24 17:49:33 -04002091 return gl::error(GL_OUT_OF_MEMORY, false);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002092 }
Jamie Madille664e202013-10-24 17:49:40 -04002093
2094 setCompleteTexStorage(newRenderTargetStorage);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002095 }
2096 }
2097
Jamie Madille83d1a92013-10-24 17:49:33 -04002098 return (mTexStorage && mTexStorage->isRenderTarget());
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002099}
2100
Jamie Madilla2d4e552013-10-10 15:12:01 -04002101rx::RenderTarget *Texture3D::getRenderTarget(GLint level)
2102{
2103 // ensure the underlying texture is created
2104 if (getStorage(true) == NULL)
2105 {
2106 return NULL;
2107 }
2108
Jamie Madill169d1112013-10-24 17:49:37 -04002109 updateStorageLevel(level);
Jamie Madilla2d4e552013-10-10 15:12:01 -04002110
2111 // ensure this is NOT a depth texture
2112 if (isDepth(level))
2113 {
2114 return NULL;
2115 }
2116
2117 return mTexStorage->getRenderTarget(level);
2118}
2119
Geoff Lang8040f572013-07-25 16:49:54 -04002120rx::RenderTarget *Texture3D::getRenderTarget(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002121{
Geoff Lang8040f572013-07-25 16:49:54 -04002122 // ensure the underlying texture is created
2123 if (getStorage(true) == NULL)
2124 {
2125 return NULL;
2126 }
2127
Jamie Madill169d1112013-10-24 17:49:37 -04002128 updateStorage();
Geoff Lang8040f572013-07-25 16:49:54 -04002129
2130 // ensure this is NOT a depth texture
2131 if (isDepth(level))
2132 {
2133 return NULL;
2134 }
2135
2136 return mTexStorage->getRenderTarget(level, layer);
2137}
2138
2139rx::RenderTarget *Texture3D::getDepthStencil(GLint level, GLint layer)
2140{
2141 // ensure the underlying texture is created
2142 if (getStorage(true) == NULL)
2143 {
2144 return NULL;
2145 }
2146
Jamie Madill169d1112013-10-24 17:49:37 -04002147 updateStorageLevel(level);
Geoff Lang8040f572013-07-25 16:49:54 -04002148
2149 // ensure this is a depth texture
2150 if (!isDepth(level))
2151 {
2152 return NULL;
2153 }
2154
2155 return mTexStorage->getRenderTarget(level, layer);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002156}
2157
2158rx::TextureStorageInterface *Texture3D::getStorage(bool renderTarget)
2159{
2160 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
2161 {
2162 if (renderTarget)
2163 {
Jamie Madille83d1a92013-10-24 17:49:33 -04002164 ensureRenderTarget();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002165 }
2166 else
2167 {
Jamie Madill73b5d062013-10-24 17:49:38 -04002168 initializeStorage(false);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002169 }
2170 }
2171
2172 return mTexStorage;
2173}
2174
Geoff Lang005df412013-10-16 14:12:50 -04002175void Texture3D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002176{
2177 // If there currently is a corresponding storage texture image, it has these parameters
Jamie Madilld3d2a342013-10-07 10:46:35 -04002178 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2179 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
2180 const int storageDepth = std::max(1, getBaseLevelDepth() >> level);
Geoff Lang005df412013-10-16 14:12:50 -04002181 const GLenum storageFormat = getBaseLevelInternalFormat();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002182
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00002183 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, false);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002184
2185 if (mTexStorage)
2186 {
2187 const int storageLevels = mTexStorage->levelCount();
2188
2189 if ((level >= storageLevels && storageLevels != 0) ||
2190 width != storageWidth ||
2191 height != storageHeight ||
2192 depth != storageDepth ||
2193 internalformat != storageFormat) // Discard mismatched storage
2194 {
2195 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
2196 {
2197 mImageArray[i]->markDirty();
2198 }
2199
2200 delete mTexStorage;
2201 mTexStorage = NULL;
2202 mDirtyImages = true;
2203 }
2204 }
2205}
2206
2207void Texture3D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth)
2208{
2209 if (level < levelCount())
2210 {
2211 rx::Image *image = mImageArray[level];
Jamie Madill169d1112013-10-24 17:49:37 -04002212 if (image->copyToStorage(mTexStorage, level, xoffset, yoffset, zoffset, width, height, depth))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002213 {
2214 image->markClean();
2215 }
2216 }
2217}
2218
Geoff Lang4907f2c2013-07-25 12:53:57 -04002219Texture2DArray::Texture2DArray(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_2D_ARRAY)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002220{
2221 mTexStorage = NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002222
2223 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2224 {
2225 mLayerCounts[level] = 0;
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002226 mImageArray[level] = NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002227 }
2228}
2229
2230Texture2DArray::~Texture2DArray()
2231{
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002232 delete mTexStorage;
2233 mTexStorage = NULL;
Jamie Madill884a4622013-10-24 17:49:41 -04002234
2235 deleteImages();
2236}
2237
2238void Texture2DArray::deleteImages()
2239{
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002240 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2241 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002242 for (int layer = 0; layer < mLayerCounts[level]; ++layer)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002243 {
2244 delete mImageArray[level][layer];
2245 }
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002246 delete[] mImageArray[level];
Jamie Madill884a4622013-10-24 17:49:41 -04002247 mImageArray[level] = NULL;
2248 mLayerCounts[level] = 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002249 }
2250}
2251
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002252GLsizei Texture2DArray::getWidth(GLint level) const
2253{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002254 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 +00002255}
2256
2257GLsizei Texture2DArray::getHeight(GLint level) const
2258{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002259 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 +00002260}
2261
2262GLsizei Texture2DArray::getDepth(GLint level) const
2263{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002264 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mLayerCounts[level] : 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002265}
2266
2267GLenum Texture2DArray::getInternalFormat(GLint level) const
2268{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002269 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 +00002270}
2271
2272GLenum Texture2DArray::getActualFormat(GLint level) const
2273{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002274 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 +00002275}
2276
2277bool Texture2DArray::isCompressed(GLint level) const
2278{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00002279 return IsFormatCompressed(getInternalFormat(level), mRenderer->getCurrentClientVersion());
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002280}
2281
2282bool Texture2DArray::isDepth(GLint level) const
2283{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00002284 return GetDepthBits(getInternalFormat(level), mRenderer->getCurrentClientVersion()) > 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002285}
2286
Geoff Lang005df412013-10-16 14:12:50 -04002287void Texture2DArray::setImage(GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002288{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00002289 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Geoff Lang005df412013-10-16 14:12:50 -04002290 GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
2291 : GetSizedInternalFormat(format, type, clientVersion);
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00002292 redefineImage(level, sizedInternalFormat, width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002293
Jamie Madill88f18f42013-09-18 14:36:19 -04002294 GLsizei inputDepthPitch = gl::GetDepthPitch(sizedInternalFormat, type, clientVersion, width, height, unpack.alignment);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002295
2296 for (int i = 0; i < depth; i++)
2297 {
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002298 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
Jamie Madill88f18f42013-09-18 14:36:19 -04002299 Texture::setImage(unpack, type, layerPixels, mImageArray[level][i]);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002300 }
2301}
2302
2303void Texture2DArray::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
2304{
2305 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
2306 redefineImage(level, format, width, height, depth);
2307
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002308 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2309 GLsizei inputDepthPitch = gl::GetDepthPitch(format, GL_UNSIGNED_BYTE, clientVersion, width, height, 1);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002310
2311 for (int i = 0; i < depth; i++)
2312 {
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002313 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002314 Texture::setCompressedImage(imageSize, layerPixels, mImageArray[level][i]);
2315 }
2316}
2317
Jamie Madill88f18f42013-09-18 14:36:19 -04002318void 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 +00002319{
Geoff Lang005df412013-10-16 14:12:50 -04002320 GLenum internalformat = getInternalFormat(level);
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002321 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Jamie Madill88f18f42013-09-18 14:36:19 -04002322 GLsizei inputDepthPitch = gl::GetDepthPitch(internalformat, type, clientVersion, width, height, unpack.alignment);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002323
2324 for (int i = 0; i < depth; i++)
2325 {
2326 int layer = zoffset + i;
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002327 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002328
Jamie Madill88f18f42013-09-18 14:36:19 -04002329 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 +00002330 {
2331 commitRect(level, xoffset, yoffset, layer, width, height);
2332 }
2333 }
2334}
2335
2336void Texture2DArray::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
2337{
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002338 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2339 GLsizei inputDepthPitch = gl::GetDepthPitch(format, GL_UNSIGNED_BYTE, clientVersion, width, height, 1);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002340
2341 for (int i = 0; i < depth; i++)
2342 {
2343 int layer = zoffset + i;
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002344 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002345
2346 if (Texture::subImageCompressed(xoffset, yoffset, zoffset, width, height, 1, format, imageSize, layerPixels, mImageArray[level][layer]))
2347 {
2348 commitRect(level, xoffset, yoffset, layer, width, height);
2349 }
2350 }
2351}
2352
2353void Texture2DArray::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2354{
Jamie Madill884a4622013-10-24 17:49:41 -04002355 deleteImages();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002356
2357 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2358 {
Jamie Madill884a4622013-10-24 17:49:41 -04002359 GLsizei levelWidth = std::max(1, width >> level);
2360 GLsizei levelHeight = std::max(1, height >> level);
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002361
Jamie Madill884a4622013-10-24 17:49:41 -04002362 mLayerCounts[level] = (level < levels ? depth : 0);
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002363
Jamie Madill884a4622013-10-24 17:49:41 -04002364 if (mLayerCounts[level] > 0)
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002365 {
2366 // Create new images for this level
Jamie Madill884a4622013-10-24 17:49:41 -04002367 mImageArray[level] = new rx::Image*[mLayerCounts[level]];
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002368
2369 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002370 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002371 mImageArray[level][layer] = mRenderer->createImage();
2372 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, levelWidth,
2373 levelHeight, 1, true);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002374 }
2375 }
2376 }
2377
Jamie Madill884a4622013-10-24 17:49:41 -04002378 mImmutable = true;
2379 setCompleteTexStorage(new rx::TextureStorageInterface2DArray(mRenderer, levels, internalformat, IsRenderTargetUsage(mUsage), width, height, depth));
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002380}
2381
2382void Texture2DArray::generateMipmaps()
2383{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002384 int baseWidth = getBaseLevelWidth();
2385 int baseHeight = getBaseLevelHeight();
2386 int baseDepth = getBaseLevelDepth();
2387 GLenum baseFormat = getBaseLevelInternalFormat();
2388
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00002389 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Jamie Madill22f843a2013-10-24 17:49:36 -04002390 int q = mipLevels();
2391 for (int level = 1; level <= q; level++)
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00002392 {
Jamie Madill22f843a2013-10-24 17:49:36 -04002393 redefineImage(level, baseFormat, std::max(baseWidth >> level, 1), std::max(baseHeight >> level, 1), baseDepth);
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00002394 }
2395
2396 if (mTexStorage && mTexStorage->isRenderTarget())
2397 {
2398 for (int level = 1; level <= q; level++)
2399 {
2400 mTexStorage->generateMipmap(level);
2401
2402 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2403 {
2404 mImageArray[level][layer]->markClean();
2405 }
2406 }
2407 }
2408 else
2409 {
2410 for (int level = 1; level <= q; level++)
2411 {
2412 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2413 {
2414 mRenderer->generateMipmap(mImageArray[level][layer], mImageArray[level - 1][layer]);
2415 }
2416 }
2417 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002418}
2419
Jamie Madilld3d2a342013-10-07 10:46:35 -04002420const rx::Image *Texture2DArray::getBaseLevelImage() const
2421{
Jamie Madill152ed092013-10-09 17:01:15 -04002422 return (mLayerCounts[0] > 0 ? mImageArray[0][0] : NULL);
Jamie Madilld3d2a342013-10-07 10:46:35 -04002423}
2424
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002425void Texture2DArray::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
2426{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002427 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 +00002428 {
2429 return gl::error(GL_INVALID_VALUE);
2430 }
2431
Jamie Madill07edd442013-07-19 16:36:58 -04002432 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
2433 // the current level we're copying to is defined (with appropriate format, width & height)
2434 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
2435
2436 if (!mImageArray[level][0]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002437 {
2438 mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, x, y, width, height, source);
2439 mDirtyImages = true;
2440 }
2441 else
2442 {
Jamie Madille83d1a92013-10-24 17:49:33 -04002443 ensureRenderTarget();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002444
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002445 if (level < levelCount())
2446 {
Jamie Madill169d1112013-10-24 17:49:37 -04002447 updateStorageLevel(level);
Jamie Madill07edd442013-07-19 16:36:58 -04002448
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002449 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2450
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002451 gl::Rectangle sourceRect;
2452 sourceRect.x = x;
2453 sourceRect.width = width;
2454 sourceRect.y = y;
2455 sourceRect.height = height;
2456
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002457 mRenderer->copyImage(source, sourceRect, gl::GetFormat(getInternalFormat(0), clientVersion),
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002458 xoffset, yoffset, zoffset, mTexStorage, level);
2459 }
2460 }
2461}
2462
Jamie Madillf8989902013-07-19 16:36:58 -04002463bool Texture2DArray::isSamplerComplete(const SamplerState &samplerState) const
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002464{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002465 GLsizei width = getBaseLevelWidth();
2466 GLsizei height = getBaseLevelHeight();
2467 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002468
2469 if (width <= 0 || height <= 0 || depth <= 0)
2470 {
2471 return false;
2472 }
2473
Jamie Madilld3d2a342013-10-07 10:46:35 -04002474 if (!IsTextureFilteringSupported(getBaseLevelInternalFormat(), mRenderer))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002475 {
Jamie Madillf8989902013-07-19 16:36:58 -04002476 if (samplerState.magFilter != GL_NEAREST ||
2477 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002478 {
2479 return false;
2480 }
2481 }
2482
Jamie Madillf8989902013-07-19 16:36:58 -04002483 if (IsMipmapFiltered(samplerState) && !isMipmapComplete())
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002484 {
2485 return false;
2486 }
2487
2488 return true;
2489}
2490
2491bool Texture2DArray::isMipmapComplete() const
2492{
Jamie Madill22f843a2013-10-24 17:49:36 -04002493 int q = mipLevels();
Jamie Madill07edd442013-07-19 16:36:58 -04002494
2495 for (int level = 1; level <= q; level++)
2496 {
2497 if (!isLevelComplete(level))
2498 {
2499 return false;
2500 }
2501 }
2502
2503 return true;
2504}
2505
2506bool Texture2DArray::isLevelComplete(int level) const
2507{
2508 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
2509
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002510 if (isImmutable())
2511 {
2512 return true;
2513 }
2514
Jamie Madilld3d2a342013-10-07 10:46:35 -04002515 GLsizei width = getBaseLevelWidth();
2516 GLsizei height = getBaseLevelHeight();
2517 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002518
2519 if (width <= 0 || height <= 0 || depth <= 0)
2520 {
2521 return false;
2522 }
2523
Jamie Madill07edd442013-07-19 16:36:58 -04002524 if (level == 0)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002525 {
Jamie Madill07edd442013-07-19 16:36:58 -04002526 return true;
2527 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002528
Jamie Madill07edd442013-07-19 16:36:58 -04002529 if (getInternalFormat(level) != getInternalFormat(0))
2530 {
2531 return false;
2532 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002533
Jamie Madill07edd442013-07-19 16:36:58 -04002534 if (getWidth(level) != std::max(1, width >> level))
2535 {
2536 return false;
2537 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002538
Jamie Madill07edd442013-07-19 16:36:58 -04002539 if (getHeight(level) != std::max(1, height >> level))
2540 {
2541 return false;
2542 }
2543
2544 if (getDepth(level) != depth)
2545 {
2546 return false;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002547 }
2548
2549 return true;
2550}
2551
Geoff Lang8040f572013-07-25 16:49:54 -04002552Renderbuffer *Texture2DArray::getRenderbuffer(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002553{
Geoff Lang8040f572013-07-25 16:49:54 -04002554 Renderbuffer *renderBuffer = mRenderbufferProxies.get(level, layer);
2555 if (!renderBuffer)
2556 {
Geoff Langd5d8e392013-07-25 16:53:03 -04002557 renderBuffer = new Renderbuffer(mRenderer, id(), new RenderbufferTexture2DArrayLayer(this, level, layer));
2558 mRenderbufferProxies.add(level, 0, renderBuffer);
Geoff Lang8040f572013-07-25 16:49:54 -04002559 }
2560
2561 return renderBuffer;
2562}
2563
Jamie Madille83d1a92013-10-24 17:49:33 -04002564unsigned int Texture2DArray::getRenderTargetSerial(GLint level, GLint layer)
Geoff Lang8040f572013-07-25 16:49:54 -04002565{
Jamie Madille83d1a92013-10-24 17:49:33 -04002566 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(level, layer) : 0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002567}
2568
2569int Texture2DArray::levelCount()
2570{
2571 return mTexStorage ? mTexStorage->levelCount() : 0;
2572}
2573
Jamie Madill73b5d062013-10-24 17:49:38 -04002574void Texture2DArray::initializeStorage(bool renderTarget)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002575{
Jamie Madill884a4622013-10-24 17:49:41 -04002576 // Only initialize the first time this texture is used as a render target or shader resource
2577 if (mTexStorage)
2578 {
2579 return;
2580 }
2581
2582 // do not attempt to create storage for nonexistant data
2583 if (!isLevelComplete(0))
2584 {
2585 return;
2586 }
2587
2588 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
2589
2590 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
2591 ASSERT(mTexStorage);
2592
2593 // flush image data to the storage
2594 updateStorage();
2595}
2596
2597rx::TextureStorageInterface2DArray *Texture2DArray::createCompleteStorage(bool renderTarget) const
2598{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002599 GLsizei width = getBaseLevelWidth();
2600 GLsizei height = getBaseLevelHeight();
2601 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002602
Jamie Madill884a4622013-10-24 17:49:41 -04002603 ASSERT(width > 0 && height > 0 && depth > 0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002604
Jamie Madill884a4622013-10-24 17:49:41 -04002605 // use existing storage level count, when previously specified by TexStorage*D
2606 GLint levels = (mTexStorage ? mTexStorage->levelCount() : creationLevels(width, height));
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002607
Jamie Madill884a4622013-10-24 17:49:41 -04002608 return new rx::TextureStorageInterface2DArray(mRenderer, levels, getBaseLevelInternalFormat(), renderTarget, width, height, depth);
2609}
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002610
Jamie Madill884a4622013-10-24 17:49:41 -04002611void Texture2DArray::setCompleteTexStorage(rx::TextureStorageInterface2DArray *newCompleteTexStorage)
2612{
2613 SafeDelete(mTexStorage);
2614 mTexStorage = newCompleteTexStorage;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002615 mDirtyImages = true;
Jamie Madill884a4622013-10-24 17:49:41 -04002616
2617 // We do not support managed 2D array storage, as managed storage is ES2/D3D9 only
2618 ASSERT(!mTexStorage->isManaged());
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002619}
2620
Jamie Madill169d1112013-10-24 17:49:37 -04002621void Texture2DArray::updateStorage()
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002622{
Jamie Madilld9b9a502013-10-10 17:46:13 -04002623 int storageLevels = levelCount();
2624
2625 for (int level = 0; level < storageLevels; level++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002626 {
Jamie Madilld9b9a502013-10-10 17:46:13 -04002627 if (isLevelComplete(level))
2628 {
Jamie Madill169d1112013-10-24 17:49:37 -04002629 updateStorageLevel(level);
Jamie Madilld9b9a502013-10-10 17:46:13 -04002630 }
Jamie Madill07edd442013-07-19 16:36:58 -04002631 }
2632}
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002633
Jamie Madill169d1112013-10-24 17:49:37 -04002634void Texture2DArray::updateStorageLevel(int level)
Jamie Madill07edd442013-07-19 16:36:58 -04002635{
Jamie Madillaee7ad82013-10-10 16:07:32 -04002636 ASSERT(level >= 0 && level < (int)ArraySize(mLayerCounts));
2637 ASSERT(isLevelComplete(level));
2638
Jamie Madill07edd442013-07-19 16:36:58 -04002639 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2640 {
Jamie Madillaee7ad82013-10-10 16:07:32 -04002641 ASSERT(mImageArray[level] != NULL && mImageArray[level][layer] != NULL);
2642 if (mImageArray[level][layer]->isDirty())
Jamie Madill07edd442013-07-19 16:36:58 -04002643 {
Jamie Madillaee7ad82013-10-10 16:07:32 -04002644 commitRect(level, 0, 0, layer, getWidth(level), getHeight(level));
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002645 }
2646 }
2647}
2648
Jamie Madille83d1a92013-10-24 17:49:33 -04002649bool Texture2DArray::ensureRenderTarget()
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002650{
Jamie Madill884a4622013-10-24 17:49:41 -04002651 initializeStorage(true);
2652
2653 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0 && getBaseLevelDepth() > 0)
Jamie Madille83d1a92013-10-24 17:49:33 -04002654 {
Jamie Madill884a4622013-10-24 17:49:41 -04002655 ASSERT(mTexStorage);
2656 if (!mTexStorage->isRenderTarget())
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002657 {
Jamie Madill884a4622013-10-24 17:49:41 -04002658 rx::TextureStorageInterface2DArray *newRenderTargetStorage = createCompleteStorage(true);
2659
2660 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002661 {
Jamie Madill884a4622013-10-24 17:49:41 -04002662 delete newRenderTargetStorage;
Jamie Madille83d1a92013-10-24 17:49:33 -04002663 return gl::error(GL_OUT_OF_MEMORY, false);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002664 }
Jamie Madill884a4622013-10-24 17:49:41 -04002665
2666 setCompleteTexStorage(newRenderTargetStorage);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002667 }
2668 }
2669
Jamie Madille83d1a92013-10-24 17:49:33 -04002670 return (mTexStorage && mTexStorage->isRenderTarget());
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002671}
2672
Geoff Lang8040f572013-07-25 16:49:54 -04002673rx::RenderTarget *Texture2DArray::getRenderTarget(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002674{
Geoff Lang8040f572013-07-25 16:49:54 -04002675 // ensure the underlying texture is created
2676 if (getStorage(true) == NULL)
2677 {
2678 return NULL;
2679 }
2680
Jamie Madill169d1112013-10-24 17:49:37 -04002681 updateStorageLevel(level);
Geoff Lang8040f572013-07-25 16:49:54 -04002682
2683 // ensure this is NOT a depth texture
2684 if (isDepth(level))
2685 {
2686 return NULL;
2687 }
2688
2689 return mTexStorage->getRenderTarget(level, layer);
2690}
2691
2692rx::RenderTarget *Texture2DArray::getDepthStencil(GLint level, GLint layer)
2693{
2694 // ensure the underlying texture is created
2695 if (getStorage(true) == NULL)
2696 {
2697 return NULL;
2698 }
2699
Jamie Madill169d1112013-10-24 17:49:37 -04002700 updateStorageLevel(level);
Geoff Lang8040f572013-07-25 16:49:54 -04002701
2702 // ensure this is a depth texture
2703 if (!isDepth(level))
2704 {
2705 return NULL;
2706 }
2707
2708 return mTexStorage->getRenderTarget(level, layer);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002709}
2710
2711rx::TextureStorageInterface *Texture2DArray::getStorage(bool renderTarget)
2712{
2713 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
2714 {
2715 if (renderTarget)
2716 {
Jamie Madille83d1a92013-10-24 17:49:33 -04002717 ensureRenderTarget();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002718 }
2719 else
2720 {
Jamie Madill73b5d062013-10-24 17:49:38 -04002721 initializeStorage(false);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002722 }
2723 }
2724
2725 return mTexStorage;
2726}
2727
Geoff Lang005df412013-10-16 14:12:50 -04002728void Texture2DArray::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002729{
2730 // If there currently is a corresponding storage texture image, it has these parameters
Jamie Madilld3d2a342013-10-07 10:46:35 -04002731 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2732 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
2733 const int storageDepth = getBaseLevelDepth();
Geoff Lang005df412013-10-16 14:12:50 -04002734 const GLenum storageFormat = getBaseLevelInternalFormat();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002735
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002736 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002737 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002738 delete mImageArray[level][layer];
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002739 }
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002740 delete[] mImageArray[level];
Jamie Madill152ed092013-10-09 17:01:15 -04002741 mImageArray[level] = NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002742 mLayerCounts[level] = depth;
2743
Jamie Madill152ed092013-10-09 17:01:15 -04002744 if (depth > 0)
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002745 {
Jamie Madill152ed092013-10-09 17:01:15 -04002746 mImageArray[level] = new rx::Image*[depth]();
2747
2748 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2749 {
2750 mImageArray[level][layer] = mRenderer->createImage();
2751 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, width, height, 1, false);
2752 }
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002753 }
2754
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002755 if (mTexStorage)
2756 {
2757 const int storageLevels = mTexStorage->levelCount();
2758
2759 if ((level >= storageLevels && storageLevels != 0) ||
2760 width != storageWidth ||
2761 height != storageHeight ||
2762 depth != storageDepth ||
2763 internalformat != storageFormat) // Discard mismatched storage
2764 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002765 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002766 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002767 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002768 {
2769 mImageArray[level][layer]->markDirty();
2770 }
2771 }
2772
2773 delete mTexStorage;
2774 mTexStorage = NULL;
2775 mDirtyImages = true;
2776 }
2777 }
2778}
2779
2780void Texture2DArray::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint layerTarget, GLsizei width, GLsizei height)
2781{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002782 if (level < levelCount() && layerTarget < getDepth(level))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002783 {
2784 rx::Image *image = mImageArray[level][layerTarget];
Jamie Madill169d1112013-10-24 17:49:37 -04002785 if (image->copyToStorage(mTexStorage, level, xoffset, yoffset, layerTarget, width, height))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002786 {
2787 image->markClean();
2788 }
2789 }
2790}
2791
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00002792}