blob: 16179c5b5e77983f33da4c24f2f380ae1e97948a [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 Madilleb3665c2013-07-19 16:36:57 -0400833 int levels = (isMipmapComplete() ? levelCount() : 1);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000834
835 for (int level = 0; level < levels; level++)
836 {
Jamie Madill07edd442013-07-19 16:36:58 -0400837 updateTextureLevel(level);
838 }
839}
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000840
Jamie Madill07edd442013-07-19 16:36:58 -0400841void Texture2D::updateTextureLevel(int level)
842{
843 ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
844 rx::Image *image = mImageArray[level];
845
846 if (image->isDirty())
847 {
848 commitRect(level, 0, 0, mImageArray[level]->getWidth(), mImageArray[level]->getHeight());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000849 }
850}
851
852void Texture2D::convertToRenderTarget()
853{
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000854 rx::TextureStorageInterface2D *newTexStorage = NULL;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000855
Jamie Madilld3d2a342013-10-07 10:46:35 -0400856 GLsizei width = getBaseLevelWidth();
857 GLsizei height = getBaseLevelHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000858
Jamie Madilld3d2a342013-10-07 10:46:35 -0400859 if (width != 0 && height != 0)
860 {
861 GLint levels = mTexStorage != NULL ? mTexStorage->levelCount() : creationLevels(width, height);
862
863 newTexStorage = new rx::TextureStorageInterface2D(mRenderer, levels, getBaseLevelInternalFormat(), GL_FRAMEBUFFER_ATTACHMENT_ANGLE, true, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000864
865 if (mTexStorage != NULL)
866 {
daniel@transgaming.com1d80eee2012-11-28 19:33:31 +0000867 if (!mRenderer->copyToRenderTarget(newTexStorage, mTexStorage))
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +0000868 {
869 delete newTexStorage;
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +0000870 return gl::error(GL_OUT_OF_MEMORY);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000871 }
872 }
873 }
874
875 delete mTexStorage;
876 mTexStorage = newTexStorage;
877
878 mDirtyImages = true;
879}
880
881void Texture2D::generateMipmaps()
882{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000883 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Jamie Madilld3d2a342013-10-07 10:46:35 -0400884 unsigned int q = log2(std::max(getBaseLevelWidth(), getBaseLevelHeight()));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000885 for (unsigned int i = 1; i <= q; i++)
886 {
Jamie Madilld3d2a342013-10-07 10:46:35 -0400887 redefineImage(i, getBaseLevelInternalFormat(),
888 std::max(getBaseLevelWidth() >> i, 1),
889 std::max(getBaseLevelHeight() >> i, 1));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000890 }
891
892 if (mTexStorage && mTexStorage->isRenderTarget())
893 {
894 for (unsigned int i = 1; i <= q; i++)
895 {
daniel@transgaming.com0ad830b2012-10-31 19:52:12 +0000896 mTexStorage->generateMipmap(i);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000897
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000898 mImageArray[i]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000899 }
900 }
901 else
902 {
903 for (unsigned int i = 1; i <= q; i++)
904 {
daniel@transgaming.com4ba24062012-12-20 20:54:24 +0000905 mRenderer->generateMipmap(mImageArray[i], mImageArray[i - 1]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000906 }
907 }
908}
909
Jamie Madilld3d2a342013-10-07 10:46:35 -0400910const rx::Image *Texture2D::getBaseLevelImage() const
911{
912 return mImageArray[0];
913}
914
Geoff Lang8040f572013-07-25 16:49:54 -0400915Renderbuffer *Texture2D::getRenderbuffer(GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000916{
Geoff Lang8040f572013-07-25 16:49:54 -0400917 Renderbuffer *renderBuffer = mRenderbufferProxies.get(level, 0);
918 if (!renderBuffer)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000919 {
Geoff Lang8040f572013-07-25 16:49:54 -0400920 renderBuffer = new Renderbuffer(mRenderer, id(), new RenderbufferTexture2D(this, level));
921 mRenderbufferProxies.add(level, 0, renderBuffer);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000922 }
923
Geoff Lang8040f572013-07-25 16:49:54 -0400924 return renderBuffer;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000925}
926
Geoff Lang8040f572013-07-25 16:49:54 -0400927unsigned int Texture2D::getRenderTargetSerial(GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000928{
Geoff Lang8040f572013-07-25 16:49:54 -0400929 if (!mTexStorage || !mTexStorage->isRenderTarget())
930 {
931 convertToRenderTarget();
932 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000933
Geoff Lang8040f572013-07-25 16:49:54 -0400934 return mTexStorage ? mTexStorage->getRenderTargetSerial(level) : 0;
935}
936
937rx::RenderTarget *Texture2D::getRenderTarget(GLint level)
938{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000939 // ensure the underlying texture is created
940 if (getStorage(true) == NULL)
941 {
942 return NULL;
943 }
944
945 updateTexture();
Geoff Lang8040f572013-07-25 16:49:54 -0400946
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000947 // ensure this is NOT a depth texture
Geoff Lang8040f572013-07-25 16:49:54 -0400948 if (isDepth(level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000949 {
950 return NULL;
951 }
daniel@transgaming.com34da3972012-12-20 21:10:29 +0000952
Geoff Lang8040f572013-07-25 16:49:54 -0400953 return mTexStorage->getRenderTarget(level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000954}
955
Geoff Lang8040f572013-07-25 16:49:54 -0400956rx::RenderTarget *Texture2D::getDepthSencil(GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000957{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000958 // ensure the underlying texture is created
959 if (getStorage(true) == NULL)
960 {
961 return NULL;
962 }
963
964 updateTexture();
965
966 // ensure this is actually a depth texture
Geoff Lang8040f572013-07-25 16:49:54 -0400967 if (!isDepth(level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000968 {
969 return NULL;
970 }
Geoff Lang8040f572013-07-25 16:49:54 -0400971
972 return mTexStorage->getRenderTarget(level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000973}
974
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +0000975int Texture2D::levelCount()
976{
shannon.woods@transgaming.com5016f8e2013-02-28 23:20:57 +0000977 return mTexStorage ? mTexStorage->levelCount() : 0;
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +0000978}
979
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000980rx::TextureStorageInterface *Texture2D::getStorage(bool renderTarget)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000981{
982 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
983 {
984 if (renderTarget)
985 {
986 convertToRenderTarget();
987 }
988 else
989 {
990 createTexture();
991 }
992 }
993
994 return mTexStorage;
995}
996
Geoff Lang4907f2c2013-07-25 12:53:57 -0400997TextureCubeMap::TextureCubeMap(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_CUBE_MAP)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000998{
999 mTexStorage = NULL;
1000 for (int i = 0; i < 6; i++)
1001 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001002 for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
1003 {
daniel@transgaming.com244e1832012-12-20 20:52:35 +00001004 mImageArray[i][j] = renderer->createImage();
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001005 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001006 }
1007}
1008
1009TextureCubeMap::~TextureCubeMap()
1010{
1011 for (int i = 0; i < 6; i++)
1012 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001013 for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
1014 {
1015 delete mImageArray[i][j];
1016 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001017 }
1018
1019 delete mTexStorage;
1020 mTexStorage = NULL;
1021}
1022
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001023GLsizei TextureCubeMap::getWidth(GLenum target, GLint level) const
1024{
1025 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001026 return mImageArray[faceIndex(target)][level]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001027 else
1028 return 0;
1029}
1030
1031GLsizei TextureCubeMap::getHeight(GLenum target, GLint level) const
1032{
1033 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001034 return mImageArray[faceIndex(target)][level]->getHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001035 else
1036 return 0;
1037}
1038
1039GLenum TextureCubeMap::getInternalFormat(GLenum target, GLint level) const
1040{
1041 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001042 return mImageArray[faceIndex(target)][level]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001043 else
1044 return GL_NONE;
1045}
1046
daniel@transgaming.com20d36662012-10-31 19:51:43 +00001047GLenum TextureCubeMap::getActualFormat(GLenum target, GLint level) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001048{
1049 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001050 return mImageArray[faceIndex(target)][level]->getActualFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001051 else
1052 return D3DFMT_UNKNOWN;
1053}
1054
Geoff Lang005df412013-10-16 14:12:50 -04001055void 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 +00001056{
Jamie Madill88f18f42013-09-18 14:36:19 -04001057 setImage(0, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001058}
1059
Geoff Lang005df412013-10-16 14:12:50 -04001060void 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 +00001061{
Jamie Madill88f18f42013-09-18 14:36:19 -04001062 setImage(1, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001063}
1064
Geoff Lang005df412013-10-16 14:12:50 -04001065void 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 +00001066{
Jamie Madill88f18f42013-09-18 14:36:19 -04001067 setImage(2, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001068}
1069
Geoff Lang005df412013-10-16 14:12:50 -04001070void 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 +00001071{
Jamie Madill88f18f42013-09-18 14:36:19 -04001072 setImage(3, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001073}
1074
Geoff Lang005df412013-10-16 14:12:50 -04001075void 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 +00001076{
Jamie Madill88f18f42013-09-18 14:36:19 -04001077 setImage(4, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001078}
1079
Geoff Lang005df412013-10-16 14:12:50 -04001080void 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 +00001081{
Jamie Madill88f18f42013-09-18 14:36:19 -04001082 setImage(5, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001083}
1084
1085void TextureCubeMap::setCompressedImage(GLenum face, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
1086{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001087 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001088 redefineImage(faceIndex(face), level, format, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001089
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001090 Texture::setCompressedImage(imageSize, pixels, mImageArray[faceIndex(face)][level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001091}
1092
1093void TextureCubeMap::commitRect(int face, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1094{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001095 if (level < levelCount())
1096 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001097 rx::Image *image = mImageArray[face][level];
daniel@transgaming.com0f195ad2012-10-31 19:51:59 +00001098 if (image->updateSurface(mTexStorage, face, level, xoffset, yoffset, width, height))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001099 image->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001100 }
1101}
1102
Jamie Madill88f18f42013-09-18 14:36:19 -04001103void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001104{
Jamie Madill88f18f42013-09-18 14:36:19 -04001105 if (Texture::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, mImageArray[faceIndex(target)][level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001106 {
1107 commitRect(faceIndex(target), level, xoffset, yoffset, width, height);
1108 }
1109}
1110
1111void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1112{
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +00001113 if (Texture::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[faceIndex(target)][level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001114 {
1115 commitRect(faceIndex(target), level, xoffset, yoffset, width, height);
1116 }
1117}
1118
1119// Tests for cube map sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 86.
Jamie Madillf8989902013-07-19 16:36:58 -04001120bool TextureCubeMap::isSamplerComplete(const SamplerState &samplerState) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001121{
Jamie Madilld3d2a342013-10-07 10:46:35 -04001122 int size = getBaseLevelWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001123
Jamie Madillf8989902013-07-19 16:36:58 -04001124 bool mipmapping = IsMipmapFiltered(samplerState);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001125
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001126 if (!IsTextureFilteringSupported(getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0), mRenderer))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001127 {
Jamie Madillf8989902013-07-19 16:36:58 -04001128 if (samplerState.magFilter != GL_NEAREST ||
1129 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001130 {
1131 return false;
1132 }
1133 }
1134
daniel@transgaming.comea32d482012-11-28 19:33:18 +00001135 if (!isPow2(size) && !mRenderer->getNonPower2TextureSupport())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001136 {
Jamie Madillf8989902013-07-19 16:36:58 -04001137 if (samplerState.wrapS != GL_CLAMP_TO_EDGE || samplerState.wrapT != GL_CLAMP_TO_EDGE || mipmapping)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001138 {
1139 return false;
1140 }
1141 }
1142
1143 if (!mipmapping)
1144 {
1145 if (!isCubeComplete())
1146 {
1147 return false;
1148 }
1149 }
1150 else
1151 {
1152 if (!isMipmapCubeComplete()) // Also tests for isCubeComplete()
1153 {
1154 return false;
1155 }
1156 }
1157
1158 return true;
1159}
1160
1161// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1162bool TextureCubeMap::isCubeComplete() const
1163{
Jamie Madillc1f8b162013-10-07 10:46:38 -04001164 int baseWidth = getBaseLevelWidth();
1165 int baseHeight = getBaseLevelHeight();
1166 GLenum baseFormat = getBaseLevelInternalFormat();
1167
1168 if (baseWidth <= 0 || baseWidth != baseHeight)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001169 {
1170 return false;
1171 }
1172
1173 for (unsigned int face = 1; face < 6; face++)
1174 {
Jamie Madillc1f8b162013-10-07 10:46:38 -04001175 const rx::Image &faceBaseImage = *mImageArray[face][0];
1176
1177 if (faceBaseImage.getWidth() != baseWidth ||
1178 faceBaseImage.getHeight() != baseHeight ||
1179 faceBaseImage.getInternalFormat() != baseFormat )
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001180 {
1181 return false;
1182 }
1183 }
1184
1185 return true;
1186}
1187
1188bool TextureCubeMap::isMipmapCubeComplete() const
1189{
1190 if (isImmutable())
1191 {
1192 return true;
1193 }
1194
1195 if (!isCubeComplete())
1196 {
1197 return false;
1198 }
1199
Jamie Madilld3d2a342013-10-07 10:46:35 -04001200 GLsizei size = getBaseLevelWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001201 int q = log2(size);
1202
1203 for (int face = 0; face < 6; face++)
1204 {
1205 for (int level = 1; level <= q; level++)
1206 {
Jamie Madill07edd442013-07-19 16:36:58 -04001207 if (!isFaceLevelComplete(face, level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001208 {
1209 return false;
1210 }
1211 }
1212 }
1213
1214 return true;
1215}
1216
Jamie Madill07edd442013-07-19 16:36:58 -04001217bool TextureCubeMap::isFaceLevelComplete(int face, int level) const
1218{
1219 ASSERT(level >= 0 && face < 6 && level < (int)ArraySize(mImageArray[face]) && mImageArray[face][level] != NULL);
1220
1221 if (isImmutable())
1222 {
1223 return true;
1224 }
1225
Jamie Madilld3d2a342013-10-07 10:46:35 -04001226 int baseSize = getBaseLevelWidth();
Jamie Madill07edd442013-07-19 16:36:58 -04001227
Jamie Madilld3d2a342013-10-07 10:46:35 -04001228 if (baseSize <= 0)
Jamie Madill07edd442013-07-19 16:36:58 -04001229 {
1230 return false;
1231 }
1232
Jamie Madilld3d2a342013-10-07 10:46:35 -04001233 // "isCubeComplete" checks for base level completeness and we must call that
1234 // to determine if any face at level 0 is complete. We omit that check here
1235 // to avoid re-checking cube-completeness for every face at level 0.
Jamie Madill07edd442013-07-19 16:36:58 -04001236 if (level == 0)
1237 {
1238 return true;
1239 }
1240
Jamie Madilld3d2a342013-10-07 10:46:35 -04001241 // Check that non-zero levels are consistent with the base level.
1242 const rx::Image *faceLevelImage = mImageArray[face][level];
Jamie Madill07edd442013-07-19 16:36:58 -04001243
Jamie Madilld3d2a342013-10-07 10:46:35 -04001244 if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat())
Jamie Madill07edd442013-07-19 16:36:58 -04001245 {
1246 return false;
1247 }
1248
Jamie Madilld3d2a342013-10-07 10:46:35 -04001249 if (faceLevelImage->getWidth() != std::max(1, baseSize >> level))
Jamie Madill07edd442013-07-19 16:36:58 -04001250 {
1251 return false;
1252 }
1253
1254 return true;
1255}
1256
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001257bool TextureCubeMap::isCompressed(GLenum target, GLint level) const
1258{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001259 return IsFormatCompressed(getInternalFormat(target, level), mRenderer->getCurrentClientVersion());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001260}
1261
Geoff Lang8040f572013-07-25 16:49:54 -04001262bool TextureCubeMap::isDepth(GLenum target, GLint level) const
1263{
1264 return GetDepthBits(getInternalFormat(target, level), mRenderer->getCurrentClientVersion()) > 0;
1265}
1266
daniel@transgaming.comf032cb82012-10-31 19:51:52 +00001267// Constructs a native texture resource from the texture images, or returns an existing one
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001268void TextureCubeMap::createTexture()
1269{
Jamie Madilld3d2a342013-10-07 10:46:35 -04001270 GLsizei size = getBaseLevelWidth();
daniel@transgaming.come6a09842012-09-17 21:28:55 +00001271
1272 if (!(size > 0))
daniel@transgaming.comf032cb82012-10-31 19:51:52 +00001273 return; // do not attempt to create native textures for nonexistant data
daniel@transgaming.come6a09842012-09-17 21:28:55 +00001274
sminns@adobe.comce1189b2012-09-18 20:06:35 +00001275 GLint levels = creationLevels(size);
Jamie Madilld3d2a342013-10-07 10:46:35 -04001276 GLenum internalformat = getBaseLevelInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001277
1278 delete mTexStorage;
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001279 mTexStorage = new rx::TextureStorageInterfaceCube(mRenderer, levels, internalformat, mUsage, false, size);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001280
1281 if (mTexStorage->isManaged())
1282 {
1283 int levels = levelCount();
1284
1285 for (int face = 0; face < 6; face++)
1286 {
1287 for (int level = 0; level < levels; level++)
1288 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001289 mImageArray[face][level]->setManagedSurface(mTexStorage, face, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001290 }
1291 }
1292 }
1293
1294 mDirtyImages = true;
1295}
1296
1297void TextureCubeMap::updateTexture()
1298{
Jamie Madilleb3665c2013-07-19 16:36:57 -04001299 int levels = (isMipmapCubeComplete() ? levelCount() : 1);
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +00001300
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001301 for (int face = 0; face < 6; face++)
1302 {
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001303 for (int level = 0; level < levels; level++)
1304 {
Jamie Madill07edd442013-07-19 16:36:58 -04001305 updateTextureFaceLevel(face, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001306 }
1307 }
1308}
1309
Jamie Madill07edd442013-07-19 16:36:58 -04001310void TextureCubeMap::updateTextureFaceLevel(int face, int level)
1311{
1312 ASSERT(level >= 0 && face < 6 && level < (int)ArraySize(mImageArray[face]) && mImageArray[face][level] != NULL);
1313 rx::Image *image = mImageArray[face][level];
1314
1315 if (image->isDirty())
1316 {
1317 commitRect(face, level, 0, 0, image->getWidth(), image->getHeight());
1318 }
1319}
1320
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001321void TextureCubeMap::convertToRenderTarget()
1322{
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001323 rx::TextureStorageInterfaceCube *newTexStorage = NULL;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001324
Jamie Madilld3d2a342013-10-07 10:46:35 -04001325 if (getBaseLevelWidth() != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001326 {
Jamie Madilld3d2a342013-10-07 10:46:35 -04001327 GLsizei size = getBaseLevelWidth();
shannon.woods@transgaming.com6bb48862013-02-28 23:09:34 +00001328 GLint levels = mTexStorage != NULL ? mTexStorage->levelCount() : creationLevels(size);
Jamie Madilld3d2a342013-10-07 10:46:35 -04001329 GLenum internalformat = getBaseLevelInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001330
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001331 newTexStorage = new rx::TextureStorageInterfaceCube(mRenderer, levels, internalformat, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, true, size);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001332
1333 if (mTexStorage != NULL)
1334 {
daniel@transgaming.com1d80eee2012-11-28 19:33:31 +00001335 if (!mRenderer->copyToRenderTarget(newTexStorage, mTexStorage))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001336 {
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +00001337 delete newTexStorage;
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +00001338 return gl::error(GL_OUT_OF_MEMORY);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001339 }
1340 }
1341 }
1342
1343 delete mTexStorage;
1344 mTexStorage = newTexStorage;
1345
1346 mDirtyImages = true;
1347}
1348
Geoff Lang005df412013-10-16 14:12:50 -04001349void 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 +00001350{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001351 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Geoff Lang005df412013-10-16 14:12:50 -04001352 GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
1353 : GetSizedInternalFormat(format, type, clientVersion);
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001354
1355 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001356
Jamie Madill88f18f42013-09-18 14:36:19 -04001357 Texture::setImage(unpack, type, pixels, mImageArray[faceIndex][level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001358}
1359
1360unsigned int TextureCubeMap::faceIndex(GLenum face)
1361{
1362 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
1363 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
1364 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
1365 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
1366 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
1367
1368 return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
1369}
1370
Geoff Lang005df412013-10-16 14:12:50 -04001371void TextureCubeMap::redefineImage(int face, GLint level, GLenum internalformat, GLsizei width, GLsizei height)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001372{
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001373 // If there currently is a corresponding storage texture image, it has these parameters
Jamie Madilld3d2a342013-10-07 10:46:35 -04001374 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1375 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
Geoff Lang005df412013-10-16 14:12:50 -04001376 const GLenum storageFormat = getBaseLevelInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001377
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001378 mImageArray[face][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, width, height, 1, false);
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001379
1380 if (mTexStorage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001381 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001382 const int storageLevels = mTexStorage->levelCount();
1383
1384 if ((level >= storageLevels && storageLevels != 0) ||
1385 width != storageWidth ||
1386 height != storageHeight ||
1387 internalformat != storageFormat) // Discard mismatched storage
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001388 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001389 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001390 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001391 for (int f = 0; f < 6; f++)
1392 {
1393 mImageArray[f][i]->markDirty();
1394 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001395 }
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001396
1397 delete mTexStorage;
1398 mTexStorage = NULL;
1399
1400 mDirtyImages = true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001401 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001402 }
1403}
1404
1405void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1406{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001407 unsigned int faceindex = faceIndex(target);
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001408 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Geoff Lang005df412013-10-16 14:12:50 -04001409 GLenum sizedInternalFormat = IsSizedInternalFormat(format, clientVersion) ? format
1410 : GetSizedInternalFormat(format, GL_UNSIGNED_BYTE, clientVersion);
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001411 redefineImage(faceindex, level, sizedInternalFormat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001412
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001413 if (!mImageArray[faceindex][level]->isRenderableFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001414 {
shannon.woods%transgaming.com@gtempaccount.come5dcce72013-04-13 03:44:33 +00001415 mImageArray[faceindex][level]->copy(0, 0, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001416 mDirtyImages = true;
1417 }
1418 else
1419 {
1420 if (!mTexStorage || !mTexStorage->isRenderTarget())
1421 {
1422 convertToRenderTarget();
1423 }
1424
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001425 mImageArray[faceindex][level]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001426
1427 ASSERT(width == height);
1428
1429 if (width > 0 && level < levelCount())
1430 {
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +00001431 gl::Rectangle sourceRect;
1432 sourceRect.x = x;
1433 sourceRect.width = width;
1434 sourceRect.y = y;
1435 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001436
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +00001437 mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001438 }
1439 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001440}
1441
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001442void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001443{
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001444 GLsizei size = mImageArray[faceIndex(target)][level]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001445
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001446 if (xoffset + width > size || yoffset + height > size || zoffset != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001447 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +00001448 return gl::error(GL_INVALID_VALUE);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001449 }
1450
Jamie Madill07edd442013-07-19 16:36:58 -04001451 unsigned int face = faceIndex(target);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001452
Jamie Madilld3d2a342013-10-07 10:46:35 -04001453 // We can only make our texture storage to a render target if the level we're copying *to* is complete
1454 // and the base level is cube-complete. The base level must be cube complete (common case) because we cannot
1455 // rely on the "getBaseLevel*" methods reliably otherwise.
1456 bool canCreateRenderTarget = isFaceLevelComplete(face, level) && isCubeComplete();
Jamie Madill07edd442013-07-19 16:36:58 -04001457
1458 if (!mImageArray[face][level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001459 {
Jamie Madill07edd442013-07-19 16:36:58 -04001460 mImageArray[face][level]->copy(0, 0, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001461 mDirtyImages = true;
1462 }
1463 else
1464 {
1465 if (!mTexStorage || !mTexStorage->isRenderTarget())
1466 {
1467 convertToRenderTarget();
1468 }
1469
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001470 if (level < levelCount())
1471 {
Jamie Madill07edd442013-07-19 16:36:58 -04001472 updateTextureFaceLevel(face, level);
1473
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001474 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1475
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +00001476 gl::Rectangle sourceRect;
1477 sourceRect.x = x;
1478 sourceRect.width = width;
1479 sourceRect.y = y;
1480 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001481
Jamie Madilld3d2a342013-10-07 10:46:35 -04001482 mRenderer->copyImage(source, sourceRect, gl::GetFormat(getBaseLevelInternalFormat(), clientVersion),
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +00001483 xoffset, yoffset, mTexStorage, target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001484 }
1485 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001486}
1487
1488void TextureCubeMap::storage(GLsizei levels, GLenum internalformat, GLsizei size)
1489{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001490 delete mTexStorage;
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001491 mTexStorage = new rx::TextureStorageInterfaceCube(mRenderer, levels, internalformat, mUsage, false, size);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001492 mImmutable = true;
1493
1494 for (int level = 0; level < levels; level++)
1495 {
Geoff Langd3110192013-09-24 11:52:47 -04001496 GLsizei mipSize = std::max(1, size >> level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001497 for (int face = 0; face < 6; face++)
1498 {
Geoff Langd3110192013-09-24 11:52:47 -04001499 mImageArray[face][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, mipSize, mipSize, 1, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001500 }
1501 }
1502
1503 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1504 {
1505 for (int face = 0; face < 6; face++)
1506 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001507 mImageArray[face][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, GL_NONE, 0, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001508 }
1509 }
1510
1511 if (mTexStorage->isManaged())
1512 {
1513 int levels = levelCount();
1514
1515 for (int face = 0; face < 6; face++)
1516 {
1517 for (int level = 0; level < levels; level++)
1518 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001519 mImageArray[face][level]->setManagedSurface(mTexStorage, face, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001520 }
1521 }
1522 }
1523}
1524
1525void TextureCubeMap::generateMipmaps()
1526{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001527 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Jamie Madilld3d2a342013-10-07 10:46:35 -04001528 unsigned int q = log2(getBaseLevelWidth());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001529 for (unsigned int f = 0; f < 6; f++)
1530 {
1531 for (unsigned int i = 1; i <= q; i++)
1532 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001533 redefineImage(f, i, mImageArray[f][0]->getInternalFormat(),
shannon.woods@transgaming.com8a406682013-02-28 23:15:26 +00001534 std::max(mImageArray[f][0]->getWidth() >> i, 1),
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001535 std::max(mImageArray[f][0]->getWidth() >> i, 1));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001536 }
1537 }
1538
1539 if (mTexStorage && mTexStorage->isRenderTarget())
1540 {
1541 for (unsigned int f = 0; f < 6; f++)
1542 {
1543 for (unsigned int i = 1; i <= q; i++)
1544 {
daniel@transgaming.com0ad830b2012-10-31 19:52:12 +00001545 mTexStorage->generateMipmap(f, i);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001546
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001547 mImageArray[f][i]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001548 }
1549 }
1550 }
1551 else
1552 {
1553 for (unsigned int f = 0; f < 6; f++)
1554 {
1555 for (unsigned int i = 1; i <= q; i++)
1556 {
daniel@transgaming.com4ba24062012-12-20 20:54:24 +00001557 mRenderer->generateMipmap(mImageArray[f][i], mImageArray[f][i - 1]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001558 }
1559 }
1560 }
1561}
1562
Jamie Madilld3d2a342013-10-07 10:46:35 -04001563const rx::Image *TextureCubeMap::getBaseLevelImage() const
1564{
1565 // Note: if we are not cube-complete, there is no single base level image that can describe all
1566 // cube faces, so this method is only well-defined for a cube-complete base level.
1567 return mImageArray[0][0];
1568}
1569
Geoff Lang8040f572013-07-25 16:49:54 -04001570Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target, GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001571{
1572 if (!IsCubemapTextureTarget(target))
1573 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +00001574 return gl::error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001575 }
1576
1577 unsigned int face = faceIndex(target);
1578
Geoff Lang8040f572013-07-25 16:49:54 -04001579 Renderbuffer *renderBuffer = mRenderbufferProxies.get(level, face);
1580 if (!renderBuffer)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001581 {
Geoff Lang8040f572013-07-25 16:49:54 -04001582 renderBuffer = new Renderbuffer(mRenderer, id(), new RenderbufferTextureCubeMap(this, target, level));
1583 mRenderbufferProxies.add(level, face, renderBuffer);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001584 }
1585
Geoff Lang8040f572013-07-25 16:49:54 -04001586 return renderBuffer;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001587}
1588
Geoff Lang8040f572013-07-25 16:49:54 -04001589unsigned int TextureCubeMap::getRenderTargetSerial(GLenum faceTarget, GLint level)
1590{
1591 if (!mTexStorage || !mTexStorage->isRenderTarget())
1592 {
1593 convertToRenderTarget();
1594 }
1595
1596 return mTexStorage ? mTexStorage->getRenderTargetSerial(faceTarget, level) : 0;
1597}
1598
1599rx::RenderTarget *TextureCubeMap::getRenderTarget(GLenum target, GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001600{
1601 ASSERT(IsCubemapTextureTarget(target));
1602
1603 // ensure the underlying texture is created
1604 if (getStorage(true) == NULL)
1605 {
1606 return NULL;
1607 }
1608
1609 updateTexture();
Geoff Lang8040f572013-07-25 16:49:54 -04001610
1611 // ensure this is NOT a depth texture
1612 if (isDepth(target, level))
1613 {
1614 return NULL;
1615 }
1616
1617 return mTexStorage->getRenderTarget(target, level);
1618}
1619
1620rx::RenderTarget *TextureCubeMap::getDepthStencil(GLenum target, GLint level)
1621{
1622 ASSERT(IsCubemapTextureTarget(target));
1623
1624 // ensure the underlying texture is created
1625 if (getStorage(true) == NULL)
1626 {
1627 return NULL;
1628 }
1629
1630 updateTexture();
1631
1632 // ensure this is a depth texture
1633 if (!isDepth(target, level))
1634 {
1635 return NULL;
1636 }
1637
1638 return mTexStorage->getRenderTarget(target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001639}
1640
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +00001641int TextureCubeMap::levelCount()
1642{
1643 return mTexStorage ? mTexStorage->levelCount() - getLodOffset() : 0;
1644}
1645
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001646rx::TextureStorageInterface *TextureCubeMap::getStorage(bool renderTarget)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001647{
1648 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
1649 {
1650 if (renderTarget)
1651 {
1652 convertToRenderTarget();
1653 }
1654 else
1655 {
1656 createTexture();
1657 }
1658 }
1659
1660 return mTexStorage;
1661}
1662
Geoff Lang4907f2c2013-07-25 12:53:57 -04001663Texture3D::Texture3D(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_3D)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001664{
1665 mTexStorage = NULL;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001666
1667 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1668 {
1669 mImageArray[i] = renderer->createImage();
1670 }
1671}
1672
1673Texture3D::~Texture3D()
1674{
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001675 delete mTexStorage;
1676 mTexStorage = NULL;
1677
1678 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1679 {
1680 delete mImageArray[i];
1681 }
1682}
1683
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001684GLsizei Texture3D::getWidth(GLint level) const
1685{
1686 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getWidth() : 0;
1687}
1688
1689GLsizei Texture3D::getHeight(GLint level) const
1690{
1691 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getHeight() : 0;
1692}
1693
1694GLsizei Texture3D::getDepth(GLint level) const
1695{
1696 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getDepth() : 0;
1697}
1698
1699GLenum Texture3D::getInternalFormat(GLint level) const
1700{
1701 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getInternalFormat() : GL_NONE;
1702}
1703
1704GLenum Texture3D::getActualFormat(GLint level) const
1705{
1706 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getActualFormat() : D3DFMT_UNKNOWN;
1707}
1708
1709bool Texture3D::isCompressed(GLint level) const
1710{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001711 return IsFormatCompressed(getInternalFormat(level), mRenderer->getCurrentClientVersion());
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001712}
1713
1714bool Texture3D::isDepth(GLint level) const
1715{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001716 return GetDepthBits(getInternalFormat(level), mRenderer->getCurrentClientVersion()) > 0;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001717}
1718
Geoff Lang005df412013-10-16 14:12:50 -04001719void 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 +00001720{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001721 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Geoff Lang005df412013-10-16 14:12:50 -04001722 GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
1723 : GetSizedInternalFormat(format, type, clientVersion);
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001724 redefineImage(level, sizedInternalFormat, width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001725
Jamie Madilla2d4e552013-10-10 15:12:01 -04001726 bool fastUnpacked = false;
1727
1728 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1729 if (isFastUnpackable(unpack, sizedInternalFormat))
1730 {
1731 // Will try to create RT storage if it does not exist
1732 rx::RenderTarget *destRenderTarget = getRenderTarget(level);
1733 Box destArea(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1734
1735 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget))
1736 {
1737 // Ensure we don't overwrite our newly initialized data
1738 mImageArray[level]->markClean();
1739
1740 fastUnpacked = true;
1741 }
1742 }
1743
1744 if (!fastUnpacked)
1745 {
1746 Texture::setImage(unpack, type, pixels, mImageArray[level]);
1747 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001748}
1749
1750void Texture3D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
1751{
1752 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1753 redefineImage(level, format, width, height, depth);
1754
1755 Texture::setCompressedImage(imageSize, pixels, mImageArray[level]);
1756}
1757
Jamie Madill88f18f42013-09-18 14:36:19 -04001758void Texture3D::subImage(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001759{
Jamie Madillba4f10a2013-10-10 15:12:20 -04001760 bool fastUnpacked = false;
1761
1762 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1763 if (isFastUnpackable(unpack, getInternalFormat(level)))
1764 {
1765 rx::RenderTarget *destRenderTarget = getRenderTarget(level);
1766 Box destArea(xoffset, yoffset, zoffset, width, height, depth);
1767
1768 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, destRenderTarget))
1769 {
1770 // Ensure we don't overwrite our newly initialized data
1771 mImageArray[level]->markClean();
1772
1773 fastUnpacked = true;
1774 }
1775 }
1776
1777 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 +00001778 {
1779 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1780 }
1781}
1782
1783void Texture3D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
1784{
1785 if (Texture::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth, format, imageSize, pixels, mImageArray[level]))
1786 {
1787 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1788 }
1789}
1790
1791void Texture3D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
1792{
1793 delete mTexStorage;
1794 mTexStorage = new rx::TextureStorageInterface3D(mRenderer, levels, internalformat, mUsage, width, height, depth);
1795 mImmutable = true;
1796
1797 for (int level = 0; level < levels; level++)
1798 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001799 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, true);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001800 width = std::max(1, width >> 1);
1801 height = std::max(1, height >> 1);
1802 depth = std::max(1, depth >> 1);
1803 }
1804
1805 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1806 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001807 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, GL_NONE, 0, 0, 0, true);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001808 }
1809
1810 if (mTexStorage->isManaged())
1811 {
1812 int levels = levelCount();
1813
1814 for (int level = 0; level < levels; level++)
1815 {
1816 mImageArray[level]->setManagedSurface(mTexStorage, level);
1817 }
1818 }
1819}
1820
1821
1822void Texture3D::generateMipmaps()
1823{
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001824 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Jamie Madilld3d2a342013-10-07 10:46:35 -04001825 unsigned int q = log2(std::max(getBaseLevelWidth(), getBaseLevelHeight()));
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001826 for (unsigned int i = 1; i <= q; i++)
1827 {
Jamie Madilld3d2a342013-10-07 10:46:35 -04001828 redefineImage(i, getBaseLevelInternalFormat(),
1829 std::max(getBaseLevelWidth() >> i, 1),
1830 std::max(getBaseLevelHeight() >> i, 1),
1831 std::max(getBaseLevelDepth() >> i, 1));
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001832 }
1833
1834 if (mTexStorage && mTexStorage->isRenderTarget())
1835 {
1836 for (unsigned int i = 1; i <= q; i++)
1837 {
1838 mTexStorage->generateMipmap(i);
1839
1840 mImageArray[i]->markClean();
1841 }
1842 }
1843 else
1844 {
1845 for (unsigned int i = 1; i <= q; i++)
1846 {
1847 mRenderer->generateMipmap(mImageArray[i], mImageArray[i - 1]);
1848 }
1849 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001850}
1851
Jamie Madilld3d2a342013-10-07 10:46:35 -04001852const rx::Image *Texture3D::getBaseLevelImage() const
1853{
1854 return mImageArray[0];
1855}
1856
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001857void Texture3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1858{
1859 if (xoffset + width > mImageArray[level]->getWidth() || yoffset + height > mImageArray[level]->getHeight() || zoffset >= mImageArray[level]->getDepth())
1860 {
1861 return gl::error(GL_INVALID_VALUE);
1862 }
1863
Jamie Madill07edd442013-07-19 16:36:58 -04001864 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
1865 // the current level we're copying to is defined (with appropriate format, width & height)
1866 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
1867
1868 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001869 {
1870 mImageArray[level]->copy(xoffset, yoffset, zoffset, x, y, width, height, source);
1871 mDirtyImages = true;
1872 }
1873 else
1874 {
1875 if (!mTexStorage || !mTexStorage->isRenderTarget())
1876 {
1877 convertToRenderTarget();
1878 }
1879
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001880 if (level < levelCount())
1881 {
Jamie Madill07edd442013-07-19 16:36:58 -04001882 updateTextureLevel(level);
1883
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001884 gl::Rectangle sourceRect;
1885 sourceRect.x = x;
1886 sourceRect.width = width;
1887 sourceRect.y = y;
1888 sourceRect.height = height;
1889
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001890 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1891
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001892 mRenderer->copyImage(source, sourceRect,
Jamie Madilld3d2a342013-10-07 10:46:35 -04001893 gl::GetFormat(getBaseLevelInternalFormat(), clientVersion),
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001894 xoffset, yoffset, zoffset, mTexStorage, level);
1895 }
1896 }
1897}
1898
Jamie Madillf8989902013-07-19 16:36:58 -04001899bool Texture3D::isSamplerComplete(const SamplerState &samplerState) const
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001900{
Jamie Madilld3d2a342013-10-07 10:46:35 -04001901 GLsizei width = getBaseLevelWidth();
1902 GLsizei height = getBaseLevelHeight();
1903 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001904
1905 if (width <= 0 || height <= 0 || depth <= 0)
1906 {
1907 return false;
1908 }
1909
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001910 if (!IsTextureFilteringSupported(getInternalFormat(0), mRenderer))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001911 {
Jamie Madillf8989902013-07-19 16:36:58 -04001912 if (samplerState.magFilter != GL_NEAREST ||
1913 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001914 {
1915 return false;
1916 }
1917 }
1918
Jamie Madillf8989902013-07-19 16:36:58 -04001919 if (IsMipmapFiltered(samplerState) && !isMipmapComplete())
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001920 {
1921 return false;
1922 }
1923
1924 return true;
1925}
1926
1927bool Texture3D::isMipmapComplete() const
1928{
Jamie Madilld3d2a342013-10-07 10:46:35 -04001929 GLsizei width = getBaseLevelWidth();
1930 GLsizei height = getBaseLevelHeight();
1931 GLsizei depth = getBaseLevelDepth();
Jamie Madill07edd442013-07-19 16:36:58 -04001932
1933 int q = log2(std::max(std::max(width, height), depth));
1934
1935 for (int level = 0; level <= q; level++)
1936 {
1937 if (!isLevelComplete(level))
1938 {
1939 return false;
1940 }
1941 }
1942
1943 return true;
1944}
1945
1946bool Texture3D::isLevelComplete(int level) const
1947{
1948 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1949
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001950 if (isImmutable())
1951 {
1952 return true;
1953 }
1954
Jamie Madilld3d2a342013-10-07 10:46:35 -04001955 GLsizei width = getBaseLevelWidth();
1956 GLsizei height = getBaseLevelHeight();
1957 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001958
1959 if (width <= 0 || height <= 0 || depth <= 0)
1960 {
1961 return false;
1962 }
1963
Jamie Madill07edd442013-07-19 16:36:58 -04001964 if (level == 0)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001965 {
Jamie Madill07edd442013-07-19 16:36:58 -04001966 return true;
1967 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001968
Jamie Madill07edd442013-07-19 16:36:58 -04001969 rx::Image *levelImage = mImageArray[level];
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001970
Jamie Madilld3d2a342013-10-07 10:46:35 -04001971 if (levelImage->getInternalFormat() != getBaseLevelInternalFormat())
Jamie Madill07edd442013-07-19 16:36:58 -04001972 {
1973 return false;
1974 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001975
Jamie Madill07edd442013-07-19 16:36:58 -04001976 if (levelImage->getWidth() != std::max(1, width >> level))
1977 {
1978 return false;
1979 }
1980
1981 if (levelImage->getHeight() != std::max(1, height >> level))
1982 {
1983 return false;
1984 }
1985
1986 if (levelImage->getDepth() != std::max(1, depth >> level))
1987 {
1988 return false;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001989 }
1990
1991 return true;
1992}
1993
Geoff Lang8040f572013-07-25 16:49:54 -04001994Renderbuffer *Texture3D::getRenderbuffer(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001995{
Geoff Lang8040f572013-07-25 16:49:54 -04001996 Renderbuffer *renderBuffer = mRenderbufferProxies.get(level, layer);
1997 if (!renderBuffer)
1998 {
Geoff Langd5d8e392013-07-25 16:53:03 -04001999 renderBuffer = new Renderbuffer(mRenderer, id(), new RenderbufferTexture3DLayer(this, level, layer));
2000 mRenderbufferProxies.add(level, 0, renderBuffer);
Geoff Lang8040f572013-07-25 16:49:54 -04002001 }
2002
2003 return renderBuffer;
2004}
2005
2006unsigned int Texture3D::getRenderTargetSerial(GLint level, GLint layer)
2007{
2008 if (!mTexStorage || !mTexStorage->isRenderTarget())
2009 {
2010 convertToRenderTarget();
2011 }
2012
2013 return mTexStorage ? mTexStorage->getRenderTargetSerial(level, layer) : 0;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002014}
2015
2016int Texture3D::levelCount()
2017{
2018 return mTexStorage ? mTexStorage->levelCount() : 0;
2019}
2020
2021void Texture3D::createTexture()
2022{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002023 GLsizei width = getBaseLevelWidth();
2024 GLsizei height = getBaseLevelHeight();
2025 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002026
2027 if (!(width > 0 && height > 0 && depth > 0))
2028 return; // do not attempt to create native textures for nonexistant data
2029
2030 GLint levels = creationLevels(width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002031
2032 delete mTexStorage;
Jamie Madilld3d2a342013-10-07 10:46:35 -04002033 mTexStorage = new rx::TextureStorageInterface3D(mRenderer, levels, getBaseLevelInternalFormat(), mUsage, width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002034
2035 if (mTexStorage->isManaged())
2036 {
2037 int levels = levelCount();
2038
2039 for (int level = 0; level < levels; level++)
2040 {
2041 mImageArray[level]->setManagedSurface(mTexStorage, level);
2042 }
2043 }
2044
2045 mDirtyImages = true;
2046}
2047
2048void Texture3D::updateTexture()
2049{
Jamie Madilleb3665c2013-07-19 16:36:57 -04002050 int levels = (isMipmapComplete() ? levelCount() : 1);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002051
2052 for (int level = 0; level < levels; level++)
2053 {
Jamie Madill07edd442013-07-19 16:36:58 -04002054 updateTextureLevel(level);
2055 }
2056}
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002057
Jamie Madill07edd442013-07-19 16:36:58 -04002058void Texture3D::updateTextureLevel(int level)
2059{
2060 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
2061
2062 rx::Image *image = mImageArray[level];
2063
2064 if (image->isDirty())
2065 {
2066 commitRect(level, 0, 0, 0, mImageArray[level]->getWidth(), mImageArray[level]->getHeight(), mImageArray[level]->getDepth());
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002067 }
2068}
2069
2070void Texture3D::convertToRenderTarget()
2071{
2072 rx::TextureStorageInterface3D *newTexStorage = NULL;
2073
Jamie Madilld3d2a342013-10-07 10:46:35 -04002074 if (getBaseLevelWidth() != 0 && getBaseLevelHeight() != 0 && getBaseLevelDepth() != 0)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002075 {
Jamie Madilld3d2a342013-10-07 10:46:35 -04002076 GLsizei width = getBaseLevelWidth();
2077 GLsizei height = getBaseLevelHeight();
2078 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002079 GLint levels = mTexStorage != NULL ? mTexStorage->levelCount() : creationLevels(width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002080
Jamie Madilld3d2a342013-10-07 10:46:35 -04002081 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 +00002082
2083 if (mTexStorage != NULL)
2084 {
2085 if (!mRenderer->copyToRenderTarget(newTexStorage, mTexStorage))
2086 {
2087 delete newTexStorage;
2088 return gl::error(GL_OUT_OF_MEMORY);
2089 }
2090 }
2091 }
2092
2093 delete mTexStorage;
2094 mTexStorage = newTexStorage;
2095
2096 mDirtyImages = true;
2097}
2098
Jamie Madilla2d4e552013-10-10 15:12:01 -04002099rx::RenderTarget *Texture3D::getRenderTarget(GLint level)
2100{
2101 // ensure the underlying texture is created
2102 if (getStorage(true) == NULL)
2103 {
2104 return NULL;
2105 }
2106
2107 updateTexture();
2108
2109 // ensure this is NOT a depth texture
2110 if (isDepth(level))
2111 {
2112 return NULL;
2113 }
2114
2115 return mTexStorage->getRenderTarget(level);
2116}
2117
Geoff Lang8040f572013-07-25 16:49:54 -04002118rx::RenderTarget *Texture3D::getRenderTarget(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002119{
Geoff Lang8040f572013-07-25 16:49:54 -04002120 // ensure the underlying texture is created
2121 if (getStorage(true) == NULL)
2122 {
2123 return NULL;
2124 }
2125
2126 updateTexture();
2127
2128 // ensure this is NOT a depth texture
2129 if (isDepth(level))
2130 {
2131 return NULL;
2132 }
2133
2134 return mTexStorage->getRenderTarget(level, layer);
2135}
2136
2137rx::RenderTarget *Texture3D::getDepthStencil(GLint level, GLint layer)
2138{
2139 // ensure the underlying texture is created
2140 if (getStorage(true) == NULL)
2141 {
2142 return NULL;
2143 }
2144
2145 updateTexture();
2146
2147 // ensure this is a depth texture
2148 if (!isDepth(level))
2149 {
2150 return NULL;
2151 }
2152
2153 return mTexStorage->getRenderTarget(level, layer);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002154}
2155
2156rx::TextureStorageInterface *Texture3D::getStorage(bool renderTarget)
2157{
2158 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
2159 {
2160 if (renderTarget)
2161 {
2162 convertToRenderTarget();
2163 }
2164 else
2165 {
2166 createTexture();
2167 }
2168 }
2169
2170 return mTexStorage;
2171}
2172
Geoff Lang005df412013-10-16 14:12:50 -04002173void Texture3D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002174{
2175 // If there currently is a corresponding storage texture image, it has these parameters
Jamie Madilld3d2a342013-10-07 10:46:35 -04002176 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2177 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
2178 const int storageDepth = std::max(1, getBaseLevelDepth() >> level);
Geoff Lang005df412013-10-16 14:12:50 -04002179 const GLenum storageFormat = getBaseLevelInternalFormat();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002180
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00002181 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, false);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002182
2183 if (mTexStorage)
2184 {
2185 const int storageLevels = mTexStorage->levelCount();
2186
2187 if ((level >= storageLevels && storageLevels != 0) ||
2188 width != storageWidth ||
2189 height != storageHeight ||
2190 depth != storageDepth ||
2191 internalformat != storageFormat) // Discard mismatched storage
2192 {
2193 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
2194 {
2195 mImageArray[i]->markDirty();
2196 }
2197
2198 delete mTexStorage;
2199 mTexStorage = NULL;
2200 mDirtyImages = true;
2201 }
2202 }
2203}
2204
2205void Texture3D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth)
2206{
2207 if (level < levelCount())
2208 {
2209 rx::Image *image = mImageArray[level];
2210 if (image->updateSurface(mTexStorage, level, xoffset, yoffset, zoffset, width, height, depth))
2211 {
2212 image->markClean();
2213 }
2214 }
2215}
2216
Geoff Lang4907f2c2013-07-25 12:53:57 -04002217Texture2DArray::Texture2DArray(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_2D_ARRAY)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002218{
2219 mTexStorage = NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002220
2221 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2222 {
2223 mLayerCounts[level] = 0;
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002224 mImageArray[level] = NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002225 }
2226}
2227
2228Texture2DArray::~Texture2DArray()
2229{
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002230 delete mTexStorage;
2231 mTexStorage = NULL;
2232 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2233 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002234 for (int layer = 0; layer < mLayerCounts[level]; ++layer)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002235 {
2236 delete mImageArray[level][layer];
2237 }
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002238 delete[] mImageArray[level];
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002239 }
2240}
2241
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002242GLsizei Texture2DArray::getWidth(GLint level) const
2243{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002244 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 +00002245}
2246
2247GLsizei Texture2DArray::getHeight(GLint level) const
2248{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002249 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 +00002250}
2251
2252GLsizei Texture2DArray::getDepth(GLint level) const
2253{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002254 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mLayerCounts[level] : 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002255}
2256
2257GLenum Texture2DArray::getInternalFormat(GLint level) const
2258{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002259 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 +00002260}
2261
2262GLenum Texture2DArray::getActualFormat(GLint level) const
2263{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002264 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 +00002265}
2266
2267bool Texture2DArray::isCompressed(GLint level) const
2268{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00002269 return IsFormatCompressed(getInternalFormat(level), mRenderer->getCurrentClientVersion());
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002270}
2271
2272bool Texture2DArray::isDepth(GLint level) const
2273{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00002274 return GetDepthBits(getInternalFormat(level), mRenderer->getCurrentClientVersion()) > 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002275}
2276
Geoff Lang005df412013-10-16 14:12:50 -04002277void 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 +00002278{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00002279 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Geoff Lang005df412013-10-16 14:12:50 -04002280 GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
2281 : GetSizedInternalFormat(format, type, clientVersion);
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00002282 redefineImage(level, sizedInternalFormat, width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002283
Jamie Madill88f18f42013-09-18 14:36:19 -04002284 GLsizei inputDepthPitch = gl::GetDepthPitch(sizedInternalFormat, type, clientVersion, width, height, unpack.alignment);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002285
2286 for (int i = 0; i < depth; i++)
2287 {
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002288 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
Jamie Madill88f18f42013-09-18 14:36:19 -04002289 Texture::setImage(unpack, type, layerPixels, mImageArray[level][i]);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002290 }
2291}
2292
2293void Texture2DArray::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
2294{
2295 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
2296 redefineImage(level, format, width, height, depth);
2297
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002298 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2299 GLsizei inputDepthPitch = gl::GetDepthPitch(format, GL_UNSIGNED_BYTE, clientVersion, width, height, 1);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002300
2301 for (int i = 0; i < depth; i++)
2302 {
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002303 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002304 Texture::setCompressedImage(imageSize, layerPixels, mImageArray[level][i]);
2305 }
2306}
2307
Jamie Madill88f18f42013-09-18 14:36:19 -04002308void 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 +00002309{
Geoff Lang005df412013-10-16 14:12:50 -04002310 GLenum internalformat = getInternalFormat(level);
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002311 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Jamie Madill88f18f42013-09-18 14:36:19 -04002312 GLsizei inputDepthPitch = gl::GetDepthPitch(internalformat, type, clientVersion, width, height, unpack.alignment);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002313
2314 for (int i = 0; i < depth; i++)
2315 {
2316 int layer = zoffset + i;
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002317 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002318
Jamie Madill88f18f42013-09-18 14:36:19 -04002319 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 +00002320 {
2321 commitRect(level, xoffset, yoffset, layer, width, height);
2322 }
2323 }
2324}
2325
2326void Texture2DArray::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
2327{
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002328 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2329 GLsizei inputDepthPitch = gl::GetDepthPitch(format, GL_UNSIGNED_BYTE, clientVersion, width, height, 1);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002330
2331 for (int i = 0; i < depth; i++)
2332 {
2333 int layer = zoffset + i;
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002334 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002335
2336 if (Texture::subImageCompressed(xoffset, yoffset, zoffset, width, height, 1, format, imageSize, layerPixels, mImageArray[level][layer]))
2337 {
2338 commitRect(level, xoffset, yoffset, layer, width, height);
2339 }
2340 }
2341}
2342
2343void Texture2DArray::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2344{
2345 delete mTexStorage;
2346 mTexStorage = new rx::TextureStorageInterface2DArray(mRenderer, levels, internalformat, mUsage, width, height, depth);
2347 mImmutable = true;
2348
2349 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2350 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002351 GLsizei levelWidth = std::max(width >> level, 1);
Geoff Lange836cf22013-08-05 14:12:37 -04002352 GLsizei levelHeight = std::max(height >> level, 1);
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002353
2354 // Clear this level
2355 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002356 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002357 delete mImageArray[level][layer];
2358 }
2359 delete[] mImageArray[level];
2360 mImageArray[level] = NULL;
2361 mLayerCounts[level] = 0;
2362
2363 if (level < levels)
2364 {
2365 // Create new images for this level
2366 mImageArray[level] = new rx::Image*[depth]();
2367 mLayerCounts[level] = depth;
2368
2369 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002370 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002371 mImageArray[level][layer] = mRenderer->createImage();
2372 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, levelWidth,
2373 levelHeight, 1, true);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002374 }
2375 }
2376 }
2377
2378 if (mTexStorage->isManaged())
2379 {
2380 int levels = levelCount();
2381
2382 for (int level = 0; level < levels; level++)
2383 {
2384 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2385 {
2386 mImageArray[level][layer]->setManagedSurface(mTexStorage, layer, level);
2387 }
2388 }
2389 }
2390}
2391
2392void Texture2DArray::generateMipmaps()
2393{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002394 int baseWidth = getBaseLevelWidth();
2395 int baseHeight = getBaseLevelHeight();
2396 int baseDepth = getBaseLevelDepth();
2397 GLenum baseFormat = getBaseLevelInternalFormat();
2398
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00002399 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Jamie Madilld3d2a342013-10-07 10:46:35 -04002400 int q = log2(std::max(baseWidth, baseHeight));
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00002401 for (int i = 1; i <= q; i++)
2402 {
Jamie Madilld3d2a342013-10-07 10:46:35 -04002403 redefineImage(i, baseFormat, std::max(baseWidth >> i, 1), std::max(baseHeight >> i, 1), baseDepth);
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00002404 }
2405
2406 if (mTexStorage && mTexStorage->isRenderTarget())
2407 {
2408 for (int level = 1; level <= q; level++)
2409 {
2410 mTexStorage->generateMipmap(level);
2411
2412 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2413 {
2414 mImageArray[level][layer]->markClean();
2415 }
2416 }
2417 }
2418 else
2419 {
2420 for (int level = 1; level <= q; level++)
2421 {
2422 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2423 {
2424 mRenderer->generateMipmap(mImageArray[level][layer], mImageArray[level - 1][layer]);
2425 }
2426 }
2427 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002428}
2429
Jamie Madilld3d2a342013-10-07 10:46:35 -04002430const rx::Image *Texture2DArray::getBaseLevelImage() const
2431{
Jamie Madill152ed092013-10-09 17:01:15 -04002432 return (mLayerCounts[0] > 0 ? mImageArray[0][0] : NULL);
Jamie Madilld3d2a342013-10-07 10:46:35 -04002433}
2434
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002435void Texture2DArray::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
2436{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002437 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 +00002438 {
2439 return gl::error(GL_INVALID_VALUE);
2440 }
2441
Jamie Madill07edd442013-07-19 16:36:58 -04002442 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
2443 // the current level we're copying to is defined (with appropriate format, width & height)
2444 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
2445
2446 if (!mImageArray[level][0]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002447 {
2448 mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, x, y, width, height, source);
2449 mDirtyImages = true;
2450 }
2451 else
2452 {
2453 if (!mTexStorage || !mTexStorage->isRenderTarget())
2454 {
2455 convertToRenderTarget();
2456 }
2457
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002458 if (level < levelCount())
2459 {
Jamie Madill07edd442013-07-19 16:36:58 -04002460 updateTextureLevel(level);
2461
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002462 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2463
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002464 gl::Rectangle sourceRect;
2465 sourceRect.x = x;
2466 sourceRect.width = width;
2467 sourceRect.y = y;
2468 sourceRect.height = height;
2469
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002470 mRenderer->copyImage(source, sourceRect, gl::GetFormat(getInternalFormat(0), clientVersion),
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002471 xoffset, yoffset, zoffset, mTexStorage, level);
2472 }
2473 }
2474}
2475
Jamie Madillf8989902013-07-19 16:36:58 -04002476bool Texture2DArray::isSamplerComplete(const SamplerState &samplerState) const
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002477{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002478 GLsizei width = getBaseLevelWidth();
2479 GLsizei height = getBaseLevelHeight();
2480 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002481
2482 if (width <= 0 || height <= 0 || depth <= 0)
2483 {
2484 return false;
2485 }
2486
Jamie Madilld3d2a342013-10-07 10:46:35 -04002487 if (!IsTextureFilteringSupported(getBaseLevelInternalFormat(), mRenderer))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002488 {
Jamie Madillf8989902013-07-19 16:36:58 -04002489 if (samplerState.magFilter != GL_NEAREST ||
2490 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002491 {
2492 return false;
2493 }
2494 }
2495
Jamie Madillf8989902013-07-19 16:36:58 -04002496 if (IsMipmapFiltered(samplerState) && !isMipmapComplete())
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002497 {
2498 return false;
2499 }
2500
2501 return true;
2502}
2503
2504bool Texture2DArray::isMipmapComplete() const
2505{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002506 GLsizei width = getBaseLevelWidth();
2507 GLsizei height = getBaseLevelHeight();
Jamie Madill07edd442013-07-19 16:36:58 -04002508
2509 int q = log2(std::max(width, height));
2510
2511 for (int level = 1; level <= q; level++)
2512 {
2513 if (!isLevelComplete(level))
2514 {
2515 return false;
2516 }
2517 }
2518
2519 return true;
2520}
2521
2522bool Texture2DArray::isLevelComplete(int level) const
2523{
2524 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
2525
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002526 if (isImmutable())
2527 {
2528 return true;
2529 }
2530
Jamie Madilld3d2a342013-10-07 10:46:35 -04002531 GLsizei width = getBaseLevelWidth();
2532 GLsizei height = getBaseLevelHeight();
2533 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002534
2535 if (width <= 0 || height <= 0 || depth <= 0)
2536 {
2537 return false;
2538 }
2539
Jamie Madill07edd442013-07-19 16:36:58 -04002540 if (level == 0)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002541 {
Jamie Madill07edd442013-07-19 16:36:58 -04002542 return true;
2543 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002544
Jamie Madill07edd442013-07-19 16:36:58 -04002545 if (getInternalFormat(level) != getInternalFormat(0))
2546 {
2547 return false;
2548 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002549
Jamie Madill07edd442013-07-19 16:36:58 -04002550 if (getWidth(level) != std::max(1, width >> level))
2551 {
2552 return false;
2553 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002554
Jamie Madill07edd442013-07-19 16:36:58 -04002555 if (getHeight(level) != std::max(1, height >> level))
2556 {
2557 return false;
2558 }
2559
2560 if (getDepth(level) != depth)
2561 {
2562 return false;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002563 }
2564
2565 return true;
2566}
2567
Geoff Lang8040f572013-07-25 16:49:54 -04002568Renderbuffer *Texture2DArray::getRenderbuffer(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002569{
Geoff Lang8040f572013-07-25 16:49:54 -04002570 Renderbuffer *renderBuffer = mRenderbufferProxies.get(level, layer);
2571 if (!renderBuffer)
2572 {
Geoff Langd5d8e392013-07-25 16:53:03 -04002573 renderBuffer = new Renderbuffer(mRenderer, id(), new RenderbufferTexture2DArrayLayer(this, level, layer));
2574 mRenderbufferProxies.add(level, 0, renderBuffer);
Geoff Lang8040f572013-07-25 16:49:54 -04002575 }
2576
2577 return renderBuffer;
2578}
2579
2580unsigned int Texture2DArray::getRenderTargetSerial( GLint level, GLint layer )
2581{
2582 if (!mTexStorage || !mTexStorage->isRenderTarget())
2583 {
2584 convertToRenderTarget();
2585 }
2586
2587 return mTexStorage ? mTexStorage->getRenderTargetSerial(level, layer) : 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002588}
2589
2590int Texture2DArray::levelCount()
2591{
2592 return mTexStorage ? mTexStorage->levelCount() : 0;
2593}
2594
2595void Texture2DArray::createTexture()
2596{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002597 GLsizei width = getBaseLevelWidth();
2598 GLsizei height = getBaseLevelHeight();
2599 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002600
2601 if (width <= 0 || height <= 0 || depth <= 0)
2602 {
2603 return; // do not attempt to create native textures for nonexistant data
2604 }
2605
2606 GLint levels = creationLevels(width, height);
Jamie Madilld3d2a342013-10-07 10:46:35 -04002607 GLenum internalformat = getBaseLevelInternalFormat();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002608
2609 delete mTexStorage;
2610 mTexStorage = new rx::TextureStorageInterface2DArray(mRenderer, levels, internalformat, mUsage, width, height, depth);
2611
2612 if (mTexStorage->isManaged())
2613 {
2614 int levels = levelCount();
2615 for (int level = 0; level < levels; level++)
2616 {
2617 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2618 {
2619 mImageArray[level][layer]->setManagedSurface(mTexStorage, layer, level);
2620 }
2621 }
2622 }
2623
2624 mDirtyImages = true;
2625}
2626
2627void Texture2DArray::updateTexture()
2628{
Jamie Madilleb3665c2013-07-19 16:36:57 -04002629 int levels = (isMipmapComplete() ? levelCount() : 1);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002630 for (int level = 0; level < levels; level++)
2631 {
Jamie Madill07edd442013-07-19 16:36:58 -04002632 updateTextureLevel(level);
2633 }
2634}
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002635
Jamie Madill07edd442013-07-19 16:36:58 -04002636void Texture2DArray::updateTextureLevel(int level)
2637{
2638 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2639 {
2640 rx::Image *image = mImageArray[level][layer];
2641
2642 if (image->isDirty())
2643 {
2644 commitRect(level, 0, 0, layer, image->getWidth(), image->getHeight());
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002645 }
2646 }
2647}
2648
2649void Texture2DArray::convertToRenderTarget()
2650{
2651 rx::TextureStorageInterface2DArray *newTexStorage = NULL;
2652
Jamie Madilld3d2a342013-10-07 10:46:35 -04002653 GLsizei width = getBaseLevelWidth();
2654 GLsizei height = getBaseLevelHeight();
2655 GLsizei depth = getBaseLevelDepth();
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002656
2657 if (width != 0 && height != 0 && depth != 0)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002658 {
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002659 GLint levels = mTexStorage != NULL ? mTexStorage->levelCount() : creationLevels(width, height);
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002660 GLenum internalformat = getInternalFormat(0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002661
2662 newTexStorage = new rx::TextureStorageInterface2DArray(mRenderer, levels, internalformat, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, width, height, depth);
2663
2664 if (mTexStorage != NULL)
2665 {
2666 if (!mRenderer->copyToRenderTarget(newTexStorage, mTexStorage))
2667 {
2668 delete newTexStorage;
2669 return gl::error(GL_OUT_OF_MEMORY);
2670 }
2671 }
2672 }
2673
2674 delete mTexStorage;
2675 mTexStorage = newTexStorage;
2676
2677 mDirtyImages = true;
2678}
2679
Geoff Lang8040f572013-07-25 16:49:54 -04002680rx::RenderTarget *Texture2DArray::getRenderTarget(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002681{
Geoff Lang8040f572013-07-25 16:49:54 -04002682 // ensure the underlying texture is created
2683 if (getStorage(true) == NULL)
2684 {
2685 return NULL;
2686 }
2687
2688 updateTexture();
2689
2690 // ensure this is NOT a depth texture
2691 if (isDepth(level))
2692 {
2693 return NULL;
2694 }
2695
2696 return mTexStorage->getRenderTarget(level, layer);
2697}
2698
2699rx::RenderTarget *Texture2DArray::getDepthStencil(GLint level, GLint layer)
2700{
2701 // ensure the underlying texture is created
2702 if (getStorage(true) == NULL)
2703 {
2704 return NULL;
2705 }
2706
2707 updateTexture();
2708
2709 // ensure this is a depth texture
2710 if (!isDepth(level))
2711 {
2712 return NULL;
2713 }
2714
2715 return mTexStorage->getRenderTarget(level, layer);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002716}
2717
2718rx::TextureStorageInterface *Texture2DArray::getStorage(bool renderTarget)
2719{
2720 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
2721 {
2722 if (renderTarget)
2723 {
2724 convertToRenderTarget();
2725 }
2726 else
2727 {
2728 createTexture();
2729 }
2730 }
2731
2732 return mTexStorage;
2733}
2734
Geoff Lang005df412013-10-16 14:12:50 -04002735void Texture2DArray::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002736{
2737 // If there currently is a corresponding storage texture image, it has these parameters
Jamie Madilld3d2a342013-10-07 10:46:35 -04002738 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2739 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
2740 const int storageDepth = getBaseLevelDepth();
Geoff Lang005df412013-10-16 14:12:50 -04002741 const GLenum storageFormat = getBaseLevelInternalFormat();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002742
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002743 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002744 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002745 delete mImageArray[level][layer];
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002746 }
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002747 delete[] mImageArray[level];
Jamie Madill152ed092013-10-09 17:01:15 -04002748 mImageArray[level] = NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002749 mLayerCounts[level] = depth;
2750
Jamie Madill152ed092013-10-09 17:01:15 -04002751 if (depth > 0)
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002752 {
Jamie Madill152ed092013-10-09 17:01:15 -04002753 mImageArray[level] = new rx::Image*[depth]();
2754
2755 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2756 {
2757 mImageArray[level][layer] = mRenderer->createImage();
2758 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, width, height, 1, false);
2759 }
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002760 }
2761
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002762 if (mTexStorage)
2763 {
2764 const int storageLevels = mTexStorage->levelCount();
2765
2766 if ((level >= storageLevels && storageLevels != 0) ||
2767 width != storageWidth ||
2768 height != storageHeight ||
2769 depth != storageDepth ||
2770 internalformat != storageFormat) // Discard mismatched storage
2771 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002772 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002773 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002774 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002775 {
2776 mImageArray[level][layer]->markDirty();
2777 }
2778 }
2779
2780 delete mTexStorage;
2781 mTexStorage = NULL;
2782 mDirtyImages = true;
2783 }
2784 }
2785}
2786
2787void Texture2DArray::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint layerTarget, GLsizei width, GLsizei height)
2788{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002789 if (level < levelCount() && layerTarget < getDepth(level))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002790 {
2791 rx::Image *image = mImageArray[level][layerTarget];
2792 if (image->updateSurface(mTexStorage, level, xoffset, yoffset, layerTarget, width, height))
2793 {
2794 image->markClean();
2795 }
2796 }
2797}
2798
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00002799}