blob: cc79d2516562ee3e199f9f80edf686a5ca8598cd [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"
shannon.woods@transgaming.com486d9e92013-02-28 23:15:41 +000018#include "libGLESv2/Renderbuffer.h"
19#include "libGLESv2/renderer/Image.h"
20#include "libGLESv2/renderer/Renderer.h"
21#include "libGLESv2/renderer/TextureStorage.h"
22#include "libEGL/Surface.h"
Jamie Madill1beb1db2013-09-18 14:36:28 -040023#include "libGLESv2/Buffer.h"
24#include "libGLESv2/renderer/BufferStorage.h"
Jamie Madill0e0510f2013-10-10 15:46:23 -040025#include "libGLESv2/renderer/RenderTarget.h"
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000026
27namespace gl
28{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000029
Jamie Madillf8989902013-07-19 16:36:58 -040030bool IsMipmapFiltered(const SamplerState &samplerState)
31{
32 switch (samplerState.minFilter)
33 {
34 case GL_NEAREST:
35 case GL_LINEAR:
36 return false;
37 case GL_NEAREST_MIPMAP_NEAREST:
38 case GL_LINEAR_MIPMAP_NEAREST:
39 case GL_NEAREST_MIPMAP_LINEAR:
40 case GL_LINEAR_MIPMAP_LINEAR:
41 return true;
42 default: UNREACHABLE();
43 return false;
44 }
45}
46
Jamie Madilld4589c92013-10-24 17:49:34 -040047bool IsRenderTargetUsage(GLenum usage)
48{
49 return (usage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
50}
51
Geoff Lang4907f2c2013-07-25 12:53:57 -040052Texture::Texture(rx::Renderer *renderer, GLuint id, GLenum target) : RefCountObject(id)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000053{
daniel@transgaming.com370482e2012-11-28 19:32:13 +000054 mRenderer = renderer;
55
daniel@transgaming.comebf139f2012-10-31 18:07:32 +000056 mSamplerState.minFilter = GL_NEAREST_MIPMAP_LINEAR;
57 mSamplerState.magFilter = GL_LINEAR;
58 mSamplerState.wrapS = GL_REPEAT;
59 mSamplerState.wrapT = GL_REPEAT;
shannon.woods%transgaming.com@gtempaccount.com0b3a8df2013-04-13 03:44:51 +000060 mSamplerState.wrapR = GL_REPEAT;
daniel@transgaming.comebf139f2012-10-31 18:07:32 +000061 mSamplerState.maxAnisotropy = 1.0f;
62 mSamplerState.lodOffset = 0;
Geoff Langc82fc412013-07-10 14:43:42 -040063 mSamplerState.compareMode = GL_NONE;
64 mSamplerState.compareFunc = GL_LEQUAL;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000065 mUsage = GL_NONE;
Geoff Langc82fc412013-07-10 14:43:42 -040066
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000067 mDirtyImages = true;
68
69 mImmutable = false;
Geoff Lang4907f2c2013-07-25 12:53:57 -040070
71 mTarget = target;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000072}
73
74Texture::~Texture()
75{
76}
77
Geoff Lang4907f2c2013-07-25 12:53:57 -040078GLenum Texture::getTarget() const
79{
80 return mTarget;
81}
82
Geoff Lang8040f572013-07-25 16:49:54 -040083void Texture::addProxyRef(const Renderbuffer *proxy)
84{
85 mRenderbufferProxies.addRef(proxy);
86}
87
88void Texture::releaseProxy(const Renderbuffer *proxy)
89{
90 mRenderbufferProxies.release(proxy);
91}
92
Geoff Lang63b5f1f2013-09-23 14:52:14 -040093void Texture::setMinFilter(GLenum filter)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000094{
Geoff Lang63b5f1f2013-09-23 14:52:14 -040095 mSamplerState.minFilter = filter;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000096}
97
Geoff Lang63b5f1f2013-09-23 14:52:14 -040098void Texture::setMagFilter(GLenum filter)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000099{
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400100 mSamplerState.magFilter = filter;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000101}
102
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400103void Texture::setWrapS(GLenum wrap)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000104{
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400105 mSamplerState.wrapS = wrap;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000106}
107
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400108void Texture::setWrapT(GLenum wrap)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000109{
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400110 mSamplerState.wrapT = wrap;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000111}
112
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400113void Texture::setWrapR(GLenum wrap)
shannon.woods%transgaming.com@gtempaccount.com0b3a8df2013-04-13 03:44:51 +0000114{
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400115 mSamplerState.wrapR = wrap;
shannon.woods%transgaming.com@gtempaccount.com0b3a8df2013-04-13 03:44:51 +0000116}
117
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400118void Texture::setMaxAnisotropy(float textureMaxAnisotropy, float contextMaxAnisotropy)
daniel@transgaming.com07ab8412012-07-12 15:17:09 +0000119{
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400120 mSamplerState.maxAnisotropy = std::min(textureMaxAnisotropy, contextMaxAnisotropy);
daniel@transgaming.com07ab8412012-07-12 15:17:09 +0000121}
122
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400123void Texture::setCompareMode(GLenum mode)
Geoff Langc82fc412013-07-10 14:43:42 -0400124{
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400125 mSamplerState.compareMode = mode;
Geoff Langc82fc412013-07-10 14:43:42 -0400126}
127
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400128void Texture::setCompareFunc(GLenum func)
Geoff Langc82fc412013-07-10 14:43:42 -0400129{
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400130 mSamplerState.compareFunc = func;
Geoff Langc82fc412013-07-10 14:43:42 -0400131}
132
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400133void Texture::setUsage(GLenum usage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000134{
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400135 mUsage = usage;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000136}
137
138GLenum Texture::getMinFilter() const
139{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000140 return mSamplerState.minFilter;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000141}
142
143GLenum Texture::getMagFilter() const
144{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000145 return mSamplerState.magFilter;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000146}
147
148GLenum Texture::getWrapS() const
149{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000150 return mSamplerState.wrapS;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000151}
152
153GLenum Texture::getWrapT() const
154{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000155 return mSamplerState.wrapT;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000156}
157
shannon.woods%transgaming.com@gtempaccount.com0b3a8df2013-04-13 03:44:51 +0000158GLenum Texture::getWrapR() const
159{
160 return mSamplerState.wrapR;
161}
162
daniel@transgaming.com07ab8412012-07-12 15:17:09 +0000163float Texture::getMaxAnisotropy() const
164{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000165 return mSamplerState.maxAnisotropy;
166}
167
168int Texture::getLodOffset()
169{
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000170 rx::TextureStorageInterface *texture = getStorage(false);
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000171 return texture ? texture->getLodOffset() : 0;
172}
173
174void Texture::getSamplerState(SamplerState *sampler)
175{
176 *sampler = mSamplerState;
177 sampler->lodOffset = getLodOffset();
daniel@transgaming.com07ab8412012-07-12 15:17:09 +0000178}
179
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000180GLenum Texture::getUsage() const
181{
182 return mUsage;
183}
184
Jamie Madilld3d2a342013-10-07 10:46:35 -0400185GLint Texture::getBaseLevelWidth() const
186{
187 const rx::Image *baseImage = getBaseLevelImage();
188 return (baseImage ? baseImage->getWidth() : 0);
189}
190
191GLint Texture::getBaseLevelHeight() const
192{
193 const rx::Image *baseImage = getBaseLevelImage();
194 return (baseImage ? baseImage->getHeight() : 0);
195}
196
197GLint Texture::getBaseLevelDepth() const
198{
199 const rx::Image *baseImage = getBaseLevelImage();
200 return (baseImage ? baseImage->getDepth() : 0);
201}
202
203GLenum Texture::getBaseLevelInternalFormat() const
204{
205 const rx::Image *baseImage = getBaseLevelImage();
206 return (baseImage ? baseImage->getInternalFormat() : GL_NONE);
207}
208
Jamie Madill88f18f42013-09-18 14:36:19 -0400209void Texture::setImage(const PixelUnpackState &unpack, GLenum type, const void *pixels, rx::Image *image)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000210{
Jamie Madillabef6802013-09-05 16:54:19 -0400211 // We no longer need the "GLenum format" parameter to TexImage to determine what data format "pixels" contains.
212 // From our image internal format we know how many channels to expect, and "type" gives the format of pixel's components.
Jamie Madill1beb1db2013-09-18 14:36:28 -0400213 const void *pixelData = pixels;
214
215 if (unpack.pixelBuffer.id() != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000216 {
Jamie Madill1beb1db2013-09-18 14:36:28 -0400217 // Do a CPU readback here, if we have an unpack buffer bound and the fast GPU path is not supported
218 Buffer *pixelBuffer = unpack.pixelBuffer.get();
219 ptrdiff_t offset = reinterpret_cast<ptrdiff_t>(pixels);
220 const void *bufferData = pixelBuffer->getStorage()->getData();
221 pixelData = static_cast<const unsigned char *>(bufferData) + offset;
222 }
223
224 if (pixelData != NULL)
225 {
226 image->loadData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), unpack.alignment, type, pixelData);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000227 mDirtyImages = true;
228 }
229}
230
Geoff Lang005df412013-10-16 14:12:50 -0400231bool Texture::isFastUnpackable(const PixelUnpackState &unpack, GLenum sizedInternalFormat)
Jamie Madill8cc7d972013-10-10 15:51:55 -0400232{
233 return unpack.pixelBuffer.id() != 0 && mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat);
234}
235
Jamie Madill1beb1db2013-09-18 14:36:28 -0400236bool Texture::fastUnpackPixels(const PixelUnpackState &unpack, const void *pixels, const Box &destArea,
Jamie Madill8cc7d972013-10-10 15:51:55 -0400237 GLenum sizedInternalFormat, GLenum type, rx::RenderTarget *destRenderTarget)
Jamie Madill1beb1db2013-09-18 14:36:28 -0400238{
239 if (destArea.width <= 0 && destArea.height <= 0 && destArea.depth <= 0)
240 {
241 return true;
242 }
243
244 // In order to perform the fast copy through the shader, we must have the right format, and be able
245 // to create a render target.
Jamie Madill8cc7d972013-10-10 15:51:55 -0400246 ASSERT(mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat));
Jamie Madill1beb1db2013-09-18 14:36:28 -0400247
Jamie Madill8cc7d972013-10-10 15:51:55 -0400248 unsigned int offset = reinterpret_cast<unsigned int>(pixels);
Jamie Madill1beb1db2013-09-18 14:36:28 -0400249
Jamie Madill8cc7d972013-10-10 15:51:55 -0400250 return mRenderer->fastCopyBufferToTexture(unpack, offset, destRenderTarget, sizedInternalFormat, type, destArea);
Jamie Madill1beb1db2013-09-18 14:36:28 -0400251}
252
daniel@transgaming.com31b13e12012-11-28 19:34:30 +0000253void Texture::setCompressedImage(GLsizei imageSize, const void *pixels, rx::Image *image)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000254{
255 if (pixels != NULL)
256 {
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000257 image->loadCompressedData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000258 mDirtyImages = true;
259 }
260}
261
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000262bool Texture::subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
Jamie Madill88f18f42013-09-18 14:36:19 -0400263 GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels, rx::Image *image)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000264{
Jamie Madill065e1a32013-10-10 15:11:50 -0400265 const void *pixelData = pixels;
266
267 // CPU readback & copy where direct GPU copy is not supported
268 if (unpack.pixelBuffer.id() != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000269 {
Jamie Madill065e1a32013-10-10 15:11:50 -0400270 Buffer *pixelBuffer = unpack.pixelBuffer.get();
271 unsigned int offset = reinterpret_cast<unsigned int>(pixels);
272 const void *bufferData = pixelBuffer->getStorage()->getData();
273 pixelData = static_cast<const unsigned char *>(bufferData) + offset;
274 }
275
276 if (pixelData != NULL)
277 {
278 image->loadData(xoffset, yoffset, zoffset, width, height, depth, unpack.alignment, type, pixelData);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000279 mDirtyImages = true;
280 }
281
282 return true;
283}
284
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000285bool Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
286 GLenum format, GLsizei imageSize, const void *pixels, rx::Image *image)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000287{
288 if (pixels != NULL)
289 {
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000290 image->loadCompressedData(xoffset, yoffset, zoffset, width, height, depth, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000291 mDirtyImages = true;
292 }
293
294 return true;
295}
296
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000297rx::TextureStorageInterface *Texture::getNativeTexture()
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000298{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000299 // ensure the underlying texture is created
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000300
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000301 rx::TextureStorageInterface *storage = getStorage(false);
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000302 if (storage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000303 {
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000304 updateTexture();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000305 }
306
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000307 return storage;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000308}
309
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000310bool Texture::hasDirtyImages() const
311{
312 return mDirtyImages;
313}
314
315void Texture::resetDirty()
316{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000317 mDirtyImages = false;
318}
319
320unsigned int Texture::getTextureSerial()
321{
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000322 rx::TextureStorageInterface *texture = getStorage(false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000323 return texture ? texture->getTextureSerial() : 0;
324}
325
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000326bool Texture::isImmutable() const
327{
328 return mImmutable;
329}
330
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +0000331GLint Texture::creationLevels(GLsizei width, GLsizei height, GLsizei depth) const
332{
333 // NPOT checks are not required in ES 3.0, NPOT texture support is assumed.
334 return 0; // Maximum number of levels
335}
336
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000337GLint Texture::creationLevels(GLsizei width, GLsizei height) const
338{
daniel@transgaming.comea32d482012-11-28 19:33:18 +0000339 if ((isPow2(width) && isPow2(height)) || mRenderer->getNonPower2TextureSupport())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000340 {
341 return 0; // Maximum number of levels
342 }
343 else
344 {
345 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
346 return 1;
347 }
348}
349
350GLint Texture::creationLevels(GLsizei size) const
351{
352 return creationLevels(size, size);
353}
354
Jamie Madill22f843a2013-10-24 17:49:36 -0400355int Texture::mipLevels() const
356{
357 return log2(std::max(std::max(getBaseLevelWidth(), getBaseLevelHeight()), getBaseLevelDepth()));
358}
359
Geoff Lang4907f2c2013-07-25 12:53:57 -0400360Texture2D::Texture2D(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_2D)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000361{
362 mTexStorage = NULL;
363 mSurface = NULL;
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000364
365 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
366 {
daniel@transgaming.com244e1832012-12-20 20:52:35 +0000367 mImageArray[i] = renderer->createImage();
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000368 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000369}
370
371Texture2D::~Texture2D()
372{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000373 delete mTexStorage;
374 mTexStorage = NULL;
375
376 if (mSurface)
377 {
378 mSurface->setBoundTexture(NULL);
379 mSurface = NULL;
380 }
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000381
382 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
383 {
384 delete mImageArray[i];
385 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000386}
387
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000388GLsizei Texture2D::getWidth(GLint level) const
389{
390 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000391 return mImageArray[level]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000392 else
393 return 0;
394}
395
396GLsizei Texture2D::getHeight(GLint level) const
397{
398 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000399 return mImageArray[level]->getHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000400 else
401 return 0;
402}
403
404GLenum Texture2D::getInternalFormat(GLint level) const
405{
406 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000407 return mImageArray[level]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000408 else
409 return GL_NONE;
410}
411
daniel@transgaming.com20d36662012-10-31 19:51:43 +0000412GLenum Texture2D::getActualFormat(GLint level) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000413{
414 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000415 return mImageArray[level]->getActualFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000416 else
417 return D3DFMT_UNKNOWN;
418}
419
Geoff Lang005df412013-10-16 14:12:50 -0400420void Texture2D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000421{
422 releaseTexImage();
shannon.woods@transgaming.com8a406682013-02-28 23:15:26 +0000423
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000424 // If there currently is a corresponding storage texture image, it has these parameters
Jamie Madilld3d2a342013-10-07 10:46:35 -0400425 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
426 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
Geoff Lang005df412013-10-16 14:12:50 -0400427 const GLenum storageFormat = getBaseLevelInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000428
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000429 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, width, height, 1, false);
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000430
431 if (mTexStorage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000432 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000433 const int storageLevels = mTexStorage->levelCount();
434
435 if ((level >= storageLevels && storageLevels != 0) ||
436 width != storageWidth ||
437 height != storageHeight ||
438 internalformat != storageFormat) // Discard mismatched storage
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000439 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000440 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
441 {
442 mImageArray[i]->markDirty();
443 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000444
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000445 delete mTexStorage;
446 mTexStorage = NULL;
447 mDirtyImages = true;
448 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000449 }
450}
451
Geoff Lang005df412013-10-16 14:12:50 -0400452void Texture2D::setImage(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000453{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +0000454 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Geoff Lang005df412013-10-16 14:12:50 -0400455 GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
456 : GetSizedInternalFormat(format, type, clientVersion);
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +0000457 redefineImage(level, sizedInternalFormat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000458
Jamie Madill8cc7d972013-10-10 15:51:55 -0400459 bool fastUnpacked = false;
460
Jamie Madill1beb1db2013-09-18 14:36:28 -0400461 // Attempt a fast gpu copy of the pixel data to the surface
Jamie Madill8cc7d972013-10-10 15:51:55 -0400462 if (isFastUnpackable(unpack, sizedInternalFormat) && isLevelComplete(level))
Jamie Madill1beb1db2013-09-18 14:36:28 -0400463 {
Jamie Madill8cc7d972013-10-10 15:51:55 -0400464 // Will try to create RT storage if it does not exist
465 rx::RenderTarget *destRenderTarget = getRenderTarget(level);
466 Box destArea(0, 0, 0, getWidth(level), getHeight(level), 1);
467
468 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget))
469 {
470 // Ensure we don't overwrite our newly initialized data
471 mImageArray[level]->markClean();
472
473 fastUnpacked = true;
474 }
Jamie Madill1beb1db2013-09-18 14:36:28 -0400475 }
Jamie Madill8cc7d972013-10-10 15:51:55 -0400476
477 if (!fastUnpacked)
Jamie Madill1beb1db2013-09-18 14:36:28 -0400478 {
479 Texture::setImage(unpack, type, pixels, mImageArray[level]);
480 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000481}
482
483void Texture2D::bindTexImage(egl::Surface *surface)
484{
485 releaseTexImage();
486
Geoff Lang005df412013-10-16 14:12:50 -0400487 GLenum internalformat = surface->getFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000488
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000489 mImageArray[0]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, surface->getWidth(), surface->getHeight(), 1, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000490
491 delete mTexStorage;
daniel@transgaming.comd8353dd2012-12-20 21:11:14 +0000492 mTexStorage = new rx::TextureStorageInterface2D(mRenderer, surface->getSwapChain());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000493
494 mDirtyImages = true;
495 mSurface = surface;
496 mSurface->setBoundTexture(this);
497}
498
499void Texture2D::releaseTexImage()
500{
501 if (mSurface)
502 {
503 mSurface->setBoundTexture(NULL);
504 mSurface = NULL;
505
506 if (mTexStorage)
507 {
508 delete mTexStorage;
509 mTexStorage = NULL;
510 }
511
512 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
513 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000514 mImageArray[i]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000515 }
516 }
517}
518
519void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
520{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000521 // 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 +0000522 redefineImage(level, format, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000523
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000524 Texture::setCompressedImage(imageSize, pixels, mImageArray[level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000525}
526
527void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
528{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000529 if (level < levelCount())
530 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000531 rx::Image *image = mImageArray[level];
daniel@transgaming.com0f195ad2012-10-31 19:51:59 +0000532 if (image->updateSurface(mTexStorage, level, xoffset, yoffset, width, height))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000533 {
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000534 image->markClean();
535 }
536 }
537}
538
Jamie Madill88f18f42013-09-18 14:36:19 -0400539void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000540{
Jamie Madill065e1a32013-10-10 15:11:50 -0400541 bool fastUnpacked = false;
542
543 if (isFastUnpackable(unpack, getInternalFormat(level)) && isLevelComplete(level))
544 {
545 rx::RenderTarget *renderTarget = getRenderTarget(level);
546 Box destArea(xoffset, yoffset, 0, width, height, 1);
547
548 if (renderTarget && fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, renderTarget))
549 {
550 // Ensure we don't overwrite our newly initialized data
551 mImageArray[level]->markClean();
552
553 fastUnpacked = true;
554 }
555 }
556
557 if (!fastUnpacked && Texture::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, mImageArray[level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000558 {
559 commitRect(level, xoffset, yoffset, width, height);
560 }
561}
562
563void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
564{
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000565 if (Texture::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000566 {
567 commitRect(level, xoffset, yoffset, width, height);
568 }
569}
570
571void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
572{
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +0000573 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Geoff Lang005df412013-10-16 14:12:50 -0400574 GLenum sizedInternalFormat = IsSizedInternalFormat(format, clientVersion) ? format
575 : GetSizedInternalFormat(format, GL_UNSIGNED_BYTE, clientVersion);
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +0000576 redefineImage(level, sizedInternalFormat, width, height);
shannon.woods@transgaming.com8a406682013-02-28 23:15:26 +0000577
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000578 if (!mImageArray[level]->isRenderableFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000579 {
shannon.woods%transgaming.com@gtempaccount.come5dcce72013-04-13 03:44:33 +0000580 mImageArray[level]->copy(0, 0, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000581 mDirtyImages = true;
582 }
583 else
584 {
Jamie Madille83d1a92013-10-24 17:49:33 -0400585 ensureRenderTarget();
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000586 mImageArray[level]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000587
588 if (width != 0 && height != 0 && level < levelCount())
589 {
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +0000590 gl::Rectangle sourceRect;
591 sourceRect.x = x;
592 sourceRect.width = width;
593 sourceRect.y = y;
594 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000595
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +0000596 mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000597 }
598 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000599}
600
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +0000601void 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 +0000602{
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +0000603 if (xoffset + width > mImageArray[level]->getWidth() || yoffset + height > mImageArray[level]->getHeight() || zoffset != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000604 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +0000605 return gl::error(GL_INVALID_VALUE);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000606 }
607
Jamie Madill07edd442013-07-19 16:36:58 -0400608 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
609 // the current level we're copying to is defined (with appropriate format, width & height)
610 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
611
612 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000613 {
shannon.woods%transgaming.com@gtempaccount.come5dcce72013-04-13 03:44:33 +0000614 mImageArray[level]->copy(xoffset, yoffset, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000615 mDirtyImages = true;
616 }
617 else
618 {
Jamie Madille83d1a92013-10-24 17:49:33 -0400619 ensureRenderTarget();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000620
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000621 if (level < levelCount())
622 {
Jamie Madill07edd442013-07-19 16:36:58 -0400623 updateTextureLevel(level);
624
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +0000625 GLuint clientVersion = mRenderer->getCurrentClientVersion();
626
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +0000627 gl::Rectangle sourceRect;
628 sourceRect.x = x;
629 sourceRect.width = width;
630 sourceRect.y = y;
631 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000632
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +0000633 mRenderer->copyImage(source, sourceRect,
Jamie Madilld3d2a342013-10-07 10:46:35 -0400634 gl::GetFormat(getBaseLevelInternalFormat(), clientVersion),
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +0000635 xoffset, yoffset, mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000636 }
637 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000638}
639
640void Texture2D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height)
641{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000642 delete mTexStorage;
Jamie Madilld4589c92013-10-24 17:49:34 -0400643 mTexStorage = new rx::TextureStorageInterface2D(mRenderer, levels, internalformat, IsRenderTargetUsage(mUsage), width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000644 mImmutable = true;
645
646 for (int level = 0; level < levels; level++)
647 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000648 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, width, height, 1, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000649 width = std::max(1, width >> 1);
650 height = std::max(1, height >> 1);
651 }
652
653 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
654 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000655 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000656 }
657
658 if (mTexStorage->isManaged())
659 {
660 int levels = levelCount();
661
662 for (int level = 0; level < levels; level++)
663 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000664 mImageArray[level]->setManagedSurface(mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000665 }
666 }
667}
668
669// Tests for 2D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85.
Jamie Madillf8989902013-07-19 16:36:58 -0400670bool Texture2D::isSamplerComplete(const SamplerState &samplerState) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000671{
Jamie Madilld3d2a342013-10-07 10:46:35 -0400672 GLsizei width = getBaseLevelWidth();
673 GLsizei height = getBaseLevelHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000674
675 if (width <= 0 || height <= 0)
676 {
677 return false;
678 }
679
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000680 if (!IsTextureFilteringSupported(getInternalFormat(0), mRenderer))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000681 {
Jamie Madillf8989902013-07-19 16:36:58 -0400682 if (samplerState.magFilter != GL_NEAREST ||
683 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000684 {
685 return false;
686 }
687 }
688
daniel@transgaming.comea32d482012-11-28 19:33:18 +0000689 bool npotSupport = mRenderer->getNonPower2TextureSupport();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000690
691 if (!npotSupport)
692 {
Jamie Madillf8989902013-07-19 16:36:58 -0400693 if ((samplerState.wrapS != GL_CLAMP_TO_EDGE && !isPow2(width)) ||
694 (samplerState.wrapT != GL_CLAMP_TO_EDGE && !isPow2(height)))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000695 {
696 return false;
697 }
698 }
699
Jamie Madillf8989902013-07-19 16:36:58 -0400700 if (IsMipmapFiltered(samplerState))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000701 {
702 if (!npotSupport)
703 {
704 if (!isPow2(width) || !isPow2(height))
705 {
706 return false;
707 }
708 }
709
710 if (!isMipmapComplete())
711 {
712 return false;
713 }
714 }
715
Geoff Langc82fc412013-07-10 14:43:42 -0400716 // OpenGLES 3.0.2 spec section 3.8.13 states that a texture is not mipmap complete if:
717 // The internalformat specified for the texture arrays is a sized internal depth or
718 // depth and stencil format (see table 3.13), the value of TEXTURE_COMPARE_-
719 // MODE is NONE, and either the magnification filter is not NEAREST or the mini-
720 // fication filter is neither NEAREST nor NEAREST_MIPMAP_NEAREST.
721 if (gl::GetDepthBits(getInternalFormat(0), mRenderer->getCurrentClientVersion()) > 0)
722 {
723 if (mSamplerState.compareMode == GL_NONE)
724 {
725 if ((mSamplerState.minFilter != GL_NEAREST && mSamplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST) ||
726 mSamplerState.magFilter != GL_NEAREST)
727 {
728 return false;
729 }
730 }
731 }
732
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000733 return true;
734}
735
736// Tests for 2D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
737bool Texture2D::isMipmapComplete() const
738{
Jamie Madill22f843a2013-10-24 17:49:36 -0400739 int q = mipLevels();
Jamie Madill07edd442013-07-19 16:36:58 -0400740
741 for (int level = 0; level <= q; level++)
742 {
743 if (!isLevelComplete(level))
744 {
745 return false;
746 }
747 }
748
749 return true;
750}
751
752bool Texture2D::isLevelComplete(int level) const
753{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000754 if (isImmutable())
755 {
756 return true;
757 }
758
Jamie Madilld3d2a342013-10-07 10:46:35 -0400759 GLsizei width = getBaseLevelWidth();
760 GLsizei height = getBaseLevelHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000761
762 if (width <= 0 || height <= 0)
763 {
764 return false;
765 }
766
Jamie Madill07edd442013-07-19 16:36:58 -0400767 // The base image level is complete if the width and height are positive
768 if (level == 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000769 {
Jamie Madill07edd442013-07-19 16:36:58 -0400770 return true;
771 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000772
Jamie Madill07edd442013-07-19 16:36:58 -0400773 ASSERT(level >= 1 && level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
774 rx::Image *image = mImageArray[level];
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000775
Jamie Madilld3d2a342013-10-07 10:46:35 -0400776 if (image->getInternalFormat() != getBaseLevelInternalFormat())
Jamie Madill07edd442013-07-19 16:36:58 -0400777 {
778 return false;
779 }
780
781 if (image->getWidth() != std::max(1, width >> level))
782 {
783 return false;
784 }
785
786 if (image->getHeight() != std::max(1, height >> level))
787 {
788 return false;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000789 }
790
791 return true;
792}
793
794bool Texture2D::isCompressed(GLint level) const
795{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000796 return IsFormatCompressed(getInternalFormat(level), mRenderer->getCurrentClientVersion());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000797}
798
799bool Texture2D::isDepth(GLint level) const
800{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000801 return GetDepthBits(getInternalFormat(level), mRenderer->getCurrentClientVersion()) > 0;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000802}
803
daniel@transgaming.comf032cb82012-10-31 19:51:52 +0000804// Constructs a native texture resource from the texture images
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000805void Texture2D::createTexture()
806{
Jamie Madilld3d2a342013-10-07 10:46:35 -0400807 GLsizei width = getBaseLevelWidth();
808 GLsizei height = getBaseLevelHeight();
daniel@transgaming.come6a09842012-09-17 21:28:55 +0000809
810 if (!(width > 0 && height > 0))
daniel@transgaming.comf032cb82012-10-31 19:51:52 +0000811 return; // do not attempt to create native textures for nonexistant data
daniel@transgaming.come6a09842012-09-17 21:28:55 +0000812
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000813 GLint levels = creationLevels(width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000814
815 delete mTexStorage;
Jamie Madilld4589c92013-10-24 17:49:34 -0400816 mTexStorage = new rx::TextureStorageInterface2D(mRenderer, levels, getBaseLevelInternalFormat(), IsRenderTargetUsage(mUsage), width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000817
818 if (mTexStorage->isManaged())
819 {
820 int levels = levelCount();
821
822 for (int level = 0; level < levels; level++)
823 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000824 mImageArray[level]->setManagedSurface(mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000825 }
826 }
827
828 mDirtyImages = true;
829}
830
831void Texture2D::updateTexture()
832{
Jamie Madilld9b9a502013-10-10 17:46:13 -0400833 int storageLevels = levelCount();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000834
Jamie Madilld9b9a502013-10-10 17:46:13 -0400835 for (int level = 0; level < storageLevels; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000836 {
Jamie Madilld9b9a502013-10-10 17:46:13 -0400837 if (isLevelComplete(level))
838 {
839 updateTextureLevel(level);
840 }
Jamie Madill07edd442013-07-19 16:36:58 -0400841 }
842}
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000843
Jamie Madill07edd442013-07-19 16:36:58 -0400844void Texture2D::updateTextureLevel(int level)
845{
846 ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
Jamie Madillaee7ad82013-10-10 16:07:32 -0400847 ASSERT(isLevelComplete(level));
Jamie Madill07edd442013-07-19 16:36:58 -0400848
Jamie Madillaee7ad82013-10-10 16:07:32 -0400849 if (mImageArray[level]->isDirty())
Jamie Madill07edd442013-07-19 16:36:58 -0400850 {
Jamie Madillaee7ad82013-10-10 16:07:32 -0400851 commitRect(level, 0, 0, getWidth(level), getHeight(level));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000852 }
853}
854
Jamie Madille83d1a92013-10-24 17:49:33 -0400855bool Texture2D::ensureRenderTarget()
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000856{
Jamie Madille83d1a92013-10-24 17:49:33 -0400857 if (mTexStorage && mTexStorage->isRenderTarget())
858 {
859 return true;
860 }
861
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000862 rx::TextureStorageInterface2D *newTexStorage = NULL;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000863
Jamie Madilld3d2a342013-10-07 10:46:35 -0400864 GLsizei width = getBaseLevelWidth();
865 GLsizei height = getBaseLevelHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000866
Jamie Madilld3d2a342013-10-07 10:46:35 -0400867 if (width != 0 && height != 0)
868 {
869 GLint levels = mTexStorage != NULL ? mTexStorage->levelCount() : creationLevels(width, height);
870
Jamie Madilld4589c92013-10-24 17:49:34 -0400871 newTexStorage = new rx::TextureStorageInterface2D(mRenderer, levels, getBaseLevelInternalFormat(), true, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000872
873 if (mTexStorage != NULL)
874 {
daniel@transgaming.com1d80eee2012-11-28 19:33:31 +0000875 if (!mRenderer->copyToRenderTarget(newTexStorage, mTexStorage))
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +0000876 {
877 delete newTexStorage;
Jamie Madille83d1a92013-10-24 17:49:33 -0400878 return gl::error(GL_OUT_OF_MEMORY, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000879 }
880 }
881 }
882
883 delete mTexStorage;
884 mTexStorage = newTexStorage;
885
886 mDirtyImages = true;
Jamie Madille83d1a92013-10-24 17:49:33 -0400887
888 return (mTexStorage && mTexStorage->isRenderTarget());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000889}
890
891void Texture2D::generateMipmaps()
892{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000893 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Jamie Madill22f843a2013-10-24 17:49:36 -0400894 int q = mipLevels();
895 for (int level = 1; level <= q; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000896 {
Jamie Madill22f843a2013-10-24 17:49:36 -0400897 redefineImage(level, getBaseLevelInternalFormat(),
898 std::max(getBaseLevelWidth() >> level, 1),
899 std::max(getBaseLevelHeight() >> level, 1));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000900 }
901
902 if (mTexStorage && mTexStorage->isRenderTarget())
903 {
Jamie Madill22f843a2013-10-24 17:49:36 -0400904 for (int level = 1; level <= q; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000905 {
Jamie Madill22f843a2013-10-24 17:49:36 -0400906 mTexStorage->generateMipmap(level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000907
Jamie Madill22f843a2013-10-24 17:49:36 -0400908 mImageArray[level]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000909 }
910 }
911 else
912 {
Jamie Madill22f843a2013-10-24 17:49:36 -0400913 for (int level = 1; level <= q; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000914 {
Jamie Madill22f843a2013-10-24 17:49:36 -0400915 mRenderer->generateMipmap(mImageArray[level], mImageArray[level - 1]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000916 }
917 }
918}
919
Jamie Madilld3d2a342013-10-07 10:46:35 -0400920const rx::Image *Texture2D::getBaseLevelImage() const
921{
922 return mImageArray[0];
923}
924
Geoff Lang8040f572013-07-25 16:49:54 -0400925Renderbuffer *Texture2D::getRenderbuffer(GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000926{
Geoff Lang8040f572013-07-25 16:49:54 -0400927 Renderbuffer *renderBuffer = mRenderbufferProxies.get(level, 0);
928 if (!renderBuffer)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000929 {
Geoff Lang8040f572013-07-25 16:49:54 -0400930 renderBuffer = new Renderbuffer(mRenderer, id(), new RenderbufferTexture2D(this, level));
931 mRenderbufferProxies.add(level, 0, renderBuffer);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000932 }
933
Geoff Lang8040f572013-07-25 16:49:54 -0400934 return renderBuffer;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000935}
936
Geoff Lang8040f572013-07-25 16:49:54 -0400937unsigned int Texture2D::getRenderTargetSerial(GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000938{
Jamie Madille83d1a92013-10-24 17:49:33 -0400939 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(level) : 0);
Geoff Lang8040f572013-07-25 16:49:54 -0400940}
941
942rx::RenderTarget *Texture2D::getRenderTarget(GLint level)
943{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000944 // ensure the underlying texture is created
945 if (getStorage(true) == NULL)
946 {
947 return NULL;
948 }
949
Jamie Madillaee7ad82013-10-10 16:07:32 -0400950 updateTextureLevel(level);
Geoff Lang8040f572013-07-25 16:49:54 -0400951
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000952 // ensure this is NOT a depth texture
Geoff Lang8040f572013-07-25 16:49:54 -0400953 if (isDepth(level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000954 {
955 return NULL;
956 }
daniel@transgaming.com34da3972012-12-20 21:10:29 +0000957
Geoff Lang8040f572013-07-25 16:49:54 -0400958 return mTexStorage->getRenderTarget(level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000959}
960
Geoff Lang8040f572013-07-25 16:49:54 -0400961rx::RenderTarget *Texture2D::getDepthSencil(GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000962{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000963 // ensure the underlying texture is created
964 if (getStorage(true) == NULL)
965 {
966 return NULL;
967 }
968
Jamie Madillaee7ad82013-10-10 16:07:32 -0400969 updateTextureLevel(level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000970
971 // ensure this is actually a depth texture
Geoff Lang8040f572013-07-25 16:49:54 -0400972 if (!isDepth(level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000973 {
974 return NULL;
975 }
Geoff Lang8040f572013-07-25 16:49:54 -0400976
977 return mTexStorage->getRenderTarget(level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000978}
979
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +0000980int Texture2D::levelCount()
981{
shannon.woods@transgaming.com5016f8e2013-02-28 23:20:57 +0000982 return mTexStorage ? mTexStorage->levelCount() : 0;
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +0000983}
984
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000985rx::TextureStorageInterface *Texture2D::getStorage(bool renderTarget)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000986{
987 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
988 {
989 if (renderTarget)
990 {
Jamie Madille83d1a92013-10-24 17:49:33 -0400991 ensureRenderTarget();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000992 }
993 else
994 {
995 createTexture();
996 }
997 }
998
999 return mTexStorage;
1000}
1001
Geoff Lang4907f2c2013-07-25 12:53:57 -04001002TextureCubeMap::TextureCubeMap(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_CUBE_MAP)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001003{
1004 mTexStorage = NULL;
1005 for (int i = 0; i < 6; i++)
1006 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001007 for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
1008 {
daniel@transgaming.com244e1832012-12-20 20:52:35 +00001009 mImageArray[i][j] = renderer->createImage();
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001010 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001011 }
1012}
1013
1014TextureCubeMap::~TextureCubeMap()
1015{
1016 for (int i = 0; i < 6; i++)
1017 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001018 for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
1019 {
1020 delete mImageArray[i][j];
1021 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001022 }
1023
1024 delete mTexStorage;
1025 mTexStorage = NULL;
1026}
1027
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001028GLsizei TextureCubeMap::getWidth(GLenum target, GLint level) const
1029{
1030 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Jamie Madill2db197c2013-10-24 17:49:35 -04001031 return mImageArray[targetToIndex(target)][level]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001032 else
1033 return 0;
1034}
1035
1036GLsizei TextureCubeMap::getHeight(GLenum target, GLint level) const
1037{
1038 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Jamie Madill2db197c2013-10-24 17:49:35 -04001039 return mImageArray[targetToIndex(target)][level]->getHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001040 else
1041 return 0;
1042}
1043
1044GLenum TextureCubeMap::getInternalFormat(GLenum target, GLint level) const
1045{
1046 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Jamie Madill2db197c2013-10-24 17:49:35 -04001047 return mImageArray[targetToIndex(target)][level]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001048 else
1049 return GL_NONE;
1050}
1051
daniel@transgaming.com20d36662012-10-31 19:51:43 +00001052GLenum TextureCubeMap::getActualFormat(GLenum target, GLint level) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001053{
1054 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Jamie Madill2db197c2013-10-24 17:49:35 -04001055 return mImageArray[targetToIndex(target)][level]->getActualFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001056 else
1057 return D3DFMT_UNKNOWN;
1058}
1059
Geoff Lang005df412013-10-16 14:12:50 -04001060void TextureCubeMap::setImagePosX(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001061{
Jamie Madill88f18f42013-09-18 14:36:19 -04001062 setImage(0, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001063}
1064
Geoff Lang005df412013-10-16 14:12:50 -04001065void TextureCubeMap::setImageNegX(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001066{
Jamie Madill88f18f42013-09-18 14:36:19 -04001067 setImage(1, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001068}
1069
Geoff Lang005df412013-10-16 14:12:50 -04001070void TextureCubeMap::setImagePosY(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001071{
Jamie Madill88f18f42013-09-18 14:36:19 -04001072 setImage(2, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001073}
1074
Geoff Lang005df412013-10-16 14:12:50 -04001075void TextureCubeMap::setImageNegY(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001076{
Jamie Madill88f18f42013-09-18 14:36:19 -04001077 setImage(3, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001078}
1079
Geoff Lang005df412013-10-16 14:12:50 -04001080void TextureCubeMap::setImagePosZ(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001081{
Jamie Madill88f18f42013-09-18 14:36:19 -04001082 setImage(4, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001083}
1084
Geoff Lang005df412013-10-16 14:12:50 -04001085void TextureCubeMap::setImageNegZ(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001086{
Jamie Madill88f18f42013-09-18 14:36:19 -04001087 setImage(5, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001088}
1089
Jamie Madill2db197c2013-10-24 17:49:35 -04001090void TextureCubeMap::setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001091{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001092 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
Jamie Madill2db197c2013-10-24 17:49:35 -04001093 int faceIndex = targetToIndex(target);
1094 redefineImage(faceIndex, level, format, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001095
Jamie Madill2db197c2013-10-24 17:49:35 -04001096 Texture::setCompressedImage(imageSize, pixels, mImageArray[faceIndex][level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001097}
1098
Jamie Madill2db197c2013-10-24 17:49:35 -04001099void TextureCubeMap::commitRect(int faceIndex, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001100{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001101 if (level < levelCount())
1102 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001103 rx::Image *image = mImageArray[faceIndex][level];
1104 if (image->updateSurface(mTexStorage, faceIndex, level, xoffset, yoffset, width, height))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001105 image->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001106 }
1107}
1108
Jamie Madill88f18f42013-09-18 14:36:19 -04001109void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001110{
Jamie Madill2db197c2013-10-24 17:49:35 -04001111 int faceIndex = targetToIndex(target);
1112 if (Texture::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, mImageArray[faceIndex][level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001113 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001114 commitRect(faceIndex, level, xoffset, yoffset, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001115 }
1116}
1117
1118void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1119{
Jamie Madill2db197c2013-10-24 17:49:35 -04001120 int faceIndex = targetToIndex(target);
1121 if (Texture::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[faceIndex][level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001122 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001123 commitRect(faceIndex, level, xoffset, yoffset, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001124 }
1125}
1126
1127// Tests for cube map sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 86.
Jamie Madillf8989902013-07-19 16:36:58 -04001128bool TextureCubeMap::isSamplerComplete(const SamplerState &samplerState) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001129{
Jamie Madilld3d2a342013-10-07 10:46:35 -04001130 int size = getBaseLevelWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001131
Jamie Madillf8989902013-07-19 16:36:58 -04001132 bool mipmapping = IsMipmapFiltered(samplerState);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001133
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001134 if (!IsTextureFilteringSupported(getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0), mRenderer))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001135 {
Jamie Madillf8989902013-07-19 16:36:58 -04001136 if (samplerState.magFilter != GL_NEAREST ||
1137 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001138 {
1139 return false;
1140 }
1141 }
1142
daniel@transgaming.comea32d482012-11-28 19:33:18 +00001143 if (!isPow2(size) && !mRenderer->getNonPower2TextureSupport())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001144 {
Jamie Madillf8989902013-07-19 16:36:58 -04001145 if (samplerState.wrapS != GL_CLAMP_TO_EDGE || samplerState.wrapT != GL_CLAMP_TO_EDGE || mipmapping)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001146 {
1147 return false;
1148 }
1149 }
1150
1151 if (!mipmapping)
1152 {
1153 if (!isCubeComplete())
1154 {
1155 return false;
1156 }
1157 }
1158 else
1159 {
1160 if (!isMipmapCubeComplete()) // Also tests for isCubeComplete()
1161 {
1162 return false;
1163 }
1164 }
1165
1166 return true;
1167}
1168
1169// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1170bool TextureCubeMap::isCubeComplete() const
1171{
Jamie Madillc1f8b162013-10-07 10:46:38 -04001172 int baseWidth = getBaseLevelWidth();
1173 int baseHeight = getBaseLevelHeight();
1174 GLenum baseFormat = getBaseLevelInternalFormat();
1175
1176 if (baseWidth <= 0 || baseWidth != baseHeight)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001177 {
1178 return false;
1179 }
1180
Jamie Madill2db197c2013-10-24 17:49:35 -04001181 for (int faceIndex = 1; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001182 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001183 const rx::Image &faceBaseImage = *mImageArray[faceIndex][0];
Jamie Madillc1f8b162013-10-07 10:46:38 -04001184
1185 if (faceBaseImage.getWidth() != baseWidth ||
1186 faceBaseImage.getHeight() != baseHeight ||
1187 faceBaseImage.getInternalFormat() != baseFormat )
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001188 {
1189 return false;
1190 }
1191 }
1192
1193 return true;
1194}
1195
1196bool TextureCubeMap::isMipmapCubeComplete() const
1197{
1198 if (isImmutable())
1199 {
1200 return true;
1201 }
1202
1203 if (!isCubeComplete())
1204 {
1205 return false;
1206 }
1207
Jamie Madill22f843a2013-10-24 17:49:36 -04001208 int q = mipLevels();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001209
1210 for (int face = 0; face < 6; face++)
1211 {
1212 for (int level = 1; level <= q; level++)
1213 {
Jamie Madill07edd442013-07-19 16:36:58 -04001214 if (!isFaceLevelComplete(face, level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001215 {
1216 return false;
1217 }
1218 }
1219 }
1220
1221 return true;
1222}
1223
Jamie Madill2db197c2013-10-24 17:49:35 -04001224bool TextureCubeMap::isFaceLevelComplete(int faceIndex, int level) const
Jamie Madill07edd442013-07-19 16:36:58 -04001225{
Jamie Madill2db197c2013-10-24 17:49:35 -04001226 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
Jamie Madill07edd442013-07-19 16:36:58 -04001227
1228 if (isImmutable())
1229 {
1230 return true;
1231 }
1232
Jamie Madilld3d2a342013-10-07 10:46:35 -04001233 int baseSize = getBaseLevelWidth();
Jamie Madill07edd442013-07-19 16:36:58 -04001234
Jamie Madilld3d2a342013-10-07 10:46:35 -04001235 if (baseSize <= 0)
Jamie Madill07edd442013-07-19 16:36:58 -04001236 {
1237 return false;
1238 }
1239
Jamie Madilld3d2a342013-10-07 10:46:35 -04001240 // "isCubeComplete" checks for base level completeness and we must call that
1241 // to determine if any face at level 0 is complete. We omit that check here
1242 // to avoid re-checking cube-completeness for every face at level 0.
Jamie Madill07edd442013-07-19 16:36:58 -04001243 if (level == 0)
1244 {
1245 return true;
1246 }
1247
Jamie Madilld3d2a342013-10-07 10:46:35 -04001248 // Check that non-zero levels are consistent with the base level.
Jamie Madill2db197c2013-10-24 17:49:35 -04001249 const rx::Image *faceLevelImage = mImageArray[faceIndex][level];
Jamie Madill07edd442013-07-19 16:36:58 -04001250
Jamie Madilld3d2a342013-10-07 10:46:35 -04001251 if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat())
Jamie Madill07edd442013-07-19 16:36:58 -04001252 {
1253 return false;
1254 }
1255
Jamie Madilld3d2a342013-10-07 10:46:35 -04001256 if (faceLevelImage->getWidth() != std::max(1, baseSize >> level))
Jamie Madill07edd442013-07-19 16:36:58 -04001257 {
1258 return false;
1259 }
1260
1261 return true;
1262}
1263
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001264bool TextureCubeMap::isCompressed(GLenum target, GLint level) const
1265{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001266 return IsFormatCompressed(getInternalFormat(target, level), mRenderer->getCurrentClientVersion());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001267}
1268
Geoff Lang8040f572013-07-25 16:49:54 -04001269bool TextureCubeMap::isDepth(GLenum target, GLint level) const
1270{
1271 return GetDepthBits(getInternalFormat(target, level), mRenderer->getCurrentClientVersion()) > 0;
1272}
1273
daniel@transgaming.comf032cb82012-10-31 19:51:52 +00001274// Constructs a native texture resource from the texture images, or returns an existing one
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001275void TextureCubeMap::createTexture()
1276{
Jamie Madilld3d2a342013-10-07 10:46:35 -04001277 GLsizei size = getBaseLevelWidth();
daniel@transgaming.come6a09842012-09-17 21:28:55 +00001278
1279 if (!(size > 0))
daniel@transgaming.comf032cb82012-10-31 19:51:52 +00001280 return; // do not attempt to create native textures for nonexistant data
daniel@transgaming.come6a09842012-09-17 21:28:55 +00001281
sminns@adobe.comce1189b2012-09-18 20:06:35 +00001282 GLint levels = creationLevels(size);
Jamie Madilld3d2a342013-10-07 10:46:35 -04001283 GLenum internalformat = getBaseLevelInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001284
1285 delete mTexStorage;
Jamie Madilld4589c92013-10-24 17:49:34 -04001286 mTexStorage = new rx::TextureStorageInterfaceCube(mRenderer, levels, internalformat, IsRenderTargetUsage(mUsage), size);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001287
1288 if (mTexStorage->isManaged())
1289 {
1290 int levels = levelCount();
1291
Jamie Madill2db197c2013-10-24 17:49:35 -04001292 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001293 {
1294 for (int level = 0; level < levels; level++)
1295 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001296 mImageArray[faceIndex][level]->setManagedSurface(mTexStorage, faceIndex, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001297 }
1298 }
1299 }
1300
1301 mDirtyImages = true;
1302}
1303
1304void TextureCubeMap::updateTexture()
1305{
Jamie Madilld9b9a502013-10-10 17:46:13 -04001306 int storageLevels = levelCount();
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +00001307
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001308 for (int face = 0; face < 6; face++)
1309 {
Jamie Madilld9b9a502013-10-10 17:46:13 -04001310 for (int level = 0; level < storageLevels; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001311 {
Jamie Madilld9b9a502013-10-10 17:46:13 -04001312 if (isFaceLevelComplete(face, level))
1313 {
1314 updateTextureFaceLevel(face, level);
1315 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001316 }
1317 }
1318}
1319
Jamie Madill2db197c2013-10-24 17:49:35 -04001320void TextureCubeMap::updateTextureFaceLevel(int faceIndex, int level)
Jamie Madill07edd442013-07-19 16:36:58 -04001321{
Jamie Madill2db197c2013-10-24 17:49:35 -04001322 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1323 rx::Image *image = mImageArray[faceIndex][level];
Jamie Madill07edd442013-07-19 16:36:58 -04001324
1325 if (image->isDirty())
1326 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001327 commitRect(faceIndex, level, 0, 0, image->getWidth(), image->getHeight());
Jamie Madill07edd442013-07-19 16:36:58 -04001328 }
1329}
1330
Jamie Madille83d1a92013-10-24 17:49:33 -04001331bool TextureCubeMap::ensureRenderTarget()
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001332{
Jamie Madille83d1a92013-10-24 17:49:33 -04001333 if (mTexStorage && mTexStorage->isRenderTarget())
1334 {
1335 return true;
1336 }
1337
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001338 rx::TextureStorageInterfaceCube *newTexStorage = NULL;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001339
Jamie Madilld3d2a342013-10-07 10:46:35 -04001340 if (getBaseLevelWidth() != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001341 {
Jamie Madilld3d2a342013-10-07 10:46:35 -04001342 GLsizei size = getBaseLevelWidth();
shannon.woods@transgaming.com6bb48862013-02-28 23:09:34 +00001343 GLint levels = mTexStorage != NULL ? mTexStorage->levelCount() : creationLevels(size);
Jamie Madilld3d2a342013-10-07 10:46:35 -04001344 GLenum internalformat = getBaseLevelInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001345
Jamie Madilld4589c92013-10-24 17:49:34 -04001346 newTexStorage = new rx::TextureStorageInterfaceCube(mRenderer, levels, internalformat, true, size);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001347
1348 if (mTexStorage != NULL)
1349 {
daniel@transgaming.com1d80eee2012-11-28 19:33:31 +00001350 if (!mRenderer->copyToRenderTarget(newTexStorage, mTexStorage))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001351 {
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +00001352 delete newTexStorage;
Jamie Madille83d1a92013-10-24 17:49:33 -04001353 return gl::error(GL_OUT_OF_MEMORY, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001354 }
1355 }
1356 }
1357
1358 delete mTexStorage;
1359 mTexStorage = newTexStorage;
1360
1361 mDirtyImages = true;
Jamie Madille83d1a92013-10-24 17:49:33 -04001362 return (mTexStorage && mTexStorage->isRenderTarget());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001363}
1364
Geoff Lang005df412013-10-16 14:12:50 -04001365void TextureCubeMap::setImage(int faceIndex, GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001366{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001367 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Geoff Lang005df412013-10-16 14:12:50 -04001368 GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
1369 : GetSizedInternalFormat(format, type, clientVersion);
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001370
1371 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001372
Jamie Madill88f18f42013-09-18 14:36:19 -04001373 Texture::setImage(unpack, type, pixels, mImageArray[faceIndex][level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001374}
1375
Jamie Madill2db197c2013-10-24 17:49:35 -04001376int TextureCubeMap::targetToIndex(GLenum target)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001377{
1378 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
1379 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
1380 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
1381 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
1382 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
1383
Jamie Madill2db197c2013-10-24 17:49:35 -04001384 return target - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001385}
1386
Jamie Madill2db197c2013-10-24 17:49:35 -04001387void TextureCubeMap::redefineImage(int faceIndex, GLint level, GLenum internalformat, GLsizei width, GLsizei height)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001388{
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001389 // If there currently is a corresponding storage texture image, it has these parameters
Jamie Madilld3d2a342013-10-07 10:46:35 -04001390 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1391 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
Geoff Lang005df412013-10-16 14:12:50 -04001392 const GLenum storageFormat = getBaseLevelInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001393
Jamie Madill2db197c2013-10-24 17:49:35 -04001394 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, width, height, 1, false);
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001395
1396 if (mTexStorage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001397 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001398 const int storageLevels = mTexStorage->levelCount();
1399
1400 if ((level >= storageLevels && storageLevels != 0) ||
1401 width != storageWidth ||
1402 height != storageHeight ||
1403 internalformat != storageFormat) // Discard mismatched storage
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001404 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001405 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001406 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001407 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001408 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001409 mImageArray[faceIndex][level]->markDirty();
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001410 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001411 }
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001412
1413 delete mTexStorage;
1414 mTexStorage = NULL;
1415
1416 mDirtyImages = true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001417 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001418 }
1419}
1420
1421void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1422{
Jamie Madill2db197c2013-10-24 17:49:35 -04001423 int faceIndex = targetToIndex(target);
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001424 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Geoff Lang005df412013-10-16 14:12:50 -04001425 GLenum sizedInternalFormat = IsSizedInternalFormat(format, clientVersion) ? format
1426 : GetSizedInternalFormat(format, GL_UNSIGNED_BYTE, clientVersion);
Jamie Madill2db197c2013-10-24 17:49:35 -04001427 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001428
Jamie Madill2db197c2013-10-24 17:49:35 -04001429 if (!mImageArray[faceIndex][level]->isRenderableFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001430 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001431 mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001432 mDirtyImages = true;
1433 }
1434 else
1435 {
Jamie Madille83d1a92013-10-24 17:49:33 -04001436 ensureRenderTarget();
Jamie Madill2db197c2013-10-24 17:49:35 -04001437 mImageArray[faceIndex][level]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001438
1439 ASSERT(width == height);
1440
1441 if (width > 0 && level < levelCount())
1442 {
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +00001443 gl::Rectangle sourceRect;
1444 sourceRect.x = x;
1445 sourceRect.width = width;
1446 sourceRect.y = y;
1447 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001448
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +00001449 mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001450 }
1451 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001452}
1453
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001454void 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 +00001455{
Jamie Madill2db197c2013-10-24 17:49:35 -04001456 int faceIndex = targetToIndex(target);
1457
1458 GLsizei size = mImageArray[faceIndex][level]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001459
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001460 if (xoffset + width > size || yoffset + height > size || zoffset != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001461 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +00001462 return gl::error(GL_INVALID_VALUE);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001463 }
1464
Jamie Madilld3d2a342013-10-07 10:46:35 -04001465 // We can only make our texture storage to a render target if the level we're copying *to* is complete
1466 // and the base level is cube-complete. The base level must be cube complete (common case) because we cannot
1467 // rely on the "getBaseLevel*" methods reliably otherwise.
Jamie Madill2db197c2013-10-24 17:49:35 -04001468 bool canCreateRenderTarget = isFaceLevelComplete(faceIndex, level) && isCubeComplete();
Jamie Madill07edd442013-07-19 16:36:58 -04001469
Jamie Madill2db197c2013-10-24 17:49:35 -04001470 if (!mImageArray[faceIndex][level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001471 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001472 mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001473 mDirtyImages = true;
1474 }
1475 else
1476 {
Jamie Madille83d1a92013-10-24 17:49:33 -04001477 ensureRenderTarget();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001478
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001479 if (level < levelCount())
1480 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001481 updateTextureFaceLevel(faceIndex, level);
Jamie Madill07edd442013-07-19 16:36:58 -04001482
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001483 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1484
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +00001485 gl::Rectangle sourceRect;
1486 sourceRect.x = x;
1487 sourceRect.width = width;
1488 sourceRect.y = y;
1489 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001490
Jamie Madilld3d2a342013-10-07 10:46:35 -04001491 mRenderer->copyImage(source, sourceRect, gl::GetFormat(getBaseLevelInternalFormat(), clientVersion),
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +00001492 xoffset, yoffset, mTexStorage, target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001493 }
1494 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001495}
1496
1497void TextureCubeMap::storage(GLsizei levels, GLenum internalformat, GLsizei size)
1498{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001499 delete mTexStorage;
Jamie Madilld4589c92013-10-24 17:49:34 -04001500 mTexStorage = new rx::TextureStorageInterfaceCube(mRenderer, levels, internalformat, IsRenderTargetUsage(mUsage), size);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001501 mImmutable = true;
1502
1503 for (int level = 0; level < levels; level++)
1504 {
Geoff Langd3110192013-09-24 11:52:47 -04001505 GLsizei mipSize = std::max(1, size >> level);
Jamie Madill2db197c2013-10-24 17:49:35 -04001506 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001507 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001508 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, mipSize, mipSize, 1, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001509 }
1510 }
1511
1512 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1513 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001514 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001515 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001516 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, GL_NONE, 0, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001517 }
1518 }
1519
1520 if (mTexStorage->isManaged())
1521 {
1522 int levels = levelCount();
1523
Jamie Madill2db197c2013-10-24 17:49:35 -04001524 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001525 {
1526 for (int level = 0; level < levels; level++)
1527 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001528 mImageArray[faceIndex][level]->setManagedSurface(mTexStorage, faceIndex, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001529 }
1530 }
1531 }
1532}
1533
1534void TextureCubeMap::generateMipmaps()
1535{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001536 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Jamie Madill22f843a2013-10-24 17:49:36 -04001537 int q = mipLevels();
Jamie Madill2db197c2013-10-24 17:49:35 -04001538 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001539 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001540 for (int level = 1; level <= q; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001541 {
Jamie Madill22f843a2013-10-24 17:49:36 -04001542 int faceLevelSize = (std::max(mImageArray[faceIndex][0]->getWidth() >> level, 1));
1543 redefineImage(faceIndex, level, mImageArray[faceIndex][0]->getInternalFormat(), faceLevelSize, faceLevelSize);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001544 }
1545 }
1546
1547 if (mTexStorage && mTexStorage->isRenderTarget())
1548 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001549 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001550 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001551 for (int level = 1; level <= q; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001552 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001553 mTexStorage->generateMipmap(faceIndex, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001554
Jamie Madill2db197c2013-10-24 17:49:35 -04001555 mImageArray[faceIndex][level]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001556 }
1557 }
1558 }
1559 else
1560 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001561 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001562 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001563 for (int level = 1; level <= q; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001564 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001565 mRenderer->generateMipmap(mImageArray[faceIndex][level], mImageArray[faceIndex][level - 1]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001566 }
1567 }
1568 }
1569}
1570
Jamie Madilld3d2a342013-10-07 10:46:35 -04001571const rx::Image *TextureCubeMap::getBaseLevelImage() const
1572{
1573 // Note: if we are not cube-complete, there is no single base level image that can describe all
1574 // cube faces, so this method is only well-defined for a cube-complete base level.
1575 return mImageArray[0][0];
1576}
1577
Geoff Lang8040f572013-07-25 16:49:54 -04001578Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target, GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001579{
1580 if (!IsCubemapTextureTarget(target))
1581 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +00001582 return gl::error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001583 }
1584
Jamie Madill2db197c2013-10-24 17:49:35 -04001585 int faceIndex = targetToIndex(target);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001586
Jamie Madill2db197c2013-10-24 17:49:35 -04001587 Renderbuffer *renderBuffer = mRenderbufferProxies.get(level, faceIndex);
Geoff Lang8040f572013-07-25 16:49:54 -04001588 if (!renderBuffer)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001589 {
Geoff Lang8040f572013-07-25 16:49:54 -04001590 renderBuffer = new Renderbuffer(mRenderer, id(), new RenderbufferTextureCubeMap(this, target, level));
Jamie Madill2db197c2013-10-24 17:49:35 -04001591 mRenderbufferProxies.add(level, faceIndex, renderBuffer);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001592 }
1593
Geoff Lang8040f572013-07-25 16:49:54 -04001594 return renderBuffer;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001595}
1596
Jamie Madill2db197c2013-10-24 17:49:35 -04001597unsigned int TextureCubeMap::getRenderTargetSerial(GLenum target, GLint level)
Geoff Lang8040f572013-07-25 16:49:54 -04001598{
Jamie Madill2db197c2013-10-24 17:49:35 -04001599 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(target, level) : 0);
Geoff Lang8040f572013-07-25 16:49:54 -04001600}
1601
1602rx::RenderTarget *TextureCubeMap::getRenderTarget(GLenum target, GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001603{
1604 ASSERT(IsCubemapTextureTarget(target));
1605
1606 // ensure the underlying texture is created
1607 if (getStorage(true) == NULL)
1608 {
1609 return NULL;
1610 }
1611
Jamie Madill2db197c2013-10-24 17:49:35 -04001612 updateTextureFaceLevel(targetToIndex(target), level);
Geoff Lang8040f572013-07-25 16:49:54 -04001613
1614 // ensure this is NOT a depth texture
1615 if (isDepth(target, level))
1616 {
1617 return NULL;
1618 }
1619
1620 return mTexStorage->getRenderTarget(target, level);
1621}
1622
1623rx::RenderTarget *TextureCubeMap::getDepthStencil(GLenum target, GLint level)
1624{
1625 ASSERT(IsCubemapTextureTarget(target));
1626
1627 // ensure the underlying texture is created
1628 if (getStorage(true) == NULL)
1629 {
1630 return NULL;
1631 }
1632
Jamie Madill2db197c2013-10-24 17:49:35 -04001633 updateTextureFaceLevel(targetToIndex(target), level);
Geoff Lang8040f572013-07-25 16:49:54 -04001634
1635 // ensure this is a depth texture
1636 if (!isDepth(target, level))
1637 {
1638 return NULL;
1639 }
1640
1641 return mTexStorage->getRenderTarget(target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001642}
1643
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +00001644int TextureCubeMap::levelCount()
1645{
1646 return mTexStorage ? mTexStorage->levelCount() - getLodOffset() : 0;
1647}
1648
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001649rx::TextureStorageInterface *TextureCubeMap::getStorage(bool renderTarget)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001650{
1651 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
1652 {
1653 if (renderTarget)
1654 {
Jamie Madille83d1a92013-10-24 17:49:33 -04001655 ensureRenderTarget();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001656 }
1657 else
1658 {
1659 createTexture();
1660 }
1661 }
1662
1663 return mTexStorage;
1664}
1665
Geoff Lang4907f2c2013-07-25 12:53:57 -04001666Texture3D::Texture3D(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_3D)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001667{
1668 mTexStorage = NULL;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001669
1670 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1671 {
1672 mImageArray[i] = renderer->createImage();
1673 }
1674}
1675
1676Texture3D::~Texture3D()
1677{
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001678 delete mTexStorage;
1679 mTexStorage = NULL;
1680
1681 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1682 {
1683 delete mImageArray[i];
1684 }
1685}
1686
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001687GLsizei Texture3D::getWidth(GLint level) const
1688{
1689 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getWidth() : 0;
1690}
1691
1692GLsizei Texture3D::getHeight(GLint level) const
1693{
1694 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getHeight() : 0;
1695}
1696
1697GLsizei Texture3D::getDepth(GLint level) const
1698{
1699 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getDepth() : 0;
1700}
1701
1702GLenum Texture3D::getInternalFormat(GLint level) const
1703{
1704 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getInternalFormat() : GL_NONE;
1705}
1706
1707GLenum Texture3D::getActualFormat(GLint level) const
1708{
1709 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getActualFormat() : D3DFMT_UNKNOWN;
1710}
1711
1712bool Texture3D::isCompressed(GLint level) const
1713{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001714 return IsFormatCompressed(getInternalFormat(level), mRenderer->getCurrentClientVersion());
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001715}
1716
1717bool Texture3D::isDepth(GLint level) const
1718{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001719 return GetDepthBits(getInternalFormat(level), mRenderer->getCurrentClientVersion()) > 0;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001720}
1721
Geoff Lang005df412013-10-16 14:12:50 -04001722void Texture3D::setImage(GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001723{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001724 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Geoff Lang005df412013-10-16 14:12:50 -04001725 GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
1726 : GetSizedInternalFormat(format, type, clientVersion);
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001727 redefineImage(level, sizedInternalFormat, width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001728
Jamie Madilla2d4e552013-10-10 15:12:01 -04001729 bool fastUnpacked = false;
1730
1731 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1732 if (isFastUnpackable(unpack, sizedInternalFormat))
1733 {
1734 // Will try to create RT storage if it does not exist
1735 rx::RenderTarget *destRenderTarget = getRenderTarget(level);
1736 Box destArea(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1737
1738 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget))
1739 {
1740 // Ensure we don't overwrite our newly initialized data
1741 mImageArray[level]->markClean();
1742
1743 fastUnpacked = true;
1744 }
1745 }
1746
1747 if (!fastUnpacked)
1748 {
1749 Texture::setImage(unpack, type, pixels, mImageArray[level]);
1750 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001751}
1752
1753void Texture3D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
1754{
1755 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1756 redefineImage(level, format, width, height, depth);
1757
1758 Texture::setCompressedImage(imageSize, pixels, mImageArray[level]);
1759}
1760
Jamie Madill88f18f42013-09-18 14:36:19 -04001761void Texture3D::subImage(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001762{
Jamie Madillba4f10a2013-10-10 15:12:20 -04001763 bool fastUnpacked = false;
1764
1765 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1766 if (isFastUnpackable(unpack, getInternalFormat(level)))
1767 {
1768 rx::RenderTarget *destRenderTarget = getRenderTarget(level);
1769 Box destArea(xoffset, yoffset, zoffset, width, height, depth);
1770
1771 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, destRenderTarget))
1772 {
1773 // Ensure we don't overwrite our newly initialized data
1774 mImageArray[level]->markClean();
1775
1776 fastUnpacked = true;
1777 }
1778 }
1779
1780 if (!fastUnpacked && Texture::subImage(xoffset, yoffset, zoffset, width, height, depth, format, type, unpack, pixels, mImageArray[level]))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001781 {
1782 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1783 }
1784}
1785
1786void Texture3D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
1787{
1788 if (Texture::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth, format, imageSize, pixels, mImageArray[level]))
1789 {
1790 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1791 }
1792}
1793
1794void Texture3D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
1795{
1796 delete mTexStorage;
Jamie Madilld4589c92013-10-24 17:49:34 -04001797 mTexStorage = new rx::TextureStorageInterface3D(mRenderer, levels, internalformat, IsRenderTargetUsage(mUsage), width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001798 mImmutable = true;
1799
1800 for (int level = 0; level < levels; level++)
1801 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001802 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, true);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001803 width = std::max(1, width >> 1);
1804 height = std::max(1, height >> 1);
1805 depth = std::max(1, depth >> 1);
1806 }
1807
1808 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1809 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001810 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, GL_NONE, 0, 0, 0, true);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001811 }
1812
1813 if (mTexStorage->isManaged())
1814 {
1815 int levels = levelCount();
1816
1817 for (int level = 0; level < levels; level++)
1818 {
1819 mImageArray[level]->setManagedSurface(mTexStorage, level);
1820 }
1821 }
1822}
1823
1824
1825void Texture3D::generateMipmaps()
1826{
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001827 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Jamie Madill22f843a2013-10-24 17:49:36 -04001828 int q = mipLevels();
1829 for (int level = 1; level <= q; level++)
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001830 {
Jamie Madill22f843a2013-10-24 17:49:36 -04001831 redefineImage(level, getBaseLevelInternalFormat(),
1832 std::max(getBaseLevelWidth() >> level, 1),
1833 std::max(getBaseLevelHeight() >> level, 1),
1834 std::max(getBaseLevelDepth() >> level, 1));
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001835 }
1836
1837 if (mTexStorage && mTexStorage->isRenderTarget())
1838 {
Jamie Madill22f843a2013-10-24 17:49:36 -04001839 for (int level = 1; level <= q; level++)
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001840 {
Jamie Madill22f843a2013-10-24 17:49:36 -04001841 mTexStorage->generateMipmap(level);
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001842
Jamie Madill22f843a2013-10-24 17:49:36 -04001843 mImageArray[level]->markClean();
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001844 }
1845 }
1846 else
1847 {
Jamie Madill22f843a2013-10-24 17:49:36 -04001848 for (int level = 1; level <= q; level++)
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001849 {
Jamie Madill22f843a2013-10-24 17:49:36 -04001850 mRenderer->generateMipmap(mImageArray[level], mImageArray[level - 1]);
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001851 }
1852 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001853}
1854
Jamie Madilld3d2a342013-10-07 10:46:35 -04001855const rx::Image *Texture3D::getBaseLevelImage() const
1856{
1857 return mImageArray[0];
1858}
1859
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001860void Texture3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1861{
1862 if (xoffset + width > mImageArray[level]->getWidth() || yoffset + height > mImageArray[level]->getHeight() || zoffset >= mImageArray[level]->getDepth())
1863 {
1864 return gl::error(GL_INVALID_VALUE);
1865 }
1866
Jamie Madill07edd442013-07-19 16:36:58 -04001867 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
1868 // the current level we're copying to is defined (with appropriate format, width & height)
1869 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
1870
1871 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001872 {
1873 mImageArray[level]->copy(xoffset, yoffset, zoffset, x, y, width, height, source);
1874 mDirtyImages = true;
1875 }
1876 else
1877 {
Jamie Madille83d1a92013-10-24 17:49:33 -04001878 ensureRenderTarget();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001879
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001880 if (level < levelCount())
1881 {
Jamie Madill07edd442013-07-19 16:36:58 -04001882 updateTextureLevel(level);
1883
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001884 gl::Rectangle sourceRect;
1885 sourceRect.x = x;
1886 sourceRect.width = width;
1887 sourceRect.y = y;
1888 sourceRect.height = height;
1889
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001890 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1891
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001892 mRenderer->copyImage(source, sourceRect,
Jamie Madilld3d2a342013-10-07 10:46:35 -04001893 gl::GetFormat(getBaseLevelInternalFormat(), clientVersion),
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001894 xoffset, yoffset, zoffset, mTexStorage, level);
1895 }
1896 }
1897}
1898
Jamie Madillf8989902013-07-19 16:36:58 -04001899bool Texture3D::isSamplerComplete(const SamplerState &samplerState) const
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001900{
Jamie Madilld3d2a342013-10-07 10:46:35 -04001901 GLsizei width = getBaseLevelWidth();
1902 GLsizei height = getBaseLevelHeight();
1903 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001904
1905 if (width <= 0 || height <= 0 || depth <= 0)
1906 {
1907 return false;
1908 }
1909
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001910 if (!IsTextureFilteringSupported(getInternalFormat(0), mRenderer))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001911 {
Jamie Madillf8989902013-07-19 16:36:58 -04001912 if (samplerState.magFilter != GL_NEAREST ||
1913 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001914 {
1915 return false;
1916 }
1917 }
1918
Jamie Madillf8989902013-07-19 16:36:58 -04001919 if (IsMipmapFiltered(samplerState) && !isMipmapComplete())
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001920 {
1921 return false;
1922 }
1923
1924 return true;
1925}
1926
1927bool Texture3D::isMipmapComplete() const
1928{
Jamie Madill22f843a2013-10-24 17:49:36 -04001929 int q = mipLevels();
Jamie Madill07edd442013-07-19 16:36:58 -04001930
1931 for (int level = 0; level <= q; level++)
1932 {
1933 if (!isLevelComplete(level))
1934 {
1935 return false;
1936 }
1937 }
1938
1939 return true;
1940}
1941
1942bool Texture3D::isLevelComplete(int level) const
1943{
1944 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1945
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001946 if (isImmutable())
1947 {
1948 return true;
1949 }
1950
Jamie Madilld3d2a342013-10-07 10:46:35 -04001951 GLsizei width = getBaseLevelWidth();
1952 GLsizei height = getBaseLevelHeight();
1953 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001954
1955 if (width <= 0 || height <= 0 || depth <= 0)
1956 {
1957 return false;
1958 }
1959
Jamie Madill07edd442013-07-19 16:36:58 -04001960 if (level == 0)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001961 {
Jamie Madill07edd442013-07-19 16:36:58 -04001962 return true;
1963 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001964
Jamie Madill07edd442013-07-19 16:36:58 -04001965 rx::Image *levelImage = mImageArray[level];
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001966
Jamie Madilld3d2a342013-10-07 10:46:35 -04001967 if (levelImage->getInternalFormat() != getBaseLevelInternalFormat())
Jamie Madill07edd442013-07-19 16:36:58 -04001968 {
1969 return false;
1970 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001971
Jamie Madill07edd442013-07-19 16:36:58 -04001972 if (levelImage->getWidth() != std::max(1, width >> level))
1973 {
1974 return false;
1975 }
1976
1977 if (levelImage->getHeight() != std::max(1, height >> level))
1978 {
1979 return false;
1980 }
1981
1982 if (levelImage->getDepth() != std::max(1, depth >> level))
1983 {
1984 return false;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001985 }
1986
1987 return true;
1988}
1989
Geoff Lang8040f572013-07-25 16:49:54 -04001990Renderbuffer *Texture3D::getRenderbuffer(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001991{
Geoff Lang8040f572013-07-25 16:49:54 -04001992 Renderbuffer *renderBuffer = mRenderbufferProxies.get(level, layer);
1993 if (!renderBuffer)
1994 {
Geoff Langd5d8e392013-07-25 16:53:03 -04001995 renderBuffer = new Renderbuffer(mRenderer, id(), new RenderbufferTexture3DLayer(this, level, layer));
1996 mRenderbufferProxies.add(level, 0, renderBuffer);
Geoff Lang8040f572013-07-25 16:49:54 -04001997 }
1998
1999 return renderBuffer;
2000}
2001
2002unsigned int Texture3D::getRenderTargetSerial(GLint level, GLint layer)
2003{
Jamie Madille83d1a92013-10-24 17:49:33 -04002004 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(level, layer) : 0);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002005}
2006
2007int Texture3D::levelCount()
2008{
2009 return mTexStorage ? mTexStorage->levelCount() : 0;
2010}
2011
2012void Texture3D::createTexture()
2013{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002014 GLsizei width = getBaseLevelWidth();
2015 GLsizei height = getBaseLevelHeight();
2016 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002017
2018 if (!(width > 0 && height > 0 && depth > 0))
2019 return; // do not attempt to create native textures for nonexistant data
2020
2021 GLint levels = creationLevels(width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002022
2023 delete mTexStorage;
Jamie Madilld4589c92013-10-24 17:49:34 -04002024 mTexStorage = new rx::TextureStorageInterface3D(mRenderer, levels, getBaseLevelInternalFormat(), IsRenderTargetUsage(mUsage), width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002025
2026 if (mTexStorage->isManaged())
2027 {
2028 int levels = levelCount();
2029
2030 for (int level = 0; level < levels; level++)
2031 {
2032 mImageArray[level]->setManagedSurface(mTexStorage, level);
2033 }
2034 }
2035
2036 mDirtyImages = true;
2037}
2038
2039void Texture3D::updateTexture()
2040{
Jamie Madilld9b9a502013-10-10 17:46:13 -04002041 int storageLevels = levelCount();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002042
Jamie Madilld9b9a502013-10-10 17:46:13 -04002043 for (int level = 0; level < storageLevels; level++)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002044 {
Jamie Madilld9b9a502013-10-10 17:46:13 -04002045 if (isLevelComplete(level))
2046 {
2047 updateTextureLevel(level);
2048 }
Jamie Madill07edd442013-07-19 16:36:58 -04002049 }
2050}
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002051
Jamie Madill07edd442013-07-19 16:36:58 -04002052void Texture3D::updateTextureLevel(int level)
2053{
2054 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
Jamie Madillaee7ad82013-10-10 16:07:32 -04002055 ASSERT(isLevelComplete(level));
Jamie Madill07edd442013-07-19 16:36:58 -04002056
Jamie Madillaee7ad82013-10-10 16:07:32 -04002057 if (mImageArray[level]->isDirty())
Jamie Madill07edd442013-07-19 16:36:58 -04002058 {
Jamie Madillaee7ad82013-10-10 16:07:32 -04002059 commitRect(level, 0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002060 }
2061}
2062
Jamie Madille83d1a92013-10-24 17:49:33 -04002063bool Texture3D::ensureRenderTarget()
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002064{
Jamie Madille83d1a92013-10-24 17:49:33 -04002065 if (mTexStorage && mTexStorage->isRenderTarget())
2066 {
2067 return true;
2068 }
2069
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002070 rx::TextureStorageInterface3D *newTexStorage = NULL;
2071
Jamie Madilld3d2a342013-10-07 10:46:35 -04002072 if (getBaseLevelWidth() != 0 && getBaseLevelHeight() != 0 && getBaseLevelDepth() != 0)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002073 {
Jamie Madilld3d2a342013-10-07 10:46:35 -04002074 GLsizei width = getBaseLevelWidth();
2075 GLsizei height = getBaseLevelHeight();
2076 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002077 GLint levels = mTexStorage != NULL ? mTexStorage->levelCount() : creationLevels(width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002078
Jamie Madilld4589c92013-10-24 17:49:34 -04002079 newTexStorage = new rx::TextureStorageInterface3D(mRenderer, levels, getBaseLevelInternalFormat(), true, width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002080
2081 if (mTexStorage != NULL)
2082 {
2083 if (!mRenderer->copyToRenderTarget(newTexStorage, mTexStorage))
2084 {
2085 delete newTexStorage;
Jamie Madille83d1a92013-10-24 17:49:33 -04002086 return gl::error(GL_OUT_OF_MEMORY, false);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002087 }
2088 }
2089 }
2090
2091 delete mTexStorage;
2092 mTexStorage = newTexStorage;
2093
2094 mDirtyImages = true;
Jamie Madille83d1a92013-10-24 17:49:33 -04002095 return (mTexStorage && mTexStorage->isRenderTarget());
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002096}
2097
Jamie Madilla2d4e552013-10-10 15:12:01 -04002098rx::RenderTarget *Texture3D::getRenderTarget(GLint level)
2099{
2100 // ensure the underlying texture is created
2101 if (getStorage(true) == NULL)
2102 {
2103 return NULL;
2104 }
2105
Jamie Madillaee7ad82013-10-10 16:07:32 -04002106 updateTextureLevel(level);
Jamie Madilla2d4e552013-10-10 15:12:01 -04002107
2108 // ensure this is NOT a depth texture
2109 if (isDepth(level))
2110 {
2111 return NULL;
2112 }
2113
2114 return mTexStorage->getRenderTarget(level);
2115}
2116
Geoff Lang8040f572013-07-25 16:49:54 -04002117rx::RenderTarget *Texture3D::getRenderTarget(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002118{
Geoff Lang8040f572013-07-25 16:49:54 -04002119 // ensure the underlying texture is created
2120 if (getStorage(true) == NULL)
2121 {
2122 return NULL;
2123 }
2124
2125 updateTexture();
2126
2127 // ensure this is NOT a depth texture
2128 if (isDepth(level))
2129 {
2130 return NULL;
2131 }
2132
2133 return mTexStorage->getRenderTarget(level, layer);
2134}
2135
2136rx::RenderTarget *Texture3D::getDepthStencil(GLint level, GLint layer)
2137{
2138 // ensure the underlying texture is created
2139 if (getStorage(true) == NULL)
2140 {
2141 return NULL;
2142 }
2143
Jamie Madillaee7ad82013-10-10 16:07:32 -04002144 updateTextureLevel(level);
Geoff Lang8040f572013-07-25 16:49:54 -04002145
2146 // ensure this is a depth texture
2147 if (!isDepth(level))
2148 {
2149 return NULL;
2150 }
2151
2152 return mTexStorage->getRenderTarget(level, layer);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002153}
2154
2155rx::TextureStorageInterface *Texture3D::getStorage(bool renderTarget)
2156{
2157 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
2158 {
2159 if (renderTarget)
2160 {
Jamie Madille83d1a92013-10-24 17:49:33 -04002161 ensureRenderTarget();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002162 }
2163 else
2164 {
2165 createTexture();
2166 }
2167 }
2168
2169 return mTexStorage;
2170}
2171
Geoff Lang005df412013-10-16 14:12:50 -04002172void Texture3D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002173{
2174 // If there currently is a corresponding storage texture image, it has these parameters
Jamie Madilld3d2a342013-10-07 10:46:35 -04002175 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2176 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
2177 const int storageDepth = std::max(1, getBaseLevelDepth() >> level);
Geoff Lang005df412013-10-16 14:12:50 -04002178 const GLenum storageFormat = getBaseLevelInternalFormat();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002179
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00002180 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, false);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002181
2182 if (mTexStorage)
2183 {
2184 const int storageLevels = mTexStorage->levelCount();
2185
2186 if ((level >= storageLevels && storageLevels != 0) ||
2187 width != storageWidth ||
2188 height != storageHeight ||
2189 depth != storageDepth ||
2190 internalformat != storageFormat) // Discard mismatched storage
2191 {
2192 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
2193 {
2194 mImageArray[i]->markDirty();
2195 }
2196
2197 delete mTexStorage;
2198 mTexStorage = NULL;
2199 mDirtyImages = true;
2200 }
2201 }
2202}
2203
2204void Texture3D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth)
2205{
2206 if (level < levelCount())
2207 {
2208 rx::Image *image = mImageArray[level];
2209 if (image->updateSurface(mTexStorage, level, xoffset, yoffset, zoffset, width, height, depth))
2210 {
2211 image->markClean();
2212 }
2213 }
2214}
2215
Geoff Lang4907f2c2013-07-25 12:53:57 -04002216Texture2DArray::Texture2DArray(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_2D_ARRAY)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002217{
2218 mTexStorage = NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002219
2220 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2221 {
2222 mLayerCounts[level] = 0;
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002223 mImageArray[level] = NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002224 }
2225}
2226
2227Texture2DArray::~Texture2DArray()
2228{
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002229 delete mTexStorage;
2230 mTexStorage = NULL;
2231 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2232 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002233 for (int layer = 0; layer < mLayerCounts[level]; ++layer)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002234 {
2235 delete mImageArray[level][layer];
2236 }
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002237 delete[] mImageArray[level];
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002238 }
2239}
2240
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002241GLsizei Texture2DArray::getWidth(GLint level) const
2242{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002243 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 +00002244}
2245
2246GLsizei Texture2DArray::getHeight(GLint level) const
2247{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002248 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 +00002249}
2250
2251GLsizei Texture2DArray::getDepth(GLint level) const
2252{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002253 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mLayerCounts[level] : 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002254}
2255
2256GLenum Texture2DArray::getInternalFormat(GLint level) const
2257{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002258 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 +00002259}
2260
2261GLenum Texture2DArray::getActualFormat(GLint level) const
2262{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002263 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 +00002264}
2265
2266bool Texture2DArray::isCompressed(GLint level) const
2267{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00002268 return IsFormatCompressed(getInternalFormat(level), mRenderer->getCurrentClientVersion());
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002269}
2270
2271bool Texture2DArray::isDepth(GLint level) const
2272{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00002273 return GetDepthBits(getInternalFormat(level), mRenderer->getCurrentClientVersion()) > 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002274}
2275
Geoff Lang005df412013-10-16 14:12:50 -04002276void Texture2DArray::setImage(GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002277{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00002278 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Geoff Lang005df412013-10-16 14:12:50 -04002279 GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
2280 : GetSizedInternalFormat(format, type, clientVersion);
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00002281 redefineImage(level, sizedInternalFormat, width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002282
Jamie Madill88f18f42013-09-18 14:36:19 -04002283 GLsizei inputDepthPitch = gl::GetDepthPitch(sizedInternalFormat, type, clientVersion, width, height, unpack.alignment);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002284
2285 for (int i = 0; i < depth; i++)
2286 {
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002287 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
Jamie Madill88f18f42013-09-18 14:36:19 -04002288 Texture::setImage(unpack, type, layerPixels, mImageArray[level][i]);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002289 }
2290}
2291
2292void Texture2DArray::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
2293{
2294 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
2295 redefineImage(level, format, width, height, depth);
2296
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002297 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2298 GLsizei inputDepthPitch = gl::GetDepthPitch(format, GL_UNSIGNED_BYTE, clientVersion, width, height, 1);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002299
2300 for (int i = 0; i < depth; i++)
2301 {
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002302 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002303 Texture::setCompressedImage(imageSize, layerPixels, mImageArray[level][i]);
2304 }
2305}
2306
Jamie Madill88f18f42013-09-18 14:36:19 -04002307void Texture2DArray::subImage(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002308{
Geoff Lang005df412013-10-16 14:12:50 -04002309 GLenum internalformat = getInternalFormat(level);
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002310 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Jamie Madill88f18f42013-09-18 14:36:19 -04002311 GLsizei inputDepthPitch = gl::GetDepthPitch(internalformat, type, clientVersion, width, height, unpack.alignment);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002312
2313 for (int i = 0; i < depth; i++)
2314 {
2315 int layer = zoffset + i;
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002316 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002317
Jamie Madill88f18f42013-09-18 14:36:19 -04002318 if (Texture::subImage(xoffset, yoffset, zoffset, width, height, 1, format, type, unpack, layerPixels, mImageArray[level][layer]))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002319 {
2320 commitRect(level, xoffset, yoffset, layer, width, height);
2321 }
2322 }
2323}
2324
2325void Texture2DArray::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
2326{
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002327 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2328 GLsizei inputDepthPitch = gl::GetDepthPitch(format, GL_UNSIGNED_BYTE, clientVersion, width, height, 1);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002329
2330 for (int i = 0; i < depth; i++)
2331 {
2332 int layer = zoffset + i;
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002333 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002334
2335 if (Texture::subImageCompressed(xoffset, yoffset, zoffset, width, height, 1, format, imageSize, layerPixels, mImageArray[level][layer]))
2336 {
2337 commitRect(level, xoffset, yoffset, layer, width, height);
2338 }
2339 }
2340}
2341
2342void Texture2DArray::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2343{
2344 delete mTexStorage;
Jamie Madilld4589c92013-10-24 17:49:34 -04002345 mTexStorage = new rx::TextureStorageInterface2DArray(mRenderer, levels, internalformat, IsRenderTargetUsage(mUsage), width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002346 mImmutable = true;
2347
2348 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2349 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002350 GLsizei levelWidth = std::max(width >> level, 1);
Geoff Lange836cf22013-08-05 14:12:37 -04002351 GLsizei levelHeight = std::max(height >> level, 1);
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002352
2353 // Clear this level
2354 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002355 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002356 delete mImageArray[level][layer];
2357 }
2358 delete[] mImageArray[level];
2359 mImageArray[level] = NULL;
2360 mLayerCounts[level] = 0;
2361
2362 if (level < levels)
2363 {
2364 // Create new images for this level
2365 mImageArray[level] = new rx::Image*[depth]();
2366 mLayerCounts[level] = depth;
2367
2368 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002369 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002370 mImageArray[level][layer] = mRenderer->createImage();
2371 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, levelWidth,
2372 levelHeight, 1, true);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002373 }
2374 }
2375 }
2376
2377 if (mTexStorage->isManaged())
2378 {
2379 int levels = levelCount();
2380
2381 for (int level = 0; level < levels; level++)
2382 {
2383 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2384 {
2385 mImageArray[level][layer]->setManagedSurface(mTexStorage, layer, level);
2386 }
2387 }
2388 }
2389}
2390
2391void Texture2DArray::generateMipmaps()
2392{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002393 int baseWidth = getBaseLevelWidth();
2394 int baseHeight = getBaseLevelHeight();
2395 int baseDepth = getBaseLevelDepth();
2396 GLenum baseFormat = getBaseLevelInternalFormat();
2397
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00002398 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Jamie Madill22f843a2013-10-24 17:49:36 -04002399 int q = mipLevels();
2400 for (int level = 1; level <= q; level++)
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00002401 {
Jamie Madill22f843a2013-10-24 17:49:36 -04002402 redefineImage(level, baseFormat, std::max(baseWidth >> level, 1), std::max(baseHeight >> level, 1), baseDepth);
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00002403 }
2404
2405 if (mTexStorage && mTexStorage->isRenderTarget())
2406 {
2407 for (int level = 1; level <= q; level++)
2408 {
2409 mTexStorage->generateMipmap(level);
2410
2411 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2412 {
2413 mImageArray[level][layer]->markClean();
2414 }
2415 }
2416 }
2417 else
2418 {
2419 for (int level = 1; level <= q; level++)
2420 {
2421 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2422 {
2423 mRenderer->generateMipmap(mImageArray[level][layer], mImageArray[level - 1][layer]);
2424 }
2425 }
2426 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002427}
2428
Jamie Madilld3d2a342013-10-07 10:46:35 -04002429const rx::Image *Texture2DArray::getBaseLevelImage() const
2430{
Jamie Madill152ed092013-10-09 17:01:15 -04002431 return (mLayerCounts[0] > 0 ? mImageArray[0][0] : NULL);
Jamie Madilld3d2a342013-10-07 10:46:35 -04002432}
2433
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002434void Texture2DArray::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
2435{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002436 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 +00002437 {
2438 return gl::error(GL_INVALID_VALUE);
2439 }
2440
Jamie Madill07edd442013-07-19 16:36:58 -04002441 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
2442 // the current level we're copying to is defined (with appropriate format, width & height)
2443 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
2444
2445 if (!mImageArray[level][0]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002446 {
2447 mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, x, y, width, height, source);
2448 mDirtyImages = true;
2449 }
2450 else
2451 {
Jamie Madille83d1a92013-10-24 17:49:33 -04002452 ensureRenderTarget();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002453
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002454 if (level < levelCount())
2455 {
Jamie Madill07edd442013-07-19 16:36:58 -04002456 updateTextureLevel(level);
2457
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002458 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2459
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002460 gl::Rectangle sourceRect;
2461 sourceRect.x = x;
2462 sourceRect.width = width;
2463 sourceRect.y = y;
2464 sourceRect.height = height;
2465
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002466 mRenderer->copyImage(source, sourceRect, gl::GetFormat(getInternalFormat(0), clientVersion),
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002467 xoffset, yoffset, zoffset, mTexStorage, level);
2468 }
2469 }
2470}
2471
Jamie Madillf8989902013-07-19 16:36:58 -04002472bool Texture2DArray::isSamplerComplete(const SamplerState &samplerState) const
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002473{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002474 GLsizei width = getBaseLevelWidth();
2475 GLsizei height = getBaseLevelHeight();
2476 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002477
2478 if (width <= 0 || height <= 0 || depth <= 0)
2479 {
2480 return false;
2481 }
2482
Jamie Madilld3d2a342013-10-07 10:46:35 -04002483 if (!IsTextureFilteringSupported(getBaseLevelInternalFormat(), mRenderer))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002484 {
Jamie Madillf8989902013-07-19 16:36:58 -04002485 if (samplerState.magFilter != GL_NEAREST ||
2486 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002487 {
2488 return false;
2489 }
2490 }
2491
Jamie Madillf8989902013-07-19 16:36:58 -04002492 if (IsMipmapFiltered(samplerState) && !isMipmapComplete())
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002493 {
2494 return false;
2495 }
2496
2497 return true;
2498}
2499
2500bool Texture2DArray::isMipmapComplete() const
2501{
Jamie Madill22f843a2013-10-24 17:49:36 -04002502 int q = mipLevels();
Jamie Madill07edd442013-07-19 16:36:58 -04002503
2504 for (int level = 1; level <= q; level++)
2505 {
2506 if (!isLevelComplete(level))
2507 {
2508 return false;
2509 }
2510 }
2511
2512 return true;
2513}
2514
2515bool Texture2DArray::isLevelComplete(int level) const
2516{
2517 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
2518
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002519 if (isImmutable())
2520 {
2521 return true;
2522 }
2523
Jamie Madilld3d2a342013-10-07 10:46:35 -04002524 GLsizei width = getBaseLevelWidth();
2525 GLsizei height = getBaseLevelHeight();
2526 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002527
2528 if (width <= 0 || height <= 0 || depth <= 0)
2529 {
2530 return false;
2531 }
2532
Jamie Madill07edd442013-07-19 16:36:58 -04002533 if (level == 0)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002534 {
Jamie Madill07edd442013-07-19 16:36:58 -04002535 return true;
2536 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002537
Jamie Madill07edd442013-07-19 16:36:58 -04002538 if (getInternalFormat(level) != getInternalFormat(0))
2539 {
2540 return false;
2541 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002542
Jamie Madill07edd442013-07-19 16:36:58 -04002543 if (getWidth(level) != std::max(1, width >> level))
2544 {
2545 return false;
2546 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002547
Jamie Madill07edd442013-07-19 16:36:58 -04002548 if (getHeight(level) != std::max(1, height >> level))
2549 {
2550 return false;
2551 }
2552
2553 if (getDepth(level) != depth)
2554 {
2555 return false;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002556 }
2557
2558 return true;
2559}
2560
Geoff Lang8040f572013-07-25 16:49:54 -04002561Renderbuffer *Texture2DArray::getRenderbuffer(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002562{
Geoff Lang8040f572013-07-25 16:49:54 -04002563 Renderbuffer *renderBuffer = mRenderbufferProxies.get(level, layer);
2564 if (!renderBuffer)
2565 {
Geoff Langd5d8e392013-07-25 16:53:03 -04002566 renderBuffer = new Renderbuffer(mRenderer, id(), new RenderbufferTexture2DArrayLayer(this, level, layer));
2567 mRenderbufferProxies.add(level, 0, renderBuffer);
Geoff Lang8040f572013-07-25 16:49:54 -04002568 }
2569
2570 return renderBuffer;
2571}
2572
Jamie Madille83d1a92013-10-24 17:49:33 -04002573unsigned int Texture2DArray::getRenderTargetSerial(GLint level, GLint layer)
Geoff Lang8040f572013-07-25 16:49:54 -04002574{
Jamie Madille83d1a92013-10-24 17:49:33 -04002575 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(level, layer) : 0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002576}
2577
2578int Texture2DArray::levelCount()
2579{
2580 return mTexStorage ? mTexStorage->levelCount() : 0;
2581}
2582
2583void Texture2DArray::createTexture()
2584{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002585 GLsizei width = getBaseLevelWidth();
2586 GLsizei height = getBaseLevelHeight();
2587 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002588
2589 if (width <= 0 || height <= 0 || depth <= 0)
2590 {
2591 return; // do not attempt to create native textures for nonexistant data
2592 }
2593
2594 GLint levels = creationLevels(width, height);
Jamie Madilld3d2a342013-10-07 10:46:35 -04002595 GLenum internalformat = getBaseLevelInternalFormat();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002596
2597 delete mTexStorage;
Jamie Madilld4589c92013-10-24 17:49:34 -04002598 mTexStorage = new rx::TextureStorageInterface2DArray(mRenderer, levels, internalformat, IsRenderTargetUsage(mUsage), width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002599
2600 if (mTexStorage->isManaged())
2601 {
2602 int levels = levelCount();
2603 for (int level = 0; level < levels; level++)
2604 {
2605 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2606 {
2607 mImageArray[level][layer]->setManagedSurface(mTexStorage, layer, level);
2608 }
2609 }
2610 }
2611
2612 mDirtyImages = true;
2613}
2614
2615void Texture2DArray::updateTexture()
2616{
Jamie Madilld9b9a502013-10-10 17:46:13 -04002617 int storageLevels = levelCount();
2618
2619 for (int level = 0; level < storageLevels; level++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002620 {
Jamie Madilld9b9a502013-10-10 17:46:13 -04002621 if (isLevelComplete(level))
2622 {
2623 updateTextureLevel(level);
2624 }
Jamie Madill07edd442013-07-19 16:36:58 -04002625 }
2626}
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002627
Jamie Madill07edd442013-07-19 16:36:58 -04002628void Texture2DArray::updateTextureLevel(int level)
2629{
Jamie Madillaee7ad82013-10-10 16:07:32 -04002630 ASSERT(level >= 0 && level < (int)ArraySize(mLayerCounts));
2631 ASSERT(isLevelComplete(level));
2632
Jamie Madill07edd442013-07-19 16:36:58 -04002633 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2634 {
Jamie Madillaee7ad82013-10-10 16:07:32 -04002635 ASSERT(mImageArray[level] != NULL && mImageArray[level][layer] != NULL);
2636 if (mImageArray[level][layer]->isDirty())
Jamie Madill07edd442013-07-19 16:36:58 -04002637 {
Jamie Madillaee7ad82013-10-10 16:07:32 -04002638 commitRect(level, 0, 0, layer, getWidth(level), getHeight(level));
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002639 }
2640 }
2641}
2642
Jamie Madille83d1a92013-10-24 17:49:33 -04002643bool Texture2DArray::ensureRenderTarget()
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002644{
Jamie Madille83d1a92013-10-24 17:49:33 -04002645 if (mTexStorage && mTexStorage->isRenderTarget())
2646 {
2647 return true;
2648 }
2649
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002650 rx::TextureStorageInterface2DArray *newTexStorage = NULL;
2651
Jamie Madilld3d2a342013-10-07 10:46:35 -04002652 GLsizei width = getBaseLevelWidth();
2653 GLsizei height = getBaseLevelHeight();
2654 GLsizei depth = getBaseLevelDepth();
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002655
2656 if (width != 0 && height != 0 && depth != 0)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002657 {
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002658 GLint levels = mTexStorage != NULL ? mTexStorage->levelCount() : creationLevels(width, height);
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002659 GLenum internalformat = getInternalFormat(0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002660
Jamie Madilld4589c92013-10-24 17:49:34 -04002661 newTexStorage = new rx::TextureStorageInterface2DArray(mRenderer, levels, internalformat, true, width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002662
2663 if (mTexStorage != NULL)
2664 {
2665 if (!mRenderer->copyToRenderTarget(newTexStorage, mTexStorage))
2666 {
2667 delete newTexStorage;
Jamie Madille83d1a92013-10-24 17:49:33 -04002668 return gl::error(GL_OUT_OF_MEMORY, false);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002669 }
2670 }
2671 }
2672
2673 delete mTexStorage;
2674 mTexStorage = newTexStorage;
2675
2676 mDirtyImages = true;
Jamie Madille83d1a92013-10-24 17:49:33 -04002677 return (mTexStorage && mTexStorage->isRenderTarget());
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002678}
2679
Geoff Lang8040f572013-07-25 16:49:54 -04002680rx::RenderTarget *Texture2DArray::getRenderTarget(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002681{
Geoff Lang8040f572013-07-25 16:49:54 -04002682 // ensure the underlying texture is created
2683 if (getStorage(true) == NULL)
2684 {
2685 return NULL;
2686 }
2687
Jamie Madillaee7ad82013-10-10 16:07:32 -04002688 updateTextureLevel(level);
Geoff Lang8040f572013-07-25 16:49:54 -04002689
2690 // ensure this is NOT a depth texture
2691 if (isDepth(level))
2692 {
2693 return NULL;
2694 }
2695
2696 return mTexStorage->getRenderTarget(level, layer);
2697}
2698
2699rx::RenderTarget *Texture2DArray::getDepthStencil(GLint level, GLint layer)
2700{
2701 // ensure the underlying texture is created
2702 if (getStorage(true) == NULL)
2703 {
2704 return NULL;
2705 }
2706
Jamie Madillaee7ad82013-10-10 16:07:32 -04002707 updateTextureLevel(level);
Geoff Lang8040f572013-07-25 16:49:54 -04002708
2709 // ensure this is a depth texture
2710 if (!isDepth(level))
2711 {
2712 return NULL;
2713 }
2714
2715 return mTexStorage->getRenderTarget(level, layer);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002716}
2717
2718rx::TextureStorageInterface *Texture2DArray::getStorage(bool renderTarget)
2719{
2720 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
2721 {
2722 if (renderTarget)
2723 {
Jamie Madille83d1a92013-10-24 17:49:33 -04002724 ensureRenderTarget();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002725 }
2726 else
2727 {
2728 createTexture();
2729 }
2730 }
2731
2732 return mTexStorage;
2733}
2734
Geoff Lang005df412013-10-16 14:12:50 -04002735void Texture2DArray::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002736{
2737 // If there currently is a corresponding storage texture image, it has these parameters
Jamie Madilld3d2a342013-10-07 10:46:35 -04002738 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2739 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
2740 const int storageDepth = getBaseLevelDepth();
Geoff Lang005df412013-10-16 14:12:50 -04002741 const GLenum storageFormat = getBaseLevelInternalFormat();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002742
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002743 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002744 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002745 delete mImageArray[level][layer];
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002746 }
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002747 delete[] mImageArray[level];
Jamie Madill152ed092013-10-09 17:01:15 -04002748 mImageArray[level] = NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002749 mLayerCounts[level] = depth;
2750
Jamie Madill152ed092013-10-09 17:01:15 -04002751 if (depth > 0)
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002752 {
Jamie Madill152ed092013-10-09 17:01:15 -04002753 mImageArray[level] = new rx::Image*[depth]();
2754
2755 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2756 {
2757 mImageArray[level][layer] = mRenderer->createImage();
2758 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, width, height, 1, false);
2759 }
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002760 }
2761
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002762 if (mTexStorage)
2763 {
2764 const int storageLevels = mTexStorage->levelCount();
2765
2766 if ((level >= storageLevels && storageLevels != 0) ||
2767 width != storageWidth ||
2768 height != storageHeight ||
2769 depth != storageDepth ||
2770 internalformat != storageFormat) // Discard mismatched storage
2771 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002772 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002773 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002774 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002775 {
2776 mImageArray[level][layer]->markDirty();
2777 }
2778 }
2779
2780 delete mTexStorage;
2781 mTexStorage = NULL;
2782 mDirtyImages = true;
2783 }
2784 }
2785}
2786
2787void Texture2DArray::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint layerTarget, GLsizei width, GLsizei height)
2788{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002789 if (level < levelCount() && layerTarget < getDepth(level))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002790 {
2791 rx::Image *image = mImageArray[level][layerTarget];
2792 if (image->updateSurface(mTexStorage, level, xoffset, yoffset, layerTarget, width, height))
2793 {
2794 image->markClean();
2795 }
2796 }
2797}
2798
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00002799}