blob: 425dee979a7fa939637744272b2d5e58f3c5652c [file] [log] [blame]
shannon.woods@transgaming.combdf2d802013-02-28 23:16:20 +00001#include "precompiled.h"
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00002//
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00003// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00004// Use of this source code is governed by a BSD-style license that can be
5// found in the LICENSE file.
6//
7
8// Texture.cpp: Implements the gl::Texture class and its derived classes
9// Texture2D and TextureCubeMap. Implements GL texture objects and related
10// functionality. [OpenGL ES 2.0.24] section 3.7 page 63.
11
12#include "libGLESv2/Texture.h"
13
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000014#include "libGLESv2/main.h"
shannonwoods@chromium.orga2ecfcc2013-05-30 00:11:59 +000015#include "common/mathutil.h"
16#include "common/utilities.h"
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +000017#include "libGLESv2/formatutils.h"
Geoff Langdce735c2013-06-04 10:21:18 -040018#include "libGLESv2/renderer/Blit9.h"
shannon.woods@transgaming.com486d9e92013-02-28 23:15:41 +000019#include "libGLESv2/Renderbuffer.h"
20#include "libGLESv2/renderer/Image.h"
21#include "libGLESv2/renderer/Renderer.h"
22#include "libGLESv2/renderer/TextureStorage.h"
23#include "libEGL/Surface.h"
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000024
25namespace gl
26{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000027
Jamie Madillf8989902013-07-19 16:36:58 -040028bool IsMipmapFiltered(const SamplerState &samplerState)
29{
30 switch (samplerState.minFilter)
31 {
32 case GL_NEAREST:
33 case GL_LINEAR:
34 return false;
35 case GL_NEAREST_MIPMAP_NEAREST:
36 case GL_LINEAR_MIPMAP_NEAREST:
37 case GL_NEAREST_MIPMAP_LINEAR:
38 case GL_LINEAR_MIPMAP_LINEAR:
39 return true;
40 default: UNREACHABLE();
41 return false;
42 }
43}
44
Geoff Lang4907f2c2013-07-25 12:53:57 -040045Texture::Texture(rx::Renderer *renderer, GLuint id, GLenum target) : RefCountObject(id)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000046{
daniel@transgaming.com370482e2012-11-28 19:32:13 +000047 mRenderer = renderer;
48
daniel@transgaming.comebf139f2012-10-31 18:07:32 +000049 mSamplerState.minFilter = GL_NEAREST_MIPMAP_LINEAR;
50 mSamplerState.magFilter = GL_LINEAR;
51 mSamplerState.wrapS = GL_REPEAT;
52 mSamplerState.wrapT = GL_REPEAT;
shannon.woods%transgaming.com@gtempaccount.com0b3a8df2013-04-13 03:44:51 +000053 mSamplerState.wrapR = GL_REPEAT;
daniel@transgaming.comebf139f2012-10-31 18:07:32 +000054 mSamplerState.maxAnisotropy = 1.0f;
55 mSamplerState.lodOffset = 0;
Geoff Langc82fc412013-07-10 14:43:42 -040056 mSamplerState.compareMode = GL_NONE;
57 mSamplerState.compareFunc = GL_LEQUAL;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000058 mUsage = GL_NONE;
Geoff Langc82fc412013-07-10 14:43:42 -040059
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000060 mDirtyImages = true;
61
62 mImmutable = false;
Geoff Lang4907f2c2013-07-25 12:53:57 -040063
64 mTarget = target;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000065}
66
67Texture::~Texture()
68{
69}
70
Geoff Lang4907f2c2013-07-25 12:53:57 -040071GLenum Texture::getTarget() const
72{
73 return mTarget;
74}
75
Geoff Lang8040f572013-07-25 16:49:54 -040076void Texture::addProxyRef(const Renderbuffer *proxy)
77{
78 mRenderbufferProxies.addRef(proxy);
79}
80
81void Texture::releaseProxy(const Renderbuffer *proxy)
82{
83 mRenderbufferProxies.release(proxy);
84}
85
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000086// Returns true on successful filter state update (valid enum parameter)
87bool Texture::setMinFilter(GLenum filter)
88{
89 switch (filter)
90 {
91 case GL_NEAREST:
92 case GL_LINEAR:
93 case GL_NEAREST_MIPMAP_NEAREST:
94 case GL_LINEAR_MIPMAP_NEAREST:
95 case GL_NEAREST_MIPMAP_LINEAR:
96 case GL_LINEAR_MIPMAP_LINEAR:
daniel@transgaming.com3c17ba62013-01-11 04:11:41 +000097 mSamplerState.minFilter = filter;
98 return true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000099 default:
100 return false;
101 }
102}
103
104// Returns true on successful filter state update (valid enum parameter)
105bool Texture::setMagFilter(GLenum filter)
106{
107 switch (filter)
108 {
109 case GL_NEAREST:
110 case GL_LINEAR:
daniel@transgaming.com3c17ba62013-01-11 04:11:41 +0000111 mSamplerState.magFilter = filter;
112 return true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000113 default:
114 return false;
115 }
116}
117
118// Returns true on successful wrap state update (valid enum parameter)
119bool Texture::setWrapS(GLenum wrap)
120{
121 switch (wrap)
122 {
123 case GL_REPEAT:
124 case GL_CLAMP_TO_EDGE:
125 case GL_MIRRORED_REPEAT:
daniel@transgaming.com3c17ba62013-01-11 04:11:41 +0000126 mSamplerState.wrapS = wrap;
127 return true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000128 default:
129 return false;
130 }
131}
132
133// Returns true on successful wrap state update (valid enum parameter)
134bool Texture::setWrapT(GLenum wrap)
135{
136 switch (wrap)
137 {
138 case GL_REPEAT:
139 case GL_CLAMP_TO_EDGE:
140 case GL_MIRRORED_REPEAT:
daniel@transgaming.com3c17ba62013-01-11 04:11:41 +0000141 mSamplerState.wrapT = wrap;
142 return true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000143 default:
144 return false;
145 }
146}
147
shannon.woods%transgaming.com@gtempaccount.com0b3a8df2013-04-13 03:44:51 +0000148// Returns true on successful wrap state update (valid enum parameter)
149bool Texture::setWrapR(GLenum wrap)
150{
151 switch (wrap)
152 {
153 case GL_REPEAT:
154 case GL_CLAMP_TO_EDGE:
155 case GL_MIRRORED_REPEAT:
156 mSamplerState.wrapR = wrap;
157 return true;
158 default:
159 return false;
160 }
161}
162
daniel@transgaming.com07ab8412012-07-12 15:17:09 +0000163// Returns true on successful max anisotropy update (valid anisotropy value)
164bool Texture::setMaxAnisotropy(float textureMaxAnisotropy, float contextMaxAnisotropy)
165{
166 textureMaxAnisotropy = std::min(textureMaxAnisotropy, contextMaxAnisotropy);
167 if (textureMaxAnisotropy < 1.0f)
168 {
169 return false;
170 }
daniel@transgaming.com3c17ba62013-01-11 04:11:41 +0000171
172 mSamplerState.maxAnisotropy = textureMaxAnisotropy;
173
daniel@transgaming.com07ab8412012-07-12 15:17:09 +0000174 return true;
175}
176
Geoff Langc82fc412013-07-10 14:43:42 -0400177bool Texture::setCompareMode(GLenum mode)
178{
179 // Acceptable mode parameters from GLES 3.0.2 spec, table 3.17
180 switch (mode)
181 {
182 case GL_NONE:
183 case GL_COMPARE_REF_TO_TEXTURE:
184 mSamplerState.compareMode = mode;
185 return true;
186 default:
187 return false;
188 }
189}
190
191bool Texture::setCompareFunc(GLenum func)
192{
193 // Acceptable function parameters from GLES 3.0.2 spec, table 3.17
194 switch (func)
195 {
196 case GL_LEQUAL:
197 case GL_GEQUAL:
198 case GL_LESS:
199 case GL_GREATER:
200 case GL_EQUAL:
201 case GL_NOTEQUAL:
202 case GL_ALWAYS:
203 case GL_NEVER:
204 mSamplerState.compareFunc = func;
205 return true;
206 default:
207 return false;
208 }
209}
210
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000211// Returns true on successful usage state update (valid enum parameter)
212bool Texture::setUsage(GLenum usage)
213{
214 switch (usage)
215 {
216 case GL_NONE:
217 case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
218 mUsage = usage;
219 return true;
220 default:
221 return false;
222 }
223}
224
225GLenum Texture::getMinFilter() const
226{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000227 return mSamplerState.minFilter;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000228}
229
230GLenum Texture::getMagFilter() const
231{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000232 return mSamplerState.magFilter;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000233}
234
235GLenum Texture::getWrapS() const
236{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000237 return mSamplerState.wrapS;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000238}
239
240GLenum Texture::getWrapT() const
241{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000242 return mSamplerState.wrapT;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000243}
244
shannon.woods%transgaming.com@gtempaccount.com0b3a8df2013-04-13 03:44:51 +0000245GLenum Texture::getWrapR() const
246{
247 return mSamplerState.wrapR;
248}
249
daniel@transgaming.com07ab8412012-07-12 15:17:09 +0000250float Texture::getMaxAnisotropy() const
251{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000252 return mSamplerState.maxAnisotropy;
253}
254
255int Texture::getLodOffset()
256{
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000257 rx::TextureStorageInterface *texture = getStorage(false);
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000258 return texture ? texture->getLodOffset() : 0;
259}
260
261void Texture::getSamplerState(SamplerState *sampler)
262{
263 *sampler = mSamplerState;
264 sampler->lodOffset = getLodOffset();
daniel@transgaming.com07ab8412012-07-12 15:17:09 +0000265}
266
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000267GLenum Texture::getUsage() const
268{
269 return mUsage;
270}
271
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +0000272void Texture::setImage(GLint unpackAlignment, GLenum type, const void *pixels, rx::Image *image)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000273{
274 if (pixels != NULL)
275 {
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +0000276 image->loadData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), unpackAlignment, type, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000277 mDirtyImages = true;
278 }
279}
280
daniel@transgaming.com31b13e12012-11-28 19:34:30 +0000281void Texture::setCompressedImage(GLsizei imageSize, const void *pixels, rx::Image *image)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000282{
283 if (pixels != NULL)
284 {
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000285 image->loadCompressedData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000286 mDirtyImages = true;
287 }
288}
289
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000290bool Texture::subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
291 GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, rx::Image *image)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000292{
293 if (pixels != NULL)
294 {
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +0000295 image->loadData(xoffset, yoffset, zoffset, width, height, depth, unpackAlignment, type, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000296 mDirtyImages = true;
297 }
298
299 return true;
300}
301
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000302bool Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
303 GLenum format, GLsizei imageSize, const void *pixels, rx::Image *image)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000304{
305 if (pixels != NULL)
306 {
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000307 image->loadCompressedData(xoffset, yoffset, zoffset, width, height, depth, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000308 mDirtyImages = true;
309 }
310
311 return true;
312}
313
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000314rx::TextureStorageInterface *Texture::getNativeTexture()
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000315{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000316 // ensure the underlying texture is created
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000317
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000318 rx::TextureStorageInterface *storage = getStorage(false);
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000319 if (storage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000320 {
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000321 updateTexture();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000322 }
323
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000324 return storage;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000325}
326
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000327bool Texture::hasDirtyImages() const
328{
329 return mDirtyImages;
330}
331
332void Texture::resetDirty()
333{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000334 mDirtyImages = false;
335}
336
337unsigned int Texture::getTextureSerial()
338{
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000339 rx::TextureStorageInterface *texture = getStorage(false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000340 return texture ? texture->getTextureSerial() : 0;
341}
342
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000343bool Texture::isImmutable() const
344{
345 return mImmutable;
346}
347
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +0000348GLint Texture::creationLevels(GLsizei width, GLsizei height, GLsizei depth) const
349{
350 // NPOT checks are not required in ES 3.0, NPOT texture support is assumed.
351 return 0; // Maximum number of levels
352}
353
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000354GLint Texture::creationLevels(GLsizei width, GLsizei height) const
355{
daniel@transgaming.comea32d482012-11-28 19:33:18 +0000356 if ((isPow2(width) && isPow2(height)) || mRenderer->getNonPower2TextureSupport())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000357 {
358 return 0; // Maximum number of levels
359 }
360 else
361 {
362 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
363 return 1;
364 }
365}
366
367GLint Texture::creationLevels(GLsizei size) const
368{
369 return creationLevels(size, size);
370}
371
Geoff Lang4907f2c2013-07-25 12:53:57 -0400372Texture2D::Texture2D(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_2D)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000373{
374 mTexStorage = NULL;
375 mSurface = NULL;
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000376
377 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
378 {
daniel@transgaming.com244e1832012-12-20 20:52:35 +0000379 mImageArray[i] = renderer->createImage();
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000380 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000381}
382
383Texture2D::~Texture2D()
384{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000385 delete mTexStorage;
386 mTexStorage = NULL;
387
388 if (mSurface)
389 {
390 mSurface->setBoundTexture(NULL);
391 mSurface = NULL;
392 }
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000393
394 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
395 {
396 delete mImageArray[i];
397 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000398}
399
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000400GLsizei Texture2D::getWidth(GLint level) const
401{
402 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000403 return mImageArray[level]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000404 else
405 return 0;
406}
407
408GLsizei Texture2D::getHeight(GLint level) const
409{
410 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000411 return mImageArray[level]->getHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000412 else
413 return 0;
414}
415
416GLenum Texture2D::getInternalFormat(GLint level) const
417{
418 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000419 return mImageArray[level]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000420 else
421 return GL_NONE;
422}
423
daniel@transgaming.com20d36662012-10-31 19:51:43 +0000424GLenum Texture2D::getActualFormat(GLint level) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000425{
426 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000427 return mImageArray[level]->getActualFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000428 else
429 return D3DFMT_UNKNOWN;
430}
431
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000432void Texture2D::redefineImage(GLint level, GLint internalformat, GLsizei width, GLsizei height)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000433{
434 releaseTexImage();
shannon.woods@transgaming.com8a406682013-02-28 23:15:26 +0000435
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000436 // If there currently is a corresponding storage texture image, it has these parameters
437 const int storageWidth = std::max(1, mImageArray[0]->getWidth() >> level);
438 const int storageHeight = std::max(1, mImageArray[0]->getHeight() >> level);
439 const int storageFormat = mImageArray[0]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000440
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000441 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, width, height, 1, false);
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000442
443 if (mTexStorage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000444 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000445 const int storageLevels = mTexStorage->levelCount();
446
447 if ((level >= storageLevels && storageLevels != 0) ||
448 width != storageWidth ||
449 height != storageHeight ||
450 internalformat != storageFormat) // Discard mismatched storage
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000451 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000452 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
453 {
454 mImageArray[i]->markDirty();
455 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000456
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000457 delete mTexStorage;
458 mTexStorage = NULL;
459 mDirtyImages = true;
460 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000461 }
462}
463
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +0000464void Texture2D::setImage(GLint level, GLsizei width, GLsizei height, GLint internalFormat, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000465{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +0000466 GLuint clientVersion = mRenderer->getCurrentClientVersion();
467 GLint sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
468 : GetSizedInternalFormat(format, type, clientVersion);
469 redefineImage(level, sizedInternalFormat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000470
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +0000471 Texture::setImage(unpackAlignment, type, pixels, mImageArray[level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000472}
473
474void Texture2D::bindTexImage(egl::Surface *surface)
475{
476 releaseTexImage();
477
daniel@transgaming.com106e1f72012-10-31 18:38:36 +0000478 GLint internalformat = surface->getFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000479
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000480 mImageArray[0]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, surface->getWidth(), surface->getHeight(), 1, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000481
482 delete mTexStorage;
daniel@transgaming.comd8353dd2012-12-20 21:11:14 +0000483 mTexStorage = new rx::TextureStorageInterface2D(mRenderer, surface->getSwapChain());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000484
485 mDirtyImages = true;
486 mSurface = surface;
487 mSurface->setBoundTexture(this);
488}
489
490void Texture2D::releaseTexImage()
491{
492 if (mSurface)
493 {
494 mSurface->setBoundTexture(NULL);
495 mSurface = NULL;
496
497 if (mTexStorage)
498 {
499 delete mTexStorage;
500 mTexStorage = NULL;
501 }
502
503 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
504 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000505 mImageArray[i]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000506 }
507 }
508}
509
510void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
511{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000512 // 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 +0000513 redefineImage(level, format, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000514
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000515 Texture::setCompressedImage(imageSize, pixels, mImageArray[level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000516}
517
518void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
519{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000520 if (level < levelCount())
521 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000522 rx::Image *image = mImageArray[level];
daniel@transgaming.com0f195ad2012-10-31 19:51:59 +0000523 if (image->updateSurface(mTexStorage, level, xoffset, yoffset, width, height))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000524 {
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000525 image->markClean();
526 }
527 }
528}
529
530void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
531{
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000532 if (Texture::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpackAlignment, pixels, mImageArray[level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000533 {
534 commitRect(level, xoffset, yoffset, width, height);
535 }
536}
537
538void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
539{
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000540 if (Texture::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000541 {
542 commitRect(level, xoffset, yoffset, width, height);
543 }
544}
545
546void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
547{
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +0000548 GLuint clientVersion = mRenderer->getCurrentClientVersion();
549 GLint sizedInternalFormat = IsSizedInternalFormat(format, clientVersion) ? format
550 : GetSizedInternalFormat(format, GL_UNSIGNED_BYTE, clientVersion);
551 redefineImage(level, sizedInternalFormat, width, height);
shannon.woods@transgaming.com8a406682013-02-28 23:15:26 +0000552
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000553 if (!mImageArray[level]->isRenderableFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000554 {
shannon.woods%transgaming.com@gtempaccount.come5dcce72013-04-13 03:44:33 +0000555 mImageArray[level]->copy(0, 0, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000556 mDirtyImages = true;
557 }
558 else
559 {
560 if (!mTexStorage || !mTexStorage->isRenderTarget())
561 {
562 convertToRenderTarget();
563 }
564
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000565 mImageArray[level]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000566
567 if (width != 0 && height != 0 && level < levelCount())
568 {
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +0000569 gl::Rectangle sourceRect;
570 sourceRect.x = x;
571 sourceRect.width = width;
572 sourceRect.y = y;
573 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000574
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +0000575 mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000576 }
577 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000578}
579
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +0000580void 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 +0000581{
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +0000582 if (xoffset + width > mImageArray[level]->getWidth() || yoffset + height > mImageArray[level]->getHeight() || zoffset != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000583 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +0000584 return gl::error(GL_INVALID_VALUE);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000585 }
586
Jamie Madill07edd442013-07-19 16:36:58 -0400587 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
588 // the current level we're copying to is defined (with appropriate format, width & height)
589 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
590
591 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000592 {
shannon.woods%transgaming.com@gtempaccount.come5dcce72013-04-13 03:44:33 +0000593 mImageArray[level]->copy(xoffset, yoffset, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000594 mDirtyImages = true;
595 }
596 else
597 {
598 if (!mTexStorage || !mTexStorage->isRenderTarget())
599 {
600 convertToRenderTarget();
601 }
602
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000603 if (level < levelCount())
604 {
Jamie Madill07edd442013-07-19 16:36:58 -0400605 updateTextureLevel(level);
606
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +0000607 GLuint clientVersion = mRenderer->getCurrentClientVersion();
608
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +0000609 gl::Rectangle sourceRect;
610 sourceRect.x = x;
611 sourceRect.width = width;
612 sourceRect.y = y;
613 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000614
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +0000615 mRenderer->copyImage(source, sourceRect,
616 gl::GetFormat(mImageArray[0]->getInternalFormat(), clientVersion),
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +0000617 xoffset, yoffset, mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000618 }
619 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000620}
621
622void Texture2D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height)
623{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000624 delete mTexStorage;
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000625 mTexStorage = new rx::TextureStorageInterface2D(mRenderer, levels, internalformat, mUsage, false, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000626 mImmutable = true;
627
628 for (int level = 0; level < levels; level++)
629 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000630 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, width, height, 1, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000631 width = std::max(1, width >> 1);
632 height = std::max(1, height >> 1);
633 }
634
635 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
636 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000637 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000638 }
639
640 if (mTexStorage->isManaged())
641 {
642 int levels = levelCount();
643
644 for (int level = 0; level < levels; level++)
645 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000646 mImageArray[level]->setManagedSurface(mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000647 }
648 }
649}
650
651// Tests for 2D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85.
Jamie Madillf8989902013-07-19 16:36:58 -0400652bool Texture2D::isSamplerComplete(const SamplerState &samplerState) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000653{
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000654 GLsizei width = mImageArray[0]->getWidth();
655 GLsizei height = mImageArray[0]->getHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000656
657 if (width <= 0 || height <= 0)
658 {
659 return false;
660 }
661
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000662 if (!IsTextureFilteringSupported(getInternalFormat(0), mRenderer))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000663 {
Jamie Madillf8989902013-07-19 16:36:58 -0400664 if (samplerState.magFilter != GL_NEAREST ||
665 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000666 {
667 return false;
668 }
669 }
670
daniel@transgaming.comea32d482012-11-28 19:33:18 +0000671 bool npotSupport = mRenderer->getNonPower2TextureSupport();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000672
673 if (!npotSupport)
674 {
Jamie Madillf8989902013-07-19 16:36:58 -0400675 if ((samplerState.wrapS != GL_CLAMP_TO_EDGE && !isPow2(width)) ||
676 (samplerState.wrapT != GL_CLAMP_TO_EDGE && !isPow2(height)))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000677 {
678 return false;
679 }
680 }
681
Jamie Madillf8989902013-07-19 16:36:58 -0400682 if (IsMipmapFiltered(samplerState))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000683 {
684 if (!npotSupport)
685 {
686 if (!isPow2(width) || !isPow2(height))
687 {
688 return false;
689 }
690 }
691
692 if (!isMipmapComplete())
693 {
694 return false;
695 }
696 }
697
Geoff Langc82fc412013-07-10 14:43:42 -0400698 // OpenGLES 3.0.2 spec section 3.8.13 states that a texture is not mipmap complete if:
699 // The internalformat specified for the texture arrays is a sized internal depth or
700 // depth and stencil format (see table 3.13), the value of TEXTURE_COMPARE_-
701 // MODE is NONE, and either the magnification filter is not NEAREST or the mini-
702 // fication filter is neither NEAREST nor NEAREST_MIPMAP_NEAREST.
703 if (gl::GetDepthBits(getInternalFormat(0), mRenderer->getCurrentClientVersion()) > 0)
704 {
705 if (mSamplerState.compareMode == GL_NONE)
706 {
707 if ((mSamplerState.minFilter != GL_NEAREST && mSamplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST) ||
708 mSamplerState.magFilter != GL_NEAREST)
709 {
710 return false;
711 }
712 }
713 }
714
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000715 return true;
716}
717
718// Tests for 2D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
719bool Texture2D::isMipmapComplete() const
720{
Jamie Madill07edd442013-07-19 16:36:58 -0400721 GLsizei width = mImageArray[0]->getWidth();
722 GLsizei height = mImageArray[0]->getHeight();
723
724 int q = log2(std::max(width, height));
725
726 for (int level = 0; level <= q; level++)
727 {
728 if (!isLevelComplete(level))
729 {
730 return false;
731 }
732 }
733
734 return true;
735}
736
737bool Texture2D::isLevelComplete(int level) const
738{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000739 if (isImmutable())
740 {
741 return true;
742 }
743
Jamie Madill07edd442013-07-19 16:36:58 -0400744 const rx::Image *baseImage = mImageArray[0];
745 GLsizei width = baseImage->getWidth();
746 GLsizei height = baseImage->getHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000747
748 if (width <= 0 || height <= 0)
749 {
750 return false;
751 }
752
Jamie Madill07edd442013-07-19 16:36:58 -0400753 // The base image level is complete if the width and height are positive
754 if (level == 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000755 {
Jamie Madill07edd442013-07-19 16:36:58 -0400756 return true;
757 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000758
Jamie Madill07edd442013-07-19 16:36:58 -0400759 ASSERT(level >= 1 && level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
760 rx::Image *image = mImageArray[level];
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000761
Jamie Madill07edd442013-07-19 16:36:58 -0400762 if (image->getInternalFormat() != baseImage->getInternalFormat())
763 {
764 return false;
765 }
766
767 if (image->getWidth() != std::max(1, width >> level))
768 {
769 return false;
770 }
771
772 if (image->getHeight() != std::max(1, height >> level))
773 {
774 return false;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000775 }
776
777 return true;
778}
779
780bool Texture2D::isCompressed(GLint level) const
781{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000782 return IsFormatCompressed(getInternalFormat(level), mRenderer->getCurrentClientVersion());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000783}
784
785bool Texture2D::isDepth(GLint level) const
786{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000787 return GetDepthBits(getInternalFormat(level), mRenderer->getCurrentClientVersion()) > 0;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000788}
789
daniel@transgaming.comf032cb82012-10-31 19:51:52 +0000790// Constructs a native texture resource from the texture images
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000791void Texture2D::createTexture()
792{
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000793 GLsizei width = mImageArray[0]->getWidth();
794 GLsizei height = mImageArray[0]->getHeight();
daniel@transgaming.come6a09842012-09-17 21:28:55 +0000795
796 if (!(width > 0 && height > 0))
daniel@transgaming.comf032cb82012-10-31 19:51:52 +0000797 return; // do not attempt to create native textures for nonexistant data
daniel@transgaming.come6a09842012-09-17 21:28:55 +0000798
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000799 GLint levels = creationLevels(width, height);
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000800 GLenum internalformat = mImageArray[0]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000801
802 delete mTexStorage;
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000803 mTexStorage = new rx::TextureStorageInterface2D(mRenderer, levels, internalformat, mUsage, false, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000804
805 if (mTexStorage->isManaged())
806 {
807 int levels = levelCount();
808
809 for (int level = 0; level < levels; level++)
810 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000811 mImageArray[level]->setManagedSurface(mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000812 }
813 }
814
815 mDirtyImages = true;
816}
817
818void Texture2D::updateTexture()
819{
Jamie Madilleb3665c2013-07-19 16:36:57 -0400820 int levels = (isMipmapComplete() ? levelCount() : 1);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000821
822 for (int level = 0; level < levels; level++)
823 {
Jamie Madill07edd442013-07-19 16:36:58 -0400824 updateTextureLevel(level);
825 }
826}
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000827
Jamie Madill07edd442013-07-19 16:36:58 -0400828void Texture2D::updateTextureLevel(int level)
829{
830 ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
831 rx::Image *image = mImageArray[level];
832
833 if (image->isDirty())
834 {
835 commitRect(level, 0, 0, mImageArray[level]->getWidth(), mImageArray[level]->getHeight());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000836 }
837}
838
839void Texture2D::convertToRenderTarget()
840{
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000841 rx::TextureStorageInterface2D *newTexStorage = NULL;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000842
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000843 if (mImageArray[0]->getWidth() != 0 && mImageArray[0]->getHeight() != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000844 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000845 GLsizei width = mImageArray[0]->getWidth();
846 GLsizei height = mImageArray[0]->getHeight();
shannon.woods@transgaming.com6bb48862013-02-28 23:09:34 +0000847 GLint levels = mTexStorage != NULL ? mTexStorage->levelCount() : creationLevels(width, height);
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000848 GLenum internalformat = mImageArray[0]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000849
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000850 newTexStorage = new rx::TextureStorageInterface2D(mRenderer, levels, internalformat, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, true, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000851
852 if (mTexStorage != NULL)
853 {
daniel@transgaming.com1d80eee2012-11-28 19:33:31 +0000854 if (!mRenderer->copyToRenderTarget(newTexStorage, mTexStorage))
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +0000855 {
856 delete newTexStorage;
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +0000857 return gl::error(GL_OUT_OF_MEMORY);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000858 }
859 }
860 }
861
862 delete mTexStorage;
863 mTexStorage = newTexStorage;
864
865 mDirtyImages = true;
866}
867
868void Texture2D::generateMipmaps()
869{
daniel@transgaming.comea32d482012-11-28 19:33:18 +0000870 if (!mRenderer->getNonPower2TextureSupport())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000871 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000872 if (!isPow2(mImageArray[0]->getWidth()) || !isPow2(mImageArray[0]->getHeight()))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000873 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +0000874 return gl::error(GL_INVALID_OPERATION);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000875 }
876 }
877
878 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000879 unsigned int q = log2(std::max(mImageArray[0]->getWidth(), mImageArray[0]->getHeight()));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000880 for (unsigned int i = 1; i <= q; i++)
881 {
shannon.woods@transgaming.com8a406682013-02-28 23:15:26 +0000882 redefineImage(i, mImageArray[0]->getInternalFormat(),
883 std::max(mImageArray[0]->getWidth() >> i, 1),
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000884 std::max(mImageArray[0]->getHeight() >> i, 1));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000885 }
886
887 if (mTexStorage && mTexStorage->isRenderTarget())
888 {
889 for (unsigned int i = 1; i <= q; i++)
890 {
daniel@transgaming.com0ad830b2012-10-31 19:52:12 +0000891 mTexStorage->generateMipmap(i);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000892
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000893 mImageArray[i]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000894 }
895 }
896 else
897 {
898 for (unsigned int i = 1; i <= q; i++)
899 {
daniel@transgaming.com4ba24062012-12-20 20:54:24 +0000900 mRenderer->generateMipmap(mImageArray[i], mImageArray[i - 1]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000901 }
902 }
903}
904
Geoff Lang8040f572013-07-25 16:49:54 -0400905Renderbuffer *Texture2D::getRenderbuffer(GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000906{
Geoff Lang8040f572013-07-25 16:49:54 -0400907 Renderbuffer *renderBuffer = mRenderbufferProxies.get(level, 0);
908 if (!renderBuffer)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000909 {
Geoff Lang8040f572013-07-25 16:49:54 -0400910 renderBuffer = new Renderbuffer(mRenderer, id(), new RenderbufferTexture2D(this, level));
911 mRenderbufferProxies.add(level, 0, renderBuffer);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000912 }
913
Geoff Lang8040f572013-07-25 16:49:54 -0400914 return renderBuffer;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000915}
916
Geoff Lang8040f572013-07-25 16:49:54 -0400917unsigned int Texture2D::getRenderTargetSerial(GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000918{
Geoff Lang8040f572013-07-25 16:49:54 -0400919 if (!mTexStorage || !mTexStorage->isRenderTarget())
920 {
921 convertToRenderTarget();
922 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000923
Geoff Lang8040f572013-07-25 16:49:54 -0400924 return mTexStorage ? mTexStorage->getRenderTargetSerial(level) : 0;
925}
926
927rx::RenderTarget *Texture2D::getRenderTarget(GLint level)
928{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000929 // ensure the underlying texture is created
930 if (getStorage(true) == NULL)
931 {
932 return NULL;
933 }
934
935 updateTexture();
Geoff Lang8040f572013-07-25 16:49:54 -0400936
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000937 // ensure this is NOT a depth texture
Geoff Lang8040f572013-07-25 16:49:54 -0400938 if (isDepth(level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000939 {
940 return NULL;
941 }
daniel@transgaming.com34da3972012-12-20 21:10:29 +0000942
Geoff Lang8040f572013-07-25 16:49:54 -0400943 return mTexStorage->getRenderTarget(level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000944}
945
Geoff Lang8040f572013-07-25 16:49:54 -0400946rx::RenderTarget *Texture2D::getDepthSencil(GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000947{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000948 // ensure the underlying texture is created
949 if (getStorage(true) == NULL)
950 {
951 return NULL;
952 }
953
954 updateTexture();
955
956 // ensure this is actually a depth texture
Geoff Lang8040f572013-07-25 16:49:54 -0400957 if (!isDepth(level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000958 {
959 return NULL;
960 }
Geoff Lang8040f572013-07-25 16:49:54 -0400961
962 return mTexStorage->getRenderTarget(level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000963}
964
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +0000965int Texture2D::levelCount()
966{
shannon.woods@transgaming.com5016f8e2013-02-28 23:20:57 +0000967 return mTexStorage ? mTexStorage->levelCount() : 0;
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +0000968}
969
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000970rx::TextureStorageInterface *Texture2D::getStorage(bool renderTarget)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000971{
972 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
973 {
974 if (renderTarget)
975 {
976 convertToRenderTarget();
977 }
978 else
979 {
980 createTexture();
981 }
982 }
983
984 return mTexStorage;
985}
986
Geoff Lang4907f2c2013-07-25 12:53:57 -0400987TextureCubeMap::TextureCubeMap(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_CUBE_MAP)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000988{
989 mTexStorage = NULL;
990 for (int i = 0; i < 6; i++)
991 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000992 for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
993 {
daniel@transgaming.com244e1832012-12-20 20:52:35 +0000994 mImageArray[i][j] = renderer->createImage();
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000995 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000996 }
997}
998
999TextureCubeMap::~TextureCubeMap()
1000{
1001 for (int i = 0; i < 6; i++)
1002 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001003 for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
1004 {
1005 delete mImageArray[i][j];
1006 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001007 }
1008
1009 delete mTexStorage;
1010 mTexStorage = NULL;
1011}
1012
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001013GLsizei TextureCubeMap::getWidth(GLenum target, GLint level) const
1014{
1015 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001016 return mImageArray[faceIndex(target)][level]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001017 else
1018 return 0;
1019}
1020
1021GLsizei TextureCubeMap::getHeight(GLenum target, GLint level) const
1022{
1023 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001024 return mImageArray[faceIndex(target)][level]->getHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001025 else
1026 return 0;
1027}
1028
1029GLenum TextureCubeMap::getInternalFormat(GLenum target, GLint level) const
1030{
1031 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001032 return mImageArray[faceIndex(target)][level]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001033 else
1034 return GL_NONE;
1035}
1036
daniel@transgaming.com20d36662012-10-31 19:51:43 +00001037GLenum TextureCubeMap::getActualFormat(GLenum target, GLint level) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001038{
1039 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001040 return mImageArray[faceIndex(target)][level]->getActualFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001041 else
1042 return D3DFMT_UNKNOWN;
1043}
1044
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001045void TextureCubeMap::setImagePosX(GLint level, GLsizei width, GLsizei height, GLint internalFormat, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001046{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001047 setImage(0, level, width, height, internalFormat, format, type, unpackAlignment, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001048}
1049
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001050void TextureCubeMap::setImageNegX(GLint level, GLsizei width, GLsizei height, GLint internalFormat, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001051{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001052 setImage(1, level, width, height, internalFormat, format, type, unpackAlignment, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001053}
1054
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001055void TextureCubeMap::setImagePosY(GLint level, GLsizei width, GLsizei height, GLint internalFormat, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001056{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001057 setImage(2, level, width, height, internalFormat, format, type, unpackAlignment, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001058}
1059
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001060void TextureCubeMap::setImageNegY(GLint level, GLsizei width, GLsizei height, GLint internalFormat, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001061{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001062 setImage(3, level, width, height, internalFormat, format, type, unpackAlignment, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001063}
1064
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001065void TextureCubeMap::setImagePosZ(GLint level, GLsizei width, GLsizei height, GLint internalFormat, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001066{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001067 setImage(4, level, width, height, internalFormat, format, type, unpackAlignment, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001068}
1069
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001070void TextureCubeMap::setImageNegZ(GLint level, GLsizei width, GLsizei height, GLint internalFormat, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001071{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001072 setImage(5, level, width, height, internalFormat, format, type, unpackAlignment, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001073}
1074
1075void TextureCubeMap::setCompressedImage(GLenum face, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
1076{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001077 // 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 +00001078 redefineImage(faceIndex(face), level, format, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001079
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001080 Texture::setCompressedImage(imageSize, pixels, mImageArray[faceIndex(face)][level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001081}
1082
1083void TextureCubeMap::commitRect(int face, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1084{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001085 if (level < levelCount())
1086 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001087 rx::Image *image = mImageArray[face][level];
daniel@transgaming.com0f195ad2012-10-31 19:51:59 +00001088 if (image->updateSurface(mTexStorage, face, level, xoffset, yoffset, width, height))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001089 image->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001090 }
1091}
1092
1093void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1094{
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +00001095 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 +00001096 {
1097 commitRect(faceIndex(target), level, xoffset, yoffset, width, height);
1098 }
1099}
1100
1101void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1102{
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +00001103 if (Texture::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[faceIndex(target)][level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001104 {
1105 commitRect(faceIndex(target), level, xoffset, yoffset, width, height);
1106 }
1107}
1108
1109// Tests for cube map sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 86.
Jamie Madillf8989902013-07-19 16:36:58 -04001110bool TextureCubeMap::isSamplerComplete(const SamplerState &samplerState) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001111{
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001112 int size = mImageArray[0][0]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001113
Jamie Madillf8989902013-07-19 16:36:58 -04001114 bool mipmapping = IsMipmapFiltered(samplerState);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001115
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001116 if (!IsTextureFilteringSupported(getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0), mRenderer))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001117 {
Jamie Madillf8989902013-07-19 16:36:58 -04001118 if (samplerState.magFilter != GL_NEAREST ||
1119 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001120 {
1121 return false;
1122 }
1123 }
1124
daniel@transgaming.comea32d482012-11-28 19:33:18 +00001125 if (!isPow2(size) && !mRenderer->getNonPower2TextureSupport())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001126 {
Jamie Madillf8989902013-07-19 16:36:58 -04001127 if (samplerState.wrapS != GL_CLAMP_TO_EDGE || samplerState.wrapT != GL_CLAMP_TO_EDGE || mipmapping)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001128 {
1129 return false;
1130 }
1131 }
1132
1133 if (!mipmapping)
1134 {
1135 if (!isCubeComplete())
1136 {
1137 return false;
1138 }
1139 }
1140 else
1141 {
1142 if (!isMipmapCubeComplete()) // Also tests for isCubeComplete()
1143 {
1144 return false;
1145 }
1146 }
1147
1148 return true;
1149}
1150
1151// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1152bool TextureCubeMap::isCubeComplete() const
1153{
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001154 if (mImageArray[0][0]->getWidth() <= 0 || mImageArray[0][0]->getHeight() != mImageArray[0][0]->getWidth())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001155 {
1156 return false;
1157 }
1158
1159 for (unsigned int face = 1; face < 6; face++)
1160 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001161 if (mImageArray[face][0]->getWidth() != mImageArray[0][0]->getWidth() ||
1162 mImageArray[face][0]->getWidth() != mImageArray[0][0]->getHeight() ||
1163 mImageArray[face][0]->getInternalFormat() != mImageArray[0][0]->getInternalFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001164 {
1165 return false;
1166 }
1167 }
1168
1169 return true;
1170}
1171
1172bool TextureCubeMap::isMipmapCubeComplete() const
1173{
1174 if (isImmutable())
1175 {
1176 return true;
1177 }
1178
1179 if (!isCubeComplete())
1180 {
1181 return false;
1182 }
1183
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001184 GLsizei size = mImageArray[0][0]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001185 int q = log2(size);
1186
1187 for (int face = 0; face < 6; face++)
1188 {
1189 for (int level = 1; level <= q; level++)
1190 {
Jamie Madill07edd442013-07-19 16:36:58 -04001191 if (!isFaceLevelComplete(face, level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001192 {
1193 return false;
1194 }
1195 }
1196 }
1197
1198 return true;
1199}
1200
Jamie Madill07edd442013-07-19 16:36:58 -04001201bool TextureCubeMap::isFaceLevelComplete(int face, int level) const
1202{
1203 ASSERT(level >= 0 && face < 6 && level < (int)ArraySize(mImageArray[face]) && mImageArray[face][level] != NULL);
1204
1205 if (isImmutable())
1206 {
1207 return true;
1208 }
1209
1210 const rx::Image *baseImage = mImageArray[face][0];
1211 GLsizei size = baseImage->getWidth();
1212
1213 if (size <= 0)
1214 {
1215 return false;
1216 }
1217
1218 // The base image level is complete if the width and height are positive
1219 if (level == 0)
1220 {
1221 return true;
1222 }
1223
1224 rx::Image *image = mImageArray[face][level];
1225
1226 if (image->getInternalFormat() != baseImage->getInternalFormat())
1227 {
1228 return false;
1229 }
1230
1231 if (mImageArray[face][level]->getWidth() != std::max(1, size >> level))
1232 {
1233 return false;
1234 }
1235
1236 return true;
1237}
1238
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001239bool TextureCubeMap::isCompressed(GLenum target, GLint level) const
1240{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001241 return IsFormatCompressed(getInternalFormat(target, level), mRenderer->getCurrentClientVersion());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001242}
1243
Geoff Lang8040f572013-07-25 16:49:54 -04001244bool TextureCubeMap::isDepth(GLenum target, GLint level) const
1245{
1246 return GetDepthBits(getInternalFormat(target, level), mRenderer->getCurrentClientVersion()) > 0;
1247}
1248
daniel@transgaming.comf032cb82012-10-31 19:51:52 +00001249// Constructs a native texture resource from the texture images, or returns an existing one
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001250void TextureCubeMap::createTexture()
1251{
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001252 GLsizei size = mImageArray[0][0]->getWidth();
daniel@transgaming.come6a09842012-09-17 21:28:55 +00001253
1254 if (!(size > 0))
daniel@transgaming.comf032cb82012-10-31 19:51:52 +00001255 return; // do not attempt to create native textures for nonexistant data
daniel@transgaming.come6a09842012-09-17 21:28:55 +00001256
sminns@adobe.comce1189b2012-09-18 20:06:35 +00001257 GLint levels = creationLevels(size);
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001258 GLenum internalformat = mImageArray[0][0]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001259
1260 delete mTexStorage;
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001261 mTexStorage = new rx::TextureStorageInterfaceCube(mRenderer, levels, internalformat, mUsage, false, size);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001262
1263 if (mTexStorage->isManaged())
1264 {
1265 int levels = levelCount();
1266
1267 for (int face = 0; face < 6; face++)
1268 {
1269 for (int level = 0; level < levels; level++)
1270 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001271 mImageArray[face][level]->setManagedSurface(mTexStorage, face, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001272 }
1273 }
1274 }
1275
1276 mDirtyImages = true;
1277}
1278
1279void TextureCubeMap::updateTexture()
1280{
Jamie Madilleb3665c2013-07-19 16:36:57 -04001281 int levels = (isMipmapCubeComplete() ? levelCount() : 1);
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +00001282
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001283 for (int face = 0; face < 6; face++)
1284 {
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001285 for (int level = 0; level < levels; level++)
1286 {
Jamie Madill07edd442013-07-19 16:36:58 -04001287 updateTextureFaceLevel(face, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001288 }
1289 }
1290}
1291
Jamie Madill07edd442013-07-19 16:36:58 -04001292void TextureCubeMap::updateTextureFaceLevel(int face, int level)
1293{
1294 ASSERT(level >= 0 && face < 6 && level < (int)ArraySize(mImageArray[face]) && mImageArray[face][level] != NULL);
1295 rx::Image *image = mImageArray[face][level];
1296
1297 if (image->isDirty())
1298 {
1299 commitRect(face, level, 0, 0, image->getWidth(), image->getHeight());
1300 }
1301}
1302
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001303void TextureCubeMap::convertToRenderTarget()
1304{
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001305 rx::TextureStorageInterfaceCube *newTexStorage = NULL;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001306
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001307 if (mImageArray[0][0]->getWidth() != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001308 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001309 GLsizei size = mImageArray[0][0]->getWidth();
shannon.woods@transgaming.com6bb48862013-02-28 23:09:34 +00001310 GLint levels = mTexStorage != NULL ? mTexStorage->levelCount() : creationLevels(size);
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001311 GLenum internalformat = mImageArray[0][0]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001312
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001313 newTexStorage = new rx::TextureStorageInterfaceCube(mRenderer, levels, internalformat, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, true, size);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001314
1315 if (mTexStorage != NULL)
1316 {
daniel@transgaming.com1d80eee2012-11-28 19:33:31 +00001317 if (!mRenderer->copyToRenderTarget(newTexStorage, mTexStorage))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001318 {
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +00001319 delete newTexStorage;
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +00001320 return gl::error(GL_OUT_OF_MEMORY);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001321 }
1322 }
1323 }
1324
1325 delete mTexStorage;
1326 mTexStorage = newTexStorage;
1327
1328 mDirtyImages = true;
1329}
1330
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001331void TextureCubeMap::setImage(int faceIndex, GLint level, GLsizei width, GLsizei height, GLint internalFormat, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001332{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001333 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1334 GLint sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
1335 : GetSizedInternalFormat(format, type, clientVersion);
1336
1337 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001338
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001339 Texture::setImage(unpackAlignment, type, pixels, mImageArray[faceIndex][level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001340}
1341
1342unsigned int TextureCubeMap::faceIndex(GLenum face)
1343{
1344 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
1345 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
1346 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
1347 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
1348 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
1349
1350 return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
1351}
1352
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001353void TextureCubeMap::redefineImage(int face, GLint level, GLint internalformat, GLsizei width, GLsizei height)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001354{
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001355 // If there currently is a corresponding storage texture image, it has these parameters
1356 const int storageWidth = std::max(1, mImageArray[0][0]->getWidth() >> level);
1357 const int storageHeight = std::max(1, mImageArray[0][0]->getHeight() >> level);
1358 const int storageFormat = mImageArray[0][0]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001359
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001360 mImageArray[face][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, width, height, 1, false);
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001361
1362 if (mTexStorage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001363 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001364 const int storageLevels = mTexStorage->levelCount();
1365
1366 if ((level >= storageLevels && storageLevels != 0) ||
1367 width != storageWidth ||
1368 height != storageHeight ||
1369 internalformat != storageFormat) // Discard mismatched storage
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001370 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001371 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001372 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001373 for (int f = 0; f < 6; f++)
1374 {
1375 mImageArray[f][i]->markDirty();
1376 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001377 }
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001378
1379 delete mTexStorage;
1380 mTexStorage = NULL;
1381
1382 mDirtyImages = true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001383 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001384 }
1385}
1386
1387void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1388{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001389 unsigned int faceindex = faceIndex(target);
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001390 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1391 GLint sizedInternalFormat = IsSizedInternalFormat(format, clientVersion) ? format
1392 : GetSizedInternalFormat(format, GL_UNSIGNED_BYTE, clientVersion);
1393 redefineImage(faceindex, level, sizedInternalFormat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001394
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001395 if (!mImageArray[faceindex][level]->isRenderableFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001396 {
shannon.woods%transgaming.com@gtempaccount.come5dcce72013-04-13 03:44:33 +00001397 mImageArray[faceindex][level]->copy(0, 0, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001398 mDirtyImages = true;
1399 }
1400 else
1401 {
1402 if (!mTexStorage || !mTexStorage->isRenderTarget())
1403 {
1404 convertToRenderTarget();
1405 }
1406
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001407 mImageArray[faceindex][level]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001408
1409 ASSERT(width == height);
1410
1411 if (width > 0 && level < levelCount())
1412 {
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +00001413 gl::Rectangle sourceRect;
1414 sourceRect.x = x;
1415 sourceRect.width = width;
1416 sourceRect.y = y;
1417 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001418
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +00001419 mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001420 }
1421 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001422}
1423
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001424void 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 +00001425{
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001426 GLsizei size = mImageArray[faceIndex(target)][level]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001427
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001428 if (xoffset + width > size || yoffset + height > size || zoffset != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001429 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +00001430 return gl::error(GL_INVALID_VALUE);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001431 }
1432
Jamie Madill07edd442013-07-19 16:36:58 -04001433 unsigned int face = faceIndex(target);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001434
Jamie Madill07edd442013-07-19 16:36:58 -04001435 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
1436 // the current level we're copying to is defined (with appropriate format, width & height)
1437 bool canCreateRenderTarget = isFaceLevelComplete(face, level) && isFaceLevelComplete(face, 0);
1438
1439 if (!mImageArray[face][level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001440 {
Jamie Madill07edd442013-07-19 16:36:58 -04001441 mImageArray[face][level]->copy(0, 0, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001442 mDirtyImages = true;
1443 }
1444 else
1445 {
1446 if (!mTexStorage || !mTexStorage->isRenderTarget())
1447 {
1448 convertToRenderTarget();
1449 }
1450
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001451 if (level < levelCount())
1452 {
Jamie Madill07edd442013-07-19 16:36:58 -04001453 updateTextureFaceLevel(face, level);
1454
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001455 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1456
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +00001457 gl::Rectangle sourceRect;
1458 sourceRect.x = x;
1459 sourceRect.width = width;
1460 sourceRect.y = y;
1461 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001462
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001463 mRenderer->copyImage(source, sourceRect, gl::GetFormat(mImageArray[0][0]->getInternalFormat(), clientVersion),
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +00001464 xoffset, yoffset, mTexStorage, target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001465 }
1466 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001467}
1468
1469void TextureCubeMap::storage(GLsizei levels, GLenum internalformat, GLsizei size)
1470{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001471 delete mTexStorage;
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001472 mTexStorage = new rx::TextureStorageInterfaceCube(mRenderer, levels, internalformat, mUsage, false, size);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001473 mImmutable = true;
1474
1475 for (int level = 0; level < levels; level++)
1476 {
1477 for (int face = 0; face < 6; face++)
1478 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001479 mImageArray[face][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, size, size, 1, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001480 size = std::max(1, size >> 1);
1481 }
1482 }
1483
1484 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1485 {
1486 for (int face = 0; face < 6; face++)
1487 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001488 mImageArray[face][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, GL_NONE, 0, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001489 }
1490 }
1491
1492 if (mTexStorage->isManaged())
1493 {
1494 int levels = levelCount();
1495
1496 for (int face = 0; face < 6; face++)
1497 {
1498 for (int level = 0; level < levels; level++)
1499 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001500 mImageArray[face][level]->setManagedSurface(mTexStorage, face, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001501 }
1502 }
1503 }
1504}
1505
1506void TextureCubeMap::generateMipmaps()
1507{
1508 if (!isCubeComplete())
1509 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +00001510 return gl::error(GL_INVALID_OPERATION);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001511 }
1512
daniel@transgaming.comea32d482012-11-28 19:33:18 +00001513 if (!mRenderer->getNonPower2TextureSupport())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001514 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001515 if (!isPow2(mImageArray[0][0]->getWidth()))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001516 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +00001517 return gl::error(GL_INVALID_OPERATION);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001518 }
1519 }
1520
1521 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001522 unsigned int q = log2(mImageArray[0][0]->getWidth());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001523 for (unsigned int f = 0; f < 6; f++)
1524 {
1525 for (unsigned int i = 1; i <= q; i++)
1526 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001527 redefineImage(f, i, mImageArray[f][0]->getInternalFormat(),
shannon.woods@transgaming.com8a406682013-02-28 23:15:26 +00001528 std::max(mImageArray[f][0]->getWidth() >> i, 1),
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001529 std::max(mImageArray[f][0]->getWidth() >> i, 1));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001530 }
1531 }
1532
1533 if (mTexStorage && mTexStorage->isRenderTarget())
1534 {
1535 for (unsigned int f = 0; f < 6; f++)
1536 {
1537 for (unsigned int i = 1; i <= q; i++)
1538 {
daniel@transgaming.com0ad830b2012-10-31 19:52:12 +00001539 mTexStorage->generateMipmap(f, i);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001540
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001541 mImageArray[f][i]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001542 }
1543 }
1544 }
1545 else
1546 {
1547 for (unsigned int f = 0; f < 6; f++)
1548 {
1549 for (unsigned int i = 1; i <= q; i++)
1550 {
daniel@transgaming.com4ba24062012-12-20 20:54:24 +00001551 mRenderer->generateMipmap(mImageArray[f][i], mImageArray[f][i - 1]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001552 }
1553 }
1554 }
1555}
1556
Geoff Lang8040f572013-07-25 16:49:54 -04001557Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target, GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001558{
1559 if (!IsCubemapTextureTarget(target))
1560 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +00001561 return gl::error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001562 }
1563
1564 unsigned int face = faceIndex(target);
1565
Geoff Lang8040f572013-07-25 16:49:54 -04001566 Renderbuffer *renderBuffer = mRenderbufferProxies.get(level, face);
1567 if (!renderBuffer)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001568 {
Geoff Lang8040f572013-07-25 16:49:54 -04001569 renderBuffer = new Renderbuffer(mRenderer, id(), new RenderbufferTextureCubeMap(this, target, level));
1570 mRenderbufferProxies.add(level, face, renderBuffer);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001571 }
1572
Geoff Lang8040f572013-07-25 16:49:54 -04001573 return renderBuffer;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001574}
1575
Geoff Lang8040f572013-07-25 16:49:54 -04001576unsigned int TextureCubeMap::getRenderTargetSerial(GLenum faceTarget, GLint level)
1577{
1578 if (!mTexStorage || !mTexStorage->isRenderTarget())
1579 {
1580 convertToRenderTarget();
1581 }
1582
1583 return mTexStorage ? mTexStorage->getRenderTargetSerial(faceTarget, level) : 0;
1584}
1585
1586rx::RenderTarget *TextureCubeMap::getRenderTarget(GLenum target, GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001587{
1588 ASSERT(IsCubemapTextureTarget(target));
1589
1590 // ensure the underlying texture is created
1591 if (getStorage(true) == NULL)
1592 {
1593 return NULL;
1594 }
1595
1596 updateTexture();
Geoff Lang8040f572013-07-25 16:49:54 -04001597
1598 // ensure this is NOT a depth texture
1599 if (isDepth(target, level))
1600 {
1601 return NULL;
1602 }
1603
1604 return mTexStorage->getRenderTarget(target, level);
1605}
1606
1607rx::RenderTarget *TextureCubeMap::getDepthStencil(GLenum target, GLint level)
1608{
1609 ASSERT(IsCubemapTextureTarget(target));
1610
1611 // ensure the underlying texture is created
1612 if (getStorage(true) == NULL)
1613 {
1614 return NULL;
1615 }
1616
1617 updateTexture();
1618
1619 // ensure this is a depth texture
1620 if (!isDepth(target, level))
1621 {
1622 return NULL;
1623 }
1624
1625 return mTexStorage->getRenderTarget(target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001626}
1627
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +00001628int TextureCubeMap::levelCount()
1629{
1630 return mTexStorage ? mTexStorage->levelCount() - getLodOffset() : 0;
1631}
1632
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001633rx::TextureStorageInterface *TextureCubeMap::getStorage(bool renderTarget)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001634{
1635 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
1636 {
1637 if (renderTarget)
1638 {
1639 convertToRenderTarget();
1640 }
1641 else
1642 {
1643 createTexture();
1644 }
1645 }
1646
1647 return mTexStorage;
1648}
1649
Geoff Lang4907f2c2013-07-25 12:53:57 -04001650Texture3D::Texture3D(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_3D)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001651{
1652 mTexStorage = NULL;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001653
1654 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1655 {
1656 mImageArray[i] = renderer->createImage();
1657 }
1658}
1659
1660Texture3D::~Texture3D()
1661{
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001662 delete mTexStorage;
1663 mTexStorage = NULL;
1664
1665 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1666 {
1667 delete mImageArray[i];
1668 }
1669}
1670
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001671GLsizei Texture3D::getWidth(GLint level) const
1672{
1673 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getWidth() : 0;
1674}
1675
1676GLsizei Texture3D::getHeight(GLint level) const
1677{
1678 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getHeight() : 0;
1679}
1680
1681GLsizei Texture3D::getDepth(GLint level) const
1682{
1683 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getDepth() : 0;
1684}
1685
1686GLenum Texture3D::getInternalFormat(GLint level) const
1687{
1688 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getInternalFormat() : GL_NONE;
1689}
1690
1691GLenum Texture3D::getActualFormat(GLint level) const
1692{
1693 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getActualFormat() : D3DFMT_UNKNOWN;
1694}
1695
1696bool Texture3D::isCompressed(GLint level) const
1697{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001698 return IsFormatCompressed(getInternalFormat(level), mRenderer->getCurrentClientVersion());
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001699}
1700
1701bool Texture3D::isDepth(GLint level) const
1702{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001703 return GetDepthBits(getInternalFormat(level), mRenderer->getCurrentClientVersion()) > 0;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001704}
1705
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001706void Texture3D::setImage(GLint level, GLsizei width, GLsizei height, GLsizei depth, GLint internalFormat, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001707{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001708 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1709 GLint sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
1710 : GetSizedInternalFormat(format, type, clientVersion);
1711 redefineImage(level, sizedInternalFormat, width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001712
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001713 Texture::setImage(unpackAlignment, type, pixels, mImageArray[level]);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001714}
1715
1716void Texture3D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
1717{
1718 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1719 redefineImage(level, format, width, height, depth);
1720
1721 Texture::setCompressedImage(imageSize, pixels, mImageArray[level]);
1722}
1723
1724void 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)
1725{
1726 if (Texture::subImage(xoffset, yoffset, zoffset, width, height, depth, format, type, unpackAlignment, pixels, mImageArray[level]))
1727 {
1728 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1729 }
1730}
1731
1732void Texture3D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
1733{
1734 if (Texture::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth, format, imageSize, pixels, mImageArray[level]))
1735 {
1736 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1737 }
1738}
1739
1740void Texture3D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
1741{
1742 delete mTexStorage;
1743 mTexStorage = new rx::TextureStorageInterface3D(mRenderer, levels, internalformat, mUsage, width, height, depth);
1744 mImmutable = true;
1745
1746 for (int level = 0; level < levels; level++)
1747 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001748 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, true);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001749 width = std::max(1, width >> 1);
1750 height = std::max(1, height >> 1);
1751 depth = std::max(1, depth >> 1);
1752 }
1753
1754 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1755 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001756 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, GL_NONE, 0, 0, 0, true);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001757 }
1758
1759 if (mTexStorage->isManaged())
1760 {
1761 int levels = levelCount();
1762
1763 for (int level = 0; level < levels; level++)
1764 {
1765 mImageArray[level]->setManagedSurface(mTexStorage, level);
1766 }
1767 }
1768}
1769
1770
1771void Texture3D::generateMipmaps()
1772{
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001773 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1774 unsigned int q = log2(std::max(mImageArray[0]->getWidth(), mImageArray[0]->getHeight()));
1775 for (unsigned int i = 1; i <= q; i++)
1776 {
1777 redefineImage(i, mImageArray[0]->getInternalFormat(),
1778 std::max(mImageArray[0]->getWidth() >> i, 1),
1779 std::max(mImageArray[0]->getHeight() >> i, 1),
1780 std::max(mImageArray[0]->getDepth() >> i, 1));
1781 }
1782
1783 if (mTexStorage && mTexStorage->isRenderTarget())
1784 {
1785 for (unsigned int i = 1; i <= q; i++)
1786 {
1787 mTexStorage->generateMipmap(i);
1788
1789 mImageArray[i]->markClean();
1790 }
1791 }
1792 else
1793 {
1794 for (unsigned int i = 1; i <= q; i++)
1795 {
1796 mRenderer->generateMipmap(mImageArray[i], mImageArray[i - 1]);
1797 }
1798 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001799}
1800
1801void Texture3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1802{
1803 if (xoffset + width > mImageArray[level]->getWidth() || yoffset + height > mImageArray[level]->getHeight() || zoffset >= mImageArray[level]->getDepth())
1804 {
1805 return gl::error(GL_INVALID_VALUE);
1806 }
1807
Jamie Madill07edd442013-07-19 16:36:58 -04001808 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
1809 // the current level we're copying to is defined (with appropriate format, width & height)
1810 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
1811
1812 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001813 {
1814 mImageArray[level]->copy(xoffset, yoffset, zoffset, x, y, width, height, source);
1815 mDirtyImages = true;
1816 }
1817 else
1818 {
1819 if (!mTexStorage || !mTexStorage->isRenderTarget())
1820 {
1821 convertToRenderTarget();
1822 }
1823
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001824 if (level < levelCount())
1825 {
Jamie Madill07edd442013-07-19 16:36:58 -04001826 updateTextureLevel(level);
1827
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001828 gl::Rectangle sourceRect;
1829 sourceRect.x = x;
1830 sourceRect.width = width;
1831 sourceRect.y = y;
1832 sourceRect.height = height;
1833
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001834 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1835
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001836 mRenderer->copyImage(source, sourceRect,
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001837 gl::GetFormat(mImageArray[0]->getInternalFormat(), clientVersion),
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001838 xoffset, yoffset, zoffset, mTexStorage, level);
1839 }
1840 }
1841}
1842
Jamie Madillf8989902013-07-19 16:36:58 -04001843bool Texture3D::isSamplerComplete(const SamplerState &samplerState) const
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001844{
1845 GLsizei width = mImageArray[0]->getWidth();
1846 GLsizei height = mImageArray[0]->getHeight();
1847 GLsizei depth = mImageArray[0]->getDepth();
1848
1849 if (width <= 0 || height <= 0 || depth <= 0)
1850 {
1851 return false;
1852 }
1853
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001854 if (!IsTextureFilteringSupported(getInternalFormat(0), mRenderer))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001855 {
Jamie Madillf8989902013-07-19 16:36:58 -04001856 if (samplerState.magFilter != GL_NEAREST ||
1857 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001858 {
1859 return false;
1860 }
1861 }
1862
Jamie Madillf8989902013-07-19 16:36:58 -04001863 if (IsMipmapFiltered(samplerState) && !isMipmapComplete())
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001864 {
1865 return false;
1866 }
1867
1868 return true;
1869}
1870
1871bool Texture3D::isMipmapComplete() const
1872{
Jamie Madill07edd442013-07-19 16:36:58 -04001873 GLsizei width = mImageArray[0]->getWidth();
1874 GLsizei height = mImageArray[0]->getHeight();
1875 GLsizei depth = mImageArray[0]->getDepth();
1876
1877 int q = log2(std::max(std::max(width, height), depth));
1878
1879 for (int level = 0; level <= q; level++)
1880 {
1881 if (!isLevelComplete(level))
1882 {
1883 return false;
1884 }
1885 }
1886
1887 return true;
1888}
1889
1890bool Texture3D::isLevelComplete(int level) const
1891{
1892 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1893
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001894 if (isImmutable())
1895 {
1896 return true;
1897 }
1898
Jamie Madill07edd442013-07-19 16:36:58 -04001899 rx::Image *baseImage = mImageArray[0];
1900
1901 GLsizei width = baseImage->getWidth();
1902 GLsizei height = baseImage->getHeight();
1903 GLsizei depth = baseImage->getDepth();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001904
1905 if (width <= 0 || height <= 0 || depth <= 0)
1906 {
1907 return false;
1908 }
1909
Jamie Madill07edd442013-07-19 16:36:58 -04001910 if (level == 0)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001911 {
Jamie Madill07edd442013-07-19 16:36:58 -04001912 return true;
1913 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001914
Jamie Madill07edd442013-07-19 16:36:58 -04001915 rx::Image *levelImage = mImageArray[level];
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001916
Jamie Madill07edd442013-07-19 16:36:58 -04001917 if (levelImage->getInternalFormat() != baseImage->getInternalFormat())
1918 {
1919 return false;
1920 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001921
Jamie Madill07edd442013-07-19 16:36:58 -04001922 if (levelImage->getWidth() != std::max(1, width >> level))
1923 {
1924 return false;
1925 }
1926
1927 if (levelImage->getHeight() != std::max(1, height >> level))
1928 {
1929 return false;
1930 }
1931
1932 if (levelImage->getDepth() != std::max(1, depth >> level))
1933 {
1934 return false;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001935 }
1936
1937 return true;
1938}
1939
Geoff Lang8040f572013-07-25 16:49:54 -04001940Renderbuffer *Texture3D::getRenderbuffer(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001941{
Geoff Lang8040f572013-07-25 16:49:54 -04001942 Renderbuffer *renderBuffer = mRenderbufferProxies.get(level, layer);
1943 if (!renderBuffer)
1944 {
1945 UNIMPLEMENTED();
1946 //renderBuffer = new Renderbuffer(mRenderer, id(), new RenderbufferTexture3DLayer(this, level, layer));
1947 //mRenderbufferProxies.add(level, 0, renderBuffer);
1948 }
1949
1950 return renderBuffer;
1951}
1952
1953unsigned int Texture3D::getRenderTargetSerial(GLint level, GLint layer)
1954{
1955 if (!mTexStorage || !mTexStorage->isRenderTarget())
1956 {
1957 convertToRenderTarget();
1958 }
1959
1960 return mTexStorage ? mTexStorage->getRenderTargetSerial(level, layer) : 0;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001961}
1962
1963int Texture3D::levelCount()
1964{
1965 return mTexStorage ? mTexStorage->levelCount() : 0;
1966}
1967
1968void Texture3D::createTexture()
1969{
1970 GLsizei width = mImageArray[0]->getWidth();
1971 GLsizei height = mImageArray[0]->getHeight();
1972 GLsizei depth = mImageArray[0]->getDepth();
1973
1974 if (!(width > 0 && height > 0 && depth > 0))
1975 return; // do not attempt to create native textures for nonexistant data
1976
1977 GLint levels = creationLevels(width, height, depth);
1978 GLenum internalformat = mImageArray[0]->getInternalFormat();
1979
1980 delete mTexStorage;
1981 mTexStorage = new rx::TextureStorageInterface3D(mRenderer, levels, internalformat, mUsage, width, height, depth);
1982
1983 if (mTexStorage->isManaged())
1984 {
1985 int levels = levelCount();
1986
1987 for (int level = 0; level < levels; level++)
1988 {
1989 mImageArray[level]->setManagedSurface(mTexStorage, level);
1990 }
1991 }
1992
1993 mDirtyImages = true;
1994}
1995
1996void Texture3D::updateTexture()
1997{
Jamie Madilleb3665c2013-07-19 16:36:57 -04001998 int levels = (isMipmapComplete() ? levelCount() : 1);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001999
2000 for (int level = 0; level < levels; level++)
2001 {
Jamie Madill07edd442013-07-19 16:36:58 -04002002 updateTextureLevel(level);
2003 }
2004}
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002005
Jamie Madill07edd442013-07-19 16:36:58 -04002006void Texture3D::updateTextureLevel(int level)
2007{
2008 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
2009
2010 rx::Image *image = mImageArray[level];
2011
2012 if (image->isDirty())
2013 {
2014 commitRect(level, 0, 0, 0, mImageArray[level]->getWidth(), mImageArray[level]->getHeight(), mImageArray[level]->getDepth());
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002015 }
2016}
2017
2018void Texture3D::convertToRenderTarget()
2019{
2020 rx::TextureStorageInterface3D *newTexStorage = NULL;
2021
2022 if (mImageArray[0]->getWidth() != 0 && mImageArray[0]->getHeight() != 0 && mImageArray[0]->getDepth() != 0)
2023 {
2024 GLsizei width = mImageArray[0]->getWidth();
2025 GLsizei height = mImageArray[0]->getHeight();
2026 GLsizei depth = mImageArray[0]->getDepth();
2027 GLint levels = mTexStorage != NULL ? mTexStorage->levelCount() : creationLevels(width, height, depth);
2028 GLenum internalformat = mImageArray[0]->getInternalFormat();
2029
2030 newTexStorage = new rx::TextureStorageInterface3D(mRenderer, levels, internalformat, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, width, height, depth);
2031
2032 if (mTexStorage != NULL)
2033 {
2034 if (!mRenderer->copyToRenderTarget(newTexStorage, mTexStorage))
2035 {
2036 delete newTexStorage;
2037 return gl::error(GL_OUT_OF_MEMORY);
2038 }
2039 }
2040 }
2041
2042 delete mTexStorage;
2043 mTexStorage = newTexStorage;
2044
2045 mDirtyImages = true;
2046}
2047
Geoff Lang8040f572013-07-25 16:49:54 -04002048rx::RenderTarget *Texture3D::getRenderTarget(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002049{
Geoff Lang8040f572013-07-25 16:49:54 -04002050 // ensure the underlying texture is created
2051 if (getStorage(true) == NULL)
2052 {
2053 return NULL;
2054 }
2055
2056 updateTexture();
2057
2058 // ensure this is NOT a depth texture
2059 if (isDepth(level))
2060 {
2061 return NULL;
2062 }
2063
2064 return mTexStorage->getRenderTarget(level, layer);
2065}
2066
2067rx::RenderTarget *Texture3D::getDepthStencil(GLint level, GLint layer)
2068{
2069 // ensure the underlying texture is created
2070 if (getStorage(true) == NULL)
2071 {
2072 return NULL;
2073 }
2074
2075 updateTexture();
2076
2077 // ensure this is a depth texture
2078 if (!isDepth(level))
2079 {
2080 return NULL;
2081 }
2082
2083 return mTexStorage->getRenderTarget(level, layer);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002084}
2085
2086rx::TextureStorageInterface *Texture3D::getStorage(bool renderTarget)
2087{
2088 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
2089 {
2090 if (renderTarget)
2091 {
2092 convertToRenderTarget();
2093 }
2094 else
2095 {
2096 createTexture();
2097 }
2098 }
2099
2100 return mTexStorage;
2101}
2102
2103void Texture3D::redefineImage(GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth)
2104{
2105 // If there currently is a corresponding storage texture image, it has these parameters
2106 const int storageWidth = std::max(1, mImageArray[0]->getWidth() >> level);
2107 const int storageHeight = std::max(1, mImageArray[0]->getHeight() >> level);
2108 const int storageDepth = std::max(1, mImageArray[0]->getDepth() >> level);
2109 const int storageFormat = mImageArray[0]->getInternalFormat();
2110
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00002111 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, false);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002112
2113 if (mTexStorage)
2114 {
2115 const int storageLevels = mTexStorage->levelCount();
2116
2117 if ((level >= storageLevels && storageLevels != 0) ||
2118 width != storageWidth ||
2119 height != storageHeight ||
2120 depth != storageDepth ||
2121 internalformat != storageFormat) // Discard mismatched storage
2122 {
2123 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
2124 {
2125 mImageArray[i]->markDirty();
2126 }
2127
2128 delete mTexStorage;
2129 mTexStorage = NULL;
2130 mDirtyImages = true;
2131 }
2132 }
2133}
2134
2135void Texture3D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth)
2136{
2137 if (level < levelCount())
2138 {
2139 rx::Image *image = mImageArray[level];
2140 if (image->updateSurface(mTexStorage, level, xoffset, yoffset, zoffset, width, height, depth))
2141 {
2142 image->markClean();
2143 }
2144 }
2145}
2146
Geoff Lang4907f2c2013-07-25 12:53:57 -04002147Texture2DArray::Texture2DArray(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_2D_ARRAY)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002148{
2149 mTexStorage = NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002150
2151 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2152 {
2153 mLayerCounts[level] = 0;
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002154 mImageArray[level] = NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002155 }
2156}
2157
2158Texture2DArray::~Texture2DArray()
2159{
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002160 delete mTexStorage;
2161 mTexStorage = NULL;
2162 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2163 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002164 for (int layer = 0; layer < mLayerCounts[level]; ++layer)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002165 {
2166 delete mImageArray[level][layer];
2167 }
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002168 delete[] mImageArray[level];
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002169 }
2170}
2171
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002172GLsizei Texture2DArray::getWidth(GLint level) const
2173{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002174 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 +00002175}
2176
2177GLsizei Texture2DArray::getHeight(GLint level) const
2178{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002179 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 +00002180}
2181
2182GLsizei Texture2DArray::getDepth(GLint level) const
2183{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002184 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mLayerCounts[level] : 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002185}
2186
2187GLenum Texture2DArray::getInternalFormat(GLint level) const
2188{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002189 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 +00002190}
2191
2192GLenum Texture2DArray::getActualFormat(GLint level) const
2193{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002194 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 +00002195}
2196
2197bool Texture2DArray::isCompressed(GLint level) const
2198{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00002199 return IsFormatCompressed(getInternalFormat(level), mRenderer->getCurrentClientVersion());
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002200}
2201
2202bool Texture2DArray::isDepth(GLint level) const
2203{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00002204 return GetDepthBits(getInternalFormat(level), mRenderer->getCurrentClientVersion()) > 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002205}
2206
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00002207void Texture2DArray::setImage(GLint level, GLsizei width, GLsizei height, GLsizei depth, GLint internalFormat, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002208{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00002209 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2210 GLint sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
2211 : GetSizedInternalFormat(format, type, clientVersion);
2212 redefineImage(level, sizedInternalFormat, width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002213
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002214 GLsizei inputDepthPitch = gl::GetDepthPitch(sizedInternalFormat, type, clientVersion, width, height, unpackAlignment);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002215
2216 for (int i = 0; i < depth; i++)
2217 {
2218 const void *layerPixels = reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i);
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002219 Texture::setImage(unpackAlignment, type, layerPixels, mImageArray[level][i]);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002220 }
2221}
2222
2223void Texture2DArray::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
2224{
2225 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
2226 redefineImage(level, format, width, height, depth);
2227
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002228 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2229 GLsizei inputDepthPitch = gl::GetDepthPitch(format, GL_UNSIGNED_BYTE, clientVersion, width, height, 1);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002230
2231 for (int i = 0; i < depth; i++)
2232 {
2233 const void *layerPixels = reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i);
2234 Texture::setCompressedImage(imageSize, layerPixels, mImageArray[level][i]);
2235 }
2236}
2237
2238void 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)
2239{
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002240 GLint internalformat = getInternalFormat(level);
2241 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2242 GLsizei inputDepthPitch = gl::GetDepthPitch(internalformat, type, width, height, clientVersion, unpackAlignment);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002243
2244 for (int i = 0; i < depth; i++)
2245 {
2246 int layer = zoffset + i;
2247 const void *layerPixels = reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i);
2248
2249 if (Texture::subImage(xoffset, yoffset, zoffset, width, height, 1, format, type, unpackAlignment, layerPixels, mImageArray[level][layer]))
2250 {
2251 commitRect(level, xoffset, yoffset, layer, width, height);
2252 }
2253 }
2254}
2255
2256void Texture2DArray::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
2257{
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002258 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2259 GLsizei inputDepthPitch = gl::GetDepthPitch(format, GL_UNSIGNED_BYTE, clientVersion, width, height, 1);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002260
2261 for (int i = 0; i < depth; i++)
2262 {
2263 int layer = zoffset + i;
2264 const void *layerPixels = reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i);
2265
2266 if (Texture::subImageCompressed(xoffset, yoffset, zoffset, width, height, 1, format, imageSize, layerPixels, mImageArray[level][layer]))
2267 {
2268 commitRect(level, xoffset, yoffset, layer, width, height);
2269 }
2270 }
2271}
2272
2273void Texture2DArray::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2274{
2275 delete mTexStorage;
2276 mTexStorage = new rx::TextureStorageInterface2DArray(mRenderer, levels, internalformat, mUsage, width, height, depth);
2277 mImmutable = true;
2278
2279 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2280 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002281 GLsizei levelWidth = std::max(width >> level, 1);
2282 GLsizei levelHeight = std::max(width >> level, 1);
2283
2284 // Clear this level
2285 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002286 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002287 delete mImageArray[level][layer];
2288 }
2289 delete[] mImageArray[level];
2290 mImageArray[level] = NULL;
2291 mLayerCounts[level] = 0;
2292
2293 if (level < levels)
2294 {
2295 // Create new images for this level
2296 mImageArray[level] = new rx::Image*[depth]();
2297 mLayerCounts[level] = depth;
2298
2299 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002300 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002301 mImageArray[level][layer] = mRenderer->createImage();
2302 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, levelWidth,
2303 levelHeight, 1, true);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002304 }
2305 }
2306 }
2307
2308 if (mTexStorage->isManaged())
2309 {
2310 int levels = levelCount();
2311
2312 for (int level = 0; level < levels; level++)
2313 {
2314 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2315 {
2316 mImageArray[level][layer]->setManagedSurface(mTexStorage, layer, level);
2317 }
2318 }
2319 }
2320}
2321
2322void Texture2DArray::generateMipmaps()
2323{
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00002324 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
2325 int q = log2(std::max(getWidth(0), getHeight(0)));
2326 for (int i = 1; i <= q; i++)
2327 {
2328 redefineImage(i, getInternalFormat(0), std::max(getWidth(0) >> i, 1), std::max(getHeight(0) >> i, 1), getDepth(0));
2329 }
2330
2331 if (mTexStorage && mTexStorage->isRenderTarget())
2332 {
2333 for (int level = 1; level <= q; level++)
2334 {
2335 mTexStorage->generateMipmap(level);
2336
2337 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2338 {
2339 mImageArray[level][layer]->markClean();
2340 }
2341 }
2342 }
2343 else
2344 {
2345 for (int level = 1; level <= q; level++)
2346 {
2347 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2348 {
2349 mRenderer->generateMipmap(mImageArray[level][layer], mImageArray[level - 1][layer]);
2350 }
2351 }
2352 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002353}
2354
2355void Texture2DArray::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
2356{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002357 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 +00002358 {
2359 return gl::error(GL_INVALID_VALUE);
2360 }
2361
Jamie Madill07edd442013-07-19 16:36:58 -04002362 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
2363 // the current level we're copying to is defined (with appropriate format, width & height)
2364 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
2365
2366 if (!mImageArray[level][0]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002367 {
2368 mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, x, y, width, height, source);
2369 mDirtyImages = true;
2370 }
2371 else
2372 {
2373 if (!mTexStorage || !mTexStorage->isRenderTarget())
2374 {
2375 convertToRenderTarget();
2376 }
2377
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002378 if (level < levelCount())
2379 {
Jamie Madill07edd442013-07-19 16:36:58 -04002380 updateTextureLevel(level);
2381
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002382 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2383
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002384 gl::Rectangle sourceRect;
2385 sourceRect.x = x;
2386 sourceRect.width = width;
2387 sourceRect.y = y;
2388 sourceRect.height = height;
2389
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002390 mRenderer->copyImage(source, sourceRect, gl::GetFormat(getInternalFormat(0), clientVersion),
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002391 xoffset, yoffset, zoffset, mTexStorage, level);
2392 }
2393 }
2394}
2395
Jamie Madillf8989902013-07-19 16:36:58 -04002396bool Texture2DArray::isSamplerComplete(const SamplerState &samplerState) const
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002397{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002398 GLsizei width = getWidth(0);
2399 GLsizei height = getHeight(0);
2400 GLsizei depth = getDepth(0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002401
2402 if (width <= 0 || height <= 0 || depth <= 0)
2403 {
2404 return false;
2405 }
2406
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00002407 if (!IsTextureFilteringSupported(getInternalFormat(0), mRenderer))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002408 {
Jamie Madillf8989902013-07-19 16:36:58 -04002409 if (samplerState.magFilter != GL_NEAREST ||
2410 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002411 {
2412 return false;
2413 }
2414 }
2415
Jamie Madillf8989902013-07-19 16:36:58 -04002416 if (IsMipmapFiltered(samplerState) && !isMipmapComplete())
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002417 {
2418 return false;
2419 }
2420
2421 return true;
2422}
2423
2424bool Texture2DArray::isMipmapComplete() const
2425{
Jamie Madill07edd442013-07-19 16:36:58 -04002426 GLsizei width = getWidth(0);
2427 GLsizei height = getHeight(0);
2428
2429 int q = log2(std::max(width, height));
2430
2431 for (int level = 1; level <= q; level++)
2432 {
2433 if (!isLevelComplete(level))
2434 {
2435 return false;
2436 }
2437 }
2438
2439 return true;
2440}
2441
2442bool Texture2DArray::isLevelComplete(int level) const
2443{
2444 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
2445
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002446 if (isImmutable())
2447 {
2448 return true;
2449 }
2450
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002451 GLsizei width = getWidth(0);
2452 GLsizei height = getHeight(0);
2453 GLsizei depth = getDepth(0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002454
2455 if (width <= 0 || height <= 0 || depth <= 0)
2456 {
2457 return false;
2458 }
2459
Jamie Madill07edd442013-07-19 16:36:58 -04002460 if (level == 0)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002461 {
Jamie Madill07edd442013-07-19 16:36:58 -04002462 return true;
2463 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002464
Jamie Madill07edd442013-07-19 16:36:58 -04002465 if (getInternalFormat(level) != getInternalFormat(0))
2466 {
2467 return false;
2468 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002469
Jamie Madill07edd442013-07-19 16:36:58 -04002470 if (getWidth(level) != std::max(1, width >> level))
2471 {
2472 return false;
2473 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002474
Jamie Madill07edd442013-07-19 16:36:58 -04002475 if (getHeight(level) != std::max(1, height >> level))
2476 {
2477 return false;
2478 }
2479
2480 if (getDepth(level) != depth)
2481 {
2482 return false;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002483 }
2484
2485 return true;
2486}
2487
Geoff Lang8040f572013-07-25 16:49:54 -04002488Renderbuffer *Texture2DArray::getRenderbuffer(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002489{
Geoff Lang8040f572013-07-25 16:49:54 -04002490 Renderbuffer *renderBuffer = mRenderbufferProxies.get(level, layer);
2491 if (!renderBuffer)
2492 {
2493 UNIMPLEMENTED();
2494 //renderBuffer = new Renderbuffer(mRenderer, id(), new RenderbufferTexture2DArrayLayer(this, level, layer));
2495 //mRenderbufferProxies.add(level, 0, renderBuffer);
2496 }
2497
2498 return renderBuffer;
2499}
2500
2501unsigned int Texture2DArray::getRenderTargetSerial( GLint level, GLint layer )
2502{
2503 if (!mTexStorage || !mTexStorage->isRenderTarget())
2504 {
2505 convertToRenderTarget();
2506 }
2507
2508 return mTexStorage ? mTexStorage->getRenderTargetSerial(level, layer) : 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002509}
2510
2511int Texture2DArray::levelCount()
2512{
2513 return mTexStorage ? mTexStorage->levelCount() : 0;
2514}
2515
2516void Texture2DArray::createTexture()
2517{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002518 GLsizei width = getWidth(0);
2519 GLsizei height = getHeight(0);
2520 GLsizei depth = getDepth(0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002521
2522 if (width <= 0 || height <= 0 || depth <= 0)
2523 {
2524 return; // do not attempt to create native textures for nonexistant data
2525 }
2526
2527 GLint levels = creationLevels(width, height);
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002528 GLenum internalformat = getInternalFormat(0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002529
2530 delete mTexStorage;
2531 mTexStorage = new rx::TextureStorageInterface2DArray(mRenderer, levels, internalformat, mUsage, width, height, depth);
2532
2533 if (mTexStorage->isManaged())
2534 {
2535 int levels = levelCount();
2536 for (int level = 0; level < levels; level++)
2537 {
2538 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2539 {
2540 mImageArray[level][layer]->setManagedSurface(mTexStorage, layer, level);
2541 }
2542 }
2543 }
2544
2545 mDirtyImages = true;
2546}
2547
2548void Texture2DArray::updateTexture()
2549{
Jamie Madilleb3665c2013-07-19 16:36:57 -04002550 int levels = (isMipmapComplete() ? levelCount() : 1);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002551 for (int level = 0; level < levels; level++)
2552 {
Jamie Madill07edd442013-07-19 16:36:58 -04002553 updateTextureLevel(level);
2554 }
2555}
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002556
Jamie Madill07edd442013-07-19 16:36:58 -04002557void Texture2DArray::updateTextureLevel(int level)
2558{
2559 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2560 {
2561 rx::Image *image = mImageArray[level][layer];
2562
2563 if (image->isDirty())
2564 {
2565 commitRect(level, 0, 0, layer, image->getWidth(), image->getHeight());
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002566 }
2567 }
2568}
2569
2570void Texture2DArray::convertToRenderTarget()
2571{
2572 rx::TextureStorageInterface2DArray *newTexStorage = NULL;
2573
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002574 GLsizei width = getWidth(0);
2575 GLsizei height = getHeight(0);
2576 GLsizei depth = getDepth(0);
2577
2578 if (width != 0 && height != 0 && depth != 0)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002579 {
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002580 GLint levels = mTexStorage != NULL ? mTexStorage->levelCount() : creationLevels(width, height);
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002581 GLenum internalformat = getInternalFormat(0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002582
2583 newTexStorage = new rx::TextureStorageInterface2DArray(mRenderer, levels, internalformat, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, width, height, depth);
2584
2585 if (mTexStorage != NULL)
2586 {
2587 if (!mRenderer->copyToRenderTarget(newTexStorage, mTexStorage))
2588 {
2589 delete newTexStorage;
2590 return gl::error(GL_OUT_OF_MEMORY);
2591 }
2592 }
2593 }
2594
2595 delete mTexStorage;
2596 mTexStorage = newTexStorage;
2597
2598 mDirtyImages = true;
2599}
2600
Geoff Lang8040f572013-07-25 16:49:54 -04002601rx::RenderTarget *Texture2DArray::getRenderTarget(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002602{
Geoff Lang8040f572013-07-25 16:49:54 -04002603 // ensure the underlying texture is created
2604 if (getStorage(true) == NULL)
2605 {
2606 return NULL;
2607 }
2608
2609 updateTexture();
2610
2611 // ensure this is NOT a depth texture
2612 if (isDepth(level))
2613 {
2614 return NULL;
2615 }
2616
2617 return mTexStorage->getRenderTarget(level, layer);
2618}
2619
2620rx::RenderTarget *Texture2DArray::getDepthStencil(GLint level, GLint layer)
2621{
2622 // ensure the underlying texture is created
2623 if (getStorage(true) == NULL)
2624 {
2625 return NULL;
2626 }
2627
2628 updateTexture();
2629
2630 // ensure this is a depth texture
2631 if (!isDepth(level))
2632 {
2633 return NULL;
2634 }
2635
2636 return mTexStorage->getRenderTarget(level, layer);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002637}
2638
2639rx::TextureStorageInterface *Texture2DArray::getStorage(bool renderTarget)
2640{
2641 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
2642 {
2643 if (renderTarget)
2644 {
2645 convertToRenderTarget();
2646 }
2647 else
2648 {
2649 createTexture();
2650 }
2651 }
2652
2653 return mTexStorage;
2654}
2655
2656void Texture2DArray::redefineImage(GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth)
2657{
2658 // If there currently is a corresponding storage texture image, it has these parameters
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002659 const int storageWidth = std::max(1, getWidth(0) >> level);
2660 const int storageHeight = std::max(1, getHeight(0) >> level);
2661 const int storageDepth = getDepth(0);
2662 const int storageFormat = getInternalFormat(0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002663
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002664 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002665 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002666 delete mImageArray[level][layer];
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002667 }
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002668 delete[] mImageArray[level];
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002669
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002670 mImageArray[level] = new rx::Image*[depth]();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002671 mLayerCounts[level] = depth;
2672
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002673 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2674 {
2675 mImageArray[level][layer] = mRenderer->createImage();
2676 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, width, height, 1, false);
2677 }
2678
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002679 if (mTexStorage)
2680 {
2681 const int storageLevels = mTexStorage->levelCount();
2682
2683 if ((level >= storageLevels && storageLevels != 0) ||
2684 width != storageWidth ||
2685 height != storageHeight ||
2686 depth != storageDepth ||
2687 internalformat != storageFormat) // Discard mismatched storage
2688 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002689 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002690 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002691 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002692 {
2693 mImageArray[level][layer]->markDirty();
2694 }
2695 }
2696
2697 delete mTexStorage;
2698 mTexStorage = NULL;
2699 mDirtyImages = true;
2700 }
2701 }
2702}
2703
2704void Texture2DArray::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint layerTarget, GLsizei width, GLsizei height)
2705{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002706 if (level < levelCount() && layerTarget < getDepth(level))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002707 {
2708 rx::Image *image = mImageArray[level][layerTarget];
2709 if (image->updateSurface(mTexStorage, level, xoffset, yoffset, layerTarget, width, height))
2710 {
2711 image->markClean();
2712 }
2713 }
2714}
2715
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00002716}