blob: 5af2fdb0b43cebe2b1f162633a1d718cbd2eb47a [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 Madill8cc7d972013-10-10 15:51:55 -0400226bool Texture::isFastUnpackable(const PixelUnpackState &unpack, GLint sizedInternalFormat)
227{
228 return unpack.pixelBuffer.id() != 0 && mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat);
229}
230
Jamie Madill1beb1db2013-09-18 14:36:28 -0400231bool Texture::fastUnpackPixels(const PixelUnpackState &unpack, const void *pixels, const Box &destArea,
Jamie Madill8cc7d972013-10-10 15:51:55 -0400232 GLenum sizedInternalFormat, GLenum type, rx::RenderTarget *destRenderTarget)
Jamie Madill1beb1db2013-09-18 14:36:28 -0400233{
234 if (destArea.width <= 0 && destArea.height <= 0 && destArea.depth <= 0)
235 {
236 return true;
237 }
238
239 // In order to perform the fast copy through the shader, we must have the right format, and be able
240 // to create a render target.
Jamie Madill8cc7d972013-10-10 15:51:55 -0400241 ASSERT(mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat));
Jamie Madill1beb1db2013-09-18 14:36:28 -0400242
Jamie Madill8cc7d972013-10-10 15:51:55 -0400243 unsigned int offset = reinterpret_cast<unsigned int>(pixels);
Jamie Madill1beb1db2013-09-18 14:36:28 -0400244
Jamie Madill8cc7d972013-10-10 15:51:55 -0400245 return mRenderer->fastCopyBufferToTexture(unpack, offset, destRenderTarget, sizedInternalFormat, type, destArea);
Jamie Madill1beb1db2013-09-18 14:36:28 -0400246}
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{
Jamie Madill065e1a32013-10-10 15:11:50 -0400260 const void *pixelData = pixels;
261
262 // CPU readback & copy where direct GPU copy is not supported
263 if (unpack.pixelBuffer.id() != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000264 {
Jamie Madill065e1a32013-10-10 15:11:50 -0400265 Buffer *pixelBuffer = unpack.pixelBuffer.get();
266 unsigned int offset = reinterpret_cast<unsigned int>(pixels);
267 const void *bufferData = pixelBuffer->getStorage()->getData();
268 pixelData = static_cast<const unsigned char *>(bufferData) + offset;
269 }
270
271 if (pixelData != NULL)
272 {
273 image->loadData(xoffset, yoffset, zoffset, width, height, depth, unpack.alignment, type, pixelData);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000274 mDirtyImages = true;
275 }
276
277 return true;
278}
279
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000280bool Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
281 GLenum format, GLsizei imageSize, const void *pixels, rx::Image *image)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000282{
283 if (pixels != NULL)
284 {
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000285 image->loadCompressedData(xoffset, yoffset, zoffset, width, height, depth, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000286 mDirtyImages = true;
287 }
288
289 return true;
290}
291
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000292rx::TextureStorageInterface *Texture::getNativeTexture()
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000293{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000294 // ensure the underlying texture is created
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000295
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000296 rx::TextureStorageInterface *storage = getStorage(false);
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000297 if (storage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000298 {
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000299 updateTexture();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000300 }
301
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000302 return storage;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000303}
304
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000305bool Texture::hasDirtyImages() const
306{
307 return mDirtyImages;
308}
309
310void Texture::resetDirty()
311{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000312 mDirtyImages = false;
313}
314
315unsigned int Texture::getTextureSerial()
316{
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000317 rx::TextureStorageInterface *texture = getStorage(false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000318 return texture ? texture->getTextureSerial() : 0;
319}
320
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000321bool Texture::isImmutable() const
322{
323 return mImmutable;
324}
325
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +0000326GLint Texture::creationLevels(GLsizei width, GLsizei height, GLsizei depth) const
327{
328 // NPOT checks are not required in ES 3.0, NPOT texture support is assumed.
329 return 0; // Maximum number of levels
330}
331
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000332GLint Texture::creationLevels(GLsizei width, GLsizei height) const
333{
daniel@transgaming.comea32d482012-11-28 19:33:18 +0000334 if ((isPow2(width) && isPow2(height)) || mRenderer->getNonPower2TextureSupport())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000335 {
336 return 0; // Maximum number of levels
337 }
338 else
339 {
340 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
341 return 1;
342 }
343}
344
345GLint Texture::creationLevels(GLsizei size) const
346{
347 return creationLevels(size, size);
348}
349
Geoff Lang4907f2c2013-07-25 12:53:57 -0400350Texture2D::Texture2D(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_2D)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000351{
352 mTexStorage = NULL;
353 mSurface = NULL;
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000354
355 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
356 {
daniel@transgaming.com244e1832012-12-20 20:52:35 +0000357 mImageArray[i] = renderer->createImage();
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000358 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000359}
360
361Texture2D::~Texture2D()
362{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000363 delete mTexStorage;
364 mTexStorage = NULL;
365
366 if (mSurface)
367 {
368 mSurface->setBoundTexture(NULL);
369 mSurface = NULL;
370 }
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000371
372 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
373 {
374 delete mImageArray[i];
375 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000376}
377
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000378GLsizei Texture2D::getWidth(GLint level) const
379{
380 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000381 return mImageArray[level]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000382 else
383 return 0;
384}
385
386GLsizei Texture2D::getHeight(GLint level) const
387{
388 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000389 return mImageArray[level]->getHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000390 else
391 return 0;
392}
393
394GLenum Texture2D::getInternalFormat(GLint level) const
395{
396 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000397 return mImageArray[level]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000398 else
399 return GL_NONE;
400}
401
daniel@transgaming.com20d36662012-10-31 19:51:43 +0000402GLenum Texture2D::getActualFormat(GLint level) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000403{
404 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000405 return mImageArray[level]->getActualFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000406 else
407 return D3DFMT_UNKNOWN;
408}
409
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000410void Texture2D::redefineImage(GLint level, GLint internalformat, GLsizei width, GLsizei height)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000411{
412 releaseTexImage();
shannon.woods@transgaming.com8a406682013-02-28 23:15:26 +0000413
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000414 // If there currently is a corresponding storage texture image, it has these parameters
Jamie Madilld3d2a342013-10-07 10:46:35 -0400415 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
416 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
417 const int storageFormat = getBaseLevelInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000418
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000419 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, width, height, 1, false);
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000420
421 if (mTexStorage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000422 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000423 const int storageLevels = mTexStorage->levelCount();
424
425 if ((level >= storageLevels && storageLevels != 0) ||
426 width != storageWidth ||
427 height != storageHeight ||
428 internalformat != storageFormat) // Discard mismatched storage
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000429 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000430 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
431 {
432 mImageArray[i]->markDirty();
433 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000434
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000435 delete mTexStorage;
436 mTexStorage = NULL;
437 mDirtyImages = true;
438 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000439 }
440}
441
Jamie Madill88f18f42013-09-18 14:36:19 -0400442void 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 +0000443{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +0000444 GLuint clientVersion = mRenderer->getCurrentClientVersion();
445 GLint sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
446 : GetSizedInternalFormat(format, type, clientVersion);
447 redefineImage(level, sizedInternalFormat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000448
Jamie Madill8cc7d972013-10-10 15:51:55 -0400449 bool fastUnpacked = false;
450
Jamie Madill1beb1db2013-09-18 14:36:28 -0400451 // Attempt a fast gpu copy of the pixel data to the surface
Jamie Madill8cc7d972013-10-10 15:51:55 -0400452 if (isFastUnpackable(unpack, sizedInternalFormat) && isLevelComplete(level))
Jamie Madill1beb1db2013-09-18 14:36:28 -0400453 {
Jamie Madill8cc7d972013-10-10 15:51:55 -0400454 // Will try to create RT storage if it does not exist
455 rx::RenderTarget *destRenderTarget = getRenderTarget(level);
456 Box destArea(0, 0, 0, getWidth(level), getHeight(level), 1);
457
458 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget))
459 {
460 // Ensure we don't overwrite our newly initialized data
461 mImageArray[level]->markClean();
462
463 fastUnpacked = true;
464 }
Jamie Madill1beb1db2013-09-18 14:36:28 -0400465 }
Jamie Madill8cc7d972013-10-10 15:51:55 -0400466
467 if (!fastUnpacked)
Jamie Madill1beb1db2013-09-18 14:36:28 -0400468 {
469 Texture::setImage(unpack, type, pixels, mImageArray[level]);
470 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000471}
472
473void Texture2D::bindTexImage(egl::Surface *surface)
474{
475 releaseTexImage();
476
daniel@transgaming.com106e1f72012-10-31 18:38:36 +0000477 GLint internalformat = surface->getFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000478
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000479 mImageArray[0]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, surface->getWidth(), surface->getHeight(), 1, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000480
481 delete mTexStorage;
daniel@transgaming.comd8353dd2012-12-20 21:11:14 +0000482 mTexStorage = new rx::TextureStorageInterface2D(mRenderer, surface->getSwapChain());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000483
484 mDirtyImages = true;
485 mSurface = surface;
486 mSurface->setBoundTexture(this);
487}
488
489void Texture2D::releaseTexImage()
490{
491 if (mSurface)
492 {
493 mSurface->setBoundTexture(NULL);
494 mSurface = NULL;
495
496 if (mTexStorage)
497 {
498 delete mTexStorage;
499 mTexStorage = NULL;
500 }
501
502 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
503 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000504 mImageArray[i]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000505 }
506 }
507}
508
509void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
510{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000511 // 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 +0000512 redefineImage(level, format, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000513
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000514 Texture::setCompressedImage(imageSize, pixels, mImageArray[level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000515}
516
517void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
518{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000519 if (level < levelCount())
520 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000521 rx::Image *image = mImageArray[level];
daniel@transgaming.com0f195ad2012-10-31 19:51:59 +0000522 if (image->updateSurface(mTexStorage, level, xoffset, yoffset, width, height))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000523 {
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000524 image->markClean();
525 }
526 }
527}
528
Jamie Madill88f18f42013-09-18 14:36:19 -0400529void 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 +0000530{
Jamie Madill065e1a32013-10-10 15:11:50 -0400531 bool fastUnpacked = false;
532
533 if (isFastUnpackable(unpack, getInternalFormat(level)) && isLevelComplete(level))
534 {
535 rx::RenderTarget *renderTarget = getRenderTarget(level);
536 Box destArea(xoffset, yoffset, 0, width, height, 1);
537
538 if (renderTarget && fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, renderTarget))
539 {
540 // Ensure we don't overwrite our newly initialized data
541 mImageArray[level]->markClean();
542
543 fastUnpacked = true;
544 }
545 }
546
547 if (!fastUnpacked && Texture::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, mImageArray[level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000548 {
549 commitRect(level, xoffset, yoffset, width, height);
550 }
551}
552
553void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
554{
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000555 if (Texture::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000556 {
557 commitRect(level, xoffset, yoffset, width, height);
558 }
559}
560
561void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
562{
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +0000563 GLuint clientVersion = mRenderer->getCurrentClientVersion();
564 GLint sizedInternalFormat = IsSizedInternalFormat(format, clientVersion) ? format
565 : GetSizedInternalFormat(format, GL_UNSIGNED_BYTE, clientVersion);
566 redefineImage(level, sizedInternalFormat, width, height);
shannon.woods@transgaming.com8a406682013-02-28 23:15:26 +0000567
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000568 if (!mImageArray[level]->isRenderableFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000569 {
shannon.woods%transgaming.com@gtempaccount.come5dcce72013-04-13 03:44:33 +0000570 mImageArray[level]->copy(0, 0, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000571 mDirtyImages = true;
572 }
573 else
574 {
575 if (!mTexStorage || !mTexStorage->isRenderTarget())
576 {
577 convertToRenderTarget();
578 }
579
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000580 mImageArray[level]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000581
582 if (width != 0 && height != 0 && level < levelCount())
583 {
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +0000584 gl::Rectangle sourceRect;
585 sourceRect.x = x;
586 sourceRect.width = width;
587 sourceRect.y = y;
588 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000589
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +0000590 mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000591 }
592 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000593}
594
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +0000595void 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 +0000596{
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +0000597 if (xoffset + width > mImageArray[level]->getWidth() || yoffset + height > mImageArray[level]->getHeight() || zoffset != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000598 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +0000599 return gl::error(GL_INVALID_VALUE);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000600 }
601
Jamie Madill07edd442013-07-19 16:36:58 -0400602 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
603 // the current level we're copying to is defined (with appropriate format, width & height)
604 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
605
606 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000607 {
shannon.woods%transgaming.com@gtempaccount.come5dcce72013-04-13 03:44:33 +0000608 mImageArray[level]->copy(xoffset, yoffset, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000609 mDirtyImages = true;
610 }
611 else
612 {
613 if (!mTexStorage || !mTexStorage->isRenderTarget())
614 {
615 convertToRenderTarget();
616 }
617
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000618 if (level < levelCount())
619 {
Jamie Madill07edd442013-07-19 16:36:58 -0400620 updateTextureLevel(level);
621
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +0000622 GLuint clientVersion = mRenderer->getCurrentClientVersion();
623
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +0000624 gl::Rectangle sourceRect;
625 sourceRect.x = x;
626 sourceRect.width = width;
627 sourceRect.y = y;
628 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000629
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +0000630 mRenderer->copyImage(source, sourceRect,
Jamie Madilld3d2a342013-10-07 10:46:35 -0400631 gl::GetFormat(getBaseLevelInternalFormat(), clientVersion),
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +0000632 xoffset, yoffset, mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000633 }
634 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000635}
636
637void Texture2D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height)
638{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000639 delete mTexStorage;
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000640 mTexStorage = new rx::TextureStorageInterface2D(mRenderer, levels, internalformat, mUsage, false, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000641 mImmutable = true;
642
643 for (int level = 0; level < levels; level++)
644 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000645 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, width, height, 1, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000646 width = std::max(1, width >> 1);
647 height = std::max(1, height >> 1);
648 }
649
650 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
651 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000652 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000653 }
654
655 if (mTexStorage->isManaged())
656 {
657 int levels = levelCount();
658
659 for (int level = 0; level < levels; level++)
660 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000661 mImageArray[level]->setManagedSurface(mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000662 }
663 }
664}
665
666// Tests for 2D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85.
Jamie Madillf8989902013-07-19 16:36:58 -0400667bool Texture2D::isSamplerComplete(const SamplerState &samplerState) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000668{
Jamie Madilld3d2a342013-10-07 10:46:35 -0400669 GLsizei width = getBaseLevelWidth();
670 GLsizei height = getBaseLevelHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000671
672 if (width <= 0 || height <= 0)
673 {
674 return false;
675 }
676
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000677 if (!IsTextureFilteringSupported(getInternalFormat(0), mRenderer))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000678 {
Jamie Madillf8989902013-07-19 16:36:58 -0400679 if (samplerState.magFilter != GL_NEAREST ||
680 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000681 {
682 return false;
683 }
684 }
685
daniel@transgaming.comea32d482012-11-28 19:33:18 +0000686 bool npotSupport = mRenderer->getNonPower2TextureSupport();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000687
688 if (!npotSupport)
689 {
Jamie Madillf8989902013-07-19 16:36:58 -0400690 if ((samplerState.wrapS != GL_CLAMP_TO_EDGE && !isPow2(width)) ||
691 (samplerState.wrapT != GL_CLAMP_TO_EDGE && !isPow2(height)))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000692 {
693 return false;
694 }
695 }
696
Jamie Madillf8989902013-07-19 16:36:58 -0400697 if (IsMipmapFiltered(samplerState))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000698 {
699 if (!npotSupport)
700 {
701 if (!isPow2(width) || !isPow2(height))
702 {
703 return false;
704 }
705 }
706
707 if (!isMipmapComplete())
708 {
709 return false;
710 }
711 }
712
Geoff Langc82fc412013-07-10 14:43:42 -0400713 // OpenGLES 3.0.2 spec section 3.8.13 states that a texture is not mipmap complete if:
714 // The internalformat specified for the texture arrays is a sized internal depth or
715 // depth and stencil format (see table 3.13), the value of TEXTURE_COMPARE_-
716 // MODE is NONE, and either the magnification filter is not NEAREST or the mini-
717 // fication filter is neither NEAREST nor NEAREST_MIPMAP_NEAREST.
718 if (gl::GetDepthBits(getInternalFormat(0), mRenderer->getCurrentClientVersion()) > 0)
719 {
720 if (mSamplerState.compareMode == GL_NONE)
721 {
722 if ((mSamplerState.minFilter != GL_NEAREST && mSamplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST) ||
723 mSamplerState.magFilter != GL_NEAREST)
724 {
725 return false;
726 }
727 }
728 }
729
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000730 return true;
731}
732
733// Tests for 2D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
734bool Texture2D::isMipmapComplete() const
735{
Jamie Madilld3d2a342013-10-07 10:46:35 -0400736 GLsizei width = getBaseLevelWidth();
737 GLsizei height = getBaseLevelHeight();
Jamie Madill07edd442013-07-19 16:36:58 -0400738
739 int q = log2(std::max(width, height));
740
741 for (int level = 0; level <= q; level++)
742 {
743 if (!isLevelComplete(level))
744 {
745 return false;
746 }
747 }
748
749 return true;
750}
751
752bool Texture2D::isLevelComplete(int level) const
753{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000754 if (isImmutable())
755 {
756 return true;
757 }
758
Jamie Madilld3d2a342013-10-07 10:46:35 -0400759 GLsizei width = getBaseLevelWidth();
760 GLsizei height = getBaseLevelHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000761
762 if (width <= 0 || height <= 0)
763 {
764 return false;
765 }
766
Jamie Madill07edd442013-07-19 16:36:58 -0400767 // The base image level is complete if the width and height are positive
768 if (level == 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000769 {
Jamie Madill07edd442013-07-19 16:36:58 -0400770 return true;
771 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000772
Jamie Madill07edd442013-07-19 16:36:58 -0400773 ASSERT(level >= 1 && level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
774 rx::Image *image = mImageArray[level];
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000775
Jamie Madilld3d2a342013-10-07 10:46:35 -0400776 if (image->getInternalFormat() != getBaseLevelInternalFormat())
Jamie Madill07edd442013-07-19 16:36:58 -0400777 {
778 return false;
779 }
780
781 if (image->getWidth() != std::max(1, width >> level))
782 {
783 return false;
784 }
785
786 if (image->getHeight() != std::max(1, height >> level))
787 {
788 return false;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000789 }
790
791 return true;
792}
793
794bool Texture2D::isCompressed(GLint level) const
795{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000796 return IsFormatCompressed(getInternalFormat(level), mRenderer->getCurrentClientVersion());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000797}
798
799bool Texture2D::isDepth(GLint level) const
800{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000801 return GetDepthBits(getInternalFormat(level), mRenderer->getCurrentClientVersion()) > 0;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000802}
803
daniel@transgaming.comf032cb82012-10-31 19:51:52 +0000804// Constructs a native texture resource from the texture images
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000805void Texture2D::createTexture()
806{
Jamie Madilld3d2a342013-10-07 10:46:35 -0400807 GLsizei width = getBaseLevelWidth();
808 GLsizei height = getBaseLevelHeight();
daniel@transgaming.come6a09842012-09-17 21:28:55 +0000809
810 if (!(width > 0 && height > 0))
daniel@transgaming.comf032cb82012-10-31 19:51:52 +0000811 return; // do not attempt to create native textures for nonexistant data
daniel@transgaming.come6a09842012-09-17 21:28:55 +0000812
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000813 GLint levels = creationLevels(width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000814
815 delete mTexStorage;
Jamie Madilld3d2a342013-10-07 10:46:35 -0400816 mTexStorage = new rx::TextureStorageInterface2D(mRenderer, levels, getBaseLevelInternalFormat(), mUsage, false, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000817
818 if (mTexStorage->isManaged())
819 {
820 int levels = levelCount();
821
822 for (int level = 0; level < levels; level++)
823 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000824 mImageArray[level]->setManagedSurface(mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000825 }
826 }
827
828 mDirtyImages = true;
829}
830
831void Texture2D::updateTexture()
832{
Jamie Madilleb3665c2013-07-19 16:36:57 -0400833 int levels = (isMipmapComplete() ? levelCount() : 1);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000834
835 for (int level = 0; level < levels; level++)
836 {
Jamie Madill07edd442013-07-19 16:36:58 -0400837 updateTextureLevel(level);
838 }
839}
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000840
Jamie Madill07edd442013-07-19 16:36:58 -0400841void Texture2D::updateTextureLevel(int level)
842{
843 ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
844 rx::Image *image = mImageArray[level];
845
846 if (image->isDirty())
847 {
848 commitRect(level, 0, 0, mImageArray[level]->getWidth(), mImageArray[level]->getHeight());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000849 }
850}
851
852void Texture2D::convertToRenderTarget()
853{
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000854 rx::TextureStorageInterface2D *newTexStorage = NULL;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000855
Jamie Madilld3d2a342013-10-07 10:46:35 -0400856 GLsizei width = getBaseLevelWidth();
857 GLsizei height = getBaseLevelHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000858
Jamie Madilld3d2a342013-10-07 10:46:35 -0400859 if (width != 0 && height != 0)
860 {
861 GLint levels = mTexStorage != NULL ? mTexStorage->levelCount() : creationLevels(width, height);
862
863 newTexStorage = new rx::TextureStorageInterface2D(mRenderer, levels, getBaseLevelInternalFormat(), GL_FRAMEBUFFER_ATTACHMENT_ANGLE, true, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000864
865 if (mTexStorage != NULL)
866 {
daniel@transgaming.com1d80eee2012-11-28 19:33:31 +0000867 if (!mRenderer->copyToRenderTarget(newTexStorage, mTexStorage))
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +0000868 {
869 delete newTexStorage;
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +0000870 return gl::error(GL_OUT_OF_MEMORY);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000871 }
872 }
873 }
874
875 delete mTexStorage;
876 mTexStorage = newTexStorage;
877
878 mDirtyImages = true;
879}
880
881void Texture2D::generateMipmaps()
882{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000883 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Jamie Madilld3d2a342013-10-07 10:46:35 -0400884 unsigned int q = log2(std::max(getBaseLevelWidth(), getBaseLevelHeight()));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000885 for (unsigned int i = 1; i <= q; i++)
886 {
Jamie Madilld3d2a342013-10-07 10:46:35 -0400887 redefineImage(i, getBaseLevelInternalFormat(),
888 std::max(getBaseLevelWidth() >> i, 1),
889 std::max(getBaseLevelHeight() >> i, 1));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000890 }
891
892 if (mTexStorage && mTexStorage->isRenderTarget())
893 {
894 for (unsigned int i = 1; i <= q; i++)
895 {
daniel@transgaming.com0ad830b2012-10-31 19:52:12 +0000896 mTexStorage->generateMipmap(i);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000897
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000898 mImageArray[i]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000899 }
900 }
901 else
902 {
903 for (unsigned int i = 1; i <= q; i++)
904 {
daniel@transgaming.com4ba24062012-12-20 20:54:24 +0000905 mRenderer->generateMipmap(mImageArray[i], mImageArray[i - 1]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000906 }
907 }
908}
909
Jamie Madilld3d2a342013-10-07 10:46:35 -0400910const rx::Image *Texture2D::getBaseLevelImage() const
911{
912 return mImageArray[0];
913}
914
Geoff Lang8040f572013-07-25 16:49:54 -0400915Renderbuffer *Texture2D::getRenderbuffer(GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000916{
Geoff Lang8040f572013-07-25 16:49:54 -0400917 Renderbuffer *renderBuffer = mRenderbufferProxies.get(level, 0);
918 if (!renderBuffer)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000919 {
Geoff Lang8040f572013-07-25 16:49:54 -0400920 renderBuffer = new Renderbuffer(mRenderer, id(), new RenderbufferTexture2D(this, level));
921 mRenderbufferProxies.add(level, 0, renderBuffer);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000922 }
923
Geoff Lang8040f572013-07-25 16:49:54 -0400924 return renderBuffer;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000925}
926
Geoff Lang8040f572013-07-25 16:49:54 -0400927unsigned int Texture2D::getRenderTargetSerial(GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000928{
Geoff Lang8040f572013-07-25 16:49:54 -0400929 if (!mTexStorage || !mTexStorage->isRenderTarget())
930 {
931 convertToRenderTarget();
932 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000933
Geoff Lang8040f572013-07-25 16:49:54 -0400934 return mTexStorage ? mTexStorage->getRenderTargetSerial(level) : 0;
935}
936
937rx::RenderTarget *Texture2D::getRenderTarget(GLint level)
938{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000939 // ensure the underlying texture is created
940 if (getStorage(true) == NULL)
941 {
942 return NULL;
943 }
944
945 updateTexture();
Geoff Lang8040f572013-07-25 16:49:54 -0400946
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000947 // ensure this is NOT a depth texture
Geoff Lang8040f572013-07-25 16:49:54 -0400948 if (isDepth(level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000949 {
950 return NULL;
951 }
daniel@transgaming.com34da3972012-12-20 21:10:29 +0000952
Geoff Lang8040f572013-07-25 16:49:54 -0400953 return mTexStorage->getRenderTarget(level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000954}
955
Geoff Lang8040f572013-07-25 16:49:54 -0400956rx::RenderTarget *Texture2D::getDepthSencil(GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000957{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000958 // ensure the underlying texture is created
959 if (getStorage(true) == NULL)
960 {
961 return NULL;
962 }
963
964 updateTexture();
965
966 // ensure this is actually a depth texture
Geoff Lang8040f572013-07-25 16:49:54 -0400967 if (!isDepth(level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000968 {
969 return NULL;
970 }
Geoff Lang8040f572013-07-25 16:49:54 -0400971
972 return mTexStorage->getRenderTarget(level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000973}
974
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +0000975int Texture2D::levelCount()
976{
shannon.woods@transgaming.com5016f8e2013-02-28 23:20:57 +0000977 return mTexStorage ? mTexStorage->levelCount() : 0;
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +0000978}
979
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000980rx::TextureStorageInterface *Texture2D::getStorage(bool renderTarget)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000981{
982 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
983 {
984 if (renderTarget)
985 {
986 convertToRenderTarget();
987 }
988 else
989 {
990 createTexture();
991 }
992 }
993
994 return mTexStorage;
995}
996
Geoff Lang4907f2c2013-07-25 12:53:57 -0400997TextureCubeMap::TextureCubeMap(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_CUBE_MAP)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000998{
999 mTexStorage = NULL;
1000 for (int i = 0; i < 6; i++)
1001 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001002 for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
1003 {
daniel@transgaming.com244e1832012-12-20 20:52:35 +00001004 mImageArray[i][j] = renderer->createImage();
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001005 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001006 }
1007}
1008
1009TextureCubeMap::~TextureCubeMap()
1010{
1011 for (int i = 0; i < 6; i++)
1012 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001013 for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
1014 {
1015 delete mImageArray[i][j];
1016 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001017 }
1018
1019 delete mTexStorage;
1020 mTexStorage = NULL;
1021}
1022
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001023GLsizei TextureCubeMap::getWidth(GLenum target, GLint level) const
1024{
1025 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001026 return mImageArray[faceIndex(target)][level]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001027 else
1028 return 0;
1029}
1030
1031GLsizei TextureCubeMap::getHeight(GLenum target, GLint level) const
1032{
1033 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001034 return mImageArray[faceIndex(target)][level]->getHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001035 else
1036 return 0;
1037}
1038
1039GLenum TextureCubeMap::getInternalFormat(GLenum target, GLint level) const
1040{
1041 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001042 return mImageArray[faceIndex(target)][level]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001043 else
1044 return GL_NONE;
1045}
1046
daniel@transgaming.com20d36662012-10-31 19:51:43 +00001047GLenum TextureCubeMap::getActualFormat(GLenum target, GLint level) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001048{
1049 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001050 return mImageArray[faceIndex(target)][level]->getActualFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001051 else
1052 return D3DFMT_UNKNOWN;
1053}
1054
Jamie Madill88f18f42013-09-18 14:36:19 -04001055void 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 +00001056{
Jamie Madill88f18f42013-09-18 14:36:19 -04001057 setImage(0, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001058}
1059
Jamie Madill88f18f42013-09-18 14:36:19 -04001060void 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 +00001061{
Jamie Madill88f18f42013-09-18 14:36:19 -04001062 setImage(1, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001063}
1064
Jamie Madill88f18f42013-09-18 14:36:19 -04001065void 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 +00001066{
Jamie Madill88f18f42013-09-18 14:36:19 -04001067 setImage(2, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001068}
1069
Jamie Madill88f18f42013-09-18 14:36:19 -04001070void 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 +00001071{
Jamie Madill88f18f42013-09-18 14:36:19 -04001072 setImage(3, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001073}
1074
Jamie Madill88f18f42013-09-18 14:36:19 -04001075void 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 +00001076{
Jamie Madill88f18f42013-09-18 14:36:19 -04001077 setImage(4, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001078}
1079
Jamie Madill88f18f42013-09-18 14:36:19 -04001080void 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 +00001081{
Jamie Madill88f18f42013-09-18 14:36:19 -04001082 setImage(5, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001083}
1084
1085void TextureCubeMap::setCompressedImage(GLenum face, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
1086{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001087 // 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 +00001088 redefineImage(faceIndex(face), level, format, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001089
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001090 Texture::setCompressedImage(imageSize, pixels, mImageArray[faceIndex(face)][level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001091}
1092
1093void TextureCubeMap::commitRect(int face, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1094{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001095 if (level < levelCount())
1096 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001097 rx::Image *image = mImageArray[face][level];
daniel@transgaming.com0f195ad2012-10-31 19:51:59 +00001098 if (image->updateSurface(mTexStorage, face, level, xoffset, yoffset, width, height))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001099 image->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001100 }
1101}
1102
Jamie Madill88f18f42013-09-18 14:36:19 -04001103void 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 +00001104{
Jamie Madill88f18f42013-09-18 14:36:19 -04001105 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 +00001106 {
1107 commitRect(faceIndex(target), level, xoffset, yoffset, width, height);
1108 }
1109}
1110
1111void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1112{
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +00001113 if (Texture::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[faceIndex(target)][level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001114 {
1115 commitRect(faceIndex(target), level, xoffset, yoffset, width, height);
1116 }
1117}
1118
1119// Tests for cube map sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 86.
Jamie Madillf8989902013-07-19 16:36:58 -04001120bool TextureCubeMap::isSamplerComplete(const SamplerState &samplerState) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001121{
Jamie Madilld3d2a342013-10-07 10:46:35 -04001122 int size = getBaseLevelWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001123
Jamie Madillf8989902013-07-19 16:36:58 -04001124 bool mipmapping = IsMipmapFiltered(samplerState);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001125
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001126 if (!IsTextureFilteringSupported(getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0), mRenderer))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001127 {
Jamie Madillf8989902013-07-19 16:36:58 -04001128 if (samplerState.magFilter != GL_NEAREST ||
1129 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001130 {
1131 return false;
1132 }
1133 }
1134
daniel@transgaming.comea32d482012-11-28 19:33:18 +00001135 if (!isPow2(size) && !mRenderer->getNonPower2TextureSupport())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001136 {
Jamie Madillf8989902013-07-19 16:36:58 -04001137 if (samplerState.wrapS != GL_CLAMP_TO_EDGE || samplerState.wrapT != GL_CLAMP_TO_EDGE || mipmapping)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001138 {
1139 return false;
1140 }
1141 }
1142
1143 if (!mipmapping)
1144 {
1145 if (!isCubeComplete())
1146 {
1147 return false;
1148 }
1149 }
1150 else
1151 {
1152 if (!isMipmapCubeComplete()) // Also tests for isCubeComplete()
1153 {
1154 return false;
1155 }
1156 }
1157
1158 return true;
1159}
1160
1161// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1162bool TextureCubeMap::isCubeComplete() const
1163{
Jamie Madillc1f8b162013-10-07 10:46:38 -04001164 int baseWidth = getBaseLevelWidth();
1165 int baseHeight = getBaseLevelHeight();
1166 GLenum baseFormat = getBaseLevelInternalFormat();
1167
1168 if (baseWidth <= 0 || baseWidth != baseHeight)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001169 {
1170 return false;
1171 }
1172
1173 for (unsigned int face = 1; face < 6; face++)
1174 {
Jamie Madillc1f8b162013-10-07 10:46:38 -04001175 const rx::Image &faceBaseImage = *mImageArray[face][0];
1176
1177 if (faceBaseImage.getWidth() != baseWidth ||
1178 faceBaseImage.getHeight() != baseHeight ||
1179 faceBaseImage.getInternalFormat() != baseFormat )
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001180 {
1181 return false;
1182 }
1183 }
1184
1185 return true;
1186}
1187
1188bool TextureCubeMap::isMipmapCubeComplete() const
1189{
1190 if (isImmutable())
1191 {
1192 return true;
1193 }
1194
1195 if (!isCubeComplete())
1196 {
1197 return false;
1198 }
1199
Jamie Madilld3d2a342013-10-07 10:46:35 -04001200 GLsizei size = getBaseLevelWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001201 int q = log2(size);
1202
1203 for (int face = 0; face < 6; face++)
1204 {
1205 for (int level = 1; level <= q; level++)
1206 {
Jamie Madill07edd442013-07-19 16:36:58 -04001207 if (!isFaceLevelComplete(face, level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001208 {
1209 return false;
1210 }
1211 }
1212 }
1213
1214 return true;
1215}
1216
Jamie Madill07edd442013-07-19 16:36:58 -04001217bool TextureCubeMap::isFaceLevelComplete(int face, int level) const
1218{
1219 ASSERT(level >= 0 && face < 6 && level < (int)ArraySize(mImageArray[face]) && mImageArray[face][level] != NULL);
1220
1221 if (isImmutable())
1222 {
1223 return true;
1224 }
1225
Jamie Madilld3d2a342013-10-07 10:46:35 -04001226 int baseSize = getBaseLevelWidth();
Jamie Madill07edd442013-07-19 16:36:58 -04001227
Jamie Madilld3d2a342013-10-07 10:46:35 -04001228 if (baseSize <= 0)
Jamie Madill07edd442013-07-19 16:36:58 -04001229 {
1230 return false;
1231 }
1232
Jamie Madilld3d2a342013-10-07 10:46:35 -04001233 // "isCubeComplete" checks for base level completeness and we must call that
1234 // to determine if any face at level 0 is complete. We omit that check here
1235 // to avoid re-checking cube-completeness for every face at level 0.
Jamie Madill07edd442013-07-19 16:36:58 -04001236 if (level == 0)
1237 {
1238 return true;
1239 }
1240
Jamie Madilld3d2a342013-10-07 10:46:35 -04001241 // Check that non-zero levels are consistent with the base level.
1242 const rx::Image *faceLevelImage = mImageArray[face][level];
Jamie Madill07edd442013-07-19 16:36:58 -04001243
Jamie Madilld3d2a342013-10-07 10:46:35 -04001244 if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat())
Jamie Madill07edd442013-07-19 16:36:58 -04001245 {
1246 return false;
1247 }
1248
Jamie Madilld3d2a342013-10-07 10:46:35 -04001249 if (faceLevelImage->getWidth() != std::max(1, baseSize >> level))
Jamie Madill07edd442013-07-19 16:36:58 -04001250 {
1251 return false;
1252 }
1253
1254 return true;
1255}
1256
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001257bool TextureCubeMap::isCompressed(GLenum target, GLint level) const
1258{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001259 return IsFormatCompressed(getInternalFormat(target, level), mRenderer->getCurrentClientVersion());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001260}
1261
Geoff Lang8040f572013-07-25 16:49:54 -04001262bool TextureCubeMap::isDepth(GLenum target, GLint level) const
1263{
1264 return GetDepthBits(getInternalFormat(target, level), mRenderer->getCurrentClientVersion()) > 0;
1265}
1266
daniel@transgaming.comf032cb82012-10-31 19:51:52 +00001267// Constructs a native texture resource from the texture images, or returns an existing one
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001268void TextureCubeMap::createTexture()
1269{
Jamie Madilld3d2a342013-10-07 10:46:35 -04001270 GLsizei size = getBaseLevelWidth();
daniel@transgaming.come6a09842012-09-17 21:28:55 +00001271
1272 if (!(size > 0))
daniel@transgaming.comf032cb82012-10-31 19:51:52 +00001273 return; // do not attempt to create native textures for nonexistant data
daniel@transgaming.come6a09842012-09-17 21:28:55 +00001274
sminns@adobe.comce1189b2012-09-18 20:06:35 +00001275 GLint levels = creationLevels(size);
Jamie Madilld3d2a342013-10-07 10:46:35 -04001276 GLenum internalformat = getBaseLevelInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001277
1278 delete mTexStorage;
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001279 mTexStorage = new rx::TextureStorageInterfaceCube(mRenderer, levels, internalformat, mUsage, false, size);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001280
1281 if (mTexStorage->isManaged())
1282 {
1283 int levels = levelCount();
1284
1285 for (int face = 0; face < 6; face++)
1286 {
1287 for (int level = 0; level < levels; level++)
1288 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001289 mImageArray[face][level]->setManagedSurface(mTexStorage, face, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001290 }
1291 }
1292 }
1293
1294 mDirtyImages = true;
1295}
1296
1297void TextureCubeMap::updateTexture()
1298{
Jamie Madilleb3665c2013-07-19 16:36:57 -04001299 int levels = (isMipmapCubeComplete() ? levelCount() : 1);
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +00001300
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001301 for (int face = 0; face < 6; face++)
1302 {
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001303 for (int level = 0; level < levels; level++)
1304 {
Jamie Madill07edd442013-07-19 16:36:58 -04001305 updateTextureFaceLevel(face, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001306 }
1307 }
1308}
1309
Jamie Madill07edd442013-07-19 16:36:58 -04001310void TextureCubeMap::updateTextureFaceLevel(int face, int level)
1311{
1312 ASSERT(level >= 0 && face < 6 && level < (int)ArraySize(mImageArray[face]) && mImageArray[face][level] != NULL);
1313 rx::Image *image = mImageArray[face][level];
1314
1315 if (image->isDirty())
1316 {
1317 commitRect(face, level, 0, 0, image->getWidth(), image->getHeight());
1318 }
1319}
1320
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001321void TextureCubeMap::convertToRenderTarget()
1322{
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001323 rx::TextureStorageInterfaceCube *newTexStorage = NULL;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001324
Jamie Madilld3d2a342013-10-07 10:46:35 -04001325 if (getBaseLevelWidth() != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001326 {
Jamie Madilld3d2a342013-10-07 10:46:35 -04001327 GLsizei size = getBaseLevelWidth();
shannon.woods@transgaming.com6bb48862013-02-28 23:09:34 +00001328 GLint levels = mTexStorage != NULL ? mTexStorage->levelCount() : creationLevels(size);
Jamie Madilld3d2a342013-10-07 10:46:35 -04001329 GLenum internalformat = getBaseLevelInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001330
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001331 newTexStorage = new rx::TextureStorageInterfaceCube(mRenderer, levels, internalformat, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, true, size);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001332
1333 if (mTexStorage != NULL)
1334 {
daniel@transgaming.com1d80eee2012-11-28 19:33:31 +00001335 if (!mRenderer->copyToRenderTarget(newTexStorage, mTexStorage))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001336 {
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +00001337 delete newTexStorage;
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +00001338 return gl::error(GL_OUT_OF_MEMORY);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001339 }
1340 }
1341 }
1342
1343 delete mTexStorage;
1344 mTexStorage = newTexStorage;
1345
1346 mDirtyImages = true;
1347}
1348
Jamie Madill88f18f42013-09-18 14:36:19 -04001349void 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 +00001350{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001351 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1352 GLint sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
1353 : GetSizedInternalFormat(format, type, clientVersion);
1354
1355 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001356
Jamie Madill88f18f42013-09-18 14:36:19 -04001357 Texture::setImage(unpack, type, pixels, mImageArray[faceIndex][level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001358}
1359
1360unsigned int TextureCubeMap::faceIndex(GLenum face)
1361{
1362 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
1363 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
1364 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
1365 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
1366 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
1367
1368 return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
1369}
1370
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001371void TextureCubeMap::redefineImage(int face, GLint level, GLint internalformat, GLsizei width, GLsizei height)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001372{
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001373 // If there currently is a corresponding storage texture image, it has these parameters
Jamie Madilld3d2a342013-10-07 10:46:35 -04001374 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1375 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1376 const int storageFormat = getBaseLevelInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001377
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001378 mImageArray[face][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, width, height, 1, false);
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001379
1380 if (mTexStorage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001381 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001382 const int storageLevels = mTexStorage->levelCount();
1383
1384 if ((level >= storageLevels && storageLevels != 0) ||
1385 width != storageWidth ||
1386 height != storageHeight ||
1387 internalformat != storageFormat) // Discard mismatched storage
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001388 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001389 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001390 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001391 for (int f = 0; f < 6; f++)
1392 {
1393 mImageArray[f][i]->markDirty();
1394 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001395 }
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001396
1397 delete mTexStorage;
1398 mTexStorage = NULL;
1399
1400 mDirtyImages = true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001401 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001402 }
1403}
1404
1405void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1406{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001407 unsigned int faceindex = faceIndex(target);
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001408 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1409 GLint sizedInternalFormat = IsSizedInternalFormat(format, clientVersion) ? format
1410 : GetSizedInternalFormat(format, GL_UNSIGNED_BYTE, clientVersion);
1411 redefineImage(faceindex, level, sizedInternalFormat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001412
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001413 if (!mImageArray[faceindex][level]->isRenderableFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001414 {
shannon.woods%transgaming.com@gtempaccount.come5dcce72013-04-13 03:44:33 +00001415 mImageArray[faceindex][level]->copy(0, 0, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001416 mDirtyImages = true;
1417 }
1418 else
1419 {
1420 if (!mTexStorage || !mTexStorage->isRenderTarget())
1421 {
1422 convertToRenderTarget();
1423 }
1424
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001425 mImageArray[faceindex][level]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001426
1427 ASSERT(width == height);
1428
1429 if (width > 0 && level < levelCount())
1430 {
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +00001431 gl::Rectangle sourceRect;
1432 sourceRect.x = x;
1433 sourceRect.width = width;
1434 sourceRect.y = y;
1435 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001436
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +00001437 mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001438 }
1439 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001440}
1441
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001442void 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 +00001443{
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001444 GLsizei size = mImageArray[faceIndex(target)][level]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001445
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001446 if (xoffset + width > size || yoffset + height > size || zoffset != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001447 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +00001448 return gl::error(GL_INVALID_VALUE);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001449 }
1450
Jamie Madill07edd442013-07-19 16:36:58 -04001451 unsigned int face = faceIndex(target);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001452
Jamie Madilld3d2a342013-10-07 10:46:35 -04001453 // We can only make our texture storage to a render target if the level we're copying *to* is complete
1454 // and the base level is cube-complete. The base level must be cube complete (common case) because we cannot
1455 // rely on the "getBaseLevel*" methods reliably otherwise.
1456 bool canCreateRenderTarget = isFaceLevelComplete(face, level) && isCubeComplete();
Jamie Madill07edd442013-07-19 16:36:58 -04001457
1458 if (!mImageArray[face][level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001459 {
Jamie Madill07edd442013-07-19 16:36:58 -04001460 mImageArray[face][level]->copy(0, 0, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001461 mDirtyImages = true;
1462 }
1463 else
1464 {
1465 if (!mTexStorage || !mTexStorage->isRenderTarget())
1466 {
1467 convertToRenderTarget();
1468 }
1469
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001470 if (level < levelCount())
1471 {
Jamie Madill07edd442013-07-19 16:36:58 -04001472 updateTextureFaceLevel(face, level);
1473
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001474 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1475
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +00001476 gl::Rectangle sourceRect;
1477 sourceRect.x = x;
1478 sourceRect.width = width;
1479 sourceRect.y = y;
1480 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001481
Jamie Madilld3d2a342013-10-07 10:46:35 -04001482 mRenderer->copyImage(source, sourceRect, gl::GetFormat(getBaseLevelInternalFormat(), clientVersion),
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +00001483 xoffset, yoffset, mTexStorage, target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001484 }
1485 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001486}
1487
1488void TextureCubeMap::storage(GLsizei levels, GLenum internalformat, GLsizei size)
1489{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001490 delete mTexStorage;
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001491 mTexStorage = new rx::TextureStorageInterfaceCube(mRenderer, levels, internalformat, mUsage, false, size);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001492 mImmutable = true;
1493
1494 for (int level = 0; level < levels; level++)
1495 {
Geoff Langd3110192013-09-24 11:52:47 -04001496 GLsizei mipSize = std::max(1, size >> level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001497 for (int face = 0; face < 6; face++)
1498 {
Geoff Langd3110192013-09-24 11:52:47 -04001499 mImageArray[face][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, mipSize, mipSize, 1, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001500 }
1501 }
1502
1503 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1504 {
1505 for (int face = 0; face < 6; face++)
1506 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001507 mImageArray[face][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, GL_NONE, 0, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001508 }
1509 }
1510
1511 if (mTexStorage->isManaged())
1512 {
1513 int levels = levelCount();
1514
1515 for (int face = 0; face < 6; face++)
1516 {
1517 for (int level = 0; level < levels; level++)
1518 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001519 mImageArray[face][level]->setManagedSurface(mTexStorage, face, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001520 }
1521 }
1522 }
1523}
1524
1525void TextureCubeMap::generateMipmaps()
1526{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001527 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Jamie Madilld3d2a342013-10-07 10:46:35 -04001528 unsigned int q = log2(getBaseLevelWidth());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001529 for (unsigned int f = 0; f < 6; f++)
1530 {
1531 for (unsigned int i = 1; i <= q; i++)
1532 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001533 redefineImage(f, i, mImageArray[f][0]->getInternalFormat(),
shannon.woods@transgaming.com8a406682013-02-28 23:15:26 +00001534 std::max(mImageArray[f][0]->getWidth() >> i, 1),
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001535 std::max(mImageArray[f][0]->getWidth() >> i, 1));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001536 }
1537 }
1538
1539 if (mTexStorage && mTexStorage->isRenderTarget())
1540 {
1541 for (unsigned int f = 0; f < 6; f++)
1542 {
1543 for (unsigned int i = 1; i <= q; i++)
1544 {
daniel@transgaming.com0ad830b2012-10-31 19:52:12 +00001545 mTexStorage->generateMipmap(f, i);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001546
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001547 mImageArray[f][i]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001548 }
1549 }
1550 }
1551 else
1552 {
1553 for (unsigned int f = 0; f < 6; f++)
1554 {
1555 for (unsigned int i = 1; i <= q; i++)
1556 {
daniel@transgaming.com4ba24062012-12-20 20:54:24 +00001557 mRenderer->generateMipmap(mImageArray[f][i], mImageArray[f][i - 1]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001558 }
1559 }
1560 }
1561}
1562
Jamie Madilld3d2a342013-10-07 10:46:35 -04001563const rx::Image *TextureCubeMap::getBaseLevelImage() const
1564{
1565 // Note: if we are not cube-complete, there is no single base level image that can describe all
1566 // cube faces, so this method is only well-defined for a cube-complete base level.
1567 return mImageArray[0][0];
1568}
1569
Geoff Lang8040f572013-07-25 16:49:54 -04001570Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target, GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001571{
1572 if (!IsCubemapTextureTarget(target))
1573 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +00001574 return gl::error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001575 }
1576
1577 unsigned int face = faceIndex(target);
1578
Geoff Lang8040f572013-07-25 16:49:54 -04001579 Renderbuffer *renderBuffer = mRenderbufferProxies.get(level, face);
1580 if (!renderBuffer)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001581 {
Geoff Lang8040f572013-07-25 16:49:54 -04001582 renderBuffer = new Renderbuffer(mRenderer, id(), new RenderbufferTextureCubeMap(this, target, level));
1583 mRenderbufferProxies.add(level, face, renderBuffer);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001584 }
1585
Geoff Lang8040f572013-07-25 16:49:54 -04001586 return renderBuffer;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001587}
1588
Geoff Lang8040f572013-07-25 16:49:54 -04001589unsigned int TextureCubeMap::getRenderTargetSerial(GLenum faceTarget, GLint level)
1590{
1591 if (!mTexStorage || !mTexStorage->isRenderTarget())
1592 {
1593 convertToRenderTarget();
1594 }
1595
1596 return mTexStorage ? mTexStorage->getRenderTargetSerial(faceTarget, level) : 0;
1597}
1598
1599rx::RenderTarget *TextureCubeMap::getRenderTarget(GLenum target, GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001600{
1601 ASSERT(IsCubemapTextureTarget(target));
1602
1603 // ensure the underlying texture is created
1604 if (getStorage(true) == NULL)
1605 {
1606 return NULL;
1607 }
1608
1609 updateTexture();
Geoff Lang8040f572013-07-25 16:49:54 -04001610
1611 // ensure this is NOT a depth texture
1612 if (isDepth(target, level))
1613 {
1614 return NULL;
1615 }
1616
1617 return mTexStorage->getRenderTarget(target, level);
1618}
1619
1620rx::RenderTarget *TextureCubeMap::getDepthStencil(GLenum target, GLint level)
1621{
1622 ASSERT(IsCubemapTextureTarget(target));
1623
1624 // ensure the underlying texture is created
1625 if (getStorage(true) == NULL)
1626 {
1627 return NULL;
1628 }
1629
1630 updateTexture();
1631
1632 // ensure this is a depth texture
1633 if (!isDepth(target, level))
1634 {
1635 return NULL;
1636 }
1637
1638 return mTexStorage->getRenderTarget(target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001639}
1640
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +00001641int TextureCubeMap::levelCount()
1642{
1643 return mTexStorage ? mTexStorage->levelCount() - getLodOffset() : 0;
1644}
1645
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001646rx::TextureStorageInterface *TextureCubeMap::getStorage(bool renderTarget)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001647{
1648 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
1649 {
1650 if (renderTarget)
1651 {
1652 convertToRenderTarget();
1653 }
1654 else
1655 {
1656 createTexture();
1657 }
1658 }
1659
1660 return mTexStorage;
1661}
1662
Geoff Lang4907f2c2013-07-25 12:53:57 -04001663Texture3D::Texture3D(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_3D)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001664{
1665 mTexStorage = NULL;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001666
1667 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1668 {
1669 mImageArray[i] = renderer->createImage();
1670 }
1671}
1672
1673Texture3D::~Texture3D()
1674{
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001675 delete mTexStorage;
1676 mTexStorage = NULL;
1677
1678 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1679 {
1680 delete mImageArray[i];
1681 }
1682}
1683
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001684GLsizei Texture3D::getWidth(GLint level) const
1685{
1686 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getWidth() : 0;
1687}
1688
1689GLsizei Texture3D::getHeight(GLint level) const
1690{
1691 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getHeight() : 0;
1692}
1693
1694GLsizei Texture3D::getDepth(GLint level) const
1695{
1696 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getDepth() : 0;
1697}
1698
1699GLenum Texture3D::getInternalFormat(GLint level) const
1700{
1701 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getInternalFormat() : GL_NONE;
1702}
1703
1704GLenum Texture3D::getActualFormat(GLint level) const
1705{
1706 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getActualFormat() : D3DFMT_UNKNOWN;
1707}
1708
1709bool Texture3D::isCompressed(GLint level) const
1710{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001711 return IsFormatCompressed(getInternalFormat(level), mRenderer->getCurrentClientVersion());
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001712}
1713
1714bool Texture3D::isDepth(GLint level) const
1715{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001716 return GetDepthBits(getInternalFormat(level), mRenderer->getCurrentClientVersion()) > 0;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001717}
1718
Jamie Madill88f18f42013-09-18 14:36:19 -04001719void 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 +00001720{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001721 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1722 GLint sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
1723 : GetSizedInternalFormat(format, type, clientVersion);
1724 redefineImage(level, sizedInternalFormat, width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001725
Jamie Madilla2d4e552013-10-10 15:12:01 -04001726 bool fastUnpacked = false;
1727
1728 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1729 if (isFastUnpackable(unpack, sizedInternalFormat))
1730 {
1731 // Will try to create RT storage if it does not exist
1732 rx::RenderTarget *destRenderTarget = getRenderTarget(level);
1733 Box destArea(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1734
1735 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget))
1736 {
1737 // Ensure we don't overwrite our newly initialized data
1738 mImageArray[level]->markClean();
1739
1740 fastUnpacked = true;
1741 }
1742 }
1743
1744 if (!fastUnpacked)
1745 {
1746 Texture::setImage(unpack, type, pixels, mImageArray[level]);
1747 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001748}
1749
1750void Texture3D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
1751{
1752 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1753 redefineImage(level, format, width, height, depth);
1754
1755 Texture::setCompressedImage(imageSize, pixels, mImageArray[level]);
1756}
1757
Jamie Madill88f18f42013-09-18 14:36:19 -04001758void 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 +00001759{
Jamie Madill88f18f42013-09-18 14:36:19 -04001760 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 +00001761 {
1762 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1763 }
1764}
1765
1766void Texture3D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
1767{
1768 if (Texture::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth, format, imageSize, pixels, mImageArray[level]))
1769 {
1770 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1771 }
1772}
1773
1774void Texture3D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
1775{
1776 delete mTexStorage;
1777 mTexStorage = new rx::TextureStorageInterface3D(mRenderer, levels, internalformat, mUsage, width, height, depth);
1778 mImmutable = true;
1779
1780 for (int level = 0; level < levels; level++)
1781 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001782 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, true);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001783 width = std::max(1, width >> 1);
1784 height = std::max(1, height >> 1);
1785 depth = std::max(1, depth >> 1);
1786 }
1787
1788 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1789 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001790 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, GL_NONE, 0, 0, 0, true);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001791 }
1792
1793 if (mTexStorage->isManaged())
1794 {
1795 int levels = levelCount();
1796
1797 for (int level = 0; level < levels; level++)
1798 {
1799 mImageArray[level]->setManagedSurface(mTexStorage, level);
1800 }
1801 }
1802}
1803
1804
1805void Texture3D::generateMipmaps()
1806{
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001807 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Jamie Madilld3d2a342013-10-07 10:46:35 -04001808 unsigned int q = log2(std::max(getBaseLevelWidth(), getBaseLevelHeight()));
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001809 for (unsigned int i = 1; i <= q; i++)
1810 {
Jamie Madilld3d2a342013-10-07 10:46:35 -04001811 redefineImage(i, getBaseLevelInternalFormat(),
1812 std::max(getBaseLevelWidth() >> i, 1),
1813 std::max(getBaseLevelHeight() >> i, 1),
1814 std::max(getBaseLevelDepth() >> i, 1));
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001815 }
1816
1817 if (mTexStorage && mTexStorage->isRenderTarget())
1818 {
1819 for (unsigned int i = 1; i <= q; i++)
1820 {
1821 mTexStorage->generateMipmap(i);
1822
1823 mImageArray[i]->markClean();
1824 }
1825 }
1826 else
1827 {
1828 for (unsigned int i = 1; i <= q; i++)
1829 {
1830 mRenderer->generateMipmap(mImageArray[i], mImageArray[i - 1]);
1831 }
1832 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001833}
1834
Jamie Madilld3d2a342013-10-07 10:46:35 -04001835const rx::Image *Texture3D::getBaseLevelImage() const
1836{
1837 return mImageArray[0];
1838}
1839
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001840void Texture3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1841{
1842 if (xoffset + width > mImageArray[level]->getWidth() || yoffset + height > mImageArray[level]->getHeight() || zoffset >= mImageArray[level]->getDepth())
1843 {
1844 return gl::error(GL_INVALID_VALUE);
1845 }
1846
Jamie Madill07edd442013-07-19 16:36:58 -04001847 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
1848 // the current level we're copying to is defined (with appropriate format, width & height)
1849 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
1850
1851 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001852 {
1853 mImageArray[level]->copy(xoffset, yoffset, zoffset, x, y, width, height, source);
1854 mDirtyImages = true;
1855 }
1856 else
1857 {
1858 if (!mTexStorage || !mTexStorage->isRenderTarget())
1859 {
1860 convertToRenderTarget();
1861 }
1862
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001863 if (level < levelCount())
1864 {
Jamie Madill07edd442013-07-19 16:36:58 -04001865 updateTextureLevel(level);
1866
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001867 gl::Rectangle sourceRect;
1868 sourceRect.x = x;
1869 sourceRect.width = width;
1870 sourceRect.y = y;
1871 sourceRect.height = height;
1872
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001873 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1874
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001875 mRenderer->copyImage(source, sourceRect,
Jamie Madilld3d2a342013-10-07 10:46:35 -04001876 gl::GetFormat(getBaseLevelInternalFormat(), clientVersion),
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001877 xoffset, yoffset, zoffset, mTexStorage, level);
1878 }
1879 }
1880}
1881
Jamie Madillf8989902013-07-19 16:36:58 -04001882bool Texture3D::isSamplerComplete(const SamplerState &samplerState) const
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001883{
Jamie Madilld3d2a342013-10-07 10:46:35 -04001884 GLsizei width = getBaseLevelWidth();
1885 GLsizei height = getBaseLevelHeight();
1886 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001887
1888 if (width <= 0 || height <= 0 || depth <= 0)
1889 {
1890 return false;
1891 }
1892
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001893 if (!IsTextureFilteringSupported(getInternalFormat(0), mRenderer))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001894 {
Jamie Madillf8989902013-07-19 16:36:58 -04001895 if (samplerState.magFilter != GL_NEAREST ||
1896 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001897 {
1898 return false;
1899 }
1900 }
1901
Jamie Madillf8989902013-07-19 16:36:58 -04001902 if (IsMipmapFiltered(samplerState) && !isMipmapComplete())
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001903 {
1904 return false;
1905 }
1906
1907 return true;
1908}
1909
1910bool Texture3D::isMipmapComplete() const
1911{
Jamie Madilld3d2a342013-10-07 10:46:35 -04001912 GLsizei width = getBaseLevelWidth();
1913 GLsizei height = getBaseLevelHeight();
1914 GLsizei depth = getBaseLevelDepth();
Jamie Madill07edd442013-07-19 16:36:58 -04001915
1916 int q = log2(std::max(std::max(width, height), depth));
1917
1918 for (int level = 0; level <= q; level++)
1919 {
1920 if (!isLevelComplete(level))
1921 {
1922 return false;
1923 }
1924 }
1925
1926 return true;
1927}
1928
1929bool Texture3D::isLevelComplete(int level) const
1930{
1931 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1932
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001933 if (isImmutable())
1934 {
1935 return true;
1936 }
1937
Jamie Madilld3d2a342013-10-07 10:46:35 -04001938 GLsizei width = getBaseLevelWidth();
1939 GLsizei height = getBaseLevelHeight();
1940 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001941
1942 if (width <= 0 || height <= 0 || depth <= 0)
1943 {
1944 return false;
1945 }
1946
Jamie Madill07edd442013-07-19 16:36:58 -04001947 if (level == 0)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001948 {
Jamie Madill07edd442013-07-19 16:36:58 -04001949 return true;
1950 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001951
Jamie Madill07edd442013-07-19 16:36:58 -04001952 rx::Image *levelImage = mImageArray[level];
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001953
Jamie Madilld3d2a342013-10-07 10:46:35 -04001954 if (levelImage->getInternalFormat() != getBaseLevelInternalFormat())
Jamie Madill07edd442013-07-19 16:36:58 -04001955 {
1956 return false;
1957 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001958
Jamie Madill07edd442013-07-19 16:36:58 -04001959 if (levelImage->getWidth() != std::max(1, width >> level))
1960 {
1961 return false;
1962 }
1963
1964 if (levelImage->getHeight() != std::max(1, height >> level))
1965 {
1966 return false;
1967 }
1968
1969 if (levelImage->getDepth() != std::max(1, depth >> level))
1970 {
1971 return false;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001972 }
1973
1974 return true;
1975}
1976
Geoff Lang8040f572013-07-25 16:49:54 -04001977Renderbuffer *Texture3D::getRenderbuffer(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001978{
Geoff Lang8040f572013-07-25 16:49:54 -04001979 Renderbuffer *renderBuffer = mRenderbufferProxies.get(level, layer);
1980 if (!renderBuffer)
1981 {
Geoff Langd5d8e392013-07-25 16:53:03 -04001982 renderBuffer = new Renderbuffer(mRenderer, id(), new RenderbufferTexture3DLayer(this, level, layer));
1983 mRenderbufferProxies.add(level, 0, renderBuffer);
Geoff Lang8040f572013-07-25 16:49:54 -04001984 }
1985
1986 return renderBuffer;
1987}
1988
1989unsigned int Texture3D::getRenderTargetSerial(GLint level, GLint layer)
1990{
1991 if (!mTexStorage || !mTexStorage->isRenderTarget())
1992 {
1993 convertToRenderTarget();
1994 }
1995
1996 return mTexStorage ? mTexStorage->getRenderTargetSerial(level, layer) : 0;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001997}
1998
1999int Texture3D::levelCount()
2000{
2001 return mTexStorage ? mTexStorage->levelCount() : 0;
2002}
2003
2004void Texture3D::createTexture()
2005{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002006 GLsizei width = getBaseLevelWidth();
2007 GLsizei height = getBaseLevelHeight();
2008 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002009
2010 if (!(width > 0 && height > 0 && depth > 0))
2011 return; // do not attempt to create native textures for nonexistant data
2012
2013 GLint levels = creationLevels(width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002014
2015 delete mTexStorage;
Jamie Madilld3d2a342013-10-07 10:46:35 -04002016 mTexStorage = new rx::TextureStorageInterface3D(mRenderer, levels, getBaseLevelInternalFormat(), mUsage, width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002017
2018 if (mTexStorage->isManaged())
2019 {
2020 int levels = levelCount();
2021
2022 for (int level = 0; level < levels; level++)
2023 {
2024 mImageArray[level]->setManagedSurface(mTexStorage, level);
2025 }
2026 }
2027
2028 mDirtyImages = true;
2029}
2030
2031void Texture3D::updateTexture()
2032{
Jamie Madilleb3665c2013-07-19 16:36:57 -04002033 int levels = (isMipmapComplete() ? levelCount() : 1);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002034
2035 for (int level = 0; level < levels; level++)
2036 {
Jamie Madill07edd442013-07-19 16:36:58 -04002037 updateTextureLevel(level);
2038 }
2039}
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002040
Jamie Madill07edd442013-07-19 16:36:58 -04002041void Texture3D::updateTextureLevel(int level)
2042{
2043 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
2044
2045 rx::Image *image = mImageArray[level];
2046
2047 if (image->isDirty())
2048 {
2049 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 +00002050 }
2051}
2052
2053void Texture3D::convertToRenderTarget()
2054{
2055 rx::TextureStorageInterface3D *newTexStorage = NULL;
2056
Jamie Madilld3d2a342013-10-07 10:46:35 -04002057 if (getBaseLevelWidth() != 0 && getBaseLevelHeight() != 0 && getBaseLevelDepth() != 0)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002058 {
Jamie Madilld3d2a342013-10-07 10:46:35 -04002059 GLsizei width = getBaseLevelWidth();
2060 GLsizei height = getBaseLevelHeight();
2061 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002062 GLint levels = mTexStorage != NULL ? mTexStorage->levelCount() : creationLevels(width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002063
Jamie Madilld3d2a342013-10-07 10:46:35 -04002064 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 +00002065
2066 if (mTexStorage != NULL)
2067 {
2068 if (!mRenderer->copyToRenderTarget(newTexStorage, mTexStorage))
2069 {
2070 delete newTexStorage;
2071 return gl::error(GL_OUT_OF_MEMORY);
2072 }
2073 }
2074 }
2075
2076 delete mTexStorage;
2077 mTexStorage = newTexStorage;
2078
2079 mDirtyImages = true;
2080}
2081
Jamie Madilla2d4e552013-10-10 15:12:01 -04002082rx::RenderTarget *Texture3D::getRenderTarget(GLint level)
2083{
2084 // ensure the underlying texture is created
2085 if (getStorage(true) == NULL)
2086 {
2087 return NULL;
2088 }
2089
2090 updateTexture();
2091
2092 // ensure this is NOT a depth texture
2093 if (isDepth(level))
2094 {
2095 return NULL;
2096 }
2097
2098 return mTexStorage->getRenderTarget(level);
2099}
2100
Geoff Lang8040f572013-07-25 16:49:54 -04002101rx::RenderTarget *Texture3D::getRenderTarget(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002102{
Geoff Lang8040f572013-07-25 16:49:54 -04002103 // ensure the underlying texture is created
2104 if (getStorage(true) == NULL)
2105 {
2106 return NULL;
2107 }
2108
2109 updateTexture();
2110
2111 // ensure this is NOT a depth texture
2112 if (isDepth(level))
2113 {
2114 return NULL;
2115 }
2116
2117 return mTexStorage->getRenderTarget(level, layer);
2118}
2119
2120rx::RenderTarget *Texture3D::getDepthStencil(GLint level, GLint layer)
2121{
2122 // ensure the underlying texture is created
2123 if (getStorage(true) == NULL)
2124 {
2125 return NULL;
2126 }
2127
2128 updateTexture();
2129
2130 // ensure this is a depth texture
2131 if (!isDepth(level))
2132 {
2133 return NULL;
2134 }
2135
2136 return mTexStorage->getRenderTarget(level, layer);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002137}
2138
2139rx::TextureStorageInterface *Texture3D::getStorage(bool renderTarget)
2140{
2141 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
2142 {
2143 if (renderTarget)
2144 {
2145 convertToRenderTarget();
2146 }
2147 else
2148 {
2149 createTexture();
2150 }
2151 }
2152
2153 return mTexStorage;
2154}
2155
2156void Texture3D::redefineImage(GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth)
2157{
2158 // If there currently is a corresponding storage texture image, it has these parameters
Jamie Madilld3d2a342013-10-07 10:46:35 -04002159 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2160 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
2161 const int storageDepth = std::max(1, getBaseLevelDepth() >> level);
2162 const int storageFormat = getBaseLevelInternalFormat();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002163
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00002164 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, false);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002165
2166 if (mTexStorage)
2167 {
2168 const int storageLevels = mTexStorage->levelCount();
2169
2170 if ((level >= storageLevels && storageLevels != 0) ||
2171 width != storageWidth ||
2172 height != storageHeight ||
2173 depth != storageDepth ||
2174 internalformat != storageFormat) // Discard mismatched storage
2175 {
2176 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
2177 {
2178 mImageArray[i]->markDirty();
2179 }
2180
2181 delete mTexStorage;
2182 mTexStorage = NULL;
2183 mDirtyImages = true;
2184 }
2185 }
2186}
2187
2188void Texture3D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth)
2189{
2190 if (level < levelCount())
2191 {
2192 rx::Image *image = mImageArray[level];
2193 if (image->updateSurface(mTexStorage, level, xoffset, yoffset, zoffset, width, height, depth))
2194 {
2195 image->markClean();
2196 }
2197 }
2198}
2199
Geoff Lang4907f2c2013-07-25 12:53:57 -04002200Texture2DArray::Texture2DArray(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_2D_ARRAY)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002201{
2202 mTexStorage = NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002203
2204 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2205 {
2206 mLayerCounts[level] = 0;
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002207 mImageArray[level] = NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002208 }
2209}
2210
2211Texture2DArray::~Texture2DArray()
2212{
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002213 delete mTexStorage;
2214 mTexStorage = NULL;
2215 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2216 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002217 for (int layer = 0; layer < mLayerCounts[level]; ++layer)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002218 {
2219 delete mImageArray[level][layer];
2220 }
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002221 delete[] mImageArray[level];
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002222 }
2223}
2224
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002225GLsizei Texture2DArray::getWidth(GLint level) const
2226{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002227 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 +00002228}
2229
2230GLsizei Texture2DArray::getHeight(GLint level) const
2231{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002232 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 +00002233}
2234
2235GLsizei Texture2DArray::getDepth(GLint level) const
2236{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002237 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mLayerCounts[level] : 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002238}
2239
2240GLenum Texture2DArray::getInternalFormat(GLint level) const
2241{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002242 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 +00002243}
2244
2245GLenum Texture2DArray::getActualFormat(GLint level) const
2246{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002247 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getActualFormat() : D3DFMT_UNKNOWN;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002248}
2249
2250bool Texture2DArray::isCompressed(GLint level) const
2251{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00002252 return IsFormatCompressed(getInternalFormat(level), mRenderer->getCurrentClientVersion());
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002253}
2254
2255bool Texture2DArray::isDepth(GLint level) const
2256{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00002257 return GetDepthBits(getInternalFormat(level), mRenderer->getCurrentClientVersion()) > 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002258}
2259
Jamie Madill88f18f42013-09-18 14:36:19 -04002260void 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 +00002261{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00002262 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2263 GLint sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
2264 : GetSizedInternalFormat(format, type, clientVersion);
2265 redefineImage(level, sizedInternalFormat, width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002266
Jamie Madill88f18f42013-09-18 14:36:19 -04002267 GLsizei inputDepthPitch = gl::GetDepthPitch(sizedInternalFormat, type, clientVersion, width, height, unpack.alignment);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002268
2269 for (int i = 0; i < depth; i++)
2270 {
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002271 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
Jamie Madill88f18f42013-09-18 14:36:19 -04002272 Texture::setImage(unpack, type, layerPixels, mImageArray[level][i]);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002273 }
2274}
2275
2276void Texture2DArray::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
2277{
2278 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
2279 redefineImage(level, format, width, height, depth);
2280
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002281 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2282 GLsizei inputDepthPitch = gl::GetDepthPitch(format, GL_UNSIGNED_BYTE, clientVersion, width, height, 1);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002283
2284 for (int i = 0; i < depth; i++)
2285 {
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002286 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002287 Texture::setCompressedImage(imageSize, layerPixels, mImageArray[level][i]);
2288 }
2289}
2290
Jamie Madill88f18f42013-09-18 14:36:19 -04002291void 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 +00002292{
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002293 GLint internalformat = getInternalFormat(level);
2294 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Jamie Madill88f18f42013-09-18 14:36:19 -04002295 GLsizei inputDepthPitch = gl::GetDepthPitch(internalformat, type, clientVersion, width, height, unpack.alignment);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002296
2297 for (int i = 0; i < depth; i++)
2298 {
2299 int layer = zoffset + i;
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002300 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002301
Jamie Madill88f18f42013-09-18 14:36:19 -04002302 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 +00002303 {
2304 commitRect(level, xoffset, yoffset, layer, width, height);
2305 }
2306 }
2307}
2308
2309void Texture2DArray::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
2310{
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002311 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2312 GLsizei inputDepthPitch = gl::GetDepthPitch(format, GL_UNSIGNED_BYTE, clientVersion, width, height, 1);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002313
2314 for (int i = 0; i < depth; i++)
2315 {
2316 int layer = zoffset + i;
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002317 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002318
2319 if (Texture::subImageCompressed(xoffset, yoffset, zoffset, width, height, 1, format, imageSize, layerPixels, mImageArray[level][layer]))
2320 {
2321 commitRect(level, xoffset, yoffset, layer, width, height);
2322 }
2323 }
2324}
2325
2326void Texture2DArray::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2327{
2328 delete mTexStorage;
2329 mTexStorage = new rx::TextureStorageInterface2DArray(mRenderer, levels, internalformat, mUsage, width, height, depth);
2330 mImmutable = true;
2331
2332 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2333 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002334 GLsizei levelWidth = std::max(width >> level, 1);
Geoff Lange836cf22013-08-05 14:12:37 -04002335 GLsizei levelHeight = std::max(height >> level, 1);
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002336
2337 // Clear this level
2338 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002339 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002340 delete mImageArray[level][layer];
2341 }
2342 delete[] mImageArray[level];
2343 mImageArray[level] = NULL;
2344 mLayerCounts[level] = 0;
2345
2346 if (level < levels)
2347 {
2348 // Create new images for this level
2349 mImageArray[level] = new rx::Image*[depth]();
2350 mLayerCounts[level] = depth;
2351
2352 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002353 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002354 mImageArray[level][layer] = mRenderer->createImage();
2355 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, levelWidth,
2356 levelHeight, 1, true);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002357 }
2358 }
2359 }
2360
2361 if (mTexStorage->isManaged())
2362 {
2363 int levels = levelCount();
2364
2365 for (int level = 0; level < levels; level++)
2366 {
2367 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2368 {
2369 mImageArray[level][layer]->setManagedSurface(mTexStorage, layer, level);
2370 }
2371 }
2372 }
2373}
2374
2375void Texture2DArray::generateMipmaps()
2376{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002377 int baseWidth = getBaseLevelWidth();
2378 int baseHeight = getBaseLevelHeight();
2379 int baseDepth = getBaseLevelDepth();
2380 GLenum baseFormat = getBaseLevelInternalFormat();
2381
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00002382 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Jamie Madilld3d2a342013-10-07 10:46:35 -04002383 int q = log2(std::max(baseWidth, baseHeight));
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00002384 for (int i = 1; i <= q; i++)
2385 {
Jamie Madilld3d2a342013-10-07 10:46:35 -04002386 redefineImage(i, baseFormat, std::max(baseWidth >> i, 1), std::max(baseHeight >> i, 1), baseDepth);
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00002387 }
2388
2389 if (mTexStorage && mTexStorage->isRenderTarget())
2390 {
2391 for (int level = 1; level <= q; level++)
2392 {
2393 mTexStorage->generateMipmap(level);
2394
2395 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2396 {
2397 mImageArray[level][layer]->markClean();
2398 }
2399 }
2400 }
2401 else
2402 {
2403 for (int level = 1; level <= q; level++)
2404 {
2405 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2406 {
2407 mRenderer->generateMipmap(mImageArray[level][layer], mImageArray[level - 1][layer]);
2408 }
2409 }
2410 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002411}
2412
Jamie Madilld3d2a342013-10-07 10:46:35 -04002413const rx::Image *Texture2DArray::getBaseLevelImage() const
2414{
Jamie Madill152ed092013-10-09 17:01:15 -04002415 return (mLayerCounts[0] > 0 ? mImageArray[0][0] : NULL);
Jamie Madilld3d2a342013-10-07 10:46:35 -04002416}
2417
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002418void Texture2DArray::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
2419{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002420 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 +00002421 {
2422 return gl::error(GL_INVALID_VALUE);
2423 }
2424
Jamie Madill07edd442013-07-19 16:36:58 -04002425 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
2426 // the current level we're copying to is defined (with appropriate format, width & height)
2427 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
2428
2429 if (!mImageArray[level][0]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002430 {
2431 mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, x, y, width, height, source);
2432 mDirtyImages = true;
2433 }
2434 else
2435 {
2436 if (!mTexStorage || !mTexStorage->isRenderTarget())
2437 {
2438 convertToRenderTarget();
2439 }
2440
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002441 if (level < levelCount())
2442 {
Jamie Madill07edd442013-07-19 16:36:58 -04002443 updateTextureLevel(level);
2444
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002445 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2446
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002447 gl::Rectangle sourceRect;
2448 sourceRect.x = x;
2449 sourceRect.width = width;
2450 sourceRect.y = y;
2451 sourceRect.height = height;
2452
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002453 mRenderer->copyImage(source, sourceRect, gl::GetFormat(getInternalFormat(0), clientVersion),
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002454 xoffset, yoffset, zoffset, mTexStorage, level);
2455 }
2456 }
2457}
2458
Jamie Madillf8989902013-07-19 16:36:58 -04002459bool Texture2DArray::isSamplerComplete(const SamplerState &samplerState) const
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002460{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002461 GLsizei width = getBaseLevelWidth();
2462 GLsizei height = getBaseLevelHeight();
2463 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002464
2465 if (width <= 0 || height <= 0 || depth <= 0)
2466 {
2467 return false;
2468 }
2469
Jamie Madilld3d2a342013-10-07 10:46:35 -04002470 if (!IsTextureFilteringSupported(getBaseLevelInternalFormat(), mRenderer))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002471 {
Jamie Madillf8989902013-07-19 16:36:58 -04002472 if (samplerState.magFilter != GL_NEAREST ||
2473 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002474 {
2475 return false;
2476 }
2477 }
2478
Jamie Madillf8989902013-07-19 16:36:58 -04002479 if (IsMipmapFiltered(samplerState) && !isMipmapComplete())
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002480 {
2481 return false;
2482 }
2483
2484 return true;
2485}
2486
2487bool Texture2DArray::isMipmapComplete() const
2488{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002489 GLsizei width = getBaseLevelWidth();
2490 GLsizei height = getBaseLevelHeight();
Jamie Madill07edd442013-07-19 16:36:58 -04002491
2492 int q = log2(std::max(width, height));
2493
2494 for (int level = 1; level <= q; level++)
2495 {
2496 if (!isLevelComplete(level))
2497 {
2498 return false;
2499 }
2500 }
2501
2502 return true;
2503}
2504
2505bool Texture2DArray::isLevelComplete(int level) const
2506{
2507 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
2508
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002509 if (isImmutable())
2510 {
2511 return true;
2512 }
2513
Jamie Madilld3d2a342013-10-07 10:46:35 -04002514 GLsizei width = getBaseLevelWidth();
2515 GLsizei height = getBaseLevelHeight();
2516 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002517
2518 if (width <= 0 || height <= 0 || depth <= 0)
2519 {
2520 return false;
2521 }
2522
Jamie Madill07edd442013-07-19 16:36:58 -04002523 if (level == 0)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002524 {
Jamie Madill07edd442013-07-19 16:36:58 -04002525 return true;
2526 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002527
Jamie Madill07edd442013-07-19 16:36:58 -04002528 if (getInternalFormat(level) != getInternalFormat(0))
2529 {
2530 return false;
2531 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002532
Jamie Madill07edd442013-07-19 16:36:58 -04002533 if (getWidth(level) != std::max(1, width >> level))
2534 {
2535 return false;
2536 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002537
Jamie Madill07edd442013-07-19 16:36:58 -04002538 if (getHeight(level) != std::max(1, height >> level))
2539 {
2540 return false;
2541 }
2542
2543 if (getDepth(level) != depth)
2544 {
2545 return false;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002546 }
2547
2548 return true;
2549}
2550
Geoff Lang8040f572013-07-25 16:49:54 -04002551Renderbuffer *Texture2DArray::getRenderbuffer(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002552{
Geoff Lang8040f572013-07-25 16:49:54 -04002553 Renderbuffer *renderBuffer = mRenderbufferProxies.get(level, layer);
2554 if (!renderBuffer)
2555 {
Geoff Langd5d8e392013-07-25 16:53:03 -04002556 renderBuffer = new Renderbuffer(mRenderer, id(), new RenderbufferTexture2DArrayLayer(this, level, layer));
2557 mRenderbufferProxies.add(level, 0, renderBuffer);
Geoff Lang8040f572013-07-25 16:49:54 -04002558 }
2559
2560 return renderBuffer;
2561}
2562
2563unsigned int Texture2DArray::getRenderTargetSerial( GLint level, GLint layer )
2564{
2565 if (!mTexStorage || !mTexStorage->isRenderTarget())
2566 {
2567 convertToRenderTarget();
2568 }
2569
2570 return mTexStorage ? mTexStorage->getRenderTargetSerial(level, layer) : 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002571}
2572
2573int Texture2DArray::levelCount()
2574{
2575 return mTexStorage ? mTexStorage->levelCount() : 0;
2576}
2577
2578void Texture2DArray::createTexture()
2579{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002580 GLsizei width = getBaseLevelWidth();
2581 GLsizei height = getBaseLevelHeight();
2582 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002583
2584 if (width <= 0 || height <= 0 || depth <= 0)
2585 {
2586 return; // do not attempt to create native textures for nonexistant data
2587 }
2588
2589 GLint levels = creationLevels(width, height);
Jamie Madilld3d2a342013-10-07 10:46:35 -04002590 GLenum internalformat = getBaseLevelInternalFormat();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002591
2592 delete mTexStorage;
2593 mTexStorage = new rx::TextureStorageInterface2DArray(mRenderer, levels, internalformat, mUsage, width, height, depth);
2594
2595 if (mTexStorage->isManaged())
2596 {
2597 int levels = levelCount();
2598 for (int level = 0; level < levels; level++)
2599 {
2600 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2601 {
2602 mImageArray[level][layer]->setManagedSurface(mTexStorage, layer, level);
2603 }
2604 }
2605 }
2606
2607 mDirtyImages = true;
2608}
2609
2610void Texture2DArray::updateTexture()
2611{
Jamie Madilleb3665c2013-07-19 16:36:57 -04002612 int levels = (isMipmapComplete() ? levelCount() : 1);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002613 for (int level = 0; level < levels; level++)
2614 {
Jamie Madill07edd442013-07-19 16:36:58 -04002615 updateTextureLevel(level);
2616 }
2617}
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002618
Jamie Madill07edd442013-07-19 16:36:58 -04002619void Texture2DArray::updateTextureLevel(int level)
2620{
2621 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2622 {
2623 rx::Image *image = mImageArray[level][layer];
2624
2625 if (image->isDirty())
2626 {
2627 commitRect(level, 0, 0, layer, image->getWidth(), image->getHeight());
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002628 }
2629 }
2630}
2631
2632void Texture2DArray::convertToRenderTarget()
2633{
2634 rx::TextureStorageInterface2DArray *newTexStorage = NULL;
2635
Jamie Madilld3d2a342013-10-07 10:46:35 -04002636 GLsizei width = getBaseLevelWidth();
2637 GLsizei height = getBaseLevelHeight();
2638 GLsizei depth = getBaseLevelDepth();
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002639
2640 if (width != 0 && height != 0 && depth != 0)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002641 {
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002642 GLint levels = mTexStorage != NULL ? mTexStorage->levelCount() : creationLevels(width, height);
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002643 GLenum internalformat = getInternalFormat(0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002644
2645 newTexStorage = new rx::TextureStorageInterface2DArray(mRenderer, levels, internalformat, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, width, height, depth);
2646
2647 if (mTexStorage != NULL)
2648 {
2649 if (!mRenderer->copyToRenderTarget(newTexStorage, mTexStorage))
2650 {
2651 delete newTexStorage;
2652 return gl::error(GL_OUT_OF_MEMORY);
2653 }
2654 }
2655 }
2656
2657 delete mTexStorage;
2658 mTexStorage = newTexStorage;
2659
2660 mDirtyImages = true;
2661}
2662
Geoff Lang8040f572013-07-25 16:49:54 -04002663rx::RenderTarget *Texture2DArray::getRenderTarget(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002664{
Geoff Lang8040f572013-07-25 16:49:54 -04002665 // ensure the underlying texture is created
2666 if (getStorage(true) == NULL)
2667 {
2668 return NULL;
2669 }
2670
2671 updateTexture();
2672
2673 // ensure this is NOT a depth texture
2674 if (isDepth(level))
2675 {
2676 return NULL;
2677 }
2678
2679 return mTexStorage->getRenderTarget(level, layer);
2680}
2681
2682rx::RenderTarget *Texture2DArray::getDepthStencil(GLint level, GLint layer)
2683{
2684 // ensure the underlying texture is created
2685 if (getStorage(true) == NULL)
2686 {
2687 return NULL;
2688 }
2689
2690 updateTexture();
2691
2692 // ensure this is a depth texture
2693 if (!isDepth(level))
2694 {
2695 return NULL;
2696 }
2697
2698 return mTexStorage->getRenderTarget(level, layer);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002699}
2700
2701rx::TextureStorageInterface *Texture2DArray::getStorage(bool renderTarget)
2702{
2703 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
2704 {
2705 if (renderTarget)
2706 {
2707 convertToRenderTarget();
2708 }
2709 else
2710 {
2711 createTexture();
2712 }
2713 }
2714
2715 return mTexStorage;
2716}
2717
2718void Texture2DArray::redefineImage(GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth)
2719{
2720 // If there currently is a corresponding storage texture image, it has these parameters
Jamie Madilld3d2a342013-10-07 10:46:35 -04002721 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2722 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
2723 const int storageDepth = getBaseLevelDepth();
2724 const int storageFormat = getBaseLevelInternalFormat();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002725
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002726 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002727 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002728 delete mImageArray[level][layer];
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002729 }
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002730 delete[] mImageArray[level];
Jamie Madill152ed092013-10-09 17:01:15 -04002731 mImageArray[level] = NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002732 mLayerCounts[level] = depth;
2733
Jamie Madill152ed092013-10-09 17:01:15 -04002734 if (depth > 0)
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002735 {
Jamie Madill152ed092013-10-09 17:01:15 -04002736 mImageArray[level] = new rx::Image*[depth]();
2737
2738 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2739 {
2740 mImageArray[level][layer] = mRenderer->createImage();
2741 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, width, height, 1, false);
2742 }
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002743 }
2744
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002745 if (mTexStorage)
2746 {
2747 const int storageLevels = mTexStorage->levelCount();
2748
2749 if ((level >= storageLevels && storageLevels != 0) ||
2750 width != storageWidth ||
2751 height != storageHeight ||
2752 depth != storageDepth ||
2753 internalformat != storageFormat) // Discard mismatched storage
2754 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002755 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002756 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002757 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002758 {
2759 mImageArray[level][layer]->markDirty();
2760 }
2761 }
2762
2763 delete mTexStorage;
2764 mTexStorage = NULL;
2765 mDirtyImages = true;
2766 }
2767 }
2768}
2769
2770void Texture2DArray::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint layerTarget, GLsizei width, GLsizei height)
2771{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002772 if (level < levelCount() && layerTarget < getDepth(level))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002773 {
2774 rx::Image *image = mImageArray[level][layerTarget];
2775 if (image->updateSurface(mTexStorage, level, xoffset, yoffset, layerTarget, width, height))
2776 {
2777 image->markClean();
2778 }
2779 }
2780}
2781
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00002782}