blob: 00b4f1c654832ab54faf8d1dff44cc07a9aac16f [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{
Jamie Madill2ebab852013-10-24 17:49:42 -0400170 rx::TextureStorageInterface *texture = getNativeTexture();
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
Jamie Madill2ebab852013-10-24 17:49:42 -0400300 initializeStorage(false);
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000301
Jamie Madill2ebab852013-10-24 17:49:42 -0400302 rx::TextureStorageInterface *storage = getBaseLevelStorage();
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000303 if (storage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000304 {
Jamie Madill169d1112013-10-24 17:49:37 -0400305 updateStorage();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000306 }
307
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000308 return storage;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000309}
310
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000311bool Texture::hasDirtyImages() const
312{
313 return mDirtyImages;
314}
315
316void Texture::resetDirty()
317{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000318 mDirtyImages = false;
319}
320
321unsigned int Texture::getTextureSerial()
322{
Jamie Madill2ebab852013-10-24 17:49:42 -0400323 rx::TextureStorageInterface *texture = getNativeTexture();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000324 return texture ? texture->getTextureSerial() : 0;
325}
326
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000327bool Texture::isImmutable() const
328{
329 return mImmutable;
330}
331
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +0000332GLint Texture::creationLevels(GLsizei width, GLsizei height, GLsizei depth) const
333{
334 // NPOT checks are not required in ES 3.0, NPOT texture support is assumed.
335 return 0; // Maximum number of levels
336}
337
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000338GLint Texture::creationLevels(GLsizei width, GLsizei height) const
339{
daniel@transgaming.comea32d482012-11-28 19:33:18 +0000340 if ((isPow2(width) && isPow2(height)) || mRenderer->getNonPower2TextureSupport())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000341 {
342 return 0; // Maximum number of levels
343 }
344 else
345 {
346 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
347 return 1;
348 }
349}
350
351GLint Texture::creationLevels(GLsizei size) const
352{
353 return creationLevels(size, size);
354}
355
Jamie Madill22f843a2013-10-24 17:49:36 -0400356int Texture::mipLevels() const
357{
358 return log2(std::max(std::max(getBaseLevelWidth(), getBaseLevelHeight()), getBaseLevelDepth()));
359}
360
Geoff Lang4907f2c2013-07-25 12:53:57 -0400361Texture2D::Texture2D(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_2D)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000362{
363 mTexStorage = NULL;
364 mSurface = NULL;
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000365
366 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
367 {
daniel@transgaming.com244e1832012-12-20 20:52:35 +0000368 mImageArray[i] = renderer->createImage();
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000369 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000370}
371
372Texture2D::~Texture2D()
373{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000374 delete mTexStorage;
375 mTexStorage = NULL;
376
377 if (mSurface)
378 {
379 mSurface->setBoundTexture(NULL);
380 mSurface = NULL;
381 }
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000382
383 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
384 {
385 delete mImageArray[i];
386 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000387}
388
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000389GLsizei Texture2D::getWidth(GLint level) const
390{
391 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000392 return mImageArray[level]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000393 else
394 return 0;
395}
396
397GLsizei Texture2D::getHeight(GLint level) const
398{
399 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000400 return mImageArray[level]->getHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000401 else
402 return 0;
403}
404
405GLenum Texture2D::getInternalFormat(GLint level) const
406{
407 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000408 return mImageArray[level]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000409 else
410 return GL_NONE;
411}
412
daniel@transgaming.com20d36662012-10-31 19:51:43 +0000413GLenum Texture2D::getActualFormat(GLint level) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000414{
415 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000416 return mImageArray[level]->getActualFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000417 else
418 return D3DFMT_UNKNOWN;
419}
420
Geoff Lang005df412013-10-16 14:12:50 -0400421void Texture2D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000422{
423 releaseTexImage();
shannon.woods@transgaming.com8a406682013-02-28 23:15:26 +0000424
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000425 // If there currently is a corresponding storage texture image, it has these parameters
Jamie Madilld3d2a342013-10-07 10:46:35 -0400426 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
427 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
Geoff Lang005df412013-10-16 14:12:50 -0400428 const GLenum storageFormat = getBaseLevelInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000429
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000430 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, width, height, 1, false);
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000431
432 if (mTexStorage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000433 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000434 const int storageLevels = mTexStorage->levelCount();
435
436 if ((level >= storageLevels && storageLevels != 0) ||
437 width != storageWidth ||
438 height != storageHeight ||
439 internalformat != storageFormat) // Discard mismatched storage
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000440 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000441 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
442 {
443 mImageArray[i]->markDirty();
444 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000445
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000446 delete mTexStorage;
447 mTexStorage = NULL;
448 mDirtyImages = true;
449 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000450 }
451}
452
Geoff Lang005df412013-10-16 14:12:50 -0400453void 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 +0000454{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +0000455 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Geoff Lang005df412013-10-16 14:12:50 -0400456 GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
457 : GetSizedInternalFormat(format, type, clientVersion);
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +0000458 redefineImage(level, sizedInternalFormat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000459
Jamie Madill8cc7d972013-10-10 15:51:55 -0400460 bool fastUnpacked = false;
461
Jamie Madill1beb1db2013-09-18 14:36:28 -0400462 // Attempt a fast gpu copy of the pixel data to the surface
Jamie Madill8cc7d972013-10-10 15:51:55 -0400463 if (isFastUnpackable(unpack, sizedInternalFormat) && isLevelComplete(level))
Jamie Madill1beb1db2013-09-18 14:36:28 -0400464 {
Jamie Madill8cc7d972013-10-10 15:51:55 -0400465 // Will try to create RT storage if it does not exist
466 rx::RenderTarget *destRenderTarget = getRenderTarget(level);
467 Box destArea(0, 0, 0, getWidth(level), getHeight(level), 1);
468
469 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget))
470 {
471 // Ensure we don't overwrite our newly initialized data
472 mImageArray[level]->markClean();
473
474 fastUnpacked = true;
475 }
Jamie Madill1beb1db2013-09-18 14:36:28 -0400476 }
Jamie Madill8cc7d972013-10-10 15:51:55 -0400477
478 if (!fastUnpacked)
Jamie Madill1beb1db2013-09-18 14:36:28 -0400479 {
480 Texture::setImage(unpack, type, pixels, mImageArray[level]);
481 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000482}
483
484void Texture2D::bindTexImage(egl::Surface *surface)
485{
486 releaseTexImage();
487
Geoff Lang005df412013-10-16 14:12:50 -0400488 GLenum internalformat = surface->getFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000489
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000490 mImageArray[0]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, surface->getWidth(), surface->getHeight(), 1, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000491
492 delete mTexStorage;
daniel@transgaming.comd8353dd2012-12-20 21:11:14 +0000493 mTexStorage = new rx::TextureStorageInterface2D(mRenderer, surface->getSwapChain());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000494
495 mDirtyImages = true;
496 mSurface = surface;
497 mSurface->setBoundTexture(this);
498}
499
500void Texture2D::releaseTexImage()
501{
502 if (mSurface)
503 {
504 mSurface->setBoundTexture(NULL);
505 mSurface = NULL;
506
507 if (mTexStorage)
508 {
509 delete mTexStorage;
510 mTexStorage = NULL;
511 }
512
513 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
514 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000515 mImageArray[i]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000516 }
517 }
518}
519
520void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
521{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000522 // 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 +0000523 redefineImage(level, format, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000524
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000525 Texture::setCompressedImage(imageSize, pixels, mImageArray[level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000526}
527
528void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
529{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000530 if (level < levelCount())
531 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000532 rx::Image *image = mImageArray[level];
Jamie Madill169d1112013-10-24 17:49:37 -0400533 if (image->copyToStorage(mTexStorage, level, xoffset, yoffset, width, height))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000534 {
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000535 image->markClean();
536 }
537 }
538}
539
Jamie Madill88f18f42013-09-18 14:36:19 -0400540void 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 +0000541{
Jamie Madill065e1a32013-10-10 15:11:50 -0400542 bool fastUnpacked = false;
543
544 if (isFastUnpackable(unpack, getInternalFormat(level)) && isLevelComplete(level))
545 {
546 rx::RenderTarget *renderTarget = getRenderTarget(level);
547 Box destArea(xoffset, yoffset, 0, width, height, 1);
548
549 if (renderTarget && fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, renderTarget))
550 {
551 // Ensure we don't overwrite our newly initialized data
552 mImageArray[level]->markClean();
553
554 fastUnpacked = true;
555 }
556 }
557
558 if (!fastUnpacked && Texture::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, mImageArray[level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000559 {
560 commitRect(level, xoffset, yoffset, width, height);
561 }
562}
563
564void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
565{
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000566 if (Texture::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000567 {
568 commitRect(level, xoffset, yoffset, width, height);
569 }
570}
571
572void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
573{
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +0000574 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Geoff Lang005df412013-10-16 14:12:50 -0400575 GLenum sizedInternalFormat = IsSizedInternalFormat(format, clientVersion) ? format
576 : GetSizedInternalFormat(format, GL_UNSIGNED_BYTE, clientVersion);
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +0000577 redefineImage(level, sizedInternalFormat, width, height);
shannon.woods@transgaming.com8a406682013-02-28 23:15:26 +0000578
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000579 if (!mImageArray[level]->isRenderableFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000580 {
shannon.woods%transgaming.com@gtempaccount.come5dcce72013-04-13 03:44:33 +0000581 mImageArray[level]->copy(0, 0, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000582 mDirtyImages = true;
583 }
584 else
585 {
Jamie Madille83d1a92013-10-24 17:49:33 -0400586 ensureRenderTarget();
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000587 mImageArray[level]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000588
589 if (width != 0 && height != 0 && level < levelCount())
590 {
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +0000591 gl::Rectangle sourceRect;
592 sourceRect.x = x;
593 sourceRect.width = width;
594 sourceRect.y = y;
595 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000596
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +0000597 mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000598 }
599 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000600}
601
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +0000602void 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 +0000603{
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +0000604 if (xoffset + width > mImageArray[level]->getWidth() || yoffset + height > mImageArray[level]->getHeight() || zoffset != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000605 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +0000606 return gl::error(GL_INVALID_VALUE);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000607 }
608
Jamie Madill07edd442013-07-19 16:36:58 -0400609 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
610 // the current level we're copying to is defined (with appropriate format, width & height)
611 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
612
613 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000614 {
shannon.woods%transgaming.com@gtempaccount.come5dcce72013-04-13 03:44:33 +0000615 mImageArray[level]->copy(xoffset, yoffset, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000616 mDirtyImages = true;
617 }
618 else
619 {
Jamie Madille83d1a92013-10-24 17:49:33 -0400620 ensureRenderTarget();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000621
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000622 if (level < levelCount())
623 {
Jamie Madill169d1112013-10-24 17:49:37 -0400624 updateStorageLevel(level);
Jamie Madill07edd442013-07-19 16:36:58 -0400625
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +0000626 GLuint clientVersion = mRenderer->getCurrentClientVersion();
627
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +0000628 gl::Rectangle sourceRect;
629 sourceRect.x = x;
630 sourceRect.width = width;
631 sourceRect.y = y;
632 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000633
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +0000634 mRenderer->copyImage(source, sourceRect,
Jamie Madilld3d2a342013-10-07 10:46:35 -0400635 gl::GetFormat(getBaseLevelInternalFormat(), clientVersion),
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +0000636 xoffset, yoffset, mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000637 }
638 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000639}
640
641void Texture2D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height)
642{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000643 for (int level = 0; level < levels; level++)
644 {
Jamie Madill73b5d062013-10-24 17:49:38 -0400645 GLsizei levelWidth = std::max(1, width >> level);
646 GLsizei levelHeight = std::max(1, height >> level);
647 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, levelWidth, levelHeight, 1, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000648 }
649
650 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
651 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000652 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000653 }
654
Jamie Madill73b5d062013-10-24 17:49:38 -0400655 mImmutable = true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000656
Jamie Madill73b5d062013-10-24 17:49:38 -0400657 setCompleteTexStorage(new rx::TextureStorageInterface2D(mRenderer, levels, internalformat, IsRenderTargetUsage(mUsage), width, height));
658}
659
660void Texture2D::setCompleteTexStorage(rx::TextureStorageInterface2D *newCompleteTexStorage)
661{
662 SafeDelete(mTexStorage);
663 mTexStorage = newCompleteTexStorage;
664
665 if (mTexStorage && mTexStorage->isManaged())
666 {
667 for (int level = 0; level < mTexStorage->levelCount(); level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000668 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000669 mImageArray[level]->setManagedSurface(mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000670 }
671 }
Jamie Madill73b5d062013-10-24 17:49:38 -0400672
673 mDirtyImages = true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000674}
675
676// Tests for 2D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85.
Jamie Madillf8989902013-07-19 16:36:58 -0400677bool Texture2D::isSamplerComplete(const SamplerState &samplerState) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000678{
Jamie Madilld3d2a342013-10-07 10:46:35 -0400679 GLsizei width = getBaseLevelWidth();
680 GLsizei height = getBaseLevelHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000681
682 if (width <= 0 || height <= 0)
683 {
684 return false;
685 }
686
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000687 if (!IsTextureFilteringSupported(getInternalFormat(0), mRenderer))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000688 {
Jamie Madillf8989902013-07-19 16:36:58 -0400689 if (samplerState.magFilter != GL_NEAREST ||
690 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000691 {
692 return false;
693 }
694 }
695
daniel@transgaming.comea32d482012-11-28 19:33:18 +0000696 bool npotSupport = mRenderer->getNonPower2TextureSupport();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000697
698 if (!npotSupport)
699 {
Jamie Madillf8989902013-07-19 16:36:58 -0400700 if ((samplerState.wrapS != GL_CLAMP_TO_EDGE && !isPow2(width)) ||
701 (samplerState.wrapT != GL_CLAMP_TO_EDGE && !isPow2(height)))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000702 {
703 return false;
704 }
705 }
706
Jamie Madillf8989902013-07-19 16:36:58 -0400707 if (IsMipmapFiltered(samplerState))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000708 {
709 if (!npotSupport)
710 {
711 if (!isPow2(width) || !isPow2(height))
712 {
713 return false;
714 }
715 }
716
717 if (!isMipmapComplete())
718 {
719 return false;
720 }
721 }
722
Geoff Langc82fc412013-07-10 14:43:42 -0400723 // OpenGLES 3.0.2 spec section 3.8.13 states that a texture is not mipmap complete if:
724 // The internalformat specified for the texture arrays is a sized internal depth or
725 // depth and stencil format (see table 3.13), the value of TEXTURE_COMPARE_-
726 // MODE is NONE, and either the magnification filter is not NEAREST or the mini-
727 // fication filter is neither NEAREST nor NEAREST_MIPMAP_NEAREST.
728 if (gl::GetDepthBits(getInternalFormat(0), mRenderer->getCurrentClientVersion()) > 0)
729 {
730 if (mSamplerState.compareMode == GL_NONE)
731 {
732 if ((mSamplerState.minFilter != GL_NEAREST && mSamplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST) ||
733 mSamplerState.magFilter != GL_NEAREST)
734 {
735 return false;
736 }
737 }
738 }
739
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000740 return true;
741}
742
743// Tests for 2D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
744bool Texture2D::isMipmapComplete() const
745{
Jamie Madill22f843a2013-10-24 17:49:36 -0400746 int q = mipLevels();
Jamie Madill07edd442013-07-19 16:36:58 -0400747
748 for (int level = 0; level <= q; level++)
749 {
750 if (!isLevelComplete(level))
751 {
752 return false;
753 }
754 }
755
756 return true;
757}
758
759bool Texture2D::isLevelComplete(int level) const
760{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000761 if (isImmutable())
762 {
763 return true;
764 }
765
Jamie Madilld3d2a342013-10-07 10:46:35 -0400766 GLsizei width = getBaseLevelWidth();
767 GLsizei height = getBaseLevelHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000768
769 if (width <= 0 || height <= 0)
770 {
771 return false;
772 }
773
Jamie Madill07edd442013-07-19 16:36:58 -0400774 // The base image level is complete if the width and height are positive
775 if (level == 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000776 {
Jamie Madill07edd442013-07-19 16:36:58 -0400777 return true;
778 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000779
Jamie Madill07edd442013-07-19 16:36:58 -0400780 ASSERT(level >= 1 && level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
781 rx::Image *image = mImageArray[level];
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000782
Jamie Madilld3d2a342013-10-07 10:46:35 -0400783 if (image->getInternalFormat() != getBaseLevelInternalFormat())
Jamie Madill07edd442013-07-19 16:36:58 -0400784 {
785 return false;
786 }
787
788 if (image->getWidth() != std::max(1, width >> level))
789 {
790 return false;
791 }
792
793 if (image->getHeight() != std::max(1, height >> level))
794 {
795 return false;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000796 }
797
798 return true;
799}
800
801bool Texture2D::isCompressed(GLint level) const
802{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000803 return IsFormatCompressed(getInternalFormat(level), mRenderer->getCurrentClientVersion());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000804}
805
806bool Texture2D::isDepth(GLint level) const
807{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000808 return GetDepthBits(getInternalFormat(level), mRenderer->getCurrentClientVersion()) > 0;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000809}
810
daniel@transgaming.comf032cb82012-10-31 19:51:52 +0000811// Constructs a native texture resource from the texture images
Jamie Madill73b5d062013-10-24 17:49:38 -0400812void Texture2D::initializeStorage(bool renderTarget)
813{
814 // Only initialize the first time this texture is used as a render target or shader resource
815 if (mTexStorage)
816 {
817 return;
818 }
819
820 // do not attempt to create storage for nonexistant data
821 if (!isLevelComplete(0))
822 {
823 return;
824 }
825
826 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
827
828 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
829 ASSERT(mTexStorage);
830
831 // flush image data to the storage
832 updateStorage();
833}
834
835rx::TextureStorageInterface2D *Texture2D::createCompleteStorage(bool renderTarget) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000836{
Jamie Madilld3d2a342013-10-07 10:46:35 -0400837 GLsizei width = getBaseLevelWidth();
838 GLsizei height = getBaseLevelHeight();
daniel@transgaming.come6a09842012-09-17 21:28:55 +0000839
Jamie Madill73b5d062013-10-24 17:49:38 -0400840 ASSERT(width > 0 && height > 0);
daniel@transgaming.come6a09842012-09-17 21:28:55 +0000841
Jamie Madill73b5d062013-10-24 17:49:38 -0400842 // use existing storage level count, when previously specified by TexStorage*D
843 GLint levels = (mTexStorage ? mTexStorage->levelCount() : creationLevels(width, height));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000844
Jamie Madill73b5d062013-10-24 17:49:38 -0400845 return new rx::TextureStorageInterface2D(mRenderer, levels, getBaseLevelInternalFormat(), renderTarget, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000846}
847
Jamie Madill169d1112013-10-24 17:49:37 -0400848void Texture2D::updateStorage()
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000849{
Jamie Madilld9b9a502013-10-10 17:46:13 -0400850 int storageLevels = levelCount();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000851
Jamie Madilld9b9a502013-10-10 17:46:13 -0400852 for (int level = 0; level < storageLevels; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000853 {
Jamie Madilld9b9a502013-10-10 17:46:13 -0400854 if (isLevelComplete(level))
855 {
Jamie Madill169d1112013-10-24 17:49:37 -0400856 updateStorageLevel(level);
Jamie Madilld9b9a502013-10-10 17:46:13 -0400857 }
Jamie Madill07edd442013-07-19 16:36:58 -0400858 }
859}
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000860
Jamie Madill169d1112013-10-24 17:49:37 -0400861void Texture2D::updateStorageLevel(int level)
Jamie Madill07edd442013-07-19 16:36:58 -0400862{
863 ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
Jamie Madillaee7ad82013-10-10 16:07:32 -0400864 ASSERT(isLevelComplete(level));
Jamie Madill07edd442013-07-19 16:36:58 -0400865
Jamie Madillaee7ad82013-10-10 16:07:32 -0400866 if (mImageArray[level]->isDirty())
Jamie Madill07edd442013-07-19 16:36:58 -0400867 {
Jamie Madillaee7ad82013-10-10 16:07:32 -0400868 commitRect(level, 0, 0, getWidth(level), getHeight(level));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000869 }
870}
871
Jamie Madille83d1a92013-10-24 17:49:33 -0400872bool Texture2D::ensureRenderTarget()
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000873{
Jamie Madill73b5d062013-10-24 17:49:38 -0400874 initializeStorage(true);
875
876 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0)
Jamie Madille83d1a92013-10-24 17:49:33 -0400877 {
Jamie Madill73b5d062013-10-24 17:49:38 -0400878 ASSERT(mTexStorage);
879 if (!mTexStorage->isRenderTarget())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000880 {
Jamie Madill73b5d062013-10-24 17:49:38 -0400881 rx::TextureStorageInterface2D *newRenderTargetStorage = createCompleteStorage(true);
882
883 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
884 {
885 delete newRenderTargetStorage;
Jamie Madille83d1a92013-10-24 17:49:33 -0400886 return gl::error(GL_OUT_OF_MEMORY, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000887 }
Jamie Madill73b5d062013-10-24 17:49:38 -0400888
889 setCompleteTexStorage(newRenderTargetStorage);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000890 }
891 }
892
Jamie Madille83d1a92013-10-24 17:49:33 -0400893 return (mTexStorage && mTexStorage->isRenderTarget());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000894}
895
896void Texture2D::generateMipmaps()
897{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000898 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Jamie Madill22f843a2013-10-24 17:49:36 -0400899 int q = mipLevels();
900 for (int level = 1; level <= q; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000901 {
Jamie Madill22f843a2013-10-24 17:49:36 -0400902 redefineImage(level, getBaseLevelInternalFormat(),
903 std::max(getBaseLevelWidth() >> level, 1),
904 std::max(getBaseLevelHeight() >> level, 1));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000905 }
906
907 if (mTexStorage && mTexStorage->isRenderTarget())
908 {
Jamie Madill22f843a2013-10-24 17:49:36 -0400909 for (int level = 1; level <= q; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000910 {
Jamie Madill22f843a2013-10-24 17:49:36 -0400911 mTexStorage->generateMipmap(level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000912
Jamie Madill22f843a2013-10-24 17:49:36 -0400913 mImageArray[level]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000914 }
915 }
916 else
917 {
Jamie Madill22f843a2013-10-24 17:49:36 -0400918 for (int level = 1; level <= q; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000919 {
Jamie Madill22f843a2013-10-24 17:49:36 -0400920 mRenderer->generateMipmap(mImageArray[level], mImageArray[level - 1]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000921 }
922 }
923}
924
Jamie Madilld3d2a342013-10-07 10:46:35 -0400925const rx::Image *Texture2D::getBaseLevelImage() const
926{
927 return mImageArray[0];
928}
929
Jamie Madill2ebab852013-10-24 17:49:42 -0400930rx::TextureStorageInterface *Texture2D::getBaseLevelStorage()
931{
932 return mTexStorage;
933}
934
Geoff Lang8040f572013-07-25 16:49:54 -0400935Renderbuffer *Texture2D::getRenderbuffer(GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000936{
Geoff Lang8040f572013-07-25 16:49:54 -0400937 Renderbuffer *renderBuffer = mRenderbufferProxies.get(level, 0);
938 if (!renderBuffer)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000939 {
Geoff Lang8040f572013-07-25 16:49:54 -0400940 renderBuffer = new Renderbuffer(mRenderer, id(), new RenderbufferTexture2D(this, level));
941 mRenderbufferProxies.add(level, 0, renderBuffer);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000942 }
943
Geoff Lang8040f572013-07-25 16:49:54 -0400944 return renderBuffer;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000945}
946
Geoff Lang8040f572013-07-25 16:49:54 -0400947unsigned int Texture2D::getRenderTargetSerial(GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000948{
Jamie Madille83d1a92013-10-24 17:49:33 -0400949 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(level) : 0);
Geoff Lang8040f572013-07-25 16:49:54 -0400950}
951
952rx::RenderTarget *Texture2D::getRenderTarget(GLint level)
953{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000954 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -0400955 if (!ensureRenderTarget())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000956 {
957 return NULL;
958 }
959
Jamie Madill169d1112013-10-24 17:49:37 -0400960 updateStorageLevel(level);
Geoff Lang8040f572013-07-25 16:49:54 -0400961
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000962 // ensure this is NOT a depth texture
Geoff Lang8040f572013-07-25 16:49:54 -0400963 if (isDepth(level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000964 {
965 return NULL;
966 }
daniel@transgaming.com34da3972012-12-20 21:10:29 +0000967
Geoff Lang8040f572013-07-25 16:49:54 -0400968 return mTexStorage->getRenderTarget(level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000969}
970
Geoff Lang8040f572013-07-25 16:49:54 -0400971rx::RenderTarget *Texture2D::getDepthSencil(GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000972{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000973 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -0400974 if (!ensureRenderTarget())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000975 {
976 return NULL;
977 }
978
Jamie Madill169d1112013-10-24 17:49:37 -0400979 updateStorageLevel(level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000980
981 // ensure this is actually a depth texture
Geoff Lang8040f572013-07-25 16:49:54 -0400982 if (!isDepth(level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000983 {
984 return NULL;
985 }
Geoff Lang8040f572013-07-25 16:49:54 -0400986
987 return mTexStorage->getRenderTarget(level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000988}
989
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +0000990int Texture2D::levelCount()
991{
shannon.woods@transgaming.com5016f8e2013-02-28 23:20:57 +0000992 return mTexStorage ? mTexStorage->levelCount() : 0;
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +0000993}
994
Geoff Lang4907f2c2013-07-25 12:53:57 -0400995TextureCubeMap::TextureCubeMap(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_CUBE_MAP)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000996{
997 mTexStorage = NULL;
998 for (int i = 0; i < 6; i++)
999 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001000 for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
1001 {
daniel@transgaming.com244e1832012-12-20 20:52:35 +00001002 mImageArray[i][j] = renderer->createImage();
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001003 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001004 }
1005}
1006
1007TextureCubeMap::~TextureCubeMap()
1008{
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 {
1013 delete mImageArray[i][j];
1014 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001015 }
1016
1017 delete mTexStorage;
1018 mTexStorage = NULL;
1019}
1020
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001021GLsizei TextureCubeMap::getWidth(GLenum target, GLint level) const
1022{
1023 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Jamie Madill2db197c2013-10-24 17:49:35 -04001024 return mImageArray[targetToIndex(target)][level]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001025 else
1026 return 0;
1027}
1028
1029GLsizei TextureCubeMap::getHeight(GLenum target, GLint level) const
1030{
1031 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Jamie Madill2db197c2013-10-24 17:49:35 -04001032 return mImageArray[targetToIndex(target)][level]->getHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001033 else
1034 return 0;
1035}
1036
1037GLenum TextureCubeMap::getInternalFormat(GLenum target, GLint level) const
1038{
1039 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Jamie Madill2db197c2013-10-24 17:49:35 -04001040 return mImageArray[targetToIndex(target)][level]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001041 else
1042 return GL_NONE;
1043}
1044
daniel@transgaming.com20d36662012-10-31 19:51:43 +00001045GLenum TextureCubeMap::getActualFormat(GLenum target, GLint level) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001046{
1047 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Jamie Madill2db197c2013-10-24 17:49:35 -04001048 return mImageArray[targetToIndex(target)][level]->getActualFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001049 else
1050 return D3DFMT_UNKNOWN;
1051}
1052
Geoff Lang005df412013-10-16 14:12:50 -04001053void 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 +00001054{
Jamie Madill88f18f42013-09-18 14:36:19 -04001055 setImage(0, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001056}
1057
Geoff Lang005df412013-10-16 14:12:50 -04001058void 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 +00001059{
Jamie Madill88f18f42013-09-18 14:36:19 -04001060 setImage(1, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001061}
1062
Geoff Lang005df412013-10-16 14:12:50 -04001063void 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 +00001064{
Jamie Madill88f18f42013-09-18 14:36:19 -04001065 setImage(2, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001066}
1067
Geoff Lang005df412013-10-16 14:12:50 -04001068void 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 +00001069{
Jamie Madill88f18f42013-09-18 14:36:19 -04001070 setImage(3, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001071}
1072
Geoff Lang005df412013-10-16 14:12:50 -04001073void 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 +00001074{
Jamie Madill88f18f42013-09-18 14:36:19 -04001075 setImage(4, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001076}
1077
Geoff Lang005df412013-10-16 14:12:50 -04001078void 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 +00001079{
Jamie Madill88f18f42013-09-18 14:36:19 -04001080 setImage(5, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001081}
1082
Jamie Madill2db197c2013-10-24 17:49:35 -04001083void 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 +00001084{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001085 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
Jamie Madill2db197c2013-10-24 17:49:35 -04001086 int faceIndex = targetToIndex(target);
1087 redefineImage(faceIndex, level, format, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001088
Jamie Madill2db197c2013-10-24 17:49:35 -04001089 Texture::setCompressedImage(imageSize, pixels, mImageArray[faceIndex][level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001090}
1091
Jamie Madill2db197c2013-10-24 17:49:35 -04001092void TextureCubeMap::commitRect(int faceIndex, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001093{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001094 if (level < levelCount())
1095 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001096 rx::Image *image = mImageArray[faceIndex][level];
Jamie Madill169d1112013-10-24 17:49:37 -04001097 if (image->copyToStorage(mTexStorage, faceIndex, level, xoffset, yoffset, width, height))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001098 image->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001099 }
1100}
1101
Jamie Madill88f18f42013-09-18 14:36:19 -04001102void 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 +00001103{
Jamie Madill2db197c2013-10-24 17:49:35 -04001104 int faceIndex = targetToIndex(target);
1105 if (Texture::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, mImageArray[faceIndex][level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001106 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001107 commitRect(faceIndex, level, xoffset, yoffset, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001108 }
1109}
1110
1111void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1112{
Jamie Madill2db197c2013-10-24 17:49:35 -04001113 int faceIndex = targetToIndex(target);
1114 if (Texture::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[faceIndex][level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001115 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001116 commitRect(faceIndex, level, xoffset, yoffset, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001117 }
1118}
1119
1120// Tests for cube map sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 86.
Jamie Madillf8989902013-07-19 16:36:58 -04001121bool TextureCubeMap::isSamplerComplete(const SamplerState &samplerState) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001122{
Jamie Madilld3d2a342013-10-07 10:46:35 -04001123 int size = getBaseLevelWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001124
Jamie Madillf8989902013-07-19 16:36:58 -04001125 bool mipmapping = IsMipmapFiltered(samplerState);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001126
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001127 if (!IsTextureFilteringSupported(getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0), mRenderer))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001128 {
Jamie Madillf8989902013-07-19 16:36:58 -04001129 if (samplerState.magFilter != GL_NEAREST ||
1130 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001131 {
1132 return false;
1133 }
1134 }
1135
daniel@transgaming.comea32d482012-11-28 19:33:18 +00001136 if (!isPow2(size) && !mRenderer->getNonPower2TextureSupport())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001137 {
Jamie Madillf8989902013-07-19 16:36:58 -04001138 if (samplerState.wrapS != GL_CLAMP_TO_EDGE || samplerState.wrapT != GL_CLAMP_TO_EDGE || mipmapping)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001139 {
1140 return false;
1141 }
1142 }
1143
1144 if (!mipmapping)
1145 {
1146 if (!isCubeComplete())
1147 {
1148 return false;
1149 }
1150 }
1151 else
1152 {
1153 if (!isMipmapCubeComplete()) // Also tests for isCubeComplete()
1154 {
1155 return false;
1156 }
1157 }
1158
1159 return true;
1160}
1161
1162// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1163bool TextureCubeMap::isCubeComplete() const
1164{
Jamie Madillc1f8b162013-10-07 10:46:38 -04001165 int baseWidth = getBaseLevelWidth();
1166 int baseHeight = getBaseLevelHeight();
1167 GLenum baseFormat = getBaseLevelInternalFormat();
1168
1169 if (baseWidth <= 0 || baseWidth != baseHeight)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001170 {
1171 return false;
1172 }
1173
Jamie Madill2db197c2013-10-24 17:49:35 -04001174 for (int faceIndex = 1; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001175 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001176 const rx::Image &faceBaseImage = *mImageArray[faceIndex][0];
Jamie Madillc1f8b162013-10-07 10:46:38 -04001177
1178 if (faceBaseImage.getWidth() != baseWidth ||
1179 faceBaseImage.getHeight() != baseHeight ||
1180 faceBaseImage.getInternalFormat() != baseFormat )
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001181 {
1182 return false;
1183 }
1184 }
1185
1186 return true;
1187}
1188
1189bool TextureCubeMap::isMipmapCubeComplete() const
1190{
1191 if (isImmutable())
1192 {
1193 return true;
1194 }
1195
1196 if (!isCubeComplete())
1197 {
1198 return false;
1199 }
1200
Jamie Madill22f843a2013-10-24 17:49:36 -04001201 int q = mipLevels();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001202
1203 for (int face = 0; face < 6; face++)
1204 {
1205 for (int level = 1; level <= q; level++)
1206 {
Jamie Madill07edd442013-07-19 16:36:58 -04001207 if (!isFaceLevelComplete(face, level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001208 {
1209 return false;
1210 }
1211 }
1212 }
1213
1214 return true;
1215}
1216
Jamie Madill2db197c2013-10-24 17:49:35 -04001217bool TextureCubeMap::isFaceLevelComplete(int faceIndex, int level) const
Jamie Madill07edd442013-07-19 16:36:58 -04001218{
Jamie Madill2db197c2013-10-24 17:49:35 -04001219 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
Jamie Madill07edd442013-07-19 16:36:58 -04001220
1221 if (isImmutable())
1222 {
1223 return true;
1224 }
1225
Jamie Madilld3d2a342013-10-07 10:46:35 -04001226 int baseSize = getBaseLevelWidth();
Jamie Madill07edd442013-07-19 16:36:58 -04001227
Jamie Madilld3d2a342013-10-07 10:46:35 -04001228 if (baseSize <= 0)
Jamie Madill07edd442013-07-19 16:36:58 -04001229 {
1230 return false;
1231 }
1232
Jamie Madilld3d2a342013-10-07 10:46:35 -04001233 // "isCubeComplete" checks for base level completeness and we must call that
1234 // to determine if any face at level 0 is complete. We omit that check here
1235 // to avoid re-checking cube-completeness for every face at level 0.
Jamie Madill07edd442013-07-19 16:36:58 -04001236 if (level == 0)
1237 {
1238 return true;
1239 }
1240
Jamie Madilld3d2a342013-10-07 10:46:35 -04001241 // Check that non-zero levels are consistent with the base level.
Jamie Madill2db197c2013-10-24 17:49:35 -04001242 const rx::Image *faceLevelImage = mImageArray[faceIndex][level];
Jamie Madill07edd442013-07-19 16:36:58 -04001243
Jamie Madilld3d2a342013-10-07 10:46:35 -04001244 if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat())
Jamie Madill07edd442013-07-19 16:36:58 -04001245 {
1246 return false;
1247 }
1248
Jamie Madilld3d2a342013-10-07 10:46:35 -04001249 if (faceLevelImage->getWidth() != std::max(1, baseSize >> level))
Jamie Madill07edd442013-07-19 16:36:58 -04001250 {
1251 return false;
1252 }
1253
1254 return true;
1255}
1256
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001257bool TextureCubeMap::isCompressed(GLenum target, GLint level) const
1258{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001259 return IsFormatCompressed(getInternalFormat(target, level), mRenderer->getCurrentClientVersion());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001260}
1261
Geoff Lang8040f572013-07-25 16:49:54 -04001262bool TextureCubeMap::isDepth(GLenum target, GLint level) const
1263{
1264 return GetDepthBits(getInternalFormat(target, level), mRenderer->getCurrentClientVersion()) > 0;
1265}
1266
Jamie Madill73b5d062013-10-24 17:49:38 -04001267void TextureCubeMap::initializeStorage(bool renderTarget)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001268{
Jamie Madill3c0989c2013-10-24 17:49:39 -04001269 // Only initialize the first time this texture is used as a render target or shader resource
1270 if (mTexStorage)
1271 {
1272 return;
1273 }
1274
1275 // do not attempt to create storage for nonexistant data
1276 if (!isFaceLevelComplete(0, 0))
1277 {
1278 return;
1279 }
1280
1281 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
1282
1283 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
1284 ASSERT(mTexStorage);
1285
1286 // flush image data to the storage
1287 updateStorage();
1288}
1289
1290rx::TextureStorageInterfaceCube *TextureCubeMap::createCompleteStorage(bool renderTarget) const
1291{
Jamie Madilld3d2a342013-10-07 10:46:35 -04001292 GLsizei size = getBaseLevelWidth();
daniel@transgaming.come6a09842012-09-17 21:28:55 +00001293
Jamie Madill3c0989c2013-10-24 17:49:39 -04001294 ASSERT(size > 0);
daniel@transgaming.come6a09842012-09-17 21:28:55 +00001295
Jamie Madill3c0989c2013-10-24 17:49:39 -04001296 // use existing storage level count, when previously specified by TexStorage*D
1297 GLint levels = (mTexStorage ? mTexStorage->levelCount() : creationLevels(size));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001298
Jamie Madill3c0989c2013-10-24 17:49:39 -04001299 return new rx::TextureStorageInterfaceCube(mRenderer, levels, getBaseLevelInternalFormat(), renderTarget, size);
1300}
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001301
Jamie Madill3c0989c2013-10-24 17:49:39 -04001302void TextureCubeMap::setCompleteTexStorage(rx::TextureStorageInterfaceCube *newCompleteTexStorage)
1303{
1304 SafeDelete(mTexStorage);
1305 mTexStorage = newCompleteTexStorage;
1306
1307 if (mTexStorage && mTexStorage->isManaged())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001308 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001309 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001310 {
Jamie Madill3c0989c2013-10-24 17:49:39 -04001311 for (int level = 0; level < mTexStorage->levelCount(); level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001312 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001313 mImageArray[faceIndex][level]->setManagedSurface(mTexStorage, faceIndex, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001314 }
1315 }
1316 }
1317
1318 mDirtyImages = true;
1319}
1320
Jamie Madill169d1112013-10-24 17:49:37 -04001321void TextureCubeMap::updateStorage()
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001322{
Jamie Madilld9b9a502013-10-10 17:46:13 -04001323 int storageLevels = levelCount();
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +00001324
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001325 for (int face = 0; face < 6; face++)
1326 {
Jamie Madilld9b9a502013-10-10 17:46:13 -04001327 for (int level = 0; level < storageLevels; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001328 {
Jamie Madilld9b9a502013-10-10 17:46:13 -04001329 if (isFaceLevelComplete(face, level))
1330 {
Jamie Madill169d1112013-10-24 17:49:37 -04001331 updateStorageFaceLevel(face, level);
Jamie Madilld9b9a502013-10-10 17:46:13 -04001332 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001333 }
1334 }
1335}
1336
Jamie Madill169d1112013-10-24 17:49:37 -04001337void TextureCubeMap::updateStorageFaceLevel(int faceIndex, int level)
Jamie Madill07edd442013-07-19 16:36:58 -04001338{
Jamie Madill2db197c2013-10-24 17:49:35 -04001339 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1340 rx::Image *image = mImageArray[faceIndex][level];
Jamie Madill07edd442013-07-19 16:36:58 -04001341
1342 if (image->isDirty())
1343 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001344 commitRect(faceIndex, level, 0, 0, image->getWidth(), image->getHeight());
Jamie Madill07edd442013-07-19 16:36:58 -04001345 }
1346}
1347
Jamie Madille83d1a92013-10-24 17:49:33 -04001348bool TextureCubeMap::ensureRenderTarget()
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001349{
Jamie Madill3c0989c2013-10-24 17:49:39 -04001350 initializeStorage(true);
1351
1352 if (getBaseLevelWidth() > 0)
Jamie Madille83d1a92013-10-24 17:49:33 -04001353 {
Jamie Madill3c0989c2013-10-24 17:49:39 -04001354 ASSERT(mTexStorage);
1355 if (!mTexStorage->isRenderTarget())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001356 {
Jamie Madill3c0989c2013-10-24 17:49:39 -04001357 rx::TextureStorageInterfaceCube *newRenderTargetStorage = createCompleteStorage(true);
1358
1359 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001360 {
Jamie Madill3c0989c2013-10-24 17:49:39 -04001361 delete newRenderTargetStorage;
Jamie Madille83d1a92013-10-24 17:49:33 -04001362 return gl::error(GL_OUT_OF_MEMORY, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001363 }
Jamie Madill3c0989c2013-10-24 17:49:39 -04001364
1365 setCompleteTexStorage(newRenderTargetStorage);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001366 }
1367 }
1368
Jamie Madille83d1a92013-10-24 17:49:33 -04001369 return (mTexStorage && mTexStorage->isRenderTarget());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001370}
1371
Geoff Lang005df412013-10-16 14:12:50 -04001372void 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 +00001373{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001374 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Geoff Lang005df412013-10-16 14:12:50 -04001375 GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
1376 : GetSizedInternalFormat(format, type, clientVersion);
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001377
1378 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001379
Jamie Madill88f18f42013-09-18 14:36:19 -04001380 Texture::setImage(unpack, type, pixels, mImageArray[faceIndex][level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001381}
1382
Jamie Madill2db197c2013-10-24 17:49:35 -04001383int TextureCubeMap::targetToIndex(GLenum target)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001384{
1385 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
1386 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
1387 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
1388 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
1389 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
1390
Jamie Madill2db197c2013-10-24 17:49:35 -04001391 return target - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001392}
1393
Jamie Madill2db197c2013-10-24 17:49:35 -04001394void TextureCubeMap::redefineImage(int faceIndex, GLint level, GLenum internalformat, GLsizei width, GLsizei height)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001395{
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001396 // If there currently is a corresponding storage texture image, it has these parameters
Jamie Madilld3d2a342013-10-07 10:46:35 -04001397 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1398 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
Geoff Lang005df412013-10-16 14:12:50 -04001399 const GLenum storageFormat = getBaseLevelInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001400
Jamie Madill2db197c2013-10-24 17:49:35 -04001401 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, width, height, 1, false);
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001402
1403 if (mTexStorage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001404 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001405 const int storageLevels = mTexStorage->levelCount();
1406
1407 if ((level >= storageLevels && storageLevels != 0) ||
1408 width != storageWidth ||
1409 height != storageHeight ||
1410 internalformat != storageFormat) // Discard mismatched storage
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001411 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001412 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001413 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001414 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001415 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001416 mImageArray[faceIndex][level]->markDirty();
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001417 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001418 }
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001419
1420 delete mTexStorage;
1421 mTexStorage = NULL;
1422
1423 mDirtyImages = true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001424 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001425 }
1426}
1427
1428void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1429{
Jamie Madill2db197c2013-10-24 17:49:35 -04001430 int faceIndex = targetToIndex(target);
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001431 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Geoff Lang005df412013-10-16 14:12:50 -04001432 GLenum sizedInternalFormat = IsSizedInternalFormat(format, clientVersion) ? format
1433 : GetSizedInternalFormat(format, GL_UNSIGNED_BYTE, clientVersion);
Jamie Madill2db197c2013-10-24 17:49:35 -04001434 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001435
Jamie Madill2db197c2013-10-24 17:49:35 -04001436 if (!mImageArray[faceIndex][level]->isRenderableFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001437 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001438 mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001439 mDirtyImages = true;
1440 }
1441 else
1442 {
Jamie Madille83d1a92013-10-24 17:49:33 -04001443 ensureRenderTarget();
Jamie Madill2db197c2013-10-24 17:49:35 -04001444 mImageArray[faceIndex][level]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001445
1446 ASSERT(width == height);
1447
1448 if (width > 0 && level < levelCount())
1449 {
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +00001450 gl::Rectangle sourceRect;
1451 sourceRect.x = x;
1452 sourceRect.width = width;
1453 sourceRect.y = y;
1454 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001455
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +00001456 mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001457 }
1458 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001459}
1460
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001461void 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 +00001462{
Jamie Madill2db197c2013-10-24 17:49:35 -04001463 int faceIndex = targetToIndex(target);
1464
1465 GLsizei size = mImageArray[faceIndex][level]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001466
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001467 if (xoffset + width > size || yoffset + height > size || zoffset != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001468 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +00001469 return gl::error(GL_INVALID_VALUE);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001470 }
1471
Jamie Madilld3d2a342013-10-07 10:46:35 -04001472 // We can only make our texture storage to a render target if the level we're copying *to* is complete
1473 // and the base level is cube-complete. The base level must be cube complete (common case) because we cannot
1474 // rely on the "getBaseLevel*" methods reliably otherwise.
Jamie Madill2db197c2013-10-24 17:49:35 -04001475 bool canCreateRenderTarget = isFaceLevelComplete(faceIndex, level) && isCubeComplete();
Jamie Madill07edd442013-07-19 16:36:58 -04001476
Jamie Madill2db197c2013-10-24 17:49:35 -04001477 if (!mImageArray[faceIndex][level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001478 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001479 mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001480 mDirtyImages = true;
1481 }
1482 else
1483 {
Jamie Madille83d1a92013-10-24 17:49:33 -04001484 ensureRenderTarget();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001485
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001486 if (level < levelCount())
1487 {
Jamie Madill169d1112013-10-24 17:49:37 -04001488 updateStorageFaceLevel(faceIndex, level);
Jamie Madill07edd442013-07-19 16:36:58 -04001489
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001490 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1491
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +00001492 gl::Rectangle sourceRect;
1493 sourceRect.x = x;
1494 sourceRect.width = width;
1495 sourceRect.y = y;
1496 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001497
Jamie Madilld3d2a342013-10-07 10:46:35 -04001498 mRenderer->copyImage(source, sourceRect, gl::GetFormat(getBaseLevelInternalFormat(), clientVersion),
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +00001499 xoffset, yoffset, mTexStorage, target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001500 }
1501 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001502}
1503
1504void TextureCubeMap::storage(GLsizei levels, GLenum internalformat, GLsizei size)
1505{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001506 for (int level = 0; level < levels; level++)
1507 {
Geoff Langd3110192013-09-24 11:52:47 -04001508 GLsizei mipSize = std::max(1, size >> level);
Jamie Madill2db197c2013-10-24 17:49:35 -04001509 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001510 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001511 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, mipSize, mipSize, 1, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001512 }
1513 }
1514
1515 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1516 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001517 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001518 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001519 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, GL_NONE, 0, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001520 }
1521 }
1522
Jamie Madill3c0989c2013-10-24 17:49:39 -04001523 mImmutable = true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001524
Jamie Madill3c0989c2013-10-24 17:49:39 -04001525 setCompleteTexStorage(new rx::TextureStorageInterfaceCube(mRenderer, levels, internalformat, IsRenderTargetUsage(mUsage), size));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001526}
1527
1528void TextureCubeMap::generateMipmaps()
1529{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001530 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Jamie Madill22f843a2013-10-24 17:49:36 -04001531 int q = mipLevels();
Jamie Madill2db197c2013-10-24 17:49:35 -04001532 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001533 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001534 for (int level = 1; level <= q; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001535 {
Jamie Madill22f843a2013-10-24 17:49:36 -04001536 int faceLevelSize = (std::max(mImageArray[faceIndex][0]->getWidth() >> level, 1));
1537 redefineImage(faceIndex, level, mImageArray[faceIndex][0]->getInternalFormat(), faceLevelSize, faceLevelSize);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001538 }
1539 }
1540
1541 if (mTexStorage && mTexStorage->isRenderTarget())
1542 {
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 Madill2db197c2013-10-24 17:49:35 -04001547 mTexStorage->generateMipmap(faceIndex, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001548
Jamie Madill2db197c2013-10-24 17:49:35 -04001549 mImageArray[faceIndex][level]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001550 }
1551 }
1552 }
1553 else
1554 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001555 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001556 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001557 for (int level = 1; level <= q; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001558 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001559 mRenderer->generateMipmap(mImageArray[faceIndex][level], mImageArray[faceIndex][level - 1]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001560 }
1561 }
1562 }
1563}
1564
Jamie Madilld3d2a342013-10-07 10:46:35 -04001565const rx::Image *TextureCubeMap::getBaseLevelImage() const
1566{
1567 // Note: if we are not cube-complete, there is no single base level image that can describe all
1568 // cube faces, so this method is only well-defined for a cube-complete base level.
1569 return mImageArray[0][0];
1570}
1571
Jamie Madill2ebab852013-10-24 17:49:42 -04001572rx::TextureStorageInterface *TextureCubeMap::getBaseLevelStorage()
1573{
1574 return mTexStorage;
1575}
1576
Geoff Lang8040f572013-07-25 16:49:54 -04001577Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target, GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001578{
1579 if (!IsCubemapTextureTarget(target))
1580 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +00001581 return gl::error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001582 }
1583
Jamie Madill2db197c2013-10-24 17:49:35 -04001584 int faceIndex = targetToIndex(target);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001585
Jamie Madill2db197c2013-10-24 17:49:35 -04001586 Renderbuffer *renderBuffer = mRenderbufferProxies.get(level, faceIndex);
Geoff Lang8040f572013-07-25 16:49:54 -04001587 if (!renderBuffer)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001588 {
Geoff Lang8040f572013-07-25 16:49:54 -04001589 renderBuffer = new Renderbuffer(mRenderer, id(), new RenderbufferTextureCubeMap(this, target, level));
Jamie Madill2db197c2013-10-24 17:49:35 -04001590 mRenderbufferProxies.add(level, faceIndex, renderBuffer);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001591 }
1592
Geoff Lang8040f572013-07-25 16:49:54 -04001593 return renderBuffer;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001594}
1595
Jamie Madill2db197c2013-10-24 17:49:35 -04001596unsigned int TextureCubeMap::getRenderTargetSerial(GLenum target, GLint level)
Geoff Lang8040f572013-07-25 16:49:54 -04001597{
Jamie Madill2db197c2013-10-24 17:49:35 -04001598 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(target, level) : 0);
Geoff Lang8040f572013-07-25 16:49:54 -04001599}
1600
1601rx::RenderTarget *TextureCubeMap::getRenderTarget(GLenum target, GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001602{
1603 ASSERT(IsCubemapTextureTarget(target));
1604
1605 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04001606 if (!ensureRenderTarget())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001607 {
1608 return NULL;
1609 }
1610
Jamie Madill169d1112013-10-24 17:49:37 -04001611 updateStorageFaceLevel(targetToIndex(target), level);
Geoff Lang8040f572013-07-25 16:49:54 -04001612
1613 // ensure this is NOT a depth texture
1614 if (isDepth(target, level))
1615 {
1616 return NULL;
1617 }
1618
1619 return mTexStorage->getRenderTarget(target, level);
1620}
1621
1622rx::RenderTarget *TextureCubeMap::getDepthStencil(GLenum target, GLint level)
1623{
1624 ASSERT(IsCubemapTextureTarget(target));
1625
1626 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04001627 if (!ensureRenderTarget())
Geoff Lang8040f572013-07-25 16:49:54 -04001628 {
1629 return NULL;
1630 }
1631
Jamie Madill169d1112013-10-24 17:49:37 -04001632 updateStorageFaceLevel(targetToIndex(target), level);
Geoff Lang8040f572013-07-25 16:49:54 -04001633
1634 // ensure this is a depth texture
1635 if (!isDepth(target, level))
1636 {
1637 return NULL;
1638 }
1639
1640 return mTexStorage->getRenderTarget(target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001641}
1642
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +00001643int TextureCubeMap::levelCount()
1644{
1645 return mTexStorage ? mTexStorage->levelCount() - getLodOffset() : 0;
1646}
1647
Geoff Lang4907f2c2013-07-25 12:53:57 -04001648Texture3D::Texture3D(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_3D)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001649{
1650 mTexStorage = NULL;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001651
1652 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1653 {
1654 mImageArray[i] = renderer->createImage();
1655 }
1656}
1657
1658Texture3D::~Texture3D()
1659{
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001660 delete mTexStorage;
1661 mTexStorage = NULL;
1662
1663 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1664 {
1665 delete mImageArray[i];
1666 }
1667}
1668
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001669GLsizei Texture3D::getWidth(GLint level) const
1670{
1671 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getWidth() : 0;
1672}
1673
1674GLsizei Texture3D::getHeight(GLint level) const
1675{
1676 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getHeight() : 0;
1677}
1678
1679GLsizei Texture3D::getDepth(GLint level) const
1680{
1681 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getDepth() : 0;
1682}
1683
1684GLenum Texture3D::getInternalFormat(GLint level) const
1685{
1686 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getInternalFormat() : GL_NONE;
1687}
1688
1689GLenum Texture3D::getActualFormat(GLint level) const
1690{
1691 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getActualFormat() : D3DFMT_UNKNOWN;
1692}
1693
1694bool Texture3D::isCompressed(GLint level) const
1695{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001696 return IsFormatCompressed(getInternalFormat(level), mRenderer->getCurrentClientVersion());
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001697}
1698
1699bool Texture3D::isDepth(GLint level) const
1700{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001701 return GetDepthBits(getInternalFormat(level), mRenderer->getCurrentClientVersion()) > 0;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001702}
1703
Geoff Lang005df412013-10-16 14:12:50 -04001704void 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 +00001705{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001706 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Geoff Lang005df412013-10-16 14:12:50 -04001707 GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
1708 : GetSizedInternalFormat(format, type, clientVersion);
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001709 redefineImage(level, sizedInternalFormat, width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001710
Jamie Madilla2d4e552013-10-10 15:12:01 -04001711 bool fastUnpacked = false;
1712
1713 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1714 if (isFastUnpackable(unpack, sizedInternalFormat))
1715 {
1716 // Will try to create RT storage if it does not exist
1717 rx::RenderTarget *destRenderTarget = getRenderTarget(level);
1718 Box destArea(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1719
1720 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget))
1721 {
1722 // Ensure we don't overwrite our newly initialized data
1723 mImageArray[level]->markClean();
1724
1725 fastUnpacked = true;
1726 }
1727 }
1728
1729 if (!fastUnpacked)
1730 {
1731 Texture::setImage(unpack, type, pixels, mImageArray[level]);
1732 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001733}
1734
1735void Texture3D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
1736{
1737 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1738 redefineImage(level, format, width, height, depth);
1739
1740 Texture::setCompressedImage(imageSize, pixels, mImageArray[level]);
1741}
1742
Jamie Madill88f18f42013-09-18 14:36:19 -04001743void 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 +00001744{
Jamie Madillba4f10a2013-10-10 15:12:20 -04001745 bool fastUnpacked = false;
1746
1747 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1748 if (isFastUnpackable(unpack, getInternalFormat(level)))
1749 {
1750 rx::RenderTarget *destRenderTarget = getRenderTarget(level);
1751 Box destArea(xoffset, yoffset, zoffset, width, height, depth);
1752
1753 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, destRenderTarget))
1754 {
1755 // Ensure we don't overwrite our newly initialized data
1756 mImageArray[level]->markClean();
1757
1758 fastUnpacked = true;
1759 }
1760 }
1761
1762 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 +00001763 {
1764 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1765 }
1766}
1767
1768void Texture3D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
1769{
1770 if (Texture::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth, format, imageSize, pixels, mImageArray[level]))
1771 {
1772 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1773 }
1774}
1775
1776void Texture3D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
1777{
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001778 for (int level = 0; level < levels; level++)
1779 {
Jamie Madille664e202013-10-24 17:49:40 -04001780 GLsizei levelWidth = std::max(1, width >> level);
1781 GLsizei levelHeight = std::max(1, height >> level);
1782 GLsizei levelDepth = std::max(1, depth >> level);
1783 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, levelWidth, levelHeight, levelDepth, true);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001784 }
1785
1786 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1787 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001788 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, GL_NONE, 0, 0, 0, true);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001789 }
1790
Jamie Madille664e202013-10-24 17:49:40 -04001791 mImmutable = true;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001792
Jamie Madille664e202013-10-24 17:49:40 -04001793 setCompleteTexStorage(new rx::TextureStorageInterface3D(mRenderer, levels, internalformat, IsRenderTargetUsage(mUsage), width, height, depth));
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001794}
1795
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001796void Texture3D::generateMipmaps()
1797{
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001798 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Jamie Madill22f843a2013-10-24 17:49:36 -04001799 int q = mipLevels();
1800 for (int level = 1; level <= q; level++)
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001801 {
Jamie Madill22f843a2013-10-24 17:49:36 -04001802 redefineImage(level, getBaseLevelInternalFormat(),
1803 std::max(getBaseLevelWidth() >> level, 1),
1804 std::max(getBaseLevelHeight() >> level, 1),
1805 std::max(getBaseLevelDepth() >> level, 1));
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001806 }
1807
1808 if (mTexStorage && mTexStorage->isRenderTarget())
1809 {
Jamie Madill22f843a2013-10-24 17:49:36 -04001810 for (int level = 1; level <= q; level++)
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001811 {
Jamie Madill22f843a2013-10-24 17:49:36 -04001812 mTexStorage->generateMipmap(level);
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001813
Jamie Madill22f843a2013-10-24 17:49:36 -04001814 mImageArray[level]->markClean();
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001815 }
1816 }
1817 else
1818 {
Jamie Madill22f843a2013-10-24 17:49:36 -04001819 for (int level = 1; level <= q; level++)
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001820 {
Jamie Madill22f843a2013-10-24 17:49:36 -04001821 mRenderer->generateMipmap(mImageArray[level], mImageArray[level - 1]);
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001822 }
1823 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001824}
1825
Jamie Madilld3d2a342013-10-07 10:46:35 -04001826const rx::Image *Texture3D::getBaseLevelImage() const
1827{
1828 return mImageArray[0];
1829}
1830
Jamie Madill2ebab852013-10-24 17:49:42 -04001831rx::TextureStorageInterface *Texture3D::getBaseLevelStorage()
1832{
1833 return mTexStorage;
1834}
1835
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001836void Texture3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1837{
1838 if (xoffset + width > mImageArray[level]->getWidth() || yoffset + height > mImageArray[level]->getHeight() || zoffset >= mImageArray[level]->getDepth())
1839 {
1840 return gl::error(GL_INVALID_VALUE);
1841 }
1842
Jamie Madill07edd442013-07-19 16:36:58 -04001843 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
1844 // the current level we're copying to is defined (with appropriate format, width & height)
1845 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
1846
1847 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001848 {
1849 mImageArray[level]->copy(xoffset, yoffset, zoffset, x, y, width, height, source);
1850 mDirtyImages = true;
1851 }
1852 else
1853 {
Jamie Madille83d1a92013-10-24 17:49:33 -04001854 ensureRenderTarget();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001855
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001856 if (level < levelCount())
1857 {
Jamie Madill169d1112013-10-24 17:49:37 -04001858 updateStorageLevel(level);
Jamie Madill07edd442013-07-19 16:36:58 -04001859
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001860 gl::Rectangle sourceRect;
1861 sourceRect.x = x;
1862 sourceRect.width = width;
1863 sourceRect.y = y;
1864 sourceRect.height = height;
1865
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001866 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1867
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001868 mRenderer->copyImage(source, sourceRect,
Jamie Madilld3d2a342013-10-07 10:46:35 -04001869 gl::GetFormat(getBaseLevelInternalFormat(), clientVersion),
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001870 xoffset, yoffset, zoffset, mTexStorage, level);
1871 }
1872 }
1873}
1874
Jamie Madillf8989902013-07-19 16:36:58 -04001875bool Texture3D::isSamplerComplete(const SamplerState &samplerState) const
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001876{
Jamie Madilld3d2a342013-10-07 10:46:35 -04001877 GLsizei width = getBaseLevelWidth();
1878 GLsizei height = getBaseLevelHeight();
1879 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001880
1881 if (width <= 0 || height <= 0 || depth <= 0)
1882 {
1883 return false;
1884 }
1885
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001886 if (!IsTextureFilteringSupported(getInternalFormat(0), mRenderer))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001887 {
Jamie Madillf8989902013-07-19 16:36:58 -04001888 if (samplerState.magFilter != GL_NEAREST ||
1889 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001890 {
1891 return false;
1892 }
1893 }
1894
Jamie Madillf8989902013-07-19 16:36:58 -04001895 if (IsMipmapFiltered(samplerState) && !isMipmapComplete())
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001896 {
1897 return false;
1898 }
1899
1900 return true;
1901}
1902
1903bool Texture3D::isMipmapComplete() const
1904{
Jamie Madill22f843a2013-10-24 17:49:36 -04001905 int q = mipLevels();
Jamie Madill07edd442013-07-19 16:36:58 -04001906
1907 for (int level = 0; level <= q; level++)
1908 {
1909 if (!isLevelComplete(level))
1910 {
1911 return false;
1912 }
1913 }
1914
1915 return true;
1916}
1917
1918bool Texture3D::isLevelComplete(int level) const
1919{
1920 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1921
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001922 if (isImmutable())
1923 {
1924 return true;
1925 }
1926
Jamie Madilld3d2a342013-10-07 10:46:35 -04001927 GLsizei width = getBaseLevelWidth();
1928 GLsizei height = getBaseLevelHeight();
1929 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001930
1931 if (width <= 0 || height <= 0 || depth <= 0)
1932 {
1933 return false;
1934 }
1935
Jamie Madill07edd442013-07-19 16:36:58 -04001936 if (level == 0)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001937 {
Jamie Madill07edd442013-07-19 16:36:58 -04001938 return true;
1939 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001940
Jamie Madill07edd442013-07-19 16:36:58 -04001941 rx::Image *levelImage = mImageArray[level];
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001942
Jamie Madilld3d2a342013-10-07 10:46:35 -04001943 if (levelImage->getInternalFormat() != getBaseLevelInternalFormat())
Jamie Madill07edd442013-07-19 16:36:58 -04001944 {
1945 return false;
1946 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001947
Jamie Madill07edd442013-07-19 16:36:58 -04001948 if (levelImage->getWidth() != std::max(1, width >> level))
1949 {
1950 return false;
1951 }
1952
1953 if (levelImage->getHeight() != std::max(1, height >> level))
1954 {
1955 return false;
1956 }
1957
1958 if (levelImage->getDepth() != std::max(1, depth >> level))
1959 {
1960 return false;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001961 }
1962
1963 return true;
1964}
1965
Geoff Lang8040f572013-07-25 16:49:54 -04001966Renderbuffer *Texture3D::getRenderbuffer(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001967{
Geoff Lang8040f572013-07-25 16:49:54 -04001968 Renderbuffer *renderBuffer = mRenderbufferProxies.get(level, layer);
1969 if (!renderBuffer)
1970 {
Geoff Langd5d8e392013-07-25 16:53:03 -04001971 renderBuffer = new Renderbuffer(mRenderer, id(), new RenderbufferTexture3DLayer(this, level, layer));
1972 mRenderbufferProxies.add(level, 0, renderBuffer);
Geoff Lang8040f572013-07-25 16:49:54 -04001973 }
1974
1975 return renderBuffer;
1976}
1977
1978unsigned int Texture3D::getRenderTargetSerial(GLint level, GLint layer)
1979{
Jamie Madille83d1a92013-10-24 17:49:33 -04001980 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(level, layer) : 0);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001981}
1982
1983int Texture3D::levelCount()
1984{
1985 return mTexStorage ? mTexStorage->levelCount() : 0;
1986}
1987
Jamie Madill73b5d062013-10-24 17:49:38 -04001988void Texture3D::initializeStorage(bool renderTarget)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001989{
Jamie Madille664e202013-10-24 17:49:40 -04001990 // Only initialize the first time this texture is used as a render target or shader resource
1991 if (mTexStorage)
1992 {
1993 return;
1994 }
1995
1996 // do not attempt to create storage for nonexistant data
1997 if (!isLevelComplete(0))
1998 {
1999 return;
2000 }
2001
2002 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
2003
2004 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
2005 ASSERT(mTexStorage);
2006
2007 // flush image data to the storage
2008 updateStorage();
2009}
2010
2011rx::TextureStorageInterface3D *Texture3D::createCompleteStorage(bool renderTarget) const
2012{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002013 GLsizei width = getBaseLevelWidth();
2014 GLsizei height = getBaseLevelHeight();
2015 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002016
Jamie Madille664e202013-10-24 17:49:40 -04002017 ASSERT(width > 0 && height > 0 && depth > 0);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002018
Jamie Madille664e202013-10-24 17:49:40 -04002019 // use existing storage level count, when previously specified by TexStorage*D
2020 GLint levels = (mTexStorage ? mTexStorage->levelCount() : creationLevels(width, height, depth));
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002021
Jamie Madille664e202013-10-24 17:49:40 -04002022 return new rx::TextureStorageInterface3D(mRenderer, levels, getBaseLevelInternalFormat(), renderTarget, width, height, depth);
2023}
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002024
Jamie Madille664e202013-10-24 17:49:40 -04002025void Texture3D::setCompleteTexStorage(rx::TextureStorageInterface3D *newCompleteTexStorage)
2026{
2027 SafeDelete(mTexStorage);
2028 mTexStorage = newCompleteTexStorage;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002029 mDirtyImages = true;
Jamie Madille664e202013-10-24 17:49:40 -04002030
2031 // We do not support managed 3D storage, as that is D3D9/ES2-only
2032 ASSERT(!mTexStorage->isManaged());
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002033}
2034
Jamie Madill169d1112013-10-24 17:49:37 -04002035void Texture3D::updateStorage()
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002036{
Jamie Madilld9b9a502013-10-10 17:46:13 -04002037 int storageLevels = levelCount();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002038
Jamie Madilld9b9a502013-10-10 17:46:13 -04002039 for (int level = 0; level < storageLevels; level++)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002040 {
Jamie Madilld9b9a502013-10-10 17:46:13 -04002041 if (isLevelComplete(level))
2042 {
Jamie Madill169d1112013-10-24 17:49:37 -04002043 updateStorageLevel(level);
Jamie Madilld9b9a502013-10-10 17:46:13 -04002044 }
Jamie Madill07edd442013-07-19 16:36:58 -04002045 }
2046}
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002047
Jamie Madill169d1112013-10-24 17:49:37 -04002048void Texture3D::updateStorageLevel(int level)
Jamie Madill07edd442013-07-19 16:36:58 -04002049{
2050 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
Jamie Madillaee7ad82013-10-10 16:07:32 -04002051 ASSERT(isLevelComplete(level));
Jamie Madill07edd442013-07-19 16:36:58 -04002052
Jamie Madillaee7ad82013-10-10 16:07:32 -04002053 if (mImageArray[level]->isDirty())
Jamie Madill07edd442013-07-19 16:36:58 -04002054 {
Jamie Madillaee7ad82013-10-10 16:07:32 -04002055 commitRect(level, 0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002056 }
2057}
2058
Jamie Madille83d1a92013-10-24 17:49:33 -04002059bool Texture3D::ensureRenderTarget()
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002060{
Jamie Madille664e202013-10-24 17:49:40 -04002061 initializeStorage(true);
2062
2063 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0 && getBaseLevelDepth() > 0)
Jamie Madille83d1a92013-10-24 17:49:33 -04002064 {
Jamie Madille664e202013-10-24 17:49:40 -04002065 ASSERT(mTexStorage);
2066 if (!mTexStorage->isRenderTarget())
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002067 {
Jamie Madille664e202013-10-24 17:49:40 -04002068 rx::TextureStorageInterface3D *newRenderTargetStorage = createCompleteStorage(true);
2069
2070 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002071 {
Jamie Madille664e202013-10-24 17:49:40 -04002072 delete newRenderTargetStorage;
Jamie Madille83d1a92013-10-24 17:49:33 -04002073 return gl::error(GL_OUT_OF_MEMORY, false);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002074 }
Jamie Madille664e202013-10-24 17:49:40 -04002075
2076 setCompleteTexStorage(newRenderTargetStorage);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002077 }
2078 }
2079
Jamie Madille83d1a92013-10-24 17:49:33 -04002080 return (mTexStorage && mTexStorage->isRenderTarget());
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002081}
2082
Jamie Madilla2d4e552013-10-10 15:12:01 -04002083rx::RenderTarget *Texture3D::getRenderTarget(GLint level)
2084{
2085 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04002086 if (!ensureRenderTarget())
Jamie Madilla2d4e552013-10-10 15:12:01 -04002087 {
2088 return NULL;
2089 }
2090
Jamie Madill169d1112013-10-24 17:49:37 -04002091 updateStorageLevel(level);
Jamie Madilla2d4e552013-10-10 15:12:01 -04002092
2093 // ensure this is NOT a depth texture
2094 if (isDepth(level))
2095 {
2096 return NULL;
2097 }
2098
2099 return mTexStorage->getRenderTarget(level);
2100}
2101
Geoff Lang8040f572013-07-25 16:49:54 -04002102rx::RenderTarget *Texture3D::getRenderTarget(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002103{
Geoff Lang8040f572013-07-25 16:49:54 -04002104 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04002105 if (!ensureRenderTarget())
Geoff Lang8040f572013-07-25 16:49:54 -04002106 {
2107 return NULL;
2108 }
2109
Jamie Madill169d1112013-10-24 17:49:37 -04002110 updateStorage();
Geoff Lang8040f572013-07-25 16:49:54 -04002111
2112 // ensure this is NOT a depth texture
2113 if (isDepth(level))
2114 {
2115 return NULL;
2116 }
2117
2118 return mTexStorage->getRenderTarget(level, layer);
2119}
2120
2121rx::RenderTarget *Texture3D::getDepthStencil(GLint level, GLint layer)
2122{
2123 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04002124 if (!ensureRenderTarget())
Geoff Lang8040f572013-07-25 16:49:54 -04002125 {
2126 return NULL;
2127 }
2128
Jamie Madill169d1112013-10-24 17:49:37 -04002129 updateStorageLevel(level);
Geoff Lang8040f572013-07-25 16:49:54 -04002130
2131 // ensure this is a depth texture
2132 if (!isDepth(level))
2133 {
2134 return NULL;
2135 }
2136
2137 return mTexStorage->getRenderTarget(level, layer);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002138}
2139
Geoff Lang005df412013-10-16 14:12:50 -04002140void Texture3D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002141{
2142 // If there currently is a corresponding storage texture image, it has these parameters
Jamie Madilld3d2a342013-10-07 10:46:35 -04002143 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2144 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
2145 const int storageDepth = std::max(1, getBaseLevelDepth() >> level);
Geoff Lang005df412013-10-16 14:12:50 -04002146 const GLenum storageFormat = getBaseLevelInternalFormat();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002147
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00002148 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, false);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002149
2150 if (mTexStorage)
2151 {
2152 const int storageLevels = mTexStorage->levelCount();
2153
2154 if ((level >= storageLevels && storageLevels != 0) ||
2155 width != storageWidth ||
2156 height != storageHeight ||
2157 depth != storageDepth ||
2158 internalformat != storageFormat) // Discard mismatched storage
2159 {
2160 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
2161 {
2162 mImageArray[i]->markDirty();
2163 }
2164
2165 delete mTexStorage;
2166 mTexStorage = NULL;
2167 mDirtyImages = true;
2168 }
2169 }
2170}
2171
2172void Texture3D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth)
2173{
2174 if (level < levelCount())
2175 {
2176 rx::Image *image = mImageArray[level];
Jamie Madill169d1112013-10-24 17:49:37 -04002177 if (image->copyToStorage(mTexStorage, level, xoffset, yoffset, zoffset, width, height, depth))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002178 {
2179 image->markClean();
2180 }
2181 }
2182}
2183
Geoff Lang4907f2c2013-07-25 12:53:57 -04002184Texture2DArray::Texture2DArray(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_2D_ARRAY)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002185{
2186 mTexStorage = NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002187
2188 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2189 {
2190 mLayerCounts[level] = 0;
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002191 mImageArray[level] = NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002192 }
2193}
2194
2195Texture2DArray::~Texture2DArray()
2196{
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002197 delete mTexStorage;
2198 mTexStorage = NULL;
Jamie Madill884a4622013-10-24 17:49:41 -04002199
2200 deleteImages();
2201}
2202
2203void Texture2DArray::deleteImages()
2204{
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002205 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2206 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002207 for (int layer = 0; layer < mLayerCounts[level]; ++layer)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002208 {
2209 delete mImageArray[level][layer];
2210 }
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002211 delete[] mImageArray[level];
Jamie Madill884a4622013-10-24 17:49:41 -04002212 mImageArray[level] = NULL;
2213 mLayerCounts[level] = 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002214 }
2215}
2216
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002217GLsizei Texture2DArray::getWidth(GLint level) const
2218{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002219 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 +00002220}
2221
2222GLsizei Texture2DArray::getHeight(GLint level) const
2223{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002224 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 +00002225}
2226
2227GLsizei Texture2DArray::getDepth(GLint level) const
2228{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002229 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mLayerCounts[level] : 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002230}
2231
2232GLenum Texture2DArray::getInternalFormat(GLint level) const
2233{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002234 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 +00002235}
2236
2237GLenum Texture2DArray::getActualFormat(GLint level) const
2238{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002239 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 +00002240}
2241
2242bool Texture2DArray::isCompressed(GLint level) const
2243{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00002244 return IsFormatCompressed(getInternalFormat(level), mRenderer->getCurrentClientVersion());
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002245}
2246
2247bool Texture2DArray::isDepth(GLint level) const
2248{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00002249 return GetDepthBits(getInternalFormat(level), mRenderer->getCurrentClientVersion()) > 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002250}
2251
Geoff Lang005df412013-10-16 14:12:50 -04002252void 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 +00002253{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00002254 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Geoff Lang005df412013-10-16 14:12:50 -04002255 GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
2256 : GetSizedInternalFormat(format, type, clientVersion);
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00002257 redefineImage(level, sizedInternalFormat, width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002258
Jamie Madill88f18f42013-09-18 14:36:19 -04002259 GLsizei inputDepthPitch = gl::GetDepthPitch(sizedInternalFormat, type, clientVersion, width, height, unpack.alignment);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002260
2261 for (int i = 0; i < depth; i++)
2262 {
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002263 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
Jamie Madill88f18f42013-09-18 14:36:19 -04002264 Texture::setImage(unpack, type, layerPixels, mImageArray[level][i]);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002265 }
2266}
2267
2268void Texture2DArray::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
2269{
2270 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
2271 redefineImage(level, format, width, height, depth);
2272
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002273 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2274 GLsizei inputDepthPitch = gl::GetDepthPitch(format, GL_UNSIGNED_BYTE, clientVersion, width, height, 1);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002275
2276 for (int i = 0; i < depth; i++)
2277 {
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002278 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002279 Texture::setCompressedImage(imageSize, layerPixels, mImageArray[level][i]);
2280 }
2281}
2282
Jamie Madill88f18f42013-09-18 14:36:19 -04002283void 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 +00002284{
Geoff Lang005df412013-10-16 14:12:50 -04002285 GLenum internalformat = getInternalFormat(level);
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002286 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Jamie Madill88f18f42013-09-18 14:36:19 -04002287 GLsizei inputDepthPitch = gl::GetDepthPitch(internalformat, type, clientVersion, width, height, unpack.alignment);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002288
2289 for (int i = 0; i < depth; i++)
2290 {
2291 int layer = zoffset + i;
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002292 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002293
Jamie Madill88f18f42013-09-18 14:36:19 -04002294 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 +00002295 {
2296 commitRect(level, xoffset, yoffset, layer, width, height);
2297 }
2298 }
2299}
2300
2301void Texture2DArray::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
2302{
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002303 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2304 GLsizei inputDepthPitch = gl::GetDepthPitch(format, GL_UNSIGNED_BYTE, clientVersion, width, height, 1);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002305
2306 for (int i = 0; i < depth; i++)
2307 {
2308 int layer = zoffset + i;
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002309 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002310
2311 if (Texture::subImageCompressed(xoffset, yoffset, zoffset, width, height, 1, format, imageSize, layerPixels, mImageArray[level][layer]))
2312 {
2313 commitRect(level, xoffset, yoffset, layer, width, height);
2314 }
2315 }
2316}
2317
2318void Texture2DArray::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2319{
Jamie Madill884a4622013-10-24 17:49:41 -04002320 deleteImages();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002321
2322 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2323 {
Jamie Madill884a4622013-10-24 17:49:41 -04002324 GLsizei levelWidth = std::max(1, width >> level);
2325 GLsizei levelHeight = std::max(1, height >> level);
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002326
Jamie Madill884a4622013-10-24 17:49:41 -04002327 mLayerCounts[level] = (level < levels ? depth : 0);
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002328
Jamie Madill884a4622013-10-24 17:49:41 -04002329 if (mLayerCounts[level] > 0)
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002330 {
2331 // Create new images for this level
Jamie Madill884a4622013-10-24 17:49:41 -04002332 mImageArray[level] = new rx::Image*[mLayerCounts[level]];
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002333
2334 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002335 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002336 mImageArray[level][layer] = mRenderer->createImage();
2337 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, levelWidth,
2338 levelHeight, 1, true);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002339 }
2340 }
2341 }
2342
Jamie Madill884a4622013-10-24 17:49:41 -04002343 mImmutable = true;
2344 setCompleteTexStorage(new rx::TextureStorageInterface2DArray(mRenderer, levels, internalformat, IsRenderTargetUsage(mUsage), width, height, depth));
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002345}
2346
2347void Texture2DArray::generateMipmaps()
2348{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002349 int baseWidth = getBaseLevelWidth();
2350 int baseHeight = getBaseLevelHeight();
2351 int baseDepth = getBaseLevelDepth();
2352 GLenum baseFormat = getBaseLevelInternalFormat();
2353
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00002354 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Jamie Madill22f843a2013-10-24 17:49:36 -04002355 int q = mipLevels();
2356 for (int level = 1; level <= q; level++)
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00002357 {
Jamie Madill22f843a2013-10-24 17:49:36 -04002358 redefineImage(level, baseFormat, std::max(baseWidth >> level, 1), std::max(baseHeight >> level, 1), baseDepth);
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00002359 }
2360
2361 if (mTexStorage && mTexStorage->isRenderTarget())
2362 {
2363 for (int level = 1; level <= q; level++)
2364 {
2365 mTexStorage->generateMipmap(level);
2366
2367 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2368 {
2369 mImageArray[level][layer]->markClean();
2370 }
2371 }
2372 }
2373 else
2374 {
2375 for (int level = 1; level <= q; level++)
2376 {
2377 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2378 {
2379 mRenderer->generateMipmap(mImageArray[level][layer], mImageArray[level - 1][layer]);
2380 }
2381 }
2382 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002383}
2384
Jamie Madilld3d2a342013-10-07 10:46:35 -04002385const rx::Image *Texture2DArray::getBaseLevelImage() const
2386{
Jamie Madill152ed092013-10-09 17:01:15 -04002387 return (mLayerCounts[0] > 0 ? mImageArray[0][0] : NULL);
Jamie Madilld3d2a342013-10-07 10:46:35 -04002388}
2389
Jamie Madill2ebab852013-10-24 17:49:42 -04002390rx::TextureStorageInterface *Texture2DArray::getBaseLevelStorage()
2391{
2392 return mTexStorage;
2393}
2394
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002395void Texture2DArray::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
2396{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002397 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 +00002398 {
2399 return gl::error(GL_INVALID_VALUE);
2400 }
2401
Jamie Madill07edd442013-07-19 16:36:58 -04002402 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
2403 // the current level we're copying to is defined (with appropriate format, width & height)
2404 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
2405
2406 if (!mImageArray[level][0]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002407 {
2408 mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, x, y, width, height, source);
2409 mDirtyImages = true;
2410 }
2411 else
2412 {
Jamie Madille83d1a92013-10-24 17:49:33 -04002413 ensureRenderTarget();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002414
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002415 if (level < levelCount())
2416 {
Jamie Madill169d1112013-10-24 17:49:37 -04002417 updateStorageLevel(level);
Jamie Madill07edd442013-07-19 16:36:58 -04002418
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002419 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2420
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002421 gl::Rectangle sourceRect;
2422 sourceRect.x = x;
2423 sourceRect.width = width;
2424 sourceRect.y = y;
2425 sourceRect.height = height;
2426
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002427 mRenderer->copyImage(source, sourceRect, gl::GetFormat(getInternalFormat(0), clientVersion),
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002428 xoffset, yoffset, zoffset, mTexStorage, level);
2429 }
2430 }
2431}
2432
Jamie Madillf8989902013-07-19 16:36:58 -04002433bool Texture2DArray::isSamplerComplete(const SamplerState &samplerState) const
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002434{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002435 GLsizei width = getBaseLevelWidth();
2436 GLsizei height = getBaseLevelHeight();
2437 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002438
2439 if (width <= 0 || height <= 0 || depth <= 0)
2440 {
2441 return false;
2442 }
2443
Jamie Madilld3d2a342013-10-07 10:46:35 -04002444 if (!IsTextureFilteringSupported(getBaseLevelInternalFormat(), mRenderer))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002445 {
Jamie Madillf8989902013-07-19 16:36:58 -04002446 if (samplerState.magFilter != GL_NEAREST ||
2447 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002448 {
2449 return false;
2450 }
2451 }
2452
Jamie Madillf8989902013-07-19 16:36:58 -04002453 if (IsMipmapFiltered(samplerState) && !isMipmapComplete())
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002454 {
2455 return false;
2456 }
2457
2458 return true;
2459}
2460
2461bool Texture2DArray::isMipmapComplete() const
2462{
Jamie Madill22f843a2013-10-24 17:49:36 -04002463 int q = mipLevels();
Jamie Madill07edd442013-07-19 16:36:58 -04002464
2465 for (int level = 1; level <= q; level++)
2466 {
2467 if (!isLevelComplete(level))
2468 {
2469 return false;
2470 }
2471 }
2472
2473 return true;
2474}
2475
2476bool Texture2DArray::isLevelComplete(int level) const
2477{
2478 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
2479
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002480 if (isImmutable())
2481 {
2482 return true;
2483 }
2484
Jamie Madilld3d2a342013-10-07 10:46:35 -04002485 GLsizei width = getBaseLevelWidth();
2486 GLsizei height = getBaseLevelHeight();
2487 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002488
2489 if (width <= 0 || height <= 0 || depth <= 0)
2490 {
2491 return false;
2492 }
2493
Jamie Madill07edd442013-07-19 16:36:58 -04002494 if (level == 0)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002495 {
Jamie Madill07edd442013-07-19 16:36:58 -04002496 return true;
2497 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002498
Jamie Madill07edd442013-07-19 16:36:58 -04002499 if (getInternalFormat(level) != getInternalFormat(0))
2500 {
2501 return false;
2502 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002503
Jamie Madill07edd442013-07-19 16:36:58 -04002504 if (getWidth(level) != std::max(1, width >> level))
2505 {
2506 return false;
2507 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002508
Jamie Madill07edd442013-07-19 16:36:58 -04002509 if (getHeight(level) != std::max(1, height >> level))
2510 {
2511 return false;
2512 }
2513
2514 if (getDepth(level) != depth)
2515 {
2516 return false;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002517 }
2518
2519 return true;
2520}
2521
Geoff Lang8040f572013-07-25 16:49:54 -04002522Renderbuffer *Texture2DArray::getRenderbuffer(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002523{
Geoff Lang8040f572013-07-25 16:49:54 -04002524 Renderbuffer *renderBuffer = mRenderbufferProxies.get(level, layer);
2525 if (!renderBuffer)
2526 {
Geoff Langd5d8e392013-07-25 16:53:03 -04002527 renderBuffer = new Renderbuffer(mRenderer, id(), new RenderbufferTexture2DArrayLayer(this, level, layer));
2528 mRenderbufferProxies.add(level, 0, renderBuffer);
Geoff Lang8040f572013-07-25 16:49:54 -04002529 }
2530
2531 return renderBuffer;
2532}
2533
Jamie Madille83d1a92013-10-24 17:49:33 -04002534unsigned int Texture2DArray::getRenderTargetSerial(GLint level, GLint layer)
Geoff Lang8040f572013-07-25 16:49:54 -04002535{
Jamie Madille83d1a92013-10-24 17:49:33 -04002536 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(level, layer) : 0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002537}
2538
2539int Texture2DArray::levelCount()
2540{
2541 return mTexStorage ? mTexStorage->levelCount() : 0;
2542}
2543
Jamie Madill73b5d062013-10-24 17:49:38 -04002544void Texture2DArray::initializeStorage(bool renderTarget)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002545{
Jamie Madill884a4622013-10-24 17:49:41 -04002546 // Only initialize the first time this texture is used as a render target or shader resource
2547 if (mTexStorage)
2548 {
2549 return;
2550 }
2551
2552 // do not attempt to create storage for nonexistant data
2553 if (!isLevelComplete(0))
2554 {
2555 return;
2556 }
2557
2558 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
2559
2560 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
2561 ASSERT(mTexStorage);
2562
2563 // flush image data to the storage
2564 updateStorage();
2565}
2566
2567rx::TextureStorageInterface2DArray *Texture2DArray::createCompleteStorage(bool renderTarget) const
2568{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002569 GLsizei width = getBaseLevelWidth();
2570 GLsizei height = getBaseLevelHeight();
2571 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002572
Jamie Madill884a4622013-10-24 17:49:41 -04002573 ASSERT(width > 0 && height > 0 && depth > 0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002574
Jamie Madill884a4622013-10-24 17:49:41 -04002575 // use existing storage level count, when previously specified by TexStorage*D
2576 GLint levels = (mTexStorage ? mTexStorage->levelCount() : creationLevels(width, height));
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002577
Jamie Madill884a4622013-10-24 17:49:41 -04002578 return new rx::TextureStorageInterface2DArray(mRenderer, levels, getBaseLevelInternalFormat(), renderTarget, width, height, depth);
2579}
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002580
Jamie Madill884a4622013-10-24 17:49:41 -04002581void Texture2DArray::setCompleteTexStorage(rx::TextureStorageInterface2DArray *newCompleteTexStorage)
2582{
2583 SafeDelete(mTexStorage);
2584 mTexStorage = newCompleteTexStorage;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002585 mDirtyImages = true;
Jamie Madill884a4622013-10-24 17:49:41 -04002586
2587 // We do not support managed 2D array storage, as managed storage is ES2/D3D9 only
2588 ASSERT(!mTexStorage->isManaged());
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002589}
2590
Jamie Madill169d1112013-10-24 17:49:37 -04002591void Texture2DArray::updateStorage()
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002592{
Jamie Madilld9b9a502013-10-10 17:46:13 -04002593 int storageLevels = levelCount();
2594
2595 for (int level = 0; level < storageLevels; level++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002596 {
Jamie Madilld9b9a502013-10-10 17:46:13 -04002597 if (isLevelComplete(level))
2598 {
Jamie Madill169d1112013-10-24 17:49:37 -04002599 updateStorageLevel(level);
Jamie Madilld9b9a502013-10-10 17:46:13 -04002600 }
Jamie Madill07edd442013-07-19 16:36:58 -04002601 }
2602}
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002603
Jamie Madill169d1112013-10-24 17:49:37 -04002604void Texture2DArray::updateStorageLevel(int level)
Jamie Madill07edd442013-07-19 16:36:58 -04002605{
Jamie Madillaee7ad82013-10-10 16:07:32 -04002606 ASSERT(level >= 0 && level < (int)ArraySize(mLayerCounts));
2607 ASSERT(isLevelComplete(level));
2608
Jamie Madill07edd442013-07-19 16:36:58 -04002609 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2610 {
Jamie Madillaee7ad82013-10-10 16:07:32 -04002611 ASSERT(mImageArray[level] != NULL && mImageArray[level][layer] != NULL);
2612 if (mImageArray[level][layer]->isDirty())
Jamie Madill07edd442013-07-19 16:36:58 -04002613 {
Jamie Madillaee7ad82013-10-10 16:07:32 -04002614 commitRect(level, 0, 0, layer, getWidth(level), getHeight(level));
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002615 }
2616 }
2617}
2618
Jamie Madille83d1a92013-10-24 17:49:33 -04002619bool Texture2DArray::ensureRenderTarget()
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002620{
Jamie Madill884a4622013-10-24 17:49:41 -04002621 initializeStorage(true);
2622
2623 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0 && getBaseLevelDepth() > 0)
Jamie Madille83d1a92013-10-24 17:49:33 -04002624 {
Jamie Madill884a4622013-10-24 17:49:41 -04002625 ASSERT(mTexStorage);
2626 if (!mTexStorage->isRenderTarget())
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002627 {
Jamie Madill884a4622013-10-24 17:49:41 -04002628 rx::TextureStorageInterface2DArray *newRenderTargetStorage = createCompleteStorage(true);
2629
2630 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002631 {
Jamie Madill884a4622013-10-24 17:49:41 -04002632 delete newRenderTargetStorage;
Jamie Madille83d1a92013-10-24 17:49:33 -04002633 return gl::error(GL_OUT_OF_MEMORY, false);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002634 }
Jamie Madill884a4622013-10-24 17:49:41 -04002635
2636 setCompleteTexStorage(newRenderTargetStorage);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002637 }
2638 }
2639
Jamie Madille83d1a92013-10-24 17:49:33 -04002640 return (mTexStorage && mTexStorage->isRenderTarget());
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002641}
2642
Geoff Lang8040f572013-07-25 16:49:54 -04002643rx::RenderTarget *Texture2DArray::getRenderTarget(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002644{
Geoff Lang8040f572013-07-25 16:49:54 -04002645 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04002646 if (!ensureRenderTarget())
Geoff Lang8040f572013-07-25 16:49:54 -04002647 {
2648 return NULL;
2649 }
2650
Jamie Madill169d1112013-10-24 17:49:37 -04002651 updateStorageLevel(level);
Geoff Lang8040f572013-07-25 16:49:54 -04002652
2653 // ensure this is NOT a depth texture
2654 if (isDepth(level))
2655 {
2656 return NULL;
2657 }
2658
2659 return mTexStorage->getRenderTarget(level, layer);
2660}
2661
2662rx::RenderTarget *Texture2DArray::getDepthStencil(GLint level, GLint layer)
2663{
2664 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04002665 if (!ensureRenderTarget())
Geoff Lang8040f572013-07-25 16:49:54 -04002666 {
2667 return NULL;
2668 }
2669
Jamie Madill169d1112013-10-24 17:49:37 -04002670 updateStorageLevel(level);
Geoff Lang8040f572013-07-25 16:49:54 -04002671
2672 // ensure this is a depth texture
2673 if (!isDepth(level))
2674 {
2675 return NULL;
2676 }
2677
2678 return mTexStorage->getRenderTarget(level, layer);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002679}
2680
Geoff Lang005df412013-10-16 14:12:50 -04002681void Texture2DArray::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002682{
2683 // If there currently is a corresponding storage texture image, it has these parameters
Jamie Madilld3d2a342013-10-07 10:46:35 -04002684 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2685 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
2686 const int storageDepth = getBaseLevelDepth();
Geoff Lang005df412013-10-16 14:12:50 -04002687 const GLenum storageFormat = getBaseLevelInternalFormat();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002688
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002689 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002690 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002691 delete mImageArray[level][layer];
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002692 }
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002693 delete[] mImageArray[level];
Jamie Madill152ed092013-10-09 17:01:15 -04002694 mImageArray[level] = NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002695 mLayerCounts[level] = depth;
2696
Jamie Madill152ed092013-10-09 17:01:15 -04002697 if (depth > 0)
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002698 {
Jamie Madill152ed092013-10-09 17:01:15 -04002699 mImageArray[level] = new rx::Image*[depth]();
2700
2701 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2702 {
2703 mImageArray[level][layer] = mRenderer->createImage();
2704 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, width, height, 1, false);
2705 }
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002706 }
2707
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002708 if (mTexStorage)
2709 {
2710 const int storageLevels = mTexStorage->levelCount();
2711
2712 if ((level >= storageLevels && storageLevels != 0) ||
2713 width != storageWidth ||
2714 height != storageHeight ||
2715 depth != storageDepth ||
2716 internalformat != storageFormat) // Discard mismatched storage
2717 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002718 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002719 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002720 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002721 {
2722 mImageArray[level][layer]->markDirty();
2723 }
2724 }
2725
2726 delete mTexStorage;
2727 mTexStorage = NULL;
2728 mDirtyImages = true;
2729 }
2730 }
2731}
2732
2733void Texture2DArray::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint layerTarget, GLsizei width, GLsizei height)
2734{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002735 if (level < levelCount() && layerTarget < getDepth(level))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002736 {
2737 rx::Image *image = mImageArray[level][layerTarget];
Jamie Madill169d1112013-10-24 17:49:37 -04002738 if (image->copyToStorage(mTexStorage, level, xoffset, yoffset, layerTarget, width, height))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002739 {
2740 image->markClean();
2741 }
2742 }
2743}
2744
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00002745}