blob: 929f8af45b17b4579ea64dbcab96e68c241839b2 [file] [log] [blame]
shannon.woods@transgaming.combdf2d802013-02-28 23:16:20 +00001#include "precompiled.h"
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00002//
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00003// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00004// Use of this source code is governed by a BSD-style license that can be
5// found in the LICENSE file.
6//
7
8// Texture.cpp: Implements the gl::Texture class and its derived classes
9// Texture2D and TextureCubeMap. Implements GL texture objects and related
10// functionality. [OpenGL ES 2.0.24] section 3.7 page 63.
11
12#include "libGLESv2/Texture.h"
13
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000014#include "libGLESv2/main.h"
15#include "libGLESv2/mathutil.h"
16#include "libGLESv2/utilities.h"
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +000017#include "libGLESv2/formatutils.h"
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +000018#include "libGLESv2/renderer/Blit.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
daniel@transgaming.com370482e2012-11-28 19:32:13 +000028Texture::Texture(rx::Renderer *renderer, GLuint id) : RefCountObject(id)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000029{
daniel@transgaming.com370482e2012-11-28 19:32:13 +000030 mRenderer = renderer;
31
daniel@transgaming.comebf139f2012-10-31 18:07:32 +000032 mSamplerState.minFilter = GL_NEAREST_MIPMAP_LINEAR;
33 mSamplerState.magFilter = GL_LINEAR;
34 mSamplerState.wrapS = GL_REPEAT;
35 mSamplerState.wrapT = GL_REPEAT;
shannon.woods%transgaming.com@gtempaccount.com0b3a8df2013-04-13 03:44:51 +000036 mSamplerState.wrapR = GL_REPEAT;
daniel@transgaming.comebf139f2012-10-31 18:07:32 +000037 mSamplerState.maxAnisotropy = 1.0f;
38 mSamplerState.lodOffset = 0;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000039 mUsage = GL_NONE;
40
41 mDirtyImages = true;
42
43 mImmutable = false;
44}
45
46Texture::~Texture()
47{
48}
49
50// Returns true on successful filter state update (valid enum parameter)
51bool Texture::setMinFilter(GLenum filter)
52{
53 switch (filter)
54 {
55 case GL_NEAREST:
56 case GL_LINEAR:
57 case GL_NEAREST_MIPMAP_NEAREST:
58 case GL_LINEAR_MIPMAP_NEAREST:
59 case GL_NEAREST_MIPMAP_LINEAR:
60 case GL_LINEAR_MIPMAP_LINEAR:
daniel@transgaming.com3c17ba62013-01-11 04:11:41 +000061 mSamplerState.minFilter = filter;
62 return true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000063 default:
64 return false;
65 }
66}
67
68// Returns true on successful filter state update (valid enum parameter)
69bool Texture::setMagFilter(GLenum filter)
70{
71 switch (filter)
72 {
73 case GL_NEAREST:
74 case GL_LINEAR:
daniel@transgaming.com3c17ba62013-01-11 04:11:41 +000075 mSamplerState.magFilter = filter;
76 return true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000077 default:
78 return false;
79 }
80}
81
82// Returns true on successful wrap state update (valid enum parameter)
83bool Texture::setWrapS(GLenum wrap)
84{
85 switch (wrap)
86 {
87 case GL_REPEAT:
88 case GL_CLAMP_TO_EDGE:
89 case GL_MIRRORED_REPEAT:
daniel@transgaming.com3c17ba62013-01-11 04:11:41 +000090 mSamplerState.wrapS = wrap;
91 return true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000092 default:
93 return false;
94 }
95}
96
97// Returns true on successful wrap state update (valid enum parameter)
98bool Texture::setWrapT(GLenum wrap)
99{
100 switch (wrap)
101 {
102 case GL_REPEAT:
103 case GL_CLAMP_TO_EDGE:
104 case GL_MIRRORED_REPEAT:
daniel@transgaming.com3c17ba62013-01-11 04:11:41 +0000105 mSamplerState.wrapT = wrap;
106 return true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000107 default:
108 return false;
109 }
110}
111
shannon.woods%transgaming.com@gtempaccount.com0b3a8df2013-04-13 03:44:51 +0000112// Returns true on successful wrap state update (valid enum parameter)
113bool Texture::setWrapR(GLenum wrap)
114{
115 switch (wrap)
116 {
117 case GL_REPEAT:
118 case GL_CLAMP_TO_EDGE:
119 case GL_MIRRORED_REPEAT:
120 mSamplerState.wrapR = wrap;
121 return true;
122 default:
123 return false;
124 }
125}
126
daniel@transgaming.com07ab8412012-07-12 15:17:09 +0000127// Returns true on successful max anisotropy update (valid anisotropy value)
128bool Texture::setMaxAnisotropy(float textureMaxAnisotropy, float contextMaxAnisotropy)
129{
130 textureMaxAnisotropy = std::min(textureMaxAnisotropy, contextMaxAnisotropy);
131 if (textureMaxAnisotropy < 1.0f)
132 {
133 return false;
134 }
daniel@transgaming.com3c17ba62013-01-11 04:11:41 +0000135
136 mSamplerState.maxAnisotropy = textureMaxAnisotropy;
137
daniel@transgaming.com07ab8412012-07-12 15:17:09 +0000138 return true;
139}
140
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000141// Returns true on successful usage state update (valid enum parameter)
142bool Texture::setUsage(GLenum usage)
143{
144 switch (usage)
145 {
146 case GL_NONE:
147 case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
148 mUsage = usage;
149 return true;
150 default:
151 return false;
152 }
153}
154
155GLenum Texture::getMinFilter() const
156{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000157 return mSamplerState.minFilter;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000158}
159
160GLenum Texture::getMagFilter() const
161{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000162 return mSamplerState.magFilter;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000163}
164
165GLenum Texture::getWrapS() const
166{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000167 return mSamplerState.wrapS;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000168}
169
170GLenum Texture::getWrapT() const
171{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000172 return mSamplerState.wrapT;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000173}
174
shannon.woods%transgaming.com@gtempaccount.com0b3a8df2013-04-13 03:44:51 +0000175GLenum Texture::getWrapR() const
176{
177 return mSamplerState.wrapR;
178}
179
daniel@transgaming.com07ab8412012-07-12 15:17:09 +0000180float Texture::getMaxAnisotropy() const
181{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000182 return mSamplerState.maxAnisotropy;
183}
184
185int Texture::getLodOffset()
186{
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000187 rx::TextureStorageInterface *texture = getStorage(false);
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000188 return texture ? texture->getLodOffset() : 0;
189}
190
191void Texture::getSamplerState(SamplerState *sampler)
192{
193 *sampler = mSamplerState;
194 sampler->lodOffset = getLodOffset();
daniel@transgaming.com07ab8412012-07-12 15:17:09 +0000195}
196
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000197GLenum Texture::getUsage() const
198{
199 return mUsage;
200}
201
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +0000202bool Texture::isMipmapFiltered() const
203{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000204 switch (mSamplerState.minFilter)
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +0000205 {
206 case GL_NEAREST:
207 case GL_LINEAR:
208 return false;
209 case GL_NEAREST_MIPMAP_NEAREST:
210 case GL_LINEAR_MIPMAP_NEAREST:
211 case GL_NEAREST_MIPMAP_LINEAR:
212 case GL_LINEAR_MIPMAP_LINEAR:
213 return true;
214 default: UNREACHABLE();
215 return false;
216 }
217}
218
daniel@transgaming.com31b13e12012-11-28 19:34:30 +0000219void Texture::setImage(GLint unpackAlignment, const void *pixels, rx::Image *image)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000220{
221 if (pixels != NULL)
222 {
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000223 image->loadData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), unpackAlignment, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000224 mDirtyImages = true;
225 }
226}
227
daniel@transgaming.com31b13e12012-11-28 19:34:30 +0000228void Texture::setCompressedImage(GLsizei imageSize, const void *pixels, rx::Image *image)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000229{
230 if (pixels != NULL)
231 {
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000232 image->loadCompressedData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000233 mDirtyImages = true;
234 }
235}
236
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000237bool Texture::subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
238 GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, rx::Image *image)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000239{
240 if (pixels != NULL)
241 {
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000242 image->loadData(xoffset, yoffset, zoffset, width, height, depth, unpackAlignment, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000243 mDirtyImages = true;
244 }
245
246 return true;
247}
248
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000249bool Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
250 GLenum format, GLsizei imageSize, const void *pixels, rx::Image *image)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000251{
252 if (pixels != NULL)
253 {
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000254 image->loadCompressedData(xoffset, yoffset, zoffset, width, height, depth, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000255 mDirtyImages = true;
256 }
257
258 return true;
259}
260
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000261rx::TextureStorageInterface *Texture::getNativeTexture()
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000262{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000263 // ensure the underlying texture is created
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000264
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000265 rx::TextureStorageInterface *storage = getStorage(false);
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000266 if (storage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000267 {
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000268 updateTexture();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000269 }
270
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000271 return storage;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000272}
273
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000274bool Texture::hasDirtyImages() const
275{
276 return mDirtyImages;
277}
278
279void Texture::resetDirty()
280{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000281 mDirtyImages = false;
282}
283
284unsigned int Texture::getTextureSerial()
285{
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000286 rx::TextureStorageInterface *texture = getStorage(false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000287 return texture ? texture->getTextureSerial() : 0;
288}
289
290unsigned int Texture::getRenderTargetSerial(GLenum target)
291{
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000292 rx::TextureStorageInterface *texture = getStorage(true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000293 return texture ? texture->getRenderTargetSerial(target) : 0;
294}
295
296bool Texture::isImmutable() const
297{
298 return mImmutable;
299}
300
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +0000301GLint Texture::creationLevels(GLsizei width, GLsizei height, GLsizei depth) const
302{
303 // NPOT checks are not required in ES 3.0, NPOT texture support is assumed.
304 return 0; // Maximum number of levels
305}
306
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000307GLint Texture::creationLevels(GLsizei width, GLsizei height) const
308{
daniel@transgaming.comea32d482012-11-28 19:33:18 +0000309 if ((isPow2(width) && isPow2(height)) || mRenderer->getNonPower2TextureSupport())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000310 {
311 return 0; // Maximum number of levels
312 }
313 else
314 {
315 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
316 return 1;
317 }
318}
319
320GLint Texture::creationLevels(GLsizei size) const
321{
322 return creationLevels(size, size);
323}
324
daniel@transgaming.com370482e2012-11-28 19:32:13 +0000325Texture2D::Texture2D(rx::Renderer *renderer, GLuint id) : Texture(renderer, id)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000326{
327 mTexStorage = NULL;
328 mSurface = NULL;
329 mColorbufferProxy = NULL;
330 mProxyRefs = 0;
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000331
332 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
333 {
daniel@transgaming.com244e1832012-12-20 20:52:35 +0000334 mImageArray[i] = renderer->createImage();
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000335 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000336}
337
338Texture2D::~Texture2D()
339{
340 mColorbufferProxy = NULL;
341
342 delete mTexStorage;
343 mTexStorage = NULL;
344
345 if (mSurface)
346 {
347 mSurface->setBoundTexture(NULL);
348 mSurface = NULL;
349 }
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000350
351 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
352 {
353 delete mImageArray[i];
354 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000355}
356
357// We need to maintain a count of references to renderbuffers acting as
358// proxies for this texture, so that we do not attempt to use a pointer
359// to a renderbuffer proxy which has been deleted.
360void Texture2D::addProxyRef(const Renderbuffer *proxy)
361{
362 mProxyRefs++;
363}
364
365void Texture2D::releaseProxy(const Renderbuffer *proxy)
366{
367 if (mProxyRefs > 0)
368 mProxyRefs--;
369
370 if (mProxyRefs == 0)
371 mColorbufferProxy = NULL;
372}
373
374GLenum Texture2D::getTarget() const
375{
376 return GL_TEXTURE_2D;
377}
378
379GLsizei Texture2D::getWidth(GLint level) const
380{
381 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000382 return mImageArray[level]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000383 else
384 return 0;
385}
386
387GLsizei Texture2D::getHeight(GLint level) const
388{
389 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000390 return mImageArray[level]->getHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000391 else
392 return 0;
393}
394
395GLenum Texture2D::getInternalFormat(GLint level) const
396{
397 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000398 return mImageArray[level]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000399 else
400 return GL_NONE;
401}
402
daniel@transgaming.com20d36662012-10-31 19:51:43 +0000403GLenum Texture2D::getActualFormat(GLint level) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000404{
405 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000406 return mImageArray[level]->getActualFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000407 else
408 return D3DFMT_UNKNOWN;
409}
410
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000411void Texture2D::redefineImage(GLint level, GLint internalformat, GLsizei width, GLsizei height)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000412{
413 releaseTexImage();
shannon.woods@transgaming.com8a406682013-02-28 23:15:26 +0000414
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000415 // If there currently is a corresponding storage texture image, it has these parameters
416 const int storageWidth = std::max(1, mImageArray[0]->getWidth() >> level);
417 const int storageHeight = std::max(1, mImageArray[0]->getHeight() >> level);
418 const int storageFormat = mImageArray[0]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000419
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000420 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, width, height, 1, false);
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000421
422 if (mTexStorage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000423 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000424 const int storageLevels = mTexStorage->levelCount();
425
426 if ((level >= storageLevels && storageLevels != 0) ||
427 width != storageWidth ||
428 height != storageHeight ||
429 internalformat != storageFormat) // Discard mismatched storage
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000430 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000431 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
432 {
433 mImageArray[i]->markDirty();
434 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000435
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000436 delete mTexStorage;
437 mTexStorage = NULL;
438 mDirtyImages = true;
439 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000440 }
441}
442
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +0000443void 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 +0000444{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +0000445 GLuint clientVersion = mRenderer->getCurrentClientVersion();
446 GLint sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
447 : GetSizedInternalFormat(format, type, clientVersion);
448 redefineImage(level, sizedInternalFormat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000449
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000450 Texture::setImage(unpackAlignment, pixels, mImageArray[level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000451}
452
453void Texture2D::bindTexImage(egl::Surface *surface)
454{
455 releaseTexImage();
456
daniel@transgaming.com106e1f72012-10-31 18:38:36 +0000457 GLint internalformat = surface->getFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000458
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000459 mImageArray[0]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, surface->getWidth(), surface->getHeight(), 1, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000460
461 delete mTexStorage;
daniel@transgaming.comd8353dd2012-12-20 21:11:14 +0000462 mTexStorage = new rx::TextureStorageInterface2D(mRenderer, surface->getSwapChain());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000463
464 mDirtyImages = true;
465 mSurface = surface;
466 mSurface->setBoundTexture(this);
467}
468
469void Texture2D::releaseTexImage()
470{
471 if (mSurface)
472 {
473 mSurface->setBoundTexture(NULL);
474 mSurface = NULL;
475
476 if (mTexStorage)
477 {
478 delete mTexStorage;
479 mTexStorage = NULL;
480 }
481
482 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
483 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000484 mImageArray[i]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000485 }
486 }
487}
488
489void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
490{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000491 // 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 +0000492 redefineImage(level, format, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000493
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000494 Texture::setCompressedImage(imageSize, pixels, mImageArray[level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000495}
496
497void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
498{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000499 if (level < levelCount())
500 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000501 rx::Image *image = mImageArray[level];
daniel@transgaming.com0f195ad2012-10-31 19:51:59 +0000502 if (image->updateSurface(mTexStorage, level, xoffset, yoffset, width, height))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000503 {
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000504 image->markClean();
505 }
506 }
507}
508
509void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
510{
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000511 if (Texture::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpackAlignment, pixels, mImageArray[level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000512 {
513 commitRect(level, xoffset, yoffset, width, height);
514 }
515}
516
517void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
518{
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000519 if (Texture::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000520 {
521 commitRect(level, xoffset, yoffset, width, height);
522 }
523}
524
525void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
526{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000527 GLint internalformat = ConvertSizedInternalFormat(format, GL_UNSIGNED_BYTE);
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000528 redefineImage(level, internalformat, width, height);
shannon.woods@transgaming.com8a406682013-02-28 23:15:26 +0000529
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000530 if (!mImageArray[level]->isRenderableFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000531 {
shannon.woods%transgaming.com@gtempaccount.come5dcce72013-04-13 03:44:33 +0000532 mImageArray[level]->copy(0, 0, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000533 mDirtyImages = true;
534 }
535 else
536 {
537 if (!mTexStorage || !mTexStorage->isRenderTarget())
538 {
539 convertToRenderTarget();
540 }
541
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000542 mImageArray[level]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000543
544 if (width != 0 && height != 0 && level < levelCount())
545 {
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +0000546 gl::Rectangle sourceRect;
547 sourceRect.x = x;
548 sourceRect.width = width;
549 sourceRect.y = y;
550 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000551
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +0000552 mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000553 }
554 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000555}
556
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +0000557void 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 +0000558{
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +0000559 if (xoffset + width > mImageArray[level]->getWidth() || yoffset + height > mImageArray[level]->getHeight() || zoffset != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000560 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +0000561 return gl::error(GL_INVALID_VALUE);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000562 }
563
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000564 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !isSamplerComplete()))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000565 {
shannon.woods%transgaming.com@gtempaccount.come5dcce72013-04-13 03:44:33 +0000566 mImageArray[level]->copy(xoffset, yoffset, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000567 mDirtyImages = true;
568 }
569 else
570 {
571 if (!mTexStorage || !mTexStorage->isRenderTarget())
572 {
573 convertToRenderTarget();
574 }
575
576 updateTexture();
577
578 if (level < levelCount())
579 {
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +0000580 gl::Rectangle sourceRect;
581 sourceRect.x = x;
582 sourceRect.width = width;
583 sourceRect.y = y;
584 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000585
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +0000586 mRenderer->copyImage(source, sourceRect,
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000587 gl::ExtractFormat(mImageArray[0]->getInternalFormat()),
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +0000588 xoffset, yoffset, mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000589 }
590 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000591}
592
593void Texture2D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height)
594{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000595 delete mTexStorage;
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000596 mTexStorage = new rx::TextureStorageInterface2D(mRenderer, levels, internalformat, mUsage, false, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000597 mImmutable = true;
598
599 for (int level = 0; level < levels; level++)
600 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000601 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, width, height, 1, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000602 width = std::max(1, width >> 1);
603 height = std::max(1, height >> 1);
604 }
605
606 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
607 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000608 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000609 }
610
611 if (mTexStorage->isManaged())
612 {
613 int levels = levelCount();
614
615 for (int level = 0; level < levels; level++)
616 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000617 mImageArray[level]->setManagedSurface(mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000618 }
619 }
620}
621
622// Tests for 2D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85.
623bool Texture2D::isSamplerComplete() const
624{
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000625 GLsizei width = mImageArray[0]->getWidth();
626 GLsizei height = mImageArray[0]->getHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000627
628 if (width <= 0 || height <= 0)
629 {
630 return false;
631 }
632
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +0000633 bool mipmapping = isMipmapFiltered();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000634
shannonwoods@chromium.org89200d92013-05-30 00:07:50 +0000635 if ((IsFloat32Format(getInternalFormat(0)) && !mRenderer->getFloat32TextureSupport()) ||
636 (IsFloat16Format(getInternalFormat(0)) && !mRenderer->getFloat16TextureSupport()))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000637 {
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000638 if (mSamplerState.magFilter != GL_NEAREST ||
639 (mSamplerState.minFilter != GL_NEAREST && mSamplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000640 {
641 return false;
642 }
643 }
644
daniel@transgaming.comea32d482012-11-28 19:33:18 +0000645 bool npotSupport = mRenderer->getNonPower2TextureSupport();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000646
647 if (!npotSupport)
648 {
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000649 if ((mSamplerState.wrapS != GL_CLAMP_TO_EDGE && !isPow2(width)) ||
650 (mSamplerState.wrapT != GL_CLAMP_TO_EDGE && !isPow2(height)))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000651 {
652 return false;
653 }
654 }
655
656 if (mipmapping)
657 {
658 if (!npotSupport)
659 {
660 if (!isPow2(width) || !isPow2(height))
661 {
662 return false;
663 }
664 }
665
666 if (!isMipmapComplete())
667 {
668 return false;
669 }
670 }
671
672 return true;
673}
674
675// Tests for 2D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
676bool Texture2D::isMipmapComplete() const
677{
678 if (isImmutable())
679 {
680 return true;
681 }
682
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000683 GLsizei width = mImageArray[0]->getWidth();
684 GLsizei height = mImageArray[0]->getHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000685
686 if (width <= 0 || height <= 0)
687 {
688 return false;
689 }
690
691 int q = log2(std::max(width, height));
692
693 for (int level = 1; level <= q; level++)
694 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000695 if (mImageArray[level]->getInternalFormat() != mImageArray[0]->getInternalFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000696 {
697 return false;
698 }
699
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000700 if (mImageArray[level]->getWidth() != std::max(1, width >> level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000701 {
702 return false;
703 }
704
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000705 if (mImageArray[level]->getHeight() != std::max(1, height >> level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000706 {
707 return false;
708 }
709 }
710
711 return true;
712}
713
714bool Texture2D::isCompressed(GLint level) const
715{
716 return IsCompressed(getInternalFormat(level));
717}
718
719bool Texture2D::isDepth(GLint level) const
720{
721 return IsDepthTexture(getInternalFormat(level));
722}
723
daniel@transgaming.comf032cb82012-10-31 19:51:52 +0000724// Constructs a native texture resource from the texture images
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000725void Texture2D::createTexture()
726{
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000727 GLsizei width = mImageArray[0]->getWidth();
728 GLsizei height = mImageArray[0]->getHeight();
daniel@transgaming.come6a09842012-09-17 21:28:55 +0000729
730 if (!(width > 0 && height > 0))
daniel@transgaming.comf032cb82012-10-31 19:51:52 +0000731 return; // do not attempt to create native textures for nonexistant data
daniel@transgaming.come6a09842012-09-17 21:28:55 +0000732
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000733 GLint levels = creationLevels(width, height);
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000734 GLenum internalformat = mImageArray[0]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000735
736 delete mTexStorage;
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000737 mTexStorage = new rx::TextureStorageInterface2D(mRenderer, levels, internalformat, mUsage, false, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000738
739 if (mTexStorage->isManaged())
740 {
741 int levels = levelCount();
742
743 for (int level = 0; level < levels; level++)
744 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000745 mImageArray[level]->setManagedSurface(mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000746 }
747 }
748
749 mDirtyImages = true;
750}
751
752void Texture2D::updateTexture()
753{
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +0000754 bool mipmapping = (isMipmapFiltered() && isMipmapComplete());
755
756 int levels = (mipmapping ? levelCount() : 1);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000757
758 for (int level = 0; level < levels; level++)
759 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000760 rx::Image *image = mImageArray[level];
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000761
762 if (image->isDirty())
763 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000764 commitRect(level, 0, 0, mImageArray[level]->getWidth(), mImageArray[level]->getHeight());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000765 }
766 }
767}
768
769void Texture2D::convertToRenderTarget()
770{
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000771 rx::TextureStorageInterface2D *newTexStorage = NULL;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000772
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000773 if (mImageArray[0]->getWidth() != 0 && mImageArray[0]->getHeight() != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000774 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000775 GLsizei width = mImageArray[0]->getWidth();
776 GLsizei height = mImageArray[0]->getHeight();
shannon.woods@transgaming.com6bb48862013-02-28 23:09:34 +0000777 GLint levels = mTexStorage != NULL ? mTexStorage->levelCount() : creationLevels(width, height);
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000778 GLenum internalformat = mImageArray[0]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000779
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000780 newTexStorage = new rx::TextureStorageInterface2D(mRenderer, levels, internalformat, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, true, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000781
782 if (mTexStorage != NULL)
783 {
daniel@transgaming.com1d80eee2012-11-28 19:33:31 +0000784 if (!mRenderer->copyToRenderTarget(newTexStorage, mTexStorage))
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +0000785 {
786 delete newTexStorage;
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +0000787 return gl::error(GL_OUT_OF_MEMORY);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000788 }
789 }
790 }
791
792 delete mTexStorage;
793 mTexStorage = newTexStorage;
794
795 mDirtyImages = true;
796}
797
798void Texture2D::generateMipmaps()
799{
daniel@transgaming.comea32d482012-11-28 19:33:18 +0000800 if (!mRenderer->getNonPower2TextureSupport())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000801 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000802 if (!isPow2(mImageArray[0]->getWidth()) || !isPow2(mImageArray[0]->getHeight()))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000803 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +0000804 return gl::error(GL_INVALID_OPERATION);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000805 }
806 }
807
808 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000809 unsigned int q = log2(std::max(mImageArray[0]->getWidth(), mImageArray[0]->getHeight()));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000810 for (unsigned int i = 1; i <= q; i++)
811 {
shannon.woods@transgaming.com8a406682013-02-28 23:15:26 +0000812 redefineImage(i, mImageArray[0]->getInternalFormat(),
813 std::max(mImageArray[0]->getWidth() >> i, 1),
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000814 std::max(mImageArray[0]->getHeight() >> i, 1));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000815 }
816
817 if (mTexStorage && mTexStorage->isRenderTarget())
818 {
819 for (unsigned int i = 1; i <= q; i++)
820 {
daniel@transgaming.com0ad830b2012-10-31 19:52:12 +0000821 mTexStorage->generateMipmap(i);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000822
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000823 mImageArray[i]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000824 }
825 }
826 else
827 {
828 for (unsigned int i = 1; i <= q; i++)
829 {
daniel@transgaming.com4ba24062012-12-20 20:54:24 +0000830 mRenderer->generateMipmap(mImageArray[i], mImageArray[i - 1]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000831 }
832 }
833}
834
835Renderbuffer *Texture2D::getRenderbuffer(GLenum target)
836{
837 if (target != GL_TEXTURE_2D)
838 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +0000839 return gl::error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000840 }
841
842 if (mColorbufferProxy == NULL)
843 {
daniel@transgaming.com70062c92012-11-28 19:32:30 +0000844 mColorbufferProxy = new Renderbuffer(mRenderer, id(), new RenderbufferTexture2D(this, target));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000845 }
846
847 return mColorbufferProxy;
848}
849
daniel@transgaming.comd186dc72012-11-28 19:40:16 +0000850rx::RenderTarget *Texture2D::getRenderTarget(GLenum target)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000851{
852 ASSERT(target == GL_TEXTURE_2D);
853
854 // ensure the underlying texture is created
855 if (getStorage(true) == NULL)
856 {
857 return NULL;
858 }
859
860 updateTexture();
861
862 // ensure this is NOT a depth texture
863 if (isDepth(0))
864 {
865 return NULL;
866 }
daniel@transgaming.com34da3972012-12-20 21:10:29 +0000867
daniel@transgaming.comd186dc72012-11-28 19:40:16 +0000868 return mTexStorage->getRenderTarget();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000869}
870
daniel@transgaming.comd186dc72012-11-28 19:40:16 +0000871rx::RenderTarget *Texture2D::getDepthStencil(GLenum target)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000872{
873 ASSERT(target == GL_TEXTURE_2D);
874
875 // ensure the underlying texture is created
876 if (getStorage(true) == NULL)
877 {
878 return NULL;
879 }
880
881 updateTexture();
882
883 // ensure this is actually a depth texture
884 if (!isDepth(0))
885 {
886 return NULL;
887 }
daniel@transgaming.comd186dc72012-11-28 19:40:16 +0000888 return mTexStorage->getRenderTarget();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000889}
890
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +0000891int Texture2D::levelCount()
892{
shannon.woods@transgaming.com5016f8e2013-02-28 23:20:57 +0000893 return mTexStorage ? mTexStorage->levelCount() : 0;
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +0000894}
895
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000896rx::TextureStorageInterface *Texture2D::getStorage(bool renderTarget)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000897{
898 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
899 {
900 if (renderTarget)
901 {
902 convertToRenderTarget();
903 }
904 else
905 {
906 createTexture();
907 }
908 }
909
910 return mTexStorage;
911}
912
daniel@transgaming.com370482e2012-11-28 19:32:13 +0000913TextureCubeMap::TextureCubeMap(rx::Renderer *renderer, GLuint id) : Texture(renderer, id)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000914{
915 mTexStorage = NULL;
916 for (int i = 0; i < 6; i++)
917 {
918 mFaceProxies[i] = NULL;
919 mFaceProxyRefs[i] = 0;
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000920
921 for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
922 {
daniel@transgaming.com244e1832012-12-20 20:52:35 +0000923 mImageArray[i][j] = renderer->createImage();
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000924 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000925 }
926}
927
928TextureCubeMap::~TextureCubeMap()
929{
930 for (int i = 0; i < 6; i++)
931 {
932 mFaceProxies[i] = NULL;
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000933
934 for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
935 {
936 delete mImageArray[i][j];
937 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000938 }
939
940 delete mTexStorage;
941 mTexStorage = NULL;
942}
943
944// We need to maintain a count of references to renderbuffers acting as
945// proxies for this texture, so that the texture is not deleted while
946// proxy references still exist. If the reference count drops to zero,
947// we set our proxy pointer NULL, so that a new attempt at referencing
948// will cause recreation.
949void TextureCubeMap::addProxyRef(const Renderbuffer *proxy)
950{
951 for (int i = 0; i < 6; i++)
952 {
953 if (mFaceProxies[i] == proxy)
954 mFaceProxyRefs[i]++;
955 }
956}
957
958void TextureCubeMap::releaseProxy(const Renderbuffer *proxy)
959{
960 for (int i = 0; i < 6; i++)
961 {
962 if (mFaceProxies[i] == proxy)
963 {
964 if (mFaceProxyRefs[i] > 0)
965 mFaceProxyRefs[i]--;
966
967 if (mFaceProxyRefs[i] == 0)
968 mFaceProxies[i] = NULL;
969 }
970 }
971}
972
973GLenum TextureCubeMap::getTarget() const
974{
975 return GL_TEXTURE_CUBE_MAP;
976}
977
978GLsizei TextureCubeMap::getWidth(GLenum target, GLint level) const
979{
980 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000981 return mImageArray[faceIndex(target)][level]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000982 else
983 return 0;
984}
985
986GLsizei TextureCubeMap::getHeight(GLenum target, GLint level) const
987{
988 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000989 return mImageArray[faceIndex(target)][level]->getHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000990 else
991 return 0;
992}
993
994GLenum TextureCubeMap::getInternalFormat(GLenum target, GLint level) const
995{
996 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000997 return mImageArray[faceIndex(target)][level]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000998 else
999 return GL_NONE;
1000}
1001
daniel@transgaming.com20d36662012-10-31 19:51:43 +00001002GLenum TextureCubeMap::getActualFormat(GLenum target, GLint level) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001003{
1004 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001005 return mImageArray[faceIndex(target)][level]->getActualFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001006 else
1007 return D3DFMT_UNKNOWN;
1008}
1009
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001010void 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 +00001011{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001012 setImage(0, level, width, height, internalFormat, format, type, unpackAlignment, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001013}
1014
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001015void 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 +00001016{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001017 setImage(1, level, width, height, internalFormat, format, type, unpackAlignment, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001018}
1019
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001020void 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 +00001021{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001022 setImage(2, level, width, height, internalFormat, format, type, unpackAlignment, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001023}
1024
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001025void 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 +00001026{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001027 setImage(3, level, width, height, internalFormat, format, type, unpackAlignment, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001028}
1029
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001030void 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 +00001031{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001032 setImage(4, level, width, height, internalFormat, format, type, unpackAlignment, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001033}
1034
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001035void 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 +00001036{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001037 setImage(5, level, width, height, internalFormat, format, type, unpackAlignment, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001038}
1039
1040void TextureCubeMap::setCompressedImage(GLenum face, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
1041{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001042 // 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 +00001043 redefineImage(faceIndex(face), level, format, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001044
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001045 Texture::setCompressedImage(imageSize, pixels, mImageArray[faceIndex(face)][level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001046}
1047
1048void TextureCubeMap::commitRect(int face, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1049{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001050 if (level < levelCount())
1051 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001052 rx::Image *image = mImageArray[face][level];
daniel@transgaming.com0f195ad2012-10-31 19:51:59 +00001053 if (image->updateSurface(mTexStorage, face, level, xoffset, yoffset, width, height))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001054 image->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001055 }
1056}
1057
1058void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1059{
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +00001060 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 +00001061 {
1062 commitRect(faceIndex(target), level, xoffset, yoffset, width, height);
1063 }
1064}
1065
1066void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1067{
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +00001068 if (Texture::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[faceIndex(target)][level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001069 {
1070 commitRect(faceIndex(target), level, xoffset, yoffset, width, height);
1071 }
1072}
1073
1074// Tests for cube map sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 86.
1075bool TextureCubeMap::isSamplerComplete() const
1076{
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001077 int size = mImageArray[0][0]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001078
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +00001079 bool mipmapping = isMipmapFiltered();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001080
shannonwoods@chromium.org89200d92013-05-30 00:07:50 +00001081 if ((gl::ExtractType(getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0)) == GL_FLOAT && !mRenderer->getFloat32TextureSupport()) ||
1082 (gl::ExtractType(getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0) == GL_HALF_FLOAT_OES) && !mRenderer->getFloat16TextureSupport()))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001083 {
daniel@transgaming.comebf139f2012-10-31 18:07:32 +00001084 if (mSamplerState.magFilter != GL_NEAREST ||
1085 (mSamplerState.minFilter != GL_NEAREST && mSamplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001086 {
1087 return false;
1088 }
1089 }
1090
daniel@transgaming.comea32d482012-11-28 19:33:18 +00001091 if (!isPow2(size) && !mRenderer->getNonPower2TextureSupport())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001092 {
daniel@transgaming.comebf139f2012-10-31 18:07:32 +00001093 if (mSamplerState.wrapS != GL_CLAMP_TO_EDGE || mSamplerState.wrapT != GL_CLAMP_TO_EDGE || mipmapping)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001094 {
1095 return false;
1096 }
1097 }
1098
1099 if (!mipmapping)
1100 {
1101 if (!isCubeComplete())
1102 {
1103 return false;
1104 }
1105 }
1106 else
1107 {
1108 if (!isMipmapCubeComplete()) // Also tests for isCubeComplete()
1109 {
1110 return false;
1111 }
1112 }
1113
1114 return true;
1115}
1116
1117// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1118bool TextureCubeMap::isCubeComplete() const
1119{
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001120 if (mImageArray[0][0]->getWidth() <= 0 || mImageArray[0][0]->getHeight() != mImageArray[0][0]->getWidth())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001121 {
1122 return false;
1123 }
1124
1125 for (unsigned int face = 1; face < 6; face++)
1126 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001127 if (mImageArray[face][0]->getWidth() != mImageArray[0][0]->getWidth() ||
1128 mImageArray[face][0]->getWidth() != mImageArray[0][0]->getHeight() ||
1129 mImageArray[face][0]->getInternalFormat() != mImageArray[0][0]->getInternalFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001130 {
1131 return false;
1132 }
1133 }
1134
1135 return true;
1136}
1137
1138bool TextureCubeMap::isMipmapCubeComplete() const
1139{
1140 if (isImmutable())
1141 {
1142 return true;
1143 }
1144
1145 if (!isCubeComplete())
1146 {
1147 return false;
1148 }
1149
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001150 GLsizei size = mImageArray[0][0]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001151
1152 int q = log2(size);
1153
1154 for (int face = 0; face < 6; face++)
1155 {
1156 for (int level = 1; level <= q; level++)
1157 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001158 if (mImageArray[face][level]->getInternalFormat() != mImageArray[0][0]->getInternalFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001159 {
1160 return false;
1161 }
1162
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001163 if (mImageArray[face][level]->getWidth() != std::max(1, size >> level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001164 {
1165 return false;
1166 }
1167 }
1168 }
1169
1170 return true;
1171}
1172
1173bool TextureCubeMap::isCompressed(GLenum target, GLint level) const
1174{
1175 return IsCompressed(getInternalFormat(target, level));
1176}
1177
daniel@transgaming.comf032cb82012-10-31 19:51:52 +00001178// Constructs a native texture resource from the texture images, or returns an existing one
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001179void TextureCubeMap::createTexture()
1180{
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001181 GLsizei size = mImageArray[0][0]->getWidth();
daniel@transgaming.come6a09842012-09-17 21:28:55 +00001182
1183 if (!(size > 0))
daniel@transgaming.comf032cb82012-10-31 19:51:52 +00001184 return; // do not attempt to create native textures for nonexistant data
daniel@transgaming.come6a09842012-09-17 21:28:55 +00001185
sminns@adobe.comce1189b2012-09-18 20:06:35 +00001186 GLint levels = creationLevels(size);
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001187 GLenum internalformat = mImageArray[0][0]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001188
1189 delete mTexStorage;
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001190 mTexStorage = new rx::TextureStorageInterfaceCube(mRenderer, levels, internalformat, mUsage, false, size);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001191
1192 if (mTexStorage->isManaged())
1193 {
1194 int levels = levelCount();
1195
1196 for (int face = 0; face < 6; face++)
1197 {
1198 for (int level = 0; level < levels; level++)
1199 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001200 mImageArray[face][level]->setManagedSurface(mTexStorage, face, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001201 }
1202 }
1203 }
1204
1205 mDirtyImages = true;
1206}
1207
1208void TextureCubeMap::updateTexture()
1209{
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +00001210 bool mipmapping = isMipmapFiltered() && isMipmapCubeComplete();
1211
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001212 for (int face = 0; face < 6; face++)
1213 {
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +00001214 int levels = (mipmapping ? levelCount() : 1);
1215
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001216 for (int level = 0; level < levels; level++)
1217 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001218 rx::Image *image = mImageArray[face][level];
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001219
1220 if (image->isDirty())
1221 {
1222 commitRect(face, level, 0, 0, image->getWidth(), image->getHeight());
1223 }
1224 }
1225 }
1226}
1227
1228void TextureCubeMap::convertToRenderTarget()
1229{
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001230 rx::TextureStorageInterfaceCube *newTexStorage = NULL;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001231
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001232 if (mImageArray[0][0]->getWidth() != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001233 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001234 GLsizei size = mImageArray[0][0]->getWidth();
shannon.woods@transgaming.com6bb48862013-02-28 23:09:34 +00001235 GLint levels = mTexStorage != NULL ? mTexStorage->levelCount() : creationLevels(size);
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001236 GLenum internalformat = mImageArray[0][0]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001237
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001238 newTexStorage = new rx::TextureStorageInterfaceCube(mRenderer, levels, internalformat, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, true, size);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001239
1240 if (mTexStorage != NULL)
1241 {
daniel@transgaming.com1d80eee2012-11-28 19:33:31 +00001242 if (!mRenderer->copyToRenderTarget(newTexStorage, mTexStorage))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001243 {
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +00001244 delete newTexStorage;
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +00001245 return gl::error(GL_OUT_OF_MEMORY);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001246 }
1247 }
1248 }
1249
1250 delete mTexStorage;
1251 mTexStorage = newTexStorage;
1252
1253 mDirtyImages = true;
1254}
1255
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001256void 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 +00001257{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001258 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1259 GLint sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
1260 : GetSizedInternalFormat(format, type, clientVersion);
1261
1262 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001263
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001264 Texture::setImage(unpackAlignment, pixels, mImageArray[faceIndex][level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001265}
1266
1267unsigned int TextureCubeMap::faceIndex(GLenum face)
1268{
1269 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
1270 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
1271 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
1272 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
1273 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
1274
1275 return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
1276}
1277
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001278void TextureCubeMap::redefineImage(int face, GLint level, GLint internalformat, GLsizei width, GLsizei height)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001279{
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001280 // If there currently is a corresponding storage texture image, it has these parameters
1281 const int storageWidth = std::max(1, mImageArray[0][0]->getWidth() >> level);
1282 const int storageHeight = std::max(1, mImageArray[0][0]->getHeight() >> level);
1283 const int storageFormat = mImageArray[0][0]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001284
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001285 mImageArray[face][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, width, height, 1, false);
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001286
1287 if (mTexStorage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001288 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001289 const int storageLevels = mTexStorage->levelCount();
1290
1291 if ((level >= storageLevels && storageLevels != 0) ||
1292 width != storageWidth ||
1293 height != storageHeight ||
1294 internalformat != storageFormat) // Discard mismatched storage
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001295 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001296 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001297 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001298 for (int f = 0; f < 6; f++)
1299 {
1300 mImageArray[f][i]->markDirty();
1301 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001302 }
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001303
1304 delete mTexStorage;
1305 mTexStorage = NULL;
1306
1307 mDirtyImages = true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001308 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001309 }
1310}
1311
1312void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1313{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001314 unsigned int faceindex = faceIndex(target);
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001315 GLint internalformat = gl::ConvertSizedInternalFormat(format, GL_UNSIGNED_BYTE);
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001316 redefineImage(faceindex, level, internalformat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001317
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001318 if (!mImageArray[faceindex][level]->isRenderableFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001319 {
shannon.woods%transgaming.com@gtempaccount.come5dcce72013-04-13 03:44:33 +00001320 mImageArray[faceindex][level]->copy(0, 0, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001321 mDirtyImages = true;
1322 }
1323 else
1324 {
1325 if (!mTexStorage || !mTexStorage->isRenderTarget())
1326 {
1327 convertToRenderTarget();
1328 }
1329
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001330 mImageArray[faceindex][level]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001331
1332 ASSERT(width == height);
1333
1334 if (width > 0 && level < levelCount())
1335 {
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +00001336 gl::Rectangle sourceRect;
1337 sourceRect.x = x;
1338 sourceRect.width = width;
1339 sourceRect.y = y;
1340 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001341
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +00001342 mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001343 }
1344 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001345}
1346
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001347void 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 +00001348{
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001349 GLsizei size = mImageArray[faceIndex(target)][level]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001350
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001351 if (xoffset + width > size || yoffset + height > size || zoffset != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001352 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +00001353 return gl::error(GL_INVALID_VALUE);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001354 }
1355
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001356 unsigned int faceindex = faceIndex(target);
1357
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001358 if (!mImageArray[faceindex][level]->isRenderableFormat() || (!mTexStorage && !isSamplerComplete()))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001359 {
shannon.woods%transgaming.com@gtempaccount.come5dcce72013-04-13 03:44:33 +00001360 mImageArray[faceindex][level]->copy(0, 0, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001361 mDirtyImages = true;
1362 }
1363 else
1364 {
1365 if (!mTexStorage || !mTexStorage->isRenderTarget())
1366 {
1367 convertToRenderTarget();
1368 }
1369
1370 updateTexture();
1371
1372 if (level < levelCount())
1373 {
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +00001374 gl::Rectangle sourceRect;
1375 sourceRect.x = x;
1376 sourceRect.width = width;
1377 sourceRect.y = y;
1378 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001379
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001380 mRenderer->copyImage(source, sourceRect, gl::ExtractFormat(mImageArray[0][0]->getInternalFormat()),
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +00001381 xoffset, yoffset, mTexStorage, target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001382 }
1383 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001384}
1385
1386void TextureCubeMap::storage(GLsizei levels, GLenum internalformat, GLsizei size)
1387{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001388 delete mTexStorage;
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001389 mTexStorage = new rx::TextureStorageInterfaceCube(mRenderer, levels, internalformat, mUsage, false, size);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001390 mImmutable = true;
1391
1392 for (int level = 0; level < levels; level++)
1393 {
1394 for (int face = 0; face < 6; face++)
1395 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001396 mImageArray[face][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, size, size, 1, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001397 size = std::max(1, size >> 1);
1398 }
1399 }
1400
1401 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1402 {
1403 for (int face = 0; face < 6; face++)
1404 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001405 mImageArray[face][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, GL_NONE, 0, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001406 }
1407 }
1408
1409 if (mTexStorage->isManaged())
1410 {
1411 int levels = levelCount();
1412
1413 for (int face = 0; face < 6; face++)
1414 {
1415 for (int level = 0; level < levels; level++)
1416 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001417 mImageArray[face][level]->setManagedSurface(mTexStorage, face, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001418 }
1419 }
1420 }
1421}
1422
1423void TextureCubeMap::generateMipmaps()
1424{
1425 if (!isCubeComplete())
1426 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +00001427 return gl::error(GL_INVALID_OPERATION);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001428 }
1429
daniel@transgaming.comea32d482012-11-28 19:33:18 +00001430 if (!mRenderer->getNonPower2TextureSupport())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001431 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001432 if (!isPow2(mImageArray[0][0]->getWidth()))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001433 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +00001434 return gl::error(GL_INVALID_OPERATION);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001435 }
1436 }
1437
1438 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001439 unsigned int q = log2(mImageArray[0][0]->getWidth());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001440 for (unsigned int f = 0; f < 6; f++)
1441 {
1442 for (unsigned int i = 1; i <= q; i++)
1443 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001444 redefineImage(f, i, mImageArray[f][0]->getInternalFormat(),
shannon.woods@transgaming.com8a406682013-02-28 23:15:26 +00001445 std::max(mImageArray[f][0]->getWidth() >> i, 1),
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001446 std::max(mImageArray[f][0]->getWidth() >> i, 1));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001447 }
1448 }
1449
1450 if (mTexStorage && mTexStorage->isRenderTarget())
1451 {
1452 for (unsigned int f = 0; f < 6; f++)
1453 {
1454 for (unsigned int i = 1; i <= q; i++)
1455 {
daniel@transgaming.com0ad830b2012-10-31 19:52:12 +00001456 mTexStorage->generateMipmap(f, i);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001457
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001458 mImageArray[f][i]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001459 }
1460 }
1461 }
1462 else
1463 {
1464 for (unsigned int f = 0; f < 6; f++)
1465 {
1466 for (unsigned int i = 1; i <= q; i++)
1467 {
daniel@transgaming.com4ba24062012-12-20 20:54:24 +00001468 mRenderer->generateMipmap(mImageArray[f][i], mImageArray[f][i - 1]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001469 }
1470 }
1471 }
1472}
1473
1474Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target)
1475{
1476 if (!IsCubemapTextureTarget(target))
1477 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +00001478 return gl::error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001479 }
1480
1481 unsigned int face = faceIndex(target);
1482
1483 if (mFaceProxies[face] == NULL)
1484 {
daniel@transgaming.com70062c92012-11-28 19:32:30 +00001485 mFaceProxies[face] = new Renderbuffer(mRenderer, id(), new RenderbufferTextureCubeMap(this, target));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001486 }
1487
1488 return mFaceProxies[face];
1489}
1490
daniel@transgaming.comd186dc72012-11-28 19:40:16 +00001491rx::RenderTarget *TextureCubeMap::getRenderTarget(GLenum target)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001492{
1493 ASSERT(IsCubemapTextureTarget(target));
1494
1495 // ensure the underlying texture is created
1496 if (getStorage(true) == NULL)
1497 {
1498 return NULL;
1499 }
1500
1501 updateTexture();
1502
daniel@transgaming.comd186dc72012-11-28 19:40:16 +00001503 return mTexStorage->getRenderTarget(target);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001504}
1505
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +00001506int TextureCubeMap::levelCount()
1507{
1508 return mTexStorage ? mTexStorage->levelCount() - getLodOffset() : 0;
1509}
1510
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001511rx::TextureStorageInterface *TextureCubeMap::getStorage(bool renderTarget)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001512{
1513 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
1514 {
1515 if (renderTarget)
1516 {
1517 convertToRenderTarget();
1518 }
1519 else
1520 {
1521 createTexture();
1522 }
1523 }
1524
1525 return mTexStorage;
1526}
1527
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001528Texture3D::Texture3D(rx::Renderer *renderer, GLuint id) : Texture(renderer, id)
1529{
1530 mTexStorage = NULL;
1531 mColorbufferProxy = NULL;
1532 mProxyRefs = 0;
1533
1534 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1535 {
1536 mImageArray[i] = renderer->createImage();
1537 }
1538}
1539
1540Texture3D::~Texture3D()
1541{
1542 mColorbufferProxy = NULL;
1543
1544 delete mTexStorage;
1545 mTexStorage = NULL;
1546
1547 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1548 {
1549 delete mImageArray[i];
1550 }
1551}
1552
1553void Texture3D::addProxyRef(const Renderbuffer *proxy)
1554{
1555 mProxyRefs++;
1556}
1557
1558void Texture3D::releaseProxy(const Renderbuffer *proxy)
1559{
1560 if (mProxyRefs > 0)
1561 mProxyRefs--;
1562
1563 if (mProxyRefs == 0)
1564 mColorbufferProxy = NULL;
1565}
1566
1567GLenum Texture3D::getTarget() const
1568{
1569 return GL_TEXTURE_3D;
1570}
1571
1572GLsizei Texture3D::getWidth(GLint level) const
1573{
1574 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getWidth() : 0;
1575}
1576
1577GLsizei Texture3D::getHeight(GLint level) const
1578{
1579 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getHeight() : 0;
1580}
1581
1582GLsizei Texture3D::getDepth(GLint level) const
1583{
1584 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getDepth() : 0;
1585}
1586
1587GLenum Texture3D::getInternalFormat(GLint level) const
1588{
1589 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getInternalFormat() : GL_NONE;
1590}
1591
1592GLenum Texture3D::getActualFormat(GLint level) const
1593{
1594 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getActualFormat() : D3DFMT_UNKNOWN;
1595}
1596
1597bool Texture3D::isCompressed(GLint level) const
1598{
1599 return IsCompressed(getInternalFormat(level));
1600}
1601
1602bool Texture3D::isDepth(GLint level) const
1603{
1604 return IsDepthTexture(getInternalFormat(level));
1605}
1606
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001607void 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 +00001608{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001609 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1610 GLint sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
1611 : GetSizedInternalFormat(format, type, clientVersion);
1612 redefineImage(level, sizedInternalFormat, width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001613
1614 Texture::setImage(unpackAlignment, pixels, mImageArray[level]);
1615}
1616
1617void Texture3D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
1618{
1619 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1620 redefineImage(level, format, width, height, depth);
1621
1622 Texture::setCompressedImage(imageSize, pixels, mImageArray[level]);
1623}
1624
1625void 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)
1626{
1627 if (Texture::subImage(xoffset, yoffset, zoffset, width, height, depth, format, type, unpackAlignment, pixels, mImageArray[level]))
1628 {
1629 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1630 }
1631}
1632
1633void Texture3D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
1634{
1635 if (Texture::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth, format, imageSize, pixels, mImageArray[level]))
1636 {
1637 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1638 }
1639}
1640
1641void Texture3D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
1642{
1643 delete mTexStorage;
1644 mTexStorage = new rx::TextureStorageInterface3D(mRenderer, levels, internalformat, mUsage, width, height, depth);
1645 mImmutable = true;
1646
1647 for (int level = 0; level < levels; level++)
1648 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001649 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, true);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001650 width = std::max(1, width >> 1);
1651 height = std::max(1, height >> 1);
1652 depth = std::max(1, depth >> 1);
1653 }
1654
1655 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1656 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001657 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, GL_NONE, 0, 0, 0, true);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001658 }
1659
1660 if (mTexStorage->isManaged())
1661 {
1662 int levels = levelCount();
1663
1664 for (int level = 0; level < levels; level++)
1665 {
1666 mImageArray[level]->setManagedSurface(mTexStorage, level);
1667 }
1668 }
1669}
1670
1671
1672void Texture3D::generateMipmaps()
1673{
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001674 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1675 unsigned int q = log2(std::max(mImageArray[0]->getWidth(), mImageArray[0]->getHeight()));
1676 for (unsigned int i = 1; i <= q; i++)
1677 {
1678 redefineImage(i, mImageArray[0]->getInternalFormat(),
1679 std::max(mImageArray[0]->getWidth() >> i, 1),
1680 std::max(mImageArray[0]->getHeight() >> i, 1),
1681 std::max(mImageArray[0]->getDepth() >> i, 1));
1682 }
1683
1684 if (mTexStorage && mTexStorage->isRenderTarget())
1685 {
1686 for (unsigned int i = 1; i <= q; i++)
1687 {
1688 mTexStorage->generateMipmap(i);
1689
1690 mImageArray[i]->markClean();
1691 }
1692 }
1693 else
1694 {
1695 for (unsigned int i = 1; i <= q; i++)
1696 {
1697 mRenderer->generateMipmap(mImageArray[i], mImageArray[i - 1]);
1698 }
1699 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001700}
1701
1702void Texture3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1703{
1704 if (xoffset + width > mImageArray[level]->getWidth() || yoffset + height > mImageArray[level]->getHeight() || zoffset >= mImageArray[level]->getDepth())
1705 {
1706 return gl::error(GL_INVALID_VALUE);
1707 }
1708
1709 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !isSamplerComplete()))
1710 {
1711 mImageArray[level]->copy(xoffset, yoffset, zoffset, x, y, width, height, source);
1712 mDirtyImages = true;
1713 }
1714 else
1715 {
1716 if (!mTexStorage || !mTexStorage->isRenderTarget())
1717 {
1718 convertToRenderTarget();
1719 }
1720
1721 updateTexture();
1722
1723 if (level < levelCount())
1724 {
1725 gl::Rectangle sourceRect;
1726 sourceRect.x = x;
1727 sourceRect.width = width;
1728 sourceRect.y = y;
1729 sourceRect.height = height;
1730
1731 mRenderer->copyImage(source, sourceRect,
1732 gl::ExtractFormat(mImageArray[0]->getInternalFormat()),
1733 xoffset, yoffset, zoffset, mTexStorage, level);
1734 }
1735 }
1736}
1737
1738bool Texture3D::isSamplerComplete() const
1739{
1740 GLsizei width = mImageArray[0]->getWidth();
1741 GLsizei height = mImageArray[0]->getHeight();
1742 GLsizei depth = mImageArray[0]->getDepth();
1743
1744 if (width <= 0 || height <= 0 || depth <= 0)
1745 {
1746 return false;
1747 }
1748
1749 bool mipmapping = isMipmapFiltered();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001750
shannonwoods@chromium.org89200d92013-05-30 00:07:50 +00001751 if ((IsFloat32Format(getInternalFormat(0)) && !mRenderer->getFloat32TextureSupport()) ||
1752 (IsFloat16Format(getInternalFormat(0)) && !mRenderer->getFloat16TextureSupport()))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001753 {
1754 if (mSamplerState.magFilter != GL_NEAREST ||
1755 (mSamplerState.minFilter != GL_NEAREST && mSamplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
1756 {
1757 return false;
1758 }
1759 }
1760
1761 if (mipmapping && !isMipmapComplete())
1762 {
1763 return false;
1764 }
1765
1766 return true;
1767}
1768
1769bool Texture3D::isMipmapComplete() const
1770{
1771 if (isImmutable())
1772 {
1773 return true;
1774 }
1775
1776 GLsizei width = mImageArray[0]->getWidth();
1777 GLsizei height = mImageArray[0]->getHeight();
1778 GLsizei depth = mImageArray[0]->getDepth();
1779
1780 if (width <= 0 || height <= 0 || depth <= 0)
1781 {
1782 return false;
1783 }
1784
1785 int q = log2(std::max(std::max(width, height), depth));
1786
1787 for (int level = 1; level <= q; level++)
1788 {
1789 if (mImageArray[level]->getInternalFormat() != mImageArray[0]->getInternalFormat())
1790 {
1791 return false;
1792 }
1793
1794 if (mImageArray[level]->getWidth() != std::max(1, width >> level))
1795 {
1796 return false;
1797 }
1798
1799 if (mImageArray[level]->getHeight() != std::max(1, height >> level))
1800 {
1801 return false;
1802 }
1803
1804 if (mImageArray[level]->getDepth() != std::max(1, depth >> level))
1805 {
1806 return false;
1807 }
1808 }
1809
1810 return true;
1811}
1812
1813Renderbuffer *Texture3D::getRenderbuffer(GLenum target)
1814{
1815 UNIMPLEMENTED();
1816 return NULL;
1817}
1818
1819int Texture3D::levelCount()
1820{
1821 return mTexStorage ? mTexStorage->levelCount() : 0;
1822}
1823
1824void Texture3D::createTexture()
1825{
1826 GLsizei width = mImageArray[0]->getWidth();
1827 GLsizei height = mImageArray[0]->getHeight();
1828 GLsizei depth = mImageArray[0]->getDepth();
1829
1830 if (!(width > 0 && height > 0 && depth > 0))
1831 return; // do not attempt to create native textures for nonexistant data
1832
1833 GLint levels = creationLevels(width, height, depth);
1834 GLenum internalformat = mImageArray[0]->getInternalFormat();
1835
1836 delete mTexStorage;
1837 mTexStorage = new rx::TextureStorageInterface3D(mRenderer, levels, internalformat, mUsage, width, height, depth);
1838
1839 if (mTexStorage->isManaged())
1840 {
1841 int levels = levelCount();
1842
1843 for (int level = 0; level < levels; level++)
1844 {
1845 mImageArray[level]->setManagedSurface(mTexStorage, level);
1846 }
1847 }
1848
1849 mDirtyImages = true;
1850}
1851
1852void Texture3D::updateTexture()
1853{
1854 bool mipmapping = (isMipmapFiltered() && isMipmapComplete());
1855
1856 int levels = (mipmapping ? levelCount() : 1);
1857
1858 for (int level = 0; level < levels; level++)
1859 {
1860 rx::Image *image = mImageArray[level];
1861
1862 if (image->isDirty())
1863 {
1864 commitRect(level, 0, 0, 0, mImageArray[level]->getWidth(), mImageArray[level]->getHeight(), mImageArray[level]->getDepth());
1865 }
1866 }
1867}
1868
1869void Texture3D::convertToRenderTarget()
1870{
1871 rx::TextureStorageInterface3D *newTexStorage = NULL;
1872
1873 if (mImageArray[0]->getWidth() != 0 && mImageArray[0]->getHeight() != 0 && mImageArray[0]->getDepth() != 0)
1874 {
1875 GLsizei width = mImageArray[0]->getWidth();
1876 GLsizei height = mImageArray[0]->getHeight();
1877 GLsizei depth = mImageArray[0]->getDepth();
1878 GLint levels = mTexStorage != NULL ? mTexStorage->levelCount() : creationLevels(width, height, depth);
1879 GLenum internalformat = mImageArray[0]->getInternalFormat();
1880
1881 newTexStorage = new rx::TextureStorageInterface3D(mRenderer, levels, internalformat, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, width, height, depth);
1882
1883 if (mTexStorage != NULL)
1884 {
1885 if (!mRenderer->copyToRenderTarget(newTexStorage, mTexStorage))
1886 {
1887 delete newTexStorage;
1888 return gl::error(GL_OUT_OF_MEMORY);
1889 }
1890 }
1891 }
1892
1893 delete mTexStorage;
1894 mTexStorage = newTexStorage;
1895
1896 mDirtyImages = true;
1897}
1898
1899rx::RenderTarget *Texture3D::getRenderTarget(GLenum target)
1900{
1901 UNIMPLEMENTED();
1902 return NULL;
1903}
1904
1905rx::TextureStorageInterface *Texture3D::getStorage(bool renderTarget)
1906{
1907 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
1908 {
1909 if (renderTarget)
1910 {
1911 convertToRenderTarget();
1912 }
1913 else
1914 {
1915 createTexture();
1916 }
1917 }
1918
1919 return mTexStorage;
1920}
1921
1922void Texture3D::redefineImage(GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth)
1923{
1924 // If there currently is a corresponding storage texture image, it has these parameters
1925 const int storageWidth = std::max(1, mImageArray[0]->getWidth() >> level);
1926 const int storageHeight = std::max(1, mImageArray[0]->getHeight() >> level);
1927 const int storageDepth = std::max(1, mImageArray[0]->getDepth() >> level);
1928 const int storageFormat = mImageArray[0]->getInternalFormat();
1929
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001930 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, false);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001931
1932 if (mTexStorage)
1933 {
1934 const int storageLevels = mTexStorage->levelCount();
1935
1936 if ((level >= storageLevels && storageLevels != 0) ||
1937 width != storageWidth ||
1938 height != storageHeight ||
1939 depth != storageDepth ||
1940 internalformat != storageFormat) // Discard mismatched storage
1941 {
1942 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1943 {
1944 mImageArray[i]->markDirty();
1945 }
1946
1947 delete mTexStorage;
1948 mTexStorage = NULL;
1949 mDirtyImages = true;
1950 }
1951 }
1952}
1953
1954void Texture3D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth)
1955{
1956 if (level < levelCount())
1957 {
1958 rx::Image *image = mImageArray[level];
1959 if (image->updateSurface(mTexStorage, level, xoffset, yoffset, zoffset, width, height, depth))
1960 {
1961 image->markClean();
1962 }
1963 }
1964}
1965
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00001966Texture2DArray::Texture2DArray(rx::Renderer *renderer, GLuint id) : Texture(renderer, id)
1967{
1968 mTexStorage = NULL;
1969 mColorbufferProxy = NULL;
1970 mProxyRefs = 0;
1971
1972 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
1973 {
1974 mLayerCounts[level] = 0;
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00001975 mImageArray[level] = NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00001976 }
1977}
1978
1979Texture2DArray::~Texture2DArray()
1980{
1981 mColorbufferProxy = NULL;
1982
1983 delete mTexStorage;
1984 mTexStorage = NULL;
1985 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
1986 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00001987 for (int layer = 0; layer < mLayerCounts[level]; ++layer)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00001988 {
1989 delete mImageArray[level][layer];
1990 }
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00001991 delete[] mImageArray[level];
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00001992 }
1993}
1994
1995void Texture2DArray::addProxyRef(const Renderbuffer *proxy)
1996{
1997 mProxyRefs++;
1998}
1999
2000void Texture2DArray::releaseProxy(const Renderbuffer *proxy)
2001{
2002 if (mProxyRefs > 0)
2003 mProxyRefs--;
2004
2005 if (mProxyRefs == 0)
2006 mColorbufferProxy = NULL;
2007}
2008
2009GLenum Texture2DArray::getTarget() const
2010{
2011 return GL_TEXTURE_2D_ARRAY;
2012}
2013
2014GLsizei Texture2DArray::getWidth(GLint level) const
2015{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002016 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getWidth() : 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002017}
2018
2019GLsizei Texture2DArray::getHeight(GLint level) const
2020{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002021 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 +00002022}
2023
2024GLsizei Texture2DArray::getDepth(GLint level) const
2025{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002026 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mLayerCounts[level] : 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002027}
2028
2029GLenum Texture2DArray::getInternalFormat(GLint level) const
2030{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002031 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getInternalFormat() : GL_NONE;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002032}
2033
2034GLenum Texture2DArray::getActualFormat(GLint level) const
2035{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002036 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 +00002037}
2038
2039bool Texture2DArray::isCompressed(GLint level) const
2040{
2041 return IsCompressed(getInternalFormat(level));
2042}
2043
2044bool Texture2DArray::isDepth(GLint level) const
2045{
2046 return IsDepthTexture(getInternalFormat(level));
2047}
2048
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00002049void 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 +00002050{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00002051 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2052 GLint sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
2053 : GetSizedInternalFormat(format, type, clientVersion);
2054 redefineImage(level, sizedInternalFormat, width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002055
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00002056 GLsizei inputDepthPitch = gl::ComputeDepthPitch(width, height, sizedInternalFormat, unpackAlignment);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002057
2058 for (int i = 0; i < depth; i++)
2059 {
2060 const void *layerPixels = reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i);
2061 Texture::setImage(unpackAlignment, layerPixels, mImageArray[level][i]);
2062 }
2063}
2064
2065void Texture2DArray::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
2066{
2067 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
2068 redefineImage(level, format, width, height, depth);
2069
2070 GLsizei inputDepthPitch = gl::ComputeCompressedDepthPitch(width, height, format);
2071
2072 for (int i = 0; i < depth; i++)
2073 {
2074 const void *layerPixels = reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i);
2075 Texture::setCompressedImage(imageSize, layerPixels, mImageArray[level][i]);
2076 }
2077}
2078
2079void 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)
2080{
2081 GLint internalformat = ConvertSizedInternalFormat(format, type);
2082 GLsizei inputDepthPitch = gl::ComputeDepthPitch(width, height, internalformat, unpackAlignment);
2083
2084 for (int i = 0; i < depth; i++)
2085 {
2086 int layer = zoffset + i;
2087 const void *layerPixels = reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i);
2088
2089 if (Texture::subImage(xoffset, yoffset, zoffset, width, height, 1, format, type, unpackAlignment, layerPixels, mImageArray[level][layer]))
2090 {
2091 commitRect(level, xoffset, yoffset, layer, width, height);
2092 }
2093 }
2094}
2095
2096void Texture2DArray::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
2097{
2098 GLsizei inputDepthPitch = gl::ComputeCompressedDepthPitch(width, height, format);
2099
2100 for (int i = 0; i < depth; i++)
2101 {
2102 int layer = zoffset + i;
2103 const void *layerPixels = reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i);
2104
2105 if (Texture::subImageCompressed(xoffset, yoffset, zoffset, width, height, 1, format, imageSize, layerPixels, mImageArray[level][layer]))
2106 {
2107 commitRect(level, xoffset, yoffset, layer, width, height);
2108 }
2109 }
2110}
2111
2112void Texture2DArray::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2113{
2114 delete mTexStorage;
2115 mTexStorage = new rx::TextureStorageInterface2DArray(mRenderer, levels, internalformat, mUsage, width, height, depth);
2116 mImmutable = true;
2117
2118 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2119 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002120 GLsizei levelWidth = std::max(width >> level, 1);
2121 GLsizei levelHeight = std::max(width >> level, 1);
2122
2123 // Clear this level
2124 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002125 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002126 delete mImageArray[level][layer];
2127 }
2128 delete[] mImageArray[level];
2129 mImageArray[level] = NULL;
2130 mLayerCounts[level] = 0;
2131
2132 if (level < levels)
2133 {
2134 // Create new images for this level
2135 mImageArray[level] = new rx::Image*[depth]();
2136 mLayerCounts[level] = depth;
2137
2138 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002139 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002140 mImageArray[level][layer] = mRenderer->createImage();
2141 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, levelWidth,
2142 levelHeight, 1, true);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002143 }
2144 }
2145 }
2146
2147 if (mTexStorage->isManaged())
2148 {
2149 int levels = levelCount();
2150
2151 for (int level = 0; level < levels; level++)
2152 {
2153 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2154 {
2155 mImageArray[level][layer]->setManagedSurface(mTexStorage, layer, level);
2156 }
2157 }
2158 }
2159}
2160
2161void Texture2DArray::generateMipmaps()
2162{
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00002163 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
2164 int q = log2(std::max(getWidth(0), getHeight(0)));
2165 for (int i = 1; i <= q; i++)
2166 {
2167 redefineImage(i, getInternalFormat(0), std::max(getWidth(0) >> i, 1), std::max(getHeight(0) >> i, 1), getDepth(0));
2168 }
2169
2170 if (mTexStorage && mTexStorage->isRenderTarget())
2171 {
2172 for (int level = 1; level <= q; level++)
2173 {
2174 mTexStorage->generateMipmap(level);
2175
2176 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2177 {
2178 mImageArray[level][layer]->markClean();
2179 }
2180 }
2181 }
2182 else
2183 {
2184 for (int level = 1; level <= q; level++)
2185 {
2186 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2187 {
2188 mRenderer->generateMipmap(mImageArray[level][layer], mImageArray[level - 1][layer]);
2189 }
2190 }
2191 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002192}
2193
2194void Texture2DArray::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
2195{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002196 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 +00002197 {
2198 return gl::error(GL_INVALID_VALUE);
2199 }
2200
2201 if (!mImageArray[level][0]->isRenderableFormat() || (!mTexStorage && !isSamplerComplete()))
2202 {
2203 mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, x, y, width, height, source);
2204 mDirtyImages = true;
2205 }
2206 else
2207 {
2208 if (!mTexStorage || !mTexStorage->isRenderTarget())
2209 {
2210 convertToRenderTarget();
2211 }
2212
2213 updateTexture();
2214
2215 if (level < levelCount())
2216 {
2217 gl::Rectangle sourceRect;
2218 sourceRect.x = x;
2219 sourceRect.width = width;
2220 sourceRect.y = y;
2221 sourceRect.height = height;
2222
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002223 mRenderer->copyImage(source, sourceRect, gl::ExtractFormat(getInternalFormat(0)),
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002224 xoffset, yoffset, zoffset, mTexStorage, level);
2225 }
2226 }
2227}
2228
2229bool Texture2DArray::isSamplerComplete() const
2230{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002231 GLsizei width = getWidth(0);
2232 GLsizei height = getHeight(0);
2233 GLsizei depth = getDepth(0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002234
2235 if (width <= 0 || height <= 0 || depth <= 0)
2236 {
2237 return false;
2238 }
2239
2240 bool mipmapping = isMipmapFiltered();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002241
shannonwoods@chromium.org89200d92013-05-30 00:07:50 +00002242 if ((IsFloat32Format(getInternalFormat(0)) && !mRenderer->getFloat32TextureSupport()) ||
2243 (IsFloat16Format(getInternalFormat(0)) && !mRenderer->getFloat16TextureSupport()))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002244 {
2245 if (mSamplerState.magFilter != GL_NEAREST ||
2246 (mSamplerState.minFilter != GL_NEAREST && mSamplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
2247 {
2248 return false;
2249 }
2250 }
2251
2252 if (mipmapping && !isMipmapComplete())
2253 {
2254 return false;
2255 }
2256
2257 return true;
2258}
2259
2260bool Texture2DArray::isMipmapComplete() const
2261{
2262 if (isImmutable())
2263 {
2264 return true;
2265 }
2266
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002267 GLsizei width = getWidth(0);
2268 GLsizei height = getHeight(0);
2269 GLsizei depth = getDepth(0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002270
2271 if (width <= 0 || height <= 0 || depth <= 0)
2272 {
2273 return false;
2274 }
2275
2276 int q = log2(std::max(width, height));
2277
2278 for (int level = 1; level <= q; level++)
2279 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002280 if (getInternalFormat(level) != getInternalFormat(0))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002281 {
2282 return false;
2283 }
2284
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002285 if (getWidth(level) != std::max(1, width >> level))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002286 {
2287 return false;
2288 }
2289
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002290 if (getHeight(level) != std::max(1, height >> level))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002291 {
2292 return false;
2293 }
2294
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002295 if (getDepth(level) != depth)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002296 {
2297 return false;
2298 }
2299 }
2300
2301 return true;
2302}
2303
2304Renderbuffer *Texture2DArray::getRenderbuffer(GLenum target)
2305{
2306 UNIMPLEMENTED();
2307 return NULL;
2308}
2309
2310int Texture2DArray::levelCount()
2311{
2312 return mTexStorage ? mTexStorage->levelCount() : 0;
2313}
2314
2315void Texture2DArray::createTexture()
2316{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002317 GLsizei width = getWidth(0);
2318 GLsizei height = getHeight(0);
2319 GLsizei depth = getDepth(0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002320
2321 if (width <= 0 || height <= 0 || depth <= 0)
2322 {
2323 return; // do not attempt to create native textures for nonexistant data
2324 }
2325
2326 GLint levels = creationLevels(width, height);
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002327 GLenum internalformat = getInternalFormat(0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002328
2329 delete mTexStorage;
2330 mTexStorage = new rx::TextureStorageInterface2DArray(mRenderer, levels, internalformat, mUsage, width, height, depth);
2331
2332 if (mTexStorage->isManaged())
2333 {
2334 int levels = levelCount();
2335 for (int level = 0; level < levels; level++)
2336 {
2337 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2338 {
2339 mImageArray[level][layer]->setManagedSurface(mTexStorage, layer, level);
2340 }
2341 }
2342 }
2343
2344 mDirtyImages = true;
2345}
2346
2347void Texture2DArray::updateTexture()
2348{
2349 bool mipmapping = (isMipmapFiltered() && isMipmapComplete());
2350
2351 int levels = (mipmapping ? levelCount() : 1);
2352 for (int level = 0; level < levels; level++)
2353 {
2354 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2355 {
2356 rx::Image *image = mImageArray[level][layer];
2357
2358 if (image->isDirty())
2359 {
2360 commitRect(level, 0, 0, layer, image->getWidth(), image->getHeight());
2361 }
2362 }
2363 }
2364}
2365
2366void Texture2DArray::convertToRenderTarget()
2367{
2368 rx::TextureStorageInterface2DArray *newTexStorage = NULL;
2369
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002370 GLsizei width = getWidth(0);
2371 GLsizei height = getHeight(0);
2372 GLsizei depth = getDepth(0);
2373
2374 if (width != 0 && height != 0 && depth != 0)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002375 {
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002376 GLint levels = mTexStorage != NULL ? mTexStorage->levelCount() : creationLevels(width, height);
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002377 GLenum internalformat = getInternalFormat(0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002378
2379 newTexStorage = new rx::TextureStorageInterface2DArray(mRenderer, levels, internalformat, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, width, height, depth);
2380
2381 if (mTexStorage != NULL)
2382 {
2383 if (!mRenderer->copyToRenderTarget(newTexStorage, mTexStorage))
2384 {
2385 delete newTexStorage;
2386 return gl::error(GL_OUT_OF_MEMORY);
2387 }
2388 }
2389 }
2390
2391 delete mTexStorage;
2392 mTexStorage = newTexStorage;
2393
2394 mDirtyImages = true;
2395}
2396
2397rx::RenderTarget *Texture2DArray::getRenderTarget(GLenum target)
2398{
2399 UNIMPLEMENTED();
2400 return NULL;
2401}
2402
2403rx::TextureStorageInterface *Texture2DArray::getStorage(bool renderTarget)
2404{
2405 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
2406 {
2407 if (renderTarget)
2408 {
2409 convertToRenderTarget();
2410 }
2411 else
2412 {
2413 createTexture();
2414 }
2415 }
2416
2417 return mTexStorage;
2418}
2419
2420void Texture2DArray::redefineImage(GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth)
2421{
2422 // If there currently is a corresponding storage texture image, it has these parameters
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002423 const int storageWidth = std::max(1, getWidth(0) >> level);
2424 const int storageHeight = std::max(1, getHeight(0) >> level);
2425 const int storageDepth = getDepth(0);
2426 const int storageFormat = getInternalFormat(0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002427
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002428 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002429 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002430 delete mImageArray[level][layer];
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002431 }
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002432 delete[] mImageArray[level];
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002433
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002434 mImageArray[level] = new rx::Image*[depth]();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002435 mLayerCounts[level] = depth;
2436
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002437 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2438 {
2439 mImageArray[level][layer] = mRenderer->createImage();
2440 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, width, height, 1, false);
2441 }
2442
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002443 if (mTexStorage)
2444 {
2445 const int storageLevels = mTexStorage->levelCount();
2446
2447 if ((level >= storageLevels && storageLevels != 0) ||
2448 width != storageWidth ||
2449 height != storageHeight ||
2450 depth != storageDepth ||
2451 internalformat != storageFormat) // Discard mismatched storage
2452 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002453 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002454 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002455 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002456 {
2457 mImageArray[level][layer]->markDirty();
2458 }
2459 }
2460
2461 delete mTexStorage;
2462 mTexStorage = NULL;
2463 mDirtyImages = true;
2464 }
2465 }
2466}
2467
2468void Texture2DArray::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint layerTarget, GLsizei width, GLsizei height)
2469{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002470 if (level < levelCount() && layerTarget < getDepth(level))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002471 {
2472 rx::Image *image = mImageArray[level][layerTarget];
2473 if (image->updateSurface(mTexStorage, level, xoffset, yoffset, layerTarget, width, height))
2474 {
2475 image->markClean();
2476 }
2477 }
2478}
2479
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00002480}