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