blob: cf247fcc346ecd6429d1502451368fc4c2913d71 [file] [log] [blame]
shannon.woods@transgaming.combdf2d802013-02-28 23:16:20 +00001#include "precompiled.h"
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00002//
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00003// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00004// Use of this source code is governed by a BSD-style license that can be
5// found in the LICENSE file.
6//
7
8// Texture.cpp: Implements the gl::Texture class and its derived classes
9// Texture2D and TextureCubeMap. Implements GL texture objects and related
10// functionality. [OpenGL ES 2.0.24] section 3.7 page 63.
11
12#include "libGLESv2/Texture.h"
13
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000014#include "libGLESv2/main.h"
shannonwoods@chromium.orga2ecfcc2013-05-30 00:11:59 +000015#include "common/mathutil.h"
16#include "common/utilities.h"
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +000017#include "libGLESv2/formatutils.h"
Geoff Langdce735c2013-06-04 10:21:18 -040018#include "libGLESv2/renderer/Blit9.h"
shannon.woods@transgaming.com486d9e92013-02-28 23:15:41 +000019#include "libGLESv2/Renderbuffer.h"
20#include "libGLESv2/renderer/Image.h"
21#include "libGLESv2/renderer/Renderer.h"
22#include "libGLESv2/renderer/TextureStorage.h"
23#include "libEGL/Surface.h"
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000024
25namespace gl
26{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000027
Jamie Madillf8989902013-07-19 16:36:58 -040028bool IsMipmapFiltered(const SamplerState &samplerState)
29{
30 switch (samplerState.minFilter)
31 {
32 case GL_NEAREST:
33 case GL_LINEAR:
34 return false;
35 case GL_NEAREST_MIPMAP_NEAREST:
36 case GL_LINEAR_MIPMAP_NEAREST:
37 case GL_NEAREST_MIPMAP_LINEAR:
38 case GL_LINEAR_MIPMAP_LINEAR:
39 return true;
40 default: UNREACHABLE();
41 return false;
42 }
43}
44
Geoff Lang4907f2c2013-07-25 12:53:57 -040045Texture::Texture(rx::Renderer *renderer, GLuint id, GLenum target) : RefCountObject(id)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000046{
daniel@transgaming.com370482e2012-11-28 19:32:13 +000047 mRenderer = renderer;
48
daniel@transgaming.comebf139f2012-10-31 18:07:32 +000049 mSamplerState.minFilter = GL_NEAREST_MIPMAP_LINEAR;
50 mSamplerState.magFilter = GL_LINEAR;
51 mSamplerState.wrapS = GL_REPEAT;
52 mSamplerState.wrapT = GL_REPEAT;
shannon.woods%transgaming.com@gtempaccount.com0b3a8df2013-04-13 03:44:51 +000053 mSamplerState.wrapR = GL_REPEAT;
daniel@transgaming.comebf139f2012-10-31 18:07:32 +000054 mSamplerState.maxAnisotropy = 1.0f;
55 mSamplerState.lodOffset = 0;
Geoff Langc82fc412013-07-10 14:43:42 -040056 mSamplerState.compareMode = GL_NONE;
57 mSamplerState.compareFunc = GL_LEQUAL;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000058 mUsage = GL_NONE;
Geoff Langc82fc412013-07-10 14:43:42 -040059
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000060 mDirtyImages = true;
61
62 mImmutable = false;
Geoff Lang4907f2c2013-07-25 12:53:57 -040063
64 mTarget = target;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000065}
66
67Texture::~Texture()
68{
69}
70
Geoff Lang4907f2c2013-07-25 12:53:57 -040071GLenum Texture::getTarget() const
72{
73 return mTarget;
74}
75
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000076// Returns true on successful filter state update (valid enum parameter)
77bool Texture::setMinFilter(GLenum filter)
78{
79 switch (filter)
80 {
81 case GL_NEAREST:
82 case GL_LINEAR:
83 case GL_NEAREST_MIPMAP_NEAREST:
84 case GL_LINEAR_MIPMAP_NEAREST:
85 case GL_NEAREST_MIPMAP_LINEAR:
86 case GL_LINEAR_MIPMAP_LINEAR:
daniel@transgaming.com3c17ba62013-01-11 04:11:41 +000087 mSamplerState.minFilter = filter;
88 return true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000089 default:
90 return false;
91 }
92}
93
94// Returns true on successful filter state update (valid enum parameter)
95bool Texture::setMagFilter(GLenum filter)
96{
97 switch (filter)
98 {
99 case GL_NEAREST:
100 case GL_LINEAR:
daniel@transgaming.com3c17ba62013-01-11 04:11:41 +0000101 mSamplerState.magFilter = filter;
102 return true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000103 default:
104 return false;
105 }
106}
107
108// Returns true on successful wrap state update (valid enum parameter)
109bool Texture::setWrapS(GLenum wrap)
110{
111 switch (wrap)
112 {
113 case GL_REPEAT:
114 case GL_CLAMP_TO_EDGE:
115 case GL_MIRRORED_REPEAT:
daniel@transgaming.com3c17ba62013-01-11 04:11:41 +0000116 mSamplerState.wrapS = wrap;
117 return true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000118 default:
119 return false;
120 }
121}
122
123// Returns true on successful wrap state update (valid enum parameter)
124bool Texture::setWrapT(GLenum wrap)
125{
126 switch (wrap)
127 {
128 case GL_REPEAT:
129 case GL_CLAMP_TO_EDGE:
130 case GL_MIRRORED_REPEAT:
daniel@transgaming.com3c17ba62013-01-11 04:11:41 +0000131 mSamplerState.wrapT = wrap;
132 return true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000133 default:
134 return false;
135 }
136}
137
shannon.woods%transgaming.com@gtempaccount.com0b3a8df2013-04-13 03:44:51 +0000138// Returns true on successful wrap state update (valid enum parameter)
139bool Texture::setWrapR(GLenum wrap)
140{
141 switch (wrap)
142 {
143 case GL_REPEAT:
144 case GL_CLAMP_TO_EDGE:
145 case GL_MIRRORED_REPEAT:
146 mSamplerState.wrapR = wrap;
147 return true;
148 default:
149 return false;
150 }
151}
152
daniel@transgaming.com07ab8412012-07-12 15:17:09 +0000153// Returns true on successful max anisotropy update (valid anisotropy value)
154bool Texture::setMaxAnisotropy(float textureMaxAnisotropy, float contextMaxAnisotropy)
155{
156 textureMaxAnisotropy = std::min(textureMaxAnisotropy, contextMaxAnisotropy);
157 if (textureMaxAnisotropy < 1.0f)
158 {
159 return false;
160 }
daniel@transgaming.com3c17ba62013-01-11 04:11:41 +0000161
162 mSamplerState.maxAnisotropy = textureMaxAnisotropy;
163
daniel@transgaming.com07ab8412012-07-12 15:17:09 +0000164 return true;
165}
166
Geoff Langc82fc412013-07-10 14:43:42 -0400167bool Texture::setCompareMode(GLenum mode)
168{
169 // Acceptable mode parameters from GLES 3.0.2 spec, table 3.17
170 switch (mode)
171 {
172 case GL_NONE:
173 case GL_COMPARE_REF_TO_TEXTURE:
174 mSamplerState.compareMode = mode;
175 return true;
176 default:
177 return false;
178 }
179}
180
181bool Texture::setCompareFunc(GLenum func)
182{
183 // Acceptable function parameters from GLES 3.0.2 spec, table 3.17
184 switch (func)
185 {
186 case GL_LEQUAL:
187 case GL_GEQUAL:
188 case GL_LESS:
189 case GL_GREATER:
190 case GL_EQUAL:
191 case GL_NOTEQUAL:
192 case GL_ALWAYS:
193 case GL_NEVER:
194 mSamplerState.compareFunc = func;
195 return true;
196 default:
197 return false;
198 }
199}
200
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000201// Returns true on successful usage state update (valid enum parameter)
202bool Texture::setUsage(GLenum usage)
203{
204 switch (usage)
205 {
206 case GL_NONE:
207 case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
208 mUsage = usage;
209 return true;
210 default:
211 return false;
212 }
213}
214
215GLenum Texture::getMinFilter() const
216{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000217 return mSamplerState.minFilter;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000218}
219
220GLenum Texture::getMagFilter() const
221{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000222 return mSamplerState.magFilter;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000223}
224
225GLenum Texture::getWrapS() const
226{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000227 return mSamplerState.wrapS;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000228}
229
230GLenum Texture::getWrapT() const
231{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000232 return mSamplerState.wrapT;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000233}
234
shannon.woods%transgaming.com@gtempaccount.com0b3a8df2013-04-13 03:44:51 +0000235GLenum Texture::getWrapR() const
236{
237 return mSamplerState.wrapR;
238}
239
daniel@transgaming.com07ab8412012-07-12 15:17:09 +0000240float Texture::getMaxAnisotropy() const
241{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000242 return mSamplerState.maxAnisotropy;
243}
244
245int Texture::getLodOffset()
246{
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000247 rx::TextureStorageInterface *texture = getStorage(false);
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000248 return texture ? texture->getLodOffset() : 0;
249}
250
251void Texture::getSamplerState(SamplerState *sampler)
252{
253 *sampler = mSamplerState;
254 sampler->lodOffset = getLodOffset();
daniel@transgaming.com07ab8412012-07-12 15:17:09 +0000255}
256
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000257GLenum Texture::getUsage() const
258{
259 return mUsage;
260}
261
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +0000262void Texture::setImage(GLint unpackAlignment, GLenum type, const void *pixels, rx::Image *image)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000263{
264 if (pixels != NULL)
265 {
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +0000266 image->loadData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), unpackAlignment, type, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000267 mDirtyImages = true;
268 }
269}
270
daniel@transgaming.com31b13e12012-11-28 19:34:30 +0000271void Texture::setCompressedImage(GLsizei imageSize, const void *pixels, rx::Image *image)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000272{
273 if (pixels != NULL)
274 {
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000275 image->loadCompressedData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000276 mDirtyImages = true;
277 }
278}
279
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000280bool Texture::subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
281 GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, rx::Image *image)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000282{
283 if (pixels != NULL)
284 {
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +0000285 image->loadData(xoffset, yoffset, zoffset, width, height, depth, unpackAlignment, type, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000286 mDirtyImages = true;
287 }
288
289 return true;
290}
291
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000292bool Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
293 GLenum format, GLsizei imageSize, const void *pixels, rx::Image *image)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000294{
295 if (pixels != NULL)
296 {
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000297 image->loadCompressedData(xoffset, yoffset, zoffset, width, height, depth, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000298 mDirtyImages = true;
299 }
300
301 return true;
302}
303
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000304rx::TextureStorageInterface *Texture::getNativeTexture()
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000305{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000306 // ensure the underlying texture is created
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000307
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000308 rx::TextureStorageInterface *storage = getStorage(false);
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000309 if (storage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000310 {
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000311 updateTexture();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000312 }
313
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000314 return storage;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000315}
316
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000317bool Texture::hasDirtyImages() const
318{
319 return mDirtyImages;
320}
321
322void Texture::resetDirty()
323{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000324 mDirtyImages = false;
325}
326
327unsigned int Texture::getTextureSerial()
328{
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000329 rx::TextureStorageInterface *texture = getStorage(false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000330 return texture ? texture->getTextureSerial() : 0;
331}
332
333unsigned int Texture::getRenderTargetSerial(GLenum target)
334{
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000335 rx::TextureStorageInterface *texture = getStorage(true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000336 return texture ? texture->getRenderTargetSerial(target) : 0;
337}
338
339bool Texture::isImmutable() const
340{
341 return mImmutable;
342}
343
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +0000344GLint Texture::creationLevels(GLsizei width, GLsizei height, GLsizei depth) const
345{
346 // NPOT checks are not required in ES 3.0, NPOT texture support is assumed.
347 return 0; // Maximum number of levels
348}
349
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000350GLint Texture::creationLevels(GLsizei width, GLsizei height) const
351{
daniel@transgaming.comea32d482012-11-28 19:33:18 +0000352 if ((isPow2(width) && isPow2(height)) || mRenderer->getNonPower2TextureSupport())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000353 {
354 return 0; // Maximum number of levels
355 }
356 else
357 {
358 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
359 return 1;
360 }
361}
362
363GLint Texture::creationLevels(GLsizei size) const
364{
365 return creationLevels(size, size);
366}
367
Geoff Lang4907f2c2013-07-25 12:53:57 -0400368Texture2D::Texture2D(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_2D)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000369{
370 mTexStorage = NULL;
371 mSurface = NULL;
372 mColorbufferProxy = NULL;
373 mProxyRefs = 0;
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000374
375 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
376 {
daniel@transgaming.com244e1832012-12-20 20:52:35 +0000377 mImageArray[i] = renderer->createImage();
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000378 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000379}
380
381Texture2D::~Texture2D()
382{
383 mColorbufferProxy = NULL;
384
385 delete mTexStorage;
386 mTexStorage = NULL;
387
388 if (mSurface)
389 {
390 mSurface->setBoundTexture(NULL);
391 mSurface = NULL;
392 }
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000393
394 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
395 {
396 delete mImageArray[i];
397 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000398}
399
400// We need to maintain a count of references to renderbuffers acting as
401// proxies for this texture, so that we do not attempt to use a pointer
402// to a renderbuffer proxy which has been deleted.
403void Texture2D::addProxyRef(const Renderbuffer *proxy)
404{
405 mProxyRefs++;
406}
407
408void Texture2D::releaseProxy(const Renderbuffer *proxy)
409{
410 if (mProxyRefs > 0)
411 mProxyRefs--;
412
413 if (mProxyRefs == 0)
414 mColorbufferProxy = NULL;
415}
416
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000417GLsizei Texture2D::getWidth(GLint level) const
418{
419 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000420 return mImageArray[level]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000421 else
422 return 0;
423}
424
425GLsizei Texture2D::getHeight(GLint level) const
426{
427 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000428 return mImageArray[level]->getHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000429 else
430 return 0;
431}
432
433GLenum Texture2D::getInternalFormat(GLint level) const
434{
435 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000436 return mImageArray[level]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000437 else
438 return GL_NONE;
439}
440
daniel@transgaming.com20d36662012-10-31 19:51:43 +0000441GLenum Texture2D::getActualFormat(GLint level) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000442{
443 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000444 return mImageArray[level]->getActualFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000445 else
446 return D3DFMT_UNKNOWN;
447}
448
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000449void Texture2D::redefineImage(GLint level, GLint internalformat, GLsizei width, GLsizei height)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000450{
451 releaseTexImage();
shannon.woods@transgaming.com8a406682013-02-28 23:15:26 +0000452
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000453 // If there currently is a corresponding storage texture image, it has these parameters
454 const int storageWidth = std::max(1, mImageArray[0]->getWidth() >> level);
455 const int storageHeight = std::max(1, mImageArray[0]->getHeight() >> level);
456 const int storageFormat = mImageArray[0]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000457
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000458 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, width, height, 1, false);
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000459
460 if (mTexStorage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000461 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000462 const int storageLevels = mTexStorage->levelCount();
463
464 if ((level >= storageLevels && storageLevels != 0) ||
465 width != storageWidth ||
466 height != storageHeight ||
467 internalformat != storageFormat) // Discard mismatched storage
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000468 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000469 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
470 {
471 mImageArray[i]->markDirty();
472 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000473
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000474 delete mTexStorage;
475 mTexStorage = NULL;
476 mDirtyImages = true;
477 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000478 }
479}
480
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +0000481void Texture2D::setImage(GLint level, GLsizei width, GLsizei height, GLint internalFormat, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000482{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +0000483 GLuint clientVersion = mRenderer->getCurrentClientVersion();
484 GLint sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
485 : GetSizedInternalFormat(format, type, clientVersion);
486 redefineImage(level, sizedInternalFormat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000487
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +0000488 Texture::setImage(unpackAlignment, type, pixels, mImageArray[level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000489}
490
491void Texture2D::bindTexImage(egl::Surface *surface)
492{
493 releaseTexImage();
494
daniel@transgaming.com106e1f72012-10-31 18:38:36 +0000495 GLint internalformat = surface->getFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000496
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000497 mImageArray[0]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, surface->getWidth(), surface->getHeight(), 1, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000498
499 delete mTexStorage;
daniel@transgaming.comd8353dd2012-12-20 21:11:14 +0000500 mTexStorage = new rx::TextureStorageInterface2D(mRenderer, surface->getSwapChain());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000501
502 mDirtyImages = true;
503 mSurface = surface;
504 mSurface->setBoundTexture(this);
505}
506
507void Texture2D::releaseTexImage()
508{
509 if (mSurface)
510 {
511 mSurface->setBoundTexture(NULL);
512 mSurface = NULL;
513
514 if (mTexStorage)
515 {
516 delete mTexStorage;
517 mTexStorage = NULL;
518 }
519
520 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
521 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000522 mImageArray[i]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000523 }
524 }
525}
526
527void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
528{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000529 // 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 +0000530 redefineImage(level, format, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000531
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000532 Texture::setCompressedImage(imageSize, pixels, mImageArray[level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000533}
534
535void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
536{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000537 if (level < levelCount())
538 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000539 rx::Image *image = mImageArray[level];
daniel@transgaming.com0f195ad2012-10-31 19:51:59 +0000540 if (image->updateSurface(mTexStorage, level, xoffset, yoffset, width, height))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000541 {
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000542 image->markClean();
543 }
544 }
545}
546
547void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
548{
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000549 if (Texture::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpackAlignment, pixels, mImageArray[level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000550 {
551 commitRect(level, xoffset, yoffset, width, height);
552 }
553}
554
555void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
556{
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000557 if (Texture::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000558 {
559 commitRect(level, xoffset, yoffset, width, height);
560 }
561}
562
563void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
564{
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +0000565 GLuint clientVersion = mRenderer->getCurrentClientVersion();
566 GLint sizedInternalFormat = IsSizedInternalFormat(format, clientVersion) ? format
567 : GetSizedInternalFormat(format, GL_UNSIGNED_BYTE, clientVersion);
568 redefineImage(level, sizedInternalFormat, width, height);
shannon.woods@transgaming.com8a406682013-02-28 23:15:26 +0000569
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000570 if (!mImageArray[level]->isRenderableFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000571 {
shannon.woods%transgaming.com@gtempaccount.come5dcce72013-04-13 03:44:33 +0000572 mImageArray[level]->copy(0, 0, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000573 mDirtyImages = true;
574 }
575 else
576 {
577 if (!mTexStorage || !mTexStorage->isRenderTarget())
578 {
579 convertToRenderTarget();
580 }
581
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000582 mImageArray[level]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000583
584 if (width != 0 && height != 0 && level < levelCount())
585 {
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +0000586 gl::Rectangle sourceRect;
587 sourceRect.x = x;
588 sourceRect.width = width;
589 sourceRect.y = y;
590 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000591
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +0000592 mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000593 }
594 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000595}
596
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +0000597void 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 +0000598{
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +0000599 if (xoffset + width > mImageArray[level]->getWidth() || yoffset + height > mImageArray[level]->getHeight() || zoffset != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000600 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +0000601 return gl::error(GL_INVALID_VALUE);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000602 }
603
Jamie Madill07edd442013-07-19 16:36:58 -0400604 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
605 // the current level we're copying to is defined (with appropriate format, width & height)
606 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
607
608 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000609 {
shannon.woods%transgaming.com@gtempaccount.come5dcce72013-04-13 03:44:33 +0000610 mImageArray[level]->copy(xoffset, yoffset, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000611 mDirtyImages = true;
612 }
613 else
614 {
615 if (!mTexStorage || !mTexStorage->isRenderTarget())
616 {
617 convertToRenderTarget();
618 }
619
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000620 if (level < levelCount())
621 {
Jamie Madill07edd442013-07-19 16:36:58 -0400622 updateTextureLevel(level);
623
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +0000624 GLuint clientVersion = mRenderer->getCurrentClientVersion();
625
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +0000626 gl::Rectangle sourceRect;
627 sourceRect.x = x;
628 sourceRect.width = width;
629 sourceRect.y = y;
630 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000631
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +0000632 mRenderer->copyImage(source, sourceRect,
633 gl::GetFormat(mImageArray[0]->getInternalFormat(), clientVersion),
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +0000634 xoffset, yoffset, mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000635 }
636 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000637}
638
639void Texture2D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height)
640{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000641 delete mTexStorage;
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000642 mTexStorage = new rx::TextureStorageInterface2D(mRenderer, levels, internalformat, mUsage, false, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000643 mImmutable = true;
644
645 for (int level = 0; level < levels; level++)
646 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000647 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, width, height, 1, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000648 width = std::max(1, width >> 1);
649 height = std::max(1, height >> 1);
650 }
651
652 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
653 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000654 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000655 }
656
657 if (mTexStorage->isManaged())
658 {
659 int levels = levelCount();
660
661 for (int level = 0; level < levels; level++)
662 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000663 mImageArray[level]->setManagedSurface(mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000664 }
665 }
666}
667
668// Tests for 2D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85.
Jamie Madillf8989902013-07-19 16:36:58 -0400669bool Texture2D::isSamplerComplete(const SamplerState &samplerState) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000670{
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000671 GLsizei width = mImageArray[0]->getWidth();
672 GLsizei height = mImageArray[0]->getHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000673
674 if (width <= 0 || height <= 0)
675 {
676 return false;
677 }
678
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000679 if (!IsTextureFilteringSupported(getInternalFormat(0), mRenderer))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000680 {
Jamie Madillf8989902013-07-19 16:36:58 -0400681 if (samplerState.magFilter != GL_NEAREST ||
682 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000683 {
684 return false;
685 }
686 }
687
daniel@transgaming.comea32d482012-11-28 19:33:18 +0000688 bool npotSupport = mRenderer->getNonPower2TextureSupport();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000689
690 if (!npotSupport)
691 {
Jamie Madillf8989902013-07-19 16:36:58 -0400692 if ((samplerState.wrapS != GL_CLAMP_TO_EDGE && !isPow2(width)) ||
693 (samplerState.wrapT != GL_CLAMP_TO_EDGE && !isPow2(height)))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000694 {
695 return false;
696 }
697 }
698
Jamie Madillf8989902013-07-19 16:36:58 -0400699 if (IsMipmapFiltered(samplerState))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000700 {
701 if (!npotSupport)
702 {
703 if (!isPow2(width) || !isPow2(height))
704 {
705 return false;
706 }
707 }
708
709 if (!isMipmapComplete())
710 {
711 return false;
712 }
713 }
714
Geoff Langc82fc412013-07-10 14:43:42 -0400715 // OpenGLES 3.0.2 spec section 3.8.13 states that a texture is not mipmap complete if:
716 // The internalformat specified for the texture arrays is a sized internal depth or
717 // depth and stencil format (see table 3.13), the value of TEXTURE_COMPARE_-
718 // MODE is NONE, and either the magnification filter is not NEAREST or the mini-
719 // fication filter is neither NEAREST nor NEAREST_MIPMAP_NEAREST.
720 if (gl::GetDepthBits(getInternalFormat(0), mRenderer->getCurrentClientVersion()) > 0)
721 {
722 if (mSamplerState.compareMode == GL_NONE)
723 {
724 if ((mSamplerState.minFilter != GL_NEAREST && mSamplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST) ||
725 mSamplerState.magFilter != GL_NEAREST)
726 {
727 return false;
728 }
729 }
730 }
731
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000732 return true;
733}
734
735// Tests for 2D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
736bool Texture2D::isMipmapComplete() const
737{
Jamie Madill07edd442013-07-19 16:36:58 -0400738 GLsizei width = mImageArray[0]->getWidth();
739 GLsizei height = mImageArray[0]->getHeight();
740
741 int q = log2(std::max(width, height));
742
743 for (int level = 0; level <= q; level++)
744 {
745 if (!isLevelComplete(level))
746 {
747 return false;
748 }
749 }
750
751 return true;
752}
753
754bool Texture2D::isLevelComplete(int level) const
755{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000756 if (isImmutable())
757 {
758 return true;
759 }
760
Jamie Madill07edd442013-07-19 16:36:58 -0400761 const rx::Image *baseImage = mImageArray[0];
762 GLsizei width = baseImage->getWidth();
763 GLsizei height = baseImage->getHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000764
765 if (width <= 0 || height <= 0)
766 {
767 return false;
768 }
769
Jamie Madill07edd442013-07-19 16:36:58 -0400770 // The base image level is complete if the width and height are positive
771 if (level == 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000772 {
Jamie Madill07edd442013-07-19 16:36:58 -0400773 return true;
774 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000775
Jamie Madill07edd442013-07-19 16:36:58 -0400776 ASSERT(level >= 1 && level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
777 rx::Image *image = mImageArray[level];
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000778
Jamie Madill07edd442013-07-19 16:36:58 -0400779 if (image->getInternalFormat() != baseImage->getInternalFormat())
780 {
781 return false;
782 }
783
784 if (image->getWidth() != std::max(1, width >> level))
785 {
786 return false;
787 }
788
789 if (image->getHeight() != std::max(1, height >> level))
790 {
791 return false;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000792 }
793
794 return true;
795}
796
797bool Texture2D::isCompressed(GLint level) const
798{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000799 return IsFormatCompressed(getInternalFormat(level), mRenderer->getCurrentClientVersion());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000800}
801
802bool Texture2D::isDepth(GLint level) const
803{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000804 return GetDepthBits(getInternalFormat(level), mRenderer->getCurrentClientVersion()) > 0;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000805}
806
daniel@transgaming.comf032cb82012-10-31 19:51:52 +0000807// Constructs a native texture resource from the texture images
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000808void Texture2D::createTexture()
809{
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000810 GLsizei width = mImageArray[0]->getWidth();
811 GLsizei height = mImageArray[0]->getHeight();
daniel@transgaming.come6a09842012-09-17 21:28:55 +0000812
813 if (!(width > 0 && height > 0))
daniel@transgaming.comf032cb82012-10-31 19:51:52 +0000814 return; // do not attempt to create native textures for nonexistant data
daniel@transgaming.come6a09842012-09-17 21:28:55 +0000815
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000816 GLint levels = creationLevels(width, height);
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000817 GLenum internalformat = mImageArray[0]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000818
819 delete mTexStorage;
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000820 mTexStorage = new rx::TextureStorageInterface2D(mRenderer, levels, internalformat, mUsage, false, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000821
822 if (mTexStorage->isManaged())
823 {
824 int levels = levelCount();
825
826 for (int level = 0; level < levels; level++)
827 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000828 mImageArray[level]->setManagedSurface(mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000829 }
830 }
831
832 mDirtyImages = true;
833}
834
835void Texture2D::updateTexture()
836{
Jamie Madilleb3665c2013-07-19 16:36:57 -0400837 int levels = (isMipmapComplete() ? levelCount() : 1);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000838
839 for (int level = 0; level < levels; level++)
840 {
Jamie Madill07edd442013-07-19 16:36:58 -0400841 updateTextureLevel(level);
842 }
843}
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000844
Jamie Madill07edd442013-07-19 16:36:58 -0400845void Texture2D::updateTextureLevel(int level)
846{
847 ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
848 rx::Image *image = mImageArray[level];
849
850 if (image->isDirty())
851 {
852 commitRect(level, 0, 0, mImageArray[level]->getWidth(), mImageArray[level]->getHeight());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000853 }
854}
855
856void Texture2D::convertToRenderTarget()
857{
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000858 rx::TextureStorageInterface2D *newTexStorage = NULL;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000859
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000860 if (mImageArray[0]->getWidth() != 0 && mImageArray[0]->getHeight() != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000861 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000862 GLsizei width = mImageArray[0]->getWidth();
863 GLsizei height = mImageArray[0]->getHeight();
shannon.woods@transgaming.com6bb48862013-02-28 23:09:34 +0000864 GLint levels = mTexStorage != NULL ? mTexStorage->levelCount() : creationLevels(width, height);
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000865 GLenum internalformat = mImageArray[0]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000866
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000867 newTexStorage = new rx::TextureStorageInterface2D(mRenderer, levels, internalformat, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, true, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000868
869 if (mTexStorage != NULL)
870 {
daniel@transgaming.com1d80eee2012-11-28 19:33:31 +0000871 if (!mRenderer->copyToRenderTarget(newTexStorage, mTexStorage))
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +0000872 {
873 delete newTexStorage;
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +0000874 return gl::error(GL_OUT_OF_MEMORY);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000875 }
876 }
877 }
878
879 delete mTexStorage;
880 mTexStorage = newTexStorage;
881
882 mDirtyImages = true;
883}
884
885void Texture2D::generateMipmaps()
886{
daniel@transgaming.comea32d482012-11-28 19:33:18 +0000887 if (!mRenderer->getNonPower2TextureSupport())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000888 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000889 if (!isPow2(mImageArray[0]->getWidth()) || !isPow2(mImageArray[0]->getHeight()))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000890 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +0000891 return gl::error(GL_INVALID_OPERATION);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000892 }
893 }
894
895 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000896 unsigned int q = log2(std::max(mImageArray[0]->getWidth(), mImageArray[0]->getHeight()));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000897 for (unsigned int i = 1; i <= q; i++)
898 {
shannon.woods@transgaming.com8a406682013-02-28 23:15:26 +0000899 redefineImage(i, mImageArray[0]->getInternalFormat(),
900 std::max(mImageArray[0]->getWidth() >> i, 1),
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000901 std::max(mImageArray[0]->getHeight() >> i, 1));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000902 }
903
904 if (mTexStorage && mTexStorage->isRenderTarget())
905 {
906 for (unsigned int i = 1; i <= q; i++)
907 {
daniel@transgaming.com0ad830b2012-10-31 19:52:12 +0000908 mTexStorage->generateMipmap(i);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000909
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000910 mImageArray[i]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000911 }
912 }
913 else
914 {
915 for (unsigned int i = 1; i <= q; i++)
916 {
daniel@transgaming.com4ba24062012-12-20 20:54:24 +0000917 mRenderer->generateMipmap(mImageArray[i], mImageArray[i - 1]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000918 }
919 }
920}
921
922Renderbuffer *Texture2D::getRenderbuffer(GLenum target)
923{
924 if (target != GL_TEXTURE_2D)
925 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +0000926 return gl::error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000927 }
928
929 if (mColorbufferProxy == NULL)
930 {
daniel@transgaming.com70062c92012-11-28 19:32:30 +0000931 mColorbufferProxy = new Renderbuffer(mRenderer, id(), new RenderbufferTexture2D(this, target));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000932 }
933
934 return mColorbufferProxy;
935}
936
daniel@transgaming.comd186dc72012-11-28 19:40:16 +0000937rx::RenderTarget *Texture2D::getRenderTarget(GLenum target)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000938{
939 ASSERT(target == GL_TEXTURE_2D);
940
941 // ensure the underlying texture is created
942 if (getStorage(true) == NULL)
943 {
944 return NULL;
945 }
946
947 updateTexture();
948
949 // ensure this is NOT a depth texture
950 if (isDepth(0))
951 {
952 return NULL;
953 }
daniel@transgaming.com34da3972012-12-20 21:10:29 +0000954
daniel@transgaming.comd186dc72012-11-28 19:40:16 +0000955 return mTexStorage->getRenderTarget();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000956}
957
daniel@transgaming.comd186dc72012-11-28 19:40:16 +0000958rx::RenderTarget *Texture2D::getDepthStencil(GLenum target)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000959{
960 ASSERT(target == GL_TEXTURE_2D);
961
962 // ensure the underlying texture is created
963 if (getStorage(true) == NULL)
964 {
965 return NULL;
966 }
967
968 updateTexture();
969
970 // ensure this is actually a depth texture
971 if (!isDepth(0))
972 {
973 return NULL;
974 }
daniel@transgaming.comd186dc72012-11-28 19:40:16 +0000975 return mTexStorage->getRenderTarget();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000976}
977
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +0000978int Texture2D::levelCount()
979{
shannon.woods@transgaming.com5016f8e2013-02-28 23:20:57 +0000980 return mTexStorage ? mTexStorage->levelCount() : 0;
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +0000981}
982
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000983rx::TextureStorageInterface *Texture2D::getStorage(bool renderTarget)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000984{
985 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
986 {
987 if (renderTarget)
988 {
989 convertToRenderTarget();
990 }
991 else
992 {
993 createTexture();
994 }
995 }
996
997 return mTexStorage;
998}
999
Geoff Lang4907f2c2013-07-25 12:53:57 -04001000TextureCubeMap::TextureCubeMap(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_CUBE_MAP)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001001{
1002 mTexStorage = NULL;
1003 for (int i = 0; i < 6; i++)
1004 {
1005 mFaceProxies[i] = NULL;
1006 mFaceProxyRefs[i] = 0;
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001007
1008 for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
1009 {
daniel@transgaming.com244e1832012-12-20 20:52:35 +00001010 mImageArray[i][j] = renderer->createImage();
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001011 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001012 }
1013}
1014
1015TextureCubeMap::~TextureCubeMap()
1016{
1017 for (int i = 0; i < 6; i++)
1018 {
1019 mFaceProxies[i] = NULL;
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001020
1021 for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
1022 {
1023 delete mImageArray[i][j];
1024 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001025 }
1026
1027 delete mTexStorage;
1028 mTexStorage = NULL;
1029}
1030
1031// We need to maintain a count of references to renderbuffers acting as
1032// proxies for this texture, so that the texture is not deleted while
1033// proxy references still exist. If the reference count drops to zero,
1034// we set our proxy pointer NULL, so that a new attempt at referencing
1035// will cause recreation.
1036void TextureCubeMap::addProxyRef(const Renderbuffer *proxy)
1037{
1038 for (int i = 0; i < 6; i++)
1039 {
1040 if (mFaceProxies[i] == proxy)
1041 mFaceProxyRefs[i]++;
1042 }
1043}
1044
1045void TextureCubeMap::releaseProxy(const Renderbuffer *proxy)
1046{
1047 for (int i = 0; i < 6; i++)
1048 {
1049 if (mFaceProxies[i] == proxy)
1050 {
1051 if (mFaceProxyRefs[i] > 0)
1052 mFaceProxyRefs[i]--;
1053
1054 if (mFaceProxyRefs[i] == 0)
1055 mFaceProxies[i] = NULL;
1056 }
1057 }
1058}
1059
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001060GLsizei TextureCubeMap::getWidth(GLenum target, GLint level) const
1061{
1062 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001063 return mImageArray[faceIndex(target)][level]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001064 else
1065 return 0;
1066}
1067
1068GLsizei TextureCubeMap::getHeight(GLenum target, GLint level) const
1069{
1070 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001071 return mImageArray[faceIndex(target)][level]->getHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001072 else
1073 return 0;
1074}
1075
1076GLenum TextureCubeMap::getInternalFormat(GLenum target, GLint level) const
1077{
1078 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001079 return mImageArray[faceIndex(target)][level]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001080 else
1081 return GL_NONE;
1082}
1083
daniel@transgaming.com20d36662012-10-31 19:51:43 +00001084GLenum TextureCubeMap::getActualFormat(GLenum target, GLint level) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001085{
1086 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001087 return mImageArray[faceIndex(target)][level]->getActualFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001088 else
1089 return D3DFMT_UNKNOWN;
1090}
1091
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001092void TextureCubeMap::setImagePosX(GLint level, GLsizei width, GLsizei height, GLint internalFormat, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001093{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001094 setImage(0, level, width, height, internalFormat, format, type, unpackAlignment, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001095}
1096
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001097void TextureCubeMap::setImageNegX(GLint level, GLsizei width, GLsizei height, GLint internalFormat, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001098{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001099 setImage(1, level, width, height, internalFormat, format, type, unpackAlignment, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001100}
1101
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001102void TextureCubeMap::setImagePosY(GLint level, GLsizei width, GLsizei height, GLint internalFormat, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001103{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001104 setImage(2, level, width, height, internalFormat, format, type, unpackAlignment, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001105}
1106
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001107void TextureCubeMap::setImageNegY(GLint level, GLsizei width, GLsizei height, GLint internalFormat, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001108{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001109 setImage(3, level, width, height, internalFormat, format, type, unpackAlignment, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001110}
1111
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001112void TextureCubeMap::setImagePosZ(GLint level, GLsizei width, GLsizei height, GLint internalFormat, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001113{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001114 setImage(4, level, width, height, internalFormat, format, type, unpackAlignment, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001115}
1116
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001117void TextureCubeMap::setImageNegZ(GLint level, GLsizei width, GLsizei height, GLint internalFormat, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001118{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001119 setImage(5, level, width, height, internalFormat, format, type, unpackAlignment, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001120}
1121
1122void TextureCubeMap::setCompressedImage(GLenum face, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
1123{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001124 // 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 +00001125 redefineImage(faceIndex(face), level, format, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001126
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001127 Texture::setCompressedImage(imageSize, pixels, mImageArray[faceIndex(face)][level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001128}
1129
1130void TextureCubeMap::commitRect(int face, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1131{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001132 if (level < levelCount())
1133 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001134 rx::Image *image = mImageArray[face][level];
daniel@transgaming.com0f195ad2012-10-31 19:51:59 +00001135 if (image->updateSurface(mTexStorage, face, level, xoffset, yoffset, width, height))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001136 image->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001137 }
1138}
1139
1140void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1141{
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +00001142 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 +00001143 {
1144 commitRect(faceIndex(target), level, xoffset, yoffset, width, height);
1145 }
1146}
1147
1148void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1149{
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +00001150 if (Texture::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[faceIndex(target)][level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001151 {
1152 commitRect(faceIndex(target), level, xoffset, yoffset, width, height);
1153 }
1154}
1155
1156// Tests for cube map sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 86.
Jamie Madillf8989902013-07-19 16:36:58 -04001157bool TextureCubeMap::isSamplerComplete(const SamplerState &samplerState) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001158{
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001159 int size = mImageArray[0][0]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001160
Jamie Madillf8989902013-07-19 16:36:58 -04001161 bool mipmapping = IsMipmapFiltered(samplerState);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001162
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001163 if (!IsTextureFilteringSupported(getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0), mRenderer))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001164 {
Jamie Madillf8989902013-07-19 16:36:58 -04001165 if (samplerState.magFilter != GL_NEAREST ||
1166 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001167 {
1168 return false;
1169 }
1170 }
1171
daniel@transgaming.comea32d482012-11-28 19:33:18 +00001172 if (!isPow2(size) && !mRenderer->getNonPower2TextureSupport())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001173 {
Jamie Madillf8989902013-07-19 16:36:58 -04001174 if (samplerState.wrapS != GL_CLAMP_TO_EDGE || samplerState.wrapT != GL_CLAMP_TO_EDGE || mipmapping)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001175 {
1176 return false;
1177 }
1178 }
1179
1180 if (!mipmapping)
1181 {
1182 if (!isCubeComplete())
1183 {
1184 return false;
1185 }
1186 }
1187 else
1188 {
1189 if (!isMipmapCubeComplete()) // Also tests for isCubeComplete()
1190 {
1191 return false;
1192 }
1193 }
1194
1195 return true;
1196}
1197
1198// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1199bool TextureCubeMap::isCubeComplete() const
1200{
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001201 if (mImageArray[0][0]->getWidth() <= 0 || mImageArray[0][0]->getHeight() != mImageArray[0][0]->getWidth())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001202 {
1203 return false;
1204 }
1205
1206 for (unsigned int face = 1; face < 6; face++)
1207 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001208 if (mImageArray[face][0]->getWidth() != mImageArray[0][0]->getWidth() ||
1209 mImageArray[face][0]->getWidth() != mImageArray[0][0]->getHeight() ||
1210 mImageArray[face][0]->getInternalFormat() != mImageArray[0][0]->getInternalFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001211 {
1212 return false;
1213 }
1214 }
1215
1216 return true;
1217}
1218
1219bool TextureCubeMap::isMipmapCubeComplete() const
1220{
1221 if (isImmutable())
1222 {
1223 return true;
1224 }
1225
1226 if (!isCubeComplete())
1227 {
1228 return false;
1229 }
1230
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001231 GLsizei size = mImageArray[0][0]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001232 int q = log2(size);
1233
1234 for (int face = 0; face < 6; face++)
1235 {
1236 for (int level = 1; level <= q; level++)
1237 {
Jamie Madill07edd442013-07-19 16:36:58 -04001238 if (!isFaceLevelComplete(face, level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001239 {
1240 return false;
1241 }
1242 }
1243 }
1244
1245 return true;
1246}
1247
Jamie Madill07edd442013-07-19 16:36:58 -04001248bool TextureCubeMap::isFaceLevelComplete(int face, int level) const
1249{
1250 ASSERT(level >= 0 && face < 6 && level < (int)ArraySize(mImageArray[face]) && mImageArray[face][level] != NULL);
1251
1252 if (isImmutable())
1253 {
1254 return true;
1255 }
1256
1257 const rx::Image *baseImage = mImageArray[face][0];
1258 GLsizei size = baseImage->getWidth();
1259
1260 if (size <= 0)
1261 {
1262 return false;
1263 }
1264
1265 // The base image level is complete if the width and height are positive
1266 if (level == 0)
1267 {
1268 return true;
1269 }
1270
1271 rx::Image *image = mImageArray[face][level];
1272
1273 if (image->getInternalFormat() != baseImage->getInternalFormat())
1274 {
1275 return false;
1276 }
1277
1278 if (mImageArray[face][level]->getWidth() != std::max(1, size >> level))
1279 {
1280 return false;
1281 }
1282
1283 return true;
1284}
1285
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001286bool TextureCubeMap::isCompressed(GLenum target, GLint level) const
1287{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001288 return IsFormatCompressed(getInternalFormat(target, level), mRenderer->getCurrentClientVersion());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001289}
1290
daniel@transgaming.comf032cb82012-10-31 19:51:52 +00001291// Constructs a native texture resource from the texture images, or returns an existing one
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001292void TextureCubeMap::createTexture()
1293{
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001294 GLsizei size = mImageArray[0][0]->getWidth();
daniel@transgaming.come6a09842012-09-17 21:28:55 +00001295
1296 if (!(size > 0))
daniel@transgaming.comf032cb82012-10-31 19:51:52 +00001297 return; // do not attempt to create native textures for nonexistant data
daniel@transgaming.come6a09842012-09-17 21:28:55 +00001298
sminns@adobe.comce1189b2012-09-18 20:06:35 +00001299 GLint levels = creationLevels(size);
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001300 GLenum internalformat = mImageArray[0][0]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001301
1302 delete mTexStorage;
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001303 mTexStorage = new rx::TextureStorageInterfaceCube(mRenderer, levels, internalformat, mUsage, false, size);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001304
1305 if (mTexStorage->isManaged())
1306 {
1307 int levels = levelCount();
1308
1309 for (int face = 0; face < 6; face++)
1310 {
1311 for (int level = 0; level < levels; level++)
1312 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001313 mImageArray[face][level]->setManagedSurface(mTexStorage, face, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001314 }
1315 }
1316 }
1317
1318 mDirtyImages = true;
1319}
1320
1321void TextureCubeMap::updateTexture()
1322{
Jamie Madilleb3665c2013-07-19 16:36:57 -04001323 int levels = (isMipmapCubeComplete() ? levelCount() : 1);
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +00001324
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001325 for (int face = 0; face < 6; face++)
1326 {
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001327 for (int level = 0; level < levels; level++)
1328 {
Jamie Madill07edd442013-07-19 16:36:58 -04001329 updateTextureFaceLevel(face, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001330 }
1331 }
1332}
1333
Jamie Madill07edd442013-07-19 16:36:58 -04001334void TextureCubeMap::updateTextureFaceLevel(int face, int level)
1335{
1336 ASSERT(level >= 0 && face < 6 && level < (int)ArraySize(mImageArray[face]) && mImageArray[face][level] != NULL);
1337 rx::Image *image = mImageArray[face][level];
1338
1339 if (image->isDirty())
1340 {
1341 commitRect(face, level, 0, 0, image->getWidth(), image->getHeight());
1342 }
1343}
1344
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001345void TextureCubeMap::convertToRenderTarget()
1346{
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001347 rx::TextureStorageInterfaceCube *newTexStorage = NULL;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001348
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001349 if (mImageArray[0][0]->getWidth() != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001350 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001351 GLsizei size = mImageArray[0][0]->getWidth();
shannon.woods@transgaming.com6bb48862013-02-28 23:09:34 +00001352 GLint levels = mTexStorage != NULL ? mTexStorage->levelCount() : creationLevels(size);
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001353 GLenum internalformat = mImageArray[0][0]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001354
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001355 newTexStorage = new rx::TextureStorageInterfaceCube(mRenderer, levels, internalformat, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, true, size);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001356
1357 if (mTexStorage != NULL)
1358 {
daniel@transgaming.com1d80eee2012-11-28 19:33:31 +00001359 if (!mRenderer->copyToRenderTarget(newTexStorage, mTexStorage))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001360 {
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +00001361 delete newTexStorage;
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +00001362 return gl::error(GL_OUT_OF_MEMORY);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001363 }
1364 }
1365 }
1366
1367 delete mTexStorage;
1368 mTexStorage = newTexStorage;
1369
1370 mDirtyImages = true;
1371}
1372
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001373void TextureCubeMap::setImage(int faceIndex, GLint level, GLsizei width, GLsizei height, GLint internalFormat, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001374{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001375 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1376 GLint sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
1377 : GetSizedInternalFormat(format, type, clientVersion);
1378
1379 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001380
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001381 Texture::setImage(unpackAlignment, type, pixels, mImageArray[faceIndex][level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001382}
1383
1384unsigned int TextureCubeMap::faceIndex(GLenum face)
1385{
1386 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
1387 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
1388 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
1389 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
1390 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
1391
1392 return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
1393}
1394
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001395void TextureCubeMap::redefineImage(int face, GLint level, GLint internalformat, GLsizei width, GLsizei height)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001396{
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001397 // If there currently is a corresponding storage texture image, it has these parameters
1398 const int storageWidth = std::max(1, mImageArray[0][0]->getWidth() >> level);
1399 const int storageHeight = std::max(1, mImageArray[0][0]->getHeight() >> level);
1400 const int storageFormat = mImageArray[0][0]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001401
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001402 mImageArray[face][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, width, height, 1, false);
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001403
1404 if (mTexStorage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001405 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001406 const int storageLevels = mTexStorage->levelCount();
1407
1408 if ((level >= storageLevels && storageLevels != 0) ||
1409 width != storageWidth ||
1410 height != storageHeight ||
1411 internalformat != storageFormat) // Discard mismatched storage
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001412 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001413 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001414 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001415 for (int f = 0; f < 6; f++)
1416 {
1417 mImageArray[f][i]->markDirty();
1418 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001419 }
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001420
1421 delete mTexStorage;
1422 mTexStorage = NULL;
1423
1424 mDirtyImages = true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001425 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001426 }
1427}
1428
1429void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1430{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001431 unsigned int faceindex = faceIndex(target);
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001432 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1433 GLint sizedInternalFormat = IsSizedInternalFormat(format, clientVersion) ? format
1434 : GetSizedInternalFormat(format, GL_UNSIGNED_BYTE, clientVersion);
1435 redefineImage(faceindex, level, sizedInternalFormat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001436
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001437 if (!mImageArray[faceindex][level]->isRenderableFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001438 {
shannon.woods%transgaming.com@gtempaccount.come5dcce72013-04-13 03:44:33 +00001439 mImageArray[faceindex][level]->copy(0, 0, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001440 mDirtyImages = true;
1441 }
1442 else
1443 {
1444 if (!mTexStorage || !mTexStorage->isRenderTarget())
1445 {
1446 convertToRenderTarget();
1447 }
1448
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001449 mImageArray[faceindex][level]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001450
1451 ASSERT(width == height);
1452
1453 if (width > 0 && level < levelCount())
1454 {
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +00001455 gl::Rectangle sourceRect;
1456 sourceRect.x = x;
1457 sourceRect.width = width;
1458 sourceRect.y = y;
1459 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001460
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +00001461 mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001462 }
1463 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001464}
1465
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001466void 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 +00001467{
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001468 GLsizei size = mImageArray[faceIndex(target)][level]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001469
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001470 if (xoffset + width > size || yoffset + height > size || zoffset != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001471 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +00001472 return gl::error(GL_INVALID_VALUE);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001473 }
1474
Jamie Madill07edd442013-07-19 16:36:58 -04001475 unsigned int face = faceIndex(target);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001476
Jamie Madill07edd442013-07-19 16:36:58 -04001477 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
1478 // the current level we're copying to is defined (with appropriate format, width & height)
1479 bool canCreateRenderTarget = isFaceLevelComplete(face, level) && isFaceLevelComplete(face, 0);
1480
1481 if (!mImageArray[face][level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001482 {
Jamie Madill07edd442013-07-19 16:36:58 -04001483 mImageArray[face][level]->copy(0, 0, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001484 mDirtyImages = true;
1485 }
1486 else
1487 {
1488 if (!mTexStorage || !mTexStorage->isRenderTarget())
1489 {
1490 convertToRenderTarget();
1491 }
1492
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001493 if (level < levelCount())
1494 {
Jamie Madill07edd442013-07-19 16:36:58 -04001495 updateTextureFaceLevel(face, level);
1496
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001497 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1498
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +00001499 gl::Rectangle sourceRect;
1500 sourceRect.x = x;
1501 sourceRect.width = width;
1502 sourceRect.y = y;
1503 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001504
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001505 mRenderer->copyImage(source, sourceRect, gl::GetFormat(mImageArray[0][0]->getInternalFormat(), clientVersion),
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +00001506 xoffset, yoffset, mTexStorage, target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001507 }
1508 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001509}
1510
1511void TextureCubeMap::storage(GLsizei levels, GLenum internalformat, GLsizei size)
1512{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001513 delete mTexStorage;
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001514 mTexStorage = new rx::TextureStorageInterfaceCube(mRenderer, levels, internalformat, mUsage, false, size);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001515 mImmutable = true;
1516
1517 for (int level = 0; level < levels; level++)
1518 {
1519 for (int face = 0; face < 6; face++)
1520 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001521 mImageArray[face][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, size, size, 1, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001522 size = std::max(1, size >> 1);
1523 }
1524 }
1525
1526 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1527 {
1528 for (int face = 0; face < 6; face++)
1529 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001530 mImageArray[face][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, GL_NONE, 0, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001531 }
1532 }
1533
1534 if (mTexStorage->isManaged())
1535 {
1536 int levels = levelCount();
1537
1538 for (int face = 0; face < 6; face++)
1539 {
1540 for (int level = 0; level < levels; level++)
1541 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001542 mImageArray[face][level]->setManagedSurface(mTexStorage, face, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001543 }
1544 }
1545 }
1546}
1547
1548void TextureCubeMap::generateMipmaps()
1549{
1550 if (!isCubeComplete())
1551 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +00001552 return gl::error(GL_INVALID_OPERATION);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001553 }
1554
daniel@transgaming.comea32d482012-11-28 19:33:18 +00001555 if (!mRenderer->getNonPower2TextureSupport())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001556 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001557 if (!isPow2(mImageArray[0][0]->getWidth()))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001558 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +00001559 return gl::error(GL_INVALID_OPERATION);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001560 }
1561 }
1562
1563 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001564 unsigned int q = log2(mImageArray[0][0]->getWidth());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001565 for (unsigned int f = 0; f < 6; f++)
1566 {
1567 for (unsigned int i = 1; i <= q; i++)
1568 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001569 redefineImage(f, i, mImageArray[f][0]->getInternalFormat(),
shannon.woods@transgaming.com8a406682013-02-28 23:15:26 +00001570 std::max(mImageArray[f][0]->getWidth() >> i, 1),
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001571 std::max(mImageArray[f][0]->getWidth() >> i, 1));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001572 }
1573 }
1574
1575 if (mTexStorage && mTexStorage->isRenderTarget())
1576 {
1577 for (unsigned int f = 0; f < 6; f++)
1578 {
1579 for (unsigned int i = 1; i <= q; i++)
1580 {
daniel@transgaming.com0ad830b2012-10-31 19:52:12 +00001581 mTexStorage->generateMipmap(f, i);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001582
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001583 mImageArray[f][i]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001584 }
1585 }
1586 }
1587 else
1588 {
1589 for (unsigned int f = 0; f < 6; f++)
1590 {
1591 for (unsigned int i = 1; i <= q; i++)
1592 {
daniel@transgaming.com4ba24062012-12-20 20:54:24 +00001593 mRenderer->generateMipmap(mImageArray[f][i], mImageArray[f][i - 1]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001594 }
1595 }
1596 }
1597}
1598
1599Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target)
1600{
1601 if (!IsCubemapTextureTarget(target))
1602 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +00001603 return gl::error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001604 }
1605
1606 unsigned int face = faceIndex(target);
1607
1608 if (mFaceProxies[face] == NULL)
1609 {
daniel@transgaming.com70062c92012-11-28 19:32:30 +00001610 mFaceProxies[face] = new Renderbuffer(mRenderer, id(), new RenderbufferTextureCubeMap(this, target));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001611 }
1612
1613 return mFaceProxies[face];
1614}
1615
daniel@transgaming.comd186dc72012-11-28 19:40:16 +00001616rx::RenderTarget *TextureCubeMap::getRenderTarget(GLenum target)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001617{
1618 ASSERT(IsCubemapTextureTarget(target));
1619
1620 // ensure the underlying texture is created
1621 if (getStorage(true) == NULL)
1622 {
1623 return NULL;
1624 }
1625
1626 updateTexture();
1627
daniel@transgaming.comd186dc72012-11-28 19:40:16 +00001628 return mTexStorage->getRenderTarget(target);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001629}
1630
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +00001631int TextureCubeMap::levelCount()
1632{
1633 return mTexStorage ? mTexStorage->levelCount() - getLodOffset() : 0;
1634}
1635
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001636rx::TextureStorageInterface *TextureCubeMap::getStorage(bool renderTarget)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001637{
1638 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
1639 {
1640 if (renderTarget)
1641 {
1642 convertToRenderTarget();
1643 }
1644 else
1645 {
1646 createTexture();
1647 }
1648 }
1649
1650 return mTexStorage;
1651}
1652
Geoff Lang4907f2c2013-07-25 12:53:57 -04001653Texture3D::Texture3D(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_3D)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001654{
1655 mTexStorage = NULL;
1656 mColorbufferProxy = NULL;
1657 mProxyRefs = 0;
1658
1659 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1660 {
1661 mImageArray[i] = renderer->createImage();
1662 }
1663}
1664
1665Texture3D::~Texture3D()
1666{
1667 mColorbufferProxy = NULL;
1668
1669 delete mTexStorage;
1670 mTexStorage = NULL;
1671
1672 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1673 {
1674 delete mImageArray[i];
1675 }
1676}
1677
1678void Texture3D::addProxyRef(const Renderbuffer *proxy)
1679{
1680 mProxyRefs++;
1681}
1682
1683void Texture3D::releaseProxy(const Renderbuffer *proxy)
1684{
1685 if (mProxyRefs > 0)
1686 mProxyRefs--;
1687
1688 if (mProxyRefs == 0)
1689 mColorbufferProxy = NULL;
1690}
1691
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001692GLsizei Texture3D::getWidth(GLint level) const
1693{
1694 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getWidth() : 0;
1695}
1696
1697GLsizei Texture3D::getHeight(GLint level) const
1698{
1699 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getHeight() : 0;
1700}
1701
1702GLsizei Texture3D::getDepth(GLint level) const
1703{
1704 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getDepth() : 0;
1705}
1706
1707GLenum Texture3D::getInternalFormat(GLint level) const
1708{
1709 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getInternalFormat() : GL_NONE;
1710}
1711
1712GLenum Texture3D::getActualFormat(GLint level) const
1713{
1714 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getActualFormat() : D3DFMT_UNKNOWN;
1715}
1716
1717bool Texture3D::isCompressed(GLint level) const
1718{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001719 return IsFormatCompressed(getInternalFormat(level), mRenderer->getCurrentClientVersion());
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001720}
1721
1722bool Texture3D::isDepth(GLint level) const
1723{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001724 return GetDepthBits(getInternalFormat(level), mRenderer->getCurrentClientVersion()) > 0;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001725}
1726
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001727void Texture3D::setImage(GLint level, GLsizei width, GLsizei height, GLsizei depth, GLint internalFormat, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001728{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001729 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1730 GLint sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
1731 : GetSizedInternalFormat(format, type, clientVersion);
1732 redefineImage(level, sizedInternalFormat, width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001733
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001734 Texture::setImage(unpackAlignment, type, pixels, mImageArray[level]);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001735}
1736
1737void Texture3D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
1738{
1739 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1740 redefineImage(level, format, width, height, depth);
1741
1742 Texture::setCompressedImage(imageSize, pixels, mImageArray[level]);
1743}
1744
1745void 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)
1746{
1747 if (Texture::subImage(xoffset, yoffset, zoffset, width, height, depth, format, type, unpackAlignment, pixels, mImageArray[level]))
1748 {
1749 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1750 }
1751}
1752
1753void Texture3D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
1754{
1755 if (Texture::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth, format, imageSize, pixels, mImageArray[level]))
1756 {
1757 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1758 }
1759}
1760
1761void Texture3D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
1762{
1763 delete mTexStorage;
1764 mTexStorage = new rx::TextureStorageInterface3D(mRenderer, levels, internalformat, mUsage, width, height, depth);
1765 mImmutable = true;
1766
1767 for (int level = 0; level < levels; level++)
1768 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001769 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, true);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001770 width = std::max(1, width >> 1);
1771 height = std::max(1, height >> 1);
1772 depth = std::max(1, depth >> 1);
1773 }
1774
1775 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1776 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001777 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, GL_NONE, 0, 0, 0, true);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001778 }
1779
1780 if (mTexStorage->isManaged())
1781 {
1782 int levels = levelCount();
1783
1784 for (int level = 0; level < levels; level++)
1785 {
1786 mImageArray[level]->setManagedSurface(mTexStorage, level);
1787 }
1788 }
1789}
1790
1791
1792void Texture3D::generateMipmaps()
1793{
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001794 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1795 unsigned int q = log2(std::max(mImageArray[0]->getWidth(), mImageArray[0]->getHeight()));
1796 for (unsigned int i = 1; i <= q; i++)
1797 {
1798 redefineImage(i, mImageArray[0]->getInternalFormat(),
1799 std::max(mImageArray[0]->getWidth() >> i, 1),
1800 std::max(mImageArray[0]->getHeight() >> i, 1),
1801 std::max(mImageArray[0]->getDepth() >> i, 1));
1802 }
1803
1804 if (mTexStorage && mTexStorage->isRenderTarget())
1805 {
1806 for (unsigned int i = 1; i <= q; i++)
1807 {
1808 mTexStorage->generateMipmap(i);
1809
1810 mImageArray[i]->markClean();
1811 }
1812 }
1813 else
1814 {
1815 for (unsigned int i = 1; i <= q; i++)
1816 {
1817 mRenderer->generateMipmap(mImageArray[i], mImageArray[i - 1]);
1818 }
1819 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001820}
1821
1822void Texture3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1823{
1824 if (xoffset + width > mImageArray[level]->getWidth() || yoffset + height > mImageArray[level]->getHeight() || zoffset >= mImageArray[level]->getDepth())
1825 {
1826 return gl::error(GL_INVALID_VALUE);
1827 }
1828
Jamie Madill07edd442013-07-19 16:36:58 -04001829 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
1830 // the current level we're copying to is defined (with appropriate format, width & height)
1831 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
1832
1833 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001834 {
1835 mImageArray[level]->copy(xoffset, yoffset, zoffset, x, y, width, height, source);
1836 mDirtyImages = true;
1837 }
1838 else
1839 {
1840 if (!mTexStorage || !mTexStorage->isRenderTarget())
1841 {
1842 convertToRenderTarget();
1843 }
1844
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001845 if (level < levelCount())
1846 {
Jamie Madill07edd442013-07-19 16:36:58 -04001847 updateTextureLevel(level);
1848
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001849 gl::Rectangle sourceRect;
1850 sourceRect.x = x;
1851 sourceRect.width = width;
1852 sourceRect.y = y;
1853 sourceRect.height = height;
1854
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001855 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1856
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001857 mRenderer->copyImage(source, sourceRect,
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001858 gl::GetFormat(mImageArray[0]->getInternalFormat(), clientVersion),
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001859 xoffset, yoffset, zoffset, mTexStorage, level);
1860 }
1861 }
1862}
1863
Jamie Madillf8989902013-07-19 16:36:58 -04001864bool Texture3D::isSamplerComplete(const SamplerState &samplerState) const
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001865{
1866 GLsizei width = mImageArray[0]->getWidth();
1867 GLsizei height = mImageArray[0]->getHeight();
1868 GLsizei depth = mImageArray[0]->getDepth();
1869
1870 if (width <= 0 || height <= 0 || depth <= 0)
1871 {
1872 return false;
1873 }
1874
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001875 if (!IsTextureFilteringSupported(getInternalFormat(0), mRenderer))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001876 {
Jamie Madillf8989902013-07-19 16:36:58 -04001877 if (samplerState.magFilter != GL_NEAREST ||
1878 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001879 {
1880 return false;
1881 }
1882 }
1883
Jamie Madillf8989902013-07-19 16:36:58 -04001884 if (IsMipmapFiltered(samplerState) && !isMipmapComplete())
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001885 {
1886 return false;
1887 }
1888
1889 return true;
1890}
1891
1892bool Texture3D::isMipmapComplete() const
1893{
Jamie Madill07edd442013-07-19 16:36:58 -04001894 GLsizei width = mImageArray[0]->getWidth();
1895 GLsizei height = mImageArray[0]->getHeight();
1896 GLsizei depth = mImageArray[0]->getDepth();
1897
1898 int q = log2(std::max(std::max(width, height), depth));
1899
1900 for (int level = 0; level <= q; level++)
1901 {
1902 if (!isLevelComplete(level))
1903 {
1904 return false;
1905 }
1906 }
1907
1908 return true;
1909}
1910
1911bool Texture3D::isLevelComplete(int level) const
1912{
1913 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1914
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001915 if (isImmutable())
1916 {
1917 return true;
1918 }
1919
Jamie Madill07edd442013-07-19 16:36:58 -04001920 rx::Image *baseImage = mImageArray[0];
1921
1922 GLsizei width = baseImage->getWidth();
1923 GLsizei height = baseImage->getHeight();
1924 GLsizei depth = baseImage->getDepth();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001925
1926 if (width <= 0 || height <= 0 || depth <= 0)
1927 {
1928 return false;
1929 }
1930
Jamie Madill07edd442013-07-19 16:36:58 -04001931 if (level == 0)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001932 {
Jamie Madill07edd442013-07-19 16:36:58 -04001933 return true;
1934 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001935
Jamie Madill07edd442013-07-19 16:36:58 -04001936 rx::Image *levelImage = mImageArray[level];
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001937
Jamie Madill07edd442013-07-19 16:36:58 -04001938 if (levelImage->getInternalFormat() != baseImage->getInternalFormat())
1939 {
1940 return false;
1941 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001942
Jamie Madill07edd442013-07-19 16:36:58 -04001943 if (levelImage->getWidth() != std::max(1, width >> level))
1944 {
1945 return false;
1946 }
1947
1948 if (levelImage->getHeight() != std::max(1, height >> level))
1949 {
1950 return false;
1951 }
1952
1953 if (levelImage->getDepth() != std::max(1, depth >> level))
1954 {
1955 return false;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001956 }
1957
1958 return true;
1959}
1960
1961Renderbuffer *Texture3D::getRenderbuffer(GLenum target)
1962{
1963 UNIMPLEMENTED();
1964 return NULL;
1965}
1966
1967int Texture3D::levelCount()
1968{
1969 return mTexStorage ? mTexStorage->levelCount() : 0;
1970}
1971
1972void Texture3D::createTexture()
1973{
1974 GLsizei width = mImageArray[0]->getWidth();
1975 GLsizei height = mImageArray[0]->getHeight();
1976 GLsizei depth = mImageArray[0]->getDepth();
1977
1978 if (!(width > 0 && height > 0 && depth > 0))
1979 return; // do not attempt to create native textures for nonexistant data
1980
1981 GLint levels = creationLevels(width, height, depth);
1982 GLenum internalformat = mImageArray[0]->getInternalFormat();
1983
1984 delete mTexStorage;
1985 mTexStorage = new rx::TextureStorageInterface3D(mRenderer, levels, internalformat, mUsage, width, height, depth);
1986
1987 if (mTexStorage->isManaged())
1988 {
1989 int levels = levelCount();
1990
1991 for (int level = 0; level < levels; level++)
1992 {
1993 mImageArray[level]->setManagedSurface(mTexStorage, level);
1994 }
1995 }
1996
1997 mDirtyImages = true;
1998}
1999
2000void Texture3D::updateTexture()
2001{
Jamie Madilleb3665c2013-07-19 16:36:57 -04002002 int levels = (isMipmapComplete() ? levelCount() : 1);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002003
2004 for (int level = 0; level < levels; level++)
2005 {
Jamie Madill07edd442013-07-19 16:36:58 -04002006 updateTextureLevel(level);
2007 }
2008}
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002009
Jamie Madill07edd442013-07-19 16:36:58 -04002010void Texture3D::updateTextureLevel(int level)
2011{
2012 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
2013
2014 rx::Image *image = mImageArray[level];
2015
2016 if (image->isDirty())
2017 {
2018 commitRect(level, 0, 0, 0, mImageArray[level]->getWidth(), mImageArray[level]->getHeight(), mImageArray[level]->getDepth());
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002019 }
2020}
2021
2022void Texture3D::convertToRenderTarget()
2023{
2024 rx::TextureStorageInterface3D *newTexStorage = NULL;
2025
2026 if (mImageArray[0]->getWidth() != 0 && mImageArray[0]->getHeight() != 0 && mImageArray[0]->getDepth() != 0)
2027 {
2028 GLsizei width = mImageArray[0]->getWidth();
2029 GLsizei height = mImageArray[0]->getHeight();
2030 GLsizei depth = mImageArray[0]->getDepth();
2031 GLint levels = mTexStorage != NULL ? mTexStorage->levelCount() : creationLevels(width, height, depth);
2032 GLenum internalformat = mImageArray[0]->getInternalFormat();
2033
2034 newTexStorage = new rx::TextureStorageInterface3D(mRenderer, levels, internalformat, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, width, height, depth);
2035
2036 if (mTexStorage != NULL)
2037 {
2038 if (!mRenderer->copyToRenderTarget(newTexStorage, mTexStorage))
2039 {
2040 delete newTexStorage;
2041 return gl::error(GL_OUT_OF_MEMORY);
2042 }
2043 }
2044 }
2045
2046 delete mTexStorage;
2047 mTexStorage = newTexStorage;
2048
2049 mDirtyImages = true;
2050}
2051
2052rx::RenderTarget *Texture3D::getRenderTarget(GLenum target)
2053{
2054 UNIMPLEMENTED();
2055 return NULL;
2056}
2057
2058rx::TextureStorageInterface *Texture3D::getStorage(bool renderTarget)
2059{
2060 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
2061 {
2062 if (renderTarget)
2063 {
2064 convertToRenderTarget();
2065 }
2066 else
2067 {
2068 createTexture();
2069 }
2070 }
2071
2072 return mTexStorage;
2073}
2074
2075void Texture3D::redefineImage(GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth)
2076{
2077 // If there currently is a corresponding storage texture image, it has these parameters
2078 const int storageWidth = std::max(1, mImageArray[0]->getWidth() >> level);
2079 const int storageHeight = std::max(1, mImageArray[0]->getHeight() >> level);
2080 const int storageDepth = std::max(1, mImageArray[0]->getDepth() >> level);
2081 const int storageFormat = mImageArray[0]->getInternalFormat();
2082
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00002083 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, false);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002084
2085 if (mTexStorage)
2086 {
2087 const int storageLevels = mTexStorage->levelCount();
2088
2089 if ((level >= storageLevels && storageLevels != 0) ||
2090 width != storageWidth ||
2091 height != storageHeight ||
2092 depth != storageDepth ||
2093 internalformat != storageFormat) // Discard mismatched storage
2094 {
2095 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
2096 {
2097 mImageArray[i]->markDirty();
2098 }
2099
2100 delete mTexStorage;
2101 mTexStorage = NULL;
2102 mDirtyImages = true;
2103 }
2104 }
2105}
2106
2107void Texture3D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth)
2108{
2109 if (level < levelCount())
2110 {
2111 rx::Image *image = mImageArray[level];
2112 if (image->updateSurface(mTexStorage, level, xoffset, yoffset, zoffset, width, height, depth))
2113 {
2114 image->markClean();
2115 }
2116 }
2117}
2118
Geoff Lang4907f2c2013-07-25 12:53:57 -04002119Texture2DArray::Texture2DArray(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_2D_ARRAY)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002120{
2121 mTexStorage = NULL;
2122 mColorbufferProxy = NULL;
2123 mProxyRefs = 0;
2124
2125 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2126 {
2127 mLayerCounts[level] = 0;
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002128 mImageArray[level] = NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002129 }
2130}
2131
2132Texture2DArray::~Texture2DArray()
2133{
2134 mColorbufferProxy = NULL;
2135
2136 delete mTexStorage;
2137 mTexStorage = NULL;
2138 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2139 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002140 for (int layer = 0; layer < mLayerCounts[level]; ++layer)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002141 {
2142 delete mImageArray[level][layer];
2143 }
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002144 delete[] mImageArray[level];
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002145 }
2146}
2147
2148void Texture2DArray::addProxyRef(const Renderbuffer *proxy)
2149{
2150 mProxyRefs++;
2151}
2152
2153void Texture2DArray::releaseProxy(const Renderbuffer *proxy)
2154{
2155 if (mProxyRefs > 0)
2156 mProxyRefs--;
2157
2158 if (mProxyRefs == 0)
2159 mColorbufferProxy = NULL;
2160}
2161
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002162GLsizei Texture2DArray::getWidth(GLint level) const
2163{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002164 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getWidth() : 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002165}
2166
2167GLsizei Texture2DArray::getHeight(GLint level) const
2168{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002169 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getHeight() : 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002170}
2171
2172GLsizei Texture2DArray::getDepth(GLint level) const
2173{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002174 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mLayerCounts[level] : 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002175}
2176
2177GLenum Texture2DArray::getInternalFormat(GLint level) const
2178{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002179 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getInternalFormat() : GL_NONE;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002180}
2181
2182GLenum Texture2DArray::getActualFormat(GLint level) const
2183{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002184 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getActualFormat() : D3DFMT_UNKNOWN;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002185}
2186
2187bool Texture2DArray::isCompressed(GLint level) const
2188{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00002189 return IsFormatCompressed(getInternalFormat(level), mRenderer->getCurrentClientVersion());
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002190}
2191
2192bool Texture2DArray::isDepth(GLint level) const
2193{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00002194 return GetDepthBits(getInternalFormat(level), mRenderer->getCurrentClientVersion()) > 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002195}
2196
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00002197void Texture2DArray::setImage(GLint level, GLsizei width, GLsizei height, GLsizei depth, GLint internalFormat, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002198{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00002199 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2200 GLint sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
2201 : GetSizedInternalFormat(format, type, clientVersion);
2202 redefineImage(level, sizedInternalFormat, width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002203
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002204 GLsizei inputDepthPitch = gl::GetDepthPitch(sizedInternalFormat, type, clientVersion, width, height, unpackAlignment);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002205
2206 for (int i = 0; i < depth; i++)
2207 {
2208 const void *layerPixels = reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i);
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002209 Texture::setImage(unpackAlignment, type, layerPixels, mImageArray[level][i]);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002210 }
2211}
2212
2213void Texture2DArray::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
2214{
2215 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
2216 redefineImage(level, format, width, height, depth);
2217
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002218 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2219 GLsizei inputDepthPitch = gl::GetDepthPitch(format, GL_UNSIGNED_BYTE, clientVersion, width, height, 1);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002220
2221 for (int i = 0; i < depth; i++)
2222 {
2223 const void *layerPixels = reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i);
2224 Texture::setCompressedImage(imageSize, layerPixels, mImageArray[level][i]);
2225 }
2226}
2227
2228void 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)
2229{
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002230 GLint internalformat = getInternalFormat(level);
2231 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2232 GLsizei inputDepthPitch = gl::GetDepthPitch(internalformat, type, width, height, clientVersion, unpackAlignment);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002233
2234 for (int i = 0; i < depth; i++)
2235 {
2236 int layer = zoffset + i;
2237 const void *layerPixels = reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i);
2238
2239 if (Texture::subImage(xoffset, yoffset, zoffset, width, height, 1, format, type, unpackAlignment, layerPixels, mImageArray[level][layer]))
2240 {
2241 commitRect(level, xoffset, yoffset, layer, width, height);
2242 }
2243 }
2244}
2245
2246void Texture2DArray::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
2247{
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002248 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2249 GLsizei inputDepthPitch = gl::GetDepthPitch(format, GL_UNSIGNED_BYTE, clientVersion, width, height, 1);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002250
2251 for (int i = 0; i < depth; i++)
2252 {
2253 int layer = zoffset + i;
2254 const void *layerPixels = reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i);
2255
2256 if (Texture::subImageCompressed(xoffset, yoffset, zoffset, width, height, 1, format, imageSize, layerPixels, mImageArray[level][layer]))
2257 {
2258 commitRect(level, xoffset, yoffset, layer, width, height);
2259 }
2260 }
2261}
2262
2263void Texture2DArray::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2264{
2265 delete mTexStorage;
2266 mTexStorage = new rx::TextureStorageInterface2DArray(mRenderer, levels, internalformat, mUsage, width, height, depth);
2267 mImmutable = true;
2268
2269 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2270 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002271 GLsizei levelWidth = std::max(width >> level, 1);
2272 GLsizei levelHeight = std::max(width >> level, 1);
2273
2274 // Clear this level
2275 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002276 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002277 delete mImageArray[level][layer];
2278 }
2279 delete[] mImageArray[level];
2280 mImageArray[level] = NULL;
2281 mLayerCounts[level] = 0;
2282
2283 if (level < levels)
2284 {
2285 // Create new images for this level
2286 mImageArray[level] = new rx::Image*[depth]();
2287 mLayerCounts[level] = depth;
2288
2289 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002290 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002291 mImageArray[level][layer] = mRenderer->createImage();
2292 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, levelWidth,
2293 levelHeight, 1, true);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002294 }
2295 }
2296 }
2297
2298 if (mTexStorage->isManaged())
2299 {
2300 int levels = levelCount();
2301
2302 for (int level = 0; level < levels; level++)
2303 {
2304 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2305 {
2306 mImageArray[level][layer]->setManagedSurface(mTexStorage, layer, level);
2307 }
2308 }
2309 }
2310}
2311
2312void Texture2DArray::generateMipmaps()
2313{
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00002314 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
2315 int q = log2(std::max(getWidth(0), getHeight(0)));
2316 for (int i = 1; i <= q; i++)
2317 {
2318 redefineImage(i, getInternalFormat(0), std::max(getWidth(0) >> i, 1), std::max(getHeight(0) >> i, 1), getDepth(0));
2319 }
2320
2321 if (mTexStorage && mTexStorage->isRenderTarget())
2322 {
2323 for (int level = 1; level <= q; level++)
2324 {
2325 mTexStorage->generateMipmap(level);
2326
2327 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2328 {
2329 mImageArray[level][layer]->markClean();
2330 }
2331 }
2332 }
2333 else
2334 {
2335 for (int level = 1; level <= q; level++)
2336 {
2337 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2338 {
2339 mRenderer->generateMipmap(mImageArray[level][layer], mImageArray[level - 1][layer]);
2340 }
2341 }
2342 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002343}
2344
2345void Texture2DArray::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
2346{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002347 if (xoffset + width > getWidth(level) || yoffset + height > getHeight(level) || zoffset >= getDepth(level) || getDepth(level) == 0)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002348 {
2349 return gl::error(GL_INVALID_VALUE);
2350 }
2351
Jamie Madill07edd442013-07-19 16:36:58 -04002352 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
2353 // the current level we're copying to is defined (with appropriate format, width & height)
2354 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
2355
2356 if (!mImageArray[level][0]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002357 {
2358 mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, x, y, width, height, source);
2359 mDirtyImages = true;
2360 }
2361 else
2362 {
2363 if (!mTexStorage || !mTexStorage->isRenderTarget())
2364 {
2365 convertToRenderTarget();
2366 }
2367
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002368 if (level < levelCount())
2369 {
Jamie Madill07edd442013-07-19 16:36:58 -04002370 updateTextureLevel(level);
2371
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002372 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2373
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002374 gl::Rectangle sourceRect;
2375 sourceRect.x = x;
2376 sourceRect.width = width;
2377 sourceRect.y = y;
2378 sourceRect.height = height;
2379
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002380 mRenderer->copyImage(source, sourceRect, gl::GetFormat(getInternalFormat(0), clientVersion),
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002381 xoffset, yoffset, zoffset, mTexStorage, level);
2382 }
2383 }
2384}
2385
Jamie Madillf8989902013-07-19 16:36:58 -04002386bool Texture2DArray::isSamplerComplete(const SamplerState &samplerState) const
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002387{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002388 GLsizei width = getWidth(0);
2389 GLsizei height = getHeight(0);
2390 GLsizei depth = getDepth(0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002391
2392 if (width <= 0 || height <= 0 || depth <= 0)
2393 {
2394 return false;
2395 }
2396
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00002397 if (!IsTextureFilteringSupported(getInternalFormat(0), mRenderer))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002398 {
Jamie Madillf8989902013-07-19 16:36:58 -04002399 if (samplerState.magFilter != GL_NEAREST ||
2400 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002401 {
2402 return false;
2403 }
2404 }
2405
Jamie Madillf8989902013-07-19 16:36:58 -04002406 if (IsMipmapFiltered(samplerState) && !isMipmapComplete())
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002407 {
2408 return false;
2409 }
2410
2411 return true;
2412}
2413
2414bool Texture2DArray::isMipmapComplete() const
2415{
Jamie Madill07edd442013-07-19 16:36:58 -04002416 GLsizei width = getWidth(0);
2417 GLsizei height = getHeight(0);
2418
2419 int q = log2(std::max(width, height));
2420
2421 for (int level = 1; level <= q; level++)
2422 {
2423 if (!isLevelComplete(level))
2424 {
2425 return false;
2426 }
2427 }
2428
2429 return true;
2430}
2431
2432bool Texture2DArray::isLevelComplete(int level) const
2433{
2434 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
2435
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002436 if (isImmutable())
2437 {
2438 return true;
2439 }
2440
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002441 GLsizei width = getWidth(0);
2442 GLsizei height = getHeight(0);
2443 GLsizei depth = getDepth(0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002444
2445 if (width <= 0 || height <= 0 || depth <= 0)
2446 {
2447 return false;
2448 }
2449
Jamie Madill07edd442013-07-19 16:36:58 -04002450 if (level == 0)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002451 {
Jamie Madill07edd442013-07-19 16:36:58 -04002452 return true;
2453 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002454
Jamie Madill07edd442013-07-19 16:36:58 -04002455 if (getInternalFormat(level) != getInternalFormat(0))
2456 {
2457 return false;
2458 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002459
Jamie Madill07edd442013-07-19 16:36:58 -04002460 if (getWidth(level) != std::max(1, width >> level))
2461 {
2462 return false;
2463 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002464
Jamie Madill07edd442013-07-19 16:36:58 -04002465 if (getHeight(level) != std::max(1, height >> level))
2466 {
2467 return false;
2468 }
2469
2470 if (getDepth(level) != depth)
2471 {
2472 return false;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002473 }
2474
2475 return true;
2476}
2477
2478Renderbuffer *Texture2DArray::getRenderbuffer(GLenum target)
2479{
2480 UNIMPLEMENTED();
2481 return NULL;
2482}
2483
2484int Texture2DArray::levelCount()
2485{
2486 return mTexStorage ? mTexStorage->levelCount() : 0;
2487}
2488
2489void Texture2DArray::createTexture()
2490{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002491 GLsizei width = getWidth(0);
2492 GLsizei height = getHeight(0);
2493 GLsizei depth = getDepth(0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002494
2495 if (width <= 0 || height <= 0 || depth <= 0)
2496 {
2497 return; // do not attempt to create native textures for nonexistant data
2498 }
2499
2500 GLint levels = creationLevels(width, height);
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002501 GLenum internalformat = getInternalFormat(0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002502
2503 delete mTexStorage;
2504 mTexStorage = new rx::TextureStorageInterface2DArray(mRenderer, levels, internalformat, mUsage, width, height, depth);
2505
2506 if (mTexStorage->isManaged())
2507 {
2508 int levels = levelCount();
2509 for (int level = 0; level < levels; level++)
2510 {
2511 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2512 {
2513 mImageArray[level][layer]->setManagedSurface(mTexStorage, layer, level);
2514 }
2515 }
2516 }
2517
2518 mDirtyImages = true;
2519}
2520
2521void Texture2DArray::updateTexture()
2522{
Jamie Madilleb3665c2013-07-19 16:36:57 -04002523 int levels = (isMipmapComplete() ? levelCount() : 1);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002524 for (int level = 0; level < levels; level++)
2525 {
Jamie Madill07edd442013-07-19 16:36:58 -04002526 updateTextureLevel(level);
2527 }
2528}
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002529
Jamie Madill07edd442013-07-19 16:36:58 -04002530void Texture2DArray::updateTextureLevel(int level)
2531{
2532 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2533 {
2534 rx::Image *image = mImageArray[level][layer];
2535
2536 if (image->isDirty())
2537 {
2538 commitRect(level, 0, 0, layer, image->getWidth(), image->getHeight());
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002539 }
2540 }
2541}
2542
2543void Texture2DArray::convertToRenderTarget()
2544{
2545 rx::TextureStorageInterface2DArray *newTexStorage = NULL;
2546
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002547 GLsizei width = getWidth(0);
2548 GLsizei height = getHeight(0);
2549 GLsizei depth = getDepth(0);
2550
2551 if (width != 0 && height != 0 && depth != 0)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002552 {
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002553 GLint levels = mTexStorage != NULL ? mTexStorage->levelCount() : creationLevels(width, height);
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002554 GLenum internalformat = getInternalFormat(0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002555
2556 newTexStorage = new rx::TextureStorageInterface2DArray(mRenderer, levels, internalformat, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, width, height, depth);
2557
2558 if (mTexStorage != NULL)
2559 {
2560 if (!mRenderer->copyToRenderTarget(newTexStorage, mTexStorage))
2561 {
2562 delete newTexStorage;
2563 return gl::error(GL_OUT_OF_MEMORY);
2564 }
2565 }
2566 }
2567
2568 delete mTexStorage;
2569 mTexStorage = newTexStorage;
2570
2571 mDirtyImages = true;
2572}
2573
2574rx::RenderTarget *Texture2DArray::getRenderTarget(GLenum target)
2575{
2576 UNIMPLEMENTED();
2577 return NULL;
2578}
2579
2580rx::TextureStorageInterface *Texture2DArray::getStorage(bool renderTarget)
2581{
2582 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
2583 {
2584 if (renderTarget)
2585 {
2586 convertToRenderTarget();
2587 }
2588 else
2589 {
2590 createTexture();
2591 }
2592 }
2593
2594 return mTexStorage;
2595}
2596
2597void Texture2DArray::redefineImage(GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth)
2598{
2599 // If there currently is a corresponding storage texture image, it has these parameters
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002600 const int storageWidth = std::max(1, getWidth(0) >> level);
2601 const int storageHeight = std::max(1, getHeight(0) >> level);
2602 const int storageDepth = getDepth(0);
2603 const int storageFormat = getInternalFormat(0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002604
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002605 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002606 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002607 delete mImageArray[level][layer];
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002608 }
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002609 delete[] mImageArray[level];
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002610
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002611 mImageArray[level] = new rx::Image*[depth]();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002612 mLayerCounts[level] = depth;
2613
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002614 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2615 {
2616 mImageArray[level][layer] = mRenderer->createImage();
2617 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, width, height, 1, false);
2618 }
2619
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002620 if (mTexStorage)
2621 {
2622 const int storageLevels = mTexStorage->levelCount();
2623
2624 if ((level >= storageLevels && storageLevels != 0) ||
2625 width != storageWidth ||
2626 height != storageHeight ||
2627 depth != storageDepth ||
2628 internalformat != storageFormat) // Discard mismatched storage
2629 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002630 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002631 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002632 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002633 {
2634 mImageArray[level][layer]->markDirty();
2635 }
2636 }
2637
2638 delete mTexStorage;
2639 mTexStorage = NULL;
2640 mDirtyImages = true;
2641 }
2642 }
2643}
2644
2645void Texture2DArray::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint layerTarget, GLsizei width, GLsizei height)
2646{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002647 if (level < levelCount() && layerTarget < getDepth(level))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002648 {
2649 rx::Image *image = mImageArray[level][layerTarget];
2650 if (image->updateSurface(mTexStorage, level, xoffset, yoffset, layerTarget, width, height))
2651 {
2652 image->markClean();
2653 }
2654 }
2655}
2656
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00002657}