blob: f35445a7f6ec189c49e925f6658cf04388829b20 [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
Geoff Lang005df412013-10-16 14:12:50 -0400226bool Texture::isFastUnpackable(const PixelUnpackState &unpack, GLenum sizedInternalFormat)
Jamie Madill8cc7d972013-10-10 15:51:55 -0400227{
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
Geoff Lang005df412013-10-16 14:12:50 -0400410void Texture2D::redefineImage(GLint level, GLenum 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);
Geoff Lang005df412013-10-16 14:12:50 -0400417 const GLenum 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
Geoff Lang005df412013-10-16 14:12:50 -0400442void Texture2D::setImage(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000443{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +0000444 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Geoff Lang005df412013-10-16 14:12:50 -0400445 GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
446 : GetSizedInternalFormat(format, type, clientVersion);
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +0000447 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
Geoff Lang005df412013-10-16 14:12:50 -0400477 GLenum 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();
Geoff Lang005df412013-10-16 14:12:50 -0400564 GLenum sizedInternalFormat = IsSizedInternalFormat(format, clientVersion) ? format
565 : GetSizedInternalFormat(format, GL_UNSIGNED_BYTE, clientVersion);
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +0000566 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 Madilld9b9a502013-10-10 17:46:13 -0400833 int storageLevels = levelCount();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000834
Jamie Madilld9b9a502013-10-10 17:46:13 -0400835 for (int level = 0; level < storageLevels; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000836 {
Jamie Madilld9b9a502013-10-10 17:46:13 -0400837 if (isLevelComplete(level))
838 {
839 updateTextureLevel(level);
840 }
Jamie Madill07edd442013-07-19 16:36:58 -0400841 }
842}
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000843
Jamie Madill07edd442013-07-19 16:36:58 -0400844void Texture2D::updateTextureLevel(int level)
845{
846 ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
Jamie Madillaee7ad82013-10-10 16:07:32 -0400847 ASSERT(isLevelComplete(level));
Jamie Madill07edd442013-07-19 16:36:58 -0400848
Jamie Madillaee7ad82013-10-10 16:07:32 -0400849 if (mImageArray[level]->isDirty())
Jamie Madill07edd442013-07-19 16:36:58 -0400850 {
Jamie Madillaee7ad82013-10-10 16:07:32 -0400851 commitRect(level, 0, 0, getWidth(level), getHeight(level));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000852 }
853}
854
855void Texture2D::convertToRenderTarget()
856{
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000857 rx::TextureStorageInterface2D *newTexStorage = NULL;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000858
Jamie Madilld3d2a342013-10-07 10:46:35 -0400859 GLsizei width = getBaseLevelWidth();
860 GLsizei height = getBaseLevelHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000861
Jamie Madilld3d2a342013-10-07 10:46:35 -0400862 if (width != 0 && height != 0)
863 {
864 GLint levels = mTexStorage != NULL ? mTexStorage->levelCount() : creationLevels(width, height);
865
866 newTexStorage = new rx::TextureStorageInterface2D(mRenderer, levels, getBaseLevelInternalFormat(), GL_FRAMEBUFFER_ATTACHMENT_ANGLE, true, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000867
868 if (mTexStorage != NULL)
869 {
daniel@transgaming.com1d80eee2012-11-28 19:33:31 +0000870 if (!mRenderer->copyToRenderTarget(newTexStorage, mTexStorage))
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +0000871 {
872 delete newTexStorage;
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +0000873 return gl::error(GL_OUT_OF_MEMORY);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000874 }
875 }
876 }
877
878 delete mTexStorage;
879 mTexStorage = newTexStorage;
880
881 mDirtyImages = true;
882}
883
884void Texture2D::generateMipmaps()
885{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000886 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Jamie Madilld3d2a342013-10-07 10:46:35 -0400887 unsigned int q = log2(std::max(getBaseLevelWidth(), getBaseLevelHeight()));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000888 for (unsigned int i = 1; i <= q; i++)
889 {
Jamie Madilld3d2a342013-10-07 10:46:35 -0400890 redefineImage(i, getBaseLevelInternalFormat(),
891 std::max(getBaseLevelWidth() >> i, 1),
892 std::max(getBaseLevelHeight() >> i, 1));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000893 }
894
895 if (mTexStorage && mTexStorage->isRenderTarget())
896 {
897 for (unsigned int i = 1; i <= q; i++)
898 {
daniel@transgaming.com0ad830b2012-10-31 19:52:12 +0000899 mTexStorage->generateMipmap(i);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000900
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000901 mImageArray[i]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000902 }
903 }
904 else
905 {
906 for (unsigned int i = 1; i <= q; i++)
907 {
daniel@transgaming.com4ba24062012-12-20 20:54:24 +0000908 mRenderer->generateMipmap(mImageArray[i], mImageArray[i - 1]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000909 }
910 }
911}
912
Jamie Madilld3d2a342013-10-07 10:46:35 -0400913const rx::Image *Texture2D::getBaseLevelImage() const
914{
915 return mImageArray[0];
916}
917
Geoff Lang8040f572013-07-25 16:49:54 -0400918Renderbuffer *Texture2D::getRenderbuffer(GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000919{
Geoff Lang8040f572013-07-25 16:49:54 -0400920 Renderbuffer *renderBuffer = mRenderbufferProxies.get(level, 0);
921 if (!renderBuffer)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000922 {
Geoff Lang8040f572013-07-25 16:49:54 -0400923 renderBuffer = new Renderbuffer(mRenderer, id(), new RenderbufferTexture2D(this, level));
924 mRenderbufferProxies.add(level, 0, renderBuffer);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000925 }
926
Geoff Lang8040f572013-07-25 16:49:54 -0400927 return renderBuffer;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000928}
929
Geoff Lang8040f572013-07-25 16:49:54 -0400930unsigned int Texture2D::getRenderTargetSerial(GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000931{
Geoff Lang8040f572013-07-25 16:49:54 -0400932 if (!mTexStorage || !mTexStorage->isRenderTarget())
933 {
934 convertToRenderTarget();
935 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000936
Geoff Lang8040f572013-07-25 16:49:54 -0400937 return mTexStorage ? mTexStorage->getRenderTargetSerial(level) : 0;
938}
939
940rx::RenderTarget *Texture2D::getRenderTarget(GLint level)
941{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000942 // ensure the underlying texture is created
943 if (getStorage(true) == NULL)
944 {
945 return NULL;
946 }
947
Jamie Madillaee7ad82013-10-10 16:07:32 -0400948 updateTextureLevel(level);
Geoff Lang8040f572013-07-25 16:49:54 -0400949
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000950 // ensure this is NOT a depth texture
Geoff Lang8040f572013-07-25 16:49:54 -0400951 if (isDepth(level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000952 {
953 return NULL;
954 }
daniel@transgaming.com34da3972012-12-20 21:10:29 +0000955
Geoff Lang8040f572013-07-25 16:49:54 -0400956 return mTexStorage->getRenderTarget(level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000957}
958
Geoff Lang8040f572013-07-25 16:49:54 -0400959rx::RenderTarget *Texture2D::getDepthSencil(GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000960{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000961 // ensure the underlying texture is created
962 if (getStorage(true) == NULL)
963 {
964 return NULL;
965 }
966
Jamie Madillaee7ad82013-10-10 16:07:32 -0400967 updateTextureLevel(level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000968
969 // ensure this is actually a depth texture
Geoff Lang8040f572013-07-25 16:49:54 -0400970 if (!isDepth(level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000971 {
972 return NULL;
973 }
Geoff Lang8040f572013-07-25 16:49:54 -0400974
975 return mTexStorage->getRenderTarget(level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000976}
977
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +0000978int Texture2D::levelCount()
979{
shannon.woods@transgaming.com5016f8e2013-02-28 23:20:57 +0000980 return mTexStorage ? mTexStorage->levelCount() : 0;
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +0000981}
982
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000983rx::TextureStorageInterface *Texture2D::getStorage(bool renderTarget)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000984{
985 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
986 {
987 if (renderTarget)
988 {
989 convertToRenderTarget();
990 }
991 else
992 {
993 createTexture();
994 }
995 }
996
997 return mTexStorage;
998}
999
Geoff Lang4907f2c2013-07-25 12:53:57 -04001000TextureCubeMap::TextureCubeMap(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_CUBE_MAP)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001001{
1002 mTexStorage = NULL;
1003 for (int i = 0; i < 6; i++)
1004 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001005 for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
1006 {
daniel@transgaming.com244e1832012-12-20 20:52:35 +00001007 mImageArray[i][j] = renderer->createImage();
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001008 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001009 }
1010}
1011
1012TextureCubeMap::~TextureCubeMap()
1013{
1014 for (int i = 0; i < 6; i++)
1015 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001016 for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
1017 {
1018 delete mImageArray[i][j];
1019 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001020 }
1021
1022 delete mTexStorage;
1023 mTexStorage = NULL;
1024}
1025
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001026GLsizei TextureCubeMap::getWidth(GLenum target, GLint level) const
1027{
1028 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001029 return mImageArray[faceIndex(target)][level]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001030 else
1031 return 0;
1032}
1033
1034GLsizei TextureCubeMap::getHeight(GLenum target, GLint level) const
1035{
1036 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001037 return mImageArray[faceIndex(target)][level]->getHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001038 else
1039 return 0;
1040}
1041
1042GLenum TextureCubeMap::getInternalFormat(GLenum target, GLint level) const
1043{
1044 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001045 return mImageArray[faceIndex(target)][level]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001046 else
1047 return GL_NONE;
1048}
1049
daniel@transgaming.com20d36662012-10-31 19:51:43 +00001050GLenum TextureCubeMap::getActualFormat(GLenum target, GLint level) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001051{
1052 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001053 return mImageArray[faceIndex(target)][level]->getActualFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001054 else
1055 return D3DFMT_UNKNOWN;
1056}
1057
Geoff Lang005df412013-10-16 14:12:50 -04001058void TextureCubeMap::setImagePosX(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001059{
Jamie Madill88f18f42013-09-18 14:36:19 -04001060 setImage(0, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001061}
1062
Geoff Lang005df412013-10-16 14:12:50 -04001063void TextureCubeMap::setImageNegX(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001064{
Jamie Madill88f18f42013-09-18 14:36:19 -04001065 setImage(1, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001066}
1067
Geoff Lang005df412013-10-16 14:12:50 -04001068void TextureCubeMap::setImagePosY(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001069{
Jamie Madill88f18f42013-09-18 14:36:19 -04001070 setImage(2, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001071}
1072
Geoff Lang005df412013-10-16 14:12:50 -04001073void TextureCubeMap::setImageNegY(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001074{
Jamie Madill88f18f42013-09-18 14:36:19 -04001075 setImage(3, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001076}
1077
Geoff Lang005df412013-10-16 14:12:50 -04001078void TextureCubeMap::setImagePosZ(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001079{
Jamie Madill88f18f42013-09-18 14:36:19 -04001080 setImage(4, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001081}
1082
Geoff Lang005df412013-10-16 14:12:50 -04001083void TextureCubeMap::setImageNegZ(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001084{
Jamie Madill88f18f42013-09-18 14:36:19 -04001085 setImage(5, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001086}
1087
1088void TextureCubeMap::setCompressedImage(GLenum face, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
1089{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001090 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001091 redefineImage(faceIndex(face), level, format, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001092
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001093 Texture::setCompressedImage(imageSize, pixels, mImageArray[faceIndex(face)][level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001094}
1095
1096void TextureCubeMap::commitRect(int face, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1097{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001098 if (level < levelCount())
1099 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001100 rx::Image *image = mImageArray[face][level];
daniel@transgaming.com0f195ad2012-10-31 19:51:59 +00001101 if (image->updateSurface(mTexStorage, face, level, xoffset, yoffset, width, height))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001102 image->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001103 }
1104}
1105
Jamie Madill88f18f42013-09-18 14:36:19 -04001106void 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 +00001107{
Jamie Madill88f18f42013-09-18 14:36:19 -04001108 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 +00001109 {
1110 commitRect(faceIndex(target), level, xoffset, yoffset, width, height);
1111 }
1112}
1113
1114void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1115{
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +00001116 if (Texture::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[faceIndex(target)][level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001117 {
1118 commitRect(faceIndex(target), level, xoffset, yoffset, width, height);
1119 }
1120}
1121
1122// Tests for cube map sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 86.
Jamie Madillf8989902013-07-19 16:36:58 -04001123bool TextureCubeMap::isSamplerComplete(const SamplerState &samplerState) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001124{
Jamie Madilld3d2a342013-10-07 10:46:35 -04001125 int size = getBaseLevelWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001126
Jamie Madillf8989902013-07-19 16:36:58 -04001127 bool mipmapping = IsMipmapFiltered(samplerState);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001128
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001129 if (!IsTextureFilteringSupported(getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0), mRenderer))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001130 {
Jamie Madillf8989902013-07-19 16:36:58 -04001131 if (samplerState.magFilter != GL_NEAREST ||
1132 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001133 {
1134 return false;
1135 }
1136 }
1137
daniel@transgaming.comea32d482012-11-28 19:33:18 +00001138 if (!isPow2(size) && !mRenderer->getNonPower2TextureSupport())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001139 {
Jamie Madillf8989902013-07-19 16:36:58 -04001140 if (samplerState.wrapS != GL_CLAMP_TO_EDGE || samplerState.wrapT != GL_CLAMP_TO_EDGE || mipmapping)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001141 {
1142 return false;
1143 }
1144 }
1145
1146 if (!mipmapping)
1147 {
1148 if (!isCubeComplete())
1149 {
1150 return false;
1151 }
1152 }
1153 else
1154 {
1155 if (!isMipmapCubeComplete()) // Also tests for isCubeComplete()
1156 {
1157 return false;
1158 }
1159 }
1160
1161 return true;
1162}
1163
1164// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1165bool TextureCubeMap::isCubeComplete() const
1166{
Jamie Madillc1f8b162013-10-07 10:46:38 -04001167 int baseWidth = getBaseLevelWidth();
1168 int baseHeight = getBaseLevelHeight();
1169 GLenum baseFormat = getBaseLevelInternalFormat();
1170
1171 if (baseWidth <= 0 || baseWidth != baseHeight)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001172 {
1173 return false;
1174 }
1175
1176 for (unsigned int face = 1; face < 6; face++)
1177 {
Jamie Madillc1f8b162013-10-07 10:46:38 -04001178 const rx::Image &faceBaseImage = *mImageArray[face][0];
1179
1180 if (faceBaseImage.getWidth() != baseWidth ||
1181 faceBaseImage.getHeight() != baseHeight ||
1182 faceBaseImage.getInternalFormat() != baseFormat )
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001183 {
1184 return false;
1185 }
1186 }
1187
1188 return true;
1189}
1190
1191bool TextureCubeMap::isMipmapCubeComplete() const
1192{
1193 if (isImmutable())
1194 {
1195 return true;
1196 }
1197
1198 if (!isCubeComplete())
1199 {
1200 return false;
1201 }
1202
Jamie Madilld3d2a342013-10-07 10:46:35 -04001203 GLsizei size = getBaseLevelWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001204 int q = log2(size);
1205
1206 for (int face = 0; face < 6; face++)
1207 {
1208 for (int level = 1; level <= q; level++)
1209 {
Jamie Madill07edd442013-07-19 16:36:58 -04001210 if (!isFaceLevelComplete(face, level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001211 {
1212 return false;
1213 }
1214 }
1215 }
1216
1217 return true;
1218}
1219
Jamie Madill07edd442013-07-19 16:36:58 -04001220bool TextureCubeMap::isFaceLevelComplete(int face, int level) const
1221{
1222 ASSERT(level >= 0 && face < 6 && level < (int)ArraySize(mImageArray[face]) && mImageArray[face][level] != NULL);
1223
1224 if (isImmutable())
1225 {
1226 return true;
1227 }
1228
Jamie Madilld3d2a342013-10-07 10:46:35 -04001229 int baseSize = getBaseLevelWidth();
Jamie Madill07edd442013-07-19 16:36:58 -04001230
Jamie Madilld3d2a342013-10-07 10:46:35 -04001231 if (baseSize <= 0)
Jamie Madill07edd442013-07-19 16:36:58 -04001232 {
1233 return false;
1234 }
1235
Jamie Madilld3d2a342013-10-07 10:46:35 -04001236 // "isCubeComplete" checks for base level completeness and we must call that
1237 // to determine if any face at level 0 is complete. We omit that check here
1238 // to avoid re-checking cube-completeness for every face at level 0.
Jamie Madill07edd442013-07-19 16:36:58 -04001239 if (level == 0)
1240 {
1241 return true;
1242 }
1243
Jamie Madilld3d2a342013-10-07 10:46:35 -04001244 // Check that non-zero levels are consistent with the base level.
1245 const rx::Image *faceLevelImage = mImageArray[face][level];
Jamie Madill07edd442013-07-19 16:36:58 -04001246
Jamie Madilld3d2a342013-10-07 10:46:35 -04001247 if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat())
Jamie Madill07edd442013-07-19 16:36:58 -04001248 {
1249 return false;
1250 }
1251
Jamie Madilld3d2a342013-10-07 10:46:35 -04001252 if (faceLevelImage->getWidth() != std::max(1, baseSize >> level))
Jamie Madill07edd442013-07-19 16:36:58 -04001253 {
1254 return false;
1255 }
1256
1257 return true;
1258}
1259
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001260bool TextureCubeMap::isCompressed(GLenum target, GLint level) const
1261{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001262 return IsFormatCompressed(getInternalFormat(target, level), mRenderer->getCurrentClientVersion());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001263}
1264
Geoff Lang8040f572013-07-25 16:49:54 -04001265bool TextureCubeMap::isDepth(GLenum target, GLint level) const
1266{
1267 return GetDepthBits(getInternalFormat(target, level), mRenderer->getCurrentClientVersion()) > 0;
1268}
1269
daniel@transgaming.comf032cb82012-10-31 19:51:52 +00001270// Constructs a native texture resource from the texture images, or returns an existing one
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001271void TextureCubeMap::createTexture()
1272{
Jamie Madilld3d2a342013-10-07 10:46:35 -04001273 GLsizei size = getBaseLevelWidth();
daniel@transgaming.come6a09842012-09-17 21:28:55 +00001274
1275 if (!(size > 0))
daniel@transgaming.comf032cb82012-10-31 19:51:52 +00001276 return; // do not attempt to create native textures for nonexistant data
daniel@transgaming.come6a09842012-09-17 21:28:55 +00001277
sminns@adobe.comce1189b2012-09-18 20:06:35 +00001278 GLint levels = creationLevels(size);
Jamie Madilld3d2a342013-10-07 10:46:35 -04001279 GLenum internalformat = getBaseLevelInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001280
1281 delete mTexStorage;
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001282 mTexStorage = new rx::TextureStorageInterfaceCube(mRenderer, levels, internalformat, mUsage, false, size);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001283
1284 if (mTexStorage->isManaged())
1285 {
1286 int levels = levelCount();
1287
1288 for (int face = 0; face < 6; face++)
1289 {
1290 for (int level = 0; level < levels; level++)
1291 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001292 mImageArray[face][level]->setManagedSurface(mTexStorage, face, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001293 }
1294 }
1295 }
1296
1297 mDirtyImages = true;
1298}
1299
1300void TextureCubeMap::updateTexture()
1301{
Jamie Madilld9b9a502013-10-10 17:46:13 -04001302 int storageLevels = levelCount();
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +00001303
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001304 for (int face = 0; face < 6; face++)
1305 {
Jamie Madilld9b9a502013-10-10 17:46:13 -04001306 for (int level = 0; level < storageLevels; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001307 {
Jamie Madilld9b9a502013-10-10 17:46:13 -04001308 if (isFaceLevelComplete(face, level))
1309 {
1310 updateTextureFaceLevel(face, level);
1311 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001312 }
1313 }
1314}
1315
Jamie Madill07edd442013-07-19 16:36:58 -04001316void TextureCubeMap::updateTextureFaceLevel(int face, int level)
1317{
1318 ASSERT(level >= 0 && face < 6 && level < (int)ArraySize(mImageArray[face]) && mImageArray[face][level] != NULL);
1319 rx::Image *image = mImageArray[face][level];
1320
1321 if (image->isDirty())
1322 {
1323 commitRect(face, level, 0, 0, image->getWidth(), image->getHeight());
1324 }
1325}
1326
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001327void TextureCubeMap::convertToRenderTarget()
1328{
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001329 rx::TextureStorageInterfaceCube *newTexStorage = NULL;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001330
Jamie Madilld3d2a342013-10-07 10:46:35 -04001331 if (getBaseLevelWidth() != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001332 {
Jamie Madilld3d2a342013-10-07 10:46:35 -04001333 GLsizei size = getBaseLevelWidth();
shannon.woods@transgaming.com6bb48862013-02-28 23:09:34 +00001334 GLint levels = mTexStorage != NULL ? mTexStorage->levelCount() : creationLevels(size);
Jamie Madilld3d2a342013-10-07 10:46:35 -04001335 GLenum internalformat = getBaseLevelInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001336
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001337 newTexStorage = new rx::TextureStorageInterfaceCube(mRenderer, levels, internalformat, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, true, size);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001338
1339 if (mTexStorage != NULL)
1340 {
daniel@transgaming.com1d80eee2012-11-28 19:33:31 +00001341 if (!mRenderer->copyToRenderTarget(newTexStorage, mTexStorage))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001342 {
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +00001343 delete newTexStorage;
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +00001344 return gl::error(GL_OUT_OF_MEMORY);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001345 }
1346 }
1347 }
1348
1349 delete mTexStorage;
1350 mTexStorage = newTexStorage;
1351
1352 mDirtyImages = true;
1353}
1354
Geoff Lang005df412013-10-16 14:12:50 -04001355void TextureCubeMap::setImage(int faceIndex, GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001356{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001357 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Geoff Lang005df412013-10-16 14:12:50 -04001358 GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
1359 : GetSizedInternalFormat(format, type, clientVersion);
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001360
1361 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001362
Jamie Madill88f18f42013-09-18 14:36:19 -04001363 Texture::setImage(unpack, type, pixels, mImageArray[faceIndex][level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001364}
1365
1366unsigned int TextureCubeMap::faceIndex(GLenum face)
1367{
1368 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
1369 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
1370 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
1371 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
1372 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
1373
1374 return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
1375}
1376
Geoff Lang005df412013-10-16 14:12:50 -04001377void TextureCubeMap::redefineImage(int face, GLint level, GLenum internalformat, GLsizei width, GLsizei height)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001378{
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001379 // If there currently is a corresponding storage texture image, it has these parameters
Jamie Madilld3d2a342013-10-07 10:46:35 -04001380 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1381 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
Geoff Lang005df412013-10-16 14:12:50 -04001382 const GLenum storageFormat = getBaseLevelInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001383
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001384 mImageArray[face][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, width, height, 1, false);
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001385
1386 if (mTexStorage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001387 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001388 const int storageLevels = mTexStorage->levelCount();
1389
1390 if ((level >= storageLevels && storageLevels != 0) ||
1391 width != storageWidth ||
1392 height != storageHeight ||
1393 internalformat != storageFormat) // Discard mismatched storage
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001394 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001395 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001396 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001397 for (int f = 0; f < 6; f++)
1398 {
1399 mImageArray[f][i]->markDirty();
1400 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001401 }
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001402
1403 delete mTexStorage;
1404 mTexStorage = NULL;
1405
1406 mDirtyImages = true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001407 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001408 }
1409}
1410
1411void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1412{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001413 unsigned int faceindex = faceIndex(target);
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001414 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Geoff Lang005df412013-10-16 14:12:50 -04001415 GLenum sizedInternalFormat = IsSizedInternalFormat(format, clientVersion) ? format
1416 : GetSizedInternalFormat(format, GL_UNSIGNED_BYTE, clientVersion);
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001417 redefineImage(faceindex, level, sizedInternalFormat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001418
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001419 if (!mImageArray[faceindex][level]->isRenderableFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001420 {
shannon.woods%transgaming.com@gtempaccount.come5dcce72013-04-13 03:44:33 +00001421 mImageArray[faceindex][level]->copy(0, 0, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001422 mDirtyImages = true;
1423 }
1424 else
1425 {
1426 if (!mTexStorage || !mTexStorage->isRenderTarget())
1427 {
1428 convertToRenderTarget();
1429 }
1430
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001431 mImageArray[faceindex][level]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001432
1433 ASSERT(width == height);
1434
1435 if (width > 0 && level < levelCount())
1436 {
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +00001437 gl::Rectangle sourceRect;
1438 sourceRect.x = x;
1439 sourceRect.width = width;
1440 sourceRect.y = y;
1441 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001442
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +00001443 mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001444 }
1445 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001446}
1447
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001448void 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 +00001449{
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001450 GLsizei size = mImageArray[faceIndex(target)][level]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001451
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001452 if (xoffset + width > size || yoffset + height > size || zoffset != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001453 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +00001454 return gl::error(GL_INVALID_VALUE);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001455 }
1456
Jamie Madill07edd442013-07-19 16:36:58 -04001457 unsigned int face = faceIndex(target);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001458
Jamie Madilld3d2a342013-10-07 10:46:35 -04001459 // We can only make our texture storage to a render target if the level we're copying *to* is complete
1460 // and the base level is cube-complete. The base level must be cube complete (common case) because we cannot
1461 // rely on the "getBaseLevel*" methods reliably otherwise.
1462 bool canCreateRenderTarget = isFaceLevelComplete(face, level) && isCubeComplete();
Jamie Madill07edd442013-07-19 16:36:58 -04001463
1464 if (!mImageArray[face][level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001465 {
Jamie Madill07edd442013-07-19 16:36:58 -04001466 mImageArray[face][level]->copy(0, 0, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001467 mDirtyImages = true;
1468 }
1469 else
1470 {
1471 if (!mTexStorage || !mTexStorage->isRenderTarget())
1472 {
1473 convertToRenderTarget();
1474 }
1475
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001476 if (level < levelCount())
1477 {
Jamie Madill07edd442013-07-19 16:36:58 -04001478 updateTextureFaceLevel(face, level);
1479
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001480 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1481
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +00001482 gl::Rectangle sourceRect;
1483 sourceRect.x = x;
1484 sourceRect.width = width;
1485 sourceRect.y = y;
1486 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001487
Jamie Madilld3d2a342013-10-07 10:46:35 -04001488 mRenderer->copyImage(source, sourceRect, gl::GetFormat(getBaseLevelInternalFormat(), clientVersion),
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +00001489 xoffset, yoffset, mTexStorage, target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001490 }
1491 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001492}
1493
1494void TextureCubeMap::storage(GLsizei levels, GLenum internalformat, GLsizei size)
1495{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001496 delete mTexStorage;
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001497 mTexStorage = new rx::TextureStorageInterfaceCube(mRenderer, levels, internalformat, mUsage, false, size);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001498 mImmutable = true;
1499
1500 for (int level = 0; level < levels; level++)
1501 {
Geoff Langd3110192013-09-24 11:52:47 -04001502 GLsizei mipSize = std::max(1, size >> level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001503 for (int face = 0; face < 6; face++)
1504 {
Geoff Langd3110192013-09-24 11:52:47 -04001505 mImageArray[face][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, mipSize, mipSize, 1, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001506 }
1507 }
1508
1509 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1510 {
1511 for (int face = 0; face < 6; face++)
1512 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001513 mImageArray[face][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, GL_NONE, 0, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001514 }
1515 }
1516
1517 if (mTexStorage->isManaged())
1518 {
1519 int levels = levelCount();
1520
1521 for (int face = 0; face < 6; face++)
1522 {
1523 for (int level = 0; level < levels; level++)
1524 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001525 mImageArray[face][level]->setManagedSurface(mTexStorage, face, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001526 }
1527 }
1528 }
1529}
1530
1531void TextureCubeMap::generateMipmaps()
1532{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001533 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Jamie Madilld3d2a342013-10-07 10:46:35 -04001534 unsigned int q = log2(getBaseLevelWidth());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001535 for (unsigned int f = 0; f < 6; f++)
1536 {
1537 for (unsigned int i = 1; i <= q; i++)
1538 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001539 redefineImage(f, i, mImageArray[f][0]->getInternalFormat(),
shannon.woods@transgaming.com8a406682013-02-28 23:15:26 +00001540 std::max(mImageArray[f][0]->getWidth() >> i, 1),
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001541 std::max(mImageArray[f][0]->getWidth() >> i, 1));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001542 }
1543 }
1544
1545 if (mTexStorage && mTexStorage->isRenderTarget())
1546 {
1547 for (unsigned int f = 0; f < 6; f++)
1548 {
1549 for (unsigned int i = 1; i <= q; i++)
1550 {
daniel@transgaming.com0ad830b2012-10-31 19:52:12 +00001551 mTexStorage->generateMipmap(f, i);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001552
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001553 mImageArray[f][i]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001554 }
1555 }
1556 }
1557 else
1558 {
1559 for (unsigned int f = 0; f < 6; f++)
1560 {
1561 for (unsigned int i = 1; i <= q; i++)
1562 {
daniel@transgaming.com4ba24062012-12-20 20:54:24 +00001563 mRenderer->generateMipmap(mImageArray[f][i], mImageArray[f][i - 1]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001564 }
1565 }
1566 }
1567}
1568
Jamie Madilld3d2a342013-10-07 10:46:35 -04001569const rx::Image *TextureCubeMap::getBaseLevelImage() const
1570{
1571 // Note: if we are not cube-complete, there is no single base level image that can describe all
1572 // cube faces, so this method is only well-defined for a cube-complete base level.
1573 return mImageArray[0][0];
1574}
1575
Geoff Lang8040f572013-07-25 16:49:54 -04001576Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target, GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001577{
1578 if (!IsCubemapTextureTarget(target))
1579 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +00001580 return gl::error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001581 }
1582
1583 unsigned int face = faceIndex(target);
1584
Geoff Lang8040f572013-07-25 16:49:54 -04001585 Renderbuffer *renderBuffer = mRenderbufferProxies.get(level, face);
1586 if (!renderBuffer)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001587 {
Geoff Lang8040f572013-07-25 16:49:54 -04001588 renderBuffer = new Renderbuffer(mRenderer, id(), new RenderbufferTextureCubeMap(this, target, level));
1589 mRenderbufferProxies.add(level, face, renderBuffer);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001590 }
1591
Geoff Lang8040f572013-07-25 16:49:54 -04001592 return renderBuffer;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001593}
1594
Geoff Lang8040f572013-07-25 16:49:54 -04001595unsigned int TextureCubeMap::getRenderTargetSerial(GLenum faceTarget, GLint level)
1596{
1597 if (!mTexStorage || !mTexStorage->isRenderTarget())
1598 {
1599 convertToRenderTarget();
1600 }
1601
1602 return mTexStorage ? mTexStorage->getRenderTargetSerial(faceTarget, level) : 0;
1603}
1604
1605rx::RenderTarget *TextureCubeMap::getRenderTarget(GLenum target, GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001606{
1607 ASSERT(IsCubemapTextureTarget(target));
1608
1609 // ensure the underlying texture is created
1610 if (getStorage(true) == NULL)
1611 {
1612 return NULL;
1613 }
1614
Jamie Madillaee7ad82013-10-10 16:07:32 -04001615 updateTextureFaceLevel(faceIndex(target), level);
Geoff Lang8040f572013-07-25 16:49:54 -04001616
1617 // ensure this is NOT a depth texture
1618 if (isDepth(target, level))
1619 {
1620 return NULL;
1621 }
1622
1623 return mTexStorage->getRenderTarget(target, level);
1624}
1625
1626rx::RenderTarget *TextureCubeMap::getDepthStencil(GLenum target, GLint level)
1627{
1628 ASSERT(IsCubemapTextureTarget(target));
1629
1630 // ensure the underlying texture is created
1631 if (getStorage(true) == NULL)
1632 {
1633 return NULL;
1634 }
1635
Jamie Madillaee7ad82013-10-10 16:07:32 -04001636 updateTextureFaceLevel(faceIndex(target), level);
Geoff Lang8040f572013-07-25 16:49:54 -04001637
1638 // ensure this is a depth texture
1639 if (!isDepth(target, level))
1640 {
1641 return NULL;
1642 }
1643
1644 return mTexStorage->getRenderTarget(target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001645}
1646
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +00001647int TextureCubeMap::levelCount()
1648{
1649 return mTexStorage ? mTexStorage->levelCount() - getLodOffset() : 0;
1650}
1651
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001652rx::TextureStorageInterface *TextureCubeMap::getStorage(bool renderTarget)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001653{
1654 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
1655 {
1656 if (renderTarget)
1657 {
1658 convertToRenderTarget();
1659 }
1660 else
1661 {
1662 createTexture();
1663 }
1664 }
1665
1666 return mTexStorage;
1667}
1668
Geoff Lang4907f2c2013-07-25 12:53:57 -04001669Texture3D::Texture3D(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_3D)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001670{
1671 mTexStorage = NULL;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001672
1673 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1674 {
1675 mImageArray[i] = renderer->createImage();
1676 }
1677}
1678
1679Texture3D::~Texture3D()
1680{
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001681 delete mTexStorage;
1682 mTexStorage = NULL;
1683
1684 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1685 {
1686 delete mImageArray[i];
1687 }
1688}
1689
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001690GLsizei Texture3D::getWidth(GLint level) const
1691{
1692 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getWidth() : 0;
1693}
1694
1695GLsizei Texture3D::getHeight(GLint level) const
1696{
1697 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getHeight() : 0;
1698}
1699
1700GLsizei Texture3D::getDepth(GLint level) const
1701{
1702 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getDepth() : 0;
1703}
1704
1705GLenum Texture3D::getInternalFormat(GLint level) const
1706{
1707 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getInternalFormat() : GL_NONE;
1708}
1709
1710GLenum Texture3D::getActualFormat(GLint level) const
1711{
1712 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getActualFormat() : D3DFMT_UNKNOWN;
1713}
1714
1715bool Texture3D::isCompressed(GLint level) const
1716{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001717 return IsFormatCompressed(getInternalFormat(level), mRenderer->getCurrentClientVersion());
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001718}
1719
1720bool Texture3D::isDepth(GLint level) const
1721{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001722 return GetDepthBits(getInternalFormat(level), mRenderer->getCurrentClientVersion()) > 0;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001723}
1724
Geoff Lang005df412013-10-16 14:12:50 -04001725void Texture3D::setImage(GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001726{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001727 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Geoff Lang005df412013-10-16 14:12:50 -04001728 GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
1729 : GetSizedInternalFormat(format, type, clientVersion);
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001730 redefineImage(level, sizedInternalFormat, width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001731
Jamie Madilla2d4e552013-10-10 15:12:01 -04001732 bool fastUnpacked = false;
1733
1734 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1735 if (isFastUnpackable(unpack, sizedInternalFormat))
1736 {
1737 // Will try to create RT storage if it does not exist
1738 rx::RenderTarget *destRenderTarget = getRenderTarget(level);
1739 Box destArea(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1740
1741 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget))
1742 {
1743 // Ensure we don't overwrite our newly initialized data
1744 mImageArray[level]->markClean();
1745
1746 fastUnpacked = true;
1747 }
1748 }
1749
1750 if (!fastUnpacked)
1751 {
1752 Texture::setImage(unpack, type, pixels, mImageArray[level]);
1753 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001754}
1755
1756void Texture3D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
1757{
1758 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1759 redefineImage(level, format, width, height, depth);
1760
1761 Texture::setCompressedImage(imageSize, pixels, mImageArray[level]);
1762}
1763
Jamie Madill88f18f42013-09-18 14:36:19 -04001764void 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 +00001765{
Jamie Madillba4f10a2013-10-10 15:12:20 -04001766 bool fastUnpacked = false;
1767
1768 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1769 if (isFastUnpackable(unpack, getInternalFormat(level)))
1770 {
1771 rx::RenderTarget *destRenderTarget = getRenderTarget(level);
1772 Box destArea(xoffset, yoffset, zoffset, width, height, depth);
1773
1774 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, destRenderTarget))
1775 {
1776 // Ensure we don't overwrite our newly initialized data
1777 mImageArray[level]->markClean();
1778
1779 fastUnpacked = true;
1780 }
1781 }
1782
1783 if (!fastUnpacked && Texture::subImage(xoffset, yoffset, zoffset, width, height, depth, format, type, unpack, pixels, mImageArray[level]))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001784 {
1785 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1786 }
1787}
1788
1789void Texture3D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
1790{
1791 if (Texture::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth, format, imageSize, pixels, mImageArray[level]))
1792 {
1793 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1794 }
1795}
1796
1797void Texture3D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
1798{
1799 delete mTexStorage;
1800 mTexStorage = new rx::TextureStorageInterface3D(mRenderer, levels, internalformat, mUsage, width, height, depth);
1801 mImmutable = true;
1802
1803 for (int level = 0; level < levels; level++)
1804 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001805 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, true);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001806 width = std::max(1, width >> 1);
1807 height = std::max(1, height >> 1);
1808 depth = std::max(1, depth >> 1);
1809 }
1810
1811 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1812 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001813 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, GL_NONE, 0, 0, 0, true);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001814 }
1815
1816 if (mTexStorage->isManaged())
1817 {
1818 int levels = levelCount();
1819
1820 for (int level = 0; level < levels; level++)
1821 {
1822 mImageArray[level]->setManagedSurface(mTexStorage, level);
1823 }
1824 }
1825}
1826
1827
1828void Texture3D::generateMipmaps()
1829{
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001830 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Jamie Madilld3d2a342013-10-07 10:46:35 -04001831 unsigned int q = log2(std::max(getBaseLevelWidth(), getBaseLevelHeight()));
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001832 for (unsigned int i = 1; i <= q; i++)
1833 {
Jamie Madilld3d2a342013-10-07 10:46:35 -04001834 redefineImage(i, getBaseLevelInternalFormat(),
1835 std::max(getBaseLevelWidth() >> i, 1),
1836 std::max(getBaseLevelHeight() >> i, 1),
1837 std::max(getBaseLevelDepth() >> i, 1));
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001838 }
1839
1840 if (mTexStorage && mTexStorage->isRenderTarget())
1841 {
1842 for (unsigned int i = 1; i <= q; i++)
1843 {
1844 mTexStorage->generateMipmap(i);
1845
1846 mImageArray[i]->markClean();
1847 }
1848 }
1849 else
1850 {
1851 for (unsigned int i = 1; i <= q; i++)
1852 {
1853 mRenderer->generateMipmap(mImageArray[i], mImageArray[i - 1]);
1854 }
1855 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001856}
1857
Jamie Madilld3d2a342013-10-07 10:46:35 -04001858const rx::Image *Texture3D::getBaseLevelImage() const
1859{
1860 return mImageArray[0];
1861}
1862
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001863void Texture3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1864{
1865 if (xoffset + width > mImageArray[level]->getWidth() || yoffset + height > mImageArray[level]->getHeight() || zoffset >= mImageArray[level]->getDepth())
1866 {
1867 return gl::error(GL_INVALID_VALUE);
1868 }
1869
Jamie Madill07edd442013-07-19 16:36:58 -04001870 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
1871 // the current level we're copying to is defined (with appropriate format, width & height)
1872 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
1873
1874 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001875 {
1876 mImageArray[level]->copy(xoffset, yoffset, zoffset, x, y, width, height, source);
1877 mDirtyImages = true;
1878 }
1879 else
1880 {
1881 if (!mTexStorage || !mTexStorage->isRenderTarget())
1882 {
1883 convertToRenderTarget();
1884 }
1885
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001886 if (level < levelCount())
1887 {
Jamie Madill07edd442013-07-19 16:36:58 -04001888 updateTextureLevel(level);
1889
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001890 gl::Rectangle sourceRect;
1891 sourceRect.x = x;
1892 sourceRect.width = width;
1893 sourceRect.y = y;
1894 sourceRect.height = height;
1895
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001896 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1897
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001898 mRenderer->copyImage(source, sourceRect,
Jamie Madilld3d2a342013-10-07 10:46:35 -04001899 gl::GetFormat(getBaseLevelInternalFormat(), clientVersion),
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001900 xoffset, yoffset, zoffset, mTexStorage, level);
1901 }
1902 }
1903}
1904
Jamie Madillf8989902013-07-19 16:36:58 -04001905bool Texture3D::isSamplerComplete(const SamplerState &samplerState) const
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001906{
Jamie Madilld3d2a342013-10-07 10:46:35 -04001907 GLsizei width = getBaseLevelWidth();
1908 GLsizei height = getBaseLevelHeight();
1909 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001910
1911 if (width <= 0 || height <= 0 || depth <= 0)
1912 {
1913 return false;
1914 }
1915
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001916 if (!IsTextureFilteringSupported(getInternalFormat(0), mRenderer))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001917 {
Jamie Madillf8989902013-07-19 16:36:58 -04001918 if (samplerState.magFilter != GL_NEAREST ||
1919 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001920 {
1921 return false;
1922 }
1923 }
1924
Jamie Madillf8989902013-07-19 16:36:58 -04001925 if (IsMipmapFiltered(samplerState) && !isMipmapComplete())
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001926 {
1927 return false;
1928 }
1929
1930 return true;
1931}
1932
1933bool Texture3D::isMipmapComplete() const
1934{
Jamie Madilld3d2a342013-10-07 10:46:35 -04001935 GLsizei width = getBaseLevelWidth();
1936 GLsizei height = getBaseLevelHeight();
1937 GLsizei depth = getBaseLevelDepth();
Jamie Madill07edd442013-07-19 16:36:58 -04001938
1939 int q = log2(std::max(std::max(width, height), depth));
1940
1941 for (int level = 0; level <= q; level++)
1942 {
1943 if (!isLevelComplete(level))
1944 {
1945 return false;
1946 }
1947 }
1948
1949 return true;
1950}
1951
1952bool Texture3D::isLevelComplete(int level) const
1953{
1954 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1955
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001956 if (isImmutable())
1957 {
1958 return true;
1959 }
1960
Jamie Madilld3d2a342013-10-07 10:46:35 -04001961 GLsizei width = getBaseLevelWidth();
1962 GLsizei height = getBaseLevelHeight();
1963 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001964
1965 if (width <= 0 || height <= 0 || depth <= 0)
1966 {
1967 return false;
1968 }
1969
Jamie Madill07edd442013-07-19 16:36:58 -04001970 if (level == 0)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001971 {
Jamie Madill07edd442013-07-19 16:36:58 -04001972 return true;
1973 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001974
Jamie Madill07edd442013-07-19 16:36:58 -04001975 rx::Image *levelImage = mImageArray[level];
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001976
Jamie Madilld3d2a342013-10-07 10:46:35 -04001977 if (levelImage->getInternalFormat() != getBaseLevelInternalFormat())
Jamie Madill07edd442013-07-19 16:36:58 -04001978 {
1979 return false;
1980 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001981
Jamie Madill07edd442013-07-19 16:36:58 -04001982 if (levelImage->getWidth() != std::max(1, width >> level))
1983 {
1984 return false;
1985 }
1986
1987 if (levelImage->getHeight() != std::max(1, height >> level))
1988 {
1989 return false;
1990 }
1991
1992 if (levelImage->getDepth() != std::max(1, depth >> level))
1993 {
1994 return false;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001995 }
1996
1997 return true;
1998}
1999
Geoff Lang8040f572013-07-25 16:49:54 -04002000Renderbuffer *Texture3D::getRenderbuffer(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002001{
Geoff Lang8040f572013-07-25 16:49:54 -04002002 Renderbuffer *renderBuffer = mRenderbufferProxies.get(level, layer);
2003 if (!renderBuffer)
2004 {
Geoff Langd5d8e392013-07-25 16:53:03 -04002005 renderBuffer = new Renderbuffer(mRenderer, id(), new RenderbufferTexture3DLayer(this, level, layer));
2006 mRenderbufferProxies.add(level, 0, renderBuffer);
Geoff Lang8040f572013-07-25 16:49:54 -04002007 }
2008
2009 return renderBuffer;
2010}
2011
2012unsigned int Texture3D::getRenderTargetSerial(GLint level, GLint layer)
2013{
2014 if (!mTexStorage || !mTexStorage->isRenderTarget())
2015 {
2016 convertToRenderTarget();
2017 }
2018
2019 return mTexStorage ? mTexStorage->getRenderTargetSerial(level, layer) : 0;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002020}
2021
2022int Texture3D::levelCount()
2023{
2024 return mTexStorage ? mTexStorage->levelCount() : 0;
2025}
2026
2027void Texture3D::createTexture()
2028{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002029 GLsizei width = getBaseLevelWidth();
2030 GLsizei height = getBaseLevelHeight();
2031 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002032
2033 if (!(width > 0 && height > 0 && depth > 0))
2034 return; // do not attempt to create native textures for nonexistant data
2035
2036 GLint levels = creationLevels(width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002037
2038 delete mTexStorage;
Jamie Madilld3d2a342013-10-07 10:46:35 -04002039 mTexStorage = new rx::TextureStorageInterface3D(mRenderer, levels, getBaseLevelInternalFormat(), mUsage, width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002040
2041 if (mTexStorage->isManaged())
2042 {
2043 int levels = levelCount();
2044
2045 for (int level = 0; level < levels; level++)
2046 {
2047 mImageArray[level]->setManagedSurface(mTexStorage, level);
2048 }
2049 }
2050
2051 mDirtyImages = true;
2052}
2053
2054void Texture3D::updateTexture()
2055{
Jamie Madilld9b9a502013-10-10 17:46:13 -04002056 int storageLevels = levelCount();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002057
Jamie Madilld9b9a502013-10-10 17:46:13 -04002058 for (int level = 0; level < storageLevels; level++)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002059 {
Jamie Madilld9b9a502013-10-10 17:46:13 -04002060 if (isLevelComplete(level))
2061 {
2062 updateTextureLevel(level);
2063 }
Jamie Madill07edd442013-07-19 16:36:58 -04002064 }
2065}
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002066
Jamie Madill07edd442013-07-19 16:36:58 -04002067void Texture3D::updateTextureLevel(int level)
2068{
2069 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
Jamie Madillaee7ad82013-10-10 16:07:32 -04002070 ASSERT(isLevelComplete(level));
Jamie Madill07edd442013-07-19 16:36:58 -04002071
Jamie Madillaee7ad82013-10-10 16:07:32 -04002072 if (mImageArray[level]->isDirty())
Jamie Madill07edd442013-07-19 16:36:58 -04002073 {
Jamie Madillaee7ad82013-10-10 16:07:32 -04002074 commitRect(level, 0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002075 }
2076}
2077
2078void Texture3D::convertToRenderTarget()
2079{
2080 rx::TextureStorageInterface3D *newTexStorage = NULL;
2081
Jamie Madilld3d2a342013-10-07 10:46:35 -04002082 if (getBaseLevelWidth() != 0 && getBaseLevelHeight() != 0 && getBaseLevelDepth() != 0)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002083 {
Jamie Madilld3d2a342013-10-07 10:46:35 -04002084 GLsizei width = getBaseLevelWidth();
2085 GLsizei height = getBaseLevelHeight();
2086 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002087 GLint levels = mTexStorage != NULL ? mTexStorage->levelCount() : creationLevels(width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002088
Jamie Madilld3d2a342013-10-07 10:46:35 -04002089 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 +00002090
2091 if (mTexStorage != NULL)
2092 {
2093 if (!mRenderer->copyToRenderTarget(newTexStorage, mTexStorage))
2094 {
2095 delete newTexStorage;
2096 return gl::error(GL_OUT_OF_MEMORY);
2097 }
2098 }
2099 }
2100
2101 delete mTexStorage;
2102 mTexStorage = newTexStorage;
2103
2104 mDirtyImages = true;
2105}
2106
Jamie Madilla2d4e552013-10-10 15:12:01 -04002107rx::RenderTarget *Texture3D::getRenderTarget(GLint level)
2108{
2109 // ensure the underlying texture is created
2110 if (getStorage(true) == NULL)
2111 {
2112 return NULL;
2113 }
2114
Jamie Madillaee7ad82013-10-10 16:07:32 -04002115 updateTextureLevel(level);
Jamie Madilla2d4e552013-10-10 15:12:01 -04002116
2117 // ensure this is NOT a depth texture
2118 if (isDepth(level))
2119 {
2120 return NULL;
2121 }
2122
2123 return mTexStorage->getRenderTarget(level);
2124}
2125
Geoff Lang8040f572013-07-25 16:49:54 -04002126rx::RenderTarget *Texture3D::getRenderTarget(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002127{
Geoff Lang8040f572013-07-25 16:49:54 -04002128 // ensure the underlying texture is created
2129 if (getStorage(true) == NULL)
2130 {
2131 return NULL;
2132 }
2133
2134 updateTexture();
2135
2136 // ensure this is NOT a depth texture
2137 if (isDepth(level))
2138 {
2139 return NULL;
2140 }
2141
2142 return mTexStorage->getRenderTarget(level, layer);
2143}
2144
2145rx::RenderTarget *Texture3D::getDepthStencil(GLint level, GLint layer)
2146{
2147 // ensure the underlying texture is created
2148 if (getStorage(true) == NULL)
2149 {
2150 return NULL;
2151 }
2152
Jamie Madillaee7ad82013-10-10 16:07:32 -04002153 updateTextureLevel(level);
Geoff Lang8040f572013-07-25 16:49:54 -04002154
2155 // ensure this is a depth texture
2156 if (!isDepth(level))
2157 {
2158 return NULL;
2159 }
2160
2161 return mTexStorage->getRenderTarget(level, layer);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002162}
2163
2164rx::TextureStorageInterface *Texture3D::getStorage(bool renderTarget)
2165{
2166 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
2167 {
2168 if (renderTarget)
2169 {
2170 convertToRenderTarget();
2171 }
2172 else
2173 {
2174 createTexture();
2175 }
2176 }
2177
2178 return mTexStorage;
2179}
2180
Geoff Lang005df412013-10-16 14:12:50 -04002181void Texture3D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002182{
2183 // If there currently is a corresponding storage texture image, it has these parameters
Jamie Madilld3d2a342013-10-07 10:46:35 -04002184 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2185 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
2186 const int storageDepth = std::max(1, getBaseLevelDepth() >> level);
Geoff Lang005df412013-10-16 14:12:50 -04002187 const GLenum storageFormat = getBaseLevelInternalFormat();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002188
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00002189 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, false);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002190
2191 if (mTexStorage)
2192 {
2193 const int storageLevels = mTexStorage->levelCount();
2194
2195 if ((level >= storageLevels && storageLevels != 0) ||
2196 width != storageWidth ||
2197 height != storageHeight ||
2198 depth != storageDepth ||
2199 internalformat != storageFormat) // Discard mismatched storage
2200 {
2201 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
2202 {
2203 mImageArray[i]->markDirty();
2204 }
2205
2206 delete mTexStorage;
2207 mTexStorage = NULL;
2208 mDirtyImages = true;
2209 }
2210 }
2211}
2212
2213void Texture3D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth)
2214{
2215 if (level < levelCount())
2216 {
2217 rx::Image *image = mImageArray[level];
2218 if (image->updateSurface(mTexStorage, level, xoffset, yoffset, zoffset, width, height, depth))
2219 {
2220 image->markClean();
2221 }
2222 }
2223}
2224
Geoff Lang4907f2c2013-07-25 12:53:57 -04002225Texture2DArray::Texture2DArray(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_2D_ARRAY)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002226{
2227 mTexStorage = NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002228
2229 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2230 {
2231 mLayerCounts[level] = 0;
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002232 mImageArray[level] = NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002233 }
2234}
2235
2236Texture2DArray::~Texture2DArray()
2237{
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002238 delete mTexStorage;
2239 mTexStorage = NULL;
2240 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2241 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002242 for (int layer = 0; layer < mLayerCounts[level]; ++layer)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002243 {
2244 delete mImageArray[level][layer];
2245 }
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002246 delete[] mImageArray[level];
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002247 }
2248}
2249
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002250GLsizei Texture2DArray::getWidth(GLint level) const
2251{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002252 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getWidth() : 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002253}
2254
2255GLsizei Texture2DArray::getHeight(GLint level) const
2256{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002257 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 +00002258}
2259
2260GLsizei Texture2DArray::getDepth(GLint level) const
2261{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002262 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mLayerCounts[level] : 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002263}
2264
2265GLenum Texture2DArray::getInternalFormat(GLint level) const
2266{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002267 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getInternalFormat() : GL_NONE;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002268}
2269
2270GLenum Texture2DArray::getActualFormat(GLint level) const
2271{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002272 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 +00002273}
2274
2275bool Texture2DArray::isCompressed(GLint level) const
2276{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00002277 return IsFormatCompressed(getInternalFormat(level), mRenderer->getCurrentClientVersion());
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002278}
2279
2280bool Texture2DArray::isDepth(GLint level) const
2281{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00002282 return GetDepthBits(getInternalFormat(level), mRenderer->getCurrentClientVersion()) > 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002283}
2284
Geoff Lang005df412013-10-16 14:12:50 -04002285void Texture2DArray::setImage(GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002286{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00002287 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Geoff Lang005df412013-10-16 14:12:50 -04002288 GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
2289 : GetSizedInternalFormat(format, type, clientVersion);
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00002290 redefineImage(level, sizedInternalFormat, width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002291
Jamie Madill88f18f42013-09-18 14:36:19 -04002292 GLsizei inputDepthPitch = gl::GetDepthPitch(sizedInternalFormat, type, clientVersion, width, height, unpack.alignment);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002293
2294 for (int i = 0; i < depth; i++)
2295 {
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002296 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
Jamie Madill88f18f42013-09-18 14:36:19 -04002297 Texture::setImage(unpack, type, layerPixels, mImageArray[level][i]);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002298 }
2299}
2300
2301void Texture2DArray::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
2302{
2303 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
2304 redefineImage(level, format, width, height, depth);
2305
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002306 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2307 GLsizei inputDepthPitch = gl::GetDepthPitch(format, GL_UNSIGNED_BYTE, clientVersion, width, height, 1);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002308
2309 for (int i = 0; i < depth; i++)
2310 {
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002311 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002312 Texture::setCompressedImage(imageSize, layerPixels, mImageArray[level][i]);
2313 }
2314}
2315
Jamie Madill88f18f42013-09-18 14:36:19 -04002316void 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 +00002317{
Geoff Lang005df412013-10-16 14:12:50 -04002318 GLenum internalformat = getInternalFormat(level);
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002319 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Jamie Madill88f18f42013-09-18 14:36:19 -04002320 GLsizei inputDepthPitch = gl::GetDepthPitch(internalformat, type, clientVersion, width, height, unpack.alignment);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002321
2322 for (int i = 0; i < depth; i++)
2323 {
2324 int layer = zoffset + i;
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002325 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002326
Jamie Madill88f18f42013-09-18 14:36:19 -04002327 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 +00002328 {
2329 commitRect(level, xoffset, yoffset, layer, width, height);
2330 }
2331 }
2332}
2333
2334void Texture2DArray::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
2335{
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002336 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2337 GLsizei inputDepthPitch = gl::GetDepthPitch(format, GL_UNSIGNED_BYTE, clientVersion, width, height, 1);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002338
2339 for (int i = 0; i < depth; i++)
2340 {
2341 int layer = zoffset + i;
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002342 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002343
2344 if (Texture::subImageCompressed(xoffset, yoffset, zoffset, width, height, 1, format, imageSize, layerPixels, mImageArray[level][layer]))
2345 {
2346 commitRect(level, xoffset, yoffset, layer, width, height);
2347 }
2348 }
2349}
2350
2351void Texture2DArray::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2352{
2353 delete mTexStorage;
2354 mTexStorage = new rx::TextureStorageInterface2DArray(mRenderer, levels, internalformat, mUsage, width, height, depth);
2355 mImmutable = true;
2356
2357 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2358 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002359 GLsizei levelWidth = std::max(width >> level, 1);
Geoff Lange836cf22013-08-05 14:12:37 -04002360 GLsizei levelHeight = std::max(height >> level, 1);
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002361
2362 // Clear this level
2363 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002364 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002365 delete mImageArray[level][layer];
2366 }
2367 delete[] mImageArray[level];
2368 mImageArray[level] = NULL;
2369 mLayerCounts[level] = 0;
2370
2371 if (level < levels)
2372 {
2373 // Create new images for this level
2374 mImageArray[level] = new rx::Image*[depth]();
2375 mLayerCounts[level] = depth;
2376
2377 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002378 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002379 mImageArray[level][layer] = mRenderer->createImage();
2380 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, levelWidth,
2381 levelHeight, 1, true);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002382 }
2383 }
2384 }
2385
2386 if (mTexStorage->isManaged())
2387 {
2388 int levels = levelCount();
2389
2390 for (int level = 0; level < levels; level++)
2391 {
2392 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2393 {
2394 mImageArray[level][layer]->setManagedSurface(mTexStorage, layer, level);
2395 }
2396 }
2397 }
2398}
2399
2400void Texture2DArray::generateMipmaps()
2401{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002402 int baseWidth = getBaseLevelWidth();
2403 int baseHeight = getBaseLevelHeight();
2404 int baseDepth = getBaseLevelDepth();
2405 GLenum baseFormat = getBaseLevelInternalFormat();
2406
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00002407 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Jamie Madilld3d2a342013-10-07 10:46:35 -04002408 int q = log2(std::max(baseWidth, baseHeight));
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00002409 for (int i = 1; i <= q; i++)
2410 {
Jamie Madilld3d2a342013-10-07 10:46:35 -04002411 redefineImage(i, baseFormat, std::max(baseWidth >> i, 1), std::max(baseHeight >> i, 1), baseDepth);
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00002412 }
2413
2414 if (mTexStorage && mTexStorage->isRenderTarget())
2415 {
2416 for (int level = 1; level <= q; level++)
2417 {
2418 mTexStorage->generateMipmap(level);
2419
2420 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2421 {
2422 mImageArray[level][layer]->markClean();
2423 }
2424 }
2425 }
2426 else
2427 {
2428 for (int level = 1; level <= q; level++)
2429 {
2430 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2431 {
2432 mRenderer->generateMipmap(mImageArray[level][layer], mImageArray[level - 1][layer]);
2433 }
2434 }
2435 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002436}
2437
Jamie Madilld3d2a342013-10-07 10:46:35 -04002438const rx::Image *Texture2DArray::getBaseLevelImage() const
2439{
Jamie Madill152ed092013-10-09 17:01:15 -04002440 return (mLayerCounts[0] > 0 ? mImageArray[0][0] : NULL);
Jamie Madilld3d2a342013-10-07 10:46:35 -04002441}
2442
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002443void Texture2DArray::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
2444{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002445 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 +00002446 {
2447 return gl::error(GL_INVALID_VALUE);
2448 }
2449
Jamie Madill07edd442013-07-19 16:36:58 -04002450 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
2451 // the current level we're copying to is defined (with appropriate format, width & height)
2452 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
2453
2454 if (!mImageArray[level][0]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002455 {
2456 mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, x, y, width, height, source);
2457 mDirtyImages = true;
2458 }
2459 else
2460 {
2461 if (!mTexStorage || !mTexStorage->isRenderTarget())
2462 {
2463 convertToRenderTarget();
2464 }
2465
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002466 if (level < levelCount())
2467 {
Jamie Madill07edd442013-07-19 16:36:58 -04002468 updateTextureLevel(level);
2469
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002470 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2471
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002472 gl::Rectangle sourceRect;
2473 sourceRect.x = x;
2474 sourceRect.width = width;
2475 sourceRect.y = y;
2476 sourceRect.height = height;
2477
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002478 mRenderer->copyImage(source, sourceRect, gl::GetFormat(getInternalFormat(0), clientVersion),
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002479 xoffset, yoffset, zoffset, mTexStorage, level);
2480 }
2481 }
2482}
2483
Jamie Madillf8989902013-07-19 16:36:58 -04002484bool Texture2DArray::isSamplerComplete(const SamplerState &samplerState) const
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002485{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002486 GLsizei width = getBaseLevelWidth();
2487 GLsizei height = getBaseLevelHeight();
2488 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002489
2490 if (width <= 0 || height <= 0 || depth <= 0)
2491 {
2492 return false;
2493 }
2494
Jamie Madilld3d2a342013-10-07 10:46:35 -04002495 if (!IsTextureFilteringSupported(getBaseLevelInternalFormat(), mRenderer))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002496 {
Jamie Madillf8989902013-07-19 16:36:58 -04002497 if (samplerState.magFilter != GL_NEAREST ||
2498 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002499 {
2500 return false;
2501 }
2502 }
2503
Jamie Madillf8989902013-07-19 16:36:58 -04002504 if (IsMipmapFiltered(samplerState) && !isMipmapComplete())
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002505 {
2506 return false;
2507 }
2508
2509 return true;
2510}
2511
2512bool Texture2DArray::isMipmapComplete() const
2513{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002514 GLsizei width = getBaseLevelWidth();
2515 GLsizei height = getBaseLevelHeight();
Jamie Madill07edd442013-07-19 16:36:58 -04002516
2517 int q = log2(std::max(width, height));
2518
2519 for (int level = 1; level <= q; level++)
2520 {
2521 if (!isLevelComplete(level))
2522 {
2523 return false;
2524 }
2525 }
2526
2527 return true;
2528}
2529
2530bool Texture2DArray::isLevelComplete(int level) const
2531{
2532 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
2533
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002534 if (isImmutable())
2535 {
2536 return true;
2537 }
2538
Jamie Madilld3d2a342013-10-07 10:46:35 -04002539 GLsizei width = getBaseLevelWidth();
2540 GLsizei height = getBaseLevelHeight();
2541 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002542
2543 if (width <= 0 || height <= 0 || depth <= 0)
2544 {
2545 return false;
2546 }
2547
Jamie Madill07edd442013-07-19 16:36:58 -04002548 if (level == 0)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002549 {
Jamie Madill07edd442013-07-19 16:36:58 -04002550 return true;
2551 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002552
Jamie Madill07edd442013-07-19 16:36:58 -04002553 if (getInternalFormat(level) != getInternalFormat(0))
2554 {
2555 return false;
2556 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002557
Jamie Madill07edd442013-07-19 16:36:58 -04002558 if (getWidth(level) != std::max(1, width >> level))
2559 {
2560 return false;
2561 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002562
Jamie Madill07edd442013-07-19 16:36:58 -04002563 if (getHeight(level) != std::max(1, height >> level))
2564 {
2565 return false;
2566 }
2567
2568 if (getDepth(level) != depth)
2569 {
2570 return false;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002571 }
2572
2573 return true;
2574}
2575
Geoff Lang8040f572013-07-25 16:49:54 -04002576Renderbuffer *Texture2DArray::getRenderbuffer(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002577{
Geoff Lang8040f572013-07-25 16:49:54 -04002578 Renderbuffer *renderBuffer = mRenderbufferProxies.get(level, layer);
2579 if (!renderBuffer)
2580 {
Geoff Langd5d8e392013-07-25 16:53:03 -04002581 renderBuffer = new Renderbuffer(mRenderer, id(), new RenderbufferTexture2DArrayLayer(this, level, layer));
2582 mRenderbufferProxies.add(level, 0, renderBuffer);
Geoff Lang8040f572013-07-25 16:49:54 -04002583 }
2584
2585 return renderBuffer;
2586}
2587
2588unsigned int Texture2DArray::getRenderTargetSerial( GLint level, GLint layer )
2589{
2590 if (!mTexStorage || !mTexStorage->isRenderTarget())
2591 {
2592 convertToRenderTarget();
2593 }
2594
2595 return mTexStorage ? mTexStorage->getRenderTargetSerial(level, layer) : 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002596}
2597
2598int Texture2DArray::levelCount()
2599{
2600 return mTexStorage ? mTexStorage->levelCount() : 0;
2601}
2602
2603void Texture2DArray::createTexture()
2604{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002605 GLsizei width = getBaseLevelWidth();
2606 GLsizei height = getBaseLevelHeight();
2607 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002608
2609 if (width <= 0 || height <= 0 || depth <= 0)
2610 {
2611 return; // do not attempt to create native textures for nonexistant data
2612 }
2613
2614 GLint levels = creationLevels(width, height);
Jamie Madilld3d2a342013-10-07 10:46:35 -04002615 GLenum internalformat = getBaseLevelInternalFormat();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002616
2617 delete mTexStorage;
2618 mTexStorage = new rx::TextureStorageInterface2DArray(mRenderer, levels, internalformat, mUsage, width, height, depth);
2619
2620 if (mTexStorage->isManaged())
2621 {
2622 int levels = levelCount();
2623 for (int level = 0; level < levels; level++)
2624 {
2625 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2626 {
2627 mImageArray[level][layer]->setManagedSurface(mTexStorage, layer, level);
2628 }
2629 }
2630 }
2631
2632 mDirtyImages = true;
2633}
2634
2635void Texture2DArray::updateTexture()
2636{
Jamie Madilld9b9a502013-10-10 17:46:13 -04002637 int storageLevels = levelCount();
2638
2639 for (int level = 0; level < storageLevels; level++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002640 {
Jamie Madilld9b9a502013-10-10 17:46:13 -04002641 if (isLevelComplete(level))
2642 {
2643 updateTextureLevel(level);
2644 }
Jamie Madill07edd442013-07-19 16:36:58 -04002645 }
2646}
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002647
Jamie Madill07edd442013-07-19 16:36:58 -04002648void Texture2DArray::updateTextureLevel(int level)
2649{
Jamie Madillaee7ad82013-10-10 16:07:32 -04002650 ASSERT(level >= 0 && level < (int)ArraySize(mLayerCounts));
2651 ASSERT(isLevelComplete(level));
2652
Jamie Madill07edd442013-07-19 16:36:58 -04002653 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2654 {
Jamie Madillaee7ad82013-10-10 16:07:32 -04002655 ASSERT(mImageArray[level] != NULL && mImageArray[level][layer] != NULL);
2656 if (mImageArray[level][layer]->isDirty())
Jamie Madill07edd442013-07-19 16:36:58 -04002657 {
Jamie Madillaee7ad82013-10-10 16:07:32 -04002658 commitRect(level, 0, 0, layer, getWidth(level), getHeight(level));
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002659 }
2660 }
2661}
2662
2663void Texture2DArray::convertToRenderTarget()
2664{
2665 rx::TextureStorageInterface2DArray *newTexStorage = NULL;
2666
Jamie Madilld3d2a342013-10-07 10:46:35 -04002667 GLsizei width = getBaseLevelWidth();
2668 GLsizei height = getBaseLevelHeight();
2669 GLsizei depth = getBaseLevelDepth();
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002670
2671 if (width != 0 && height != 0 && depth != 0)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002672 {
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002673 GLint levels = mTexStorage != NULL ? mTexStorage->levelCount() : creationLevels(width, height);
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002674 GLenum internalformat = getInternalFormat(0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002675
2676 newTexStorage = new rx::TextureStorageInterface2DArray(mRenderer, levels, internalformat, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, width, height, depth);
2677
2678 if (mTexStorage != NULL)
2679 {
2680 if (!mRenderer->copyToRenderTarget(newTexStorage, mTexStorage))
2681 {
2682 delete newTexStorage;
2683 return gl::error(GL_OUT_OF_MEMORY);
2684 }
2685 }
2686 }
2687
2688 delete mTexStorage;
2689 mTexStorage = newTexStorage;
2690
2691 mDirtyImages = true;
2692}
2693
Geoff Lang8040f572013-07-25 16:49:54 -04002694rx::RenderTarget *Texture2DArray::getRenderTarget(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002695{
Geoff Lang8040f572013-07-25 16:49:54 -04002696 // ensure the underlying texture is created
2697 if (getStorage(true) == NULL)
2698 {
2699 return NULL;
2700 }
2701
Jamie Madillaee7ad82013-10-10 16:07:32 -04002702 updateTextureLevel(level);
Geoff Lang8040f572013-07-25 16:49:54 -04002703
2704 // ensure this is NOT a depth texture
2705 if (isDepth(level))
2706 {
2707 return NULL;
2708 }
2709
2710 return mTexStorage->getRenderTarget(level, layer);
2711}
2712
2713rx::RenderTarget *Texture2DArray::getDepthStencil(GLint level, GLint layer)
2714{
2715 // ensure the underlying texture is created
2716 if (getStorage(true) == NULL)
2717 {
2718 return NULL;
2719 }
2720
Jamie Madillaee7ad82013-10-10 16:07:32 -04002721 updateTextureLevel(level);
Geoff Lang8040f572013-07-25 16:49:54 -04002722
2723 // ensure this is a depth texture
2724 if (!isDepth(level))
2725 {
2726 return NULL;
2727 }
2728
2729 return mTexStorage->getRenderTarget(level, layer);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002730}
2731
2732rx::TextureStorageInterface *Texture2DArray::getStorage(bool renderTarget)
2733{
2734 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
2735 {
2736 if (renderTarget)
2737 {
2738 convertToRenderTarget();
2739 }
2740 else
2741 {
2742 createTexture();
2743 }
2744 }
2745
2746 return mTexStorage;
2747}
2748
Geoff Lang005df412013-10-16 14:12:50 -04002749void Texture2DArray::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002750{
2751 // If there currently is a corresponding storage texture image, it has these parameters
Jamie Madilld3d2a342013-10-07 10:46:35 -04002752 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2753 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
2754 const int storageDepth = getBaseLevelDepth();
Geoff Lang005df412013-10-16 14:12:50 -04002755 const GLenum storageFormat = getBaseLevelInternalFormat();
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 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002759 delete mImageArray[level][layer];
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002760 }
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002761 delete[] mImageArray[level];
Jamie Madill152ed092013-10-09 17:01:15 -04002762 mImageArray[level] = NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002763 mLayerCounts[level] = depth;
2764
Jamie Madill152ed092013-10-09 17:01:15 -04002765 if (depth > 0)
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002766 {
Jamie Madill152ed092013-10-09 17:01:15 -04002767 mImageArray[level] = new rx::Image*[depth]();
2768
2769 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2770 {
2771 mImageArray[level][layer] = mRenderer->createImage();
2772 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, width, height, 1, false);
2773 }
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002774 }
2775
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002776 if (mTexStorage)
2777 {
2778 const int storageLevels = mTexStorage->levelCount();
2779
2780 if ((level >= storageLevels && storageLevels != 0) ||
2781 width != storageWidth ||
2782 height != storageHeight ||
2783 depth != storageDepth ||
2784 internalformat != storageFormat) // Discard mismatched storage
2785 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002786 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002787 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002788 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002789 {
2790 mImageArray[level][layer]->markDirty();
2791 }
2792 }
2793
2794 delete mTexStorage;
2795 mTexStorage = NULL;
2796 mDirtyImages = true;
2797 }
2798 }
2799}
2800
2801void Texture2DArray::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint layerTarget, GLsizei width, GLsizei height)
2802{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002803 if (level < levelCount() && layerTarget < getDepth(level))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002804 {
2805 rx::Image *image = mImageArray[level][layerTarget];
2806 if (image->updateSurface(mTexStorage, level, xoffset, yoffset, layerTarget, width, height))
2807 {
2808 image->markClean();
2809 }
2810 }
2811}
2812
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00002813}