blob: dc2e2d10d4d87b03f2dc305df1e58941aa46c871 [file] [log] [blame]
shannon.woods@transgaming.combdf2d802013-02-28 23:16:20 +00001#include "precompiled.h"
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00002//
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00003// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00004// Use of this source code is governed by a BSD-style license that can be
5// found in the LICENSE file.
6//
7
8// Texture.cpp: Implements the gl::Texture class and its derived classes
9// Texture2D and TextureCubeMap. Implements GL texture objects and related
10// functionality. [OpenGL ES 2.0.24] section 3.7 page 63.
11
12#include "libGLESv2/Texture.h"
13
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000014#include "libGLESv2/main.h"
shannonwoods@chromium.orga2ecfcc2013-05-30 00:11:59 +000015#include "common/mathutil.h"
16#include "common/utilities.h"
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +000017#include "libGLESv2/formatutils.h"
shannon.woods@transgaming.com486d9e92013-02-28 23:15:41 +000018#include "libGLESv2/Renderbuffer.h"
19#include "libGLESv2/renderer/Image.h"
20#include "libGLESv2/renderer/Renderer.h"
21#include "libGLESv2/renderer/TextureStorage.h"
22#include "libEGL/Surface.h"
Jamie Madill1beb1db2013-09-18 14:36:28 -040023#include "libGLESv2/Buffer.h"
24#include "libGLESv2/renderer/BufferStorage.h"
Jamie Madill0e0510f2013-10-10 15:46:23 -040025#include "libGLESv2/renderer/RenderTarget.h"
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000026
27namespace gl
28{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000029
Jamie Madillf8989902013-07-19 16:36:58 -040030bool IsMipmapFiltered(const SamplerState &samplerState)
31{
32 switch (samplerState.minFilter)
33 {
34 case GL_NEAREST:
35 case GL_LINEAR:
36 return false;
37 case GL_NEAREST_MIPMAP_NEAREST:
38 case GL_LINEAR_MIPMAP_NEAREST:
39 case GL_NEAREST_MIPMAP_LINEAR:
40 case GL_LINEAR_MIPMAP_LINEAR:
41 return true;
42 default: UNREACHABLE();
43 return false;
44 }
45}
46
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.
Jamie Madill0e0510f2013-10-10 15:46:23 -0400236 if (mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat))
Jamie Madill1beb1db2013-09-18 14:36:28 -0400237 {
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.com95a758f2012-07-12 15:17:06 +0000846 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Jamie Madilld3d2a342013-10-07 10:46:35 -0400847 unsigned int q = log2(std::max(getBaseLevelWidth(), getBaseLevelHeight()));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000848 for (unsigned int i = 1; i <= q; i++)
849 {
Jamie Madilld3d2a342013-10-07 10:46:35 -0400850 redefineImage(i, getBaseLevelInternalFormat(),
851 std::max(getBaseLevelWidth() >> i, 1),
852 std::max(getBaseLevelHeight() >> i, 1));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000853 }
854
855 if (mTexStorage && mTexStorage->isRenderTarget())
856 {
857 for (unsigned int i = 1; i <= q; i++)
858 {
daniel@transgaming.com0ad830b2012-10-31 19:52:12 +0000859 mTexStorage->generateMipmap(i);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000860
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000861 mImageArray[i]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000862 }
863 }
864 else
865 {
866 for (unsigned int i = 1; i <= q; i++)
867 {
daniel@transgaming.com4ba24062012-12-20 20:54:24 +0000868 mRenderer->generateMipmap(mImageArray[i], mImageArray[i - 1]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000869 }
870 }
871}
872
Jamie Madilld3d2a342013-10-07 10:46:35 -0400873const rx::Image *Texture2D::getBaseLevelImage() const
874{
875 return mImageArray[0];
876}
877
Geoff Lang8040f572013-07-25 16:49:54 -0400878Renderbuffer *Texture2D::getRenderbuffer(GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000879{
Geoff Lang8040f572013-07-25 16:49:54 -0400880 Renderbuffer *renderBuffer = mRenderbufferProxies.get(level, 0);
881 if (!renderBuffer)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000882 {
Geoff Lang8040f572013-07-25 16:49:54 -0400883 renderBuffer = new Renderbuffer(mRenderer, id(), new RenderbufferTexture2D(this, level));
884 mRenderbufferProxies.add(level, 0, renderBuffer);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000885 }
886
Geoff Lang8040f572013-07-25 16:49:54 -0400887 return renderBuffer;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000888}
889
Geoff Lang8040f572013-07-25 16:49:54 -0400890unsigned int Texture2D::getRenderTargetSerial(GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000891{
Geoff Lang8040f572013-07-25 16:49:54 -0400892 if (!mTexStorage || !mTexStorage->isRenderTarget())
893 {
894 convertToRenderTarget();
895 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000896
Geoff Lang8040f572013-07-25 16:49:54 -0400897 return mTexStorage ? mTexStorage->getRenderTargetSerial(level) : 0;
898}
899
900rx::RenderTarget *Texture2D::getRenderTarget(GLint level)
901{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000902 // ensure the underlying texture is created
903 if (getStorage(true) == NULL)
904 {
905 return NULL;
906 }
907
908 updateTexture();
Geoff Lang8040f572013-07-25 16:49:54 -0400909
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000910 // ensure this is NOT a depth texture
Geoff Lang8040f572013-07-25 16:49:54 -0400911 if (isDepth(level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000912 {
913 return NULL;
914 }
daniel@transgaming.com34da3972012-12-20 21:10:29 +0000915
Geoff Lang8040f572013-07-25 16:49:54 -0400916 return mTexStorage->getRenderTarget(level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000917}
918
Geoff Lang8040f572013-07-25 16:49:54 -0400919rx::RenderTarget *Texture2D::getDepthSencil(GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000920{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000921 // ensure the underlying texture is created
922 if (getStorage(true) == NULL)
923 {
924 return NULL;
925 }
926
927 updateTexture();
928
929 // ensure this is actually a depth texture
Geoff Lang8040f572013-07-25 16:49:54 -0400930 if (!isDepth(level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000931 {
932 return NULL;
933 }
Geoff Lang8040f572013-07-25 16:49:54 -0400934
935 return mTexStorage->getRenderTarget(level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000936}
937
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +0000938int Texture2D::levelCount()
939{
shannon.woods@transgaming.com5016f8e2013-02-28 23:20:57 +0000940 return mTexStorage ? mTexStorage->levelCount() : 0;
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +0000941}
942
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000943rx::TextureStorageInterface *Texture2D::getStorage(bool renderTarget)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000944{
945 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
946 {
947 if (renderTarget)
948 {
949 convertToRenderTarget();
950 }
951 else
952 {
953 createTexture();
954 }
955 }
956
957 return mTexStorage;
958}
959
Geoff Lang4907f2c2013-07-25 12:53:57 -0400960TextureCubeMap::TextureCubeMap(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_CUBE_MAP)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000961{
962 mTexStorage = NULL;
963 for (int i = 0; i < 6; i++)
964 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000965 for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
966 {
daniel@transgaming.com244e1832012-12-20 20:52:35 +0000967 mImageArray[i][j] = renderer->createImage();
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000968 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000969 }
970}
971
972TextureCubeMap::~TextureCubeMap()
973{
974 for (int i = 0; i < 6; i++)
975 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000976 for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
977 {
978 delete mImageArray[i][j];
979 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000980 }
981
982 delete mTexStorage;
983 mTexStorage = NULL;
984}
985
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000986GLsizei TextureCubeMap::getWidth(GLenum target, GLint level) const
987{
988 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000989 return mImageArray[faceIndex(target)][level]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000990 else
991 return 0;
992}
993
994GLsizei TextureCubeMap::getHeight(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]->getHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000998 else
999 return 0;
1000}
1001
1002GLenum TextureCubeMap::getInternalFormat(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]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001006 else
1007 return GL_NONE;
1008}
1009
daniel@transgaming.com20d36662012-10-31 19:51:43 +00001010GLenum TextureCubeMap::getActualFormat(GLenum target, GLint level) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001011{
1012 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001013 return mImageArray[faceIndex(target)][level]->getActualFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001014 else
1015 return D3DFMT_UNKNOWN;
1016}
1017
Jamie Madill88f18f42013-09-18 14:36:19 -04001018void 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 +00001019{
Jamie Madill88f18f42013-09-18 14:36:19 -04001020 setImage(0, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001021}
1022
Jamie Madill88f18f42013-09-18 14:36:19 -04001023void 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 +00001024{
Jamie Madill88f18f42013-09-18 14:36:19 -04001025 setImage(1, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001026}
1027
Jamie Madill88f18f42013-09-18 14:36:19 -04001028void 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 +00001029{
Jamie Madill88f18f42013-09-18 14:36:19 -04001030 setImage(2, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001031}
1032
Jamie Madill88f18f42013-09-18 14:36:19 -04001033void 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 +00001034{
Jamie Madill88f18f42013-09-18 14:36:19 -04001035 setImage(3, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001036}
1037
Jamie Madill88f18f42013-09-18 14:36:19 -04001038void 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 +00001039{
Jamie Madill88f18f42013-09-18 14:36:19 -04001040 setImage(4, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001041}
1042
Jamie Madill88f18f42013-09-18 14:36:19 -04001043void 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 +00001044{
Jamie Madill88f18f42013-09-18 14:36:19 -04001045 setImage(5, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001046}
1047
1048void TextureCubeMap::setCompressedImage(GLenum face, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
1049{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001050 // 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 +00001051 redefineImage(faceIndex(face), level, format, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001052
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001053 Texture::setCompressedImage(imageSize, pixels, mImageArray[faceIndex(face)][level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001054}
1055
1056void TextureCubeMap::commitRect(int face, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1057{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001058 if (level < levelCount())
1059 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001060 rx::Image *image = mImageArray[face][level];
daniel@transgaming.com0f195ad2012-10-31 19:51:59 +00001061 if (image->updateSurface(mTexStorage, face, level, xoffset, yoffset, width, height))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001062 image->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001063 }
1064}
1065
Jamie Madill88f18f42013-09-18 14:36:19 -04001066void 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 +00001067{
Jamie Madill88f18f42013-09-18 14:36:19 -04001068 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 +00001069 {
1070 commitRect(faceIndex(target), level, xoffset, yoffset, width, height);
1071 }
1072}
1073
1074void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1075{
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +00001076 if (Texture::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, 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
1082// Tests for cube map sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 86.
Jamie Madillf8989902013-07-19 16:36:58 -04001083bool TextureCubeMap::isSamplerComplete(const SamplerState &samplerState) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001084{
Jamie Madilld3d2a342013-10-07 10:46:35 -04001085 int size = getBaseLevelWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001086
Jamie Madillf8989902013-07-19 16:36:58 -04001087 bool mipmapping = IsMipmapFiltered(samplerState);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001088
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001089 if (!IsTextureFilteringSupported(getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0), mRenderer))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001090 {
Jamie Madillf8989902013-07-19 16:36:58 -04001091 if (samplerState.magFilter != GL_NEAREST ||
1092 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001093 {
1094 return false;
1095 }
1096 }
1097
daniel@transgaming.comea32d482012-11-28 19:33:18 +00001098 if (!isPow2(size) && !mRenderer->getNonPower2TextureSupport())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001099 {
Jamie Madillf8989902013-07-19 16:36:58 -04001100 if (samplerState.wrapS != GL_CLAMP_TO_EDGE || samplerState.wrapT != GL_CLAMP_TO_EDGE || mipmapping)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001101 {
1102 return false;
1103 }
1104 }
1105
1106 if (!mipmapping)
1107 {
1108 if (!isCubeComplete())
1109 {
1110 return false;
1111 }
1112 }
1113 else
1114 {
1115 if (!isMipmapCubeComplete()) // Also tests for isCubeComplete()
1116 {
1117 return false;
1118 }
1119 }
1120
1121 return true;
1122}
1123
1124// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1125bool TextureCubeMap::isCubeComplete() const
1126{
Jamie Madillc1f8b162013-10-07 10:46:38 -04001127 int baseWidth = getBaseLevelWidth();
1128 int baseHeight = getBaseLevelHeight();
1129 GLenum baseFormat = getBaseLevelInternalFormat();
1130
1131 if (baseWidth <= 0 || baseWidth != baseHeight)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001132 {
1133 return false;
1134 }
1135
1136 for (unsigned int face = 1; face < 6; face++)
1137 {
Jamie Madillc1f8b162013-10-07 10:46:38 -04001138 const rx::Image &faceBaseImage = *mImageArray[face][0];
1139
1140 if (faceBaseImage.getWidth() != baseWidth ||
1141 faceBaseImage.getHeight() != baseHeight ||
1142 faceBaseImage.getInternalFormat() != baseFormat )
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001143 {
1144 return false;
1145 }
1146 }
1147
1148 return true;
1149}
1150
1151bool TextureCubeMap::isMipmapCubeComplete() const
1152{
1153 if (isImmutable())
1154 {
1155 return true;
1156 }
1157
1158 if (!isCubeComplete())
1159 {
1160 return false;
1161 }
1162
Jamie Madilld3d2a342013-10-07 10:46:35 -04001163 GLsizei size = getBaseLevelWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001164 int q = log2(size);
1165
1166 for (int face = 0; face < 6; face++)
1167 {
1168 for (int level = 1; level <= q; level++)
1169 {
Jamie Madill07edd442013-07-19 16:36:58 -04001170 if (!isFaceLevelComplete(face, level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001171 {
1172 return false;
1173 }
1174 }
1175 }
1176
1177 return true;
1178}
1179
Jamie Madill07edd442013-07-19 16:36:58 -04001180bool TextureCubeMap::isFaceLevelComplete(int face, int level) const
1181{
1182 ASSERT(level >= 0 && face < 6 && level < (int)ArraySize(mImageArray[face]) && mImageArray[face][level] != NULL);
1183
1184 if (isImmutable())
1185 {
1186 return true;
1187 }
1188
Jamie Madilld3d2a342013-10-07 10:46:35 -04001189 int baseSize = getBaseLevelWidth();
Jamie Madill07edd442013-07-19 16:36:58 -04001190
Jamie Madilld3d2a342013-10-07 10:46:35 -04001191 if (baseSize <= 0)
Jamie Madill07edd442013-07-19 16:36:58 -04001192 {
1193 return false;
1194 }
1195
Jamie Madilld3d2a342013-10-07 10:46:35 -04001196 // "isCubeComplete" checks for base level completeness and we must call that
1197 // to determine if any face at level 0 is complete. We omit that check here
1198 // to avoid re-checking cube-completeness for every face at level 0.
Jamie Madill07edd442013-07-19 16:36:58 -04001199 if (level == 0)
1200 {
1201 return true;
1202 }
1203
Jamie Madilld3d2a342013-10-07 10:46:35 -04001204 // Check that non-zero levels are consistent with the base level.
1205 const rx::Image *faceLevelImage = mImageArray[face][level];
Jamie Madill07edd442013-07-19 16:36:58 -04001206
Jamie Madilld3d2a342013-10-07 10:46:35 -04001207 if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat())
Jamie Madill07edd442013-07-19 16:36:58 -04001208 {
1209 return false;
1210 }
1211
Jamie Madilld3d2a342013-10-07 10:46:35 -04001212 if (faceLevelImage->getWidth() != std::max(1, baseSize >> level))
Jamie Madill07edd442013-07-19 16:36:58 -04001213 {
1214 return false;
1215 }
1216
1217 return true;
1218}
1219
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001220bool TextureCubeMap::isCompressed(GLenum target, GLint level) const
1221{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001222 return IsFormatCompressed(getInternalFormat(target, level), mRenderer->getCurrentClientVersion());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001223}
1224
Geoff Lang8040f572013-07-25 16:49:54 -04001225bool TextureCubeMap::isDepth(GLenum target, GLint level) const
1226{
1227 return GetDepthBits(getInternalFormat(target, level), mRenderer->getCurrentClientVersion()) > 0;
1228}
1229
daniel@transgaming.comf032cb82012-10-31 19:51:52 +00001230// Constructs a native texture resource from the texture images, or returns an existing one
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001231void TextureCubeMap::createTexture()
1232{
Jamie Madilld3d2a342013-10-07 10:46:35 -04001233 GLsizei size = getBaseLevelWidth();
daniel@transgaming.come6a09842012-09-17 21:28:55 +00001234
1235 if (!(size > 0))
daniel@transgaming.comf032cb82012-10-31 19:51:52 +00001236 return; // do not attempt to create native textures for nonexistant data
daniel@transgaming.come6a09842012-09-17 21:28:55 +00001237
sminns@adobe.comce1189b2012-09-18 20:06:35 +00001238 GLint levels = creationLevels(size);
Jamie Madilld3d2a342013-10-07 10:46:35 -04001239 GLenum internalformat = getBaseLevelInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001240
1241 delete mTexStorage;
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001242 mTexStorage = new rx::TextureStorageInterfaceCube(mRenderer, levels, internalformat, mUsage, false, size);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001243
1244 if (mTexStorage->isManaged())
1245 {
1246 int levels = levelCount();
1247
1248 for (int face = 0; face < 6; face++)
1249 {
1250 for (int level = 0; level < levels; level++)
1251 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001252 mImageArray[face][level]->setManagedSurface(mTexStorage, face, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001253 }
1254 }
1255 }
1256
1257 mDirtyImages = true;
1258}
1259
1260void TextureCubeMap::updateTexture()
1261{
Jamie Madilleb3665c2013-07-19 16:36:57 -04001262 int levels = (isMipmapCubeComplete() ? levelCount() : 1);
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +00001263
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001264 for (int face = 0; face < 6; face++)
1265 {
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001266 for (int level = 0; level < levels; level++)
1267 {
Jamie Madill07edd442013-07-19 16:36:58 -04001268 updateTextureFaceLevel(face, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001269 }
1270 }
1271}
1272
Jamie Madill07edd442013-07-19 16:36:58 -04001273void TextureCubeMap::updateTextureFaceLevel(int face, int level)
1274{
1275 ASSERT(level >= 0 && face < 6 && level < (int)ArraySize(mImageArray[face]) && mImageArray[face][level] != NULL);
1276 rx::Image *image = mImageArray[face][level];
1277
1278 if (image->isDirty())
1279 {
1280 commitRect(face, level, 0, 0, image->getWidth(), image->getHeight());
1281 }
1282}
1283
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001284void TextureCubeMap::convertToRenderTarget()
1285{
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001286 rx::TextureStorageInterfaceCube *newTexStorage = NULL;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001287
Jamie Madilld3d2a342013-10-07 10:46:35 -04001288 if (getBaseLevelWidth() != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001289 {
Jamie Madilld3d2a342013-10-07 10:46:35 -04001290 GLsizei size = getBaseLevelWidth();
shannon.woods@transgaming.com6bb48862013-02-28 23:09:34 +00001291 GLint levels = mTexStorage != NULL ? mTexStorage->levelCount() : creationLevels(size);
Jamie Madilld3d2a342013-10-07 10:46:35 -04001292 GLenum internalformat = getBaseLevelInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001293
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001294 newTexStorage = new rx::TextureStorageInterfaceCube(mRenderer, levels, internalformat, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, true, size);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001295
1296 if (mTexStorage != NULL)
1297 {
daniel@transgaming.com1d80eee2012-11-28 19:33:31 +00001298 if (!mRenderer->copyToRenderTarget(newTexStorage, mTexStorage))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001299 {
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +00001300 delete newTexStorage;
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +00001301 return gl::error(GL_OUT_OF_MEMORY);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001302 }
1303 }
1304 }
1305
1306 delete mTexStorage;
1307 mTexStorage = newTexStorage;
1308
1309 mDirtyImages = true;
1310}
1311
Jamie Madill88f18f42013-09-18 14:36:19 -04001312void 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 +00001313{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001314 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1315 GLint sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
1316 : GetSizedInternalFormat(format, type, clientVersion);
1317
1318 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001319
Jamie Madill88f18f42013-09-18 14:36:19 -04001320 Texture::setImage(unpack, type, pixels, mImageArray[faceIndex][level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001321}
1322
1323unsigned int TextureCubeMap::faceIndex(GLenum face)
1324{
1325 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
1326 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
1327 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
1328 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
1329 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
1330
1331 return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
1332}
1333
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001334void TextureCubeMap::redefineImage(int face, GLint level, GLint internalformat, GLsizei width, GLsizei height)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001335{
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001336 // If there currently is a corresponding storage texture image, it has these parameters
Jamie Madilld3d2a342013-10-07 10:46:35 -04001337 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1338 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1339 const int storageFormat = getBaseLevelInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001340
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001341 mImageArray[face][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, width, height, 1, false);
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001342
1343 if (mTexStorage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001344 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001345 const int storageLevels = mTexStorage->levelCount();
1346
1347 if ((level >= storageLevels && storageLevels != 0) ||
1348 width != storageWidth ||
1349 height != storageHeight ||
1350 internalformat != storageFormat) // Discard mismatched storage
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001351 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001352 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001353 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001354 for (int f = 0; f < 6; f++)
1355 {
1356 mImageArray[f][i]->markDirty();
1357 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001358 }
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001359
1360 delete mTexStorage;
1361 mTexStorage = NULL;
1362
1363 mDirtyImages = true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001364 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001365 }
1366}
1367
1368void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1369{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001370 unsigned int faceindex = faceIndex(target);
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001371 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1372 GLint sizedInternalFormat = IsSizedInternalFormat(format, clientVersion) ? format
1373 : GetSizedInternalFormat(format, GL_UNSIGNED_BYTE, clientVersion);
1374 redefineImage(faceindex, level, sizedInternalFormat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001375
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001376 if (!mImageArray[faceindex][level]->isRenderableFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001377 {
shannon.woods%transgaming.com@gtempaccount.come5dcce72013-04-13 03:44:33 +00001378 mImageArray[faceindex][level]->copy(0, 0, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001379 mDirtyImages = true;
1380 }
1381 else
1382 {
1383 if (!mTexStorage || !mTexStorage->isRenderTarget())
1384 {
1385 convertToRenderTarget();
1386 }
1387
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001388 mImageArray[faceindex][level]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001389
1390 ASSERT(width == height);
1391
1392 if (width > 0 && level < levelCount())
1393 {
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +00001394 gl::Rectangle sourceRect;
1395 sourceRect.x = x;
1396 sourceRect.width = width;
1397 sourceRect.y = y;
1398 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001399
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +00001400 mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001401 }
1402 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001403}
1404
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001405void 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 +00001406{
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001407 GLsizei size = mImageArray[faceIndex(target)][level]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001408
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001409 if (xoffset + width > size || yoffset + height > size || zoffset != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001410 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +00001411 return gl::error(GL_INVALID_VALUE);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001412 }
1413
Jamie Madill07edd442013-07-19 16:36:58 -04001414 unsigned int face = faceIndex(target);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001415
Jamie Madilld3d2a342013-10-07 10:46:35 -04001416 // We can only make our texture storage to a render target if the level we're copying *to* is complete
1417 // and the base level is cube-complete. The base level must be cube complete (common case) because we cannot
1418 // rely on the "getBaseLevel*" methods reliably otherwise.
1419 bool canCreateRenderTarget = isFaceLevelComplete(face, level) && isCubeComplete();
Jamie Madill07edd442013-07-19 16:36:58 -04001420
1421 if (!mImageArray[face][level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001422 {
Jamie Madill07edd442013-07-19 16:36:58 -04001423 mImageArray[face][level]->copy(0, 0, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001424 mDirtyImages = true;
1425 }
1426 else
1427 {
1428 if (!mTexStorage || !mTexStorage->isRenderTarget())
1429 {
1430 convertToRenderTarget();
1431 }
1432
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001433 if (level < levelCount())
1434 {
Jamie Madill07edd442013-07-19 16:36:58 -04001435 updateTextureFaceLevel(face, level);
1436
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001437 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1438
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +00001439 gl::Rectangle sourceRect;
1440 sourceRect.x = x;
1441 sourceRect.width = width;
1442 sourceRect.y = y;
1443 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001444
Jamie Madilld3d2a342013-10-07 10:46:35 -04001445 mRenderer->copyImage(source, sourceRect, gl::GetFormat(getBaseLevelInternalFormat(), clientVersion),
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +00001446 xoffset, yoffset, mTexStorage, target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001447 }
1448 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001449}
1450
1451void TextureCubeMap::storage(GLsizei levels, GLenum internalformat, GLsizei size)
1452{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001453 delete mTexStorage;
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001454 mTexStorage = new rx::TextureStorageInterfaceCube(mRenderer, levels, internalformat, mUsage, false, size);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001455 mImmutable = true;
1456
1457 for (int level = 0; level < levels; level++)
1458 {
Geoff Langd3110192013-09-24 11:52:47 -04001459 GLsizei mipSize = std::max(1, size >> level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001460 for (int face = 0; face < 6; face++)
1461 {
Geoff Langd3110192013-09-24 11:52:47 -04001462 mImageArray[face][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, mipSize, mipSize, 1, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001463 }
1464 }
1465
1466 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1467 {
1468 for (int face = 0; face < 6; face++)
1469 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001470 mImageArray[face][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, GL_NONE, 0, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001471 }
1472 }
1473
1474 if (mTexStorage->isManaged())
1475 {
1476 int levels = levelCount();
1477
1478 for (int face = 0; face < 6; face++)
1479 {
1480 for (int level = 0; level < levels; level++)
1481 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001482 mImageArray[face][level]->setManagedSurface(mTexStorage, face, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001483 }
1484 }
1485 }
1486}
1487
1488void TextureCubeMap::generateMipmaps()
1489{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001490 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Jamie Madilld3d2a342013-10-07 10:46:35 -04001491 unsigned int q = log2(getBaseLevelWidth());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001492 for (unsigned int f = 0; f < 6; f++)
1493 {
1494 for (unsigned int i = 1; i <= q; i++)
1495 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001496 redefineImage(f, i, mImageArray[f][0]->getInternalFormat(),
shannon.woods@transgaming.com8a406682013-02-28 23:15:26 +00001497 std::max(mImageArray[f][0]->getWidth() >> i, 1),
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001498 std::max(mImageArray[f][0]->getWidth() >> i, 1));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001499 }
1500 }
1501
1502 if (mTexStorage && mTexStorage->isRenderTarget())
1503 {
1504 for (unsigned int f = 0; f < 6; f++)
1505 {
1506 for (unsigned int i = 1; i <= q; i++)
1507 {
daniel@transgaming.com0ad830b2012-10-31 19:52:12 +00001508 mTexStorage->generateMipmap(f, i);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001509
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001510 mImageArray[f][i]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001511 }
1512 }
1513 }
1514 else
1515 {
1516 for (unsigned int f = 0; f < 6; f++)
1517 {
1518 for (unsigned int i = 1; i <= q; i++)
1519 {
daniel@transgaming.com4ba24062012-12-20 20:54:24 +00001520 mRenderer->generateMipmap(mImageArray[f][i], mImageArray[f][i - 1]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001521 }
1522 }
1523 }
1524}
1525
Jamie Madilld3d2a342013-10-07 10:46:35 -04001526const rx::Image *TextureCubeMap::getBaseLevelImage() const
1527{
1528 // Note: if we are not cube-complete, there is no single base level image that can describe all
1529 // cube faces, so this method is only well-defined for a cube-complete base level.
1530 return mImageArray[0][0];
1531}
1532
Geoff Lang8040f572013-07-25 16:49:54 -04001533Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target, GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001534{
1535 if (!IsCubemapTextureTarget(target))
1536 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +00001537 return gl::error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001538 }
1539
1540 unsigned int face = faceIndex(target);
1541
Geoff Lang8040f572013-07-25 16:49:54 -04001542 Renderbuffer *renderBuffer = mRenderbufferProxies.get(level, face);
1543 if (!renderBuffer)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001544 {
Geoff Lang8040f572013-07-25 16:49:54 -04001545 renderBuffer = new Renderbuffer(mRenderer, id(), new RenderbufferTextureCubeMap(this, target, level));
1546 mRenderbufferProxies.add(level, face, renderBuffer);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001547 }
1548
Geoff Lang8040f572013-07-25 16:49:54 -04001549 return renderBuffer;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001550}
1551
Geoff Lang8040f572013-07-25 16:49:54 -04001552unsigned int TextureCubeMap::getRenderTargetSerial(GLenum faceTarget, GLint level)
1553{
1554 if (!mTexStorage || !mTexStorage->isRenderTarget())
1555 {
1556 convertToRenderTarget();
1557 }
1558
1559 return mTexStorage ? mTexStorage->getRenderTargetSerial(faceTarget, level) : 0;
1560}
1561
1562rx::RenderTarget *TextureCubeMap::getRenderTarget(GLenum target, GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001563{
1564 ASSERT(IsCubemapTextureTarget(target));
1565
1566 // ensure the underlying texture is created
1567 if (getStorage(true) == NULL)
1568 {
1569 return NULL;
1570 }
1571
1572 updateTexture();
Geoff Lang8040f572013-07-25 16:49:54 -04001573
1574 // ensure this is NOT a depth texture
1575 if (isDepth(target, level))
1576 {
1577 return NULL;
1578 }
1579
1580 return mTexStorage->getRenderTarget(target, level);
1581}
1582
1583rx::RenderTarget *TextureCubeMap::getDepthStencil(GLenum target, GLint level)
1584{
1585 ASSERT(IsCubemapTextureTarget(target));
1586
1587 // ensure the underlying texture is created
1588 if (getStorage(true) == NULL)
1589 {
1590 return NULL;
1591 }
1592
1593 updateTexture();
1594
1595 // ensure this is a depth texture
1596 if (!isDepth(target, level))
1597 {
1598 return NULL;
1599 }
1600
1601 return mTexStorage->getRenderTarget(target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001602}
1603
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +00001604int TextureCubeMap::levelCount()
1605{
1606 return mTexStorage ? mTexStorage->levelCount() - getLodOffset() : 0;
1607}
1608
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001609rx::TextureStorageInterface *TextureCubeMap::getStorage(bool renderTarget)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001610{
1611 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
1612 {
1613 if (renderTarget)
1614 {
1615 convertToRenderTarget();
1616 }
1617 else
1618 {
1619 createTexture();
1620 }
1621 }
1622
1623 return mTexStorage;
1624}
1625
Geoff Lang4907f2c2013-07-25 12:53:57 -04001626Texture3D::Texture3D(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_3D)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001627{
1628 mTexStorage = NULL;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001629
1630 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1631 {
1632 mImageArray[i] = renderer->createImage();
1633 }
1634}
1635
1636Texture3D::~Texture3D()
1637{
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001638 delete mTexStorage;
1639 mTexStorage = NULL;
1640
1641 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1642 {
1643 delete mImageArray[i];
1644 }
1645}
1646
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001647GLsizei Texture3D::getWidth(GLint level) const
1648{
1649 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getWidth() : 0;
1650}
1651
1652GLsizei Texture3D::getHeight(GLint level) const
1653{
1654 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getHeight() : 0;
1655}
1656
1657GLsizei Texture3D::getDepth(GLint level) const
1658{
1659 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getDepth() : 0;
1660}
1661
1662GLenum Texture3D::getInternalFormat(GLint level) const
1663{
1664 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getInternalFormat() : GL_NONE;
1665}
1666
1667GLenum Texture3D::getActualFormat(GLint level) const
1668{
1669 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getActualFormat() : D3DFMT_UNKNOWN;
1670}
1671
1672bool Texture3D::isCompressed(GLint level) const
1673{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001674 return IsFormatCompressed(getInternalFormat(level), mRenderer->getCurrentClientVersion());
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001675}
1676
1677bool Texture3D::isDepth(GLint level) const
1678{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001679 return GetDepthBits(getInternalFormat(level), mRenderer->getCurrentClientVersion()) > 0;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001680}
1681
Jamie Madill88f18f42013-09-18 14:36:19 -04001682void 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 +00001683{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001684 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1685 GLint sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
1686 : GetSizedInternalFormat(format, type, clientVersion);
1687 redefineImage(level, sizedInternalFormat, width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001688
Jamie Madill88f18f42013-09-18 14:36:19 -04001689 Texture::setImage(unpack, type, pixels, mImageArray[level]);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001690}
1691
1692void Texture3D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
1693{
1694 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1695 redefineImage(level, format, width, height, depth);
1696
1697 Texture::setCompressedImage(imageSize, pixels, mImageArray[level]);
1698}
1699
Jamie Madill88f18f42013-09-18 14:36:19 -04001700void 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 +00001701{
Jamie Madill88f18f42013-09-18 14:36:19 -04001702 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 +00001703 {
1704 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1705 }
1706}
1707
1708void Texture3D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
1709{
1710 if (Texture::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth, format, imageSize, pixels, mImageArray[level]))
1711 {
1712 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1713 }
1714}
1715
1716void Texture3D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
1717{
1718 delete mTexStorage;
1719 mTexStorage = new rx::TextureStorageInterface3D(mRenderer, levels, internalformat, mUsage, width, height, depth);
1720 mImmutable = true;
1721
1722 for (int level = 0; level < levels; level++)
1723 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001724 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, true);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001725 width = std::max(1, width >> 1);
1726 height = std::max(1, height >> 1);
1727 depth = std::max(1, depth >> 1);
1728 }
1729
1730 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1731 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001732 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, GL_NONE, 0, 0, 0, true);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001733 }
1734
1735 if (mTexStorage->isManaged())
1736 {
1737 int levels = levelCount();
1738
1739 for (int level = 0; level < levels; level++)
1740 {
1741 mImageArray[level]->setManagedSurface(mTexStorage, level);
1742 }
1743 }
1744}
1745
1746
1747void Texture3D::generateMipmaps()
1748{
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001749 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Jamie Madilld3d2a342013-10-07 10:46:35 -04001750 unsigned int q = log2(std::max(getBaseLevelWidth(), getBaseLevelHeight()));
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001751 for (unsigned int i = 1; i <= q; i++)
1752 {
Jamie Madilld3d2a342013-10-07 10:46:35 -04001753 redefineImage(i, getBaseLevelInternalFormat(),
1754 std::max(getBaseLevelWidth() >> i, 1),
1755 std::max(getBaseLevelHeight() >> i, 1),
1756 std::max(getBaseLevelDepth() >> i, 1));
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001757 }
1758
1759 if (mTexStorage && mTexStorage->isRenderTarget())
1760 {
1761 for (unsigned int i = 1; i <= q; i++)
1762 {
1763 mTexStorage->generateMipmap(i);
1764
1765 mImageArray[i]->markClean();
1766 }
1767 }
1768 else
1769 {
1770 for (unsigned int i = 1; i <= q; i++)
1771 {
1772 mRenderer->generateMipmap(mImageArray[i], mImageArray[i - 1]);
1773 }
1774 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001775}
1776
Jamie Madilld3d2a342013-10-07 10:46:35 -04001777const rx::Image *Texture3D::getBaseLevelImage() const
1778{
1779 return mImageArray[0];
1780}
1781
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001782void Texture3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1783{
1784 if (xoffset + width > mImageArray[level]->getWidth() || yoffset + height > mImageArray[level]->getHeight() || zoffset >= mImageArray[level]->getDepth())
1785 {
1786 return gl::error(GL_INVALID_VALUE);
1787 }
1788
Jamie Madill07edd442013-07-19 16:36:58 -04001789 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
1790 // the current level we're copying to is defined (with appropriate format, width & height)
1791 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
1792
1793 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001794 {
1795 mImageArray[level]->copy(xoffset, yoffset, zoffset, x, y, width, height, source);
1796 mDirtyImages = true;
1797 }
1798 else
1799 {
1800 if (!mTexStorage || !mTexStorage->isRenderTarget())
1801 {
1802 convertToRenderTarget();
1803 }
1804
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001805 if (level < levelCount())
1806 {
Jamie Madill07edd442013-07-19 16:36:58 -04001807 updateTextureLevel(level);
1808
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001809 gl::Rectangle sourceRect;
1810 sourceRect.x = x;
1811 sourceRect.width = width;
1812 sourceRect.y = y;
1813 sourceRect.height = height;
1814
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001815 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1816
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001817 mRenderer->copyImage(source, sourceRect,
Jamie Madilld3d2a342013-10-07 10:46:35 -04001818 gl::GetFormat(getBaseLevelInternalFormat(), clientVersion),
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001819 xoffset, yoffset, zoffset, mTexStorage, level);
1820 }
1821 }
1822}
1823
Jamie Madillf8989902013-07-19 16:36:58 -04001824bool Texture3D::isSamplerComplete(const SamplerState &samplerState) const
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001825{
Jamie Madilld3d2a342013-10-07 10:46:35 -04001826 GLsizei width = getBaseLevelWidth();
1827 GLsizei height = getBaseLevelHeight();
1828 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001829
1830 if (width <= 0 || height <= 0 || depth <= 0)
1831 {
1832 return false;
1833 }
1834
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001835 if (!IsTextureFilteringSupported(getInternalFormat(0), mRenderer))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001836 {
Jamie Madillf8989902013-07-19 16:36:58 -04001837 if (samplerState.magFilter != GL_NEAREST ||
1838 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001839 {
1840 return false;
1841 }
1842 }
1843
Jamie Madillf8989902013-07-19 16:36:58 -04001844 if (IsMipmapFiltered(samplerState) && !isMipmapComplete())
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001845 {
1846 return false;
1847 }
1848
1849 return true;
1850}
1851
1852bool Texture3D::isMipmapComplete() const
1853{
Jamie Madilld3d2a342013-10-07 10:46:35 -04001854 GLsizei width = getBaseLevelWidth();
1855 GLsizei height = getBaseLevelHeight();
1856 GLsizei depth = getBaseLevelDepth();
Jamie Madill07edd442013-07-19 16:36:58 -04001857
1858 int q = log2(std::max(std::max(width, height), depth));
1859
1860 for (int level = 0; level <= q; level++)
1861 {
1862 if (!isLevelComplete(level))
1863 {
1864 return false;
1865 }
1866 }
1867
1868 return true;
1869}
1870
1871bool Texture3D::isLevelComplete(int level) const
1872{
1873 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1874
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001875 if (isImmutable())
1876 {
1877 return true;
1878 }
1879
Jamie Madilld3d2a342013-10-07 10:46:35 -04001880 GLsizei width = getBaseLevelWidth();
1881 GLsizei height = getBaseLevelHeight();
1882 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001883
1884 if (width <= 0 || height <= 0 || depth <= 0)
1885 {
1886 return false;
1887 }
1888
Jamie Madill07edd442013-07-19 16:36:58 -04001889 if (level == 0)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001890 {
Jamie Madill07edd442013-07-19 16:36:58 -04001891 return true;
1892 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001893
Jamie Madill07edd442013-07-19 16:36:58 -04001894 rx::Image *levelImage = mImageArray[level];
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001895
Jamie Madilld3d2a342013-10-07 10:46:35 -04001896 if (levelImage->getInternalFormat() != getBaseLevelInternalFormat())
Jamie Madill07edd442013-07-19 16:36:58 -04001897 {
1898 return false;
1899 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001900
Jamie Madill07edd442013-07-19 16:36:58 -04001901 if (levelImage->getWidth() != std::max(1, width >> level))
1902 {
1903 return false;
1904 }
1905
1906 if (levelImage->getHeight() != std::max(1, height >> level))
1907 {
1908 return false;
1909 }
1910
1911 if (levelImage->getDepth() != std::max(1, depth >> level))
1912 {
1913 return false;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001914 }
1915
1916 return true;
1917}
1918
Geoff Lang8040f572013-07-25 16:49:54 -04001919Renderbuffer *Texture3D::getRenderbuffer(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001920{
Geoff Lang8040f572013-07-25 16:49:54 -04001921 Renderbuffer *renderBuffer = mRenderbufferProxies.get(level, layer);
1922 if (!renderBuffer)
1923 {
Geoff Langd5d8e392013-07-25 16:53:03 -04001924 renderBuffer = new Renderbuffer(mRenderer, id(), new RenderbufferTexture3DLayer(this, level, layer));
1925 mRenderbufferProxies.add(level, 0, renderBuffer);
Geoff Lang8040f572013-07-25 16:49:54 -04001926 }
1927
1928 return renderBuffer;
1929}
1930
1931unsigned int Texture3D::getRenderTargetSerial(GLint level, GLint layer)
1932{
1933 if (!mTexStorage || !mTexStorage->isRenderTarget())
1934 {
1935 convertToRenderTarget();
1936 }
1937
1938 return mTexStorage ? mTexStorage->getRenderTargetSerial(level, layer) : 0;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001939}
1940
1941int Texture3D::levelCount()
1942{
1943 return mTexStorage ? mTexStorage->levelCount() : 0;
1944}
1945
1946void Texture3D::createTexture()
1947{
Jamie Madilld3d2a342013-10-07 10:46:35 -04001948 GLsizei width = getBaseLevelWidth();
1949 GLsizei height = getBaseLevelHeight();
1950 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001951
1952 if (!(width > 0 && height > 0 && depth > 0))
1953 return; // do not attempt to create native textures for nonexistant data
1954
1955 GLint levels = creationLevels(width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001956
1957 delete mTexStorage;
Jamie Madilld3d2a342013-10-07 10:46:35 -04001958 mTexStorage = new rx::TextureStorageInterface3D(mRenderer, levels, getBaseLevelInternalFormat(), mUsage, width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001959
1960 if (mTexStorage->isManaged())
1961 {
1962 int levels = levelCount();
1963
1964 for (int level = 0; level < levels; level++)
1965 {
1966 mImageArray[level]->setManagedSurface(mTexStorage, level);
1967 }
1968 }
1969
1970 mDirtyImages = true;
1971}
1972
1973void Texture3D::updateTexture()
1974{
Jamie Madilleb3665c2013-07-19 16:36:57 -04001975 int levels = (isMipmapComplete() ? levelCount() : 1);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001976
1977 for (int level = 0; level < levels; level++)
1978 {
Jamie Madill07edd442013-07-19 16:36:58 -04001979 updateTextureLevel(level);
1980 }
1981}
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001982
Jamie Madill07edd442013-07-19 16:36:58 -04001983void Texture3D::updateTextureLevel(int level)
1984{
1985 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1986
1987 rx::Image *image = mImageArray[level];
1988
1989 if (image->isDirty())
1990 {
1991 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 +00001992 }
1993}
1994
1995void Texture3D::convertToRenderTarget()
1996{
1997 rx::TextureStorageInterface3D *newTexStorage = NULL;
1998
Jamie Madilld3d2a342013-10-07 10:46:35 -04001999 if (getBaseLevelWidth() != 0 && getBaseLevelHeight() != 0 && getBaseLevelDepth() != 0)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002000 {
Jamie Madilld3d2a342013-10-07 10:46:35 -04002001 GLsizei width = getBaseLevelWidth();
2002 GLsizei height = getBaseLevelHeight();
2003 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002004 GLint levels = mTexStorage != NULL ? mTexStorage->levelCount() : creationLevels(width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002005
Jamie Madilld3d2a342013-10-07 10:46:35 -04002006 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 +00002007
2008 if (mTexStorage != NULL)
2009 {
2010 if (!mRenderer->copyToRenderTarget(newTexStorage, mTexStorage))
2011 {
2012 delete newTexStorage;
2013 return gl::error(GL_OUT_OF_MEMORY);
2014 }
2015 }
2016 }
2017
2018 delete mTexStorage;
2019 mTexStorage = newTexStorage;
2020
2021 mDirtyImages = true;
2022}
2023
Geoff Lang8040f572013-07-25 16:49:54 -04002024rx::RenderTarget *Texture3D::getRenderTarget(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002025{
Geoff Lang8040f572013-07-25 16:49:54 -04002026 // ensure the underlying texture is created
2027 if (getStorage(true) == NULL)
2028 {
2029 return NULL;
2030 }
2031
2032 updateTexture();
2033
2034 // ensure this is NOT a depth texture
2035 if (isDepth(level))
2036 {
2037 return NULL;
2038 }
2039
2040 return mTexStorage->getRenderTarget(level, layer);
2041}
2042
2043rx::RenderTarget *Texture3D::getDepthStencil(GLint level, GLint layer)
2044{
2045 // ensure the underlying texture is created
2046 if (getStorage(true) == NULL)
2047 {
2048 return NULL;
2049 }
2050
2051 updateTexture();
2052
2053 // ensure this is a depth texture
2054 if (!isDepth(level))
2055 {
2056 return NULL;
2057 }
2058
2059 return mTexStorage->getRenderTarget(level, layer);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002060}
2061
2062rx::TextureStorageInterface *Texture3D::getStorage(bool renderTarget)
2063{
2064 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
2065 {
2066 if (renderTarget)
2067 {
2068 convertToRenderTarget();
2069 }
2070 else
2071 {
2072 createTexture();
2073 }
2074 }
2075
2076 return mTexStorage;
2077}
2078
2079void Texture3D::redefineImage(GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth)
2080{
2081 // If there currently is a corresponding storage texture image, it has these parameters
Jamie Madilld3d2a342013-10-07 10:46:35 -04002082 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2083 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
2084 const int storageDepth = std::max(1, getBaseLevelDepth() >> level);
2085 const int storageFormat = getBaseLevelInternalFormat();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002086
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00002087 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, false);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002088
2089 if (mTexStorage)
2090 {
2091 const int storageLevels = mTexStorage->levelCount();
2092
2093 if ((level >= storageLevels && storageLevels != 0) ||
2094 width != storageWidth ||
2095 height != storageHeight ||
2096 depth != storageDepth ||
2097 internalformat != storageFormat) // Discard mismatched storage
2098 {
2099 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
2100 {
2101 mImageArray[i]->markDirty();
2102 }
2103
2104 delete mTexStorage;
2105 mTexStorage = NULL;
2106 mDirtyImages = true;
2107 }
2108 }
2109}
2110
2111void Texture3D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth)
2112{
2113 if (level < levelCount())
2114 {
2115 rx::Image *image = mImageArray[level];
2116 if (image->updateSurface(mTexStorage, level, xoffset, yoffset, zoffset, width, height, depth))
2117 {
2118 image->markClean();
2119 }
2120 }
2121}
2122
Geoff Lang4907f2c2013-07-25 12:53:57 -04002123Texture2DArray::Texture2DArray(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_2D_ARRAY)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002124{
2125 mTexStorage = NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002126
2127 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2128 {
2129 mLayerCounts[level] = 0;
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002130 mImageArray[level] = NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002131 }
2132}
2133
2134Texture2DArray::~Texture2DArray()
2135{
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002136 delete mTexStorage;
2137 mTexStorage = NULL;
2138 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2139 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002140 for (int layer = 0; layer < mLayerCounts[level]; ++layer)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002141 {
2142 delete mImageArray[level][layer];
2143 }
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002144 delete[] mImageArray[level];
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002145 }
2146}
2147
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002148GLsizei Texture2DArray::getWidth(GLint level) const
2149{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002150 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 +00002151}
2152
2153GLsizei Texture2DArray::getHeight(GLint level) const
2154{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002155 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 +00002156}
2157
2158GLsizei Texture2DArray::getDepth(GLint level) const
2159{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002160 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mLayerCounts[level] : 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002161}
2162
2163GLenum Texture2DArray::getInternalFormat(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]->getInternalFormat() : GL_NONE;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002166}
2167
2168GLenum Texture2DArray::getActualFormat(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]->getActualFormat() : D3DFMT_UNKNOWN;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002171}
2172
2173bool Texture2DArray::isCompressed(GLint level) const
2174{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00002175 return IsFormatCompressed(getInternalFormat(level), mRenderer->getCurrentClientVersion());
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002176}
2177
2178bool Texture2DArray::isDepth(GLint level) const
2179{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00002180 return GetDepthBits(getInternalFormat(level), mRenderer->getCurrentClientVersion()) > 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002181}
2182
Jamie Madill88f18f42013-09-18 14:36:19 -04002183void 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 +00002184{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00002185 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2186 GLint sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
2187 : GetSizedInternalFormat(format, type, clientVersion);
2188 redefineImage(level, sizedInternalFormat, width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002189
Jamie Madill88f18f42013-09-18 14:36:19 -04002190 GLsizei inputDepthPitch = gl::GetDepthPitch(sizedInternalFormat, type, clientVersion, width, height, unpack.alignment);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002191
2192 for (int i = 0; i < depth; i++)
2193 {
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002194 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
Jamie Madill88f18f42013-09-18 14:36:19 -04002195 Texture::setImage(unpack, type, layerPixels, mImageArray[level][i]);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002196 }
2197}
2198
2199void Texture2DArray::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
2200{
2201 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
2202 redefineImage(level, format, width, height, depth);
2203
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002204 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2205 GLsizei inputDepthPitch = gl::GetDepthPitch(format, GL_UNSIGNED_BYTE, clientVersion, width, height, 1);
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;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002210 Texture::setCompressedImage(imageSize, layerPixels, mImageArray[level][i]);
2211 }
2212}
2213
Jamie Madill88f18f42013-09-18 14:36:19 -04002214void 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 +00002215{
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002216 GLint internalformat = getInternalFormat(level);
2217 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Jamie Madill88f18f42013-09-18 14:36:19 -04002218 GLsizei inputDepthPitch = gl::GetDepthPitch(internalformat, type, clientVersion, width, height, unpack.alignment);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002219
2220 for (int i = 0; i < depth; i++)
2221 {
2222 int layer = zoffset + i;
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002223 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002224
Jamie Madill88f18f42013-09-18 14:36:19 -04002225 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 +00002226 {
2227 commitRect(level, xoffset, yoffset, layer, width, height);
2228 }
2229 }
2230}
2231
2232void Texture2DArray::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
2233{
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002234 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2235 GLsizei inputDepthPitch = gl::GetDepthPitch(format, GL_UNSIGNED_BYTE, clientVersion, width, height, 1);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002236
2237 for (int i = 0; i < depth; i++)
2238 {
2239 int layer = zoffset + i;
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002240 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002241
2242 if (Texture::subImageCompressed(xoffset, yoffset, zoffset, width, height, 1, format, imageSize, layerPixels, mImageArray[level][layer]))
2243 {
2244 commitRect(level, xoffset, yoffset, layer, width, height);
2245 }
2246 }
2247}
2248
2249void Texture2DArray::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2250{
2251 delete mTexStorage;
2252 mTexStorage = new rx::TextureStorageInterface2DArray(mRenderer, levels, internalformat, mUsage, width, height, depth);
2253 mImmutable = true;
2254
2255 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2256 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002257 GLsizei levelWidth = std::max(width >> level, 1);
Geoff Lange836cf22013-08-05 14:12:37 -04002258 GLsizei levelHeight = std::max(height >> level, 1);
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002259
2260 // Clear this level
2261 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002262 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002263 delete mImageArray[level][layer];
2264 }
2265 delete[] mImageArray[level];
2266 mImageArray[level] = NULL;
2267 mLayerCounts[level] = 0;
2268
2269 if (level < levels)
2270 {
2271 // Create new images for this level
2272 mImageArray[level] = new rx::Image*[depth]();
2273 mLayerCounts[level] = depth;
2274
2275 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002276 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002277 mImageArray[level][layer] = mRenderer->createImage();
2278 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, levelWidth,
2279 levelHeight, 1, true);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002280 }
2281 }
2282 }
2283
2284 if (mTexStorage->isManaged())
2285 {
2286 int levels = levelCount();
2287
2288 for (int level = 0; level < levels; level++)
2289 {
2290 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2291 {
2292 mImageArray[level][layer]->setManagedSurface(mTexStorage, layer, level);
2293 }
2294 }
2295 }
2296}
2297
2298void Texture2DArray::generateMipmaps()
2299{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002300 int baseWidth = getBaseLevelWidth();
2301 int baseHeight = getBaseLevelHeight();
2302 int baseDepth = getBaseLevelDepth();
2303 GLenum baseFormat = getBaseLevelInternalFormat();
2304
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00002305 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Jamie Madilld3d2a342013-10-07 10:46:35 -04002306 int q = log2(std::max(baseWidth, baseHeight));
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00002307 for (int i = 1; i <= q; i++)
2308 {
Jamie Madilld3d2a342013-10-07 10:46:35 -04002309 redefineImage(i, baseFormat, std::max(baseWidth >> i, 1), std::max(baseHeight >> i, 1), baseDepth);
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00002310 }
2311
2312 if (mTexStorage && mTexStorage->isRenderTarget())
2313 {
2314 for (int level = 1; level <= q; level++)
2315 {
2316 mTexStorage->generateMipmap(level);
2317
2318 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2319 {
2320 mImageArray[level][layer]->markClean();
2321 }
2322 }
2323 }
2324 else
2325 {
2326 for (int level = 1; level <= q; level++)
2327 {
2328 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2329 {
2330 mRenderer->generateMipmap(mImageArray[level][layer], mImageArray[level - 1][layer]);
2331 }
2332 }
2333 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002334}
2335
Jamie Madilld3d2a342013-10-07 10:46:35 -04002336const rx::Image *Texture2DArray::getBaseLevelImage() const
2337{
Jamie Madill152ed092013-10-09 17:01:15 -04002338 return (mLayerCounts[0] > 0 ? mImageArray[0][0] : NULL);
Jamie Madilld3d2a342013-10-07 10:46:35 -04002339}
2340
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002341void Texture2DArray::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
2342{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002343 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 +00002344 {
2345 return gl::error(GL_INVALID_VALUE);
2346 }
2347
Jamie Madill07edd442013-07-19 16:36:58 -04002348 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
2349 // the current level we're copying to is defined (with appropriate format, width & height)
2350 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
2351
2352 if (!mImageArray[level][0]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002353 {
2354 mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, x, y, width, height, source);
2355 mDirtyImages = true;
2356 }
2357 else
2358 {
2359 if (!mTexStorage || !mTexStorage->isRenderTarget())
2360 {
2361 convertToRenderTarget();
2362 }
2363
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002364 if (level < levelCount())
2365 {
Jamie Madill07edd442013-07-19 16:36:58 -04002366 updateTextureLevel(level);
2367
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002368 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2369
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002370 gl::Rectangle sourceRect;
2371 sourceRect.x = x;
2372 sourceRect.width = width;
2373 sourceRect.y = y;
2374 sourceRect.height = height;
2375
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002376 mRenderer->copyImage(source, sourceRect, gl::GetFormat(getInternalFormat(0), clientVersion),
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002377 xoffset, yoffset, zoffset, mTexStorage, level);
2378 }
2379 }
2380}
2381
Jamie Madillf8989902013-07-19 16:36:58 -04002382bool Texture2DArray::isSamplerComplete(const SamplerState &samplerState) const
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002383{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002384 GLsizei width = getBaseLevelWidth();
2385 GLsizei height = getBaseLevelHeight();
2386 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002387
2388 if (width <= 0 || height <= 0 || depth <= 0)
2389 {
2390 return false;
2391 }
2392
Jamie Madilld3d2a342013-10-07 10:46:35 -04002393 if (!IsTextureFilteringSupported(getBaseLevelInternalFormat(), mRenderer))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002394 {
Jamie Madillf8989902013-07-19 16:36:58 -04002395 if (samplerState.magFilter != GL_NEAREST ||
2396 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002397 {
2398 return false;
2399 }
2400 }
2401
Jamie Madillf8989902013-07-19 16:36:58 -04002402 if (IsMipmapFiltered(samplerState) && !isMipmapComplete())
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002403 {
2404 return false;
2405 }
2406
2407 return true;
2408}
2409
2410bool Texture2DArray::isMipmapComplete() const
2411{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002412 GLsizei width = getBaseLevelWidth();
2413 GLsizei height = getBaseLevelHeight();
Jamie Madill07edd442013-07-19 16:36:58 -04002414
2415 int q = log2(std::max(width, height));
2416
2417 for (int level = 1; level <= q; level++)
2418 {
2419 if (!isLevelComplete(level))
2420 {
2421 return false;
2422 }
2423 }
2424
2425 return true;
2426}
2427
2428bool Texture2DArray::isLevelComplete(int level) const
2429{
2430 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
2431
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002432 if (isImmutable())
2433 {
2434 return true;
2435 }
2436
Jamie Madilld3d2a342013-10-07 10:46:35 -04002437 GLsizei width = getBaseLevelWidth();
2438 GLsizei height = getBaseLevelHeight();
2439 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002440
2441 if (width <= 0 || height <= 0 || depth <= 0)
2442 {
2443 return false;
2444 }
2445
Jamie Madill07edd442013-07-19 16:36:58 -04002446 if (level == 0)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002447 {
Jamie Madill07edd442013-07-19 16:36:58 -04002448 return true;
2449 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002450
Jamie Madill07edd442013-07-19 16:36:58 -04002451 if (getInternalFormat(level) != getInternalFormat(0))
2452 {
2453 return false;
2454 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002455
Jamie Madill07edd442013-07-19 16:36:58 -04002456 if (getWidth(level) != std::max(1, width >> level))
2457 {
2458 return false;
2459 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002460
Jamie Madill07edd442013-07-19 16:36:58 -04002461 if (getHeight(level) != std::max(1, height >> level))
2462 {
2463 return false;
2464 }
2465
2466 if (getDepth(level) != depth)
2467 {
2468 return false;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002469 }
2470
2471 return true;
2472}
2473
Geoff Lang8040f572013-07-25 16:49:54 -04002474Renderbuffer *Texture2DArray::getRenderbuffer(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002475{
Geoff Lang8040f572013-07-25 16:49:54 -04002476 Renderbuffer *renderBuffer = mRenderbufferProxies.get(level, layer);
2477 if (!renderBuffer)
2478 {
Geoff Langd5d8e392013-07-25 16:53:03 -04002479 renderBuffer = new Renderbuffer(mRenderer, id(), new RenderbufferTexture2DArrayLayer(this, level, layer));
2480 mRenderbufferProxies.add(level, 0, renderBuffer);
Geoff Lang8040f572013-07-25 16:49:54 -04002481 }
2482
2483 return renderBuffer;
2484}
2485
2486unsigned int Texture2DArray::getRenderTargetSerial( GLint level, GLint layer )
2487{
2488 if (!mTexStorage || !mTexStorage->isRenderTarget())
2489 {
2490 convertToRenderTarget();
2491 }
2492
2493 return mTexStorage ? mTexStorage->getRenderTargetSerial(level, layer) : 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002494}
2495
2496int Texture2DArray::levelCount()
2497{
2498 return mTexStorage ? mTexStorage->levelCount() : 0;
2499}
2500
2501void Texture2DArray::createTexture()
2502{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002503 GLsizei width = getBaseLevelWidth();
2504 GLsizei height = getBaseLevelHeight();
2505 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002506
2507 if (width <= 0 || height <= 0 || depth <= 0)
2508 {
2509 return; // do not attempt to create native textures for nonexistant data
2510 }
2511
2512 GLint levels = creationLevels(width, height);
Jamie Madilld3d2a342013-10-07 10:46:35 -04002513 GLenum internalformat = getBaseLevelInternalFormat();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002514
2515 delete mTexStorage;
2516 mTexStorage = new rx::TextureStorageInterface2DArray(mRenderer, levels, internalformat, mUsage, width, height, depth);
2517
2518 if (mTexStorage->isManaged())
2519 {
2520 int levels = levelCount();
2521 for (int level = 0; level < levels; level++)
2522 {
2523 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2524 {
2525 mImageArray[level][layer]->setManagedSurface(mTexStorage, layer, level);
2526 }
2527 }
2528 }
2529
2530 mDirtyImages = true;
2531}
2532
2533void Texture2DArray::updateTexture()
2534{
Jamie Madilleb3665c2013-07-19 16:36:57 -04002535 int levels = (isMipmapComplete() ? levelCount() : 1);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002536 for (int level = 0; level < levels; level++)
2537 {
Jamie Madill07edd442013-07-19 16:36:58 -04002538 updateTextureLevel(level);
2539 }
2540}
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002541
Jamie Madill07edd442013-07-19 16:36:58 -04002542void Texture2DArray::updateTextureLevel(int level)
2543{
2544 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2545 {
2546 rx::Image *image = mImageArray[level][layer];
2547
2548 if (image->isDirty())
2549 {
2550 commitRect(level, 0, 0, layer, image->getWidth(), image->getHeight());
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002551 }
2552 }
2553}
2554
2555void Texture2DArray::convertToRenderTarget()
2556{
2557 rx::TextureStorageInterface2DArray *newTexStorage = NULL;
2558
Jamie Madilld3d2a342013-10-07 10:46:35 -04002559 GLsizei width = getBaseLevelWidth();
2560 GLsizei height = getBaseLevelHeight();
2561 GLsizei depth = getBaseLevelDepth();
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002562
2563 if (width != 0 && height != 0 && depth != 0)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002564 {
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002565 GLint levels = mTexStorage != NULL ? mTexStorage->levelCount() : creationLevels(width, height);
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002566 GLenum internalformat = getInternalFormat(0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002567
2568 newTexStorage = new rx::TextureStorageInterface2DArray(mRenderer, levels, internalformat, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, width, height, depth);
2569
2570 if (mTexStorage != NULL)
2571 {
2572 if (!mRenderer->copyToRenderTarget(newTexStorage, mTexStorage))
2573 {
2574 delete newTexStorage;
2575 return gl::error(GL_OUT_OF_MEMORY);
2576 }
2577 }
2578 }
2579
2580 delete mTexStorage;
2581 mTexStorage = newTexStorage;
2582
2583 mDirtyImages = true;
2584}
2585
Geoff Lang8040f572013-07-25 16:49:54 -04002586rx::RenderTarget *Texture2DArray::getRenderTarget(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002587{
Geoff Lang8040f572013-07-25 16:49:54 -04002588 // ensure the underlying texture is created
2589 if (getStorage(true) == NULL)
2590 {
2591 return NULL;
2592 }
2593
2594 updateTexture();
2595
2596 // ensure this is NOT a depth texture
2597 if (isDepth(level))
2598 {
2599 return NULL;
2600 }
2601
2602 return mTexStorage->getRenderTarget(level, layer);
2603}
2604
2605rx::RenderTarget *Texture2DArray::getDepthStencil(GLint level, GLint layer)
2606{
2607 // ensure the underlying texture is created
2608 if (getStorage(true) == NULL)
2609 {
2610 return NULL;
2611 }
2612
2613 updateTexture();
2614
2615 // ensure this is a depth texture
2616 if (!isDepth(level))
2617 {
2618 return NULL;
2619 }
2620
2621 return mTexStorage->getRenderTarget(level, layer);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002622}
2623
2624rx::TextureStorageInterface *Texture2DArray::getStorage(bool renderTarget)
2625{
2626 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
2627 {
2628 if (renderTarget)
2629 {
2630 convertToRenderTarget();
2631 }
2632 else
2633 {
2634 createTexture();
2635 }
2636 }
2637
2638 return mTexStorage;
2639}
2640
2641void Texture2DArray::redefineImage(GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth)
2642{
2643 // If there currently is a corresponding storage texture image, it has these parameters
Jamie Madilld3d2a342013-10-07 10:46:35 -04002644 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2645 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
2646 const int storageDepth = getBaseLevelDepth();
2647 const int storageFormat = getBaseLevelInternalFormat();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002648
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002649 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002650 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002651 delete mImageArray[level][layer];
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002652 }
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002653 delete[] mImageArray[level];
Jamie Madill152ed092013-10-09 17:01:15 -04002654 mImageArray[level] = NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002655 mLayerCounts[level] = depth;
2656
Jamie Madill152ed092013-10-09 17:01:15 -04002657 if (depth > 0)
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002658 {
Jamie Madill152ed092013-10-09 17:01:15 -04002659 mImageArray[level] = new rx::Image*[depth]();
2660
2661 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2662 {
2663 mImageArray[level][layer] = mRenderer->createImage();
2664 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, width, height, 1, false);
2665 }
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002666 }
2667
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002668 if (mTexStorage)
2669 {
2670 const int storageLevels = mTexStorage->levelCount();
2671
2672 if ((level >= storageLevels && storageLevels != 0) ||
2673 width != storageWidth ||
2674 height != storageHeight ||
2675 depth != storageDepth ||
2676 internalformat != storageFormat) // Discard mismatched storage
2677 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002678 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002679 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002680 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002681 {
2682 mImageArray[level][layer]->markDirty();
2683 }
2684 }
2685
2686 delete mTexStorage;
2687 mTexStorage = NULL;
2688 mDirtyImages = true;
2689 }
2690 }
2691}
2692
2693void Texture2DArray::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint layerTarget, GLsizei width, GLsizei height)
2694{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002695 if (level < levelCount() && layerTarget < getDepth(level))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002696 {
2697 rx::Image *image = mImageArray[level][layerTarget];
2698 if (image->updateSurface(mTexStorage, level, xoffset, yoffset, layerTarget, width, height))
2699 {
2700 image->markClean();
2701 }
2702 }
2703}
2704
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00002705}