blob: cc8fe8780001329af4fe27abfae8a917b78706c7 [file] [log] [blame]
shannon.woods@transgaming.combdf2d802013-02-28 23:16:20 +00001#include "precompiled.h"
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00002//
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00003// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00004// Use of this source code is governed by a BSD-style license that can be
5// found in the LICENSE file.
6//
7
8// Texture.cpp: Implements the gl::Texture class and its derived classes
9// Texture2D and TextureCubeMap. Implements GL texture objects and related
10// functionality. [OpenGL ES 2.0.24] section 3.7 page 63.
11
12#include "libGLESv2/Texture.h"
13
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000014#include "libGLESv2/main.h"
shannonwoods@chromium.orga2ecfcc2013-05-30 00:11:59 +000015#include "common/mathutil.h"
16#include "common/utilities.h"
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +000017#include "libGLESv2/formatutils.h"
Geoff Langdce735c2013-06-04 10:21:18 -040018#include "libGLESv2/renderer/Blit9.h"
shannon.woods@transgaming.com486d9e92013-02-28 23:15:41 +000019#include "libGLESv2/Renderbuffer.h"
20#include "libGLESv2/renderer/Image.h"
21#include "libGLESv2/renderer/Renderer.h"
22#include "libGLESv2/renderer/TextureStorage.h"
23#include "libEGL/Surface.h"
Jamie Madill1beb1db2013-09-18 14:36:28 -040024#include "libGLESv2/Buffer.h"
25#include "libGLESv2/renderer/BufferStorage.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
Geoff Lang4907f2c2013-07-25 12:53:57 -040047Texture::Texture(rx::Renderer *renderer, GLuint id, GLenum target) : RefCountObject(id)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000048{
daniel@transgaming.com370482e2012-11-28 19:32:13 +000049 mRenderer = renderer;
50
daniel@transgaming.comebf139f2012-10-31 18:07:32 +000051 mSamplerState.minFilter = GL_NEAREST_MIPMAP_LINEAR;
52 mSamplerState.magFilter = GL_LINEAR;
53 mSamplerState.wrapS = GL_REPEAT;
54 mSamplerState.wrapT = GL_REPEAT;
shannon.woods%transgaming.com@gtempaccount.com0b3a8df2013-04-13 03:44:51 +000055 mSamplerState.wrapR = GL_REPEAT;
daniel@transgaming.comebf139f2012-10-31 18:07:32 +000056 mSamplerState.maxAnisotropy = 1.0f;
57 mSamplerState.lodOffset = 0;
Geoff Langc82fc412013-07-10 14:43:42 -040058 mSamplerState.compareMode = GL_NONE;
59 mSamplerState.compareFunc = GL_LEQUAL;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000060 mUsage = GL_NONE;
Geoff Langc82fc412013-07-10 14:43:42 -040061
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000062 mDirtyImages = true;
63
64 mImmutable = false;
Geoff Lang4907f2c2013-07-25 12:53:57 -040065
66 mTarget = target;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000067}
68
69Texture::~Texture()
70{
71}
72
Geoff Lang4907f2c2013-07-25 12:53:57 -040073GLenum Texture::getTarget() const
74{
75 return mTarget;
76}
77
Geoff Lang8040f572013-07-25 16:49:54 -040078void Texture::addProxyRef(const Renderbuffer *proxy)
79{
80 mRenderbufferProxies.addRef(proxy);
81}
82
83void Texture::releaseProxy(const Renderbuffer *proxy)
84{
85 mRenderbufferProxies.release(proxy);
86}
87
Geoff Lang63b5f1f2013-09-23 14:52:14 -040088void Texture::setMinFilter(GLenum filter)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000089{
Geoff Lang63b5f1f2013-09-23 14:52:14 -040090 mSamplerState.minFilter = filter;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000091}
92
Geoff Lang63b5f1f2013-09-23 14:52:14 -040093void Texture::setMagFilter(GLenum filter)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000094{
Geoff Lang63b5f1f2013-09-23 14:52:14 -040095 mSamplerState.magFilter = filter;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000096}
97
Geoff Lang63b5f1f2013-09-23 14:52:14 -040098void Texture::setWrapS(GLenum wrap)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000099{
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400100 mSamplerState.wrapS = wrap;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000101}
102
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400103void Texture::setWrapT(GLenum wrap)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000104{
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400105 mSamplerState.wrapT = wrap;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000106}
107
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400108void Texture::setWrapR(GLenum wrap)
shannon.woods%transgaming.com@gtempaccount.com0b3a8df2013-04-13 03:44:51 +0000109{
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400110 mSamplerState.wrapR = wrap;
shannon.woods%transgaming.com@gtempaccount.com0b3a8df2013-04-13 03:44:51 +0000111}
112
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400113void Texture::setMaxAnisotropy(float textureMaxAnisotropy, float contextMaxAnisotropy)
daniel@transgaming.com07ab8412012-07-12 15:17:09 +0000114{
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400115 mSamplerState.maxAnisotropy = std::min(textureMaxAnisotropy, contextMaxAnisotropy);
daniel@transgaming.com07ab8412012-07-12 15:17:09 +0000116}
117
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400118void Texture::setCompareMode(GLenum mode)
Geoff Langc82fc412013-07-10 14:43:42 -0400119{
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400120 mSamplerState.compareMode = mode;
Geoff Langc82fc412013-07-10 14:43:42 -0400121}
122
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400123void Texture::setCompareFunc(GLenum func)
Geoff Langc82fc412013-07-10 14:43:42 -0400124{
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400125 mSamplerState.compareFunc = func;
Geoff Langc82fc412013-07-10 14:43:42 -0400126}
127
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400128void Texture::setUsage(GLenum usage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000129{
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400130 mUsage = usage;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000131}
132
133GLenum Texture::getMinFilter() const
134{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000135 return mSamplerState.minFilter;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000136}
137
138GLenum Texture::getMagFilter() const
139{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000140 return mSamplerState.magFilter;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000141}
142
143GLenum Texture::getWrapS() const
144{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000145 return mSamplerState.wrapS;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000146}
147
148GLenum Texture::getWrapT() const
149{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000150 return mSamplerState.wrapT;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000151}
152
shannon.woods%transgaming.com@gtempaccount.com0b3a8df2013-04-13 03:44:51 +0000153GLenum Texture::getWrapR() const
154{
155 return mSamplerState.wrapR;
156}
157
daniel@transgaming.com07ab8412012-07-12 15:17:09 +0000158float Texture::getMaxAnisotropy() const
159{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000160 return mSamplerState.maxAnisotropy;
161}
162
163int Texture::getLodOffset()
164{
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000165 rx::TextureStorageInterface *texture = getStorage(false);
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000166 return texture ? texture->getLodOffset() : 0;
167}
168
169void Texture::getSamplerState(SamplerState *sampler)
170{
171 *sampler = mSamplerState;
172 sampler->lodOffset = getLodOffset();
daniel@transgaming.com07ab8412012-07-12 15:17:09 +0000173}
174
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000175GLenum Texture::getUsage() const
176{
177 return mUsage;
178}
179
Jamie Madilld3d2a342013-10-07 10:46:35 -0400180GLint Texture::getBaseLevelWidth() const
181{
182 const rx::Image *baseImage = getBaseLevelImage();
183 return (baseImage ? baseImage->getWidth() : 0);
184}
185
186GLint Texture::getBaseLevelHeight() const
187{
188 const rx::Image *baseImage = getBaseLevelImage();
189 return (baseImage ? baseImage->getHeight() : 0);
190}
191
192GLint Texture::getBaseLevelDepth() const
193{
194 const rx::Image *baseImage = getBaseLevelImage();
195 return (baseImage ? baseImage->getDepth() : 0);
196}
197
198GLenum Texture::getBaseLevelInternalFormat() const
199{
200 const rx::Image *baseImage = getBaseLevelImage();
201 return (baseImage ? baseImage->getInternalFormat() : GL_NONE);
202}
203
Jamie Madill88f18f42013-09-18 14:36:19 -0400204void Texture::setImage(const PixelUnpackState &unpack, GLenum type, const void *pixels, rx::Image *image)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000205{
Jamie Madillabef6802013-09-05 16:54:19 -0400206 // We no longer need the "GLenum format" parameter to TexImage to determine what data format "pixels" contains.
207 // 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 -0400208 const void *pixelData = pixels;
209
210 if (unpack.pixelBuffer.id() != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000211 {
Jamie Madill1beb1db2013-09-18 14:36:28 -0400212 // Do a CPU readback here, if we have an unpack buffer bound and the fast GPU path is not supported
213 Buffer *pixelBuffer = unpack.pixelBuffer.get();
214 ptrdiff_t offset = reinterpret_cast<ptrdiff_t>(pixels);
215 const void *bufferData = pixelBuffer->getStorage()->getData();
216 pixelData = static_cast<const unsigned char *>(bufferData) + offset;
217 }
218
219 if (pixelData != NULL)
220 {
221 image->loadData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), unpack.alignment, type, pixelData);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000222 mDirtyImages = true;
223 }
224}
225
Jamie Madill1beb1db2013-09-18 14:36:28 -0400226bool Texture::fastUnpackPixels(const PixelUnpackState &unpack, const void *pixels, const Box &destArea,
227 GLenum sizedInternalFormat, GLenum type, GLint level)
228{
229 if (destArea.width <= 0 && destArea.height <= 0 && destArea.depth <= 0)
230 {
231 return true;
232 }
233
234 // In order to perform the fast copy through the shader, we must have the right format, and be able
235 // to create a render target.
236 if (IsFastCopyBufferToTextureSupported(sizedInternalFormat, mRenderer->getCurrentClientVersion()))
237 {
238 unsigned int offset = reinterpret_cast<unsigned int>(pixels);
239 rx::RenderTarget *destRenderTarget = getStorage(true)->getStorageInstance()->getRenderTarget(level);
240
241 return mRenderer->fastCopyBufferToTexture(unpack, offset, destRenderTarget, sizedInternalFormat, type, destArea);
242 }
243
244 // Return false if we do not support fast unpack
245 return false;
246}
247
daniel@transgaming.com31b13e12012-11-28 19:34:30 +0000248void Texture::setCompressedImage(GLsizei imageSize, const void *pixels, rx::Image *image)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000249{
250 if (pixels != NULL)
251 {
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000252 image->loadCompressedData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000253 mDirtyImages = true;
254 }
255}
256
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000257bool Texture::subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
Jamie Madill88f18f42013-09-18 14:36:19 -0400258 GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels, rx::Image *image)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000259{
260 if (pixels != NULL)
261 {
Jamie Madill88f18f42013-09-18 14:36:19 -0400262 image->loadData(xoffset, yoffset, zoffset, width, height, depth, unpack.alignment, type, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000263 mDirtyImages = true;
264 }
265
266 return true;
267}
268
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000269bool Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
270 GLenum format, GLsizei imageSize, const void *pixels, rx::Image *image)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000271{
272 if (pixels != NULL)
273 {
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000274 image->loadCompressedData(xoffset, yoffset, zoffset, width, height, depth, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000275 mDirtyImages = true;
276 }
277
278 return true;
279}
280
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000281rx::TextureStorageInterface *Texture::getNativeTexture()
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000282{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000283 // ensure the underlying texture is created
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000284
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000285 rx::TextureStorageInterface *storage = getStorage(false);
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000286 if (storage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000287 {
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000288 updateTexture();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000289 }
290
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000291 return storage;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000292}
293
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000294bool Texture::hasDirtyImages() const
295{
296 return mDirtyImages;
297}
298
299void Texture::resetDirty()
300{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000301 mDirtyImages = false;
302}
303
304unsigned int Texture::getTextureSerial()
305{
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000306 rx::TextureStorageInterface *texture = getStorage(false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000307 return texture ? texture->getTextureSerial() : 0;
308}
309
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000310bool Texture::isImmutable() const
311{
312 return mImmutable;
313}
314
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +0000315GLint Texture::creationLevels(GLsizei width, GLsizei height, GLsizei depth) const
316{
317 // NPOT checks are not required in ES 3.0, NPOT texture support is assumed.
318 return 0; // Maximum number of levels
319}
320
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000321GLint Texture::creationLevels(GLsizei width, GLsizei height) const
322{
daniel@transgaming.comea32d482012-11-28 19:33:18 +0000323 if ((isPow2(width) && isPow2(height)) || mRenderer->getNonPower2TextureSupport())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000324 {
325 return 0; // Maximum number of levels
326 }
327 else
328 {
329 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
330 return 1;
331 }
332}
333
334GLint Texture::creationLevels(GLsizei size) const
335{
336 return creationLevels(size, size);
337}
338
Geoff Lang4907f2c2013-07-25 12:53:57 -0400339Texture2D::Texture2D(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_2D)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000340{
341 mTexStorage = NULL;
342 mSurface = NULL;
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000343
344 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
345 {
daniel@transgaming.com244e1832012-12-20 20:52:35 +0000346 mImageArray[i] = renderer->createImage();
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000347 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000348}
349
350Texture2D::~Texture2D()
351{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000352 delete mTexStorage;
353 mTexStorage = NULL;
354
355 if (mSurface)
356 {
357 mSurface->setBoundTexture(NULL);
358 mSurface = NULL;
359 }
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000360
361 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
362 {
363 delete mImageArray[i];
364 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000365}
366
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000367GLsizei Texture2D::getWidth(GLint level) const
368{
369 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000370 return mImageArray[level]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000371 else
372 return 0;
373}
374
375GLsizei Texture2D::getHeight(GLint level) const
376{
377 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000378 return mImageArray[level]->getHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000379 else
380 return 0;
381}
382
383GLenum Texture2D::getInternalFormat(GLint level) const
384{
385 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000386 return mImageArray[level]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000387 else
388 return GL_NONE;
389}
390
daniel@transgaming.com20d36662012-10-31 19:51:43 +0000391GLenum Texture2D::getActualFormat(GLint level) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000392{
393 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000394 return mImageArray[level]->getActualFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000395 else
396 return D3DFMT_UNKNOWN;
397}
398
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000399void Texture2D::redefineImage(GLint level, GLint internalformat, GLsizei width, GLsizei height)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000400{
401 releaseTexImage();
shannon.woods@transgaming.com8a406682013-02-28 23:15:26 +0000402
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000403 // If there currently is a corresponding storage texture image, it has these parameters
Jamie Madilld3d2a342013-10-07 10:46:35 -0400404 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
405 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
406 const int storageFormat = getBaseLevelInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000407
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000408 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, width, height, 1, false);
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000409
410 if (mTexStorage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000411 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000412 const int storageLevels = mTexStorage->levelCount();
413
414 if ((level >= storageLevels && storageLevels != 0) ||
415 width != storageWidth ||
416 height != storageHeight ||
417 internalformat != storageFormat) // Discard mismatched storage
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000418 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000419 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
420 {
421 mImageArray[i]->markDirty();
422 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000423
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000424 delete mTexStorage;
425 mTexStorage = NULL;
426 mDirtyImages = true;
427 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000428 }
429}
430
Jamie Madill88f18f42013-09-18 14:36:19 -0400431void Texture2D::setImage(GLint level, GLsizei width, GLsizei height, GLint internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000432{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +0000433 GLuint clientVersion = mRenderer->getCurrentClientVersion();
434 GLint sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
435 : GetSizedInternalFormat(format, type, clientVersion);
436 redefineImage(level, sizedInternalFormat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000437
Jamie Madill1beb1db2013-09-18 14:36:28 -0400438 // Attempt a fast gpu copy of the pixel data to the surface
439 // If we want to support rendering (which is necessary for GPU unpack buffers), level 0 must be complete
440 Box destArea(0, 0, 0, getWidth(level), getHeight(level), 1);
441 if (unpack.pixelBuffer.id() != 0 && isLevelComplete(0) && fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, level))
442 {
443 // Ensure we don't overwrite our newly initialized data
444 mImageArray[level]->markClean();
445 }
446 else
447 {
448 Texture::setImage(unpack, type, pixels, mImageArray[level]);
449 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000450}
451
452void Texture2D::bindTexImage(egl::Surface *surface)
453{
454 releaseTexImage();
455
daniel@transgaming.com106e1f72012-10-31 18:38:36 +0000456 GLint internalformat = surface->getFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000457
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000458 mImageArray[0]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, surface->getWidth(), surface->getHeight(), 1, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000459
460 delete mTexStorage;
daniel@transgaming.comd8353dd2012-12-20 21:11:14 +0000461 mTexStorage = new rx::TextureStorageInterface2D(mRenderer, surface->getSwapChain());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000462
463 mDirtyImages = true;
464 mSurface = surface;
465 mSurface->setBoundTexture(this);
466}
467
468void Texture2D::releaseTexImage()
469{
470 if (mSurface)
471 {
472 mSurface->setBoundTexture(NULL);
473 mSurface = NULL;
474
475 if (mTexStorage)
476 {
477 delete mTexStorage;
478 mTexStorage = NULL;
479 }
480
481 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
482 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000483 mImageArray[i]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000484 }
485 }
486}
487
488void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
489{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000490 // 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 +0000491 redefineImage(level, format, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000492
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000493 Texture::setCompressedImage(imageSize, pixels, mImageArray[level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000494}
495
496void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
497{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000498 if (level < levelCount())
499 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000500 rx::Image *image = mImageArray[level];
daniel@transgaming.com0f195ad2012-10-31 19:51:59 +0000501 if (image->updateSurface(mTexStorage, level, xoffset, yoffset, width, height))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000502 {
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000503 image->markClean();
504 }
505 }
506}
507
Jamie Madill88f18f42013-09-18 14:36:19 -0400508void 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 +0000509{
Jamie Madill88f18f42013-09-18 14:36:19 -0400510 if (Texture::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, mImageArray[level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000511 {
512 commitRect(level, xoffset, yoffset, width, height);
513 }
514}
515
516void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
517{
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000518 if (Texture::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000519 {
520 commitRect(level, xoffset, yoffset, width, height);
521 }
522}
523
524void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
525{
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +0000526 GLuint clientVersion = mRenderer->getCurrentClientVersion();
527 GLint sizedInternalFormat = IsSizedInternalFormat(format, clientVersion) ? format
528 : GetSizedInternalFormat(format, GL_UNSIGNED_BYTE, clientVersion);
529 redefineImage(level, sizedInternalFormat, width, height);
shannon.woods@transgaming.com8a406682013-02-28 23:15:26 +0000530
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000531 if (!mImageArray[level]->isRenderableFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000532 {
shannon.woods%transgaming.com@gtempaccount.come5dcce72013-04-13 03:44:33 +0000533 mImageArray[level]->copy(0, 0, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000534 mDirtyImages = true;
535 }
536 else
537 {
538 if (!mTexStorage || !mTexStorage->isRenderTarget())
539 {
540 convertToRenderTarget();
541 }
542
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000543 mImageArray[level]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000544
545 if (width != 0 && height != 0 && level < levelCount())
546 {
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +0000547 gl::Rectangle sourceRect;
548 sourceRect.x = x;
549 sourceRect.width = width;
550 sourceRect.y = y;
551 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000552
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +0000553 mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000554 }
555 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000556}
557
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +0000558void 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 +0000559{
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +0000560 if (xoffset + width > mImageArray[level]->getWidth() || yoffset + height > mImageArray[level]->getHeight() || zoffset != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000561 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +0000562 return gl::error(GL_INVALID_VALUE);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000563 }
564
Jamie Madill07edd442013-07-19 16:36:58 -0400565 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
566 // the current level we're copying to is defined (with appropriate format, width & height)
567 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
568
569 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000570 {
shannon.woods%transgaming.com@gtempaccount.come5dcce72013-04-13 03:44:33 +0000571 mImageArray[level]->copy(xoffset, yoffset, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000572 mDirtyImages = true;
573 }
574 else
575 {
576 if (!mTexStorage || !mTexStorage->isRenderTarget())
577 {
578 convertToRenderTarget();
579 }
580
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000581 if (level < levelCount())
582 {
Jamie Madill07edd442013-07-19 16:36:58 -0400583 updateTextureLevel(level);
584
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +0000585 GLuint clientVersion = mRenderer->getCurrentClientVersion();
586
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +0000587 gl::Rectangle sourceRect;
588 sourceRect.x = x;
589 sourceRect.width = width;
590 sourceRect.y = y;
591 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000592
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +0000593 mRenderer->copyImage(source, sourceRect,
Jamie Madilld3d2a342013-10-07 10:46:35 -0400594 gl::GetFormat(getBaseLevelInternalFormat(), clientVersion),
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +0000595 xoffset, yoffset, mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000596 }
597 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000598}
599
600void Texture2D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height)
601{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000602 delete mTexStorage;
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000603 mTexStorage = new rx::TextureStorageInterface2D(mRenderer, levels, internalformat, mUsage, false, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000604 mImmutable = true;
605
606 for (int level = 0; level < levels; level++)
607 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000608 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, width, height, 1, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000609 width = std::max(1, width >> 1);
610 height = std::max(1, height >> 1);
611 }
612
613 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
614 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000615 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000616 }
617
618 if (mTexStorage->isManaged())
619 {
620 int levels = levelCount();
621
622 for (int level = 0; level < levels; level++)
623 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000624 mImageArray[level]->setManagedSurface(mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000625 }
626 }
627}
628
629// Tests for 2D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85.
Jamie Madillf8989902013-07-19 16:36:58 -0400630bool Texture2D::isSamplerComplete(const SamplerState &samplerState) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000631{
Jamie Madilld3d2a342013-10-07 10:46:35 -0400632 GLsizei width = getBaseLevelWidth();
633 GLsizei height = getBaseLevelHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000634
635 if (width <= 0 || height <= 0)
636 {
637 return false;
638 }
639
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000640 if (!IsTextureFilteringSupported(getInternalFormat(0), mRenderer))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000641 {
Jamie Madillf8989902013-07-19 16:36:58 -0400642 if (samplerState.magFilter != GL_NEAREST ||
643 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000644 {
645 return false;
646 }
647 }
648
daniel@transgaming.comea32d482012-11-28 19:33:18 +0000649 bool npotSupport = mRenderer->getNonPower2TextureSupport();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000650
651 if (!npotSupport)
652 {
Jamie Madillf8989902013-07-19 16:36:58 -0400653 if ((samplerState.wrapS != GL_CLAMP_TO_EDGE && !isPow2(width)) ||
654 (samplerState.wrapT != GL_CLAMP_TO_EDGE && !isPow2(height)))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000655 {
656 return false;
657 }
658 }
659
Jamie Madillf8989902013-07-19 16:36:58 -0400660 if (IsMipmapFiltered(samplerState))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000661 {
662 if (!npotSupport)
663 {
664 if (!isPow2(width) || !isPow2(height))
665 {
666 return false;
667 }
668 }
669
670 if (!isMipmapComplete())
671 {
672 return false;
673 }
674 }
675
Geoff Langc82fc412013-07-10 14:43:42 -0400676 // OpenGLES 3.0.2 spec section 3.8.13 states that a texture is not mipmap complete if:
677 // The internalformat specified for the texture arrays is a sized internal depth or
678 // depth and stencil format (see table 3.13), the value of TEXTURE_COMPARE_-
679 // MODE is NONE, and either the magnification filter is not NEAREST or the mini-
680 // fication filter is neither NEAREST nor NEAREST_MIPMAP_NEAREST.
681 if (gl::GetDepthBits(getInternalFormat(0), mRenderer->getCurrentClientVersion()) > 0)
682 {
683 if (mSamplerState.compareMode == GL_NONE)
684 {
685 if ((mSamplerState.minFilter != GL_NEAREST && mSamplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST) ||
686 mSamplerState.magFilter != GL_NEAREST)
687 {
688 return false;
689 }
690 }
691 }
692
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000693 return true;
694}
695
696// Tests for 2D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
697bool Texture2D::isMipmapComplete() const
698{
Jamie Madilld3d2a342013-10-07 10:46:35 -0400699 GLsizei width = getBaseLevelWidth();
700 GLsizei height = getBaseLevelHeight();
Jamie Madill07edd442013-07-19 16:36:58 -0400701
702 int q = log2(std::max(width, height));
703
704 for (int level = 0; level <= q; level++)
705 {
706 if (!isLevelComplete(level))
707 {
708 return false;
709 }
710 }
711
712 return true;
713}
714
715bool Texture2D::isLevelComplete(int level) const
716{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000717 if (isImmutable())
718 {
719 return true;
720 }
721
Jamie Madilld3d2a342013-10-07 10:46:35 -0400722 GLsizei width = getBaseLevelWidth();
723 GLsizei height = getBaseLevelHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000724
725 if (width <= 0 || height <= 0)
726 {
727 return false;
728 }
729
Jamie Madill07edd442013-07-19 16:36:58 -0400730 // The base image level is complete if the width and height are positive
731 if (level == 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000732 {
Jamie Madill07edd442013-07-19 16:36:58 -0400733 return true;
734 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000735
Jamie Madill07edd442013-07-19 16:36:58 -0400736 ASSERT(level >= 1 && level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
737 rx::Image *image = mImageArray[level];
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000738
Jamie Madilld3d2a342013-10-07 10:46:35 -0400739 if (image->getInternalFormat() != getBaseLevelInternalFormat())
Jamie Madill07edd442013-07-19 16:36:58 -0400740 {
741 return false;
742 }
743
744 if (image->getWidth() != std::max(1, width >> level))
745 {
746 return false;
747 }
748
749 if (image->getHeight() != std::max(1, height >> level))
750 {
751 return false;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000752 }
753
754 return true;
755}
756
757bool Texture2D::isCompressed(GLint level) const
758{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000759 return IsFormatCompressed(getInternalFormat(level), mRenderer->getCurrentClientVersion());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000760}
761
762bool Texture2D::isDepth(GLint level) const
763{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000764 return GetDepthBits(getInternalFormat(level), mRenderer->getCurrentClientVersion()) > 0;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000765}
766
daniel@transgaming.comf032cb82012-10-31 19:51:52 +0000767// Constructs a native texture resource from the texture images
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000768void Texture2D::createTexture()
769{
Jamie Madilld3d2a342013-10-07 10:46:35 -0400770 GLsizei width = getBaseLevelWidth();
771 GLsizei height = getBaseLevelHeight();
daniel@transgaming.come6a09842012-09-17 21:28:55 +0000772
773 if (!(width > 0 && height > 0))
daniel@transgaming.comf032cb82012-10-31 19:51:52 +0000774 return; // do not attempt to create native textures for nonexistant data
daniel@transgaming.come6a09842012-09-17 21:28:55 +0000775
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000776 GLint levels = creationLevels(width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000777
778 delete mTexStorage;
Jamie Madilld3d2a342013-10-07 10:46:35 -0400779 mTexStorage = new rx::TextureStorageInterface2D(mRenderer, levels, getBaseLevelInternalFormat(), mUsage, false, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000780
781 if (mTexStorage->isManaged())
782 {
783 int levels = levelCount();
784
785 for (int level = 0; level < levels; level++)
786 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000787 mImageArray[level]->setManagedSurface(mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000788 }
789 }
790
791 mDirtyImages = true;
792}
793
794void Texture2D::updateTexture()
795{
Jamie Madilleb3665c2013-07-19 16:36:57 -0400796 int levels = (isMipmapComplete() ? levelCount() : 1);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000797
798 for (int level = 0; level < levels; level++)
799 {
Jamie Madill07edd442013-07-19 16:36:58 -0400800 updateTextureLevel(level);
801 }
802}
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000803
Jamie Madill07edd442013-07-19 16:36:58 -0400804void Texture2D::updateTextureLevel(int level)
805{
806 ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
807 rx::Image *image = mImageArray[level];
808
809 if (image->isDirty())
810 {
811 commitRect(level, 0, 0, mImageArray[level]->getWidth(), mImageArray[level]->getHeight());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000812 }
813}
814
815void Texture2D::convertToRenderTarget()
816{
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000817 rx::TextureStorageInterface2D *newTexStorage = NULL;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000818
Jamie Madilld3d2a342013-10-07 10:46:35 -0400819 GLsizei width = getBaseLevelWidth();
820 GLsizei height = getBaseLevelHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000821
Jamie Madilld3d2a342013-10-07 10:46:35 -0400822 if (width != 0 && height != 0)
823 {
824 GLint levels = mTexStorage != NULL ? mTexStorage->levelCount() : creationLevels(width, height);
825
826 newTexStorage = new rx::TextureStorageInterface2D(mRenderer, levels, getBaseLevelInternalFormat(), GL_FRAMEBUFFER_ATTACHMENT_ANGLE, true, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000827
828 if (mTexStorage != NULL)
829 {
daniel@transgaming.com1d80eee2012-11-28 19:33:31 +0000830 if (!mRenderer->copyToRenderTarget(newTexStorage, mTexStorage))
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +0000831 {
832 delete newTexStorage;
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +0000833 return gl::error(GL_OUT_OF_MEMORY);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000834 }
835 }
836 }
837
838 delete mTexStorage;
839 mTexStorage = newTexStorage;
840
841 mDirtyImages = true;
842}
843
844void Texture2D::generateMipmaps()
845{
daniel@transgaming.comea32d482012-11-28 19:33:18 +0000846 if (!mRenderer->getNonPower2TextureSupport())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000847 {
Jamie Madilld3d2a342013-10-07 10:46:35 -0400848 if (!isPow2(getBaseLevelWidth()) || !isPow2(getBaseLevelHeight()))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000849 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +0000850 return gl::error(GL_INVALID_OPERATION);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000851 }
852 }
853
854 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Jamie Madilld3d2a342013-10-07 10:46:35 -0400855 unsigned int q = log2(std::max(getBaseLevelWidth(), getBaseLevelHeight()));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000856 for (unsigned int i = 1; i <= q; i++)
857 {
Jamie Madilld3d2a342013-10-07 10:46:35 -0400858 redefineImage(i, getBaseLevelInternalFormat(),
859 std::max(getBaseLevelWidth() >> i, 1),
860 std::max(getBaseLevelHeight() >> i, 1));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000861 }
862
863 if (mTexStorage && mTexStorage->isRenderTarget())
864 {
865 for (unsigned int i = 1; i <= q; i++)
866 {
daniel@transgaming.com0ad830b2012-10-31 19:52:12 +0000867 mTexStorage->generateMipmap(i);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000868
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000869 mImageArray[i]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000870 }
871 }
872 else
873 {
874 for (unsigned int i = 1; i <= q; i++)
875 {
daniel@transgaming.com4ba24062012-12-20 20:54:24 +0000876 mRenderer->generateMipmap(mImageArray[i], mImageArray[i - 1]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000877 }
878 }
879}
880
Jamie Madilld3d2a342013-10-07 10:46:35 -0400881const rx::Image *Texture2D::getBaseLevelImage() const
882{
883 return mImageArray[0];
884}
885
Geoff Lang8040f572013-07-25 16:49:54 -0400886Renderbuffer *Texture2D::getRenderbuffer(GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000887{
Geoff Lang8040f572013-07-25 16:49:54 -0400888 Renderbuffer *renderBuffer = mRenderbufferProxies.get(level, 0);
889 if (!renderBuffer)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000890 {
Geoff Lang8040f572013-07-25 16:49:54 -0400891 renderBuffer = new Renderbuffer(mRenderer, id(), new RenderbufferTexture2D(this, level));
892 mRenderbufferProxies.add(level, 0, renderBuffer);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000893 }
894
Geoff Lang8040f572013-07-25 16:49:54 -0400895 return renderBuffer;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000896}
897
Geoff Lang8040f572013-07-25 16:49:54 -0400898unsigned int Texture2D::getRenderTargetSerial(GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000899{
Geoff Lang8040f572013-07-25 16:49:54 -0400900 if (!mTexStorage || !mTexStorage->isRenderTarget())
901 {
902 convertToRenderTarget();
903 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000904
Geoff Lang8040f572013-07-25 16:49:54 -0400905 return mTexStorage ? mTexStorage->getRenderTargetSerial(level) : 0;
906}
907
908rx::RenderTarget *Texture2D::getRenderTarget(GLint level)
909{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000910 // ensure the underlying texture is created
911 if (getStorage(true) == NULL)
912 {
913 return NULL;
914 }
915
916 updateTexture();
Geoff Lang8040f572013-07-25 16:49:54 -0400917
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000918 // ensure this is NOT a depth texture
Geoff Lang8040f572013-07-25 16:49:54 -0400919 if (isDepth(level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000920 {
921 return NULL;
922 }
daniel@transgaming.com34da3972012-12-20 21:10:29 +0000923
Geoff Lang8040f572013-07-25 16:49:54 -0400924 return mTexStorage->getRenderTarget(level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000925}
926
Geoff Lang8040f572013-07-25 16:49:54 -0400927rx::RenderTarget *Texture2D::getDepthSencil(GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000928{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000929 // ensure the underlying texture is created
930 if (getStorage(true) == NULL)
931 {
932 return NULL;
933 }
934
935 updateTexture();
936
937 // ensure this is actually a depth texture
Geoff Lang8040f572013-07-25 16:49:54 -0400938 if (!isDepth(level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000939 {
940 return NULL;
941 }
Geoff Lang8040f572013-07-25 16:49:54 -0400942
943 return mTexStorage->getRenderTarget(level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000944}
945
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +0000946int Texture2D::levelCount()
947{
shannon.woods@transgaming.com5016f8e2013-02-28 23:20:57 +0000948 return mTexStorage ? mTexStorage->levelCount() : 0;
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +0000949}
950
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000951rx::TextureStorageInterface *Texture2D::getStorage(bool renderTarget)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000952{
953 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
954 {
955 if (renderTarget)
956 {
957 convertToRenderTarget();
958 }
959 else
960 {
961 createTexture();
962 }
963 }
964
965 return mTexStorage;
966}
967
Geoff Lang4907f2c2013-07-25 12:53:57 -0400968TextureCubeMap::TextureCubeMap(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_CUBE_MAP)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000969{
970 mTexStorage = NULL;
971 for (int i = 0; i < 6; i++)
972 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000973 for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
974 {
daniel@transgaming.com244e1832012-12-20 20:52:35 +0000975 mImageArray[i][j] = renderer->createImage();
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000976 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000977 }
978}
979
980TextureCubeMap::~TextureCubeMap()
981{
982 for (int i = 0; i < 6; i++)
983 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000984 for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
985 {
986 delete mImageArray[i][j];
987 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000988 }
989
990 delete mTexStorage;
991 mTexStorage = NULL;
992}
993
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000994GLsizei TextureCubeMap::getWidth(GLenum target, GLint level) const
995{
996 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000997 return mImageArray[faceIndex(target)][level]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000998 else
999 return 0;
1000}
1001
1002GLsizei TextureCubeMap::getHeight(GLenum target, GLint level) const
1003{
1004 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001005 return mImageArray[faceIndex(target)][level]->getHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001006 else
1007 return 0;
1008}
1009
1010GLenum TextureCubeMap::getInternalFormat(GLenum target, GLint level) const
1011{
1012 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001013 return mImageArray[faceIndex(target)][level]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001014 else
1015 return GL_NONE;
1016}
1017
daniel@transgaming.com20d36662012-10-31 19:51:43 +00001018GLenum TextureCubeMap::getActualFormat(GLenum target, GLint level) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001019{
1020 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001021 return mImageArray[faceIndex(target)][level]->getActualFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001022 else
1023 return D3DFMT_UNKNOWN;
1024}
1025
Jamie Madill88f18f42013-09-18 14:36:19 -04001026void TextureCubeMap::setImagePosX(GLint level, GLsizei width, GLsizei height, GLint internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001027{
Jamie Madill88f18f42013-09-18 14:36:19 -04001028 setImage(0, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001029}
1030
Jamie Madill88f18f42013-09-18 14:36:19 -04001031void TextureCubeMap::setImageNegX(GLint level, GLsizei width, GLsizei height, GLint internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001032{
Jamie Madill88f18f42013-09-18 14:36:19 -04001033 setImage(1, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001034}
1035
Jamie Madill88f18f42013-09-18 14:36:19 -04001036void TextureCubeMap::setImagePosY(GLint level, GLsizei width, GLsizei height, GLint internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001037{
Jamie Madill88f18f42013-09-18 14:36:19 -04001038 setImage(2, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001039}
1040
Jamie Madill88f18f42013-09-18 14:36:19 -04001041void TextureCubeMap::setImageNegY(GLint level, GLsizei width, GLsizei height, GLint internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001042{
Jamie Madill88f18f42013-09-18 14:36:19 -04001043 setImage(3, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001044}
1045
Jamie Madill88f18f42013-09-18 14:36:19 -04001046void TextureCubeMap::setImagePosZ(GLint level, GLsizei width, GLsizei height, GLint internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001047{
Jamie Madill88f18f42013-09-18 14:36:19 -04001048 setImage(4, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001049}
1050
Jamie Madill88f18f42013-09-18 14:36:19 -04001051void TextureCubeMap::setImageNegZ(GLint level, GLsizei width, GLsizei height, GLint internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001052{
Jamie Madill88f18f42013-09-18 14:36:19 -04001053 setImage(5, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001054}
1055
1056void TextureCubeMap::setCompressedImage(GLenum face, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
1057{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001058 // 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 +00001059 redefineImage(faceIndex(face), level, format, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001060
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001061 Texture::setCompressedImage(imageSize, pixels, mImageArray[faceIndex(face)][level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001062}
1063
1064void TextureCubeMap::commitRect(int face, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1065{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001066 if (level < levelCount())
1067 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001068 rx::Image *image = mImageArray[face][level];
daniel@transgaming.com0f195ad2012-10-31 19:51:59 +00001069 if (image->updateSurface(mTexStorage, face, level, xoffset, yoffset, width, height))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001070 image->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001071 }
1072}
1073
Jamie Madill88f18f42013-09-18 14:36:19 -04001074void 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 +00001075{
Jamie Madill88f18f42013-09-18 14:36:19 -04001076 if (Texture::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, mImageArray[faceIndex(target)][level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001077 {
1078 commitRect(faceIndex(target), level, xoffset, yoffset, width, height);
1079 }
1080}
1081
1082void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1083{
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +00001084 if (Texture::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[faceIndex(target)][level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001085 {
1086 commitRect(faceIndex(target), level, xoffset, yoffset, width, height);
1087 }
1088}
1089
1090// Tests for cube map sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 86.
Jamie Madillf8989902013-07-19 16:36:58 -04001091bool TextureCubeMap::isSamplerComplete(const SamplerState &samplerState) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001092{
Jamie Madilld3d2a342013-10-07 10:46:35 -04001093 int size = getBaseLevelWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001094
Jamie Madillf8989902013-07-19 16:36:58 -04001095 bool mipmapping = IsMipmapFiltered(samplerState);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001096
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001097 if (!IsTextureFilteringSupported(getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0), mRenderer))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001098 {
Jamie Madillf8989902013-07-19 16:36:58 -04001099 if (samplerState.magFilter != GL_NEAREST ||
1100 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001101 {
1102 return false;
1103 }
1104 }
1105
daniel@transgaming.comea32d482012-11-28 19:33:18 +00001106 if (!isPow2(size) && !mRenderer->getNonPower2TextureSupport())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001107 {
Jamie Madillf8989902013-07-19 16:36:58 -04001108 if (samplerState.wrapS != GL_CLAMP_TO_EDGE || samplerState.wrapT != GL_CLAMP_TO_EDGE || mipmapping)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001109 {
1110 return false;
1111 }
1112 }
1113
1114 if (!mipmapping)
1115 {
1116 if (!isCubeComplete())
1117 {
1118 return false;
1119 }
1120 }
1121 else
1122 {
1123 if (!isMipmapCubeComplete()) // Also tests for isCubeComplete()
1124 {
1125 return false;
1126 }
1127 }
1128
1129 return true;
1130}
1131
1132// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1133bool TextureCubeMap::isCubeComplete() const
1134{
Jamie Madilld3d2a342013-10-07 10:46:35 -04001135 if (getBaseLevelWidth() <= 0 || getBaseLevelHeight() != getBaseLevelWidth())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001136 {
1137 return false;
1138 }
1139
1140 for (unsigned int face = 1; face < 6; face++)
1141 {
Jamie Madilld3d2a342013-10-07 10:46:35 -04001142 if (mImageArray[face][0]->getWidth() != getBaseLevelWidth() ||
1143 mImageArray[face][0]->getWidth() != getBaseLevelHeight() ||
1144 mImageArray[face][0]->getInternalFormat() != getBaseLevelInternalFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001145 {
1146 return false;
1147 }
1148 }
1149
1150 return true;
1151}
1152
1153bool TextureCubeMap::isMipmapCubeComplete() const
1154{
1155 if (isImmutable())
1156 {
1157 return true;
1158 }
1159
1160 if (!isCubeComplete())
1161 {
1162 return false;
1163 }
1164
Jamie Madilld3d2a342013-10-07 10:46:35 -04001165 GLsizei size = getBaseLevelWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001166 int q = log2(size);
1167
1168 for (int face = 0; face < 6; face++)
1169 {
1170 for (int level = 1; level <= q; level++)
1171 {
Jamie Madill07edd442013-07-19 16:36:58 -04001172 if (!isFaceLevelComplete(face, level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001173 {
1174 return false;
1175 }
1176 }
1177 }
1178
1179 return true;
1180}
1181
Jamie Madill07edd442013-07-19 16:36:58 -04001182bool TextureCubeMap::isFaceLevelComplete(int face, int level) const
1183{
1184 ASSERT(level >= 0 && face < 6 && level < (int)ArraySize(mImageArray[face]) && mImageArray[face][level] != NULL);
1185
1186 if (isImmutable())
1187 {
1188 return true;
1189 }
1190
Jamie Madilld3d2a342013-10-07 10:46:35 -04001191 int baseSize = getBaseLevelWidth();
Jamie Madill07edd442013-07-19 16:36:58 -04001192
Jamie Madilld3d2a342013-10-07 10:46:35 -04001193 if (baseSize <= 0)
Jamie Madill07edd442013-07-19 16:36:58 -04001194 {
1195 return false;
1196 }
1197
Jamie Madilld3d2a342013-10-07 10:46:35 -04001198 // "isCubeComplete" checks for base level completeness and we must call that
1199 // to determine if any face at level 0 is complete. We omit that check here
1200 // to avoid re-checking cube-completeness for every face at level 0.
Jamie Madill07edd442013-07-19 16:36:58 -04001201 if (level == 0)
1202 {
1203 return true;
1204 }
1205
Jamie Madilld3d2a342013-10-07 10:46:35 -04001206 // Check that non-zero levels are consistent with the base level.
1207 const rx::Image *faceLevelImage = mImageArray[face][level];
Jamie Madill07edd442013-07-19 16:36:58 -04001208
Jamie Madilld3d2a342013-10-07 10:46:35 -04001209 if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat())
Jamie Madill07edd442013-07-19 16:36:58 -04001210 {
1211 return false;
1212 }
1213
Jamie Madilld3d2a342013-10-07 10:46:35 -04001214 if (faceLevelImage->getWidth() != std::max(1, baseSize >> level))
Jamie Madill07edd442013-07-19 16:36:58 -04001215 {
1216 return false;
1217 }
1218
1219 return true;
1220}
1221
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001222bool TextureCubeMap::isCompressed(GLenum target, GLint level) const
1223{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001224 return IsFormatCompressed(getInternalFormat(target, level), mRenderer->getCurrentClientVersion());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001225}
1226
Geoff Lang8040f572013-07-25 16:49:54 -04001227bool TextureCubeMap::isDepth(GLenum target, GLint level) const
1228{
1229 return GetDepthBits(getInternalFormat(target, level), mRenderer->getCurrentClientVersion()) > 0;
1230}
1231
daniel@transgaming.comf032cb82012-10-31 19:51:52 +00001232// Constructs a native texture resource from the texture images, or returns an existing one
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001233void TextureCubeMap::createTexture()
1234{
Jamie Madilld3d2a342013-10-07 10:46:35 -04001235 GLsizei size = getBaseLevelWidth();
daniel@transgaming.come6a09842012-09-17 21:28:55 +00001236
1237 if (!(size > 0))
daniel@transgaming.comf032cb82012-10-31 19:51:52 +00001238 return; // do not attempt to create native textures for nonexistant data
daniel@transgaming.come6a09842012-09-17 21:28:55 +00001239
sminns@adobe.comce1189b2012-09-18 20:06:35 +00001240 GLint levels = creationLevels(size);
Jamie Madilld3d2a342013-10-07 10:46:35 -04001241 GLenum internalformat = getBaseLevelInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001242
1243 delete mTexStorage;
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001244 mTexStorage = new rx::TextureStorageInterfaceCube(mRenderer, levels, internalformat, mUsage, false, size);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001245
1246 if (mTexStorage->isManaged())
1247 {
1248 int levels = levelCount();
1249
1250 for (int face = 0; face < 6; face++)
1251 {
1252 for (int level = 0; level < levels; level++)
1253 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001254 mImageArray[face][level]->setManagedSurface(mTexStorage, face, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001255 }
1256 }
1257 }
1258
1259 mDirtyImages = true;
1260}
1261
1262void TextureCubeMap::updateTexture()
1263{
Jamie Madilleb3665c2013-07-19 16:36:57 -04001264 int levels = (isMipmapCubeComplete() ? levelCount() : 1);
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +00001265
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001266 for (int face = 0; face < 6; face++)
1267 {
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001268 for (int level = 0; level < levels; level++)
1269 {
Jamie Madill07edd442013-07-19 16:36:58 -04001270 updateTextureFaceLevel(face, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001271 }
1272 }
1273}
1274
Jamie Madill07edd442013-07-19 16:36:58 -04001275void TextureCubeMap::updateTextureFaceLevel(int face, int level)
1276{
1277 ASSERT(level >= 0 && face < 6 && level < (int)ArraySize(mImageArray[face]) && mImageArray[face][level] != NULL);
1278 rx::Image *image = mImageArray[face][level];
1279
1280 if (image->isDirty())
1281 {
1282 commitRect(face, level, 0, 0, image->getWidth(), image->getHeight());
1283 }
1284}
1285
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001286void TextureCubeMap::convertToRenderTarget()
1287{
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001288 rx::TextureStorageInterfaceCube *newTexStorage = NULL;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001289
Jamie Madilld3d2a342013-10-07 10:46:35 -04001290 if (getBaseLevelWidth() != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001291 {
Jamie Madilld3d2a342013-10-07 10:46:35 -04001292 GLsizei size = getBaseLevelWidth();
shannon.woods@transgaming.com6bb48862013-02-28 23:09:34 +00001293 GLint levels = mTexStorage != NULL ? mTexStorage->levelCount() : creationLevels(size);
Jamie Madilld3d2a342013-10-07 10:46:35 -04001294 GLenum internalformat = getBaseLevelInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001295
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001296 newTexStorage = new rx::TextureStorageInterfaceCube(mRenderer, levels, internalformat, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, true, size);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001297
1298 if (mTexStorage != NULL)
1299 {
daniel@transgaming.com1d80eee2012-11-28 19:33:31 +00001300 if (!mRenderer->copyToRenderTarget(newTexStorage, mTexStorage))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001301 {
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +00001302 delete newTexStorage;
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +00001303 return gl::error(GL_OUT_OF_MEMORY);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001304 }
1305 }
1306 }
1307
1308 delete mTexStorage;
1309 mTexStorage = newTexStorage;
1310
1311 mDirtyImages = true;
1312}
1313
Jamie Madill88f18f42013-09-18 14:36:19 -04001314void TextureCubeMap::setImage(int faceIndex, GLint level, GLsizei width, GLsizei height, GLint internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001315{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001316 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1317 GLint sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
1318 : GetSizedInternalFormat(format, type, clientVersion);
1319
1320 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001321
Jamie Madill88f18f42013-09-18 14:36:19 -04001322 Texture::setImage(unpack, type, pixels, mImageArray[faceIndex][level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001323}
1324
1325unsigned int TextureCubeMap::faceIndex(GLenum face)
1326{
1327 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
1328 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
1329 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
1330 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
1331 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
1332
1333 return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
1334}
1335
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001336void TextureCubeMap::redefineImage(int face, GLint level, GLint internalformat, GLsizei width, GLsizei height)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001337{
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001338 // If there currently is a corresponding storage texture image, it has these parameters
Jamie Madilld3d2a342013-10-07 10:46:35 -04001339 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1340 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1341 const int storageFormat = getBaseLevelInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001342
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001343 mImageArray[face][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, width, height, 1, false);
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001344
1345 if (mTexStorage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001346 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001347 const int storageLevels = mTexStorage->levelCount();
1348
1349 if ((level >= storageLevels && storageLevels != 0) ||
1350 width != storageWidth ||
1351 height != storageHeight ||
1352 internalformat != storageFormat) // Discard mismatched storage
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001353 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001354 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001355 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001356 for (int f = 0; f < 6; f++)
1357 {
1358 mImageArray[f][i]->markDirty();
1359 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001360 }
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001361
1362 delete mTexStorage;
1363 mTexStorage = NULL;
1364
1365 mDirtyImages = true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001366 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001367 }
1368}
1369
1370void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1371{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001372 unsigned int faceindex = faceIndex(target);
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001373 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1374 GLint sizedInternalFormat = IsSizedInternalFormat(format, clientVersion) ? format
1375 : GetSizedInternalFormat(format, GL_UNSIGNED_BYTE, clientVersion);
1376 redefineImage(faceindex, level, sizedInternalFormat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001377
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001378 if (!mImageArray[faceindex][level]->isRenderableFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001379 {
shannon.woods%transgaming.com@gtempaccount.come5dcce72013-04-13 03:44:33 +00001380 mImageArray[faceindex][level]->copy(0, 0, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001381 mDirtyImages = true;
1382 }
1383 else
1384 {
1385 if (!mTexStorage || !mTexStorage->isRenderTarget())
1386 {
1387 convertToRenderTarget();
1388 }
1389
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001390 mImageArray[faceindex][level]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001391
1392 ASSERT(width == height);
1393
1394 if (width > 0 && level < levelCount())
1395 {
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +00001396 gl::Rectangle sourceRect;
1397 sourceRect.x = x;
1398 sourceRect.width = width;
1399 sourceRect.y = y;
1400 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001401
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +00001402 mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001403 }
1404 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001405}
1406
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001407void 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 +00001408{
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001409 GLsizei size = mImageArray[faceIndex(target)][level]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001410
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001411 if (xoffset + width > size || yoffset + height > size || zoffset != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001412 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +00001413 return gl::error(GL_INVALID_VALUE);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001414 }
1415
Jamie Madill07edd442013-07-19 16:36:58 -04001416 unsigned int face = faceIndex(target);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001417
Jamie Madilld3d2a342013-10-07 10:46:35 -04001418 // We can only make our texture storage to a render target if the level we're copying *to* is complete
1419 // and the base level is cube-complete. The base level must be cube complete (common case) because we cannot
1420 // rely on the "getBaseLevel*" methods reliably otherwise.
1421 bool canCreateRenderTarget = isFaceLevelComplete(face, level) && isCubeComplete();
Jamie Madill07edd442013-07-19 16:36:58 -04001422
1423 if (!mImageArray[face][level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001424 {
Jamie Madill07edd442013-07-19 16:36:58 -04001425 mImageArray[face][level]->copy(0, 0, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001426 mDirtyImages = true;
1427 }
1428 else
1429 {
1430 if (!mTexStorage || !mTexStorage->isRenderTarget())
1431 {
1432 convertToRenderTarget();
1433 }
1434
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001435 if (level < levelCount())
1436 {
Jamie Madill07edd442013-07-19 16:36:58 -04001437 updateTextureFaceLevel(face, level);
1438
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001439 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1440
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +00001441 gl::Rectangle sourceRect;
1442 sourceRect.x = x;
1443 sourceRect.width = width;
1444 sourceRect.y = y;
1445 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001446
Jamie Madilld3d2a342013-10-07 10:46:35 -04001447 mRenderer->copyImage(source, sourceRect, gl::GetFormat(getBaseLevelInternalFormat(), clientVersion),
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +00001448 xoffset, yoffset, mTexStorage, target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001449 }
1450 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001451}
1452
1453void TextureCubeMap::storage(GLsizei levels, GLenum internalformat, GLsizei size)
1454{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001455 delete mTexStorage;
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001456 mTexStorage = new rx::TextureStorageInterfaceCube(mRenderer, levels, internalformat, mUsage, false, size);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001457 mImmutable = true;
1458
1459 for (int level = 0; level < levels; level++)
1460 {
1461 for (int face = 0; face < 6; face++)
1462 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001463 mImageArray[face][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, size, size, 1, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001464 size = std::max(1, size >> 1);
1465 }
1466 }
1467
1468 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1469 {
1470 for (int face = 0; face < 6; face++)
1471 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001472 mImageArray[face][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, GL_NONE, 0, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001473 }
1474 }
1475
1476 if (mTexStorage->isManaged())
1477 {
1478 int levels = levelCount();
1479
1480 for (int face = 0; face < 6; face++)
1481 {
1482 for (int level = 0; level < levels; level++)
1483 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001484 mImageArray[face][level]->setManagedSurface(mTexStorage, face, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001485 }
1486 }
1487 }
1488}
1489
1490void TextureCubeMap::generateMipmaps()
1491{
1492 if (!isCubeComplete())
1493 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +00001494 return gl::error(GL_INVALID_OPERATION);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001495 }
1496
daniel@transgaming.comea32d482012-11-28 19:33:18 +00001497 if (!mRenderer->getNonPower2TextureSupport())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001498 {
Jamie Madilld3d2a342013-10-07 10:46:35 -04001499 if (!isPow2(getBaseLevelWidth()))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001500 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +00001501 return gl::error(GL_INVALID_OPERATION);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001502 }
1503 }
1504
1505 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Jamie Madilld3d2a342013-10-07 10:46:35 -04001506 unsigned int q = log2(getBaseLevelWidth());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001507 for (unsigned int f = 0; f < 6; f++)
1508 {
1509 for (unsigned int i = 1; i <= q; i++)
1510 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001511 redefineImage(f, i, mImageArray[f][0]->getInternalFormat(),
shannon.woods@transgaming.com8a406682013-02-28 23:15:26 +00001512 std::max(mImageArray[f][0]->getWidth() >> i, 1),
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001513 std::max(mImageArray[f][0]->getWidth() >> i, 1));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001514 }
1515 }
1516
1517 if (mTexStorage && mTexStorage->isRenderTarget())
1518 {
1519 for (unsigned int f = 0; f < 6; f++)
1520 {
1521 for (unsigned int i = 1; i <= q; i++)
1522 {
daniel@transgaming.com0ad830b2012-10-31 19:52:12 +00001523 mTexStorage->generateMipmap(f, i);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001524
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001525 mImageArray[f][i]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001526 }
1527 }
1528 }
1529 else
1530 {
1531 for (unsigned int f = 0; f < 6; f++)
1532 {
1533 for (unsigned int i = 1; i <= q; i++)
1534 {
daniel@transgaming.com4ba24062012-12-20 20:54:24 +00001535 mRenderer->generateMipmap(mImageArray[f][i], mImageArray[f][i - 1]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001536 }
1537 }
1538 }
1539}
1540
Jamie Madilld3d2a342013-10-07 10:46:35 -04001541const rx::Image *TextureCubeMap::getBaseLevelImage() const
1542{
1543 // Note: if we are not cube-complete, there is no single base level image that can describe all
1544 // cube faces, so this method is only well-defined for a cube-complete base level.
1545 return mImageArray[0][0];
1546}
1547
Geoff Lang8040f572013-07-25 16:49:54 -04001548Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target, GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001549{
1550 if (!IsCubemapTextureTarget(target))
1551 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +00001552 return gl::error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001553 }
1554
1555 unsigned int face = faceIndex(target);
1556
Geoff Lang8040f572013-07-25 16:49:54 -04001557 Renderbuffer *renderBuffer = mRenderbufferProxies.get(level, face);
1558 if (!renderBuffer)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001559 {
Geoff Lang8040f572013-07-25 16:49:54 -04001560 renderBuffer = new Renderbuffer(mRenderer, id(), new RenderbufferTextureCubeMap(this, target, level));
1561 mRenderbufferProxies.add(level, face, renderBuffer);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001562 }
1563
Geoff Lang8040f572013-07-25 16:49:54 -04001564 return renderBuffer;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001565}
1566
Geoff Lang8040f572013-07-25 16:49:54 -04001567unsigned int TextureCubeMap::getRenderTargetSerial(GLenum faceTarget, GLint level)
1568{
1569 if (!mTexStorage || !mTexStorage->isRenderTarget())
1570 {
1571 convertToRenderTarget();
1572 }
1573
1574 return mTexStorage ? mTexStorage->getRenderTargetSerial(faceTarget, level) : 0;
1575}
1576
1577rx::RenderTarget *TextureCubeMap::getRenderTarget(GLenum target, GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001578{
1579 ASSERT(IsCubemapTextureTarget(target));
1580
1581 // ensure the underlying texture is created
1582 if (getStorage(true) == NULL)
1583 {
1584 return NULL;
1585 }
1586
1587 updateTexture();
Geoff Lang8040f572013-07-25 16:49:54 -04001588
1589 // ensure this is NOT a depth texture
1590 if (isDepth(target, level))
1591 {
1592 return NULL;
1593 }
1594
1595 return mTexStorage->getRenderTarget(target, level);
1596}
1597
1598rx::RenderTarget *TextureCubeMap::getDepthStencil(GLenum target, GLint level)
1599{
1600 ASSERT(IsCubemapTextureTarget(target));
1601
1602 // ensure the underlying texture is created
1603 if (getStorage(true) == NULL)
1604 {
1605 return NULL;
1606 }
1607
1608 updateTexture();
1609
1610 // ensure this is a depth texture
1611 if (!isDepth(target, level))
1612 {
1613 return NULL;
1614 }
1615
1616 return mTexStorage->getRenderTarget(target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001617}
1618
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +00001619int TextureCubeMap::levelCount()
1620{
1621 return mTexStorage ? mTexStorage->levelCount() - getLodOffset() : 0;
1622}
1623
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001624rx::TextureStorageInterface *TextureCubeMap::getStorage(bool renderTarget)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001625{
1626 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
1627 {
1628 if (renderTarget)
1629 {
1630 convertToRenderTarget();
1631 }
1632 else
1633 {
1634 createTexture();
1635 }
1636 }
1637
1638 return mTexStorage;
1639}
1640
Geoff Lang4907f2c2013-07-25 12:53:57 -04001641Texture3D::Texture3D(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_3D)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001642{
1643 mTexStorage = NULL;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001644
1645 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1646 {
1647 mImageArray[i] = renderer->createImage();
1648 }
1649}
1650
1651Texture3D::~Texture3D()
1652{
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001653 delete mTexStorage;
1654 mTexStorage = NULL;
1655
1656 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1657 {
1658 delete mImageArray[i];
1659 }
1660}
1661
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001662GLsizei Texture3D::getWidth(GLint level) const
1663{
1664 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getWidth() : 0;
1665}
1666
1667GLsizei Texture3D::getHeight(GLint level) const
1668{
1669 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getHeight() : 0;
1670}
1671
1672GLsizei Texture3D::getDepth(GLint level) const
1673{
1674 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getDepth() : 0;
1675}
1676
1677GLenum Texture3D::getInternalFormat(GLint level) const
1678{
1679 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getInternalFormat() : GL_NONE;
1680}
1681
1682GLenum Texture3D::getActualFormat(GLint level) const
1683{
1684 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getActualFormat() : D3DFMT_UNKNOWN;
1685}
1686
1687bool Texture3D::isCompressed(GLint level) const
1688{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001689 return IsFormatCompressed(getInternalFormat(level), mRenderer->getCurrentClientVersion());
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001690}
1691
1692bool Texture3D::isDepth(GLint level) const
1693{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001694 return GetDepthBits(getInternalFormat(level), mRenderer->getCurrentClientVersion()) > 0;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001695}
1696
Jamie Madill88f18f42013-09-18 14:36:19 -04001697void Texture3D::setImage(GLint level, GLsizei width, GLsizei height, GLsizei depth, GLint internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001698{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001699 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1700 GLint sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
1701 : GetSizedInternalFormat(format, type, clientVersion);
1702 redefineImage(level, sizedInternalFormat, width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001703
Jamie Madill88f18f42013-09-18 14:36:19 -04001704 Texture::setImage(unpack, type, pixels, mImageArray[level]);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001705}
1706
1707void Texture3D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
1708{
1709 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1710 redefineImage(level, format, width, height, depth);
1711
1712 Texture::setCompressedImage(imageSize, pixels, mImageArray[level]);
1713}
1714
Jamie Madill88f18f42013-09-18 14:36:19 -04001715void 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 +00001716{
Jamie Madill88f18f42013-09-18 14:36:19 -04001717 if (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 +00001718 {
1719 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1720 }
1721}
1722
1723void Texture3D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
1724{
1725 if (Texture::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth, format, imageSize, pixels, mImageArray[level]))
1726 {
1727 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1728 }
1729}
1730
1731void Texture3D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
1732{
1733 delete mTexStorage;
1734 mTexStorage = new rx::TextureStorageInterface3D(mRenderer, levels, internalformat, mUsage, width, height, depth);
1735 mImmutable = true;
1736
1737 for (int level = 0; level < levels; level++)
1738 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001739 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, true);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001740 width = std::max(1, width >> 1);
1741 height = std::max(1, height >> 1);
1742 depth = std::max(1, depth >> 1);
1743 }
1744
1745 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1746 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001747 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, GL_NONE, 0, 0, 0, true);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001748 }
1749
1750 if (mTexStorage->isManaged())
1751 {
1752 int levels = levelCount();
1753
1754 for (int level = 0; level < levels; level++)
1755 {
1756 mImageArray[level]->setManagedSurface(mTexStorage, level);
1757 }
1758 }
1759}
1760
1761
1762void Texture3D::generateMipmaps()
1763{
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001764 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Jamie Madilld3d2a342013-10-07 10:46:35 -04001765 unsigned int q = log2(std::max(getBaseLevelWidth(), getBaseLevelHeight()));
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001766 for (unsigned int i = 1; i <= q; i++)
1767 {
Jamie Madilld3d2a342013-10-07 10:46:35 -04001768 redefineImage(i, getBaseLevelInternalFormat(),
1769 std::max(getBaseLevelWidth() >> i, 1),
1770 std::max(getBaseLevelHeight() >> i, 1),
1771 std::max(getBaseLevelDepth() >> i, 1));
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001772 }
1773
1774 if (mTexStorage && mTexStorage->isRenderTarget())
1775 {
1776 for (unsigned int i = 1; i <= q; i++)
1777 {
1778 mTexStorage->generateMipmap(i);
1779
1780 mImageArray[i]->markClean();
1781 }
1782 }
1783 else
1784 {
1785 for (unsigned int i = 1; i <= q; i++)
1786 {
1787 mRenderer->generateMipmap(mImageArray[i], mImageArray[i - 1]);
1788 }
1789 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001790}
1791
Jamie Madilld3d2a342013-10-07 10:46:35 -04001792const rx::Image *Texture3D::getBaseLevelImage() const
1793{
1794 return mImageArray[0];
1795}
1796
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001797void Texture3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1798{
1799 if (xoffset + width > mImageArray[level]->getWidth() || yoffset + height > mImageArray[level]->getHeight() || zoffset >= mImageArray[level]->getDepth())
1800 {
1801 return gl::error(GL_INVALID_VALUE);
1802 }
1803
Jamie Madill07edd442013-07-19 16:36:58 -04001804 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
1805 // the current level we're copying to is defined (with appropriate format, width & height)
1806 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
1807
1808 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001809 {
1810 mImageArray[level]->copy(xoffset, yoffset, zoffset, x, y, width, height, source);
1811 mDirtyImages = true;
1812 }
1813 else
1814 {
1815 if (!mTexStorage || !mTexStorage->isRenderTarget())
1816 {
1817 convertToRenderTarget();
1818 }
1819
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001820 if (level < levelCount())
1821 {
Jamie Madill07edd442013-07-19 16:36:58 -04001822 updateTextureLevel(level);
1823
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001824 gl::Rectangle sourceRect;
1825 sourceRect.x = x;
1826 sourceRect.width = width;
1827 sourceRect.y = y;
1828 sourceRect.height = height;
1829
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001830 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1831
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001832 mRenderer->copyImage(source, sourceRect,
Jamie Madilld3d2a342013-10-07 10:46:35 -04001833 gl::GetFormat(getBaseLevelInternalFormat(), clientVersion),
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001834 xoffset, yoffset, zoffset, mTexStorage, level);
1835 }
1836 }
1837}
1838
Jamie Madillf8989902013-07-19 16:36:58 -04001839bool Texture3D::isSamplerComplete(const SamplerState &samplerState) const
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001840{
Jamie Madilld3d2a342013-10-07 10:46:35 -04001841 GLsizei width = getBaseLevelWidth();
1842 GLsizei height = getBaseLevelHeight();
1843 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001844
1845 if (width <= 0 || height <= 0 || depth <= 0)
1846 {
1847 return false;
1848 }
1849
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001850 if (!IsTextureFilteringSupported(getInternalFormat(0), mRenderer))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001851 {
Jamie Madillf8989902013-07-19 16:36:58 -04001852 if (samplerState.magFilter != GL_NEAREST ||
1853 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001854 {
1855 return false;
1856 }
1857 }
1858
Jamie Madillf8989902013-07-19 16:36:58 -04001859 if (IsMipmapFiltered(samplerState) && !isMipmapComplete())
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001860 {
1861 return false;
1862 }
1863
1864 return true;
1865}
1866
1867bool Texture3D::isMipmapComplete() const
1868{
Jamie Madilld3d2a342013-10-07 10:46:35 -04001869 GLsizei width = getBaseLevelWidth();
1870 GLsizei height = getBaseLevelHeight();
1871 GLsizei depth = getBaseLevelDepth();
Jamie Madill07edd442013-07-19 16:36:58 -04001872
1873 int q = log2(std::max(std::max(width, height), depth));
1874
1875 for (int level = 0; level <= q; level++)
1876 {
1877 if (!isLevelComplete(level))
1878 {
1879 return false;
1880 }
1881 }
1882
1883 return true;
1884}
1885
1886bool Texture3D::isLevelComplete(int level) const
1887{
1888 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1889
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001890 if (isImmutable())
1891 {
1892 return true;
1893 }
1894
Jamie Madilld3d2a342013-10-07 10:46:35 -04001895 GLsizei width = getBaseLevelWidth();
1896 GLsizei height = getBaseLevelHeight();
1897 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001898
1899 if (width <= 0 || height <= 0 || depth <= 0)
1900 {
1901 return false;
1902 }
1903
Jamie Madill07edd442013-07-19 16:36:58 -04001904 if (level == 0)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001905 {
Jamie Madill07edd442013-07-19 16:36:58 -04001906 return true;
1907 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001908
Jamie Madill07edd442013-07-19 16:36:58 -04001909 rx::Image *levelImage = mImageArray[level];
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001910
Jamie Madilld3d2a342013-10-07 10:46:35 -04001911 if (levelImage->getInternalFormat() != getBaseLevelInternalFormat())
Jamie Madill07edd442013-07-19 16:36:58 -04001912 {
1913 return false;
1914 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001915
Jamie Madill07edd442013-07-19 16:36:58 -04001916 if (levelImage->getWidth() != std::max(1, width >> level))
1917 {
1918 return false;
1919 }
1920
1921 if (levelImage->getHeight() != std::max(1, height >> level))
1922 {
1923 return false;
1924 }
1925
1926 if (levelImage->getDepth() != std::max(1, depth >> level))
1927 {
1928 return false;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001929 }
1930
1931 return true;
1932}
1933
Geoff Lang8040f572013-07-25 16:49:54 -04001934Renderbuffer *Texture3D::getRenderbuffer(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001935{
Geoff Lang8040f572013-07-25 16:49:54 -04001936 Renderbuffer *renderBuffer = mRenderbufferProxies.get(level, layer);
1937 if (!renderBuffer)
1938 {
Geoff Langd5d8e392013-07-25 16:53:03 -04001939 renderBuffer = new Renderbuffer(mRenderer, id(), new RenderbufferTexture3DLayer(this, level, layer));
1940 mRenderbufferProxies.add(level, 0, renderBuffer);
Geoff Lang8040f572013-07-25 16:49:54 -04001941 }
1942
1943 return renderBuffer;
1944}
1945
1946unsigned int Texture3D::getRenderTargetSerial(GLint level, GLint layer)
1947{
1948 if (!mTexStorage || !mTexStorage->isRenderTarget())
1949 {
1950 convertToRenderTarget();
1951 }
1952
1953 return mTexStorage ? mTexStorage->getRenderTargetSerial(level, layer) : 0;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001954}
1955
1956int Texture3D::levelCount()
1957{
1958 return mTexStorage ? mTexStorage->levelCount() : 0;
1959}
1960
1961void Texture3D::createTexture()
1962{
Jamie Madilld3d2a342013-10-07 10:46:35 -04001963 GLsizei width = getBaseLevelWidth();
1964 GLsizei height = getBaseLevelHeight();
1965 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001966
1967 if (!(width > 0 && height > 0 && depth > 0))
1968 return; // do not attempt to create native textures for nonexistant data
1969
1970 GLint levels = creationLevels(width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001971
1972 delete mTexStorage;
Jamie Madilld3d2a342013-10-07 10:46:35 -04001973 mTexStorage = new rx::TextureStorageInterface3D(mRenderer, levels, getBaseLevelInternalFormat(), mUsage, width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001974
1975 if (mTexStorage->isManaged())
1976 {
1977 int levels = levelCount();
1978
1979 for (int level = 0; level < levels; level++)
1980 {
1981 mImageArray[level]->setManagedSurface(mTexStorage, level);
1982 }
1983 }
1984
1985 mDirtyImages = true;
1986}
1987
1988void Texture3D::updateTexture()
1989{
Jamie Madilleb3665c2013-07-19 16:36:57 -04001990 int levels = (isMipmapComplete() ? levelCount() : 1);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001991
1992 for (int level = 0; level < levels; level++)
1993 {
Jamie Madill07edd442013-07-19 16:36:58 -04001994 updateTextureLevel(level);
1995 }
1996}
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001997
Jamie Madill07edd442013-07-19 16:36:58 -04001998void Texture3D::updateTextureLevel(int level)
1999{
2000 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
2001
2002 rx::Image *image = mImageArray[level];
2003
2004 if (image->isDirty())
2005 {
2006 commitRect(level, 0, 0, 0, mImageArray[level]->getWidth(), mImageArray[level]->getHeight(), mImageArray[level]->getDepth());
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002007 }
2008}
2009
2010void Texture3D::convertToRenderTarget()
2011{
2012 rx::TextureStorageInterface3D *newTexStorage = NULL;
2013
Jamie Madilld3d2a342013-10-07 10:46:35 -04002014 if (getBaseLevelWidth() != 0 && getBaseLevelHeight() != 0 && getBaseLevelDepth() != 0)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002015 {
Jamie Madilld3d2a342013-10-07 10:46:35 -04002016 GLsizei width = getBaseLevelWidth();
2017 GLsizei height = getBaseLevelHeight();
2018 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002019 GLint levels = mTexStorage != NULL ? mTexStorage->levelCount() : creationLevels(width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002020
Jamie Madilld3d2a342013-10-07 10:46:35 -04002021 newTexStorage = new rx::TextureStorageInterface3D(mRenderer, levels, getBaseLevelInternalFormat(), GL_FRAMEBUFFER_ATTACHMENT_ANGLE, width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002022
2023 if (mTexStorage != NULL)
2024 {
2025 if (!mRenderer->copyToRenderTarget(newTexStorage, mTexStorage))
2026 {
2027 delete newTexStorage;
2028 return gl::error(GL_OUT_OF_MEMORY);
2029 }
2030 }
2031 }
2032
2033 delete mTexStorage;
2034 mTexStorage = newTexStorage;
2035
2036 mDirtyImages = true;
2037}
2038
Geoff Lang8040f572013-07-25 16:49:54 -04002039rx::RenderTarget *Texture3D::getRenderTarget(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002040{
Geoff Lang8040f572013-07-25 16:49:54 -04002041 // ensure the underlying texture is created
2042 if (getStorage(true) == NULL)
2043 {
2044 return NULL;
2045 }
2046
2047 updateTexture();
2048
2049 // ensure this is NOT a depth texture
2050 if (isDepth(level))
2051 {
2052 return NULL;
2053 }
2054
2055 return mTexStorage->getRenderTarget(level, layer);
2056}
2057
2058rx::RenderTarget *Texture3D::getDepthStencil(GLint level, GLint layer)
2059{
2060 // ensure the underlying texture is created
2061 if (getStorage(true) == NULL)
2062 {
2063 return NULL;
2064 }
2065
2066 updateTexture();
2067
2068 // ensure this is a depth texture
2069 if (!isDepth(level))
2070 {
2071 return NULL;
2072 }
2073
2074 return mTexStorage->getRenderTarget(level, layer);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002075}
2076
2077rx::TextureStorageInterface *Texture3D::getStorage(bool renderTarget)
2078{
2079 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
2080 {
2081 if (renderTarget)
2082 {
2083 convertToRenderTarget();
2084 }
2085 else
2086 {
2087 createTexture();
2088 }
2089 }
2090
2091 return mTexStorage;
2092}
2093
2094void Texture3D::redefineImage(GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth)
2095{
2096 // If there currently is a corresponding storage texture image, it has these parameters
Jamie Madilld3d2a342013-10-07 10:46:35 -04002097 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2098 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
2099 const int storageDepth = std::max(1, getBaseLevelDepth() >> level);
2100 const int storageFormat = getBaseLevelInternalFormat();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002101
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00002102 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, false);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002103
2104 if (mTexStorage)
2105 {
2106 const int storageLevels = mTexStorage->levelCount();
2107
2108 if ((level >= storageLevels && storageLevels != 0) ||
2109 width != storageWidth ||
2110 height != storageHeight ||
2111 depth != storageDepth ||
2112 internalformat != storageFormat) // Discard mismatched storage
2113 {
2114 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
2115 {
2116 mImageArray[i]->markDirty();
2117 }
2118
2119 delete mTexStorage;
2120 mTexStorage = NULL;
2121 mDirtyImages = true;
2122 }
2123 }
2124}
2125
2126void Texture3D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth)
2127{
2128 if (level < levelCount())
2129 {
2130 rx::Image *image = mImageArray[level];
2131 if (image->updateSurface(mTexStorage, level, xoffset, yoffset, zoffset, width, height, depth))
2132 {
2133 image->markClean();
2134 }
2135 }
2136}
2137
Geoff Lang4907f2c2013-07-25 12:53:57 -04002138Texture2DArray::Texture2DArray(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_2D_ARRAY)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002139{
2140 mTexStorage = NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002141
2142 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2143 {
2144 mLayerCounts[level] = 0;
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002145 mImageArray[level] = NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002146 }
2147}
2148
2149Texture2DArray::~Texture2DArray()
2150{
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002151 delete mTexStorage;
2152 mTexStorage = NULL;
2153 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2154 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002155 for (int layer = 0; layer < mLayerCounts[level]; ++layer)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002156 {
2157 delete mImageArray[level][layer];
2158 }
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002159 delete[] mImageArray[level];
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002160 }
2161}
2162
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002163GLsizei Texture2DArray::getWidth(GLint level) const
2164{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002165 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 +00002166}
2167
2168GLsizei Texture2DArray::getHeight(GLint level) const
2169{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002170 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 +00002171}
2172
2173GLsizei Texture2DArray::getDepth(GLint level) const
2174{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002175 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mLayerCounts[level] : 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002176}
2177
2178GLenum Texture2DArray::getInternalFormat(GLint level) const
2179{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002180 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 +00002181}
2182
2183GLenum Texture2DArray::getActualFormat(GLint level) const
2184{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002185 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 +00002186}
2187
2188bool Texture2DArray::isCompressed(GLint level) const
2189{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00002190 return IsFormatCompressed(getInternalFormat(level), mRenderer->getCurrentClientVersion());
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002191}
2192
2193bool Texture2DArray::isDepth(GLint level) const
2194{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00002195 return GetDepthBits(getInternalFormat(level), mRenderer->getCurrentClientVersion()) > 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002196}
2197
Jamie Madill88f18f42013-09-18 14:36:19 -04002198void Texture2DArray::setImage(GLint level, GLsizei width, GLsizei height, GLsizei depth, GLint internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002199{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00002200 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2201 GLint sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
2202 : GetSizedInternalFormat(format, type, clientVersion);
2203 redefineImage(level, sizedInternalFormat, width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002204
Jamie Madill88f18f42013-09-18 14:36:19 -04002205 GLsizei inputDepthPitch = gl::GetDepthPitch(sizedInternalFormat, type, clientVersion, width, height, unpack.alignment);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002206
2207 for (int i = 0; i < depth; i++)
2208 {
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002209 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
Jamie Madill88f18f42013-09-18 14:36:19 -04002210 Texture::setImage(unpack, type, layerPixels, mImageArray[level][i]);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002211 }
2212}
2213
2214void Texture2DArray::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
2215{
2216 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
2217 redefineImage(level, format, width, height, depth);
2218
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002219 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2220 GLsizei inputDepthPitch = gl::GetDepthPitch(format, GL_UNSIGNED_BYTE, clientVersion, width, height, 1);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002221
2222 for (int i = 0; i < depth; i++)
2223 {
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002224 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002225 Texture::setCompressedImage(imageSize, layerPixels, mImageArray[level][i]);
2226 }
2227}
2228
Jamie Madill88f18f42013-09-18 14:36:19 -04002229void 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 +00002230{
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002231 GLint internalformat = getInternalFormat(level);
2232 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Jamie Madill88f18f42013-09-18 14:36:19 -04002233 GLsizei inputDepthPitch = gl::GetDepthPitch(internalformat, type, clientVersion, width, height, unpack.alignment);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002234
2235 for (int i = 0; i < depth; i++)
2236 {
2237 int layer = zoffset + i;
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002238 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002239
Jamie Madill88f18f42013-09-18 14:36:19 -04002240 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 +00002241 {
2242 commitRect(level, xoffset, yoffset, layer, width, height);
2243 }
2244 }
2245}
2246
2247void Texture2DArray::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
2248{
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002249 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2250 GLsizei inputDepthPitch = gl::GetDepthPitch(format, GL_UNSIGNED_BYTE, clientVersion, width, height, 1);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002251
2252 for (int i = 0; i < depth; i++)
2253 {
2254 int layer = zoffset + i;
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002255 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002256
2257 if (Texture::subImageCompressed(xoffset, yoffset, zoffset, width, height, 1, format, imageSize, layerPixels, mImageArray[level][layer]))
2258 {
2259 commitRect(level, xoffset, yoffset, layer, width, height);
2260 }
2261 }
2262}
2263
2264void Texture2DArray::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2265{
2266 delete mTexStorage;
2267 mTexStorage = new rx::TextureStorageInterface2DArray(mRenderer, levels, internalformat, mUsage, width, height, depth);
2268 mImmutable = true;
2269
2270 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2271 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002272 GLsizei levelWidth = std::max(width >> level, 1);
Geoff Lange836cf22013-08-05 14:12:37 -04002273 GLsizei levelHeight = std::max(height >> level, 1);
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002274
2275 // Clear this level
2276 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002277 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002278 delete mImageArray[level][layer];
2279 }
2280 delete[] mImageArray[level];
2281 mImageArray[level] = NULL;
2282 mLayerCounts[level] = 0;
2283
2284 if (level < levels)
2285 {
2286 // Create new images for this level
2287 mImageArray[level] = new rx::Image*[depth]();
2288 mLayerCounts[level] = depth;
2289
2290 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002291 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002292 mImageArray[level][layer] = mRenderer->createImage();
2293 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, levelWidth,
2294 levelHeight, 1, true);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002295 }
2296 }
2297 }
2298
2299 if (mTexStorage->isManaged())
2300 {
2301 int levels = levelCount();
2302
2303 for (int level = 0; level < levels; level++)
2304 {
2305 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2306 {
2307 mImageArray[level][layer]->setManagedSurface(mTexStorage, layer, level);
2308 }
2309 }
2310 }
2311}
2312
2313void Texture2DArray::generateMipmaps()
2314{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002315 int baseWidth = getBaseLevelWidth();
2316 int baseHeight = getBaseLevelHeight();
2317 int baseDepth = getBaseLevelDepth();
2318 GLenum baseFormat = getBaseLevelInternalFormat();
2319
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00002320 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Jamie Madilld3d2a342013-10-07 10:46:35 -04002321 int q = log2(std::max(baseWidth, baseHeight));
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00002322 for (int i = 1; i <= q; i++)
2323 {
Jamie Madilld3d2a342013-10-07 10:46:35 -04002324 redefineImage(i, baseFormat, std::max(baseWidth >> i, 1), std::max(baseHeight >> i, 1), baseDepth);
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00002325 }
2326
2327 if (mTexStorage && mTexStorage->isRenderTarget())
2328 {
2329 for (int level = 1; level <= q; level++)
2330 {
2331 mTexStorage->generateMipmap(level);
2332
2333 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2334 {
2335 mImageArray[level][layer]->markClean();
2336 }
2337 }
2338 }
2339 else
2340 {
2341 for (int level = 1; level <= q; level++)
2342 {
2343 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2344 {
2345 mRenderer->generateMipmap(mImageArray[level][layer], mImageArray[level - 1][layer]);
2346 }
2347 }
2348 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002349}
2350
Jamie Madilld3d2a342013-10-07 10:46:35 -04002351const rx::Image *Texture2DArray::getBaseLevelImage() const
2352{
2353 return mImageArray[0][0];
2354}
2355
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002356void Texture2DArray::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
2357{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002358 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 +00002359 {
2360 return gl::error(GL_INVALID_VALUE);
2361 }
2362
Jamie Madill07edd442013-07-19 16:36:58 -04002363 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
2364 // the current level we're copying to is defined (with appropriate format, width & height)
2365 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
2366
2367 if (!mImageArray[level][0]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002368 {
2369 mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, x, y, width, height, source);
2370 mDirtyImages = true;
2371 }
2372 else
2373 {
2374 if (!mTexStorage || !mTexStorage->isRenderTarget())
2375 {
2376 convertToRenderTarget();
2377 }
2378
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002379 if (level < levelCount())
2380 {
Jamie Madill07edd442013-07-19 16:36:58 -04002381 updateTextureLevel(level);
2382
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002383 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2384
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002385 gl::Rectangle sourceRect;
2386 sourceRect.x = x;
2387 sourceRect.width = width;
2388 sourceRect.y = y;
2389 sourceRect.height = height;
2390
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002391 mRenderer->copyImage(source, sourceRect, gl::GetFormat(getInternalFormat(0), clientVersion),
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002392 xoffset, yoffset, zoffset, mTexStorage, level);
2393 }
2394 }
2395}
2396
Jamie Madillf8989902013-07-19 16:36:58 -04002397bool Texture2DArray::isSamplerComplete(const SamplerState &samplerState) const
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002398{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002399 GLsizei width = getBaseLevelWidth();
2400 GLsizei height = getBaseLevelHeight();
2401 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002402
2403 if (width <= 0 || height <= 0 || depth <= 0)
2404 {
2405 return false;
2406 }
2407
Jamie Madilld3d2a342013-10-07 10:46:35 -04002408 if (!IsTextureFilteringSupported(getBaseLevelInternalFormat(), mRenderer))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002409 {
Jamie Madillf8989902013-07-19 16:36:58 -04002410 if (samplerState.magFilter != GL_NEAREST ||
2411 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002412 {
2413 return false;
2414 }
2415 }
2416
Jamie Madillf8989902013-07-19 16:36:58 -04002417 if (IsMipmapFiltered(samplerState) && !isMipmapComplete())
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002418 {
2419 return false;
2420 }
2421
2422 return true;
2423}
2424
2425bool Texture2DArray::isMipmapComplete() const
2426{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002427 GLsizei width = getBaseLevelWidth();
2428 GLsizei height = getBaseLevelHeight();
Jamie Madill07edd442013-07-19 16:36:58 -04002429
2430 int q = log2(std::max(width, height));
2431
2432 for (int level = 1; level <= q; level++)
2433 {
2434 if (!isLevelComplete(level))
2435 {
2436 return false;
2437 }
2438 }
2439
2440 return true;
2441}
2442
2443bool Texture2DArray::isLevelComplete(int level) const
2444{
2445 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
2446
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002447 if (isImmutable())
2448 {
2449 return true;
2450 }
2451
Jamie Madilld3d2a342013-10-07 10:46:35 -04002452 GLsizei width = getBaseLevelWidth();
2453 GLsizei height = getBaseLevelHeight();
2454 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002455
2456 if (width <= 0 || height <= 0 || depth <= 0)
2457 {
2458 return false;
2459 }
2460
Jamie Madill07edd442013-07-19 16:36:58 -04002461 if (level == 0)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002462 {
Jamie Madill07edd442013-07-19 16:36:58 -04002463 return true;
2464 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002465
Jamie Madill07edd442013-07-19 16:36:58 -04002466 if (getInternalFormat(level) != getInternalFormat(0))
2467 {
2468 return false;
2469 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002470
Jamie Madill07edd442013-07-19 16:36:58 -04002471 if (getWidth(level) != std::max(1, width >> level))
2472 {
2473 return false;
2474 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002475
Jamie Madill07edd442013-07-19 16:36:58 -04002476 if (getHeight(level) != std::max(1, height >> level))
2477 {
2478 return false;
2479 }
2480
2481 if (getDepth(level) != depth)
2482 {
2483 return false;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002484 }
2485
2486 return true;
2487}
2488
Geoff Lang8040f572013-07-25 16:49:54 -04002489Renderbuffer *Texture2DArray::getRenderbuffer(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002490{
Geoff Lang8040f572013-07-25 16:49:54 -04002491 Renderbuffer *renderBuffer = mRenderbufferProxies.get(level, layer);
2492 if (!renderBuffer)
2493 {
Geoff Langd5d8e392013-07-25 16:53:03 -04002494 renderBuffer = new Renderbuffer(mRenderer, id(), new RenderbufferTexture2DArrayLayer(this, level, layer));
2495 mRenderbufferProxies.add(level, 0, renderBuffer);
Geoff Lang8040f572013-07-25 16:49:54 -04002496 }
2497
2498 return renderBuffer;
2499}
2500
2501unsigned int Texture2DArray::getRenderTargetSerial( GLint level, GLint layer )
2502{
2503 if (!mTexStorage || !mTexStorage->isRenderTarget())
2504 {
2505 convertToRenderTarget();
2506 }
2507
2508 return mTexStorage ? mTexStorage->getRenderTargetSerial(level, layer) : 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002509}
2510
2511int Texture2DArray::levelCount()
2512{
2513 return mTexStorage ? mTexStorage->levelCount() : 0;
2514}
2515
2516void Texture2DArray::createTexture()
2517{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002518 GLsizei width = getBaseLevelWidth();
2519 GLsizei height = getBaseLevelHeight();
2520 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002521
2522 if (width <= 0 || height <= 0 || depth <= 0)
2523 {
2524 return; // do not attempt to create native textures for nonexistant data
2525 }
2526
2527 GLint levels = creationLevels(width, height);
Jamie Madilld3d2a342013-10-07 10:46:35 -04002528 GLenum internalformat = getBaseLevelInternalFormat();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002529
2530 delete mTexStorage;
2531 mTexStorage = new rx::TextureStorageInterface2DArray(mRenderer, levels, internalformat, mUsage, width, height, depth);
2532
2533 if (mTexStorage->isManaged())
2534 {
2535 int levels = levelCount();
2536 for (int level = 0; level < levels; level++)
2537 {
2538 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2539 {
2540 mImageArray[level][layer]->setManagedSurface(mTexStorage, layer, level);
2541 }
2542 }
2543 }
2544
2545 mDirtyImages = true;
2546}
2547
2548void Texture2DArray::updateTexture()
2549{
Jamie Madilleb3665c2013-07-19 16:36:57 -04002550 int levels = (isMipmapComplete() ? levelCount() : 1);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002551 for (int level = 0; level < levels; level++)
2552 {
Jamie Madill07edd442013-07-19 16:36:58 -04002553 updateTextureLevel(level);
2554 }
2555}
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002556
Jamie Madill07edd442013-07-19 16:36:58 -04002557void Texture2DArray::updateTextureLevel(int level)
2558{
2559 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2560 {
2561 rx::Image *image = mImageArray[level][layer];
2562
2563 if (image->isDirty())
2564 {
2565 commitRect(level, 0, 0, layer, image->getWidth(), image->getHeight());
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002566 }
2567 }
2568}
2569
2570void Texture2DArray::convertToRenderTarget()
2571{
2572 rx::TextureStorageInterface2DArray *newTexStorage = NULL;
2573
Jamie Madilld3d2a342013-10-07 10:46:35 -04002574 GLsizei width = getBaseLevelWidth();
2575 GLsizei height = getBaseLevelHeight();
2576 GLsizei depth = getBaseLevelDepth();
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002577
2578 if (width != 0 && height != 0 && depth != 0)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002579 {
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002580 GLint levels = mTexStorage != NULL ? mTexStorage->levelCount() : creationLevels(width, height);
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002581 GLenum internalformat = getInternalFormat(0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002582
2583 newTexStorage = new rx::TextureStorageInterface2DArray(mRenderer, levels, internalformat, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, width, height, depth);
2584
2585 if (mTexStorage != NULL)
2586 {
2587 if (!mRenderer->copyToRenderTarget(newTexStorage, mTexStorage))
2588 {
2589 delete newTexStorage;
2590 return gl::error(GL_OUT_OF_MEMORY);
2591 }
2592 }
2593 }
2594
2595 delete mTexStorage;
2596 mTexStorage = newTexStorage;
2597
2598 mDirtyImages = true;
2599}
2600
Geoff Lang8040f572013-07-25 16:49:54 -04002601rx::RenderTarget *Texture2DArray::getRenderTarget(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002602{
Geoff Lang8040f572013-07-25 16:49:54 -04002603 // ensure the underlying texture is created
2604 if (getStorage(true) == NULL)
2605 {
2606 return NULL;
2607 }
2608
2609 updateTexture();
2610
2611 // ensure this is NOT a depth texture
2612 if (isDepth(level))
2613 {
2614 return NULL;
2615 }
2616
2617 return mTexStorage->getRenderTarget(level, layer);
2618}
2619
2620rx::RenderTarget *Texture2DArray::getDepthStencil(GLint level, GLint layer)
2621{
2622 // ensure the underlying texture is created
2623 if (getStorage(true) == NULL)
2624 {
2625 return NULL;
2626 }
2627
2628 updateTexture();
2629
2630 // ensure this is a depth texture
2631 if (!isDepth(level))
2632 {
2633 return NULL;
2634 }
2635
2636 return mTexStorage->getRenderTarget(level, layer);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002637}
2638
2639rx::TextureStorageInterface *Texture2DArray::getStorage(bool renderTarget)
2640{
2641 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
2642 {
2643 if (renderTarget)
2644 {
2645 convertToRenderTarget();
2646 }
2647 else
2648 {
2649 createTexture();
2650 }
2651 }
2652
2653 return mTexStorage;
2654}
2655
2656void Texture2DArray::redefineImage(GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth)
2657{
2658 // If there currently is a corresponding storage texture image, it has these parameters
Jamie Madilld3d2a342013-10-07 10:46:35 -04002659 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2660 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
2661 const int storageDepth = getBaseLevelDepth();
2662 const int storageFormat = getBaseLevelInternalFormat();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002663
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002664 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002665 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002666 delete mImageArray[level][layer];
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002667 }
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002668 delete[] mImageArray[level];
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002669
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002670 mImageArray[level] = new rx::Image*[depth]();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002671 mLayerCounts[level] = depth;
2672
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002673 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2674 {
2675 mImageArray[level][layer] = mRenderer->createImage();
2676 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, width, height, 1, false);
2677 }
2678
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002679 if (mTexStorage)
2680 {
2681 const int storageLevels = mTexStorage->levelCount();
2682
2683 if ((level >= storageLevels && storageLevels != 0) ||
2684 width != storageWidth ||
2685 height != storageHeight ||
2686 depth != storageDepth ||
2687 internalformat != storageFormat) // Discard mismatched storage
2688 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002689 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002690 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002691 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002692 {
2693 mImageArray[level][layer]->markDirty();
2694 }
2695 }
2696
2697 delete mTexStorage;
2698 mTexStorage = NULL;
2699 mDirtyImages = true;
2700 }
2701 }
2702}
2703
2704void Texture2DArray::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint layerTarget, GLsizei width, GLsizei height)
2705{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002706 if (level < levelCount() && layerTarget < getDepth(level))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002707 {
2708 rx::Image *image = mImageArray[level][layerTarget];
2709 if (image->updateSurface(mTexStorage, level, xoffset, yoffset, layerTarget, width, height))
2710 {
2711 image->markClean();
2712 }
2713 }
2714}
2715
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00002716}