blob: d5811f21de1a4ff32a1cfb9b45bb4c30e610920f [file] [log] [blame]
shannon.woods@transgaming.combdf2d802013-02-28 23:16:20 +00001#include "precompiled.h"
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00002//
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00003// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00004// Use of this source code is governed by a BSD-style license that can be
5// found in the LICENSE file.
6//
7
8// Texture.cpp: Implements the gl::Texture class and its derived classes
9// Texture2D and TextureCubeMap. Implements GL texture objects and related
10// functionality. [OpenGL ES 2.0.24] section 3.7 page 63.
11
12#include "libGLESv2/Texture.h"
13
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000014#include "libGLESv2/main.h"
15#include "libGLESv2/mathutil.h"
16#include "libGLESv2/utilities.h"
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +000017#include "libGLESv2/renderer/Blit.h"
shannon.woods@transgaming.com486d9e92013-02-28 23:15:41 +000018#include "libGLESv2/Renderbuffer.h"
19#include "libGLESv2/renderer/Image.h"
20#include "libGLESv2/renderer/Renderer.h"
21#include "libGLESv2/renderer/TextureStorage.h"
22#include "libEGL/Surface.h"
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000023
24namespace gl
25{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000026
daniel@transgaming.com370482e2012-11-28 19:32:13 +000027Texture::Texture(rx::Renderer *renderer, GLuint id) : RefCountObject(id)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000028{
daniel@transgaming.com370482e2012-11-28 19:32:13 +000029 mRenderer = renderer;
30
daniel@transgaming.comebf139f2012-10-31 18:07:32 +000031 mSamplerState.minFilter = GL_NEAREST_MIPMAP_LINEAR;
32 mSamplerState.magFilter = GL_LINEAR;
33 mSamplerState.wrapS = GL_REPEAT;
34 mSamplerState.wrapT = GL_REPEAT;
35 mSamplerState.maxAnisotropy = 1.0f;
36 mSamplerState.lodOffset = 0;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000037 mUsage = GL_NONE;
38
39 mDirtyImages = true;
40
41 mImmutable = false;
42}
43
44Texture::~Texture()
45{
46}
47
48// Returns true on successful filter state update (valid enum parameter)
49bool Texture::setMinFilter(GLenum filter)
50{
51 switch (filter)
52 {
53 case GL_NEAREST:
54 case GL_LINEAR:
55 case GL_NEAREST_MIPMAP_NEAREST:
56 case GL_LINEAR_MIPMAP_NEAREST:
57 case GL_NEAREST_MIPMAP_LINEAR:
58 case GL_LINEAR_MIPMAP_LINEAR:
daniel@transgaming.com3c17ba62013-01-11 04:11:41 +000059 mSamplerState.minFilter = filter;
60 return true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000061 default:
62 return false;
63 }
64}
65
66// Returns true on successful filter state update (valid enum parameter)
67bool Texture::setMagFilter(GLenum filter)
68{
69 switch (filter)
70 {
71 case GL_NEAREST:
72 case GL_LINEAR:
daniel@transgaming.com3c17ba62013-01-11 04:11:41 +000073 mSamplerState.magFilter = filter;
74 return true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000075 default:
76 return false;
77 }
78}
79
80// Returns true on successful wrap state update (valid enum parameter)
81bool Texture::setWrapS(GLenum wrap)
82{
83 switch (wrap)
84 {
85 case GL_REPEAT:
86 case GL_CLAMP_TO_EDGE:
87 case GL_MIRRORED_REPEAT:
daniel@transgaming.com3c17ba62013-01-11 04:11:41 +000088 mSamplerState.wrapS = wrap;
89 return true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000090 default:
91 return false;
92 }
93}
94
95// Returns true on successful wrap state update (valid enum parameter)
96bool Texture::setWrapT(GLenum wrap)
97{
98 switch (wrap)
99 {
100 case GL_REPEAT:
101 case GL_CLAMP_TO_EDGE:
102 case GL_MIRRORED_REPEAT:
daniel@transgaming.com3c17ba62013-01-11 04:11:41 +0000103 mSamplerState.wrapT = wrap;
104 return true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000105 default:
106 return false;
107 }
108}
109
daniel@transgaming.com07ab8412012-07-12 15:17:09 +0000110// Returns true on successful max anisotropy update (valid anisotropy value)
111bool Texture::setMaxAnisotropy(float textureMaxAnisotropy, float contextMaxAnisotropy)
112{
113 textureMaxAnisotropy = std::min(textureMaxAnisotropy, contextMaxAnisotropy);
114 if (textureMaxAnisotropy < 1.0f)
115 {
116 return false;
117 }
daniel@transgaming.com3c17ba62013-01-11 04:11:41 +0000118
119 mSamplerState.maxAnisotropy = textureMaxAnisotropy;
120
daniel@transgaming.com07ab8412012-07-12 15:17:09 +0000121 return true;
122}
123
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000124// Returns true on successful usage state update (valid enum parameter)
125bool Texture::setUsage(GLenum usage)
126{
127 switch (usage)
128 {
129 case GL_NONE:
130 case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
131 mUsage = usage;
132 return true;
133 default:
134 return false;
135 }
136}
137
138GLenum Texture::getMinFilter() const
139{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000140 return mSamplerState.minFilter;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000141}
142
143GLenum Texture::getMagFilter() const
144{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000145 return mSamplerState.magFilter;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000146}
147
148GLenum Texture::getWrapS() const
149{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000150 return mSamplerState.wrapS;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000151}
152
153GLenum Texture::getWrapT() const
154{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000155 return mSamplerState.wrapT;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000156}
157
daniel@transgaming.com07ab8412012-07-12 15:17:09 +0000158float Texture::getMaxAnisotropy() const
159{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000160 return mSamplerState.maxAnisotropy;
161}
162
163int Texture::getLodOffset()
164{
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000165 rx::TextureStorageInterface *texture = getStorage(false);
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000166 return texture ? texture->getLodOffset() : 0;
167}
168
169void Texture::getSamplerState(SamplerState *sampler)
170{
171 *sampler = mSamplerState;
172 sampler->lodOffset = getLodOffset();
daniel@transgaming.com07ab8412012-07-12 15:17:09 +0000173}
174
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000175GLenum Texture::getUsage() const
176{
177 return mUsage;
178}
179
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +0000180bool Texture::isMipmapFiltered() const
181{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000182 switch (mSamplerState.minFilter)
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +0000183 {
184 case GL_NEAREST:
185 case GL_LINEAR:
186 return false;
187 case GL_NEAREST_MIPMAP_NEAREST:
188 case GL_LINEAR_MIPMAP_NEAREST:
189 case GL_NEAREST_MIPMAP_LINEAR:
190 case GL_LINEAR_MIPMAP_LINEAR:
191 return true;
192 default: UNREACHABLE();
193 return false;
194 }
195}
196
daniel@transgaming.com31b13e12012-11-28 19:34:30 +0000197void Texture::setImage(GLint unpackAlignment, const void *pixels, rx::Image *image)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000198{
199 if (pixels != NULL)
200 {
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000201 image->loadData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), unpackAlignment, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000202 mDirtyImages = true;
203 }
204}
205
daniel@transgaming.com31b13e12012-11-28 19:34:30 +0000206void Texture::setCompressedImage(GLsizei imageSize, const void *pixels, rx::Image *image)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000207{
208 if (pixels != NULL)
209 {
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000210 image->loadCompressedData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000211 mDirtyImages = true;
212 }
213}
214
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000215bool Texture::subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
216 GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, rx::Image *image)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000217{
218 if (pixels != NULL)
219 {
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000220 image->loadData(xoffset, yoffset, zoffset, width, height, depth, unpackAlignment, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000221 mDirtyImages = true;
222 }
223
224 return true;
225}
226
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000227bool Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
228 GLenum format, 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(xoffset, yoffset, zoffset, width, height, depth, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000233 mDirtyImages = true;
234 }
235
236 return true;
237}
238
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000239rx::TextureStorageInterface *Texture::getNativeTexture()
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000240{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000241 // ensure the underlying texture is created
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000242
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000243 rx::TextureStorageInterface *storage = getStorage(false);
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000244 if (storage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000245 {
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000246 updateTexture();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000247 }
248
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000249 return storage;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000250}
251
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000252bool Texture::hasDirtyImages() const
253{
254 return mDirtyImages;
255}
256
257void Texture::resetDirty()
258{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000259 mDirtyImages = false;
260}
261
262unsigned int Texture::getTextureSerial()
263{
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000264 rx::TextureStorageInterface *texture = getStorage(false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000265 return texture ? texture->getTextureSerial() : 0;
266}
267
268unsigned int Texture::getRenderTargetSerial(GLenum target)
269{
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000270 rx::TextureStorageInterface *texture = getStorage(true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000271 return texture ? texture->getRenderTargetSerial(target) : 0;
272}
273
274bool Texture::isImmutable() const
275{
276 return mImmutable;
277}
278
279GLint Texture::creationLevels(GLsizei width, GLsizei height) const
280{
daniel@transgaming.comea32d482012-11-28 19:33:18 +0000281 if ((isPow2(width) && isPow2(height)) || mRenderer->getNonPower2TextureSupport())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000282 {
283 return 0; // Maximum number of levels
284 }
285 else
286 {
287 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
288 return 1;
289 }
290}
291
292GLint Texture::creationLevels(GLsizei size) const
293{
294 return creationLevels(size, size);
295}
296
daniel@transgaming.com370482e2012-11-28 19:32:13 +0000297Texture2D::Texture2D(rx::Renderer *renderer, GLuint id) : Texture(renderer, id)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000298{
299 mTexStorage = NULL;
300 mSurface = NULL;
301 mColorbufferProxy = NULL;
302 mProxyRefs = 0;
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000303
304 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
305 {
daniel@transgaming.com244e1832012-12-20 20:52:35 +0000306 mImageArray[i] = renderer->createImage();
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000307 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000308}
309
310Texture2D::~Texture2D()
311{
312 mColorbufferProxy = NULL;
313
314 delete mTexStorage;
315 mTexStorage = NULL;
316
317 if (mSurface)
318 {
319 mSurface->setBoundTexture(NULL);
320 mSurface = NULL;
321 }
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000322
323 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
324 {
325 delete mImageArray[i];
326 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000327}
328
329// We need to maintain a count of references to renderbuffers acting as
330// proxies for this texture, so that we do not attempt to use a pointer
331// to a renderbuffer proxy which has been deleted.
332void Texture2D::addProxyRef(const Renderbuffer *proxy)
333{
334 mProxyRefs++;
335}
336
337void Texture2D::releaseProxy(const Renderbuffer *proxy)
338{
339 if (mProxyRefs > 0)
340 mProxyRefs--;
341
342 if (mProxyRefs == 0)
343 mColorbufferProxy = NULL;
344}
345
346GLenum Texture2D::getTarget() const
347{
348 return GL_TEXTURE_2D;
349}
350
351GLsizei Texture2D::getWidth(GLint level) const
352{
353 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000354 return mImageArray[level]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000355 else
356 return 0;
357}
358
359GLsizei Texture2D::getHeight(GLint level) const
360{
361 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000362 return mImageArray[level]->getHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000363 else
364 return 0;
365}
366
367GLenum Texture2D::getInternalFormat(GLint level) const
368{
369 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000370 return mImageArray[level]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000371 else
372 return GL_NONE;
373}
374
daniel@transgaming.com20d36662012-10-31 19:51:43 +0000375GLenum Texture2D::getActualFormat(GLint level) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000376{
377 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000378 return mImageArray[level]->getActualFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000379 else
380 return D3DFMT_UNKNOWN;
381}
382
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000383void Texture2D::redefineImage(GLint level, GLint internalformat, GLsizei width, GLsizei height)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000384{
385 releaseTexImage();
shannon.woods@transgaming.com8a406682013-02-28 23:15:26 +0000386
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000387 // If there currently is a corresponding storage texture image, it has these parameters
388 const int storageWidth = std::max(1, mImageArray[0]->getWidth() >> level);
389 const int storageHeight = std::max(1, mImageArray[0]->getHeight() >> level);
390 const int storageFormat = mImageArray[0]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000391
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000392 mImageArray[level]->redefine(mRenderer, internalformat, width, height, 1, false);
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000393
394 if (mTexStorage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000395 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000396 const int storageLevels = mTexStorage->levelCount();
397
398 if ((level >= storageLevels && storageLevels != 0) ||
399 width != storageWidth ||
400 height != storageHeight ||
401 internalformat != storageFormat) // Discard mismatched storage
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000402 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000403 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
404 {
405 mImageArray[i]->markDirty();
406 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000407
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000408 delete mTexStorage;
409 mTexStorage = NULL;
410 mDirtyImages = true;
411 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000412 }
413}
414
415void Texture2D::setImage(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
416{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000417 GLint internalformat = ConvertSizedInternalFormat(format, type);
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000418 redefineImage(level, internalformat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000419
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000420 Texture::setImage(unpackAlignment, pixels, mImageArray[level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000421}
422
423void Texture2D::bindTexImage(egl::Surface *surface)
424{
425 releaseTexImage();
426
daniel@transgaming.com106e1f72012-10-31 18:38:36 +0000427 GLint internalformat = surface->getFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000428
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000429 mImageArray[0]->redefine(mRenderer, internalformat, surface->getWidth(), surface->getHeight(), 1, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000430
431 delete mTexStorage;
daniel@transgaming.comd8353dd2012-12-20 21:11:14 +0000432 mTexStorage = new rx::TextureStorageInterface2D(mRenderer, surface->getSwapChain());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000433
434 mDirtyImages = true;
435 mSurface = surface;
436 mSurface->setBoundTexture(this);
437}
438
439void Texture2D::releaseTexImage()
440{
441 if (mSurface)
442 {
443 mSurface->setBoundTexture(NULL);
444 mSurface = NULL;
445
446 if (mTexStorage)
447 {
448 delete mTexStorage;
449 mTexStorage = NULL;
450 }
451
452 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
453 {
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000454 mImageArray[i]->redefine(mRenderer, GL_NONE, 0, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000455 }
456 }
457}
458
459void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
460{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000461 // 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 +0000462 redefineImage(level, format, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000463
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000464 Texture::setCompressedImage(imageSize, pixels, mImageArray[level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000465}
466
467void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
468{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000469 if (level < levelCount())
470 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000471 rx::Image *image = mImageArray[level];
daniel@transgaming.com0f195ad2012-10-31 19:51:59 +0000472 if (image->updateSurface(mTexStorage, level, xoffset, yoffset, width, height))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000473 {
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000474 image->markClean();
475 }
476 }
477}
478
479void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
480{
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000481 if (Texture::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpackAlignment, pixels, mImageArray[level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000482 {
483 commitRect(level, xoffset, yoffset, width, height);
484 }
485}
486
487void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
488{
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000489 if (Texture::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000490 {
491 commitRect(level, xoffset, yoffset, width, height);
492 }
493}
494
495void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
496{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000497 GLint internalformat = ConvertSizedInternalFormat(format, GL_UNSIGNED_BYTE);
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000498 redefineImage(level, internalformat, width, height);
shannon.woods@transgaming.com8a406682013-02-28 23:15:26 +0000499
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000500 if (!mImageArray[level]->isRenderableFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000501 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000502 mImageArray[level]->copy(0, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000503 mDirtyImages = true;
504 }
505 else
506 {
507 if (!mTexStorage || !mTexStorage->isRenderTarget())
508 {
509 convertToRenderTarget();
510 }
511
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000512 mImageArray[level]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000513
514 if (width != 0 && height != 0 && level < levelCount())
515 {
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +0000516 gl::Rectangle sourceRect;
517 sourceRect.x = x;
518 sourceRect.width = width;
519 sourceRect.y = y;
520 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000521
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +0000522 mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000523 }
524 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000525}
526
527void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
528{
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000529 if (xoffset + width > mImageArray[level]->getWidth() || yoffset + height > mImageArray[level]->getHeight())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000530 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +0000531 return gl::error(GL_INVALID_VALUE);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000532 }
533
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000534 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !isSamplerComplete()))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000535 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000536 mImageArray[level]->copy(xoffset, yoffset, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000537 mDirtyImages = true;
538 }
539 else
540 {
541 if (!mTexStorage || !mTexStorage->isRenderTarget())
542 {
543 convertToRenderTarget();
544 }
545
546 updateTexture();
547
548 if (level < levelCount())
549 {
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +0000550 gl::Rectangle sourceRect;
551 sourceRect.x = x;
552 sourceRect.width = width;
553 sourceRect.y = y;
554 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000555
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +0000556 mRenderer->copyImage(source, sourceRect,
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000557 gl::ExtractFormat(mImageArray[0]->getInternalFormat()),
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +0000558 xoffset, yoffset, mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000559 }
560 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000561}
562
563void Texture2D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height)
564{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000565 delete mTexStorage;
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000566 mTexStorage = new rx::TextureStorageInterface2D(mRenderer, levels, internalformat, mUsage, false, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000567 mImmutable = true;
568
569 for (int level = 0; level < levels; level++)
570 {
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000571 mImageArray[level]->redefine(mRenderer, internalformat, width, height, 1, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000572 width = std::max(1, width >> 1);
573 height = std::max(1, height >> 1);
574 }
575
576 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
577 {
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000578 mImageArray[level]->redefine(mRenderer, GL_NONE, 0, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000579 }
580
581 if (mTexStorage->isManaged())
582 {
583 int levels = levelCount();
584
585 for (int level = 0; level < levels; level++)
586 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000587 mImageArray[level]->setManagedSurface(mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000588 }
589 }
590}
591
592// Tests for 2D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85.
593bool Texture2D::isSamplerComplete() const
594{
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000595 GLsizei width = mImageArray[0]->getWidth();
596 GLsizei height = mImageArray[0]->getHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000597
598 if (width <= 0 || height <= 0)
599 {
600 return false;
601 }
602
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +0000603 bool mipmapping = isMipmapFiltered();
daniel@transgaming.comea32d482012-11-28 19:33:18 +0000604 bool filtering, renderable;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000605
daniel@transgaming.comea32d482012-11-28 19:33:18 +0000606 if ((IsFloat32Format(getInternalFormat(0)) && !mRenderer->getFloat32TextureSupport(&filtering, &renderable)) ||
607 (IsFloat16Format(getInternalFormat(0)) && !mRenderer->getFloat16TextureSupport(&filtering, &renderable)))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000608 {
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000609 if (mSamplerState.magFilter != GL_NEAREST ||
610 (mSamplerState.minFilter != GL_NEAREST && mSamplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000611 {
612 return false;
613 }
614 }
615
daniel@transgaming.comea32d482012-11-28 19:33:18 +0000616 bool npotSupport = mRenderer->getNonPower2TextureSupport();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000617
618 if (!npotSupport)
619 {
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000620 if ((mSamplerState.wrapS != GL_CLAMP_TO_EDGE && !isPow2(width)) ||
621 (mSamplerState.wrapT != GL_CLAMP_TO_EDGE && !isPow2(height)))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000622 {
623 return false;
624 }
625 }
626
627 if (mipmapping)
628 {
629 if (!npotSupport)
630 {
631 if (!isPow2(width) || !isPow2(height))
632 {
633 return false;
634 }
635 }
636
637 if (!isMipmapComplete())
638 {
639 return false;
640 }
641 }
642
643 return true;
644}
645
646// Tests for 2D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
647bool Texture2D::isMipmapComplete() const
648{
649 if (isImmutable())
650 {
651 return true;
652 }
653
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000654 GLsizei width = mImageArray[0]->getWidth();
655 GLsizei height = mImageArray[0]->getHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000656
657 if (width <= 0 || height <= 0)
658 {
659 return false;
660 }
661
662 int q = log2(std::max(width, height));
663
664 for (int level = 1; level <= q; level++)
665 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000666 if (mImageArray[level]->getInternalFormat() != mImageArray[0]->getInternalFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000667 {
668 return false;
669 }
670
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000671 if (mImageArray[level]->getWidth() != std::max(1, width >> level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000672 {
673 return false;
674 }
675
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000676 if (mImageArray[level]->getHeight() != std::max(1, height >> level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000677 {
678 return false;
679 }
680 }
681
682 return true;
683}
684
685bool Texture2D::isCompressed(GLint level) const
686{
687 return IsCompressed(getInternalFormat(level));
688}
689
690bool Texture2D::isDepth(GLint level) const
691{
692 return IsDepthTexture(getInternalFormat(level));
693}
694
daniel@transgaming.comf032cb82012-10-31 19:51:52 +0000695// Constructs a native texture resource from the texture images
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000696void Texture2D::createTexture()
697{
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000698 GLsizei width = mImageArray[0]->getWidth();
699 GLsizei height = mImageArray[0]->getHeight();
daniel@transgaming.come6a09842012-09-17 21:28:55 +0000700
701 if (!(width > 0 && height > 0))
daniel@transgaming.comf032cb82012-10-31 19:51:52 +0000702 return; // do not attempt to create native textures for nonexistant data
daniel@transgaming.come6a09842012-09-17 21:28:55 +0000703
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000704 GLint levels = creationLevels(width, height);
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000705 GLenum internalformat = mImageArray[0]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000706
707 delete mTexStorage;
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000708 mTexStorage = new rx::TextureStorageInterface2D(mRenderer, levels, internalformat, mUsage, false, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000709
710 if (mTexStorage->isManaged())
711 {
712 int levels = levelCount();
713
714 for (int level = 0; level < levels; level++)
715 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000716 mImageArray[level]->setManagedSurface(mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000717 }
718 }
719
720 mDirtyImages = true;
721}
722
723void Texture2D::updateTexture()
724{
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +0000725 bool mipmapping = (isMipmapFiltered() && isMipmapComplete());
726
727 int levels = (mipmapping ? levelCount() : 1);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000728
729 for (int level = 0; level < levels; level++)
730 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000731 rx::Image *image = mImageArray[level];
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000732
733 if (image->isDirty())
734 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000735 commitRect(level, 0, 0, mImageArray[level]->getWidth(), mImageArray[level]->getHeight());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000736 }
737 }
738}
739
740void Texture2D::convertToRenderTarget()
741{
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000742 rx::TextureStorageInterface2D *newTexStorage = NULL;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000743
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000744 if (mImageArray[0]->getWidth() != 0 && mImageArray[0]->getHeight() != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000745 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000746 GLsizei width = mImageArray[0]->getWidth();
747 GLsizei height = mImageArray[0]->getHeight();
shannon.woods@transgaming.com6bb48862013-02-28 23:09:34 +0000748 GLint levels = mTexStorage != NULL ? mTexStorage->levelCount() : creationLevels(width, height);
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000749 GLenum internalformat = mImageArray[0]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000750
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000751 newTexStorage = new rx::TextureStorageInterface2D(mRenderer, levels, internalformat, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, true, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000752
753 if (mTexStorage != NULL)
754 {
daniel@transgaming.com1d80eee2012-11-28 19:33:31 +0000755 if (!mRenderer->copyToRenderTarget(newTexStorage, mTexStorage))
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +0000756 {
757 delete newTexStorage;
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +0000758 return gl::error(GL_OUT_OF_MEMORY);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000759 }
760 }
761 }
762
763 delete mTexStorage;
764 mTexStorage = newTexStorage;
765
766 mDirtyImages = true;
767}
768
769void Texture2D::generateMipmaps()
770{
daniel@transgaming.comea32d482012-11-28 19:33:18 +0000771 if (!mRenderer->getNonPower2TextureSupport())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000772 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000773 if (!isPow2(mImageArray[0]->getWidth()) || !isPow2(mImageArray[0]->getHeight()))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000774 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +0000775 return gl::error(GL_INVALID_OPERATION);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000776 }
777 }
778
779 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000780 unsigned int q = log2(std::max(mImageArray[0]->getWidth(), mImageArray[0]->getHeight()));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000781 for (unsigned int i = 1; i <= q; i++)
782 {
shannon.woods@transgaming.com8a406682013-02-28 23:15:26 +0000783 redefineImage(i, mImageArray[0]->getInternalFormat(),
784 std::max(mImageArray[0]->getWidth() >> i, 1),
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000785 std::max(mImageArray[0]->getHeight() >> i, 1));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000786 }
787
788 if (mTexStorage && mTexStorage->isRenderTarget())
789 {
790 for (unsigned int i = 1; i <= q; i++)
791 {
daniel@transgaming.com0ad830b2012-10-31 19:52:12 +0000792 mTexStorage->generateMipmap(i);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000793
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000794 mImageArray[i]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000795 }
796 }
797 else
798 {
799 for (unsigned int i = 1; i <= q; i++)
800 {
daniel@transgaming.com4ba24062012-12-20 20:54:24 +0000801 mRenderer->generateMipmap(mImageArray[i], mImageArray[i - 1]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000802 }
803 }
804}
805
806Renderbuffer *Texture2D::getRenderbuffer(GLenum target)
807{
808 if (target != GL_TEXTURE_2D)
809 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +0000810 return gl::error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000811 }
812
813 if (mColorbufferProxy == NULL)
814 {
daniel@transgaming.com70062c92012-11-28 19:32:30 +0000815 mColorbufferProxy = new Renderbuffer(mRenderer, id(), new RenderbufferTexture2D(this, target));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000816 }
817
818 return mColorbufferProxy;
819}
820
daniel@transgaming.comd186dc72012-11-28 19:40:16 +0000821rx::RenderTarget *Texture2D::getRenderTarget(GLenum target)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000822{
823 ASSERT(target == GL_TEXTURE_2D);
824
825 // ensure the underlying texture is created
826 if (getStorage(true) == NULL)
827 {
828 return NULL;
829 }
830
831 updateTexture();
832
833 // ensure this is NOT a depth texture
834 if (isDepth(0))
835 {
836 return NULL;
837 }
daniel@transgaming.com34da3972012-12-20 21:10:29 +0000838
daniel@transgaming.comd186dc72012-11-28 19:40:16 +0000839 return mTexStorage->getRenderTarget();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000840}
841
daniel@transgaming.comd186dc72012-11-28 19:40:16 +0000842rx::RenderTarget *Texture2D::getDepthStencil(GLenum target)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000843{
844 ASSERT(target == GL_TEXTURE_2D);
845
846 // ensure the underlying texture is created
847 if (getStorage(true) == NULL)
848 {
849 return NULL;
850 }
851
852 updateTexture();
853
854 // ensure this is actually a depth texture
855 if (!isDepth(0))
856 {
857 return NULL;
858 }
daniel@transgaming.comd186dc72012-11-28 19:40:16 +0000859 return mTexStorage->getRenderTarget();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000860}
861
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +0000862int Texture2D::levelCount()
863{
shannon.woods@transgaming.com5016f8e2013-02-28 23:20:57 +0000864 return mTexStorage ? mTexStorage->levelCount() : 0;
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +0000865}
866
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000867rx::TextureStorageInterface *Texture2D::getStorage(bool renderTarget)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000868{
869 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
870 {
871 if (renderTarget)
872 {
873 convertToRenderTarget();
874 }
875 else
876 {
877 createTexture();
878 }
879 }
880
881 return mTexStorage;
882}
883
daniel@transgaming.com370482e2012-11-28 19:32:13 +0000884TextureCubeMap::TextureCubeMap(rx::Renderer *renderer, GLuint id) : Texture(renderer, id)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000885{
886 mTexStorage = NULL;
887 for (int i = 0; i < 6; i++)
888 {
889 mFaceProxies[i] = NULL;
890 mFaceProxyRefs[i] = 0;
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000891
892 for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
893 {
daniel@transgaming.com244e1832012-12-20 20:52:35 +0000894 mImageArray[i][j] = renderer->createImage();
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000895 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000896 }
897}
898
899TextureCubeMap::~TextureCubeMap()
900{
901 for (int i = 0; i < 6; i++)
902 {
903 mFaceProxies[i] = NULL;
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000904
905 for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
906 {
907 delete mImageArray[i][j];
908 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000909 }
910
911 delete mTexStorage;
912 mTexStorage = NULL;
913}
914
915// We need to maintain a count of references to renderbuffers acting as
916// proxies for this texture, so that the texture is not deleted while
917// proxy references still exist. If the reference count drops to zero,
918// we set our proxy pointer NULL, so that a new attempt at referencing
919// will cause recreation.
920void TextureCubeMap::addProxyRef(const Renderbuffer *proxy)
921{
922 for (int i = 0; i < 6; i++)
923 {
924 if (mFaceProxies[i] == proxy)
925 mFaceProxyRefs[i]++;
926 }
927}
928
929void TextureCubeMap::releaseProxy(const Renderbuffer *proxy)
930{
931 for (int i = 0; i < 6; i++)
932 {
933 if (mFaceProxies[i] == proxy)
934 {
935 if (mFaceProxyRefs[i] > 0)
936 mFaceProxyRefs[i]--;
937
938 if (mFaceProxyRefs[i] == 0)
939 mFaceProxies[i] = NULL;
940 }
941 }
942}
943
944GLenum TextureCubeMap::getTarget() const
945{
946 return GL_TEXTURE_CUBE_MAP;
947}
948
949GLsizei TextureCubeMap::getWidth(GLenum target, GLint level) const
950{
951 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000952 return mImageArray[faceIndex(target)][level]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000953 else
954 return 0;
955}
956
957GLsizei TextureCubeMap::getHeight(GLenum target, GLint level) const
958{
959 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000960 return mImageArray[faceIndex(target)][level]->getHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000961 else
962 return 0;
963}
964
965GLenum TextureCubeMap::getInternalFormat(GLenum target, GLint level) const
966{
967 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000968 return mImageArray[faceIndex(target)][level]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000969 else
970 return GL_NONE;
971}
972
daniel@transgaming.com20d36662012-10-31 19:51:43 +0000973GLenum TextureCubeMap::getActualFormat(GLenum target, GLint level) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000974{
975 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000976 return mImageArray[faceIndex(target)][level]->getActualFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000977 else
978 return D3DFMT_UNKNOWN;
979}
980
981void TextureCubeMap::setImagePosX(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
982{
983 setImage(0, level, width, height, format, type, unpackAlignment, pixels);
984}
985
986void TextureCubeMap::setImageNegX(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
987{
988 setImage(1, level, width, height, format, type, unpackAlignment, pixels);
989}
990
991void TextureCubeMap::setImagePosY(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
992{
993 setImage(2, level, width, height, format, type, unpackAlignment, pixels);
994}
995
996void TextureCubeMap::setImageNegY(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
997{
998 setImage(3, level, width, height, format, type, unpackAlignment, pixels);
999}
1000
1001void TextureCubeMap::setImagePosZ(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1002{
1003 setImage(4, level, width, height, format, type, unpackAlignment, pixels);
1004}
1005
1006void TextureCubeMap::setImageNegZ(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1007{
1008 setImage(5, level, width, height, format, type, unpackAlignment, pixels);
1009}
1010
1011void TextureCubeMap::setCompressedImage(GLenum face, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
1012{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001013 // 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 +00001014 redefineImage(faceIndex(face), level, format, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001015
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001016 Texture::setCompressedImage(imageSize, pixels, mImageArray[faceIndex(face)][level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001017}
1018
1019void TextureCubeMap::commitRect(int face, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1020{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001021 if (level < levelCount())
1022 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001023 rx::Image *image = mImageArray[face][level];
daniel@transgaming.com0f195ad2012-10-31 19:51:59 +00001024 if (image->updateSurface(mTexStorage, face, level, xoffset, yoffset, width, height))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001025 image->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001026 }
1027}
1028
1029void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1030{
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +00001031 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 +00001032 {
1033 commitRect(faceIndex(target), level, xoffset, yoffset, width, height);
1034 }
1035}
1036
1037void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1038{
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +00001039 if (Texture::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[faceIndex(target)][level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001040 {
1041 commitRect(faceIndex(target), level, xoffset, yoffset, width, height);
1042 }
1043}
1044
1045// Tests for cube map sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 86.
1046bool TextureCubeMap::isSamplerComplete() const
1047{
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001048 int size = mImageArray[0][0]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001049
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +00001050 bool mipmapping = isMipmapFiltered();
daniel@transgaming.comea32d482012-11-28 19:33:18 +00001051 bool filtering, renderable;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001052
daniel@transgaming.comea32d482012-11-28 19:33:18 +00001053 if ((gl::ExtractType(getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0)) == GL_FLOAT && !mRenderer->getFloat32TextureSupport(&filtering, &renderable)) ||
1054 (gl::ExtractType(getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0) == GL_HALF_FLOAT_OES) && !mRenderer->getFloat16TextureSupport(&filtering, &renderable)))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001055 {
daniel@transgaming.comebf139f2012-10-31 18:07:32 +00001056 if (mSamplerState.magFilter != GL_NEAREST ||
1057 (mSamplerState.minFilter != GL_NEAREST && mSamplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001058 {
1059 return false;
1060 }
1061 }
1062
daniel@transgaming.comea32d482012-11-28 19:33:18 +00001063 if (!isPow2(size) && !mRenderer->getNonPower2TextureSupport())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001064 {
daniel@transgaming.comebf139f2012-10-31 18:07:32 +00001065 if (mSamplerState.wrapS != GL_CLAMP_TO_EDGE || mSamplerState.wrapT != GL_CLAMP_TO_EDGE || mipmapping)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001066 {
1067 return false;
1068 }
1069 }
1070
1071 if (!mipmapping)
1072 {
1073 if (!isCubeComplete())
1074 {
1075 return false;
1076 }
1077 }
1078 else
1079 {
1080 if (!isMipmapCubeComplete()) // Also tests for isCubeComplete()
1081 {
1082 return false;
1083 }
1084 }
1085
1086 return true;
1087}
1088
1089// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1090bool TextureCubeMap::isCubeComplete() const
1091{
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001092 if (mImageArray[0][0]->getWidth() <= 0 || mImageArray[0][0]->getHeight() != mImageArray[0][0]->getWidth())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001093 {
1094 return false;
1095 }
1096
1097 for (unsigned int face = 1; face < 6; face++)
1098 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001099 if (mImageArray[face][0]->getWidth() != mImageArray[0][0]->getWidth() ||
1100 mImageArray[face][0]->getWidth() != mImageArray[0][0]->getHeight() ||
1101 mImageArray[face][0]->getInternalFormat() != mImageArray[0][0]->getInternalFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001102 {
1103 return false;
1104 }
1105 }
1106
1107 return true;
1108}
1109
1110bool TextureCubeMap::isMipmapCubeComplete() const
1111{
1112 if (isImmutable())
1113 {
1114 return true;
1115 }
1116
1117 if (!isCubeComplete())
1118 {
1119 return false;
1120 }
1121
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001122 GLsizei size = mImageArray[0][0]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001123
1124 int q = log2(size);
1125
1126 for (int face = 0; face < 6; face++)
1127 {
1128 for (int level = 1; level <= q; level++)
1129 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001130 if (mImageArray[face][level]->getInternalFormat() != mImageArray[0][0]->getInternalFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001131 {
1132 return false;
1133 }
1134
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001135 if (mImageArray[face][level]->getWidth() != std::max(1, size >> level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001136 {
1137 return false;
1138 }
1139 }
1140 }
1141
1142 return true;
1143}
1144
1145bool TextureCubeMap::isCompressed(GLenum target, GLint level) const
1146{
1147 return IsCompressed(getInternalFormat(target, level));
1148}
1149
daniel@transgaming.comf032cb82012-10-31 19:51:52 +00001150// Constructs a native texture resource from the texture images, or returns an existing one
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001151void TextureCubeMap::createTexture()
1152{
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001153 GLsizei size = mImageArray[0][0]->getWidth();
daniel@transgaming.come6a09842012-09-17 21:28:55 +00001154
1155 if (!(size > 0))
daniel@transgaming.comf032cb82012-10-31 19:51:52 +00001156 return; // do not attempt to create native textures for nonexistant data
daniel@transgaming.come6a09842012-09-17 21:28:55 +00001157
sminns@adobe.comce1189b2012-09-18 20:06:35 +00001158 GLint levels = creationLevels(size);
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001159 GLenum internalformat = mImageArray[0][0]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001160
1161 delete mTexStorage;
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001162 mTexStorage = new rx::TextureStorageInterfaceCube(mRenderer, levels, internalformat, mUsage, false, size);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001163
1164 if (mTexStorage->isManaged())
1165 {
1166 int levels = levelCount();
1167
1168 for (int face = 0; face < 6; face++)
1169 {
1170 for (int level = 0; level < levels; level++)
1171 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001172 mImageArray[face][level]->setManagedSurface(mTexStorage, face, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001173 }
1174 }
1175 }
1176
1177 mDirtyImages = true;
1178}
1179
1180void TextureCubeMap::updateTexture()
1181{
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +00001182 bool mipmapping = isMipmapFiltered() && isMipmapCubeComplete();
1183
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001184 for (int face = 0; face < 6; face++)
1185 {
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +00001186 int levels = (mipmapping ? levelCount() : 1);
1187
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001188 for (int level = 0; level < levels; level++)
1189 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001190 rx::Image *image = mImageArray[face][level];
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001191
1192 if (image->isDirty())
1193 {
1194 commitRect(face, level, 0, 0, image->getWidth(), image->getHeight());
1195 }
1196 }
1197 }
1198}
1199
1200void TextureCubeMap::convertToRenderTarget()
1201{
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001202 rx::TextureStorageInterfaceCube *newTexStorage = NULL;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001203
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001204 if (mImageArray[0][0]->getWidth() != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001205 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001206 GLsizei size = mImageArray[0][0]->getWidth();
shannon.woods@transgaming.com6bb48862013-02-28 23:09:34 +00001207 GLint levels = mTexStorage != NULL ? mTexStorage->levelCount() : creationLevels(size);
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001208 GLenum internalformat = mImageArray[0][0]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001209
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001210 newTexStorage = new rx::TextureStorageInterfaceCube(mRenderer, levels, internalformat, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, true, size);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001211
1212 if (mTexStorage != NULL)
1213 {
daniel@transgaming.com1d80eee2012-11-28 19:33:31 +00001214 if (!mRenderer->copyToRenderTarget(newTexStorage, mTexStorage))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001215 {
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +00001216 delete newTexStorage;
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +00001217 return gl::error(GL_OUT_OF_MEMORY);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001218 }
1219 }
1220 }
1221
1222 delete mTexStorage;
1223 mTexStorage = newTexStorage;
1224
1225 mDirtyImages = true;
1226}
1227
1228void TextureCubeMap::setImage(int faceIndex, GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1229{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001230 GLint internalformat = ConvertSizedInternalFormat(format, type);
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001231 redefineImage(faceIndex, level, internalformat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001232
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001233 Texture::setImage(unpackAlignment, pixels, mImageArray[faceIndex][level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001234}
1235
1236unsigned int TextureCubeMap::faceIndex(GLenum face)
1237{
1238 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
1239 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
1240 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
1241 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
1242 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
1243
1244 return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
1245}
1246
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001247void TextureCubeMap::redefineImage(int face, GLint level, GLint internalformat, GLsizei width, GLsizei height)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001248{
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001249 // If there currently is a corresponding storage texture image, it has these parameters
1250 const int storageWidth = std::max(1, mImageArray[0][0]->getWidth() >> level);
1251 const int storageHeight = std::max(1, mImageArray[0][0]->getHeight() >> level);
1252 const int storageFormat = mImageArray[0][0]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001253
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +00001254 mImageArray[face][level]->redefine(mRenderer, internalformat, width, height, 1, false);
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001255
1256 if (mTexStorage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001257 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001258 const int storageLevels = mTexStorage->levelCount();
1259
1260 if ((level >= storageLevels && storageLevels != 0) ||
1261 width != storageWidth ||
1262 height != storageHeight ||
1263 internalformat != storageFormat) // Discard mismatched storage
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001264 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001265 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001266 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001267 for (int f = 0; f < 6; f++)
1268 {
1269 mImageArray[f][i]->markDirty();
1270 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001271 }
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001272
1273 delete mTexStorage;
1274 mTexStorage = NULL;
1275
1276 mDirtyImages = true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001277 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001278 }
1279}
1280
1281void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1282{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001283 unsigned int faceindex = faceIndex(target);
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001284 GLint internalformat = gl::ConvertSizedInternalFormat(format, GL_UNSIGNED_BYTE);
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001285 redefineImage(faceindex, level, internalformat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001286
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001287 if (!mImageArray[faceindex][level]->isRenderableFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001288 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001289 mImageArray[faceindex][level]->copy(0, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001290 mDirtyImages = true;
1291 }
1292 else
1293 {
1294 if (!mTexStorage || !mTexStorage->isRenderTarget())
1295 {
1296 convertToRenderTarget();
1297 }
1298
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001299 mImageArray[faceindex][level]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001300
1301 ASSERT(width == height);
1302
1303 if (width > 0 && level < levelCount())
1304 {
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +00001305 gl::Rectangle sourceRect;
1306 sourceRect.x = x;
1307 sourceRect.width = width;
1308 sourceRect.y = y;
1309 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001310
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +00001311 mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001312 }
1313 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001314}
1315
1316void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1317{
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001318 GLsizei size = mImageArray[faceIndex(target)][level]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001319
1320 if (xoffset + width > size || yoffset + height > size)
1321 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +00001322 return gl::error(GL_INVALID_VALUE);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001323 }
1324
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001325 unsigned int faceindex = faceIndex(target);
1326
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001327 if (!mImageArray[faceindex][level]->isRenderableFormat() || (!mTexStorage && !isSamplerComplete()))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001328 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001329 mImageArray[faceindex][level]->copy(0, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001330 mDirtyImages = true;
1331 }
1332 else
1333 {
1334 if (!mTexStorage || !mTexStorage->isRenderTarget())
1335 {
1336 convertToRenderTarget();
1337 }
1338
1339 updateTexture();
1340
1341 if (level < levelCount())
1342 {
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +00001343 gl::Rectangle sourceRect;
1344 sourceRect.x = x;
1345 sourceRect.width = width;
1346 sourceRect.y = y;
1347 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001348
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001349 mRenderer->copyImage(source, sourceRect, gl::ExtractFormat(mImageArray[0][0]->getInternalFormat()),
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +00001350 xoffset, yoffset, mTexStorage, target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001351 }
1352 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001353}
1354
1355void TextureCubeMap::storage(GLsizei levels, GLenum internalformat, GLsizei size)
1356{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001357 delete mTexStorage;
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001358 mTexStorage = new rx::TextureStorageInterfaceCube(mRenderer, levels, internalformat, mUsage, false, size);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001359 mImmutable = true;
1360
1361 for (int level = 0; level < levels; level++)
1362 {
1363 for (int face = 0; face < 6; face++)
1364 {
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +00001365 mImageArray[face][level]->redefine(mRenderer, internalformat, size, size, 1, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001366 size = std::max(1, size >> 1);
1367 }
1368 }
1369
1370 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1371 {
1372 for (int face = 0; face < 6; face++)
1373 {
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +00001374 mImageArray[face][level]->redefine(mRenderer, GL_NONE, 0, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001375 }
1376 }
1377
1378 if (mTexStorage->isManaged())
1379 {
1380 int levels = levelCount();
1381
1382 for (int face = 0; face < 6; face++)
1383 {
1384 for (int level = 0; level < levels; level++)
1385 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001386 mImageArray[face][level]->setManagedSurface(mTexStorage, face, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001387 }
1388 }
1389 }
1390}
1391
1392void TextureCubeMap::generateMipmaps()
1393{
1394 if (!isCubeComplete())
1395 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +00001396 return gl::error(GL_INVALID_OPERATION);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001397 }
1398
daniel@transgaming.comea32d482012-11-28 19:33:18 +00001399 if (!mRenderer->getNonPower2TextureSupport())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001400 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001401 if (!isPow2(mImageArray[0][0]->getWidth()))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001402 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +00001403 return gl::error(GL_INVALID_OPERATION);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001404 }
1405 }
1406
1407 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001408 unsigned int q = log2(mImageArray[0][0]->getWidth());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001409 for (unsigned int f = 0; f < 6; f++)
1410 {
1411 for (unsigned int i = 1; i <= q; i++)
1412 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001413 redefineImage(f, i, mImageArray[f][0]->getInternalFormat(),
shannon.woods@transgaming.com8a406682013-02-28 23:15:26 +00001414 std::max(mImageArray[f][0]->getWidth() >> i, 1),
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001415 std::max(mImageArray[f][0]->getWidth() >> i, 1));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001416 }
1417 }
1418
1419 if (mTexStorage && mTexStorage->isRenderTarget())
1420 {
1421 for (unsigned int f = 0; f < 6; f++)
1422 {
1423 for (unsigned int i = 1; i <= q; i++)
1424 {
daniel@transgaming.com0ad830b2012-10-31 19:52:12 +00001425 mTexStorage->generateMipmap(f, i);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001426
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001427 mImageArray[f][i]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001428 }
1429 }
1430 }
1431 else
1432 {
1433 for (unsigned int f = 0; f < 6; f++)
1434 {
1435 for (unsigned int i = 1; i <= q; i++)
1436 {
daniel@transgaming.com4ba24062012-12-20 20:54:24 +00001437 mRenderer->generateMipmap(mImageArray[f][i], mImageArray[f][i - 1]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001438 }
1439 }
1440 }
1441}
1442
1443Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target)
1444{
1445 if (!IsCubemapTextureTarget(target))
1446 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +00001447 return gl::error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001448 }
1449
1450 unsigned int face = faceIndex(target);
1451
1452 if (mFaceProxies[face] == NULL)
1453 {
daniel@transgaming.com70062c92012-11-28 19:32:30 +00001454 mFaceProxies[face] = new Renderbuffer(mRenderer, id(), new RenderbufferTextureCubeMap(this, target));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001455 }
1456
1457 return mFaceProxies[face];
1458}
1459
daniel@transgaming.comd186dc72012-11-28 19:40:16 +00001460rx::RenderTarget *TextureCubeMap::getRenderTarget(GLenum target)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001461{
1462 ASSERT(IsCubemapTextureTarget(target));
1463
1464 // ensure the underlying texture is created
1465 if (getStorage(true) == NULL)
1466 {
1467 return NULL;
1468 }
1469
1470 updateTexture();
1471
daniel@transgaming.comd186dc72012-11-28 19:40:16 +00001472 return mTexStorage->getRenderTarget(target);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001473}
1474
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +00001475int TextureCubeMap::levelCount()
1476{
1477 return mTexStorage ? mTexStorage->levelCount() - getLodOffset() : 0;
1478}
1479
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001480rx::TextureStorageInterface *TextureCubeMap::getStorage(bool renderTarget)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001481{
1482 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
1483 {
1484 if (renderTarget)
1485 {
1486 convertToRenderTarget();
1487 }
1488 else
1489 {
1490 createTexture();
1491 }
1492 }
1493
1494 return mTexStorage;
1495}
1496
1497}