blob: 9bfde17095b6c00a673caf953f9658bf099719f6 [file] [log] [blame]
shannon.woods@transgaming.combdf2d802013-02-28 23:16:20 +00001#include "precompiled.h"
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00002//
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00003// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00004// Use of this source code is governed by a BSD-style license that can be
5// found in the LICENSE file.
6//
7
8// Texture.cpp: Implements the gl::Texture class and its derived classes
9// Texture2D and TextureCubeMap. Implements GL texture objects and related
10// functionality. [OpenGL ES 2.0.24] section 3.7 page 63.
11
12#include "libGLESv2/Texture.h"
13
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000014#include "libGLESv2/main.h"
shannonwoods@chromium.orga2ecfcc2013-05-30 00:11:59 +000015#include "common/mathutil.h"
16#include "common/utilities.h"
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +000017#include "libGLESv2/formatutils.h"
Geoff Langdce735c2013-06-04 10:21:18 -040018#include "libGLESv2/renderer/Blit9.h"
shannon.woods@transgaming.com486d9e92013-02-28 23:15:41 +000019#include "libGLESv2/Renderbuffer.h"
20#include "libGLESv2/renderer/Image.h"
21#include "libGLESv2/renderer/Renderer.h"
22#include "libGLESv2/renderer/TextureStorage.h"
23#include "libEGL/Surface.h"
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000024
25namespace gl
26{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000027
Jamie Madillf8989902013-07-19 16:36:58 -040028bool IsMipmapFiltered(const SamplerState &samplerState)
29{
30 switch (samplerState.minFilter)
31 {
32 case GL_NEAREST:
33 case GL_LINEAR:
34 return false;
35 case GL_NEAREST_MIPMAP_NEAREST:
36 case GL_LINEAR_MIPMAP_NEAREST:
37 case GL_NEAREST_MIPMAP_LINEAR:
38 case GL_LINEAR_MIPMAP_LINEAR:
39 return true;
40 default: UNREACHABLE();
41 return false;
42 }
43}
44
Geoff Lang4907f2c2013-07-25 12:53:57 -040045Texture::Texture(rx::Renderer *renderer, GLuint id, GLenum target) : RefCountObject(id)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000046{
daniel@transgaming.com370482e2012-11-28 19:32:13 +000047 mRenderer = renderer;
48
daniel@transgaming.comebf139f2012-10-31 18:07:32 +000049 mSamplerState.minFilter = GL_NEAREST_MIPMAP_LINEAR;
50 mSamplerState.magFilter = GL_LINEAR;
51 mSamplerState.wrapS = GL_REPEAT;
52 mSamplerState.wrapT = GL_REPEAT;
shannon.woods%transgaming.com@gtempaccount.com0b3a8df2013-04-13 03:44:51 +000053 mSamplerState.wrapR = GL_REPEAT;
daniel@transgaming.comebf139f2012-10-31 18:07:32 +000054 mSamplerState.maxAnisotropy = 1.0f;
55 mSamplerState.lodOffset = 0;
Geoff Langc82fc412013-07-10 14:43:42 -040056 mSamplerState.compareMode = GL_NONE;
57 mSamplerState.compareFunc = GL_LEQUAL;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000058 mUsage = GL_NONE;
Geoff Langc82fc412013-07-10 14:43:42 -040059
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000060 mDirtyImages = true;
61
62 mImmutable = false;
Geoff Lang4907f2c2013-07-25 12:53:57 -040063
64 mTarget = target;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000065}
66
67Texture::~Texture()
68{
69}
70
Geoff Lang4907f2c2013-07-25 12:53:57 -040071GLenum Texture::getTarget() const
72{
73 return mTarget;
74}
75
Geoff Lang8040f572013-07-25 16:49:54 -040076void Texture::addProxyRef(const Renderbuffer *proxy)
77{
78 mRenderbufferProxies.addRef(proxy);
79}
80
81void Texture::releaseProxy(const Renderbuffer *proxy)
82{
83 mRenderbufferProxies.release(proxy);
84}
85
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000086// Returns true on successful filter state update (valid enum parameter)
87bool Texture::setMinFilter(GLenum filter)
88{
89 switch (filter)
90 {
91 case GL_NEAREST:
92 case GL_LINEAR:
93 case GL_NEAREST_MIPMAP_NEAREST:
94 case GL_LINEAR_MIPMAP_NEAREST:
95 case GL_NEAREST_MIPMAP_LINEAR:
96 case GL_LINEAR_MIPMAP_LINEAR:
daniel@transgaming.com3c17ba62013-01-11 04:11:41 +000097 mSamplerState.minFilter = filter;
98 return true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000099 default:
100 return false;
101 }
102}
103
104// Returns true on successful filter state update (valid enum parameter)
105bool Texture::setMagFilter(GLenum filter)
106{
107 switch (filter)
108 {
109 case GL_NEAREST:
110 case GL_LINEAR:
daniel@transgaming.com3c17ba62013-01-11 04:11:41 +0000111 mSamplerState.magFilter = filter;
112 return true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000113 default:
114 return false;
115 }
116}
117
118// Returns true on successful wrap state update (valid enum parameter)
119bool Texture::setWrapS(GLenum wrap)
120{
121 switch (wrap)
122 {
123 case GL_REPEAT:
124 case GL_CLAMP_TO_EDGE:
125 case GL_MIRRORED_REPEAT:
daniel@transgaming.com3c17ba62013-01-11 04:11:41 +0000126 mSamplerState.wrapS = wrap;
127 return true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000128 default:
129 return false;
130 }
131}
132
133// Returns true on successful wrap state update (valid enum parameter)
134bool Texture::setWrapT(GLenum wrap)
135{
136 switch (wrap)
137 {
138 case GL_REPEAT:
139 case GL_CLAMP_TO_EDGE:
140 case GL_MIRRORED_REPEAT:
daniel@transgaming.com3c17ba62013-01-11 04:11:41 +0000141 mSamplerState.wrapT = wrap;
142 return true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000143 default:
144 return false;
145 }
146}
147
shannon.woods%transgaming.com@gtempaccount.com0b3a8df2013-04-13 03:44:51 +0000148// Returns true on successful wrap state update (valid enum parameter)
149bool Texture::setWrapR(GLenum wrap)
150{
151 switch (wrap)
152 {
153 case GL_REPEAT:
154 case GL_CLAMP_TO_EDGE:
155 case GL_MIRRORED_REPEAT:
156 mSamplerState.wrapR = wrap;
157 return true;
158 default:
159 return false;
160 }
161}
162
daniel@transgaming.com07ab8412012-07-12 15:17:09 +0000163// Returns true on successful max anisotropy update (valid anisotropy value)
164bool Texture::setMaxAnisotropy(float textureMaxAnisotropy, float contextMaxAnisotropy)
165{
166 textureMaxAnisotropy = std::min(textureMaxAnisotropy, contextMaxAnisotropy);
167 if (textureMaxAnisotropy < 1.0f)
168 {
169 return false;
170 }
daniel@transgaming.com3c17ba62013-01-11 04:11:41 +0000171
172 mSamplerState.maxAnisotropy = textureMaxAnisotropy;
173
daniel@transgaming.com07ab8412012-07-12 15:17:09 +0000174 return true;
175}
176
Geoff Langc82fc412013-07-10 14:43:42 -0400177bool Texture::setCompareMode(GLenum mode)
178{
179 // Acceptable mode parameters from GLES 3.0.2 spec, table 3.17
180 switch (mode)
181 {
182 case GL_NONE:
183 case GL_COMPARE_REF_TO_TEXTURE:
184 mSamplerState.compareMode = mode;
185 return true;
186 default:
187 return false;
188 }
189}
190
191bool Texture::setCompareFunc(GLenum func)
192{
193 // Acceptable function parameters from GLES 3.0.2 spec, table 3.17
194 switch (func)
195 {
196 case GL_LEQUAL:
197 case GL_GEQUAL:
198 case GL_LESS:
199 case GL_GREATER:
200 case GL_EQUAL:
201 case GL_NOTEQUAL:
202 case GL_ALWAYS:
203 case GL_NEVER:
204 mSamplerState.compareFunc = func;
205 return true;
206 default:
207 return false;
208 }
209}
210
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000211// Returns true on successful usage state update (valid enum parameter)
212bool Texture::setUsage(GLenum usage)
213{
214 switch (usage)
215 {
216 case GL_NONE:
217 case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
218 mUsage = usage;
219 return true;
220 default:
221 return false;
222 }
223}
224
225GLenum Texture::getMinFilter() const
226{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000227 return mSamplerState.minFilter;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000228}
229
230GLenum Texture::getMagFilter() const
231{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000232 return mSamplerState.magFilter;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000233}
234
235GLenum Texture::getWrapS() const
236{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000237 return mSamplerState.wrapS;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000238}
239
240GLenum Texture::getWrapT() const
241{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000242 return mSamplerState.wrapT;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000243}
244
shannon.woods%transgaming.com@gtempaccount.com0b3a8df2013-04-13 03:44:51 +0000245GLenum Texture::getWrapR() const
246{
247 return mSamplerState.wrapR;
248}
249
daniel@transgaming.com07ab8412012-07-12 15:17:09 +0000250float Texture::getMaxAnisotropy() const
251{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000252 return mSamplerState.maxAnisotropy;
253}
254
255int Texture::getLodOffset()
256{
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000257 rx::TextureStorageInterface *texture = getStorage(false);
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000258 return texture ? texture->getLodOffset() : 0;
259}
260
261void Texture::getSamplerState(SamplerState *sampler)
262{
263 *sampler = mSamplerState;
264 sampler->lodOffset = getLodOffset();
daniel@transgaming.com07ab8412012-07-12 15:17:09 +0000265}
266
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000267GLenum Texture::getUsage() const
268{
269 return mUsage;
270}
271
Jamie Madill88f18f42013-09-18 14:36:19 -0400272void Texture::setImage(const PixelUnpackState &unpack, GLenum type, const void *pixels, rx::Image *image)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000273{
Jamie Madillabef6802013-09-05 16:54:19 -0400274 // We no longer need the "GLenum format" parameter to TexImage to determine what data format "pixels" contains.
275 // From our image internal format we know how many channels to expect, and "type" gives the format of pixel's components.
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000276 if (pixels != NULL)
277 {
Jamie Madill88f18f42013-09-18 14:36:19 -0400278 image->loadData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), unpack.alignment, type, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000279 mDirtyImages = true;
280 }
281}
282
daniel@transgaming.com31b13e12012-11-28 19:34:30 +0000283void Texture::setCompressedImage(GLsizei imageSize, const void *pixels, rx::Image *image)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000284{
285 if (pixels != NULL)
286 {
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000287 image->loadCompressedData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000288 mDirtyImages = true;
289 }
290}
291
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000292bool Texture::subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
Jamie Madill88f18f42013-09-18 14:36:19 -0400293 GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels, rx::Image *image)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000294{
295 if (pixels != NULL)
296 {
Jamie Madill88f18f42013-09-18 14:36:19 -0400297 image->loadData(xoffset, yoffset, zoffset, width, height, depth, unpack.alignment, type, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000298 mDirtyImages = true;
299 }
300
301 return true;
302}
303
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000304bool Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
305 GLenum format, GLsizei imageSize, const void *pixels, rx::Image *image)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000306{
307 if (pixels != NULL)
308 {
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000309 image->loadCompressedData(xoffset, yoffset, zoffset, width, height, depth, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000310 mDirtyImages = true;
311 }
312
313 return true;
314}
315
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000316rx::TextureStorageInterface *Texture::getNativeTexture()
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000317{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000318 // ensure the underlying texture is created
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000319
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000320 rx::TextureStorageInterface *storage = getStorage(false);
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000321 if (storage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000322 {
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000323 updateTexture();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000324 }
325
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000326 return storage;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000327}
328
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000329bool Texture::hasDirtyImages() const
330{
331 return mDirtyImages;
332}
333
334void Texture::resetDirty()
335{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000336 mDirtyImages = false;
337}
338
339unsigned int Texture::getTextureSerial()
340{
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000341 rx::TextureStorageInterface *texture = getStorage(false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000342 return texture ? texture->getTextureSerial() : 0;
343}
344
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000345bool Texture::isImmutable() const
346{
347 return mImmutable;
348}
349
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +0000350GLint Texture::creationLevels(GLsizei width, GLsizei height, GLsizei depth) const
351{
352 // NPOT checks are not required in ES 3.0, NPOT texture support is assumed.
353 return 0; // Maximum number of levels
354}
355
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000356GLint Texture::creationLevels(GLsizei width, GLsizei height) const
357{
daniel@transgaming.comea32d482012-11-28 19:33:18 +0000358 if ((isPow2(width) && isPow2(height)) || mRenderer->getNonPower2TextureSupport())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000359 {
360 return 0; // Maximum number of levels
361 }
362 else
363 {
364 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
365 return 1;
366 }
367}
368
369GLint Texture::creationLevels(GLsizei size) const
370{
371 return creationLevels(size, size);
372}
373
Geoff Lang4907f2c2013-07-25 12:53:57 -0400374Texture2D::Texture2D(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_2D)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000375{
376 mTexStorage = NULL;
377 mSurface = NULL;
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000378
379 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
380 {
daniel@transgaming.com244e1832012-12-20 20:52:35 +0000381 mImageArray[i] = renderer->createImage();
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000382 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000383}
384
385Texture2D::~Texture2D()
386{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000387 delete mTexStorage;
388 mTexStorage = NULL;
389
390 if (mSurface)
391 {
392 mSurface->setBoundTexture(NULL);
393 mSurface = NULL;
394 }
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000395
396 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
397 {
398 delete mImageArray[i];
399 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000400}
401
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000402GLsizei Texture2D::getWidth(GLint level) const
403{
404 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000405 return mImageArray[level]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000406 else
407 return 0;
408}
409
410GLsizei Texture2D::getHeight(GLint level) const
411{
412 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000413 return mImageArray[level]->getHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000414 else
415 return 0;
416}
417
418GLenum Texture2D::getInternalFormat(GLint level) const
419{
420 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000421 return mImageArray[level]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000422 else
423 return GL_NONE;
424}
425
daniel@transgaming.com20d36662012-10-31 19:51:43 +0000426GLenum Texture2D::getActualFormat(GLint level) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000427{
428 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000429 return mImageArray[level]->getActualFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000430 else
431 return D3DFMT_UNKNOWN;
432}
433
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000434void Texture2D::redefineImage(GLint level, GLint internalformat, GLsizei width, GLsizei height)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000435{
436 releaseTexImage();
shannon.woods@transgaming.com8a406682013-02-28 23:15:26 +0000437
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000438 // If there currently is a corresponding storage texture image, it has these parameters
439 const int storageWidth = std::max(1, mImageArray[0]->getWidth() >> level);
440 const int storageHeight = std::max(1, mImageArray[0]->getHeight() >> level);
441 const int storageFormat = mImageArray[0]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000442
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000443 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, width, height, 1, false);
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000444
445 if (mTexStorage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000446 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000447 const int storageLevels = mTexStorage->levelCount();
448
449 if ((level >= storageLevels && storageLevels != 0) ||
450 width != storageWidth ||
451 height != storageHeight ||
452 internalformat != storageFormat) // Discard mismatched storage
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000453 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000454 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
455 {
456 mImageArray[i]->markDirty();
457 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000458
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000459 delete mTexStorage;
460 mTexStorage = NULL;
461 mDirtyImages = true;
462 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000463 }
464}
465
Jamie Madill88f18f42013-09-18 14:36:19 -0400466void Texture2D::setImage(GLint level, GLsizei width, GLsizei height, GLint internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000467{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +0000468 GLuint clientVersion = mRenderer->getCurrentClientVersion();
469 GLint sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
470 : GetSizedInternalFormat(format, type, clientVersion);
471 redefineImage(level, sizedInternalFormat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000472
Jamie Madill88f18f42013-09-18 14:36:19 -0400473 Texture::setImage(unpack, type, pixels, mImageArray[level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000474}
475
476void Texture2D::bindTexImage(egl::Surface *surface)
477{
478 releaseTexImage();
479
daniel@transgaming.com106e1f72012-10-31 18:38:36 +0000480 GLint internalformat = surface->getFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000481
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000482 mImageArray[0]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, surface->getWidth(), surface->getHeight(), 1, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000483
484 delete mTexStorage;
daniel@transgaming.comd8353dd2012-12-20 21:11:14 +0000485 mTexStorage = new rx::TextureStorageInterface2D(mRenderer, surface->getSwapChain());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000486
487 mDirtyImages = true;
488 mSurface = surface;
489 mSurface->setBoundTexture(this);
490}
491
492void Texture2D::releaseTexImage()
493{
494 if (mSurface)
495 {
496 mSurface->setBoundTexture(NULL);
497 mSurface = NULL;
498
499 if (mTexStorage)
500 {
501 delete mTexStorage;
502 mTexStorage = NULL;
503 }
504
505 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
506 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000507 mImageArray[i]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000508 }
509 }
510}
511
512void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
513{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000514 // 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 +0000515 redefineImage(level, format, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000516
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000517 Texture::setCompressedImage(imageSize, pixels, mImageArray[level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000518}
519
520void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
521{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000522 if (level < levelCount())
523 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000524 rx::Image *image = mImageArray[level];
daniel@transgaming.com0f195ad2012-10-31 19:51:59 +0000525 if (image->updateSurface(mTexStorage, level, xoffset, yoffset, width, height))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000526 {
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000527 image->markClean();
528 }
529 }
530}
531
Jamie Madill88f18f42013-09-18 14:36:19 -0400532void 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 +0000533{
Jamie Madill88f18f42013-09-18 14:36:19 -0400534 if (Texture::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, mImageArray[level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000535 {
536 commitRect(level, xoffset, yoffset, width, height);
537 }
538}
539
540void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
541{
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000542 if (Texture::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000543 {
544 commitRect(level, xoffset, yoffset, width, height);
545 }
546}
547
548void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
549{
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +0000550 GLuint clientVersion = mRenderer->getCurrentClientVersion();
551 GLint sizedInternalFormat = IsSizedInternalFormat(format, clientVersion) ? format
552 : GetSizedInternalFormat(format, GL_UNSIGNED_BYTE, clientVersion);
553 redefineImage(level, sizedInternalFormat, width, height);
shannon.woods@transgaming.com8a406682013-02-28 23:15:26 +0000554
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000555 if (!mImageArray[level]->isRenderableFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000556 {
shannon.woods%transgaming.com@gtempaccount.come5dcce72013-04-13 03:44:33 +0000557 mImageArray[level]->copy(0, 0, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000558 mDirtyImages = true;
559 }
560 else
561 {
562 if (!mTexStorage || !mTexStorage->isRenderTarget())
563 {
564 convertToRenderTarget();
565 }
566
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000567 mImageArray[level]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000568
569 if (width != 0 && height != 0 && level < levelCount())
570 {
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +0000571 gl::Rectangle sourceRect;
572 sourceRect.x = x;
573 sourceRect.width = width;
574 sourceRect.y = y;
575 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000576
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +0000577 mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000578 }
579 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000580}
581
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +0000582void 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 +0000583{
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +0000584 if (xoffset + width > mImageArray[level]->getWidth() || yoffset + height > mImageArray[level]->getHeight() || zoffset != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000585 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +0000586 return gl::error(GL_INVALID_VALUE);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000587 }
588
Jamie Madill07edd442013-07-19 16:36:58 -0400589 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
590 // the current level we're copying to is defined (with appropriate format, width & height)
591 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
592
593 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000594 {
shannon.woods%transgaming.com@gtempaccount.come5dcce72013-04-13 03:44:33 +0000595 mImageArray[level]->copy(xoffset, yoffset, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000596 mDirtyImages = true;
597 }
598 else
599 {
600 if (!mTexStorage || !mTexStorage->isRenderTarget())
601 {
602 convertToRenderTarget();
603 }
604
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000605 if (level < levelCount())
606 {
Jamie Madill07edd442013-07-19 16:36:58 -0400607 updateTextureLevel(level);
608
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +0000609 GLuint clientVersion = mRenderer->getCurrentClientVersion();
610
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +0000611 gl::Rectangle sourceRect;
612 sourceRect.x = x;
613 sourceRect.width = width;
614 sourceRect.y = y;
615 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000616
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +0000617 mRenderer->copyImage(source, sourceRect,
618 gl::GetFormat(mImageArray[0]->getInternalFormat(), clientVersion),
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +0000619 xoffset, yoffset, mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000620 }
621 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000622}
623
624void Texture2D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height)
625{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000626 delete mTexStorage;
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000627 mTexStorage = new rx::TextureStorageInterface2D(mRenderer, levels, internalformat, mUsage, false, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000628 mImmutable = true;
629
630 for (int level = 0; level < levels; level++)
631 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000632 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, width, height, 1, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000633 width = std::max(1, width >> 1);
634 height = std::max(1, height >> 1);
635 }
636
637 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
638 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000639 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000640 }
641
642 if (mTexStorage->isManaged())
643 {
644 int levels = levelCount();
645
646 for (int level = 0; level < levels; level++)
647 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000648 mImageArray[level]->setManagedSurface(mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000649 }
650 }
651}
652
653// Tests for 2D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85.
Jamie Madillf8989902013-07-19 16:36:58 -0400654bool Texture2D::isSamplerComplete(const SamplerState &samplerState) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000655{
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000656 GLsizei width = mImageArray[0]->getWidth();
657 GLsizei height = mImageArray[0]->getHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000658
659 if (width <= 0 || height <= 0)
660 {
661 return false;
662 }
663
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000664 if (!IsTextureFilteringSupported(getInternalFormat(0), mRenderer))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000665 {
Jamie Madillf8989902013-07-19 16:36:58 -0400666 if (samplerState.magFilter != GL_NEAREST ||
667 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000668 {
669 return false;
670 }
671 }
672
daniel@transgaming.comea32d482012-11-28 19:33:18 +0000673 bool npotSupport = mRenderer->getNonPower2TextureSupport();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000674
675 if (!npotSupport)
676 {
Jamie Madillf8989902013-07-19 16:36:58 -0400677 if ((samplerState.wrapS != GL_CLAMP_TO_EDGE && !isPow2(width)) ||
678 (samplerState.wrapT != GL_CLAMP_TO_EDGE && !isPow2(height)))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000679 {
680 return false;
681 }
682 }
683
Jamie Madillf8989902013-07-19 16:36:58 -0400684 if (IsMipmapFiltered(samplerState))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000685 {
686 if (!npotSupport)
687 {
688 if (!isPow2(width) || !isPow2(height))
689 {
690 return false;
691 }
692 }
693
694 if (!isMipmapComplete())
695 {
696 return false;
697 }
698 }
699
Geoff Langc82fc412013-07-10 14:43:42 -0400700 // OpenGLES 3.0.2 spec section 3.8.13 states that a texture is not mipmap complete if:
701 // The internalformat specified for the texture arrays is a sized internal depth or
702 // depth and stencil format (see table 3.13), the value of TEXTURE_COMPARE_-
703 // MODE is NONE, and either the magnification filter is not NEAREST or the mini-
704 // fication filter is neither NEAREST nor NEAREST_MIPMAP_NEAREST.
705 if (gl::GetDepthBits(getInternalFormat(0), mRenderer->getCurrentClientVersion()) > 0)
706 {
707 if (mSamplerState.compareMode == GL_NONE)
708 {
709 if ((mSamplerState.minFilter != GL_NEAREST && mSamplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST) ||
710 mSamplerState.magFilter != GL_NEAREST)
711 {
712 return false;
713 }
714 }
715 }
716
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000717 return true;
718}
719
720// Tests for 2D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
721bool Texture2D::isMipmapComplete() const
722{
Jamie Madill07edd442013-07-19 16:36:58 -0400723 GLsizei width = mImageArray[0]->getWidth();
724 GLsizei height = mImageArray[0]->getHeight();
725
726 int q = log2(std::max(width, height));
727
728 for (int level = 0; level <= q; level++)
729 {
730 if (!isLevelComplete(level))
731 {
732 return false;
733 }
734 }
735
736 return true;
737}
738
739bool Texture2D::isLevelComplete(int level) const
740{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000741 if (isImmutable())
742 {
743 return true;
744 }
745
Jamie Madill07edd442013-07-19 16:36:58 -0400746 const rx::Image *baseImage = mImageArray[0];
747 GLsizei width = baseImage->getWidth();
748 GLsizei height = baseImage->getHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000749
750 if (width <= 0 || height <= 0)
751 {
752 return false;
753 }
754
Jamie Madill07edd442013-07-19 16:36:58 -0400755 // The base image level is complete if the width and height are positive
756 if (level == 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000757 {
Jamie Madill07edd442013-07-19 16:36:58 -0400758 return true;
759 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000760
Jamie Madill07edd442013-07-19 16:36:58 -0400761 ASSERT(level >= 1 && level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
762 rx::Image *image = mImageArray[level];
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000763
Jamie Madill07edd442013-07-19 16:36:58 -0400764 if (image->getInternalFormat() != baseImage->getInternalFormat())
765 {
766 return false;
767 }
768
769 if (image->getWidth() != std::max(1, width >> level))
770 {
771 return false;
772 }
773
774 if (image->getHeight() != std::max(1, height >> level))
775 {
776 return false;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000777 }
778
779 return true;
780}
781
782bool Texture2D::isCompressed(GLint level) const
783{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000784 return IsFormatCompressed(getInternalFormat(level), mRenderer->getCurrentClientVersion());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000785}
786
787bool Texture2D::isDepth(GLint level) const
788{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000789 return GetDepthBits(getInternalFormat(level), mRenderer->getCurrentClientVersion()) > 0;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000790}
791
daniel@transgaming.comf032cb82012-10-31 19:51:52 +0000792// Constructs a native texture resource from the texture images
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000793void Texture2D::createTexture()
794{
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000795 GLsizei width = mImageArray[0]->getWidth();
796 GLsizei height = mImageArray[0]->getHeight();
daniel@transgaming.come6a09842012-09-17 21:28:55 +0000797
798 if (!(width > 0 && height > 0))
daniel@transgaming.comf032cb82012-10-31 19:51:52 +0000799 return; // do not attempt to create native textures for nonexistant data
daniel@transgaming.come6a09842012-09-17 21:28:55 +0000800
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000801 GLint levels = creationLevels(width, height);
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000802 GLenum internalformat = mImageArray[0]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000803
804 delete mTexStorage;
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000805 mTexStorage = new rx::TextureStorageInterface2D(mRenderer, levels, internalformat, mUsage, false, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000806
807 if (mTexStorage->isManaged())
808 {
809 int levels = levelCount();
810
811 for (int level = 0; level < levels; level++)
812 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000813 mImageArray[level]->setManagedSurface(mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000814 }
815 }
816
817 mDirtyImages = true;
818}
819
820void Texture2D::updateTexture()
821{
Jamie Madilleb3665c2013-07-19 16:36:57 -0400822 int levels = (isMipmapComplete() ? levelCount() : 1);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000823
824 for (int level = 0; level < levels; level++)
825 {
Jamie Madill07edd442013-07-19 16:36:58 -0400826 updateTextureLevel(level);
827 }
828}
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000829
Jamie Madill07edd442013-07-19 16:36:58 -0400830void Texture2D::updateTextureLevel(int level)
831{
832 ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
833 rx::Image *image = mImageArray[level];
834
835 if (image->isDirty())
836 {
837 commitRect(level, 0, 0, mImageArray[level]->getWidth(), mImageArray[level]->getHeight());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000838 }
839}
840
841void Texture2D::convertToRenderTarget()
842{
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000843 rx::TextureStorageInterface2D *newTexStorage = NULL;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000844
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000845 if (mImageArray[0]->getWidth() != 0 && mImageArray[0]->getHeight() != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000846 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000847 GLsizei width = mImageArray[0]->getWidth();
848 GLsizei height = mImageArray[0]->getHeight();
shannon.woods@transgaming.com6bb48862013-02-28 23:09:34 +0000849 GLint levels = mTexStorage != NULL ? mTexStorage->levelCount() : creationLevels(width, height);
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000850 GLenum internalformat = mImageArray[0]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000851
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000852 newTexStorage = new rx::TextureStorageInterface2D(mRenderer, levels, internalformat, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, true, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000853
854 if (mTexStorage != NULL)
855 {
daniel@transgaming.com1d80eee2012-11-28 19:33:31 +0000856 if (!mRenderer->copyToRenderTarget(newTexStorage, mTexStorage))
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +0000857 {
858 delete newTexStorage;
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +0000859 return gl::error(GL_OUT_OF_MEMORY);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000860 }
861 }
862 }
863
864 delete mTexStorage;
865 mTexStorage = newTexStorage;
866
867 mDirtyImages = true;
868}
869
870void Texture2D::generateMipmaps()
871{
daniel@transgaming.comea32d482012-11-28 19:33:18 +0000872 if (!mRenderer->getNonPower2TextureSupport())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000873 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000874 if (!isPow2(mImageArray[0]->getWidth()) || !isPow2(mImageArray[0]->getHeight()))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000875 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +0000876 return gl::error(GL_INVALID_OPERATION);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000877 }
878 }
879
880 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000881 unsigned int q = log2(std::max(mImageArray[0]->getWidth(), mImageArray[0]->getHeight()));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000882 for (unsigned int i = 1; i <= q; i++)
883 {
shannon.woods@transgaming.com8a406682013-02-28 23:15:26 +0000884 redefineImage(i, mImageArray[0]->getInternalFormat(),
885 std::max(mImageArray[0]->getWidth() >> i, 1),
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000886 std::max(mImageArray[0]->getHeight() >> i, 1));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000887 }
888
889 if (mTexStorage && mTexStorage->isRenderTarget())
890 {
891 for (unsigned int i = 1; i <= q; i++)
892 {
daniel@transgaming.com0ad830b2012-10-31 19:52:12 +0000893 mTexStorage->generateMipmap(i);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000894
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000895 mImageArray[i]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000896 }
897 }
898 else
899 {
900 for (unsigned int i = 1; i <= q; i++)
901 {
daniel@transgaming.com4ba24062012-12-20 20:54:24 +0000902 mRenderer->generateMipmap(mImageArray[i], mImageArray[i - 1]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000903 }
904 }
905}
906
Geoff Lang8040f572013-07-25 16:49:54 -0400907Renderbuffer *Texture2D::getRenderbuffer(GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000908{
Geoff Lang8040f572013-07-25 16:49:54 -0400909 Renderbuffer *renderBuffer = mRenderbufferProxies.get(level, 0);
910 if (!renderBuffer)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000911 {
Geoff Lang8040f572013-07-25 16:49:54 -0400912 renderBuffer = new Renderbuffer(mRenderer, id(), new RenderbufferTexture2D(this, level));
913 mRenderbufferProxies.add(level, 0, renderBuffer);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000914 }
915
Geoff Lang8040f572013-07-25 16:49:54 -0400916 return renderBuffer;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000917}
918
Geoff Lang8040f572013-07-25 16:49:54 -0400919unsigned int Texture2D::getRenderTargetSerial(GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000920{
Geoff Lang8040f572013-07-25 16:49:54 -0400921 if (!mTexStorage || !mTexStorage->isRenderTarget())
922 {
923 convertToRenderTarget();
924 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000925
Geoff Lang8040f572013-07-25 16:49:54 -0400926 return mTexStorage ? mTexStorage->getRenderTargetSerial(level) : 0;
927}
928
929rx::RenderTarget *Texture2D::getRenderTarget(GLint level)
930{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000931 // ensure the underlying texture is created
932 if (getStorage(true) == NULL)
933 {
934 return NULL;
935 }
936
937 updateTexture();
Geoff Lang8040f572013-07-25 16:49:54 -0400938
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000939 // ensure this is NOT a depth texture
Geoff Lang8040f572013-07-25 16:49:54 -0400940 if (isDepth(level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000941 {
942 return NULL;
943 }
daniel@transgaming.com34da3972012-12-20 21:10:29 +0000944
Geoff Lang8040f572013-07-25 16:49:54 -0400945 return mTexStorage->getRenderTarget(level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000946}
947
Geoff Lang8040f572013-07-25 16:49:54 -0400948rx::RenderTarget *Texture2D::getDepthSencil(GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000949{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000950 // ensure the underlying texture is created
951 if (getStorage(true) == NULL)
952 {
953 return NULL;
954 }
955
956 updateTexture();
957
958 // ensure this is actually a depth texture
Geoff Lang8040f572013-07-25 16:49:54 -0400959 if (!isDepth(level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000960 {
961 return NULL;
962 }
Geoff Lang8040f572013-07-25 16:49:54 -0400963
964 return mTexStorage->getRenderTarget(level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000965}
966
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +0000967int Texture2D::levelCount()
968{
shannon.woods@transgaming.com5016f8e2013-02-28 23:20:57 +0000969 return mTexStorage ? mTexStorage->levelCount() : 0;
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +0000970}
971
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000972rx::TextureStorageInterface *Texture2D::getStorage(bool renderTarget)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000973{
974 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
975 {
976 if (renderTarget)
977 {
978 convertToRenderTarget();
979 }
980 else
981 {
982 createTexture();
983 }
984 }
985
986 return mTexStorage;
987}
988
Geoff Lang4907f2c2013-07-25 12:53:57 -0400989TextureCubeMap::TextureCubeMap(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_CUBE_MAP)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000990{
991 mTexStorage = NULL;
992 for (int i = 0; i < 6; i++)
993 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000994 for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
995 {
daniel@transgaming.com244e1832012-12-20 20:52:35 +0000996 mImageArray[i][j] = renderer->createImage();
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000997 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000998 }
999}
1000
1001TextureCubeMap::~TextureCubeMap()
1002{
1003 for (int i = 0; i < 6; i++)
1004 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001005 for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
1006 {
1007 delete mImageArray[i][j];
1008 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001009 }
1010
1011 delete mTexStorage;
1012 mTexStorage = NULL;
1013}
1014
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001015GLsizei TextureCubeMap::getWidth(GLenum target, GLint level) const
1016{
1017 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001018 return mImageArray[faceIndex(target)][level]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001019 else
1020 return 0;
1021}
1022
1023GLsizei TextureCubeMap::getHeight(GLenum target, GLint level) const
1024{
1025 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001026 return mImageArray[faceIndex(target)][level]->getHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001027 else
1028 return 0;
1029}
1030
1031GLenum TextureCubeMap::getInternalFormat(GLenum target, GLint level) const
1032{
1033 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001034 return mImageArray[faceIndex(target)][level]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001035 else
1036 return GL_NONE;
1037}
1038
daniel@transgaming.com20d36662012-10-31 19:51:43 +00001039GLenum TextureCubeMap::getActualFormat(GLenum target, GLint level) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001040{
1041 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001042 return mImageArray[faceIndex(target)][level]->getActualFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001043 else
1044 return D3DFMT_UNKNOWN;
1045}
1046
Jamie Madill88f18f42013-09-18 14:36:19 -04001047void TextureCubeMap::setImagePosX(GLint level, GLsizei width, GLsizei height, GLint internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001048{
Jamie Madill88f18f42013-09-18 14:36:19 -04001049 setImage(0, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001050}
1051
Jamie Madill88f18f42013-09-18 14:36:19 -04001052void TextureCubeMap::setImageNegX(GLint level, GLsizei width, GLsizei height, GLint internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001053{
Jamie Madill88f18f42013-09-18 14:36:19 -04001054 setImage(1, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001055}
1056
Jamie Madill88f18f42013-09-18 14:36:19 -04001057void TextureCubeMap::setImagePosY(GLint level, GLsizei width, GLsizei height, GLint internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001058{
Jamie Madill88f18f42013-09-18 14:36:19 -04001059 setImage(2, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001060}
1061
Jamie Madill88f18f42013-09-18 14:36:19 -04001062void TextureCubeMap::setImageNegY(GLint level, GLsizei width, GLsizei height, GLint internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001063{
Jamie Madill88f18f42013-09-18 14:36:19 -04001064 setImage(3, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001065}
1066
Jamie Madill88f18f42013-09-18 14:36:19 -04001067void TextureCubeMap::setImagePosZ(GLint level, GLsizei width, GLsizei height, GLint internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001068{
Jamie Madill88f18f42013-09-18 14:36:19 -04001069 setImage(4, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001070}
1071
Jamie Madill88f18f42013-09-18 14:36:19 -04001072void TextureCubeMap::setImageNegZ(GLint level, GLsizei width, GLsizei height, GLint internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001073{
Jamie Madill88f18f42013-09-18 14:36:19 -04001074 setImage(5, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001075}
1076
1077void TextureCubeMap::setCompressedImage(GLenum face, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
1078{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001079 // 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 +00001080 redefineImage(faceIndex(face), level, format, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001081
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001082 Texture::setCompressedImage(imageSize, pixels, mImageArray[faceIndex(face)][level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001083}
1084
1085void TextureCubeMap::commitRect(int face, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1086{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001087 if (level < levelCount())
1088 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001089 rx::Image *image = mImageArray[face][level];
daniel@transgaming.com0f195ad2012-10-31 19:51:59 +00001090 if (image->updateSurface(mTexStorage, face, level, xoffset, yoffset, width, height))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001091 image->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001092 }
1093}
1094
Jamie Madill88f18f42013-09-18 14:36:19 -04001095void 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 +00001096{
Jamie Madill88f18f42013-09-18 14:36:19 -04001097 if (Texture::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, mImageArray[faceIndex(target)][level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001098 {
1099 commitRect(faceIndex(target), level, xoffset, yoffset, width, height);
1100 }
1101}
1102
1103void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1104{
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +00001105 if (Texture::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[faceIndex(target)][level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001106 {
1107 commitRect(faceIndex(target), level, xoffset, yoffset, width, height);
1108 }
1109}
1110
1111// Tests for cube map sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 86.
Jamie Madillf8989902013-07-19 16:36:58 -04001112bool TextureCubeMap::isSamplerComplete(const SamplerState &samplerState) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001113{
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001114 int size = mImageArray[0][0]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001115
Jamie Madillf8989902013-07-19 16:36:58 -04001116 bool mipmapping = IsMipmapFiltered(samplerState);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001117
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001118 if (!IsTextureFilteringSupported(getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0), mRenderer))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001119 {
Jamie Madillf8989902013-07-19 16:36:58 -04001120 if (samplerState.magFilter != GL_NEAREST ||
1121 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001122 {
1123 return false;
1124 }
1125 }
1126
daniel@transgaming.comea32d482012-11-28 19:33:18 +00001127 if (!isPow2(size) && !mRenderer->getNonPower2TextureSupport())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001128 {
Jamie Madillf8989902013-07-19 16:36:58 -04001129 if (samplerState.wrapS != GL_CLAMP_TO_EDGE || samplerState.wrapT != GL_CLAMP_TO_EDGE || mipmapping)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001130 {
1131 return false;
1132 }
1133 }
1134
1135 if (!mipmapping)
1136 {
1137 if (!isCubeComplete())
1138 {
1139 return false;
1140 }
1141 }
1142 else
1143 {
1144 if (!isMipmapCubeComplete()) // Also tests for isCubeComplete()
1145 {
1146 return false;
1147 }
1148 }
1149
1150 return true;
1151}
1152
1153// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1154bool TextureCubeMap::isCubeComplete() const
1155{
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001156 if (mImageArray[0][0]->getWidth() <= 0 || mImageArray[0][0]->getHeight() != mImageArray[0][0]->getWidth())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001157 {
1158 return false;
1159 }
1160
1161 for (unsigned int face = 1; face < 6; face++)
1162 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001163 if (mImageArray[face][0]->getWidth() != mImageArray[0][0]->getWidth() ||
1164 mImageArray[face][0]->getWidth() != mImageArray[0][0]->getHeight() ||
1165 mImageArray[face][0]->getInternalFormat() != mImageArray[0][0]->getInternalFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001166 {
1167 return false;
1168 }
1169 }
1170
1171 return true;
1172}
1173
1174bool TextureCubeMap::isMipmapCubeComplete() const
1175{
1176 if (isImmutable())
1177 {
1178 return true;
1179 }
1180
1181 if (!isCubeComplete())
1182 {
1183 return false;
1184 }
1185
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001186 GLsizei size = mImageArray[0][0]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001187 int q = log2(size);
1188
1189 for (int face = 0; face < 6; face++)
1190 {
1191 for (int level = 1; level <= q; level++)
1192 {
Jamie Madill07edd442013-07-19 16:36:58 -04001193 if (!isFaceLevelComplete(face, level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001194 {
1195 return false;
1196 }
1197 }
1198 }
1199
1200 return true;
1201}
1202
Jamie Madill07edd442013-07-19 16:36:58 -04001203bool TextureCubeMap::isFaceLevelComplete(int face, int level) const
1204{
1205 ASSERT(level >= 0 && face < 6 && level < (int)ArraySize(mImageArray[face]) && mImageArray[face][level] != NULL);
1206
1207 if (isImmutable())
1208 {
1209 return true;
1210 }
1211
1212 const rx::Image *baseImage = mImageArray[face][0];
1213 GLsizei size = baseImage->getWidth();
1214
1215 if (size <= 0)
1216 {
1217 return false;
1218 }
1219
1220 // The base image level is complete if the width and height are positive
1221 if (level == 0)
1222 {
1223 return true;
1224 }
1225
1226 rx::Image *image = mImageArray[face][level];
1227
1228 if (image->getInternalFormat() != baseImage->getInternalFormat())
1229 {
1230 return false;
1231 }
1232
1233 if (mImageArray[face][level]->getWidth() != std::max(1, size >> level))
1234 {
1235 return false;
1236 }
1237
1238 return true;
1239}
1240
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001241bool TextureCubeMap::isCompressed(GLenum target, GLint level) const
1242{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001243 return IsFormatCompressed(getInternalFormat(target, level), mRenderer->getCurrentClientVersion());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001244}
1245
Geoff Lang8040f572013-07-25 16:49:54 -04001246bool TextureCubeMap::isDepth(GLenum target, GLint level) const
1247{
1248 return GetDepthBits(getInternalFormat(target, level), mRenderer->getCurrentClientVersion()) > 0;
1249}
1250
daniel@transgaming.comf032cb82012-10-31 19:51:52 +00001251// Constructs a native texture resource from the texture images, or returns an existing one
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001252void TextureCubeMap::createTexture()
1253{
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001254 GLsizei size = mImageArray[0][0]->getWidth();
daniel@transgaming.come6a09842012-09-17 21:28:55 +00001255
1256 if (!(size > 0))
daniel@transgaming.comf032cb82012-10-31 19:51:52 +00001257 return; // do not attempt to create native textures for nonexistant data
daniel@transgaming.come6a09842012-09-17 21:28:55 +00001258
sminns@adobe.comce1189b2012-09-18 20:06:35 +00001259 GLint levels = creationLevels(size);
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001260 GLenum internalformat = mImageArray[0][0]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001261
1262 delete mTexStorage;
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001263 mTexStorage = new rx::TextureStorageInterfaceCube(mRenderer, levels, internalformat, mUsage, false, size);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001264
1265 if (mTexStorage->isManaged())
1266 {
1267 int levels = levelCount();
1268
1269 for (int face = 0; face < 6; face++)
1270 {
1271 for (int level = 0; level < levels; level++)
1272 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001273 mImageArray[face][level]->setManagedSurface(mTexStorage, face, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001274 }
1275 }
1276 }
1277
1278 mDirtyImages = true;
1279}
1280
1281void TextureCubeMap::updateTexture()
1282{
Jamie Madilleb3665c2013-07-19 16:36:57 -04001283 int levels = (isMipmapCubeComplete() ? levelCount() : 1);
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +00001284
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001285 for (int face = 0; face < 6; face++)
1286 {
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001287 for (int level = 0; level < levels; level++)
1288 {
Jamie Madill07edd442013-07-19 16:36:58 -04001289 updateTextureFaceLevel(face, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001290 }
1291 }
1292}
1293
Jamie Madill07edd442013-07-19 16:36:58 -04001294void TextureCubeMap::updateTextureFaceLevel(int face, int level)
1295{
1296 ASSERT(level >= 0 && face < 6 && level < (int)ArraySize(mImageArray[face]) && mImageArray[face][level] != NULL);
1297 rx::Image *image = mImageArray[face][level];
1298
1299 if (image->isDirty())
1300 {
1301 commitRect(face, level, 0, 0, image->getWidth(), image->getHeight());
1302 }
1303}
1304
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001305void TextureCubeMap::convertToRenderTarget()
1306{
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001307 rx::TextureStorageInterfaceCube *newTexStorage = NULL;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001308
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001309 if (mImageArray[0][0]->getWidth() != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001310 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001311 GLsizei size = mImageArray[0][0]->getWidth();
shannon.woods@transgaming.com6bb48862013-02-28 23:09:34 +00001312 GLint levels = mTexStorage != NULL ? mTexStorage->levelCount() : creationLevels(size);
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001313 GLenum internalformat = mImageArray[0][0]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001314
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001315 newTexStorage = new rx::TextureStorageInterfaceCube(mRenderer, levels, internalformat, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, true, size);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001316
1317 if (mTexStorage != NULL)
1318 {
daniel@transgaming.com1d80eee2012-11-28 19:33:31 +00001319 if (!mRenderer->copyToRenderTarget(newTexStorage, mTexStorage))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001320 {
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +00001321 delete newTexStorage;
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +00001322 return gl::error(GL_OUT_OF_MEMORY);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001323 }
1324 }
1325 }
1326
1327 delete mTexStorage;
1328 mTexStorage = newTexStorage;
1329
1330 mDirtyImages = true;
1331}
1332
Jamie Madill88f18f42013-09-18 14:36:19 -04001333void TextureCubeMap::setImage(int faceIndex, GLint level, GLsizei width, GLsizei height, GLint internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001334{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001335 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1336 GLint sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
1337 : GetSizedInternalFormat(format, type, clientVersion);
1338
1339 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001340
Jamie Madill88f18f42013-09-18 14:36:19 -04001341 Texture::setImage(unpack, type, pixels, mImageArray[faceIndex][level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001342}
1343
1344unsigned int TextureCubeMap::faceIndex(GLenum face)
1345{
1346 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
1347 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
1348 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
1349 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
1350 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
1351
1352 return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
1353}
1354
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001355void TextureCubeMap::redefineImage(int face, GLint level, GLint internalformat, GLsizei width, GLsizei height)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001356{
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001357 // If there currently is a corresponding storage texture image, it has these parameters
1358 const int storageWidth = std::max(1, mImageArray[0][0]->getWidth() >> level);
1359 const int storageHeight = std::max(1, mImageArray[0][0]->getHeight() >> level);
1360 const int storageFormat = mImageArray[0][0]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001361
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001362 mImageArray[face][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, width, height, 1, false);
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001363
1364 if (mTexStorage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001365 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001366 const int storageLevels = mTexStorage->levelCount();
1367
1368 if ((level >= storageLevels && storageLevels != 0) ||
1369 width != storageWidth ||
1370 height != storageHeight ||
1371 internalformat != storageFormat) // Discard mismatched storage
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001372 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001373 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001374 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001375 for (int f = 0; f < 6; f++)
1376 {
1377 mImageArray[f][i]->markDirty();
1378 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001379 }
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001380
1381 delete mTexStorage;
1382 mTexStorage = NULL;
1383
1384 mDirtyImages = true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001385 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001386 }
1387}
1388
1389void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1390{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001391 unsigned int faceindex = faceIndex(target);
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001392 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1393 GLint sizedInternalFormat = IsSizedInternalFormat(format, clientVersion) ? format
1394 : GetSizedInternalFormat(format, GL_UNSIGNED_BYTE, clientVersion);
1395 redefineImage(faceindex, level, sizedInternalFormat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001396
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001397 if (!mImageArray[faceindex][level]->isRenderableFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001398 {
shannon.woods%transgaming.com@gtempaccount.come5dcce72013-04-13 03:44:33 +00001399 mImageArray[faceindex][level]->copy(0, 0, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001400 mDirtyImages = true;
1401 }
1402 else
1403 {
1404 if (!mTexStorage || !mTexStorage->isRenderTarget())
1405 {
1406 convertToRenderTarget();
1407 }
1408
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001409 mImageArray[faceindex][level]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001410
1411 ASSERT(width == height);
1412
1413 if (width > 0 && level < levelCount())
1414 {
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +00001415 gl::Rectangle sourceRect;
1416 sourceRect.x = x;
1417 sourceRect.width = width;
1418 sourceRect.y = y;
1419 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001420
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +00001421 mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001422 }
1423 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001424}
1425
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001426void 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 +00001427{
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001428 GLsizei size = mImageArray[faceIndex(target)][level]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001429
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001430 if (xoffset + width > size || yoffset + height > size || zoffset != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001431 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +00001432 return gl::error(GL_INVALID_VALUE);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001433 }
1434
Jamie Madill07edd442013-07-19 16:36:58 -04001435 unsigned int face = faceIndex(target);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001436
Jamie Madill07edd442013-07-19 16:36:58 -04001437 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
1438 // the current level we're copying to is defined (with appropriate format, width & height)
1439 bool canCreateRenderTarget = isFaceLevelComplete(face, level) && isFaceLevelComplete(face, 0);
1440
1441 if (!mImageArray[face][level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001442 {
Jamie Madill07edd442013-07-19 16:36:58 -04001443 mImageArray[face][level]->copy(0, 0, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001444 mDirtyImages = true;
1445 }
1446 else
1447 {
1448 if (!mTexStorage || !mTexStorage->isRenderTarget())
1449 {
1450 convertToRenderTarget();
1451 }
1452
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001453 if (level < levelCount())
1454 {
Jamie Madill07edd442013-07-19 16:36:58 -04001455 updateTextureFaceLevel(face, level);
1456
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001457 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1458
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +00001459 gl::Rectangle sourceRect;
1460 sourceRect.x = x;
1461 sourceRect.width = width;
1462 sourceRect.y = y;
1463 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001464
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001465 mRenderer->copyImage(source, sourceRect, gl::GetFormat(mImageArray[0][0]->getInternalFormat(), clientVersion),
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +00001466 xoffset, yoffset, mTexStorage, target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001467 }
1468 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001469}
1470
1471void TextureCubeMap::storage(GLsizei levels, GLenum internalformat, GLsizei size)
1472{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001473 delete mTexStorage;
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001474 mTexStorage = new rx::TextureStorageInterfaceCube(mRenderer, levels, internalformat, mUsage, false, size);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001475 mImmutable = true;
1476
1477 for (int level = 0; level < levels; level++)
1478 {
1479 for (int face = 0; face < 6; face++)
1480 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001481 mImageArray[face][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, size, size, 1, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001482 size = std::max(1, size >> 1);
1483 }
1484 }
1485
1486 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1487 {
1488 for (int face = 0; face < 6; face++)
1489 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001490 mImageArray[face][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, GL_NONE, 0, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001491 }
1492 }
1493
1494 if (mTexStorage->isManaged())
1495 {
1496 int levels = levelCount();
1497
1498 for (int face = 0; face < 6; face++)
1499 {
1500 for (int level = 0; level < levels; level++)
1501 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001502 mImageArray[face][level]->setManagedSurface(mTexStorage, face, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001503 }
1504 }
1505 }
1506}
1507
1508void TextureCubeMap::generateMipmaps()
1509{
1510 if (!isCubeComplete())
1511 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +00001512 return gl::error(GL_INVALID_OPERATION);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001513 }
1514
daniel@transgaming.comea32d482012-11-28 19:33:18 +00001515 if (!mRenderer->getNonPower2TextureSupport())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001516 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001517 if (!isPow2(mImageArray[0][0]->getWidth()))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001518 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +00001519 return gl::error(GL_INVALID_OPERATION);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001520 }
1521 }
1522
1523 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001524 unsigned int q = log2(mImageArray[0][0]->getWidth());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001525 for (unsigned int f = 0; f < 6; f++)
1526 {
1527 for (unsigned int i = 1; i <= q; i++)
1528 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001529 redefineImage(f, i, mImageArray[f][0]->getInternalFormat(),
shannon.woods@transgaming.com8a406682013-02-28 23:15:26 +00001530 std::max(mImageArray[f][0]->getWidth() >> i, 1),
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001531 std::max(mImageArray[f][0]->getWidth() >> i, 1));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001532 }
1533 }
1534
1535 if (mTexStorage && mTexStorage->isRenderTarget())
1536 {
1537 for (unsigned int f = 0; f < 6; f++)
1538 {
1539 for (unsigned int i = 1; i <= q; i++)
1540 {
daniel@transgaming.com0ad830b2012-10-31 19:52:12 +00001541 mTexStorage->generateMipmap(f, i);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001542
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001543 mImageArray[f][i]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001544 }
1545 }
1546 }
1547 else
1548 {
1549 for (unsigned int f = 0; f < 6; f++)
1550 {
1551 for (unsigned int i = 1; i <= q; i++)
1552 {
daniel@transgaming.com4ba24062012-12-20 20:54:24 +00001553 mRenderer->generateMipmap(mImageArray[f][i], mImageArray[f][i - 1]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001554 }
1555 }
1556 }
1557}
1558
Geoff Lang8040f572013-07-25 16:49:54 -04001559Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target, GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001560{
1561 if (!IsCubemapTextureTarget(target))
1562 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +00001563 return gl::error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001564 }
1565
1566 unsigned int face = faceIndex(target);
1567
Geoff Lang8040f572013-07-25 16:49:54 -04001568 Renderbuffer *renderBuffer = mRenderbufferProxies.get(level, face);
1569 if (!renderBuffer)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001570 {
Geoff Lang8040f572013-07-25 16:49:54 -04001571 renderBuffer = new Renderbuffer(mRenderer, id(), new RenderbufferTextureCubeMap(this, target, level));
1572 mRenderbufferProxies.add(level, face, renderBuffer);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001573 }
1574
Geoff Lang8040f572013-07-25 16:49:54 -04001575 return renderBuffer;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001576}
1577
Geoff Lang8040f572013-07-25 16:49:54 -04001578unsigned int TextureCubeMap::getRenderTargetSerial(GLenum faceTarget, GLint level)
1579{
1580 if (!mTexStorage || !mTexStorage->isRenderTarget())
1581 {
1582 convertToRenderTarget();
1583 }
1584
1585 return mTexStorage ? mTexStorage->getRenderTargetSerial(faceTarget, level) : 0;
1586}
1587
1588rx::RenderTarget *TextureCubeMap::getRenderTarget(GLenum target, GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001589{
1590 ASSERT(IsCubemapTextureTarget(target));
1591
1592 // ensure the underlying texture is created
1593 if (getStorage(true) == NULL)
1594 {
1595 return NULL;
1596 }
1597
1598 updateTexture();
Geoff Lang8040f572013-07-25 16:49:54 -04001599
1600 // ensure this is NOT a depth texture
1601 if (isDepth(target, level))
1602 {
1603 return NULL;
1604 }
1605
1606 return mTexStorage->getRenderTarget(target, level);
1607}
1608
1609rx::RenderTarget *TextureCubeMap::getDepthStencil(GLenum target, GLint level)
1610{
1611 ASSERT(IsCubemapTextureTarget(target));
1612
1613 // ensure the underlying texture is created
1614 if (getStorage(true) == NULL)
1615 {
1616 return NULL;
1617 }
1618
1619 updateTexture();
1620
1621 // ensure this is a depth texture
1622 if (!isDepth(target, level))
1623 {
1624 return NULL;
1625 }
1626
1627 return mTexStorage->getRenderTarget(target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001628}
1629
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +00001630int TextureCubeMap::levelCount()
1631{
1632 return mTexStorage ? mTexStorage->levelCount() - getLodOffset() : 0;
1633}
1634
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001635rx::TextureStorageInterface *TextureCubeMap::getStorage(bool renderTarget)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001636{
1637 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
1638 {
1639 if (renderTarget)
1640 {
1641 convertToRenderTarget();
1642 }
1643 else
1644 {
1645 createTexture();
1646 }
1647 }
1648
1649 return mTexStorage;
1650}
1651
Geoff Lang4907f2c2013-07-25 12:53:57 -04001652Texture3D::Texture3D(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_3D)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001653{
1654 mTexStorage = NULL;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001655
1656 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1657 {
1658 mImageArray[i] = renderer->createImage();
1659 }
1660}
1661
1662Texture3D::~Texture3D()
1663{
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001664 delete mTexStorage;
1665 mTexStorage = NULL;
1666
1667 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1668 {
1669 delete mImageArray[i];
1670 }
1671}
1672
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001673GLsizei Texture3D::getWidth(GLint level) const
1674{
1675 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getWidth() : 0;
1676}
1677
1678GLsizei Texture3D::getHeight(GLint level) const
1679{
1680 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getHeight() : 0;
1681}
1682
1683GLsizei Texture3D::getDepth(GLint level) const
1684{
1685 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getDepth() : 0;
1686}
1687
1688GLenum Texture3D::getInternalFormat(GLint level) const
1689{
1690 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getInternalFormat() : GL_NONE;
1691}
1692
1693GLenum Texture3D::getActualFormat(GLint level) const
1694{
1695 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getActualFormat() : D3DFMT_UNKNOWN;
1696}
1697
1698bool Texture3D::isCompressed(GLint level) const
1699{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001700 return IsFormatCompressed(getInternalFormat(level), mRenderer->getCurrentClientVersion());
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001701}
1702
1703bool Texture3D::isDepth(GLint level) const
1704{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001705 return GetDepthBits(getInternalFormat(level), mRenderer->getCurrentClientVersion()) > 0;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001706}
1707
Jamie Madill88f18f42013-09-18 14:36:19 -04001708void Texture3D::setImage(GLint level, GLsizei width, GLsizei height, GLsizei depth, GLint internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001709{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001710 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1711 GLint sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
1712 : GetSizedInternalFormat(format, type, clientVersion);
1713 redefineImage(level, sizedInternalFormat, width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001714
Jamie Madill88f18f42013-09-18 14:36:19 -04001715 Texture::setImage(unpack, type, pixels, mImageArray[level]);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001716}
1717
1718void Texture3D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
1719{
1720 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1721 redefineImage(level, format, width, height, depth);
1722
1723 Texture::setCompressedImage(imageSize, pixels, mImageArray[level]);
1724}
1725
Jamie Madill88f18f42013-09-18 14:36:19 -04001726void 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 +00001727{
Jamie Madill88f18f42013-09-18 14:36:19 -04001728 if (Texture::subImage(xoffset, yoffset, zoffset, width, height, depth, format, type, unpack, pixels, mImageArray[level]))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001729 {
1730 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1731 }
1732}
1733
1734void Texture3D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
1735{
1736 if (Texture::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth, format, imageSize, pixels, mImageArray[level]))
1737 {
1738 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1739 }
1740}
1741
1742void Texture3D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
1743{
1744 delete mTexStorage;
1745 mTexStorage = new rx::TextureStorageInterface3D(mRenderer, levels, internalformat, mUsage, width, height, depth);
1746 mImmutable = true;
1747
1748 for (int level = 0; level < levels; level++)
1749 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001750 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, true);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001751 width = std::max(1, width >> 1);
1752 height = std::max(1, height >> 1);
1753 depth = std::max(1, depth >> 1);
1754 }
1755
1756 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1757 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001758 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, GL_NONE, 0, 0, 0, true);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001759 }
1760
1761 if (mTexStorage->isManaged())
1762 {
1763 int levels = levelCount();
1764
1765 for (int level = 0; level < levels; level++)
1766 {
1767 mImageArray[level]->setManagedSurface(mTexStorage, level);
1768 }
1769 }
1770}
1771
1772
1773void Texture3D::generateMipmaps()
1774{
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001775 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1776 unsigned int q = log2(std::max(mImageArray[0]->getWidth(), mImageArray[0]->getHeight()));
1777 for (unsigned int i = 1; i <= q; i++)
1778 {
1779 redefineImage(i, mImageArray[0]->getInternalFormat(),
1780 std::max(mImageArray[0]->getWidth() >> i, 1),
1781 std::max(mImageArray[0]->getHeight() >> i, 1),
1782 std::max(mImageArray[0]->getDepth() >> i, 1));
1783 }
1784
1785 if (mTexStorage && mTexStorage->isRenderTarget())
1786 {
1787 for (unsigned int i = 1; i <= q; i++)
1788 {
1789 mTexStorage->generateMipmap(i);
1790
1791 mImageArray[i]->markClean();
1792 }
1793 }
1794 else
1795 {
1796 for (unsigned int i = 1; i <= q; i++)
1797 {
1798 mRenderer->generateMipmap(mImageArray[i], mImageArray[i - 1]);
1799 }
1800 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001801}
1802
1803void Texture3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1804{
1805 if (xoffset + width > mImageArray[level]->getWidth() || yoffset + height > mImageArray[level]->getHeight() || zoffset >= mImageArray[level]->getDepth())
1806 {
1807 return gl::error(GL_INVALID_VALUE);
1808 }
1809
Jamie Madill07edd442013-07-19 16:36:58 -04001810 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
1811 // the current level we're copying to is defined (with appropriate format, width & height)
1812 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
1813
1814 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001815 {
1816 mImageArray[level]->copy(xoffset, yoffset, zoffset, x, y, width, height, source);
1817 mDirtyImages = true;
1818 }
1819 else
1820 {
1821 if (!mTexStorage || !mTexStorage->isRenderTarget())
1822 {
1823 convertToRenderTarget();
1824 }
1825
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001826 if (level < levelCount())
1827 {
Jamie Madill07edd442013-07-19 16:36:58 -04001828 updateTextureLevel(level);
1829
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001830 gl::Rectangle sourceRect;
1831 sourceRect.x = x;
1832 sourceRect.width = width;
1833 sourceRect.y = y;
1834 sourceRect.height = height;
1835
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001836 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1837
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001838 mRenderer->copyImage(source, sourceRect,
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001839 gl::GetFormat(mImageArray[0]->getInternalFormat(), clientVersion),
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001840 xoffset, yoffset, zoffset, mTexStorage, level);
1841 }
1842 }
1843}
1844
Jamie Madillf8989902013-07-19 16:36:58 -04001845bool Texture3D::isSamplerComplete(const SamplerState &samplerState) const
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001846{
1847 GLsizei width = mImageArray[0]->getWidth();
1848 GLsizei height = mImageArray[0]->getHeight();
1849 GLsizei depth = mImageArray[0]->getDepth();
1850
1851 if (width <= 0 || height <= 0 || depth <= 0)
1852 {
1853 return false;
1854 }
1855
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001856 if (!IsTextureFilteringSupported(getInternalFormat(0), mRenderer))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001857 {
Jamie Madillf8989902013-07-19 16:36:58 -04001858 if (samplerState.magFilter != GL_NEAREST ||
1859 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001860 {
1861 return false;
1862 }
1863 }
1864
Jamie Madillf8989902013-07-19 16:36:58 -04001865 if (IsMipmapFiltered(samplerState) && !isMipmapComplete())
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001866 {
1867 return false;
1868 }
1869
1870 return true;
1871}
1872
1873bool Texture3D::isMipmapComplete() const
1874{
Jamie Madill07edd442013-07-19 16:36:58 -04001875 GLsizei width = mImageArray[0]->getWidth();
1876 GLsizei height = mImageArray[0]->getHeight();
1877 GLsizei depth = mImageArray[0]->getDepth();
1878
1879 int q = log2(std::max(std::max(width, height), depth));
1880
1881 for (int level = 0; level <= q; level++)
1882 {
1883 if (!isLevelComplete(level))
1884 {
1885 return false;
1886 }
1887 }
1888
1889 return true;
1890}
1891
1892bool Texture3D::isLevelComplete(int level) const
1893{
1894 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1895
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001896 if (isImmutable())
1897 {
1898 return true;
1899 }
1900
Jamie Madill07edd442013-07-19 16:36:58 -04001901 rx::Image *baseImage = mImageArray[0];
1902
1903 GLsizei width = baseImage->getWidth();
1904 GLsizei height = baseImage->getHeight();
1905 GLsizei depth = baseImage->getDepth();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001906
1907 if (width <= 0 || height <= 0 || depth <= 0)
1908 {
1909 return false;
1910 }
1911
Jamie Madill07edd442013-07-19 16:36:58 -04001912 if (level == 0)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001913 {
Jamie Madill07edd442013-07-19 16:36:58 -04001914 return true;
1915 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001916
Jamie Madill07edd442013-07-19 16:36:58 -04001917 rx::Image *levelImage = mImageArray[level];
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001918
Jamie Madill07edd442013-07-19 16:36:58 -04001919 if (levelImage->getInternalFormat() != baseImage->getInternalFormat())
1920 {
1921 return false;
1922 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001923
Jamie Madill07edd442013-07-19 16:36:58 -04001924 if (levelImage->getWidth() != std::max(1, width >> level))
1925 {
1926 return false;
1927 }
1928
1929 if (levelImage->getHeight() != std::max(1, height >> level))
1930 {
1931 return false;
1932 }
1933
1934 if (levelImage->getDepth() != std::max(1, depth >> level))
1935 {
1936 return false;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001937 }
1938
1939 return true;
1940}
1941
Geoff Lang8040f572013-07-25 16:49:54 -04001942Renderbuffer *Texture3D::getRenderbuffer(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001943{
Geoff Lang8040f572013-07-25 16:49:54 -04001944 Renderbuffer *renderBuffer = mRenderbufferProxies.get(level, layer);
1945 if (!renderBuffer)
1946 {
Geoff Langd5d8e392013-07-25 16:53:03 -04001947 renderBuffer = new Renderbuffer(mRenderer, id(), new RenderbufferTexture3DLayer(this, level, layer));
1948 mRenderbufferProxies.add(level, 0, renderBuffer);
Geoff Lang8040f572013-07-25 16:49:54 -04001949 }
1950
1951 return renderBuffer;
1952}
1953
1954unsigned int Texture3D::getRenderTargetSerial(GLint level, GLint layer)
1955{
1956 if (!mTexStorage || !mTexStorage->isRenderTarget())
1957 {
1958 convertToRenderTarget();
1959 }
1960
1961 return mTexStorage ? mTexStorage->getRenderTargetSerial(level, layer) : 0;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001962}
1963
1964int Texture3D::levelCount()
1965{
1966 return mTexStorage ? mTexStorage->levelCount() : 0;
1967}
1968
1969void Texture3D::createTexture()
1970{
1971 GLsizei width = mImageArray[0]->getWidth();
1972 GLsizei height = mImageArray[0]->getHeight();
1973 GLsizei depth = mImageArray[0]->getDepth();
1974
1975 if (!(width > 0 && height > 0 && depth > 0))
1976 return; // do not attempt to create native textures for nonexistant data
1977
1978 GLint levels = creationLevels(width, height, depth);
1979 GLenum internalformat = mImageArray[0]->getInternalFormat();
1980
1981 delete mTexStorage;
1982 mTexStorage = new rx::TextureStorageInterface3D(mRenderer, levels, internalformat, mUsage, width, height, depth);
1983
1984 if (mTexStorage->isManaged())
1985 {
1986 int levels = levelCount();
1987
1988 for (int level = 0; level < levels; level++)
1989 {
1990 mImageArray[level]->setManagedSurface(mTexStorage, level);
1991 }
1992 }
1993
1994 mDirtyImages = true;
1995}
1996
1997void Texture3D::updateTexture()
1998{
Jamie Madilleb3665c2013-07-19 16:36:57 -04001999 int levels = (isMipmapComplete() ? levelCount() : 1);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002000
2001 for (int level = 0; level < levels; level++)
2002 {
Jamie Madill07edd442013-07-19 16:36:58 -04002003 updateTextureLevel(level);
2004 }
2005}
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002006
Jamie Madill07edd442013-07-19 16:36:58 -04002007void Texture3D::updateTextureLevel(int level)
2008{
2009 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
2010
2011 rx::Image *image = mImageArray[level];
2012
2013 if (image->isDirty())
2014 {
2015 commitRect(level, 0, 0, 0, mImageArray[level]->getWidth(), mImageArray[level]->getHeight(), mImageArray[level]->getDepth());
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002016 }
2017}
2018
2019void Texture3D::convertToRenderTarget()
2020{
2021 rx::TextureStorageInterface3D *newTexStorage = NULL;
2022
2023 if (mImageArray[0]->getWidth() != 0 && mImageArray[0]->getHeight() != 0 && mImageArray[0]->getDepth() != 0)
2024 {
2025 GLsizei width = mImageArray[0]->getWidth();
2026 GLsizei height = mImageArray[0]->getHeight();
2027 GLsizei depth = mImageArray[0]->getDepth();
2028 GLint levels = mTexStorage != NULL ? mTexStorage->levelCount() : creationLevels(width, height, depth);
2029 GLenum internalformat = mImageArray[0]->getInternalFormat();
2030
2031 newTexStorage = new rx::TextureStorageInterface3D(mRenderer, levels, internalformat, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, width, height, depth);
2032
2033 if (mTexStorage != NULL)
2034 {
2035 if (!mRenderer->copyToRenderTarget(newTexStorage, mTexStorage))
2036 {
2037 delete newTexStorage;
2038 return gl::error(GL_OUT_OF_MEMORY);
2039 }
2040 }
2041 }
2042
2043 delete mTexStorage;
2044 mTexStorage = newTexStorage;
2045
2046 mDirtyImages = true;
2047}
2048
Geoff Lang8040f572013-07-25 16:49:54 -04002049rx::RenderTarget *Texture3D::getRenderTarget(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002050{
Geoff Lang8040f572013-07-25 16:49:54 -04002051 // ensure the underlying texture is created
2052 if (getStorage(true) == NULL)
2053 {
2054 return NULL;
2055 }
2056
2057 updateTexture();
2058
2059 // ensure this is NOT a depth texture
2060 if (isDepth(level))
2061 {
2062 return NULL;
2063 }
2064
2065 return mTexStorage->getRenderTarget(level, layer);
2066}
2067
2068rx::RenderTarget *Texture3D::getDepthStencil(GLint level, GLint layer)
2069{
2070 // ensure the underlying texture is created
2071 if (getStorage(true) == NULL)
2072 {
2073 return NULL;
2074 }
2075
2076 updateTexture();
2077
2078 // ensure this is a depth texture
2079 if (!isDepth(level))
2080 {
2081 return NULL;
2082 }
2083
2084 return mTexStorage->getRenderTarget(level, layer);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002085}
2086
2087rx::TextureStorageInterface *Texture3D::getStorage(bool renderTarget)
2088{
2089 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
2090 {
2091 if (renderTarget)
2092 {
2093 convertToRenderTarget();
2094 }
2095 else
2096 {
2097 createTexture();
2098 }
2099 }
2100
2101 return mTexStorage;
2102}
2103
2104void Texture3D::redefineImage(GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth)
2105{
2106 // If there currently is a corresponding storage texture image, it has these parameters
2107 const int storageWidth = std::max(1, mImageArray[0]->getWidth() >> level);
2108 const int storageHeight = std::max(1, mImageArray[0]->getHeight() >> level);
2109 const int storageDepth = std::max(1, mImageArray[0]->getDepth() >> level);
2110 const int storageFormat = mImageArray[0]->getInternalFormat();
2111
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00002112 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, false);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002113
2114 if (mTexStorage)
2115 {
2116 const int storageLevels = mTexStorage->levelCount();
2117
2118 if ((level >= storageLevels && storageLevels != 0) ||
2119 width != storageWidth ||
2120 height != storageHeight ||
2121 depth != storageDepth ||
2122 internalformat != storageFormat) // Discard mismatched storage
2123 {
2124 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
2125 {
2126 mImageArray[i]->markDirty();
2127 }
2128
2129 delete mTexStorage;
2130 mTexStorage = NULL;
2131 mDirtyImages = true;
2132 }
2133 }
2134}
2135
2136void Texture3D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth)
2137{
2138 if (level < levelCount())
2139 {
2140 rx::Image *image = mImageArray[level];
2141 if (image->updateSurface(mTexStorage, level, xoffset, yoffset, zoffset, width, height, depth))
2142 {
2143 image->markClean();
2144 }
2145 }
2146}
2147
Geoff Lang4907f2c2013-07-25 12:53:57 -04002148Texture2DArray::Texture2DArray(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_2D_ARRAY)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002149{
2150 mTexStorage = NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002151
2152 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2153 {
2154 mLayerCounts[level] = 0;
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002155 mImageArray[level] = NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002156 }
2157}
2158
2159Texture2DArray::~Texture2DArray()
2160{
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002161 delete mTexStorage;
2162 mTexStorage = NULL;
2163 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2164 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002165 for (int layer = 0; layer < mLayerCounts[level]; ++layer)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002166 {
2167 delete mImageArray[level][layer];
2168 }
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002169 delete[] mImageArray[level];
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002170 }
2171}
2172
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002173GLsizei Texture2DArray::getWidth(GLint level) const
2174{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002175 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 +00002176}
2177
2178GLsizei Texture2DArray::getHeight(GLint level) const
2179{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002180 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 +00002181}
2182
2183GLsizei Texture2DArray::getDepth(GLint level) const
2184{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002185 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mLayerCounts[level] : 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002186}
2187
2188GLenum Texture2DArray::getInternalFormat(GLint level) const
2189{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002190 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 +00002191}
2192
2193GLenum Texture2DArray::getActualFormat(GLint level) const
2194{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002195 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 +00002196}
2197
2198bool Texture2DArray::isCompressed(GLint level) const
2199{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00002200 return IsFormatCompressed(getInternalFormat(level), mRenderer->getCurrentClientVersion());
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002201}
2202
2203bool Texture2DArray::isDepth(GLint level) const
2204{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00002205 return GetDepthBits(getInternalFormat(level), mRenderer->getCurrentClientVersion()) > 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002206}
2207
Jamie Madill88f18f42013-09-18 14:36:19 -04002208void Texture2DArray::setImage(GLint level, GLsizei width, GLsizei height, GLsizei depth, GLint internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002209{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00002210 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2211 GLint sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
2212 : GetSizedInternalFormat(format, type, clientVersion);
2213 redefineImage(level, sizedInternalFormat, width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002214
Jamie Madill88f18f42013-09-18 14:36:19 -04002215 GLsizei inputDepthPitch = gl::GetDepthPitch(sizedInternalFormat, type, clientVersion, width, height, unpack.alignment);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002216
2217 for (int i = 0; i < depth; i++)
2218 {
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002219 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
Jamie Madill88f18f42013-09-18 14:36:19 -04002220 Texture::setImage(unpack, type, layerPixels, mImageArray[level][i]);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002221 }
2222}
2223
2224void Texture2DArray::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
2225{
2226 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
2227 redefineImage(level, format, width, height, depth);
2228
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002229 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2230 GLsizei inputDepthPitch = gl::GetDepthPitch(format, GL_UNSIGNED_BYTE, clientVersion, width, height, 1);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002231
2232 for (int i = 0; i < depth; i++)
2233 {
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002234 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002235 Texture::setCompressedImage(imageSize, layerPixels, mImageArray[level][i]);
2236 }
2237}
2238
Jamie Madill88f18f42013-09-18 14:36:19 -04002239void 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 +00002240{
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002241 GLint internalformat = getInternalFormat(level);
2242 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Jamie Madill88f18f42013-09-18 14:36:19 -04002243 GLsizei inputDepthPitch = gl::GetDepthPitch(internalformat, type, clientVersion, width, height, unpack.alignment);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002244
2245 for (int i = 0; i < depth; i++)
2246 {
2247 int layer = zoffset + i;
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002248 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002249
Jamie Madill88f18f42013-09-18 14:36:19 -04002250 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 +00002251 {
2252 commitRect(level, xoffset, yoffset, layer, width, height);
2253 }
2254 }
2255}
2256
2257void Texture2DArray::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
2258{
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002259 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2260 GLsizei inputDepthPitch = gl::GetDepthPitch(format, GL_UNSIGNED_BYTE, clientVersion, width, height, 1);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002261
2262 for (int i = 0; i < depth; i++)
2263 {
2264 int layer = zoffset + i;
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002265 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002266
2267 if (Texture::subImageCompressed(xoffset, yoffset, zoffset, width, height, 1, format, imageSize, layerPixels, mImageArray[level][layer]))
2268 {
2269 commitRect(level, xoffset, yoffset, layer, width, height);
2270 }
2271 }
2272}
2273
2274void Texture2DArray::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2275{
2276 delete mTexStorage;
2277 mTexStorage = new rx::TextureStorageInterface2DArray(mRenderer, levels, internalformat, mUsage, width, height, depth);
2278 mImmutable = true;
2279
2280 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2281 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002282 GLsizei levelWidth = std::max(width >> level, 1);
Geoff Lange836cf22013-08-05 14:12:37 -04002283 GLsizei levelHeight = std::max(height >> level, 1);
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002284
2285 // Clear this level
2286 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002287 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002288 delete mImageArray[level][layer];
2289 }
2290 delete[] mImageArray[level];
2291 mImageArray[level] = NULL;
2292 mLayerCounts[level] = 0;
2293
2294 if (level < levels)
2295 {
2296 // Create new images for this level
2297 mImageArray[level] = new rx::Image*[depth]();
2298 mLayerCounts[level] = depth;
2299
2300 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002301 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002302 mImageArray[level][layer] = mRenderer->createImage();
2303 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, levelWidth,
2304 levelHeight, 1, true);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002305 }
2306 }
2307 }
2308
2309 if (mTexStorage->isManaged())
2310 {
2311 int levels = levelCount();
2312
2313 for (int level = 0; level < levels; level++)
2314 {
2315 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2316 {
2317 mImageArray[level][layer]->setManagedSurface(mTexStorage, layer, level);
2318 }
2319 }
2320 }
2321}
2322
2323void Texture2DArray::generateMipmaps()
2324{
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00002325 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
2326 int q = log2(std::max(getWidth(0), getHeight(0)));
2327 for (int i = 1; i <= q; i++)
2328 {
2329 redefineImage(i, getInternalFormat(0), std::max(getWidth(0) >> i, 1), std::max(getHeight(0) >> i, 1), getDepth(0));
2330 }
2331
2332 if (mTexStorage && mTexStorage->isRenderTarget())
2333 {
2334 for (int level = 1; level <= q; level++)
2335 {
2336 mTexStorage->generateMipmap(level);
2337
2338 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2339 {
2340 mImageArray[level][layer]->markClean();
2341 }
2342 }
2343 }
2344 else
2345 {
2346 for (int level = 1; level <= q; level++)
2347 {
2348 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2349 {
2350 mRenderer->generateMipmap(mImageArray[level][layer], mImageArray[level - 1][layer]);
2351 }
2352 }
2353 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002354}
2355
2356void Texture2DArray::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
2357{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002358 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 +00002359 {
2360 return gl::error(GL_INVALID_VALUE);
2361 }
2362
Jamie Madill07edd442013-07-19 16:36:58 -04002363 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
2364 // the current level we're copying to is defined (with appropriate format, width & height)
2365 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
2366
2367 if (!mImageArray[level][0]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002368 {
2369 mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, x, y, width, height, source);
2370 mDirtyImages = true;
2371 }
2372 else
2373 {
2374 if (!mTexStorage || !mTexStorage->isRenderTarget())
2375 {
2376 convertToRenderTarget();
2377 }
2378
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002379 if (level < levelCount())
2380 {
Jamie Madill07edd442013-07-19 16:36:58 -04002381 updateTextureLevel(level);
2382
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002383 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2384
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002385 gl::Rectangle sourceRect;
2386 sourceRect.x = x;
2387 sourceRect.width = width;
2388 sourceRect.y = y;
2389 sourceRect.height = height;
2390
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002391 mRenderer->copyImage(source, sourceRect, gl::GetFormat(getInternalFormat(0), clientVersion),
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002392 xoffset, yoffset, zoffset, mTexStorage, level);
2393 }
2394 }
2395}
2396
Jamie Madillf8989902013-07-19 16:36:58 -04002397bool Texture2DArray::isSamplerComplete(const SamplerState &samplerState) const
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002398{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002399 GLsizei width = getWidth(0);
2400 GLsizei height = getHeight(0);
2401 GLsizei depth = getDepth(0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002402
2403 if (width <= 0 || height <= 0 || depth <= 0)
2404 {
2405 return false;
2406 }
2407
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00002408 if (!IsTextureFilteringSupported(getInternalFormat(0), mRenderer))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002409 {
Jamie Madillf8989902013-07-19 16:36:58 -04002410 if (samplerState.magFilter != GL_NEAREST ||
2411 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002412 {
2413 return false;
2414 }
2415 }
2416
Jamie Madillf8989902013-07-19 16:36:58 -04002417 if (IsMipmapFiltered(samplerState) && !isMipmapComplete())
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002418 {
2419 return false;
2420 }
2421
2422 return true;
2423}
2424
2425bool Texture2DArray::isMipmapComplete() const
2426{
Jamie Madill07edd442013-07-19 16:36:58 -04002427 GLsizei width = getWidth(0);
2428 GLsizei height = getHeight(0);
2429
2430 int q = log2(std::max(width, height));
2431
2432 for (int level = 1; level <= q; level++)
2433 {
2434 if (!isLevelComplete(level))
2435 {
2436 return false;
2437 }
2438 }
2439
2440 return true;
2441}
2442
2443bool Texture2DArray::isLevelComplete(int level) const
2444{
2445 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
2446
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002447 if (isImmutable())
2448 {
2449 return true;
2450 }
2451
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002452 GLsizei width = getWidth(0);
2453 GLsizei height = getHeight(0);
2454 GLsizei depth = getDepth(0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002455
2456 if (width <= 0 || height <= 0 || depth <= 0)
2457 {
2458 return false;
2459 }
2460
Jamie Madill07edd442013-07-19 16:36:58 -04002461 if (level == 0)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002462 {
Jamie Madill07edd442013-07-19 16:36:58 -04002463 return true;
2464 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002465
Jamie Madill07edd442013-07-19 16:36:58 -04002466 if (getInternalFormat(level) != getInternalFormat(0))
2467 {
2468 return false;
2469 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002470
Jamie Madill07edd442013-07-19 16:36:58 -04002471 if (getWidth(level) != std::max(1, width >> level))
2472 {
2473 return false;
2474 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002475
Jamie Madill07edd442013-07-19 16:36:58 -04002476 if (getHeight(level) != std::max(1, height >> level))
2477 {
2478 return false;
2479 }
2480
2481 if (getDepth(level) != depth)
2482 {
2483 return false;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002484 }
2485
2486 return true;
2487}
2488
Geoff Lang8040f572013-07-25 16:49:54 -04002489Renderbuffer *Texture2DArray::getRenderbuffer(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002490{
Geoff Lang8040f572013-07-25 16:49:54 -04002491 Renderbuffer *renderBuffer = mRenderbufferProxies.get(level, layer);
2492 if (!renderBuffer)
2493 {
Geoff Langd5d8e392013-07-25 16:53:03 -04002494 renderBuffer = new Renderbuffer(mRenderer, id(), new RenderbufferTexture2DArrayLayer(this, level, layer));
2495 mRenderbufferProxies.add(level, 0, renderBuffer);
Geoff Lang8040f572013-07-25 16:49:54 -04002496 }
2497
2498 return renderBuffer;
2499}
2500
2501unsigned int Texture2DArray::getRenderTargetSerial( GLint level, GLint layer )
2502{
2503 if (!mTexStorage || !mTexStorage->isRenderTarget())
2504 {
2505 convertToRenderTarget();
2506 }
2507
2508 return mTexStorage ? mTexStorage->getRenderTargetSerial(level, layer) : 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002509}
2510
2511int Texture2DArray::levelCount()
2512{
2513 return mTexStorage ? mTexStorage->levelCount() : 0;
2514}
2515
2516void Texture2DArray::createTexture()
2517{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002518 GLsizei width = getWidth(0);
2519 GLsizei height = getHeight(0);
2520 GLsizei depth = getDepth(0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002521
2522 if (width <= 0 || height <= 0 || depth <= 0)
2523 {
2524 return; // do not attempt to create native textures for nonexistant data
2525 }
2526
2527 GLint levels = creationLevels(width, height);
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002528 GLenum internalformat = getInternalFormat(0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002529
2530 delete mTexStorage;
2531 mTexStorage = new rx::TextureStorageInterface2DArray(mRenderer, levels, internalformat, mUsage, width, height, depth);
2532
2533 if (mTexStorage->isManaged())
2534 {
2535 int levels = levelCount();
2536 for (int level = 0; level < levels; level++)
2537 {
2538 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2539 {
2540 mImageArray[level][layer]->setManagedSurface(mTexStorage, layer, level);
2541 }
2542 }
2543 }
2544
2545 mDirtyImages = true;
2546}
2547
2548void Texture2DArray::updateTexture()
2549{
Jamie Madilleb3665c2013-07-19 16:36:57 -04002550 int levels = (isMipmapComplete() ? levelCount() : 1);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002551 for (int level = 0; level < levels; level++)
2552 {
Jamie Madill07edd442013-07-19 16:36:58 -04002553 updateTextureLevel(level);
2554 }
2555}
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002556
Jamie Madill07edd442013-07-19 16:36:58 -04002557void Texture2DArray::updateTextureLevel(int level)
2558{
2559 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2560 {
2561 rx::Image *image = mImageArray[level][layer];
2562
2563 if (image->isDirty())
2564 {
2565 commitRect(level, 0, 0, layer, image->getWidth(), image->getHeight());
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002566 }
2567 }
2568}
2569
2570void Texture2DArray::convertToRenderTarget()
2571{
2572 rx::TextureStorageInterface2DArray *newTexStorage = NULL;
2573
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002574 GLsizei width = getWidth(0);
2575 GLsizei height = getHeight(0);
2576 GLsizei depth = getDepth(0);
2577
2578 if (width != 0 && height != 0 && depth != 0)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002579 {
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002580 GLint levels = mTexStorage != NULL ? mTexStorage->levelCount() : creationLevels(width, height);
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002581 GLenum internalformat = getInternalFormat(0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002582
2583 newTexStorage = new rx::TextureStorageInterface2DArray(mRenderer, levels, internalformat, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, width, height, depth);
2584
2585 if (mTexStorage != NULL)
2586 {
2587 if (!mRenderer->copyToRenderTarget(newTexStorage, mTexStorage))
2588 {
2589 delete newTexStorage;
2590 return gl::error(GL_OUT_OF_MEMORY);
2591 }
2592 }
2593 }
2594
2595 delete mTexStorage;
2596 mTexStorage = newTexStorage;
2597
2598 mDirtyImages = true;
2599}
2600
Geoff Lang8040f572013-07-25 16:49:54 -04002601rx::RenderTarget *Texture2DArray::getRenderTarget(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002602{
Geoff Lang8040f572013-07-25 16:49:54 -04002603 // ensure the underlying texture is created
2604 if (getStorage(true) == NULL)
2605 {
2606 return NULL;
2607 }
2608
2609 updateTexture();
2610
2611 // ensure this is NOT a depth texture
2612 if (isDepth(level))
2613 {
2614 return NULL;
2615 }
2616
2617 return mTexStorage->getRenderTarget(level, layer);
2618}
2619
2620rx::RenderTarget *Texture2DArray::getDepthStencil(GLint level, GLint layer)
2621{
2622 // ensure the underlying texture is created
2623 if (getStorage(true) == NULL)
2624 {
2625 return NULL;
2626 }
2627
2628 updateTexture();
2629
2630 // ensure this is a depth texture
2631 if (!isDepth(level))
2632 {
2633 return NULL;
2634 }
2635
2636 return mTexStorage->getRenderTarget(level, layer);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002637}
2638
2639rx::TextureStorageInterface *Texture2DArray::getStorage(bool renderTarget)
2640{
2641 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
2642 {
2643 if (renderTarget)
2644 {
2645 convertToRenderTarget();
2646 }
2647 else
2648 {
2649 createTexture();
2650 }
2651 }
2652
2653 return mTexStorage;
2654}
2655
2656void Texture2DArray::redefineImage(GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth)
2657{
2658 // If there currently is a corresponding storage texture image, it has these parameters
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002659 const int storageWidth = std::max(1, getWidth(0) >> level);
2660 const int storageHeight = std::max(1, getHeight(0) >> level);
2661 const int storageDepth = getDepth(0);
2662 const int storageFormat = getInternalFormat(0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002663
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002664 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002665 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002666 delete mImageArray[level][layer];
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002667 }
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002668 delete[] mImageArray[level];
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002669
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002670 mImageArray[level] = new rx::Image*[depth]();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002671 mLayerCounts[level] = depth;
2672
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002673 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2674 {
2675 mImageArray[level][layer] = mRenderer->createImage();
2676 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, width, height, 1, false);
2677 }
2678
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002679 if (mTexStorage)
2680 {
2681 const int storageLevels = mTexStorage->levelCount();
2682
2683 if ((level >= storageLevels && storageLevels != 0) ||
2684 width != storageWidth ||
2685 height != storageHeight ||
2686 depth != storageDepth ||
2687 internalformat != storageFormat) // Discard mismatched storage
2688 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002689 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002690 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002691 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002692 {
2693 mImageArray[level][layer]->markDirty();
2694 }
2695 }
2696
2697 delete mTexStorage;
2698 mTexStorage = NULL;
2699 mDirtyImages = true;
2700 }
2701 }
2702}
2703
2704void Texture2DArray::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint layerTarget, GLsizei width, GLsizei height)
2705{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002706 if (level < levelCount() && layerTarget < getDepth(level))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002707 {
2708 rx::Image *image = mImageArray[level][layerTarget];
2709 if (image->updateSurface(mTexStorage, level, xoffset, yoffset, layerTarget, width, height))
2710 {
2711 image->markClean();
2712 }
2713 }
2714}
2715
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00002716}