blob: 127fdbcb757cf64b0883fdd20b7e602b9fe79724 [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"
15#include "libGLESv2/mathutil.h"
16#include "libGLESv2/utilities.h"
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +000017#include "libGLESv2/renderer/Blit.h"
shannon.woods@transgaming.com486d9e92013-02-28 23:15:41 +000018#include "libGLESv2/Renderbuffer.h"
19#include "libGLESv2/renderer/Image.h"
20#include "libGLESv2/renderer/Renderer.h"
21#include "libGLESv2/renderer/TextureStorage.h"
22#include "libEGL/Surface.h"
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000023
24namespace gl
25{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000026
daniel@transgaming.com370482e2012-11-28 19:32:13 +000027Texture::Texture(rx::Renderer *renderer, GLuint id) : RefCountObject(id)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000028{
daniel@transgaming.com370482e2012-11-28 19:32:13 +000029 mRenderer = renderer;
30
daniel@transgaming.comebf139f2012-10-31 18:07:32 +000031 mSamplerState.minFilter = GL_NEAREST_MIPMAP_LINEAR;
32 mSamplerState.magFilter = GL_LINEAR;
33 mSamplerState.wrapS = GL_REPEAT;
34 mSamplerState.wrapT = GL_REPEAT;
shannon.woods%transgaming.com@gtempaccount.com0b3a8df2013-04-13 03:44:51 +000035 mSamplerState.wrapR = GL_REPEAT;
daniel@transgaming.comebf139f2012-10-31 18:07:32 +000036 mSamplerState.maxAnisotropy = 1.0f;
37 mSamplerState.lodOffset = 0;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000038 mUsage = GL_NONE;
39
40 mDirtyImages = true;
41
42 mImmutable = false;
43}
44
45Texture::~Texture()
46{
47}
48
49// Returns true on successful filter state update (valid enum parameter)
50bool Texture::setMinFilter(GLenum filter)
51{
52 switch (filter)
53 {
54 case GL_NEAREST:
55 case GL_LINEAR:
56 case GL_NEAREST_MIPMAP_NEAREST:
57 case GL_LINEAR_MIPMAP_NEAREST:
58 case GL_NEAREST_MIPMAP_LINEAR:
59 case GL_LINEAR_MIPMAP_LINEAR:
daniel@transgaming.com3c17ba62013-01-11 04:11:41 +000060 mSamplerState.minFilter = filter;
61 return true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000062 default:
63 return false;
64 }
65}
66
67// Returns true on successful filter state update (valid enum parameter)
68bool Texture::setMagFilter(GLenum filter)
69{
70 switch (filter)
71 {
72 case GL_NEAREST:
73 case GL_LINEAR:
daniel@transgaming.com3c17ba62013-01-11 04:11:41 +000074 mSamplerState.magFilter = filter;
75 return true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000076 default:
77 return false;
78 }
79}
80
81// Returns true on successful wrap state update (valid enum parameter)
82bool Texture::setWrapS(GLenum wrap)
83{
84 switch (wrap)
85 {
86 case GL_REPEAT:
87 case GL_CLAMP_TO_EDGE:
88 case GL_MIRRORED_REPEAT:
daniel@transgaming.com3c17ba62013-01-11 04:11:41 +000089 mSamplerState.wrapS = wrap;
90 return true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000091 default:
92 return false;
93 }
94}
95
96// Returns true on successful wrap state update (valid enum parameter)
97bool Texture::setWrapT(GLenum wrap)
98{
99 switch (wrap)
100 {
101 case GL_REPEAT:
102 case GL_CLAMP_TO_EDGE:
103 case GL_MIRRORED_REPEAT:
daniel@transgaming.com3c17ba62013-01-11 04:11:41 +0000104 mSamplerState.wrapT = wrap;
105 return true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000106 default:
107 return false;
108 }
109}
110
shannon.woods%transgaming.com@gtempaccount.com0b3a8df2013-04-13 03:44:51 +0000111// Returns true on successful wrap state update (valid enum parameter)
112bool Texture::setWrapR(GLenum wrap)
113{
114 switch (wrap)
115 {
116 case GL_REPEAT:
117 case GL_CLAMP_TO_EDGE:
118 case GL_MIRRORED_REPEAT:
119 mSamplerState.wrapR = wrap;
120 return true;
121 default:
122 return false;
123 }
124}
125
daniel@transgaming.com07ab8412012-07-12 15:17:09 +0000126// Returns true on successful max anisotropy update (valid anisotropy value)
127bool Texture::setMaxAnisotropy(float textureMaxAnisotropy, float contextMaxAnisotropy)
128{
129 textureMaxAnisotropy = std::min(textureMaxAnisotropy, contextMaxAnisotropy);
130 if (textureMaxAnisotropy < 1.0f)
131 {
132 return false;
133 }
daniel@transgaming.com3c17ba62013-01-11 04:11:41 +0000134
135 mSamplerState.maxAnisotropy = textureMaxAnisotropy;
136
daniel@transgaming.com07ab8412012-07-12 15:17:09 +0000137 return true;
138}
139
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000140// Returns true on successful usage state update (valid enum parameter)
141bool Texture::setUsage(GLenum usage)
142{
143 switch (usage)
144 {
145 case GL_NONE:
146 case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
147 mUsage = usage;
148 return true;
149 default:
150 return false;
151 }
152}
153
154GLenum Texture::getMinFilter() const
155{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000156 return mSamplerState.minFilter;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000157}
158
159GLenum Texture::getMagFilter() const
160{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000161 return mSamplerState.magFilter;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000162}
163
164GLenum Texture::getWrapS() const
165{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000166 return mSamplerState.wrapS;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000167}
168
169GLenum Texture::getWrapT() const
170{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000171 return mSamplerState.wrapT;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000172}
173
shannon.woods%transgaming.com@gtempaccount.com0b3a8df2013-04-13 03:44:51 +0000174GLenum Texture::getWrapR() const
175{
176 return mSamplerState.wrapR;
177}
178
daniel@transgaming.com07ab8412012-07-12 15:17:09 +0000179float Texture::getMaxAnisotropy() const
180{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000181 return mSamplerState.maxAnisotropy;
182}
183
184int Texture::getLodOffset()
185{
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000186 rx::TextureStorageInterface *texture = getStorage(false);
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000187 return texture ? texture->getLodOffset() : 0;
188}
189
190void Texture::getSamplerState(SamplerState *sampler)
191{
192 *sampler = mSamplerState;
193 sampler->lodOffset = getLodOffset();
daniel@transgaming.com07ab8412012-07-12 15:17:09 +0000194}
195
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000196GLenum Texture::getUsage() const
197{
198 return mUsage;
199}
200
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +0000201bool Texture::isMipmapFiltered() const
202{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000203 switch (mSamplerState.minFilter)
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +0000204 {
205 case GL_NEAREST:
206 case GL_LINEAR:
207 return false;
208 case GL_NEAREST_MIPMAP_NEAREST:
209 case GL_LINEAR_MIPMAP_NEAREST:
210 case GL_NEAREST_MIPMAP_LINEAR:
211 case GL_LINEAR_MIPMAP_LINEAR:
212 return true;
213 default: UNREACHABLE();
214 return false;
215 }
216}
217
daniel@transgaming.com31b13e12012-11-28 19:34:30 +0000218void Texture::setImage(GLint unpackAlignment, const void *pixels, rx::Image *image)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000219{
220 if (pixels != NULL)
221 {
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000222 image->loadData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), unpackAlignment, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000223 mDirtyImages = true;
224 }
225}
226
daniel@transgaming.com31b13e12012-11-28 19:34:30 +0000227void Texture::setCompressedImage(GLsizei imageSize, const void *pixels, rx::Image *image)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000228{
229 if (pixels != NULL)
230 {
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000231 image->loadCompressedData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000232 mDirtyImages = true;
233 }
234}
235
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000236bool Texture::subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
237 GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, rx::Image *image)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000238{
239 if (pixels != NULL)
240 {
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000241 image->loadData(xoffset, yoffset, zoffset, width, height, depth, unpackAlignment, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000242 mDirtyImages = true;
243 }
244
245 return true;
246}
247
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000248bool Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
249 GLenum format, GLsizei imageSize, const void *pixels, rx::Image *image)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000250{
251 if (pixels != NULL)
252 {
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000253 image->loadCompressedData(xoffset, yoffset, zoffset, width, height, depth, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000254 mDirtyImages = true;
255 }
256
257 return true;
258}
259
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000260rx::TextureStorageInterface *Texture::getNativeTexture()
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000261{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000262 // ensure the underlying texture is created
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000263
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000264 rx::TextureStorageInterface *storage = getStorage(false);
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000265 if (storage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000266 {
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000267 updateTexture();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000268 }
269
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000270 return storage;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000271}
272
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000273bool Texture::hasDirtyImages() const
274{
275 return mDirtyImages;
276}
277
278void Texture::resetDirty()
279{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000280 mDirtyImages = false;
281}
282
283unsigned int Texture::getTextureSerial()
284{
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000285 rx::TextureStorageInterface *texture = getStorage(false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000286 return texture ? texture->getTextureSerial() : 0;
287}
288
289unsigned int Texture::getRenderTargetSerial(GLenum target)
290{
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000291 rx::TextureStorageInterface *texture = getStorage(true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000292 return texture ? texture->getRenderTargetSerial(target) : 0;
293}
294
295bool Texture::isImmutable() const
296{
297 return mImmutable;
298}
299
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +0000300GLint Texture::creationLevels(GLsizei width, GLsizei height, GLsizei depth) const
301{
302 // NPOT checks are not required in ES 3.0, NPOT texture support is assumed.
303 return 0; // Maximum number of levels
304}
305
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000306GLint Texture::creationLevels(GLsizei width, GLsizei height) const
307{
daniel@transgaming.comea32d482012-11-28 19:33:18 +0000308 if ((isPow2(width) && isPow2(height)) || mRenderer->getNonPower2TextureSupport())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000309 {
310 return 0; // Maximum number of levels
311 }
312 else
313 {
314 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
315 return 1;
316 }
317}
318
319GLint Texture::creationLevels(GLsizei size) const
320{
321 return creationLevels(size, size);
322}
323
daniel@transgaming.com370482e2012-11-28 19:32:13 +0000324Texture2D::Texture2D(rx::Renderer *renderer, GLuint id) : Texture(renderer, id)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000325{
326 mTexStorage = NULL;
327 mSurface = NULL;
328 mColorbufferProxy = NULL;
329 mProxyRefs = 0;
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000330
331 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
332 {
daniel@transgaming.com244e1832012-12-20 20:52:35 +0000333 mImageArray[i] = renderer->createImage();
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000334 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000335}
336
337Texture2D::~Texture2D()
338{
339 mColorbufferProxy = NULL;
340
341 delete mTexStorage;
342 mTexStorage = NULL;
343
344 if (mSurface)
345 {
346 mSurface->setBoundTexture(NULL);
347 mSurface = NULL;
348 }
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000349
350 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
351 {
352 delete mImageArray[i];
353 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000354}
355
356// We need to maintain a count of references to renderbuffers acting as
357// proxies for this texture, so that we do not attempt to use a pointer
358// to a renderbuffer proxy which has been deleted.
359void Texture2D::addProxyRef(const Renderbuffer *proxy)
360{
361 mProxyRefs++;
362}
363
364void Texture2D::releaseProxy(const Renderbuffer *proxy)
365{
366 if (mProxyRefs > 0)
367 mProxyRefs--;
368
369 if (mProxyRefs == 0)
370 mColorbufferProxy = NULL;
371}
372
373GLenum Texture2D::getTarget() const
374{
375 return GL_TEXTURE_2D;
376}
377
378GLsizei Texture2D::getWidth(GLint level) const
379{
380 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000381 return mImageArray[level]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000382 else
383 return 0;
384}
385
386GLsizei Texture2D::getHeight(GLint level) const
387{
388 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000389 return mImageArray[level]->getHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000390 else
391 return 0;
392}
393
394GLenum Texture2D::getInternalFormat(GLint level) const
395{
396 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000397 return mImageArray[level]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000398 else
399 return GL_NONE;
400}
401
daniel@transgaming.com20d36662012-10-31 19:51:43 +0000402GLenum Texture2D::getActualFormat(GLint level) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000403{
404 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000405 return mImageArray[level]->getActualFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000406 else
407 return D3DFMT_UNKNOWN;
408}
409
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000410void Texture2D::redefineImage(GLint level, GLint internalformat, GLsizei width, GLsizei height)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000411{
412 releaseTexImage();
shannon.woods@transgaming.com8a406682013-02-28 23:15:26 +0000413
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000414 // If there currently is a corresponding storage texture image, it has these parameters
415 const int storageWidth = std::max(1, mImageArray[0]->getWidth() >> level);
416 const int storageHeight = std::max(1, mImageArray[0]->getHeight() >> level);
417 const int storageFormat = mImageArray[0]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000418
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000419 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, width, height, 1, false);
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000420
421 if (mTexStorage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000422 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000423 const int storageLevels = mTexStorage->levelCount();
424
425 if ((level >= storageLevels && storageLevels != 0) ||
426 width != storageWidth ||
427 height != storageHeight ||
428 internalformat != storageFormat) // Discard mismatched storage
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000429 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000430 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
431 {
432 mImageArray[i]->markDirty();
433 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000434
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000435 delete mTexStorage;
436 mTexStorage = NULL;
437 mDirtyImages = true;
438 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000439 }
440}
441
442void Texture2D::setImage(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
443{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000444 GLint internalformat = ConvertSizedInternalFormat(format, type);
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000445 redefineImage(level, internalformat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000446
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000447 Texture::setImage(unpackAlignment, pixels, mImageArray[level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000448}
449
450void Texture2D::bindTexImage(egl::Surface *surface)
451{
452 releaseTexImage();
453
daniel@transgaming.com106e1f72012-10-31 18:38:36 +0000454 GLint internalformat = surface->getFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000455
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000456 mImageArray[0]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, surface->getWidth(), surface->getHeight(), 1, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000457
458 delete mTexStorage;
daniel@transgaming.comd8353dd2012-12-20 21:11:14 +0000459 mTexStorage = new rx::TextureStorageInterface2D(mRenderer, surface->getSwapChain());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000460
461 mDirtyImages = true;
462 mSurface = surface;
463 mSurface->setBoundTexture(this);
464}
465
466void Texture2D::releaseTexImage()
467{
468 if (mSurface)
469 {
470 mSurface->setBoundTexture(NULL);
471 mSurface = NULL;
472
473 if (mTexStorage)
474 {
475 delete mTexStorage;
476 mTexStorage = NULL;
477 }
478
479 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
480 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000481 mImageArray[i]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000482 }
483 }
484}
485
486void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
487{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000488 // 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 +0000489 redefineImage(level, format, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000490
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000491 Texture::setCompressedImage(imageSize, pixels, mImageArray[level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000492}
493
494void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
495{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000496 if (level < levelCount())
497 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000498 rx::Image *image = mImageArray[level];
daniel@transgaming.com0f195ad2012-10-31 19:51:59 +0000499 if (image->updateSurface(mTexStorage, level, xoffset, yoffset, width, height))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000500 {
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000501 image->markClean();
502 }
503 }
504}
505
506void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
507{
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000508 if (Texture::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpackAlignment, pixels, mImageArray[level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000509 {
510 commitRect(level, xoffset, yoffset, width, height);
511 }
512}
513
514void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
515{
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000516 if (Texture::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000517 {
518 commitRect(level, xoffset, yoffset, width, height);
519 }
520}
521
522void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
523{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000524 GLint internalformat = ConvertSizedInternalFormat(format, GL_UNSIGNED_BYTE);
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000525 redefineImage(level, internalformat, width, height);
shannon.woods@transgaming.com8a406682013-02-28 23:15:26 +0000526
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000527 if (!mImageArray[level]->isRenderableFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000528 {
shannon.woods%transgaming.com@gtempaccount.come5dcce72013-04-13 03:44:33 +0000529 mImageArray[level]->copy(0, 0, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000530 mDirtyImages = true;
531 }
532 else
533 {
534 if (!mTexStorage || !mTexStorage->isRenderTarget())
535 {
536 convertToRenderTarget();
537 }
538
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000539 mImageArray[level]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000540
541 if (width != 0 && height != 0 && level < levelCount())
542 {
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +0000543 gl::Rectangle sourceRect;
544 sourceRect.x = x;
545 sourceRect.width = width;
546 sourceRect.y = y;
547 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000548
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +0000549 mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000550 }
551 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000552}
553
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +0000554void 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 +0000555{
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +0000556 if (xoffset + width > mImageArray[level]->getWidth() || yoffset + height > mImageArray[level]->getHeight() || zoffset != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000557 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +0000558 return gl::error(GL_INVALID_VALUE);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000559 }
560
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000561 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !isSamplerComplete()))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000562 {
shannon.woods%transgaming.com@gtempaccount.come5dcce72013-04-13 03:44:33 +0000563 mImageArray[level]->copy(xoffset, yoffset, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000564 mDirtyImages = true;
565 }
566 else
567 {
568 if (!mTexStorage || !mTexStorage->isRenderTarget())
569 {
570 convertToRenderTarget();
571 }
572
573 updateTexture();
574
575 if (level < levelCount())
576 {
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +0000577 gl::Rectangle sourceRect;
578 sourceRect.x = x;
579 sourceRect.width = width;
580 sourceRect.y = y;
581 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000582
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +0000583 mRenderer->copyImage(source, sourceRect,
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000584 gl::ExtractFormat(mImageArray[0]->getInternalFormat()),
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +0000585 xoffset, yoffset, mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000586 }
587 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000588}
589
590void Texture2D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height)
591{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000592 delete mTexStorage;
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000593 mTexStorage = new rx::TextureStorageInterface2D(mRenderer, levels, internalformat, mUsage, false, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000594 mImmutable = true;
595
596 for (int level = 0; level < levels; level++)
597 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000598 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, width, height, 1, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000599 width = std::max(1, width >> 1);
600 height = std::max(1, height >> 1);
601 }
602
603 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
604 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000605 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000606 }
607
608 if (mTexStorage->isManaged())
609 {
610 int levels = levelCount();
611
612 for (int level = 0; level < levels; level++)
613 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000614 mImageArray[level]->setManagedSurface(mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000615 }
616 }
617}
618
619// Tests for 2D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85.
620bool Texture2D::isSamplerComplete() const
621{
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000622 GLsizei width = mImageArray[0]->getWidth();
623 GLsizei height = mImageArray[0]->getHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000624
625 if (width <= 0 || height <= 0)
626 {
627 return false;
628 }
629
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +0000630 bool mipmapping = isMipmapFiltered();
daniel@transgaming.comea32d482012-11-28 19:33:18 +0000631 bool filtering, renderable;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000632
daniel@transgaming.comea32d482012-11-28 19:33:18 +0000633 if ((IsFloat32Format(getInternalFormat(0)) && !mRenderer->getFloat32TextureSupport(&filtering, &renderable)) ||
634 (IsFloat16Format(getInternalFormat(0)) && !mRenderer->getFloat16TextureSupport(&filtering, &renderable)))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000635 {
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000636 if (mSamplerState.magFilter != GL_NEAREST ||
637 (mSamplerState.minFilter != GL_NEAREST && mSamplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000638 {
639 return false;
640 }
641 }
642
daniel@transgaming.comea32d482012-11-28 19:33:18 +0000643 bool npotSupport = mRenderer->getNonPower2TextureSupport();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000644
645 if (!npotSupport)
646 {
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000647 if ((mSamplerState.wrapS != GL_CLAMP_TO_EDGE && !isPow2(width)) ||
648 (mSamplerState.wrapT != GL_CLAMP_TO_EDGE && !isPow2(height)))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000649 {
650 return false;
651 }
652 }
653
654 if (mipmapping)
655 {
656 if (!npotSupport)
657 {
658 if (!isPow2(width) || !isPow2(height))
659 {
660 return false;
661 }
662 }
663
664 if (!isMipmapComplete())
665 {
666 return false;
667 }
668 }
669
670 return true;
671}
672
673// Tests for 2D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
674bool Texture2D::isMipmapComplete() const
675{
676 if (isImmutable())
677 {
678 return true;
679 }
680
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000681 GLsizei width = mImageArray[0]->getWidth();
682 GLsizei height = mImageArray[0]->getHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000683
684 if (width <= 0 || height <= 0)
685 {
686 return false;
687 }
688
689 int q = log2(std::max(width, height));
690
691 for (int level = 1; level <= q; level++)
692 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000693 if (mImageArray[level]->getInternalFormat() != mImageArray[0]->getInternalFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000694 {
695 return false;
696 }
697
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000698 if (mImageArray[level]->getWidth() != std::max(1, width >> level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000699 {
700 return false;
701 }
702
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000703 if (mImageArray[level]->getHeight() != std::max(1, height >> level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000704 {
705 return false;
706 }
707 }
708
709 return true;
710}
711
712bool Texture2D::isCompressed(GLint level) const
713{
714 return IsCompressed(getInternalFormat(level));
715}
716
717bool Texture2D::isDepth(GLint level) const
718{
719 return IsDepthTexture(getInternalFormat(level));
720}
721
daniel@transgaming.comf032cb82012-10-31 19:51:52 +0000722// Constructs a native texture resource from the texture images
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000723void Texture2D::createTexture()
724{
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000725 GLsizei width = mImageArray[0]->getWidth();
726 GLsizei height = mImageArray[0]->getHeight();
daniel@transgaming.come6a09842012-09-17 21:28:55 +0000727
728 if (!(width > 0 && height > 0))
daniel@transgaming.comf032cb82012-10-31 19:51:52 +0000729 return; // do not attempt to create native textures for nonexistant data
daniel@transgaming.come6a09842012-09-17 21:28:55 +0000730
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000731 GLint levels = creationLevels(width, height);
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000732 GLenum internalformat = mImageArray[0]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000733
734 delete mTexStorage;
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000735 mTexStorage = new rx::TextureStorageInterface2D(mRenderer, levels, internalformat, mUsage, false, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000736
737 if (mTexStorage->isManaged())
738 {
739 int levels = levelCount();
740
741 for (int level = 0; level < levels; level++)
742 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000743 mImageArray[level]->setManagedSurface(mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000744 }
745 }
746
747 mDirtyImages = true;
748}
749
750void Texture2D::updateTexture()
751{
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +0000752 bool mipmapping = (isMipmapFiltered() && isMipmapComplete());
753
754 int levels = (mipmapping ? levelCount() : 1);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000755
756 for (int level = 0; level < levels; level++)
757 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000758 rx::Image *image = mImageArray[level];
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000759
760 if (image->isDirty())
761 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000762 commitRect(level, 0, 0, mImageArray[level]->getWidth(), mImageArray[level]->getHeight());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000763 }
764 }
765}
766
767void Texture2D::convertToRenderTarget()
768{
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000769 rx::TextureStorageInterface2D *newTexStorage = NULL;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000770
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000771 if (mImageArray[0]->getWidth() != 0 && mImageArray[0]->getHeight() != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000772 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000773 GLsizei width = mImageArray[0]->getWidth();
774 GLsizei height = mImageArray[0]->getHeight();
shannon.woods@transgaming.com6bb48862013-02-28 23:09:34 +0000775 GLint levels = mTexStorage != NULL ? mTexStorage->levelCount() : creationLevels(width, height);
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000776 GLenum internalformat = mImageArray[0]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000777
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000778 newTexStorage = new rx::TextureStorageInterface2D(mRenderer, levels, internalformat, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, true, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000779
780 if (mTexStorage != NULL)
781 {
daniel@transgaming.com1d80eee2012-11-28 19:33:31 +0000782 if (!mRenderer->copyToRenderTarget(newTexStorage, mTexStorage))
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +0000783 {
784 delete newTexStorage;
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +0000785 return gl::error(GL_OUT_OF_MEMORY);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000786 }
787 }
788 }
789
790 delete mTexStorage;
791 mTexStorage = newTexStorage;
792
793 mDirtyImages = true;
794}
795
796void Texture2D::generateMipmaps()
797{
daniel@transgaming.comea32d482012-11-28 19:33:18 +0000798 if (!mRenderer->getNonPower2TextureSupport())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000799 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000800 if (!isPow2(mImageArray[0]->getWidth()) || !isPow2(mImageArray[0]->getHeight()))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000801 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +0000802 return gl::error(GL_INVALID_OPERATION);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000803 }
804 }
805
806 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000807 unsigned int q = log2(std::max(mImageArray[0]->getWidth(), mImageArray[0]->getHeight()));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000808 for (unsigned int i = 1; i <= q; i++)
809 {
shannon.woods@transgaming.com8a406682013-02-28 23:15:26 +0000810 redefineImage(i, mImageArray[0]->getInternalFormat(),
811 std::max(mImageArray[0]->getWidth() >> i, 1),
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000812 std::max(mImageArray[0]->getHeight() >> i, 1));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000813 }
814
815 if (mTexStorage && mTexStorage->isRenderTarget())
816 {
817 for (unsigned int i = 1; i <= q; i++)
818 {
daniel@transgaming.com0ad830b2012-10-31 19:52:12 +0000819 mTexStorage->generateMipmap(i);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000820
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000821 mImageArray[i]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000822 }
823 }
824 else
825 {
826 for (unsigned int i = 1; i <= q; i++)
827 {
daniel@transgaming.com4ba24062012-12-20 20:54:24 +0000828 mRenderer->generateMipmap(mImageArray[i], mImageArray[i - 1]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000829 }
830 }
831}
832
833Renderbuffer *Texture2D::getRenderbuffer(GLenum target)
834{
835 if (target != GL_TEXTURE_2D)
836 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +0000837 return gl::error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000838 }
839
840 if (mColorbufferProxy == NULL)
841 {
daniel@transgaming.com70062c92012-11-28 19:32:30 +0000842 mColorbufferProxy = new Renderbuffer(mRenderer, id(), new RenderbufferTexture2D(this, target));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000843 }
844
845 return mColorbufferProxy;
846}
847
daniel@transgaming.comd186dc72012-11-28 19:40:16 +0000848rx::RenderTarget *Texture2D::getRenderTarget(GLenum target)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000849{
850 ASSERT(target == GL_TEXTURE_2D);
851
852 // ensure the underlying texture is created
853 if (getStorage(true) == NULL)
854 {
855 return NULL;
856 }
857
858 updateTexture();
859
860 // ensure this is NOT a depth texture
861 if (isDepth(0))
862 {
863 return NULL;
864 }
daniel@transgaming.com34da3972012-12-20 21:10:29 +0000865
daniel@transgaming.comd186dc72012-11-28 19:40:16 +0000866 return mTexStorage->getRenderTarget();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000867}
868
daniel@transgaming.comd186dc72012-11-28 19:40:16 +0000869rx::RenderTarget *Texture2D::getDepthStencil(GLenum target)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000870{
871 ASSERT(target == GL_TEXTURE_2D);
872
873 // ensure the underlying texture is created
874 if (getStorage(true) == NULL)
875 {
876 return NULL;
877 }
878
879 updateTexture();
880
881 // ensure this is actually a depth texture
882 if (!isDepth(0))
883 {
884 return NULL;
885 }
daniel@transgaming.comd186dc72012-11-28 19:40:16 +0000886 return mTexStorage->getRenderTarget();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000887}
888
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +0000889int Texture2D::levelCount()
890{
shannon.woods@transgaming.com5016f8e2013-02-28 23:20:57 +0000891 return mTexStorage ? mTexStorage->levelCount() : 0;
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +0000892}
893
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000894rx::TextureStorageInterface *Texture2D::getStorage(bool renderTarget)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000895{
896 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
897 {
898 if (renderTarget)
899 {
900 convertToRenderTarget();
901 }
902 else
903 {
904 createTexture();
905 }
906 }
907
908 return mTexStorage;
909}
910
daniel@transgaming.com370482e2012-11-28 19:32:13 +0000911TextureCubeMap::TextureCubeMap(rx::Renderer *renderer, GLuint id) : Texture(renderer, id)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000912{
913 mTexStorage = NULL;
914 for (int i = 0; i < 6; i++)
915 {
916 mFaceProxies[i] = NULL;
917 mFaceProxyRefs[i] = 0;
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000918
919 for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
920 {
daniel@transgaming.com244e1832012-12-20 20:52:35 +0000921 mImageArray[i][j] = renderer->createImage();
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000922 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000923 }
924}
925
926TextureCubeMap::~TextureCubeMap()
927{
928 for (int i = 0; i < 6; i++)
929 {
930 mFaceProxies[i] = NULL;
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000931
932 for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
933 {
934 delete mImageArray[i][j];
935 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000936 }
937
938 delete mTexStorage;
939 mTexStorage = NULL;
940}
941
942// We need to maintain a count of references to renderbuffers acting as
943// proxies for this texture, so that the texture is not deleted while
944// proxy references still exist. If the reference count drops to zero,
945// we set our proxy pointer NULL, so that a new attempt at referencing
946// will cause recreation.
947void TextureCubeMap::addProxyRef(const Renderbuffer *proxy)
948{
949 for (int i = 0; i < 6; i++)
950 {
951 if (mFaceProxies[i] == proxy)
952 mFaceProxyRefs[i]++;
953 }
954}
955
956void TextureCubeMap::releaseProxy(const Renderbuffer *proxy)
957{
958 for (int i = 0; i < 6; i++)
959 {
960 if (mFaceProxies[i] == proxy)
961 {
962 if (mFaceProxyRefs[i] > 0)
963 mFaceProxyRefs[i]--;
964
965 if (mFaceProxyRefs[i] == 0)
966 mFaceProxies[i] = NULL;
967 }
968 }
969}
970
971GLenum TextureCubeMap::getTarget() const
972{
973 return GL_TEXTURE_CUBE_MAP;
974}
975
976GLsizei TextureCubeMap::getWidth(GLenum target, GLint level) const
977{
978 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000979 return mImageArray[faceIndex(target)][level]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000980 else
981 return 0;
982}
983
984GLsizei TextureCubeMap::getHeight(GLenum target, GLint level) const
985{
986 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000987 return mImageArray[faceIndex(target)][level]->getHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000988 else
989 return 0;
990}
991
992GLenum TextureCubeMap::getInternalFormat(GLenum target, GLint level) const
993{
994 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000995 return mImageArray[faceIndex(target)][level]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000996 else
997 return GL_NONE;
998}
999
daniel@transgaming.com20d36662012-10-31 19:51:43 +00001000GLenum TextureCubeMap::getActualFormat(GLenum target, GLint level) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001001{
1002 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001003 return mImageArray[faceIndex(target)][level]->getActualFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001004 else
1005 return D3DFMT_UNKNOWN;
1006}
1007
1008void TextureCubeMap::setImagePosX(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1009{
1010 setImage(0, level, width, height, format, type, unpackAlignment, pixels);
1011}
1012
1013void TextureCubeMap::setImageNegX(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1014{
1015 setImage(1, level, width, height, format, type, unpackAlignment, pixels);
1016}
1017
1018void TextureCubeMap::setImagePosY(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1019{
1020 setImage(2, level, width, height, format, type, unpackAlignment, pixels);
1021}
1022
1023void TextureCubeMap::setImageNegY(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1024{
1025 setImage(3, level, width, height, format, type, unpackAlignment, pixels);
1026}
1027
1028void TextureCubeMap::setImagePosZ(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1029{
1030 setImage(4, level, width, height, format, type, unpackAlignment, pixels);
1031}
1032
1033void TextureCubeMap::setImageNegZ(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1034{
1035 setImage(5, level, width, height, format, type, unpackAlignment, pixels);
1036}
1037
1038void TextureCubeMap::setCompressedImage(GLenum face, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
1039{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001040 // 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 +00001041 redefineImage(faceIndex(face), level, format, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001042
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001043 Texture::setCompressedImage(imageSize, pixels, mImageArray[faceIndex(face)][level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001044}
1045
1046void TextureCubeMap::commitRect(int face, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1047{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001048 if (level < levelCount())
1049 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001050 rx::Image *image = mImageArray[face][level];
daniel@transgaming.com0f195ad2012-10-31 19:51:59 +00001051 if (image->updateSurface(mTexStorage, face, level, xoffset, yoffset, width, height))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001052 image->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001053 }
1054}
1055
1056void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1057{
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +00001058 if (Texture::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpackAlignment, pixels, mImageArray[faceIndex(target)][level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001059 {
1060 commitRect(faceIndex(target), level, xoffset, yoffset, width, height);
1061 }
1062}
1063
1064void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1065{
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +00001066 if (Texture::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[faceIndex(target)][level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001067 {
1068 commitRect(faceIndex(target), level, xoffset, yoffset, width, height);
1069 }
1070}
1071
1072// Tests for cube map sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 86.
1073bool TextureCubeMap::isSamplerComplete() const
1074{
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001075 int size = mImageArray[0][0]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001076
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +00001077 bool mipmapping = isMipmapFiltered();
daniel@transgaming.comea32d482012-11-28 19:33:18 +00001078 bool filtering, renderable;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001079
daniel@transgaming.comea32d482012-11-28 19:33:18 +00001080 if ((gl::ExtractType(getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0)) == GL_FLOAT && !mRenderer->getFloat32TextureSupport(&filtering, &renderable)) ||
1081 (gl::ExtractType(getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0) == GL_HALF_FLOAT_OES) && !mRenderer->getFloat16TextureSupport(&filtering, &renderable)))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001082 {
daniel@transgaming.comebf139f2012-10-31 18:07:32 +00001083 if (mSamplerState.magFilter != GL_NEAREST ||
1084 (mSamplerState.minFilter != GL_NEAREST && mSamplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001085 {
1086 return false;
1087 }
1088 }
1089
daniel@transgaming.comea32d482012-11-28 19:33:18 +00001090 if (!isPow2(size) && !mRenderer->getNonPower2TextureSupport())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001091 {
daniel@transgaming.comebf139f2012-10-31 18:07:32 +00001092 if (mSamplerState.wrapS != GL_CLAMP_TO_EDGE || mSamplerState.wrapT != GL_CLAMP_TO_EDGE || mipmapping)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001093 {
1094 return false;
1095 }
1096 }
1097
1098 if (!mipmapping)
1099 {
1100 if (!isCubeComplete())
1101 {
1102 return false;
1103 }
1104 }
1105 else
1106 {
1107 if (!isMipmapCubeComplete()) // Also tests for isCubeComplete()
1108 {
1109 return false;
1110 }
1111 }
1112
1113 return true;
1114}
1115
1116// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1117bool TextureCubeMap::isCubeComplete() const
1118{
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001119 if (mImageArray[0][0]->getWidth() <= 0 || mImageArray[0][0]->getHeight() != mImageArray[0][0]->getWidth())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001120 {
1121 return false;
1122 }
1123
1124 for (unsigned int face = 1; face < 6; face++)
1125 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001126 if (mImageArray[face][0]->getWidth() != mImageArray[0][0]->getWidth() ||
1127 mImageArray[face][0]->getWidth() != mImageArray[0][0]->getHeight() ||
1128 mImageArray[face][0]->getInternalFormat() != mImageArray[0][0]->getInternalFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001129 {
1130 return false;
1131 }
1132 }
1133
1134 return true;
1135}
1136
1137bool TextureCubeMap::isMipmapCubeComplete() const
1138{
1139 if (isImmutable())
1140 {
1141 return true;
1142 }
1143
1144 if (!isCubeComplete())
1145 {
1146 return false;
1147 }
1148
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001149 GLsizei size = mImageArray[0][0]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001150
1151 int q = log2(size);
1152
1153 for (int face = 0; face < 6; face++)
1154 {
1155 for (int level = 1; level <= q; level++)
1156 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001157 if (mImageArray[face][level]->getInternalFormat() != mImageArray[0][0]->getInternalFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001158 {
1159 return false;
1160 }
1161
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001162 if (mImageArray[face][level]->getWidth() != std::max(1, size >> level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001163 {
1164 return false;
1165 }
1166 }
1167 }
1168
1169 return true;
1170}
1171
1172bool TextureCubeMap::isCompressed(GLenum target, GLint level) const
1173{
1174 return IsCompressed(getInternalFormat(target, level));
1175}
1176
daniel@transgaming.comf032cb82012-10-31 19:51:52 +00001177// Constructs a native texture resource from the texture images, or returns an existing one
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001178void TextureCubeMap::createTexture()
1179{
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001180 GLsizei size = mImageArray[0][0]->getWidth();
daniel@transgaming.come6a09842012-09-17 21:28:55 +00001181
1182 if (!(size > 0))
daniel@transgaming.comf032cb82012-10-31 19:51:52 +00001183 return; // do not attempt to create native textures for nonexistant data
daniel@transgaming.come6a09842012-09-17 21:28:55 +00001184
sminns@adobe.comce1189b2012-09-18 20:06:35 +00001185 GLint levels = creationLevels(size);
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001186 GLenum internalformat = mImageArray[0][0]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001187
1188 delete mTexStorage;
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001189 mTexStorage = new rx::TextureStorageInterfaceCube(mRenderer, levels, internalformat, mUsage, false, size);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001190
1191 if (mTexStorage->isManaged())
1192 {
1193 int levels = levelCount();
1194
1195 for (int face = 0; face < 6; face++)
1196 {
1197 for (int level = 0; level < levels; level++)
1198 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001199 mImageArray[face][level]->setManagedSurface(mTexStorage, face, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001200 }
1201 }
1202 }
1203
1204 mDirtyImages = true;
1205}
1206
1207void TextureCubeMap::updateTexture()
1208{
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +00001209 bool mipmapping = isMipmapFiltered() && isMipmapCubeComplete();
1210
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001211 for (int face = 0; face < 6; face++)
1212 {
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +00001213 int levels = (mipmapping ? levelCount() : 1);
1214
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001215 for (int level = 0; level < levels; level++)
1216 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001217 rx::Image *image = mImageArray[face][level];
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001218
1219 if (image->isDirty())
1220 {
1221 commitRect(face, level, 0, 0, image->getWidth(), image->getHeight());
1222 }
1223 }
1224 }
1225}
1226
1227void TextureCubeMap::convertToRenderTarget()
1228{
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001229 rx::TextureStorageInterfaceCube *newTexStorage = NULL;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001230
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001231 if (mImageArray[0][0]->getWidth() != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001232 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001233 GLsizei size = mImageArray[0][0]->getWidth();
shannon.woods@transgaming.com6bb48862013-02-28 23:09:34 +00001234 GLint levels = mTexStorage != NULL ? mTexStorage->levelCount() : creationLevels(size);
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001235 GLenum internalformat = mImageArray[0][0]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001236
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001237 newTexStorage = new rx::TextureStorageInterfaceCube(mRenderer, levels, internalformat, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, true, size);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001238
1239 if (mTexStorage != NULL)
1240 {
daniel@transgaming.com1d80eee2012-11-28 19:33:31 +00001241 if (!mRenderer->copyToRenderTarget(newTexStorage, mTexStorage))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001242 {
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +00001243 delete newTexStorage;
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +00001244 return gl::error(GL_OUT_OF_MEMORY);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001245 }
1246 }
1247 }
1248
1249 delete mTexStorage;
1250 mTexStorage = newTexStorage;
1251
1252 mDirtyImages = true;
1253}
1254
1255void TextureCubeMap::setImage(int faceIndex, GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1256{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001257 GLint internalformat = ConvertSizedInternalFormat(format, type);
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001258 redefineImage(faceIndex, level, internalformat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001259
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001260 Texture::setImage(unpackAlignment, pixels, mImageArray[faceIndex][level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001261}
1262
1263unsigned int TextureCubeMap::faceIndex(GLenum face)
1264{
1265 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
1266 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
1267 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
1268 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
1269 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
1270
1271 return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
1272}
1273
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001274void TextureCubeMap::redefineImage(int face, GLint level, GLint internalformat, GLsizei width, GLsizei height)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001275{
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001276 // If there currently is a corresponding storage texture image, it has these parameters
1277 const int storageWidth = std::max(1, mImageArray[0][0]->getWidth() >> level);
1278 const int storageHeight = std::max(1, mImageArray[0][0]->getHeight() >> level);
1279 const int storageFormat = mImageArray[0][0]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001280
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001281 mImageArray[face][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, width, height, 1, false);
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001282
1283 if (mTexStorage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001284 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001285 const int storageLevels = mTexStorage->levelCount();
1286
1287 if ((level >= storageLevels && storageLevels != 0) ||
1288 width != storageWidth ||
1289 height != storageHeight ||
1290 internalformat != storageFormat) // Discard mismatched storage
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001291 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001292 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001293 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001294 for (int f = 0; f < 6; f++)
1295 {
1296 mImageArray[f][i]->markDirty();
1297 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001298 }
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001299
1300 delete mTexStorage;
1301 mTexStorage = NULL;
1302
1303 mDirtyImages = true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001304 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001305 }
1306}
1307
1308void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1309{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001310 unsigned int faceindex = faceIndex(target);
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001311 GLint internalformat = gl::ConvertSizedInternalFormat(format, GL_UNSIGNED_BYTE);
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001312 redefineImage(faceindex, level, internalformat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001313
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001314 if (!mImageArray[faceindex][level]->isRenderableFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001315 {
shannon.woods%transgaming.com@gtempaccount.come5dcce72013-04-13 03:44:33 +00001316 mImageArray[faceindex][level]->copy(0, 0, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001317 mDirtyImages = true;
1318 }
1319 else
1320 {
1321 if (!mTexStorage || !mTexStorage->isRenderTarget())
1322 {
1323 convertToRenderTarget();
1324 }
1325
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001326 mImageArray[faceindex][level]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001327
1328 ASSERT(width == height);
1329
1330 if (width > 0 && level < levelCount())
1331 {
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +00001332 gl::Rectangle sourceRect;
1333 sourceRect.x = x;
1334 sourceRect.width = width;
1335 sourceRect.y = y;
1336 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001337
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +00001338 mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001339 }
1340 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001341}
1342
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001343void 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 +00001344{
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001345 GLsizei size = mImageArray[faceIndex(target)][level]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001346
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001347 if (xoffset + width > size || yoffset + height > size || zoffset != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001348 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +00001349 return gl::error(GL_INVALID_VALUE);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001350 }
1351
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001352 unsigned int faceindex = faceIndex(target);
1353
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001354 if (!mImageArray[faceindex][level]->isRenderableFormat() || (!mTexStorage && !isSamplerComplete()))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001355 {
shannon.woods%transgaming.com@gtempaccount.come5dcce72013-04-13 03:44:33 +00001356 mImageArray[faceindex][level]->copy(0, 0, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001357 mDirtyImages = true;
1358 }
1359 else
1360 {
1361 if (!mTexStorage || !mTexStorage->isRenderTarget())
1362 {
1363 convertToRenderTarget();
1364 }
1365
1366 updateTexture();
1367
1368 if (level < levelCount())
1369 {
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +00001370 gl::Rectangle sourceRect;
1371 sourceRect.x = x;
1372 sourceRect.width = width;
1373 sourceRect.y = y;
1374 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001375
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001376 mRenderer->copyImage(source, sourceRect, gl::ExtractFormat(mImageArray[0][0]->getInternalFormat()),
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +00001377 xoffset, yoffset, mTexStorage, target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001378 }
1379 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001380}
1381
1382void TextureCubeMap::storage(GLsizei levels, GLenum internalformat, GLsizei size)
1383{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001384 delete mTexStorage;
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001385 mTexStorage = new rx::TextureStorageInterfaceCube(mRenderer, levels, internalformat, mUsage, false, size);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001386 mImmutable = true;
1387
1388 for (int level = 0; level < levels; level++)
1389 {
1390 for (int face = 0; face < 6; face++)
1391 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001392 mImageArray[face][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, size, size, 1, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001393 size = std::max(1, size >> 1);
1394 }
1395 }
1396
1397 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1398 {
1399 for (int face = 0; face < 6; face++)
1400 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001401 mImageArray[face][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, GL_NONE, 0, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001402 }
1403 }
1404
1405 if (mTexStorage->isManaged())
1406 {
1407 int levels = levelCount();
1408
1409 for (int face = 0; face < 6; face++)
1410 {
1411 for (int level = 0; level < levels; level++)
1412 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001413 mImageArray[face][level]->setManagedSurface(mTexStorage, face, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001414 }
1415 }
1416 }
1417}
1418
1419void TextureCubeMap::generateMipmaps()
1420{
1421 if (!isCubeComplete())
1422 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +00001423 return gl::error(GL_INVALID_OPERATION);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001424 }
1425
daniel@transgaming.comea32d482012-11-28 19:33:18 +00001426 if (!mRenderer->getNonPower2TextureSupport())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001427 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001428 if (!isPow2(mImageArray[0][0]->getWidth()))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001429 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +00001430 return gl::error(GL_INVALID_OPERATION);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001431 }
1432 }
1433
1434 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001435 unsigned int q = log2(mImageArray[0][0]->getWidth());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001436 for (unsigned int f = 0; f < 6; f++)
1437 {
1438 for (unsigned int i = 1; i <= q; i++)
1439 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001440 redefineImage(f, i, mImageArray[f][0]->getInternalFormat(),
shannon.woods@transgaming.com8a406682013-02-28 23:15:26 +00001441 std::max(mImageArray[f][0]->getWidth() >> i, 1),
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001442 std::max(mImageArray[f][0]->getWidth() >> i, 1));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001443 }
1444 }
1445
1446 if (mTexStorage && mTexStorage->isRenderTarget())
1447 {
1448 for (unsigned int f = 0; f < 6; f++)
1449 {
1450 for (unsigned int i = 1; i <= q; i++)
1451 {
daniel@transgaming.com0ad830b2012-10-31 19:52:12 +00001452 mTexStorage->generateMipmap(f, i);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001453
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001454 mImageArray[f][i]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001455 }
1456 }
1457 }
1458 else
1459 {
1460 for (unsigned int f = 0; f < 6; f++)
1461 {
1462 for (unsigned int i = 1; i <= q; i++)
1463 {
daniel@transgaming.com4ba24062012-12-20 20:54:24 +00001464 mRenderer->generateMipmap(mImageArray[f][i], mImageArray[f][i - 1]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001465 }
1466 }
1467 }
1468}
1469
1470Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target)
1471{
1472 if (!IsCubemapTextureTarget(target))
1473 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +00001474 return gl::error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001475 }
1476
1477 unsigned int face = faceIndex(target);
1478
1479 if (mFaceProxies[face] == NULL)
1480 {
daniel@transgaming.com70062c92012-11-28 19:32:30 +00001481 mFaceProxies[face] = new Renderbuffer(mRenderer, id(), new RenderbufferTextureCubeMap(this, target));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001482 }
1483
1484 return mFaceProxies[face];
1485}
1486
daniel@transgaming.comd186dc72012-11-28 19:40:16 +00001487rx::RenderTarget *TextureCubeMap::getRenderTarget(GLenum target)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001488{
1489 ASSERT(IsCubemapTextureTarget(target));
1490
1491 // ensure the underlying texture is created
1492 if (getStorage(true) == NULL)
1493 {
1494 return NULL;
1495 }
1496
1497 updateTexture();
1498
daniel@transgaming.comd186dc72012-11-28 19:40:16 +00001499 return mTexStorage->getRenderTarget(target);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001500}
1501
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +00001502int TextureCubeMap::levelCount()
1503{
1504 return mTexStorage ? mTexStorage->levelCount() - getLodOffset() : 0;
1505}
1506
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001507rx::TextureStorageInterface *TextureCubeMap::getStorage(bool renderTarget)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001508{
1509 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
1510 {
1511 if (renderTarget)
1512 {
1513 convertToRenderTarget();
1514 }
1515 else
1516 {
1517 createTexture();
1518 }
1519 }
1520
1521 return mTexStorage;
1522}
1523
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001524Texture3D::Texture3D(rx::Renderer *renderer, GLuint id) : Texture(renderer, id)
1525{
1526 mTexStorage = NULL;
1527 mColorbufferProxy = NULL;
1528 mProxyRefs = 0;
1529
1530 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1531 {
1532 mImageArray[i] = renderer->createImage();
1533 }
1534}
1535
1536Texture3D::~Texture3D()
1537{
1538 mColorbufferProxy = NULL;
1539
1540 delete mTexStorage;
1541 mTexStorage = NULL;
1542
1543 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1544 {
1545 delete mImageArray[i];
1546 }
1547}
1548
1549void Texture3D::addProxyRef(const Renderbuffer *proxy)
1550{
1551 mProxyRefs++;
1552}
1553
1554void Texture3D::releaseProxy(const Renderbuffer *proxy)
1555{
1556 if (mProxyRefs > 0)
1557 mProxyRefs--;
1558
1559 if (mProxyRefs == 0)
1560 mColorbufferProxy = NULL;
1561}
1562
1563GLenum Texture3D::getTarget() const
1564{
1565 return GL_TEXTURE_3D;
1566}
1567
1568GLsizei Texture3D::getWidth(GLint level) const
1569{
1570 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getWidth() : 0;
1571}
1572
1573GLsizei Texture3D::getHeight(GLint level) const
1574{
1575 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getHeight() : 0;
1576}
1577
1578GLsizei Texture3D::getDepth(GLint level) const
1579{
1580 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getDepth() : 0;
1581}
1582
1583GLenum Texture3D::getInternalFormat(GLint level) const
1584{
1585 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getInternalFormat() : GL_NONE;
1586}
1587
1588GLenum Texture3D::getActualFormat(GLint level) const
1589{
1590 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getActualFormat() : D3DFMT_UNKNOWN;
1591}
1592
1593bool Texture3D::isCompressed(GLint level) const
1594{
1595 return IsCompressed(getInternalFormat(level));
1596}
1597
1598bool Texture3D::isDepth(GLint level) const
1599{
1600 return IsDepthTexture(getInternalFormat(level));
1601}
1602
1603void Texture3D::setImage(GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1604{
1605 GLint internalformat = ConvertSizedInternalFormat(format, type);
1606 redefineImage(level, internalformat, width, height, depth);
1607
1608 Texture::setImage(unpackAlignment, pixels, mImageArray[level]);
1609}
1610
1611void Texture3D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
1612{
1613 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1614 redefineImage(level, format, width, height, depth);
1615
1616 Texture::setCompressedImage(imageSize, pixels, mImageArray[level]);
1617}
1618
1619void Texture3D::subImage(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1620{
1621 if (Texture::subImage(xoffset, yoffset, zoffset, width, height, depth, format, type, unpackAlignment, pixels, mImageArray[level]))
1622 {
1623 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1624 }
1625}
1626
1627void Texture3D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
1628{
1629 if (Texture::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth, format, imageSize, pixels, mImageArray[level]))
1630 {
1631 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1632 }
1633}
1634
1635void Texture3D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
1636{
1637 delete mTexStorage;
1638 mTexStorage = new rx::TextureStorageInterface3D(mRenderer, levels, internalformat, mUsage, width, height, depth);
1639 mImmutable = true;
1640
1641 for (int level = 0; level < levels; level++)
1642 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001643 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, true);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001644 width = std::max(1, width >> 1);
1645 height = std::max(1, height >> 1);
1646 depth = std::max(1, depth >> 1);
1647 }
1648
1649 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1650 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001651 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, GL_NONE, 0, 0, 0, true);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001652 }
1653
1654 if (mTexStorage->isManaged())
1655 {
1656 int levels = levelCount();
1657
1658 for (int level = 0; level < levels; level++)
1659 {
1660 mImageArray[level]->setManagedSurface(mTexStorage, level);
1661 }
1662 }
1663}
1664
1665
1666void Texture3D::generateMipmaps()
1667{
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001668 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1669 unsigned int q = log2(std::max(mImageArray[0]->getWidth(), mImageArray[0]->getHeight()));
1670 for (unsigned int i = 1; i <= q; i++)
1671 {
1672 redefineImage(i, mImageArray[0]->getInternalFormat(),
1673 std::max(mImageArray[0]->getWidth() >> i, 1),
1674 std::max(mImageArray[0]->getHeight() >> i, 1),
1675 std::max(mImageArray[0]->getDepth() >> i, 1));
1676 }
1677
1678 if (mTexStorage && mTexStorage->isRenderTarget())
1679 {
1680 for (unsigned int i = 1; i <= q; i++)
1681 {
1682 mTexStorage->generateMipmap(i);
1683
1684 mImageArray[i]->markClean();
1685 }
1686 }
1687 else
1688 {
1689 for (unsigned int i = 1; i <= q; i++)
1690 {
1691 mRenderer->generateMipmap(mImageArray[i], mImageArray[i - 1]);
1692 }
1693 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001694}
1695
1696void Texture3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1697{
1698 if (xoffset + width > mImageArray[level]->getWidth() || yoffset + height > mImageArray[level]->getHeight() || zoffset >= mImageArray[level]->getDepth())
1699 {
1700 return gl::error(GL_INVALID_VALUE);
1701 }
1702
1703 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !isSamplerComplete()))
1704 {
1705 mImageArray[level]->copy(xoffset, yoffset, zoffset, x, y, width, height, source);
1706 mDirtyImages = true;
1707 }
1708 else
1709 {
1710 if (!mTexStorage || !mTexStorage->isRenderTarget())
1711 {
1712 convertToRenderTarget();
1713 }
1714
1715 updateTexture();
1716
1717 if (level < levelCount())
1718 {
1719 gl::Rectangle sourceRect;
1720 sourceRect.x = x;
1721 sourceRect.width = width;
1722 sourceRect.y = y;
1723 sourceRect.height = height;
1724
1725 mRenderer->copyImage(source, sourceRect,
1726 gl::ExtractFormat(mImageArray[0]->getInternalFormat()),
1727 xoffset, yoffset, zoffset, mTexStorage, level);
1728 }
1729 }
1730}
1731
1732bool Texture3D::isSamplerComplete() const
1733{
1734 GLsizei width = mImageArray[0]->getWidth();
1735 GLsizei height = mImageArray[0]->getHeight();
1736 GLsizei depth = mImageArray[0]->getDepth();
1737
1738 if (width <= 0 || height <= 0 || depth <= 0)
1739 {
1740 return false;
1741 }
1742
1743 bool mipmapping = isMipmapFiltered();
1744 bool filtering, renderable;
1745
1746 if ((IsFloat32Format(getInternalFormat(0)) && !mRenderer->getFloat32TextureSupport(&filtering, &renderable)) ||
1747 (IsFloat16Format(getInternalFormat(0)) && !mRenderer->getFloat16TextureSupport(&filtering, &renderable)))
1748 {
1749 if (mSamplerState.magFilter != GL_NEAREST ||
1750 (mSamplerState.minFilter != GL_NEAREST && mSamplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
1751 {
1752 return false;
1753 }
1754 }
1755
1756 if (mipmapping && !isMipmapComplete())
1757 {
1758 return false;
1759 }
1760
1761 return true;
1762}
1763
1764bool Texture3D::isMipmapComplete() const
1765{
1766 if (isImmutable())
1767 {
1768 return true;
1769 }
1770
1771 GLsizei width = mImageArray[0]->getWidth();
1772 GLsizei height = mImageArray[0]->getHeight();
1773 GLsizei depth = mImageArray[0]->getDepth();
1774
1775 if (width <= 0 || height <= 0 || depth <= 0)
1776 {
1777 return false;
1778 }
1779
1780 int q = log2(std::max(std::max(width, height), depth));
1781
1782 for (int level = 1; level <= q; level++)
1783 {
1784 if (mImageArray[level]->getInternalFormat() != mImageArray[0]->getInternalFormat())
1785 {
1786 return false;
1787 }
1788
1789 if (mImageArray[level]->getWidth() != std::max(1, width >> level))
1790 {
1791 return false;
1792 }
1793
1794 if (mImageArray[level]->getHeight() != std::max(1, height >> level))
1795 {
1796 return false;
1797 }
1798
1799 if (mImageArray[level]->getDepth() != std::max(1, depth >> level))
1800 {
1801 return false;
1802 }
1803 }
1804
1805 return true;
1806}
1807
1808Renderbuffer *Texture3D::getRenderbuffer(GLenum target)
1809{
1810 UNIMPLEMENTED();
1811 return NULL;
1812}
1813
1814int Texture3D::levelCount()
1815{
1816 return mTexStorage ? mTexStorage->levelCount() : 0;
1817}
1818
1819void Texture3D::createTexture()
1820{
1821 GLsizei width = mImageArray[0]->getWidth();
1822 GLsizei height = mImageArray[0]->getHeight();
1823 GLsizei depth = mImageArray[0]->getDepth();
1824
1825 if (!(width > 0 && height > 0 && depth > 0))
1826 return; // do not attempt to create native textures for nonexistant data
1827
1828 GLint levels = creationLevels(width, height, depth);
1829 GLenum internalformat = mImageArray[0]->getInternalFormat();
1830
1831 delete mTexStorage;
1832 mTexStorage = new rx::TextureStorageInterface3D(mRenderer, levels, internalformat, mUsage, width, height, depth);
1833
1834 if (mTexStorage->isManaged())
1835 {
1836 int levels = levelCount();
1837
1838 for (int level = 0; level < levels; level++)
1839 {
1840 mImageArray[level]->setManagedSurface(mTexStorage, level);
1841 }
1842 }
1843
1844 mDirtyImages = true;
1845}
1846
1847void Texture3D::updateTexture()
1848{
1849 bool mipmapping = (isMipmapFiltered() && isMipmapComplete());
1850
1851 int levels = (mipmapping ? levelCount() : 1);
1852
1853 for (int level = 0; level < levels; level++)
1854 {
1855 rx::Image *image = mImageArray[level];
1856
1857 if (image->isDirty())
1858 {
1859 commitRect(level, 0, 0, 0, mImageArray[level]->getWidth(), mImageArray[level]->getHeight(), mImageArray[level]->getDepth());
1860 }
1861 }
1862}
1863
1864void Texture3D::convertToRenderTarget()
1865{
1866 rx::TextureStorageInterface3D *newTexStorage = NULL;
1867
1868 if (mImageArray[0]->getWidth() != 0 && mImageArray[0]->getHeight() != 0 && mImageArray[0]->getDepth() != 0)
1869 {
1870 GLsizei width = mImageArray[0]->getWidth();
1871 GLsizei height = mImageArray[0]->getHeight();
1872 GLsizei depth = mImageArray[0]->getDepth();
1873 GLint levels = mTexStorage != NULL ? mTexStorage->levelCount() : creationLevels(width, height, depth);
1874 GLenum internalformat = mImageArray[0]->getInternalFormat();
1875
1876 newTexStorage = new rx::TextureStorageInterface3D(mRenderer, levels, internalformat, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, width, height, depth);
1877
1878 if (mTexStorage != NULL)
1879 {
1880 if (!mRenderer->copyToRenderTarget(newTexStorage, mTexStorage))
1881 {
1882 delete newTexStorage;
1883 return gl::error(GL_OUT_OF_MEMORY);
1884 }
1885 }
1886 }
1887
1888 delete mTexStorage;
1889 mTexStorage = newTexStorage;
1890
1891 mDirtyImages = true;
1892}
1893
1894rx::RenderTarget *Texture3D::getRenderTarget(GLenum target)
1895{
1896 UNIMPLEMENTED();
1897 return NULL;
1898}
1899
1900rx::TextureStorageInterface *Texture3D::getStorage(bool renderTarget)
1901{
1902 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
1903 {
1904 if (renderTarget)
1905 {
1906 convertToRenderTarget();
1907 }
1908 else
1909 {
1910 createTexture();
1911 }
1912 }
1913
1914 return mTexStorage;
1915}
1916
1917void Texture3D::redefineImage(GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth)
1918{
1919 // If there currently is a corresponding storage texture image, it has these parameters
1920 const int storageWidth = std::max(1, mImageArray[0]->getWidth() >> level);
1921 const int storageHeight = std::max(1, mImageArray[0]->getHeight() >> level);
1922 const int storageDepth = std::max(1, mImageArray[0]->getDepth() >> level);
1923 const int storageFormat = mImageArray[0]->getInternalFormat();
1924
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001925 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, false);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001926
1927 if (mTexStorage)
1928 {
1929 const int storageLevels = mTexStorage->levelCount();
1930
1931 if ((level >= storageLevels && storageLevels != 0) ||
1932 width != storageWidth ||
1933 height != storageHeight ||
1934 depth != storageDepth ||
1935 internalformat != storageFormat) // Discard mismatched storage
1936 {
1937 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1938 {
1939 mImageArray[i]->markDirty();
1940 }
1941
1942 delete mTexStorage;
1943 mTexStorage = NULL;
1944 mDirtyImages = true;
1945 }
1946 }
1947}
1948
1949void Texture3D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth)
1950{
1951 if (level < levelCount())
1952 {
1953 rx::Image *image = mImageArray[level];
1954 if (image->updateSurface(mTexStorage, level, xoffset, yoffset, zoffset, width, height, depth))
1955 {
1956 image->markClean();
1957 }
1958 }
1959}
1960
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00001961Texture2DArray::Texture2DArray(rx::Renderer *renderer, GLuint id) : Texture(renderer, id)
1962{
1963 mTexStorage = NULL;
1964 mColorbufferProxy = NULL;
1965 mProxyRefs = 0;
1966
1967 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
1968 {
1969 mLayerCounts[level] = 0;
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00001970 mImageArray[level] = NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00001971 }
1972}
1973
1974Texture2DArray::~Texture2DArray()
1975{
1976 mColorbufferProxy = NULL;
1977
1978 delete mTexStorage;
1979 mTexStorage = NULL;
1980 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
1981 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00001982 for (int layer = 0; layer < mLayerCounts[level]; ++layer)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00001983 {
1984 delete mImageArray[level][layer];
1985 }
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00001986 delete[] mImageArray[level];
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00001987 }
1988}
1989
1990void Texture2DArray::addProxyRef(const Renderbuffer *proxy)
1991{
1992 mProxyRefs++;
1993}
1994
1995void Texture2DArray::releaseProxy(const Renderbuffer *proxy)
1996{
1997 if (mProxyRefs > 0)
1998 mProxyRefs--;
1999
2000 if (mProxyRefs == 0)
2001 mColorbufferProxy = NULL;
2002}
2003
2004GLenum Texture2DArray::getTarget() const
2005{
2006 return GL_TEXTURE_2D_ARRAY;
2007}
2008
2009GLsizei Texture2DArray::getWidth(GLint level) const
2010{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002011 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 +00002012}
2013
2014GLsizei Texture2DArray::getHeight(GLint level) const
2015{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002016 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 +00002017}
2018
2019GLsizei Texture2DArray::getDepth(GLint level) const
2020{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002021 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mLayerCounts[level] : 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002022}
2023
2024GLenum Texture2DArray::getInternalFormat(GLint level) const
2025{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002026 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 +00002027}
2028
2029GLenum Texture2DArray::getActualFormat(GLint level) const
2030{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002031 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 +00002032}
2033
2034bool Texture2DArray::isCompressed(GLint level) const
2035{
2036 return IsCompressed(getInternalFormat(level));
2037}
2038
2039bool Texture2DArray::isDepth(GLint level) const
2040{
2041 return IsDepthTexture(getInternalFormat(level));
2042}
2043
2044void Texture2DArray::setImage(GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
2045{
2046 GLint internalformat = ConvertSizedInternalFormat(format, type);
2047 redefineImage(level, internalformat, width, height, depth);
2048
2049 GLsizei inputDepthPitch = gl::ComputeDepthPitch(width, height, internalformat, unpackAlignment);
2050
2051 for (int i = 0; i < depth; i++)
2052 {
2053 const void *layerPixels = reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i);
2054 Texture::setImage(unpackAlignment, layerPixels, mImageArray[level][i]);
2055 }
2056}
2057
2058void Texture2DArray::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
2059{
2060 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
2061 redefineImage(level, format, width, height, depth);
2062
2063 GLsizei inputDepthPitch = gl::ComputeCompressedDepthPitch(width, height, format);
2064
2065 for (int i = 0; i < depth; i++)
2066 {
2067 const void *layerPixels = reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i);
2068 Texture::setCompressedImage(imageSize, layerPixels, mImageArray[level][i]);
2069 }
2070}
2071
2072void Texture2DArray::subImage(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
2073{
2074 GLint internalformat = ConvertSizedInternalFormat(format, type);
2075 GLsizei inputDepthPitch = gl::ComputeDepthPitch(width, height, internalformat, unpackAlignment);
2076
2077 for (int i = 0; i < depth; i++)
2078 {
2079 int layer = zoffset + i;
2080 const void *layerPixels = reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i);
2081
2082 if (Texture::subImage(xoffset, yoffset, zoffset, width, height, 1, format, type, unpackAlignment, layerPixels, mImageArray[level][layer]))
2083 {
2084 commitRect(level, xoffset, yoffset, layer, width, height);
2085 }
2086 }
2087}
2088
2089void Texture2DArray::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
2090{
2091 GLsizei inputDepthPitch = gl::ComputeCompressedDepthPitch(width, height, format);
2092
2093 for (int i = 0; i < depth; i++)
2094 {
2095 int layer = zoffset + i;
2096 const void *layerPixels = reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i);
2097
2098 if (Texture::subImageCompressed(xoffset, yoffset, zoffset, width, height, 1, format, imageSize, layerPixels, mImageArray[level][layer]))
2099 {
2100 commitRect(level, xoffset, yoffset, layer, width, height);
2101 }
2102 }
2103}
2104
2105void Texture2DArray::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2106{
2107 delete mTexStorage;
2108 mTexStorage = new rx::TextureStorageInterface2DArray(mRenderer, levels, internalformat, mUsage, width, height, depth);
2109 mImmutable = true;
2110
2111 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2112 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002113 GLsizei levelWidth = std::max(width >> level, 1);
2114 GLsizei levelHeight = std::max(width >> level, 1);
2115
2116 // Clear this level
2117 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002118 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002119 delete mImageArray[level][layer];
2120 }
2121 delete[] mImageArray[level];
2122 mImageArray[level] = NULL;
2123 mLayerCounts[level] = 0;
2124
2125 if (level < levels)
2126 {
2127 // Create new images for this level
2128 mImageArray[level] = new rx::Image*[depth]();
2129 mLayerCounts[level] = depth;
2130
2131 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002132 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002133 mImageArray[level][layer] = mRenderer->createImage();
2134 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, levelWidth,
2135 levelHeight, 1, true);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002136 }
2137 }
2138 }
2139
2140 if (mTexStorage->isManaged())
2141 {
2142 int levels = levelCount();
2143
2144 for (int level = 0; level < levels; level++)
2145 {
2146 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2147 {
2148 mImageArray[level][layer]->setManagedSurface(mTexStorage, layer, level);
2149 }
2150 }
2151 }
2152}
2153
2154void Texture2DArray::generateMipmaps()
2155{
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00002156 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
2157 int q = log2(std::max(getWidth(0), getHeight(0)));
2158 for (int i = 1; i <= q; i++)
2159 {
2160 redefineImage(i, getInternalFormat(0), std::max(getWidth(0) >> i, 1), std::max(getHeight(0) >> i, 1), getDepth(0));
2161 }
2162
2163 if (mTexStorage && mTexStorage->isRenderTarget())
2164 {
2165 for (int level = 1; level <= q; level++)
2166 {
2167 mTexStorage->generateMipmap(level);
2168
2169 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2170 {
2171 mImageArray[level][layer]->markClean();
2172 }
2173 }
2174 }
2175 else
2176 {
2177 for (int level = 1; level <= q; level++)
2178 {
2179 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2180 {
2181 mRenderer->generateMipmap(mImageArray[level][layer], mImageArray[level - 1][layer]);
2182 }
2183 }
2184 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002185}
2186
2187void Texture2DArray::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
2188{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002189 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 +00002190 {
2191 return gl::error(GL_INVALID_VALUE);
2192 }
2193
2194 if (!mImageArray[level][0]->isRenderableFormat() || (!mTexStorage && !isSamplerComplete()))
2195 {
2196 mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, x, y, width, height, source);
2197 mDirtyImages = true;
2198 }
2199 else
2200 {
2201 if (!mTexStorage || !mTexStorage->isRenderTarget())
2202 {
2203 convertToRenderTarget();
2204 }
2205
2206 updateTexture();
2207
2208 if (level < levelCount())
2209 {
2210 gl::Rectangle sourceRect;
2211 sourceRect.x = x;
2212 sourceRect.width = width;
2213 sourceRect.y = y;
2214 sourceRect.height = height;
2215
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002216 mRenderer->copyImage(source, sourceRect, gl::ExtractFormat(getInternalFormat(0)),
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002217 xoffset, yoffset, zoffset, mTexStorage, level);
2218 }
2219 }
2220}
2221
2222bool Texture2DArray::isSamplerComplete() const
2223{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002224 GLsizei width = getWidth(0);
2225 GLsizei height = getHeight(0);
2226 GLsizei depth = getDepth(0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002227
2228 if (width <= 0 || height <= 0 || depth <= 0)
2229 {
2230 return false;
2231 }
2232
2233 bool mipmapping = isMipmapFiltered();
2234 bool filtering, renderable;
2235
2236 if ((IsFloat32Format(getInternalFormat(0)) && !mRenderer->getFloat32TextureSupport(&filtering, &renderable)) ||
2237 (IsFloat16Format(getInternalFormat(0)) && !mRenderer->getFloat16TextureSupport(&filtering, &renderable)))
2238 {
2239 if (mSamplerState.magFilter != GL_NEAREST ||
2240 (mSamplerState.minFilter != GL_NEAREST && mSamplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
2241 {
2242 return false;
2243 }
2244 }
2245
2246 if (mipmapping && !isMipmapComplete())
2247 {
2248 return false;
2249 }
2250
2251 return true;
2252}
2253
2254bool Texture2DArray::isMipmapComplete() const
2255{
2256 if (isImmutable())
2257 {
2258 return true;
2259 }
2260
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002261 GLsizei width = getWidth(0);
2262 GLsizei height = getHeight(0);
2263 GLsizei depth = getDepth(0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002264
2265 if (width <= 0 || height <= 0 || depth <= 0)
2266 {
2267 return false;
2268 }
2269
2270 int q = log2(std::max(width, height));
2271
2272 for (int level = 1; level <= q; level++)
2273 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002274 if (getInternalFormat(level) != getInternalFormat(0))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002275 {
2276 return false;
2277 }
2278
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002279 if (getWidth(level) != std::max(1, width >> level))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002280 {
2281 return false;
2282 }
2283
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002284 if (getHeight(level) != std::max(1, height >> level))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002285 {
2286 return false;
2287 }
2288
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002289 if (getDepth(level) != depth)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002290 {
2291 return false;
2292 }
2293 }
2294
2295 return true;
2296}
2297
2298Renderbuffer *Texture2DArray::getRenderbuffer(GLenum target)
2299{
2300 UNIMPLEMENTED();
2301 return NULL;
2302}
2303
2304int Texture2DArray::levelCount()
2305{
2306 return mTexStorage ? mTexStorage->levelCount() : 0;
2307}
2308
2309void Texture2DArray::createTexture()
2310{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002311 GLsizei width = getWidth(0);
2312 GLsizei height = getHeight(0);
2313 GLsizei depth = getDepth(0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002314
2315 if (width <= 0 || height <= 0 || depth <= 0)
2316 {
2317 return; // do not attempt to create native textures for nonexistant data
2318 }
2319
2320 GLint levels = creationLevels(width, height);
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002321 GLenum internalformat = getInternalFormat(0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002322
2323 delete mTexStorage;
2324 mTexStorage = new rx::TextureStorageInterface2DArray(mRenderer, levels, internalformat, mUsage, width, height, depth);
2325
2326 if (mTexStorage->isManaged())
2327 {
2328 int levels = levelCount();
2329 for (int level = 0; level < levels; level++)
2330 {
2331 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2332 {
2333 mImageArray[level][layer]->setManagedSurface(mTexStorage, layer, level);
2334 }
2335 }
2336 }
2337
2338 mDirtyImages = true;
2339}
2340
2341void Texture2DArray::updateTexture()
2342{
2343 bool mipmapping = (isMipmapFiltered() && isMipmapComplete());
2344
2345 int levels = (mipmapping ? levelCount() : 1);
2346 for (int level = 0; level < levels; level++)
2347 {
2348 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2349 {
2350 rx::Image *image = mImageArray[level][layer];
2351
2352 if (image->isDirty())
2353 {
2354 commitRect(level, 0, 0, layer, image->getWidth(), image->getHeight());
2355 }
2356 }
2357 }
2358}
2359
2360void Texture2DArray::convertToRenderTarget()
2361{
2362 rx::TextureStorageInterface2DArray *newTexStorage = NULL;
2363
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002364 GLsizei width = getWidth(0);
2365 GLsizei height = getHeight(0);
2366 GLsizei depth = getDepth(0);
2367
2368 if (width != 0 && height != 0 && depth != 0)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002369 {
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002370 GLint levels = mTexStorage != NULL ? mTexStorage->levelCount() : creationLevels(width, height);
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002371 GLenum internalformat = getInternalFormat(0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002372
2373 newTexStorage = new rx::TextureStorageInterface2DArray(mRenderer, levels, internalformat, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, width, height, depth);
2374
2375 if (mTexStorage != NULL)
2376 {
2377 if (!mRenderer->copyToRenderTarget(newTexStorage, mTexStorage))
2378 {
2379 delete newTexStorage;
2380 return gl::error(GL_OUT_OF_MEMORY);
2381 }
2382 }
2383 }
2384
2385 delete mTexStorage;
2386 mTexStorage = newTexStorage;
2387
2388 mDirtyImages = true;
2389}
2390
2391rx::RenderTarget *Texture2DArray::getRenderTarget(GLenum target)
2392{
2393 UNIMPLEMENTED();
2394 return NULL;
2395}
2396
2397rx::TextureStorageInterface *Texture2DArray::getStorage(bool renderTarget)
2398{
2399 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
2400 {
2401 if (renderTarget)
2402 {
2403 convertToRenderTarget();
2404 }
2405 else
2406 {
2407 createTexture();
2408 }
2409 }
2410
2411 return mTexStorage;
2412}
2413
2414void Texture2DArray::redefineImage(GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth)
2415{
2416 // If there currently is a corresponding storage texture image, it has these parameters
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002417 const int storageWidth = std::max(1, getWidth(0) >> level);
2418 const int storageHeight = std::max(1, getHeight(0) >> level);
2419 const int storageDepth = getDepth(0);
2420 const int storageFormat = getInternalFormat(0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002421
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002422 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002423 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002424 delete mImageArray[level][layer];
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002425 }
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002426 delete[] mImageArray[level];
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002427
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002428 mImageArray[level] = new rx::Image*[depth]();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002429 mLayerCounts[level] = depth;
2430
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002431 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2432 {
2433 mImageArray[level][layer] = mRenderer->createImage();
2434 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, width, height, 1, false);
2435 }
2436
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002437 if (mTexStorage)
2438 {
2439 const int storageLevels = mTexStorage->levelCount();
2440
2441 if ((level >= storageLevels && storageLevels != 0) ||
2442 width != storageWidth ||
2443 height != storageHeight ||
2444 depth != storageDepth ||
2445 internalformat != storageFormat) // Discard mismatched storage
2446 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002447 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002448 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002449 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002450 {
2451 mImageArray[level][layer]->markDirty();
2452 }
2453 }
2454
2455 delete mTexStorage;
2456 mTexStorage = NULL;
2457 mDirtyImages = true;
2458 }
2459 }
2460}
2461
2462void Texture2DArray::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint layerTarget, GLsizei width, GLsizei height)
2463{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002464 if (level < levelCount() && layerTarget < getDepth(level))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002465 {
2466 rx::Image *image = mImageArray[level][layerTarget];
2467 if (image->updateSurface(mTexStorage, level, xoffset, yoffset, layerTarget, width, height))
2468 {
2469 image->markClean();
2470 }
2471 }
2472}
2473
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00002474}