blob: 34a01583a56dff143057e6bbe7dbc3d7a0b58f75 [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
Geoff Lang4907f2c2013-07-25 12:53:57 -0400355Texture2D::Texture2D(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_2D)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000356{
357 mTexStorage = NULL;
358 mSurface = NULL;
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000359
360 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
361 {
daniel@transgaming.com244e1832012-12-20 20:52:35 +0000362 mImageArray[i] = renderer->createImage();
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000363 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000364}
365
366Texture2D::~Texture2D()
367{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000368 delete mTexStorage;
369 mTexStorage = NULL;
370
371 if (mSurface)
372 {
373 mSurface->setBoundTexture(NULL);
374 mSurface = NULL;
375 }
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000376
377 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
378 {
379 delete mImageArray[i];
380 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000381}
382
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000383GLsizei Texture2D::getWidth(GLint level) const
384{
385 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000386 return mImageArray[level]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000387 else
388 return 0;
389}
390
391GLsizei Texture2D::getHeight(GLint level) const
392{
393 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000394 return mImageArray[level]->getHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000395 else
396 return 0;
397}
398
399GLenum Texture2D::getInternalFormat(GLint level) const
400{
401 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000402 return mImageArray[level]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000403 else
404 return GL_NONE;
405}
406
daniel@transgaming.com20d36662012-10-31 19:51:43 +0000407GLenum Texture2D::getActualFormat(GLint level) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000408{
409 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000410 return mImageArray[level]->getActualFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000411 else
412 return D3DFMT_UNKNOWN;
413}
414
Geoff Lang005df412013-10-16 14:12:50 -0400415void Texture2D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000416{
417 releaseTexImage();
shannon.woods@transgaming.com8a406682013-02-28 23:15:26 +0000418
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000419 // If there currently is a corresponding storage texture image, it has these parameters
Jamie Madilld3d2a342013-10-07 10:46:35 -0400420 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
421 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
Geoff Lang005df412013-10-16 14:12:50 -0400422 const GLenum storageFormat = getBaseLevelInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000423
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000424 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, width, height, 1, false);
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000425
426 if (mTexStorage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000427 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000428 const int storageLevels = mTexStorage->levelCount();
429
430 if ((level >= storageLevels && storageLevels != 0) ||
431 width != storageWidth ||
432 height != storageHeight ||
433 internalformat != storageFormat) // Discard mismatched storage
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000434 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000435 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
436 {
437 mImageArray[i]->markDirty();
438 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000439
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000440 delete mTexStorage;
441 mTexStorage = NULL;
442 mDirtyImages = true;
443 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000444 }
445}
446
Geoff Lang005df412013-10-16 14:12:50 -0400447void 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 +0000448{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +0000449 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Geoff Lang005df412013-10-16 14:12:50 -0400450 GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
451 : GetSizedInternalFormat(format, type, clientVersion);
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +0000452 redefineImage(level, sizedInternalFormat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000453
Jamie Madill8cc7d972013-10-10 15:51:55 -0400454 bool fastUnpacked = false;
455
Jamie Madill1beb1db2013-09-18 14:36:28 -0400456 // Attempt a fast gpu copy of the pixel data to the surface
Jamie Madill8cc7d972013-10-10 15:51:55 -0400457 if (isFastUnpackable(unpack, sizedInternalFormat) && isLevelComplete(level))
Jamie Madill1beb1db2013-09-18 14:36:28 -0400458 {
Jamie Madill8cc7d972013-10-10 15:51:55 -0400459 // Will try to create RT storage if it does not exist
460 rx::RenderTarget *destRenderTarget = getRenderTarget(level);
461 Box destArea(0, 0, 0, getWidth(level), getHeight(level), 1);
462
463 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget))
464 {
465 // Ensure we don't overwrite our newly initialized data
466 mImageArray[level]->markClean();
467
468 fastUnpacked = true;
469 }
Jamie Madill1beb1db2013-09-18 14:36:28 -0400470 }
Jamie Madill8cc7d972013-10-10 15:51:55 -0400471
472 if (!fastUnpacked)
Jamie Madill1beb1db2013-09-18 14:36:28 -0400473 {
474 Texture::setImage(unpack, type, pixels, mImageArray[level]);
475 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000476}
477
478void Texture2D::bindTexImage(egl::Surface *surface)
479{
480 releaseTexImage();
481
Geoff Lang005df412013-10-16 14:12:50 -0400482 GLenum internalformat = surface->getFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000483
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000484 mImageArray[0]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, surface->getWidth(), surface->getHeight(), 1, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000485
486 delete mTexStorage;
daniel@transgaming.comd8353dd2012-12-20 21:11:14 +0000487 mTexStorage = new rx::TextureStorageInterface2D(mRenderer, surface->getSwapChain());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000488
489 mDirtyImages = true;
490 mSurface = surface;
491 mSurface->setBoundTexture(this);
492}
493
494void Texture2D::releaseTexImage()
495{
496 if (mSurface)
497 {
498 mSurface->setBoundTexture(NULL);
499 mSurface = NULL;
500
501 if (mTexStorage)
502 {
503 delete mTexStorage;
504 mTexStorage = NULL;
505 }
506
507 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
508 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000509 mImageArray[i]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000510 }
511 }
512}
513
514void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
515{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000516 // 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 +0000517 redefineImage(level, format, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000518
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000519 Texture::setCompressedImage(imageSize, pixels, mImageArray[level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000520}
521
522void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
523{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000524 if (level < levelCount())
525 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000526 rx::Image *image = mImageArray[level];
daniel@transgaming.com0f195ad2012-10-31 19:51:59 +0000527 if (image->updateSurface(mTexStorage, level, xoffset, yoffset, width, height))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000528 {
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000529 image->markClean();
530 }
531 }
532}
533
Jamie Madill88f18f42013-09-18 14:36:19 -0400534void 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 +0000535{
Jamie Madill065e1a32013-10-10 15:11:50 -0400536 bool fastUnpacked = false;
537
538 if (isFastUnpackable(unpack, getInternalFormat(level)) && isLevelComplete(level))
539 {
540 rx::RenderTarget *renderTarget = getRenderTarget(level);
541 Box destArea(xoffset, yoffset, 0, width, height, 1);
542
543 if (renderTarget && fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, renderTarget))
544 {
545 // Ensure we don't overwrite our newly initialized data
546 mImageArray[level]->markClean();
547
548 fastUnpacked = true;
549 }
550 }
551
552 if (!fastUnpacked && Texture::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, mImageArray[level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000553 {
554 commitRect(level, xoffset, yoffset, width, height);
555 }
556}
557
558void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
559{
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000560 if (Texture::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000561 {
562 commitRect(level, xoffset, yoffset, width, height);
563 }
564}
565
566void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
567{
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +0000568 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Geoff Lang005df412013-10-16 14:12:50 -0400569 GLenum sizedInternalFormat = IsSizedInternalFormat(format, clientVersion) ? format
570 : GetSizedInternalFormat(format, GL_UNSIGNED_BYTE, clientVersion);
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +0000571 redefineImage(level, sizedInternalFormat, width, height);
shannon.woods@transgaming.com8a406682013-02-28 23:15:26 +0000572
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000573 if (!mImageArray[level]->isRenderableFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000574 {
shannon.woods%transgaming.com@gtempaccount.come5dcce72013-04-13 03:44:33 +0000575 mImageArray[level]->copy(0, 0, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000576 mDirtyImages = true;
577 }
578 else
579 {
Jamie Madille83d1a92013-10-24 17:49:33 -0400580 ensureRenderTarget();
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000581 mImageArray[level]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000582
583 if (width != 0 && height != 0 && level < levelCount())
584 {
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +0000585 gl::Rectangle sourceRect;
586 sourceRect.x = x;
587 sourceRect.width = width;
588 sourceRect.y = y;
589 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000590
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +0000591 mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000592 }
593 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000594}
595
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +0000596void 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 +0000597{
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +0000598 if (xoffset + width > mImageArray[level]->getWidth() || yoffset + height > mImageArray[level]->getHeight() || zoffset != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000599 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +0000600 return gl::error(GL_INVALID_VALUE);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000601 }
602
Jamie Madill07edd442013-07-19 16:36:58 -0400603 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
604 // the current level we're copying to is defined (with appropriate format, width & height)
605 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
606
607 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000608 {
shannon.woods%transgaming.com@gtempaccount.come5dcce72013-04-13 03:44:33 +0000609 mImageArray[level]->copy(xoffset, yoffset, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000610 mDirtyImages = true;
611 }
612 else
613 {
Jamie Madille83d1a92013-10-24 17:49:33 -0400614 ensureRenderTarget();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000615
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000616 if (level < levelCount())
617 {
Jamie Madill07edd442013-07-19 16:36:58 -0400618 updateTextureLevel(level);
619
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +0000620 GLuint clientVersion = mRenderer->getCurrentClientVersion();
621
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +0000622 gl::Rectangle sourceRect;
623 sourceRect.x = x;
624 sourceRect.width = width;
625 sourceRect.y = y;
626 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000627
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +0000628 mRenderer->copyImage(source, sourceRect,
Jamie Madilld3d2a342013-10-07 10:46:35 -0400629 gl::GetFormat(getBaseLevelInternalFormat(), clientVersion),
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +0000630 xoffset, yoffset, mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000631 }
632 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000633}
634
635void Texture2D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height)
636{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000637 delete mTexStorage;
Jamie Madilld4589c92013-10-24 17:49:34 -0400638 mTexStorage = new rx::TextureStorageInterface2D(mRenderer, levels, internalformat, IsRenderTargetUsage(mUsage), width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000639 mImmutable = true;
640
641 for (int level = 0; level < levels; level++)
642 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000643 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, width, height, 1, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000644 width = std::max(1, width >> 1);
645 height = std::max(1, height >> 1);
646 }
647
648 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
649 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000650 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000651 }
652
653 if (mTexStorage->isManaged())
654 {
655 int levels = levelCount();
656
657 for (int level = 0; level < levels; level++)
658 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000659 mImageArray[level]->setManagedSurface(mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000660 }
661 }
662}
663
664// Tests for 2D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85.
Jamie Madillf8989902013-07-19 16:36:58 -0400665bool Texture2D::isSamplerComplete(const SamplerState &samplerState) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000666{
Jamie Madilld3d2a342013-10-07 10:46:35 -0400667 GLsizei width = getBaseLevelWidth();
668 GLsizei height = getBaseLevelHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000669
670 if (width <= 0 || height <= 0)
671 {
672 return false;
673 }
674
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000675 if (!IsTextureFilteringSupported(getInternalFormat(0), mRenderer))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000676 {
Jamie Madillf8989902013-07-19 16:36:58 -0400677 if (samplerState.magFilter != GL_NEAREST ||
678 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000679 {
680 return false;
681 }
682 }
683
daniel@transgaming.comea32d482012-11-28 19:33:18 +0000684 bool npotSupport = mRenderer->getNonPower2TextureSupport();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000685
686 if (!npotSupport)
687 {
Jamie Madillf8989902013-07-19 16:36:58 -0400688 if ((samplerState.wrapS != GL_CLAMP_TO_EDGE && !isPow2(width)) ||
689 (samplerState.wrapT != GL_CLAMP_TO_EDGE && !isPow2(height)))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000690 {
691 return false;
692 }
693 }
694
Jamie Madillf8989902013-07-19 16:36:58 -0400695 if (IsMipmapFiltered(samplerState))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000696 {
697 if (!npotSupport)
698 {
699 if (!isPow2(width) || !isPow2(height))
700 {
701 return false;
702 }
703 }
704
705 if (!isMipmapComplete())
706 {
707 return false;
708 }
709 }
710
Geoff Langc82fc412013-07-10 14:43:42 -0400711 // OpenGLES 3.0.2 spec section 3.8.13 states that a texture is not mipmap complete if:
712 // The internalformat specified for the texture arrays is a sized internal depth or
713 // depth and stencil format (see table 3.13), the value of TEXTURE_COMPARE_-
714 // MODE is NONE, and either the magnification filter is not NEAREST or the mini-
715 // fication filter is neither NEAREST nor NEAREST_MIPMAP_NEAREST.
716 if (gl::GetDepthBits(getInternalFormat(0), mRenderer->getCurrentClientVersion()) > 0)
717 {
718 if (mSamplerState.compareMode == GL_NONE)
719 {
720 if ((mSamplerState.minFilter != GL_NEAREST && mSamplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST) ||
721 mSamplerState.magFilter != GL_NEAREST)
722 {
723 return false;
724 }
725 }
726 }
727
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000728 return true;
729}
730
731// Tests for 2D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
732bool Texture2D::isMipmapComplete() const
733{
Jamie Madilld3d2a342013-10-07 10:46:35 -0400734 GLsizei width = getBaseLevelWidth();
735 GLsizei height = getBaseLevelHeight();
Jamie Madill07edd442013-07-19 16:36:58 -0400736
737 int q = log2(std::max(width, height));
738
739 for (int level = 0; level <= q; level++)
740 {
741 if (!isLevelComplete(level))
742 {
743 return false;
744 }
745 }
746
747 return true;
748}
749
750bool Texture2D::isLevelComplete(int level) const
751{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000752 if (isImmutable())
753 {
754 return true;
755 }
756
Jamie Madilld3d2a342013-10-07 10:46:35 -0400757 GLsizei width = getBaseLevelWidth();
758 GLsizei height = getBaseLevelHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000759
760 if (width <= 0 || height <= 0)
761 {
762 return false;
763 }
764
Jamie Madill07edd442013-07-19 16:36:58 -0400765 // The base image level is complete if the width and height are positive
766 if (level == 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000767 {
Jamie Madill07edd442013-07-19 16:36:58 -0400768 return true;
769 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000770
Jamie Madill07edd442013-07-19 16:36:58 -0400771 ASSERT(level >= 1 && level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
772 rx::Image *image = mImageArray[level];
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000773
Jamie Madilld3d2a342013-10-07 10:46:35 -0400774 if (image->getInternalFormat() != getBaseLevelInternalFormat())
Jamie Madill07edd442013-07-19 16:36:58 -0400775 {
776 return false;
777 }
778
779 if (image->getWidth() != std::max(1, width >> level))
780 {
781 return false;
782 }
783
784 if (image->getHeight() != std::max(1, height >> level))
785 {
786 return false;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000787 }
788
789 return true;
790}
791
792bool Texture2D::isCompressed(GLint level) const
793{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000794 return IsFormatCompressed(getInternalFormat(level), mRenderer->getCurrentClientVersion());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000795}
796
797bool Texture2D::isDepth(GLint level) const
798{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000799 return GetDepthBits(getInternalFormat(level), mRenderer->getCurrentClientVersion()) > 0;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000800}
801
daniel@transgaming.comf032cb82012-10-31 19:51:52 +0000802// Constructs a native texture resource from the texture images
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000803void Texture2D::createTexture()
804{
Jamie Madilld3d2a342013-10-07 10:46:35 -0400805 GLsizei width = getBaseLevelWidth();
806 GLsizei height = getBaseLevelHeight();
daniel@transgaming.come6a09842012-09-17 21:28:55 +0000807
808 if (!(width > 0 && height > 0))
daniel@transgaming.comf032cb82012-10-31 19:51:52 +0000809 return; // do not attempt to create native textures for nonexistant data
daniel@transgaming.come6a09842012-09-17 21:28:55 +0000810
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000811 GLint levels = creationLevels(width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000812
813 delete mTexStorage;
Jamie Madilld4589c92013-10-24 17:49:34 -0400814 mTexStorage = new rx::TextureStorageInterface2D(mRenderer, levels, getBaseLevelInternalFormat(), IsRenderTargetUsage(mUsage), width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000815
816 if (mTexStorage->isManaged())
817 {
818 int levels = levelCount();
819
820 for (int level = 0; level < levels; level++)
821 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000822 mImageArray[level]->setManagedSurface(mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000823 }
824 }
825
826 mDirtyImages = true;
827}
828
829void Texture2D::updateTexture()
830{
Jamie Madilld9b9a502013-10-10 17:46:13 -0400831 int storageLevels = levelCount();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000832
Jamie Madilld9b9a502013-10-10 17:46:13 -0400833 for (int level = 0; level < storageLevels; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000834 {
Jamie Madilld9b9a502013-10-10 17:46:13 -0400835 if (isLevelComplete(level))
836 {
837 updateTextureLevel(level);
838 }
Jamie Madill07edd442013-07-19 16:36:58 -0400839 }
840}
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000841
Jamie Madill07edd442013-07-19 16:36:58 -0400842void Texture2D::updateTextureLevel(int level)
843{
844 ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
Jamie Madillaee7ad82013-10-10 16:07:32 -0400845 ASSERT(isLevelComplete(level));
Jamie Madill07edd442013-07-19 16:36:58 -0400846
Jamie Madillaee7ad82013-10-10 16:07:32 -0400847 if (mImageArray[level]->isDirty())
Jamie Madill07edd442013-07-19 16:36:58 -0400848 {
Jamie Madillaee7ad82013-10-10 16:07:32 -0400849 commitRect(level, 0, 0, getWidth(level), getHeight(level));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000850 }
851}
852
Jamie Madille83d1a92013-10-24 17:49:33 -0400853bool Texture2D::ensureRenderTarget()
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000854{
Jamie Madille83d1a92013-10-24 17:49:33 -0400855 if (mTexStorage && mTexStorage->isRenderTarget())
856 {
857 return true;
858 }
859
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000860 rx::TextureStorageInterface2D *newTexStorage = NULL;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000861
Jamie Madilld3d2a342013-10-07 10:46:35 -0400862 GLsizei width = getBaseLevelWidth();
863 GLsizei height = getBaseLevelHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000864
Jamie Madilld3d2a342013-10-07 10:46:35 -0400865 if (width != 0 && height != 0)
866 {
867 GLint levels = mTexStorage != NULL ? mTexStorage->levelCount() : creationLevels(width, height);
868
Jamie Madilld4589c92013-10-24 17:49:34 -0400869 newTexStorage = new rx::TextureStorageInterface2D(mRenderer, levels, getBaseLevelInternalFormat(), true, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000870
871 if (mTexStorage != NULL)
872 {
daniel@transgaming.com1d80eee2012-11-28 19:33:31 +0000873 if (!mRenderer->copyToRenderTarget(newTexStorage, mTexStorage))
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +0000874 {
875 delete newTexStorage;
Jamie Madille83d1a92013-10-24 17:49:33 -0400876 return gl::error(GL_OUT_OF_MEMORY, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000877 }
878 }
879 }
880
881 delete mTexStorage;
882 mTexStorage = newTexStorage;
883
884 mDirtyImages = true;
Jamie Madille83d1a92013-10-24 17:49:33 -0400885
886 return (mTexStorage && mTexStorage->isRenderTarget());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000887}
888
889void Texture2D::generateMipmaps()
890{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000891 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Jamie Madilld3d2a342013-10-07 10:46:35 -0400892 unsigned int q = log2(std::max(getBaseLevelWidth(), getBaseLevelHeight()));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000893 for (unsigned int i = 1; i <= q; i++)
894 {
Jamie Madilld3d2a342013-10-07 10:46:35 -0400895 redefineImage(i, getBaseLevelInternalFormat(),
896 std::max(getBaseLevelWidth() >> i, 1),
897 std::max(getBaseLevelHeight() >> i, 1));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000898 }
899
900 if (mTexStorage && mTexStorage->isRenderTarget())
901 {
902 for (unsigned int i = 1; i <= q; i++)
903 {
daniel@transgaming.com0ad830b2012-10-31 19:52:12 +0000904 mTexStorage->generateMipmap(i);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000905
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000906 mImageArray[i]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000907 }
908 }
909 else
910 {
911 for (unsigned int i = 1; i <= q; i++)
912 {
daniel@transgaming.com4ba24062012-12-20 20:54:24 +0000913 mRenderer->generateMipmap(mImageArray[i], mImageArray[i - 1]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000914 }
915 }
916}
917
Jamie Madilld3d2a342013-10-07 10:46:35 -0400918const rx::Image *Texture2D::getBaseLevelImage() const
919{
920 return mImageArray[0];
921}
922
Geoff Lang8040f572013-07-25 16:49:54 -0400923Renderbuffer *Texture2D::getRenderbuffer(GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000924{
Geoff Lang8040f572013-07-25 16:49:54 -0400925 Renderbuffer *renderBuffer = mRenderbufferProxies.get(level, 0);
926 if (!renderBuffer)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000927 {
Geoff Lang8040f572013-07-25 16:49:54 -0400928 renderBuffer = new Renderbuffer(mRenderer, id(), new RenderbufferTexture2D(this, level));
929 mRenderbufferProxies.add(level, 0, renderBuffer);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000930 }
931
Geoff Lang8040f572013-07-25 16:49:54 -0400932 return renderBuffer;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000933}
934
Geoff Lang8040f572013-07-25 16:49:54 -0400935unsigned int Texture2D::getRenderTargetSerial(GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000936{
Jamie Madille83d1a92013-10-24 17:49:33 -0400937 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(level) : 0);
Geoff Lang8040f572013-07-25 16:49:54 -0400938}
939
940rx::RenderTarget *Texture2D::getRenderTarget(GLint level)
941{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000942 // ensure the underlying texture is created
943 if (getStorage(true) == NULL)
944 {
945 return NULL;
946 }
947
Jamie Madillaee7ad82013-10-10 16:07:32 -0400948 updateTextureLevel(level);
Geoff Lang8040f572013-07-25 16:49:54 -0400949
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000950 // ensure this is NOT a depth texture
Geoff Lang8040f572013-07-25 16:49:54 -0400951 if (isDepth(level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000952 {
953 return NULL;
954 }
daniel@transgaming.com34da3972012-12-20 21:10:29 +0000955
Geoff Lang8040f572013-07-25 16:49:54 -0400956 return mTexStorage->getRenderTarget(level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000957}
958
Geoff Lang8040f572013-07-25 16:49:54 -0400959rx::RenderTarget *Texture2D::getDepthSencil(GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000960{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000961 // ensure the underlying texture is created
962 if (getStorage(true) == NULL)
963 {
964 return NULL;
965 }
966
Jamie Madillaee7ad82013-10-10 16:07:32 -0400967 updateTextureLevel(level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000968
969 // ensure this is actually a depth texture
Geoff Lang8040f572013-07-25 16:49:54 -0400970 if (!isDepth(level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000971 {
972 return NULL;
973 }
Geoff Lang8040f572013-07-25 16:49:54 -0400974
975 return mTexStorage->getRenderTarget(level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000976}
977
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +0000978int Texture2D::levelCount()
979{
shannon.woods@transgaming.com5016f8e2013-02-28 23:20:57 +0000980 return mTexStorage ? mTexStorage->levelCount() : 0;
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +0000981}
982
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000983rx::TextureStorageInterface *Texture2D::getStorage(bool renderTarget)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000984{
985 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
986 {
987 if (renderTarget)
988 {
Jamie Madille83d1a92013-10-24 17:49:33 -0400989 ensureRenderTarget();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000990 }
991 else
992 {
993 createTexture();
994 }
995 }
996
997 return mTexStorage;
998}
999
Geoff Lang4907f2c2013-07-25 12:53:57 -04001000TextureCubeMap::TextureCubeMap(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_CUBE_MAP)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001001{
1002 mTexStorage = NULL;
1003 for (int i = 0; i < 6; i++)
1004 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001005 for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
1006 {
daniel@transgaming.com244e1832012-12-20 20:52:35 +00001007 mImageArray[i][j] = renderer->createImage();
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001008 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001009 }
1010}
1011
1012TextureCubeMap::~TextureCubeMap()
1013{
1014 for (int i = 0; i < 6; i++)
1015 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001016 for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
1017 {
1018 delete mImageArray[i][j];
1019 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001020 }
1021
1022 delete mTexStorage;
1023 mTexStorage = NULL;
1024}
1025
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001026GLsizei TextureCubeMap::getWidth(GLenum target, GLint level) const
1027{
1028 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Jamie Madill2db197c2013-10-24 17:49:35 -04001029 return mImageArray[targetToIndex(target)][level]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001030 else
1031 return 0;
1032}
1033
1034GLsizei TextureCubeMap::getHeight(GLenum target, GLint level) const
1035{
1036 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Jamie Madill2db197c2013-10-24 17:49:35 -04001037 return mImageArray[targetToIndex(target)][level]->getHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001038 else
1039 return 0;
1040}
1041
1042GLenum TextureCubeMap::getInternalFormat(GLenum target, GLint level) const
1043{
1044 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Jamie Madill2db197c2013-10-24 17:49:35 -04001045 return mImageArray[targetToIndex(target)][level]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001046 else
1047 return GL_NONE;
1048}
1049
daniel@transgaming.com20d36662012-10-31 19:51:43 +00001050GLenum TextureCubeMap::getActualFormat(GLenum target, GLint level) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001051{
1052 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Jamie Madill2db197c2013-10-24 17:49:35 -04001053 return mImageArray[targetToIndex(target)][level]->getActualFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001054 else
1055 return D3DFMT_UNKNOWN;
1056}
1057
Geoff Lang005df412013-10-16 14:12:50 -04001058void 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 +00001059{
Jamie Madill88f18f42013-09-18 14:36:19 -04001060 setImage(0, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001061}
1062
Geoff Lang005df412013-10-16 14:12:50 -04001063void 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 +00001064{
Jamie Madill88f18f42013-09-18 14:36:19 -04001065 setImage(1, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001066}
1067
Geoff Lang005df412013-10-16 14:12:50 -04001068void 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 +00001069{
Jamie Madill88f18f42013-09-18 14:36:19 -04001070 setImage(2, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001071}
1072
Geoff Lang005df412013-10-16 14:12:50 -04001073void 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 +00001074{
Jamie Madill88f18f42013-09-18 14:36:19 -04001075 setImage(3, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001076}
1077
Geoff Lang005df412013-10-16 14:12:50 -04001078void 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 +00001079{
Jamie Madill88f18f42013-09-18 14:36:19 -04001080 setImage(4, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001081}
1082
Geoff Lang005df412013-10-16 14:12:50 -04001083void 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 +00001084{
Jamie Madill88f18f42013-09-18 14:36:19 -04001085 setImage(5, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001086}
1087
Jamie Madill2db197c2013-10-24 17:49:35 -04001088void 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 +00001089{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001090 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
Jamie Madill2db197c2013-10-24 17:49:35 -04001091 int faceIndex = targetToIndex(target);
1092 redefineImage(faceIndex, level, format, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001093
Jamie Madill2db197c2013-10-24 17:49:35 -04001094 Texture::setCompressedImage(imageSize, pixels, mImageArray[faceIndex][level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001095}
1096
Jamie Madill2db197c2013-10-24 17:49:35 -04001097void TextureCubeMap::commitRect(int faceIndex, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001098{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001099 if (level < levelCount())
1100 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001101 rx::Image *image = mImageArray[faceIndex][level];
1102 if (image->updateSurface(mTexStorage, faceIndex, level, xoffset, yoffset, width, height))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001103 image->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001104 }
1105}
1106
Jamie Madill88f18f42013-09-18 14:36:19 -04001107void 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 +00001108{
Jamie Madill2db197c2013-10-24 17:49:35 -04001109 int faceIndex = targetToIndex(target);
1110 if (Texture::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, mImageArray[faceIndex][level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001111 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001112 commitRect(faceIndex, level, xoffset, yoffset, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001113 }
1114}
1115
1116void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1117{
Jamie Madill2db197c2013-10-24 17:49:35 -04001118 int faceIndex = targetToIndex(target);
1119 if (Texture::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[faceIndex][level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001120 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001121 commitRect(faceIndex, level, xoffset, yoffset, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001122 }
1123}
1124
1125// Tests for cube map sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 86.
Jamie Madillf8989902013-07-19 16:36:58 -04001126bool TextureCubeMap::isSamplerComplete(const SamplerState &samplerState) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001127{
Jamie Madilld3d2a342013-10-07 10:46:35 -04001128 int size = getBaseLevelWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001129
Jamie Madillf8989902013-07-19 16:36:58 -04001130 bool mipmapping = IsMipmapFiltered(samplerState);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001131
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001132 if (!IsTextureFilteringSupported(getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0), mRenderer))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001133 {
Jamie Madillf8989902013-07-19 16:36:58 -04001134 if (samplerState.magFilter != GL_NEAREST ||
1135 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001136 {
1137 return false;
1138 }
1139 }
1140
daniel@transgaming.comea32d482012-11-28 19:33:18 +00001141 if (!isPow2(size) && !mRenderer->getNonPower2TextureSupport())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001142 {
Jamie Madillf8989902013-07-19 16:36:58 -04001143 if (samplerState.wrapS != GL_CLAMP_TO_EDGE || samplerState.wrapT != GL_CLAMP_TO_EDGE || mipmapping)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001144 {
1145 return false;
1146 }
1147 }
1148
1149 if (!mipmapping)
1150 {
1151 if (!isCubeComplete())
1152 {
1153 return false;
1154 }
1155 }
1156 else
1157 {
1158 if (!isMipmapCubeComplete()) // Also tests for isCubeComplete()
1159 {
1160 return false;
1161 }
1162 }
1163
1164 return true;
1165}
1166
1167// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1168bool TextureCubeMap::isCubeComplete() const
1169{
Jamie Madillc1f8b162013-10-07 10:46:38 -04001170 int baseWidth = getBaseLevelWidth();
1171 int baseHeight = getBaseLevelHeight();
1172 GLenum baseFormat = getBaseLevelInternalFormat();
1173
1174 if (baseWidth <= 0 || baseWidth != baseHeight)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001175 {
1176 return false;
1177 }
1178
Jamie Madill2db197c2013-10-24 17:49:35 -04001179 for (int faceIndex = 1; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001180 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001181 const rx::Image &faceBaseImage = *mImageArray[faceIndex][0];
Jamie Madillc1f8b162013-10-07 10:46:38 -04001182
1183 if (faceBaseImage.getWidth() != baseWidth ||
1184 faceBaseImage.getHeight() != baseHeight ||
1185 faceBaseImage.getInternalFormat() != baseFormat )
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001186 {
1187 return false;
1188 }
1189 }
1190
1191 return true;
1192}
1193
1194bool TextureCubeMap::isMipmapCubeComplete() const
1195{
1196 if (isImmutable())
1197 {
1198 return true;
1199 }
1200
1201 if (!isCubeComplete())
1202 {
1203 return false;
1204 }
1205
Jamie Madilld3d2a342013-10-07 10:46:35 -04001206 GLsizei size = getBaseLevelWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001207 int q = log2(size);
1208
1209 for (int face = 0; face < 6; face++)
1210 {
1211 for (int level = 1; level <= q; level++)
1212 {
Jamie Madill07edd442013-07-19 16:36:58 -04001213 if (!isFaceLevelComplete(face, level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001214 {
1215 return false;
1216 }
1217 }
1218 }
1219
1220 return true;
1221}
1222
Jamie Madill2db197c2013-10-24 17:49:35 -04001223bool TextureCubeMap::isFaceLevelComplete(int faceIndex, int level) const
Jamie Madill07edd442013-07-19 16:36:58 -04001224{
Jamie Madill2db197c2013-10-24 17:49:35 -04001225 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
Jamie Madill07edd442013-07-19 16:36:58 -04001226
1227 if (isImmutable())
1228 {
1229 return true;
1230 }
1231
Jamie Madilld3d2a342013-10-07 10:46:35 -04001232 int baseSize = getBaseLevelWidth();
Jamie Madill07edd442013-07-19 16:36:58 -04001233
Jamie Madilld3d2a342013-10-07 10:46:35 -04001234 if (baseSize <= 0)
Jamie Madill07edd442013-07-19 16:36:58 -04001235 {
1236 return false;
1237 }
1238
Jamie Madilld3d2a342013-10-07 10:46:35 -04001239 // "isCubeComplete" checks for base level completeness and we must call that
1240 // to determine if any face at level 0 is complete. We omit that check here
1241 // to avoid re-checking cube-completeness for every face at level 0.
Jamie Madill07edd442013-07-19 16:36:58 -04001242 if (level == 0)
1243 {
1244 return true;
1245 }
1246
Jamie Madilld3d2a342013-10-07 10:46:35 -04001247 // Check that non-zero levels are consistent with the base level.
Jamie Madill2db197c2013-10-24 17:49:35 -04001248 const rx::Image *faceLevelImage = mImageArray[faceIndex][level];
Jamie Madill07edd442013-07-19 16:36:58 -04001249
Jamie Madilld3d2a342013-10-07 10:46:35 -04001250 if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat())
Jamie Madill07edd442013-07-19 16:36:58 -04001251 {
1252 return false;
1253 }
1254
Jamie Madilld3d2a342013-10-07 10:46:35 -04001255 if (faceLevelImage->getWidth() != std::max(1, baseSize >> level))
Jamie Madill07edd442013-07-19 16:36:58 -04001256 {
1257 return false;
1258 }
1259
1260 return true;
1261}
1262
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001263bool TextureCubeMap::isCompressed(GLenum target, GLint level) const
1264{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001265 return IsFormatCompressed(getInternalFormat(target, level), mRenderer->getCurrentClientVersion());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001266}
1267
Geoff Lang8040f572013-07-25 16:49:54 -04001268bool TextureCubeMap::isDepth(GLenum target, GLint level) const
1269{
1270 return GetDepthBits(getInternalFormat(target, level), mRenderer->getCurrentClientVersion()) > 0;
1271}
1272
daniel@transgaming.comf032cb82012-10-31 19:51:52 +00001273// Constructs a native texture resource from the texture images, or returns an existing one
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001274void TextureCubeMap::createTexture()
1275{
Jamie Madilld3d2a342013-10-07 10:46:35 -04001276 GLsizei size = getBaseLevelWidth();
daniel@transgaming.come6a09842012-09-17 21:28:55 +00001277
1278 if (!(size > 0))
daniel@transgaming.comf032cb82012-10-31 19:51:52 +00001279 return; // do not attempt to create native textures for nonexistant data
daniel@transgaming.come6a09842012-09-17 21:28:55 +00001280
sminns@adobe.comce1189b2012-09-18 20:06:35 +00001281 GLint levels = creationLevels(size);
Jamie Madilld3d2a342013-10-07 10:46:35 -04001282 GLenum internalformat = getBaseLevelInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001283
1284 delete mTexStorage;
Jamie Madilld4589c92013-10-24 17:49:34 -04001285 mTexStorage = new rx::TextureStorageInterfaceCube(mRenderer, levels, internalformat, IsRenderTargetUsage(mUsage), size);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001286
1287 if (mTexStorage->isManaged())
1288 {
1289 int levels = levelCount();
1290
Jamie Madill2db197c2013-10-24 17:49:35 -04001291 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001292 {
1293 for (int level = 0; level < levels; level++)
1294 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001295 mImageArray[faceIndex][level]->setManagedSurface(mTexStorage, faceIndex, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001296 }
1297 }
1298 }
1299
1300 mDirtyImages = true;
1301}
1302
1303void TextureCubeMap::updateTexture()
1304{
Jamie Madilld9b9a502013-10-10 17:46:13 -04001305 int storageLevels = levelCount();
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +00001306
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001307 for (int face = 0; face < 6; face++)
1308 {
Jamie Madilld9b9a502013-10-10 17:46:13 -04001309 for (int level = 0; level < storageLevels; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001310 {
Jamie Madilld9b9a502013-10-10 17:46:13 -04001311 if (isFaceLevelComplete(face, level))
1312 {
1313 updateTextureFaceLevel(face, level);
1314 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001315 }
1316 }
1317}
1318
Jamie Madill2db197c2013-10-24 17:49:35 -04001319void TextureCubeMap::updateTextureFaceLevel(int faceIndex, int level)
Jamie Madill07edd442013-07-19 16:36:58 -04001320{
Jamie Madill2db197c2013-10-24 17:49:35 -04001321 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1322 rx::Image *image = mImageArray[faceIndex][level];
Jamie Madill07edd442013-07-19 16:36:58 -04001323
1324 if (image->isDirty())
1325 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001326 commitRect(faceIndex, level, 0, 0, image->getWidth(), image->getHeight());
Jamie Madill07edd442013-07-19 16:36:58 -04001327 }
1328}
1329
Jamie Madille83d1a92013-10-24 17:49:33 -04001330bool TextureCubeMap::ensureRenderTarget()
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001331{
Jamie Madille83d1a92013-10-24 17:49:33 -04001332 if (mTexStorage && mTexStorage->isRenderTarget())
1333 {
1334 return true;
1335 }
1336
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001337 rx::TextureStorageInterfaceCube *newTexStorage = NULL;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001338
Jamie Madilld3d2a342013-10-07 10:46:35 -04001339 if (getBaseLevelWidth() != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001340 {
Jamie Madilld3d2a342013-10-07 10:46:35 -04001341 GLsizei size = getBaseLevelWidth();
shannon.woods@transgaming.com6bb48862013-02-28 23:09:34 +00001342 GLint levels = mTexStorage != NULL ? mTexStorage->levelCount() : creationLevels(size);
Jamie Madilld3d2a342013-10-07 10:46:35 -04001343 GLenum internalformat = getBaseLevelInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001344
Jamie Madilld4589c92013-10-24 17:49:34 -04001345 newTexStorage = new rx::TextureStorageInterfaceCube(mRenderer, levels, internalformat, true, size);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001346
1347 if (mTexStorage != NULL)
1348 {
daniel@transgaming.com1d80eee2012-11-28 19:33:31 +00001349 if (!mRenderer->copyToRenderTarget(newTexStorage, mTexStorage))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001350 {
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +00001351 delete newTexStorage;
Jamie Madille83d1a92013-10-24 17:49:33 -04001352 return gl::error(GL_OUT_OF_MEMORY, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001353 }
1354 }
1355 }
1356
1357 delete mTexStorage;
1358 mTexStorage = newTexStorage;
1359
1360 mDirtyImages = true;
Jamie Madille83d1a92013-10-24 17:49:33 -04001361 return (mTexStorage && mTexStorage->isRenderTarget());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001362}
1363
Geoff Lang005df412013-10-16 14:12:50 -04001364void 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 +00001365{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001366 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Geoff Lang005df412013-10-16 14:12:50 -04001367 GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
1368 : GetSizedInternalFormat(format, type, clientVersion);
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001369
1370 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001371
Jamie Madill88f18f42013-09-18 14:36:19 -04001372 Texture::setImage(unpack, type, pixels, mImageArray[faceIndex][level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001373}
1374
Jamie Madill2db197c2013-10-24 17:49:35 -04001375int TextureCubeMap::targetToIndex(GLenum target)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001376{
1377 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
1378 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
1379 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
1380 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
1381 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
1382
Jamie Madill2db197c2013-10-24 17:49:35 -04001383 return target - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001384}
1385
Jamie Madill2db197c2013-10-24 17:49:35 -04001386void TextureCubeMap::redefineImage(int faceIndex, GLint level, GLenum internalformat, GLsizei width, GLsizei height)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001387{
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001388 // If there currently is a corresponding storage texture image, it has these parameters
Jamie Madilld3d2a342013-10-07 10:46:35 -04001389 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1390 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
Geoff Lang005df412013-10-16 14:12:50 -04001391 const GLenum storageFormat = getBaseLevelInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001392
Jamie Madill2db197c2013-10-24 17:49:35 -04001393 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, width, height, 1, false);
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001394
1395 if (mTexStorage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001396 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001397 const int storageLevels = mTexStorage->levelCount();
1398
1399 if ((level >= storageLevels && storageLevels != 0) ||
1400 width != storageWidth ||
1401 height != storageHeight ||
1402 internalformat != storageFormat) // Discard mismatched storage
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001403 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001404 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001405 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001406 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001407 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001408 mImageArray[faceIndex][level]->markDirty();
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001409 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001410 }
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001411
1412 delete mTexStorage;
1413 mTexStorage = NULL;
1414
1415 mDirtyImages = true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001416 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001417 }
1418}
1419
1420void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1421{
Jamie Madill2db197c2013-10-24 17:49:35 -04001422 int faceIndex = targetToIndex(target);
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001423 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Geoff Lang005df412013-10-16 14:12:50 -04001424 GLenum sizedInternalFormat = IsSizedInternalFormat(format, clientVersion) ? format
1425 : GetSizedInternalFormat(format, GL_UNSIGNED_BYTE, clientVersion);
Jamie Madill2db197c2013-10-24 17:49:35 -04001426 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001427
Jamie Madill2db197c2013-10-24 17:49:35 -04001428 if (!mImageArray[faceIndex][level]->isRenderableFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001429 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001430 mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001431 mDirtyImages = true;
1432 }
1433 else
1434 {
Jamie Madille83d1a92013-10-24 17:49:33 -04001435 ensureRenderTarget();
Jamie Madill2db197c2013-10-24 17:49:35 -04001436 mImageArray[faceIndex][level]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001437
1438 ASSERT(width == height);
1439
1440 if (width > 0 && level < levelCount())
1441 {
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +00001442 gl::Rectangle sourceRect;
1443 sourceRect.x = x;
1444 sourceRect.width = width;
1445 sourceRect.y = y;
1446 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001447
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +00001448 mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001449 }
1450 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001451}
1452
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001453void 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 +00001454{
Jamie Madill2db197c2013-10-24 17:49:35 -04001455 int faceIndex = targetToIndex(target);
1456
1457 GLsizei size = mImageArray[faceIndex][level]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001458
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001459 if (xoffset + width > size || yoffset + height > size || zoffset != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001460 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +00001461 return gl::error(GL_INVALID_VALUE);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001462 }
1463
Jamie Madilld3d2a342013-10-07 10:46:35 -04001464 // We can only make our texture storage to a render target if the level we're copying *to* is complete
1465 // and the base level is cube-complete. The base level must be cube complete (common case) because we cannot
1466 // rely on the "getBaseLevel*" methods reliably otherwise.
Jamie Madill2db197c2013-10-24 17:49:35 -04001467 bool canCreateRenderTarget = isFaceLevelComplete(faceIndex, level) && isCubeComplete();
Jamie Madill07edd442013-07-19 16:36:58 -04001468
Jamie Madill2db197c2013-10-24 17:49:35 -04001469 if (!mImageArray[faceIndex][level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001470 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001471 mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001472 mDirtyImages = true;
1473 }
1474 else
1475 {
Jamie Madille83d1a92013-10-24 17:49:33 -04001476 ensureRenderTarget();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001477
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001478 if (level < levelCount())
1479 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001480 updateTextureFaceLevel(faceIndex, level);
Jamie Madill07edd442013-07-19 16:36:58 -04001481
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001482 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1483
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +00001484 gl::Rectangle sourceRect;
1485 sourceRect.x = x;
1486 sourceRect.width = width;
1487 sourceRect.y = y;
1488 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001489
Jamie Madilld3d2a342013-10-07 10:46:35 -04001490 mRenderer->copyImage(source, sourceRect, gl::GetFormat(getBaseLevelInternalFormat(), clientVersion),
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +00001491 xoffset, yoffset, mTexStorage, target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001492 }
1493 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001494}
1495
1496void TextureCubeMap::storage(GLsizei levels, GLenum internalformat, GLsizei size)
1497{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001498 delete mTexStorage;
Jamie Madilld4589c92013-10-24 17:49:34 -04001499 mTexStorage = new rx::TextureStorageInterfaceCube(mRenderer, levels, internalformat, IsRenderTargetUsage(mUsage), size);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001500 mImmutable = true;
1501
1502 for (int level = 0; level < levels; level++)
1503 {
Geoff Langd3110192013-09-24 11:52:47 -04001504 GLsizei mipSize = std::max(1, size >> level);
Jamie Madill2db197c2013-10-24 17:49:35 -04001505 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001506 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001507 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, mipSize, mipSize, 1, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001508 }
1509 }
1510
1511 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1512 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001513 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001514 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001515 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, GL_NONE, 0, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001516 }
1517 }
1518
1519 if (mTexStorage->isManaged())
1520 {
1521 int levels = levelCount();
1522
Jamie Madill2db197c2013-10-24 17:49:35 -04001523 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001524 {
1525 for (int level = 0; level < levels; level++)
1526 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001527 mImageArray[faceIndex][level]->setManagedSurface(mTexStorage, faceIndex, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001528 }
1529 }
1530 }
1531}
1532
1533void TextureCubeMap::generateMipmaps()
1534{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001535 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Jamie Madill2db197c2013-10-24 17:49:35 -04001536 int q = log2(getBaseLevelWidth());
1537 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001538 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001539 for (int level = 1; level <= q; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001540 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001541 redefineImage(faceIndex, level, mImageArray[faceIndex][0]->getInternalFormat(),
1542 std::max(mImageArray[faceIndex][0]->getWidth() >> level, 1),
1543 std::max(mImageArray[faceIndex][0]->getWidth() >> level, 1));
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 Madilld3d2a342013-10-07 10:46:35 -04001828 unsigned int q = log2(std::max(getBaseLevelWidth(), getBaseLevelHeight()));
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001829 for (unsigned int i = 1; i <= q; i++)
1830 {
Jamie Madilld3d2a342013-10-07 10:46:35 -04001831 redefineImage(i, getBaseLevelInternalFormat(),
1832 std::max(getBaseLevelWidth() >> i, 1),
1833 std::max(getBaseLevelHeight() >> i, 1),
1834 std::max(getBaseLevelDepth() >> i, 1));
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001835 }
1836
1837 if (mTexStorage && mTexStorage->isRenderTarget())
1838 {
1839 for (unsigned int i = 1; i <= q; i++)
1840 {
1841 mTexStorage->generateMipmap(i);
1842
1843 mImageArray[i]->markClean();
1844 }
1845 }
1846 else
1847 {
1848 for (unsigned int i = 1; i <= q; i++)
1849 {
1850 mRenderer->generateMipmap(mImageArray[i], mImageArray[i - 1]);
1851 }
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 Madilld3d2a342013-10-07 10:46:35 -04001929 GLsizei width = getBaseLevelWidth();
1930 GLsizei height = getBaseLevelHeight();
1931 GLsizei depth = getBaseLevelDepth();
Jamie Madill07edd442013-07-19 16:36:58 -04001932
1933 int q = log2(std::max(std::max(width, height), depth));
1934
1935 for (int level = 0; level <= q; level++)
1936 {
1937 if (!isLevelComplete(level))
1938 {
1939 return false;
1940 }
1941 }
1942
1943 return true;
1944}
1945
1946bool Texture3D::isLevelComplete(int level) const
1947{
1948 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1949
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001950 if (isImmutable())
1951 {
1952 return true;
1953 }
1954
Jamie Madilld3d2a342013-10-07 10:46:35 -04001955 GLsizei width = getBaseLevelWidth();
1956 GLsizei height = getBaseLevelHeight();
1957 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001958
1959 if (width <= 0 || height <= 0 || depth <= 0)
1960 {
1961 return false;
1962 }
1963
Jamie Madill07edd442013-07-19 16:36:58 -04001964 if (level == 0)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001965 {
Jamie Madill07edd442013-07-19 16:36:58 -04001966 return true;
1967 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001968
Jamie Madill07edd442013-07-19 16:36:58 -04001969 rx::Image *levelImage = mImageArray[level];
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001970
Jamie Madilld3d2a342013-10-07 10:46:35 -04001971 if (levelImage->getInternalFormat() != getBaseLevelInternalFormat())
Jamie Madill07edd442013-07-19 16:36:58 -04001972 {
1973 return false;
1974 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001975
Jamie Madill07edd442013-07-19 16:36:58 -04001976 if (levelImage->getWidth() != std::max(1, width >> level))
1977 {
1978 return false;
1979 }
1980
1981 if (levelImage->getHeight() != std::max(1, height >> level))
1982 {
1983 return false;
1984 }
1985
1986 if (levelImage->getDepth() != std::max(1, depth >> level))
1987 {
1988 return false;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001989 }
1990
1991 return true;
1992}
1993
Geoff Lang8040f572013-07-25 16:49:54 -04001994Renderbuffer *Texture3D::getRenderbuffer(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001995{
Geoff Lang8040f572013-07-25 16:49:54 -04001996 Renderbuffer *renderBuffer = mRenderbufferProxies.get(level, layer);
1997 if (!renderBuffer)
1998 {
Geoff Langd5d8e392013-07-25 16:53:03 -04001999 renderBuffer = new Renderbuffer(mRenderer, id(), new RenderbufferTexture3DLayer(this, level, layer));
2000 mRenderbufferProxies.add(level, 0, renderBuffer);
Geoff Lang8040f572013-07-25 16:49:54 -04002001 }
2002
2003 return renderBuffer;
2004}
2005
2006unsigned int Texture3D::getRenderTargetSerial(GLint level, GLint layer)
2007{
Jamie Madille83d1a92013-10-24 17:49:33 -04002008 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(level, layer) : 0);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002009}
2010
2011int Texture3D::levelCount()
2012{
2013 return mTexStorage ? mTexStorage->levelCount() : 0;
2014}
2015
2016void Texture3D::createTexture()
2017{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002018 GLsizei width = getBaseLevelWidth();
2019 GLsizei height = getBaseLevelHeight();
2020 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002021
2022 if (!(width > 0 && height > 0 && depth > 0))
2023 return; // do not attempt to create native textures for nonexistant data
2024
2025 GLint levels = creationLevels(width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002026
2027 delete mTexStorage;
Jamie Madilld4589c92013-10-24 17:49:34 -04002028 mTexStorage = new rx::TextureStorageInterface3D(mRenderer, levels, getBaseLevelInternalFormat(), IsRenderTargetUsage(mUsage), width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002029
2030 if (mTexStorage->isManaged())
2031 {
2032 int levels = levelCount();
2033
2034 for (int level = 0; level < levels; level++)
2035 {
2036 mImageArray[level]->setManagedSurface(mTexStorage, level);
2037 }
2038 }
2039
2040 mDirtyImages = true;
2041}
2042
2043void Texture3D::updateTexture()
2044{
Jamie Madilld9b9a502013-10-10 17:46:13 -04002045 int storageLevels = levelCount();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002046
Jamie Madilld9b9a502013-10-10 17:46:13 -04002047 for (int level = 0; level < storageLevels; level++)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002048 {
Jamie Madilld9b9a502013-10-10 17:46:13 -04002049 if (isLevelComplete(level))
2050 {
2051 updateTextureLevel(level);
2052 }
Jamie Madill07edd442013-07-19 16:36:58 -04002053 }
2054}
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002055
Jamie Madill07edd442013-07-19 16:36:58 -04002056void Texture3D::updateTextureLevel(int level)
2057{
2058 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
Jamie Madillaee7ad82013-10-10 16:07:32 -04002059 ASSERT(isLevelComplete(level));
Jamie Madill07edd442013-07-19 16:36:58 -04002060
Jamie Madillaee7ad82013-10-10 16:07:32 -04002061 if (mImageArray[level]->isDirty())
Jamie Madill07edd442013-07-19 16:36:58 -04002062 {
Jamie Madillaee7ad82013-10-10 16:07:32 -04002063 commitRect(level, 0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002064 }
2065}
2066
Jamie Madille83d1a92013-10-24 17:49:33 -04002067bool Texture3D::ensureRenderTarget()
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002068{
Jamie Madille83d1a92013-10-24 17:49:33 -04002069 if (mTexStorage && mTexStorage->isRenderTarget())
2070 {
2071 return true;
2072 }
2073
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002074 rx::TextureStorageInterface3D *newTexStorage = NULL;
2075
Jamie Madilld3d2a342013-10-07 10:46:35 -04002076 if (getBaseLevelWidth() != 0 && getBaseLevelHeight() != 0 && getBaseLevelDepth() != 0)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002077 {
Jamie Madilld3d2a342013-10-07 10:46:35 -04002078 GLsizei width = getBaseLevelWidth();
2079 GLsizei height = getBaseLevelHeight();
2080 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002081 GLint levels = mTexStorage != NULL ? mTexStorage->levelCount() : creationLevels(width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002082
Jamie Madilld4589c92013-10-24 17:49:34 -04002083 newTexStorage = new rx::TextureStorageInterface3D(mRenderer, levels, getBaseLevelInternalFormat(), true, width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002084
2085 if (mTexStorage != NULL)
2086 {
2087 if (!mRenderer->copyToRenderTarget(newTexStorage, mTexStorage))
2088 {
2089 delete newTexStorage;
Jamie Madille83d1a92013-10-24 17:49:33 -04002090 return gl::error(GL_OUT_OF_MEMORY, false);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002091 }
2092 }
2093 }
2094
2095 delete mTexStorage;
2096 mTexStorage = newTexStorage;
2097
2098 mDirtyImages = true;
Jamie Madille83d1a92013-10-24 17:49:33 -04002099 return (mTexStorage && mTexStorage->isRenderTarget());
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002100}
2101
Jamie Madilla2d4e552013-10-10 15:12:01 -04002102rx::RenderTarget *Texture3D::getRenderTarget(GLint level)
2103{
2104 // ensure the underlying texture is created
2105 if (getStorage(true) == NULL)
2106 {
2107 return NULL;
2108 }
2109
Jamie Madillaee7ad82013-10-10 16:07:32 -04002110 updateTextureLevel(level);
Jamie Madilla2d4e552013-10-10 15:12:01 -04002111
2112 // ensure this is NOT a depth texture
2113 if (isDepth(level))
2114 {
2115 return NULL;
2116 }
2117
2118 return mTexStorage->getRenderTarget(level);
2119}
2120
Geoff Lang8040f572013-07-25 16:49:54 -04002121rx::RenderTarget *Texture3D::getRenderTarget(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002122{
Geoff Lang8040f572013-07-25 16:49:54 -04002123 // ensure the underlying texture is created
2124 if (getStorage(true) == NULL)
2125 {
2126 return NULL;
2127 }
2128
2129 updateTexture();
2130
2131 // ensure this is NOT a depth texture
2132 if (isDepth(level))
2133 {
2134 return NULL;
2135 }
2136
2137 return mTexStorage->getRenderTarget(level, layer);
2138}
2139
2140rx::RenderTarget *Texture3D::getDepthStencil(GLint level, GLint layer)
2141{
2142 // ensure the underlying texture is created
2143 if (getStorage(true) == NULL)
2144 {
2145 return NULL;
2146 }
2147
Jamie Madillaee7ad82013-10-10 16:07:32 -04002148 updateTextureLevel(level);
Geoff Lang8040f572013-07-25 16:49:54 -04002149
2150 // ensure this is a depth texture
2151 if (!isDepth(level))
2152 {
2153 return NULL;
2154 }
2155
2156 return mTexStorage->getRenderTarget(level, layer);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002157}
2158
2159rx::TextureStorageInterface *Texture3D::getStorage(bool renderTarget)
2160{
2161 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
2162 {
2163 if (renderTarget)
2164 {
Jamie Madille83d1a92013-10-24 17:49:33 -04002165 ensureRenderTarget();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002166 }
2167 else
2168 {
2169 createTexture();
2170 }
2171 }
2172
2173 return mTexStorage;
2174}
2175
Geoff Lang005df412013-10-16 14:12:50 -04002176void Texture3D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002177{
2178 // If there currently is a corresponding storage texture image, it has these parameters
Jamie Madilld3d2a342013-10-07 10:46:35 -04002179 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2180 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
2181 const int storageDepth = std::max(1, getBaseLevelDepth() >> level);
Geoff Lang005df412013-10-16 14:12:50 -04002182 const GLenum storageFormat = getBaseLevelInternalFormat();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002183
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00002184 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, false);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002185
2186 if (mTexStorage)
2187 {
2188 const int storageLevels = mTexStorage->levelCount();
2189
2190 if ((level >= storageLevels && storageLevels != 0) ||
2191 width != storageWidth ||
2192 height != storageHeight ||
2193 depth != storageDepth ||
2194 internalformat != storageFormat) // Discard mismatched storage
2195 {
2196 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
2197 {
2198 mImageArray[i]->markDirty();
2199 }
2200
2201 delete mTexStorage;
2202 mTexStorage = NULL;
2203 mDirtyImages = true;
2204 }
2205 }
2206}
2207
2208void Texture3D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth)
2209{
2210 if (level < levelCount())
2211 {
2212 rx::Image *image = mImageArray[level];
2213 if (image->updateSurface(mTexStorage, level, xoffset, yoffset, zoffset, width, height, depth))
2214 {
2215 image->markClean();
2216 }
2217 }
2218}
2219
Geoff Lang4907f2c2013-07-25 12:53:57 -04002220Texture2DArray::Texture2DArray(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_2D_ARRAY)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002221{
2222 mTexStorage = NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002223
2224 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2225 {
2226 mLayerCounts[level] = 0;
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002227 mImageArray[level] = NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002228 }
2229}
2230
2231Texture2DArray::~Texture2DArray()
2232{
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002233 delete mTexStorage;
2234 mTexStorage = NULL;
2235 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2236 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002237 for (int layer = 0; layer < mLayerCounts[level]; ++layer)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002238 {
2239 delete mImageArray[level][layer];
2240 }
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002241 delete[] mImageArray[level];
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002242 }
2243}
2244
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002245GLsizei Texture2DArray::getWidth(GLint level) const
2246{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002247 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 +00002248}
2249
2250GLsizei Texture2DArray::getHeight(GLint level) const
2251{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002252 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 +00002253}
2254
2255GLsizei Texture2DArray::getDepth(GLint level) const
2256{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002257 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mLayerCounts[level] : 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002258}
2259
2260GLenum Texture2DArray::getInternalFormat(GLint level) const
2261{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002262 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 +00002263}
2264
2265GLenum Texture2DArray::getActualFormat(GLint level) const
2266{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002267 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 +00002268}
2269
2270bool Texture2DArray::isCompressed(GLint level) const
2271{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00002272 return IsFormatCompressed(getInternalFormat(level), mRenderer->getCurrentClientVersion());
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002273}
2274
2275bool Texture2DArray::isDepth(GLint level) const
2276{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00002277 return GetDepthBits(getInternalFormat(level), mRenderer->getCurrentClientVersion()) > 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002278}
2279
Geoff Lang005df412013-10-16 14:12:50 -04002280void 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 +00002281{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00002282 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Geoff Lang005df412013-10-16 14:12:50 -04002283 GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
2284 : GetSizedInternalFormat(format, type, clientVersion);
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00002285 redefineImage(level, sizedInternalFormat, width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002286
Jamie Madill88f18f42013-09-18 14:36:19 -04002287 GLsizei inputDepthPitch = gl::GetDepthPitch(sizedInternalFormat, type, clientVersion, width, height, unpack.alignment);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002288
2289 for (int i = 0; i < depth; i++)
2290 {
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002291 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
Jamie Madill88f18f42013-09-18 14:36:19 -04002292 Texture::setImage(unpack, type, layerPixels, mImageArray[level][i]);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002293 }
2294}
2295
2296void Texture2DArray::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
2297{
2298 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
2299 redefineImage(level, format, width, height, depth);
2300
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002301 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2302 GLsizei inputDepthPitch = gl::GetDepthPitch(format, GL_UNSIGNED_BYTE, clientVersion, width, height, 1);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002303
2304 for (int i = 0; i < depth; i++)
2305 {
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002306 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002307 Texture::setCompressedImage(imageSize, layerPixels, mImageArray[level][i]);
2308 }
2309}
2310
Jamie Madill88f18f42013-09-18 14:36:19 -04002311void 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 +00002312{
Geoff Lang005df412013-10-16 14:12:50 -04002313 GLenum internalformat = getInternalFormat(level);
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002314 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Jamie Madill88f18f42013-09-18 14:36:19 -04002315 GLsizei inputDepthPitch = gl::GetDepthPitch(internalformat, type, clientVersion, width, height, unpack.alignment);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002316
2317 for (int i = 0; i < depth; i++)
2318 {
2319 int layer = zoffset + i;
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002320 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002321
Jamie Madill88f18f42013-09-18 14:36:19 -04002322 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 +00002323 {
2324 commitRect(level, xoffset, yoffset, layer, width, height);
2325 }
2326 }
2327}
2328
2329void Texture2DArray::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
2330{
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002331 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2332 GLsizei inputDepthPitch = gl::GetDepthPitch(format, GL_UNSIGNED_BYTE, clientVersion, width, height, 1);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002333
2334 for (int i = 0; i < depth; i++)
2335 {
2336 int layer = zoffset + i;
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002337 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002338
2339 if (Texture::subImageCompressed(xoffset, yoffset, zoffset, width, height, 1, format, imageSize, layerPixels, mImageArray[level][layer]))
2340 {
2341 commitRect(level, xoffset, yoffset, layer, width, height);
2342 }
2343 }
2344}
2345
2346void Texture2DArray::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2347{
2348 delete mTexStorage;
Jamie Madilld4589c92013-10-24 17:49:34 -04002349 mTexStorage = new rx::TextureStorageInterface2DArray(mRenderer, levels, internalformat, IsRenderTargetUsage(mUsage), width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002350 mImmutable = true;
2351
2352 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2353 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002354 GLsizei levelWidth = std::max(width >> level, 1);
Geoff Lange836cf22013-08-05 14:12:37 -04002355 GLsizei levelHeight = std::max(height >> level, 1);
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002356
2357 // Clear this level
2358 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002359 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002360 delete mImageArray[level][layer];
2361 }
2362 delete[] mImageArray[level];
2363 mImageArray[level] = NULL;
2364 mLayerCounts[level] = 0;
2365
2366 if (level < levels)
2367 {
2368 // Create new images for this level
2369 mImageArray[level] = new rx::Image*[depth]();
2370 mLayerCounts[level] = depth;
2371
2372 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002373 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002374 mImageArray[level][layer] = mRenderer->createImage();
2375 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, levelWidth,
2376 levelHeight, 1, true);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002377 }
2378 }
2379 }
2380
2381 if (mTexStorage->isManaged())
2382 {
2383 int levels = levelCount();
2384
2385 for (int level = 0; level < levels; level++)
2386 {
2387 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2388 {
2389 mImageArray[level][layer]->setManagedSurface(mTexStorage, layer, level);
2390 }
2391 }
2392 }
2393}
2394
2395void Texture2DArray::generateMipmaps()
2396{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002397 int baseWidth = getBaseLevelWidth();
2398 int baseHeight = getBaseLevelHeight();
2399 int baseDepth = getBaseLevelDepth();
2400 GLenum baseFormat = getBaseLevelInternalFormat();
2401
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00002402 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Jamie Madilld3d2a342013-10-07 10:46:35 -04002403 int q = log2(std::max(baseWidth, baseHeight));
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00002404 for (int i = 1; i <= q; i++)
2405 {
Jamie Madilld3d2a342013-10-07 10:46:35 -04002406 redefineImage(i, baseFormat, std::max(baseWidth >> i, 1), std::max(baseHeight >> i, 1), baseDepth);
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00002407 }
2408
2409 if (mTexStorage && mTexStorage->isRenderTarget())
2410 {
2411 for (int level = 1; level <= q; level++)
2412 {
2413 mTexStorage->generateMipmap(level);
2414
2415 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2416 {
2417 mImageArray[level][layer]->markClean();
2418 }
2419 }
2420 }
2421 else
2422 {
2423 for (int level = 1; level <= q; level++)
2424 {
2425 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2426 {
2427 mRenderer->generateMipmap(mImageArray[level][layer], mImageArray[level - 1][layer]);
2428 }
2429 }
2430 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002431}
2432
Jamie Madilld3d2a342013-10-07 10:46:35 -04002433const rx::Image *Texture2DArray::getBaseLevelImage() const
2434{
Jamie Madill152ed092013-10-09 17:01:15 -04002435 return (mLayerCounts[0] > 0 ? mImageArray[0][0] : NULL);
Jamie Madilld3d2a342013-10-07 10:46:35 -04002436}
2437
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002438void Texture2DArray::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
2439{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002440 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 +00002441 {
2442 return gl::error(GL_INVALID_VALUE);
2443 }
2444
Jamie Madill07edd442013-07-19 16:36:58 -04002445 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
2446 // the current level we're copying to is defined (with appropriate format, width & height)
2447 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
2448
2449 if (!mImageArray[level][0]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002450 {
2451 mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, x, y, width, height, source);
2452 mDirtyImages = true;
2453 }
2454 else
2455 {
Jamie Madille83d1a92013-10-24 17:49:33 -04002456 ensureRenderTarget();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002457
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002458 if (level < levelCount())
2459 {
Jamie Madill07edd442013-07-19 16:36:58 -04002460 updateTextureLevel(level);
2461
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002462 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2463
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002464 gl::Rectangle sourceRect;
2465 sourceRect.x = x;
2466 sourceRect.width = width;
2467 sourceRect.y = y;
2468 sourceRect.height = height;
2469
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002470 mRenderer->copyImage(source, sourceRect, gl::GetFormat(getInternalFormat(0), clientVersion),
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002471 xoffset, yoffset, zoffset, mTexStorage, level);
2472 }
2473 }
2474}
2475
Jamie Madillf8989902013-07-19 16:36:58 -04002476bool Texture2DArray::isSamplerComplete(const SamplerState &samplerState) const
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002477{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002478 GLsizei width = getBaseLevelWidth();
2479 GLsizei height = getBaseLevelHeight();
2480 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002481
2482 if (width <= 0 || height <= 0 || depth <= 0)
2483 {
2484 return false;
2485 }
2486
Jamie Madilld3d2a342013-10-07 10:46:35 -04002487 if (!IsTextureFilteringSupported(getBaseLevelInternalFormat(), mRenderer))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002488 {
Jamie Madillf8989902013-07-19 16:36:58 -04002489 if (samplerState.magFilter != GL_NEAREST ||
2490 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002491 {
2492 return false;
2493 }
2494 }
2495
Jamie Madillf8989902013-07-19 16:36:58 -04002496 if (IsMipmapFiltered(samplerState) && !isMipmapComplete())
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002497 {
2498 return false;
2499 }
2500
2501 return true;
2502}
2503
2504bool Texture2DArray::isMipmapComplete() const
2505{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002506 GLsizei width = getBaseLevelWidth();
2507 GLsizei height = getBaseLevelHeight();
Jamie Madill07edd442013-07-19 16:36:58 -04002508
2509 int q = log2(std::max(width, height));
2510
2511 for (int level = 1; level <= q; level++)
2512 {
2513 if (!isLevelComplete(level))
2514 {
2515 return false;
2516 }
2517 }
2518
2519 return true;
2520}
2521
2522bool Texture2DArray::isLevelComplete(int level) const
2523{
2524 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
2525
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002526 if (isImmutable())
2527 {
2528 return true;
2529 }
2530
Jamie Madilld3d2a342013-10-07 10:46:35 -04002531 GLsizei width = getBaseLevelWidth();
2532 GLsizei height = getBaseLevelHeight();
2533 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002534
2535 if (width <= 0 || height <= 0 || depth <= 0)
2536 {
2537 return false;
2538 }
2539
Jamie Madill07edd442013-07-19 16:36:58 -04002540 if (level == 0)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002541 {
Jamie Madill07edd442013-07-19 16:36:58 -04002542 return true;
2543 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002544
Jamie Madill07edd442013-07-19 16:36:58 -04002545 if (getInternalFormat(level) != getInternalFormat(0))
2546 {
2547 return false;
2548 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002549
Jamie Madill07edd442013-07-19 16:36:58 -04002550 if (getWidth(level) != std::max(1, width >> level))
2551 {
2552 return false;
2553 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002554
Jamie Madill07edd442013-07-19 16:36:58 -04002555 if (getHeight(level) != std::max(1, height >> level))
2556 {
2557 return false;
2558 }
2559
2560 if (getDepth(level) != depth)
2561 {
2562 return false;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002563 }
2564
2565 return true;
2566}
2567
Geoff Lang8040f572013-07-25 16:49:54 -04002568Renderbuffer *Texture2DArray::getRenderbuffer(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002569{
Geoff Lang8040f572013-07-25 16:49:54 -04002570 Renderbuffer *renderBuffer = mRenderbufferProxies.get(level, layer);
2571 if (!renderBuffer)
2572 {
Geoff Langd5d8e392013-07-25 16:53:03 -04002573 renderBuffer = new Renderbuffer(mRenderer, id(), new RenderbufferTexture2DArrayLayer(this, level, layer));
2574 mRenderbufferProxies.add(level, 0, renderBuffer);
Geoff Lang8040f572013-07-25 16:49:54 -04002575 }
2576
2577 return renderBuffer;
2578}
2579
Jamie Madille83d1a92013-10-24 17:49:33 -04002580unsigned int Texture2DArray::getRenderTargetSerial(GLint level, GLint layer)
Geoff Lang8040f572013-07-25 16:49:54 -04002581{
Jamie Madille83d1a92013-10-24 17:49:33 -04002582 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(level, layer) : 0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002583}
2584
2585int Texture2DArray::levelCount()
2586{
2587 return mTexStorage ? mTexStorage->levelCount() : 0;
2588}
2589
2590void Texture2DArray::createTexture()
2591{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002592 GLsizei width = getBaseLevelWidth();
2593 GLsizei height = getBaseLevelHeight();
2594 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002595
2596 if (width <= 0 || height <= 0 || depth <= 0)
2597 {
2598 return; // do not attempt to create native textures for nonexistant data
2599 }
2600
2601 GLint levels = creationLevels(width, height);
Jamie Madilld3d2a342013-10-07 10:46:35 -04002602 GLenum internalformat = getBaseLevelInternalFormat();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002603
2604 delete mTexStorage;
Jamie Madilld4589c92013-10-24 17:49:34 -04002605 mTexStorage = new rx::TextureStorageInterface2DArray(mRenderer, levels, internalformat, IsRenderTargetUsage(mUsage), width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002606
2607 if (mTexStorage->isManaged())
2608 {
2609 int levels = levelCount();
2610 for (int level = 0; level < levels; level++)
2611 {
2612 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2613 {
2614 mImageArray[level][layer]->setManagedSurface(mTexStorage, layer, level);
2615 }
2616 }
2617 }
2618
2619 mDirtyImages = true;
2620}
2621
2622void Texture2DArray::updateTexture()
2623{
Jamie Madilld9b9a502013-10-10 17:46:13 -04002624 int storageLevels = levelCount();
2625
2626 for (int level = 0; level < storageLevels; level++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002627 {
Jamie Madilld9b9a502013-10-10 17:46:13 -04002628 if (isLevelComplete(level))
2629 {
2630 updateTextureLevel(level);
2631 }
Jamie Madill07edd442013-07-19 16:36:58 -04002632 }
2633}
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002634
Jamie Madill07edd442013-07-19 16:36:58 -04002635void Texture2DArray::updateTextureLevel(int level)
2636{
Jamie Madillaee7ad82013-10-10 16:07:32 -04002637 ASSERT(level >= 0 && level < (int)ArraySize(mLayerCounts));
2638 ASSERT(isLevelComplete(level));
2639
Jamie Madill07edd442013-07-19 16:36:58 -04002640 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2641 {
Jamie Madillaee7ad82013-10-10 16:07:32 -04002642 ASSERT(mImageArray[level] != NULL && mImageArray[level][layer] != NULL);
2643 if (mImageArray[level][layer]->isDirty())
Jamie Madill07edd442013-07-19 16:36:58 -04002644 {
Jamie Madillaee7ad82013-10-10 16:07:32 -04002645 commitRect(level, 0, 0, layer, getWidth(level), getHeight(level));
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002646 }
2647 }
2648}
2649
Jamie Madille83d1a92013-10-24 17:49:33 -04002650bool Texture2DArray::ensureRenderTarget()
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002651{
Jamie Madille83d1a92013-10-24 17:49:33 -04002652 if (mTexStorage && mTexStorage->isRenderTarget())
2653 {
2654 return true;
2655 }
2656
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002657 rx::TextureStorageInterface2DArray *newTexStorage = NULL;
2658
Jamie Madilld3d2a342013-10-07 10:46:35 -04002659 GLsizei width = getBaseLevelWidth();
2660 GLsizei height = getBaseLevelHeight();
2661 GLsizei depth = getBaseLevelDepth();
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002662
2663 if (width != 0 && height != 0 && depth != 0)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002664 {
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002665 GLint levels = mTexStorage != NULL ? mTexStorage->levelCount() : creationLevels(width, height);
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002666 GLenum internalformat = getInternalFormat(0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002667
Jamie Madilld4589c92013-10-24 17:49:34 -04002668 newTexStorage = new rx::TextureStorageInterface2DArray(mRenderer, levels, internalformat, true, width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002669
2670 if (mTexStorage != NULL)
2671 {
2672 if (!mRenderer->copyToRenderTarget(newTexStorage, mTexStorage))
2673 {
2674 delete newTexStorage;
Jamie Madille83d1a92013-10-24 17:49:33 -04002675 return gl::error(GL_OUT_OF_MEMORY, false);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002676 }
2677 }
2678 }
2679
2680 delete mTexStorage;
2681 mTexStorage = newTexStorage;
2682
2683 mDirtyImages = true;
Jamie Madille83d1a92013-10-24 17:49:33 -04002684 return (mTexStorage && mTexStorage->isRenderTarget());
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002685}
2686
Geoff Lang8040f572013-07-25 16:49:54 -04002687rx::RenderTarget *Texture2DArray::getRenderTarget(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002688{
Geoff Lang8040f572013-07-25 16:49:54 -04002689 // ensure the underlying texture is created
2690 if (getStorage(true) == NULL)
2691 {
2692 return NULL;
2693 }
2694
Jamie Madillaee7ad82013-10-10 16:07:32 -04002695 updateTextureLevel(level);
Geoff Lang8040f572013-07-25 16:49:54 -04002696
2697 // ensure this is NOT a depth texture
2698 if (isDepth(level))
2699 {
2700 return NULL;
2701 }
2702
2703 return mTexStorage->getRenderTarget(level, layer);
2704}
2705
2706rx::RenderTarget *Texture2DArray::getDepthStencil(GLint level, GLint layer)
2707{
2708 // ensure the underlying texture is created
2709 if (getStorage(true) == NULL)
2710 {
2711 return NULL;
2712 }
2713
Jamie Madillaee7ad82013-10-10 16:07:32 -04002714 updateTextureLevel(level);
Geoff Lang8040f572013-07-25 16:49:54 -04002715
2716 // ensure this is a depth texture
2717 if (!isDepth(level))
2718 {
2719 return NULL;
2720 }
2721
2722 return mTexStorage->getRenderTarget(level, layer);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002723}
2724
2725rx::TextureStorageInterface *Texture2DArray::getStorage(bool renderTarget)
2726{
2727 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
2728 {
2729 if (renderTarget)
2730 {
Jamie Madille83d1a92013-10-24 17:49:33 -04002731 ensureRenderTarget();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002732 }
2733 else
2734 {
2735 createTexture();
2736 }
2737 }
2738
2739 return mTexStorage;
2740}
2741
Geoff Lang005df412013-10-16 14:12:50 -04002742void Texture2DArray::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002743{
2744 // If there currently is a corresponding storage texture image, it has these parameters
Jamie Madilld3d2a342013-10-07 10:46:35 -04002745 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2746 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
2747 const int storageDepth = getBaseLevelDepth();
Geoff Lang005df412013-10-16 14:12:50 -04002748 const GLenum storageFormat = getBaseLevelInternalFormat();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002749
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002750 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002751 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002752 delete mImageArray[level][layer];
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002753 }
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002754 delete[] mImageArray[level];
Jamie Madill152ed092013-10-09 17:01:15 -04002755 mImageArray[level] = NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002756 mLayerCounts[level] = depth;
2757
Jamie Madill152ed092013-10-09 17:01:15 -04002758 if (depth > 0)
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002759 {
Jamie Madill152ed092013-10-09 17:01:15 -04002760 mImageArray[level] = new rx::Image*[depth]();
2761
2762 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2763 {
2764 mImageArray[level][layer] = mRenderer->createImage();
2765 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, width, height, 1, false);
2766 }
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002767 }
2768
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002769 if (mTexStorage)
2770 {
2771 const int storageLevels = mTexStorage->levelCount();
2772
2773 if ((level >= storageLevels && storageLevels != 0) ||
2774 width != storageWidth ||
2775 height != storageHeight ||
2776 depth != storageDepth ||
2777 internalformat != storageFormat) // Discard mismatched storage
2778 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002779 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002780 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002781 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002782 {
2783 mImageArray[level][layer]->markDirty();
2784 }
2785 }
2786
2787 delete mTexStorage;
2788 mTexStorage = NULL;
2789 mDirtyImages = true;
2790 }
2791 }
2792}
2793
2794void Texture2DArray::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint layerTarget, GLsizei width, GLsizei height)
2795{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002796 if (level < levelCount() && layerTarget < getDepth(level))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002797 {
2798 rx::Image *image = mImageArray[level][layerTarget];
2799 if (image->updateSurface(mTexStorage, level, xoffset, yoffset, layerTarget, width, height))
2800 {
2801 image->markClean();
2802 }
2803 }
2804}
2805
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00002806}