blob: ba0639b2966482fd8a3456aea33aff01875ddb1a [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 {
Jamie Madille83d1a92013-10-24 17:49:33 -0400575 ensureRenderTarget();
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000576 mImageArray[level]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000577
578 if (width != 0 && height != 0 && level < levelCount())
579 {
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +0000580 gl::Rectangle sourceRect;
581 sourceRect.x = x;
582 sourceRect.width = width;
583 sourceRect.y = y;
584 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000585
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +0000586 mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000587 }
588 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000589}
590
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +0000591void 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 +0000592{
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +0000593 if (xoffset + width > mImageArray[level]->getWidth() || yoffset + height > mImageArray[level]->getHeight() || zoffset != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000594 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +0000595 return gl::error(GL_INVALID_VALUE);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000596 }
597
Jamie Madill07edd442013-07-19 16:36:58 -0400598 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
599 // the current level we're copying to is defined (with appropriate format, width & height)
600 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
601
602 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000603 {
shannon.woods%transgaming.com@gtempaccount.come5dcce72013-04-13 03:44:33 +0000604 mImageArray[level]->copy(xoffset, yoffset, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000605 mDirtyImages = true;
606 }
607 else
608 {
Jamie Madille83d1a92013-10-24 17:49:33 -0400609 ensureRenderTarget();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000610
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000611 if (level < levelCount())
612 {
Jamie Madill07edd442013-07-19 16:36:58 -0400613 updateTextureLevel(level);
614
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +0000615 GLuint clientVersion = mRenderer->getCurrentClientVersion();
616
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +0000617 gl::Rectangle sourceRect;
618 sourceRect.x = x;
619 sourceRect.width = width;
620 sourceRect.y = y;
621 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000622
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +0000623 mRenderer->copyImage(source, sourceRect,
Jamie Madilld3d2a342013-10-07 10:46:35 -0400624 gl::GetFormat(getBaseLevelInternalFormat(), clientVersion),
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +0000625 xoffset, yoffset, mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000626 }
627 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000628}
629
630void Texture2D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height)
631{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000632 delete mTexStorage;
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000633 mTexStorage = new rx::TextureStorageInterface2D(mRenderer, levels, internalformat, mUsage, false, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000634 mImmutable = true;
635
636 for (int level = 0; level < levels; level++)
637 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000638 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, width, height, 1, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000639 width = std::max(1, width >> 1);
640 height = std::max(1, height >> 1);
641 }
642
643 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
644 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000645 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000646 }
647
648 if (mTexStorage->isManaged())
649 {
650 int levels = levelCount();
651
652 for (int level = 0; level < levels; level++)
653 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000654 mImageArray[level]->setManagedSurface(mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000655 }
656 }
657}
658
659// Tests for 2D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85.
Jamie Madillf8989902013-07-19 16:36:58 -0400660bool Texture2D::isSamplerComplete(const SamplerState &samplerState) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000661{
Jamie Madilld3d2a342013-10-07 10:46:35 -0400662 GLsizei width = getBaseLevelWidth();
663 GLsizei height = getBaseLevelHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000664
665 if (width <= 0 || height <= 0)
666 {
667 return false;
668 }
669
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000670 if (!IsTextureFilteringSupported(getInternalFormat(0), mRenderer))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000671 {
Jamie Madillf8989902013-07-19 16:36:58 -0400672 if (samplerState.magFilter != GL_NEAREST ||
673 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000674 {
675 return false;
676 }
677 }
678
daniel@transgaming.comea32d482012-11-28 19:33:18 +0000679 bool npotSupport = mRenderer->getNonPower2TextureSupport();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000680
681 if (!npotSupport)
682 {
Jamie Madillf8989902013-07-19 16:36:58 -0400683 if ((samplerState.wrapS != GL_CLAMP_TO_EDGE && !isPow2(width)) ||
684 (samplerState.wrapT != GL_CLAMP_TO_EDGE && !isPow2(height)))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000685 {
686 return false;
687 }
688 }
689
Jamie Madillf8989902013-07-19 16:36:58 -0400690 if (IsMipmapFiltered(samplerState))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000691 {
692 if (!npotSupport)
693 {
694 if (!isPow2(width) || !isPow2(height))
695 {
696 return false;
697 }
698 }
699
700 if (!isMipmapComplete())
701 {
702 return false;
703 }
704 }
705
Geoff Langc82fc412013-07-10 14:43:42 -0400706 // OpenGLES 3.0.2 spec section 3.8.13 states that a texture is not mipmap complete if:
707 // The internalformat specified for the texture arrays is a sized internal depth or
708 // depth and stencil format (see table 3.13), the value of TEXTURE_COMPARE_-
709 // MODE is NONE, and either the magnification filter is not NEAREST or the mini-
710 // fication filter is neither NEAREST nor NEAREST_MIPMAP_NEAREST.
711 if (gl::GetDepthBits(getInternalFormat(0), mRenderer->getCurrentClientVersion()) > 0)
712 {
713 if (mSamplerState.compareMode == GL_NONE)
714 {
715 if ((mSamplerState.minFilter != GL_NEAREST && mSamplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST) ||
716 mSamplerState.magFilter != GL_NEAREST)
717 {
718 return false;
719 }
720 }
721 }
722
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000723 return true;
724}
725
726// Tests for 2D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
727bool Texture2D::isMipmapComplete() const
728{
Jamie Madilld3d2a342013-10-07 10:46:35 -0400729 GLsizei width = getBaseLevelWidth();
730 GLsizei height = getBaseLevelHeight();
Jamie Madill07edd442013-07-19 16:36:58 -0400731
732 int q = log2(std::max(width, height));
733
734 for (int level = 0; level <= q; level++)
735 {
736 if (!isLevelComplete(level))
737 {
738 return false;
739 }
740 }
741
742 return true;
743}
744
745bool Texture2D::isLevelComplete(int level) const
746{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000747 if (isImmutable())
748 {
749 return true;
750 }
751
Jamie Madilld3d2a342013-10-07 10:46:35 -0400752 GLsizei width = getBaseLevelWidth();
753 GLsizei height = getBaseLevelHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000754
755 if (width <= 0 || height <= 0)
756 {
757 return false;
758 }
759
Jamie Madill07edd442013-07-19 16:36:58 -0400760 // The base image level is complete if the width and height are positive
761 if (level == 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000762 {
Jamie Madill07edd442013-07-19 16:36:58 -0400763 return true;
764 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000765
Jamie Madill07edd442013-07-19 16:36:58 -0400766 ASSERT(level >= 1 && level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
767 rx::Image *image = mImageArray[level];
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000768
Jamie Madilld3d2a342013-10-07 10:46:35 -0400769 if (image->getInternalFormat() != getBaseLevelInternalFormat())
Jamie Madill07edd442013-07-19 16:36:58 -0400770 {
771 return false;
772 }
773
774 if (image->getWidth() != std::max(1, width >> level))
775 {
776 return false;
777 }
778
779 if (image->getHeight() != std::max(1, height >> level))
780 {
781 return false;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000782 }
783
784 return true;
785}
786
787bool Texture2D::isCompressed(GLint level) const
788{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000789 return IsFormatCompressed(getInternalFormat(level), mRenderer->getCurrentClientVersion());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000790}
791
792bool Texture2D::isDepth(GLint level) const
793{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000794 return GetDepthBits(getInternalFormat(level), mRenderer->getCurrentClientVersion()) > 0;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000795}
796
daniel@transgaming.comf032cb82012-10-31 19:51:52 +0000797// Constructs a native texture resource from the texture images
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000798void Texture2D::createTexture()
799{
Jamie Madilld3d2a342013-10-07 10:46:35 -0400800 GLsizei width = getBaseLevelWidth();
801 GLsizei height = getBaseLevelHeight();
daniel@transgaming.come6a09842012-09-17 21:28:55 +0000802
803 if (!(width > 0 && height > 0))
daniel@transgaming.comf032cb82012-10-31 19:51:52 +0000804 return; // do not attempt to create native textures for nonexistant data
daniel@transgaming.come6a09842012-09-17 21:28:55 +0000805
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000806 GLint levels = creationLevels(width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000807
808 delete mTexStorage;
Jamie Madilld3d2a342013-10-07 10:46:35 -0400809 mTexStorage = new rx::TextureStorageInterface2D(mRenderer, levels, getBaseLevelInternalFormat(), mUsage, false, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000810
811 if (mTexStorage->isManaged())
812 {
813 int levels = levelCount();
814
815 for (int level = 0; level < levels; level++)
816 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000817 mImageArray[level]->setManagedSurface(mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000818 }
819 }
820
821 mDirtyImages = true;
822}
823
824void Texture2D::updateTexture()
825{
Jamie Madilld9b9a502013-10-10 17:46:13 -0400826 int storageLevels = levelCount();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000827
Jamie Madilld9b9a502013-10-10 17:46:13 -0400828 for (int level = 0; level < storageLevels; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000829 {
Jamie Madilld9b9a502013-10-10 17:46:13 -0400830 if (isLevelComplete(level))
831 {
832 updateTextureLevel(level);
833 }
Jamie Madill07edd442013-07-19 16:36:58 -0400834 }
835}
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000836
Jamie Madill07edd442013-07-19 16:36:58 -0400837void Texture2D::updateTextureLevel(int level)
838{
839 ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
Jamie Madillaee7ad82013-10-10 16:07:32 -0400840 ASSERT(isLevelComplete(level));
Jamie Madill07edd442013-07-19 16:36:58 -0400841
Jamie Madillaee7ad82013-10-10 16:07:32 -0400842 if (mImageArray[level]->isDirty())
Jamie Madill07edd442013-07-19 16:36:58 -0400843 {
Jamie Madillaee7ad82013-10-10 16:07:32 -0400844 commitRect(level, 0, 0, getWidth(level), getHeight(level));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000845 }
846}
847
Jamie Madille83d1a92013-10-24 17:49:33 -0400848bool Texture2D::ensureRenderTarget()
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000849{
Jamie Madille83d1a92013-10-24 17:49:33 -0400850 if (mTexStorage && mTexStorage->isRenderTarget())
851 {
852 return true;
853 }
854
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000855 rx::TextureStorageInterface2D *newTexStorage = NULL;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000856
Jamie Madilld3d2a342013-10-07 10:46:35 -0400857 GLsizei width = getBaseLevelWidth();
858 GLsizei height = getBaseLevelHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000859
Jamie Madilld3d2a342013-10-07 10:46:35 -0400860 if (width != 0 && height != 0)
861 {
862 GLint levels = mTexStorage != NULL ? mTexStorage->levelCount() : creationLevels(width, height);
863
864 newTexStorage = new rx::TextureStorageInterface2D(mRenderer, levels, getBaseLevelInternalFormat(), GL_FRAMEBUFFER_ATTACHMENT_ANGLE, true, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000865
866 if (mTexStorage != NULL)
867 {
daniel@transgaming.com1d80eee2012-11-28 19:33:31 +0000868 if (!mRenderer->copyToRenderTarget(newTexStorage, mTexStorage))
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +0000869 {
870 delete newTexStorage;
Jamie Madille83d1a92013-10-24 17:49:33 -0400871 return gl::error(GL_OUT_OF_MEMORY, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000872 }
873 }
874 }
875
876 delete mTexStorage;
877 mTexStorage = newTexStorage;
878
879 mDirtyImages = true;
Jamie Madille83d1a92013-10-24 17:49:33 -0400880
881 return (mTexStorage && mTexStorage->isRenderTarget());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000882}
883
884void Texture2D::generateMipmaps()
885{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000886 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Jamie Madilld3d2a342013-10-07 10:46:35 -0400887 unsigned int q = log2(std::max(getBaseLevelWidth(), getBaseLevelHeight()));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000888 for (unsigned int i = 1; i <= q; i++)
889 {
Jamie Madilld3d2a342013-10-07 10:46:35 -0400890 redefineImage(i, getBaseLevelInternalFormat(),
891 std::max(getBaseLevelWidth() >> i, 1),
892 std::max(getBaseLevelHeight() >> i, 1));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000893 }
894
895 if (mTexStorage && mTexStorage->isRenderTarget())
896 {
897 for (unsigned int i = 1; i <= q; i++)
898 {
daniel@transgaming.com0ad830b2012-10-31 19:52:12 +0000899 mTexStorage->generateMipmap(i);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000900
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000901 mImageArray[i]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000902 }
903 }
904 else
905 {
906 for (unsigned int i = 1; i <= q; i++)
907 {
daniel@transgaming.com4ba24062012-12-20 20:54:24 +0000908 mRenderer->generateMipmap(mImageArray[i], mImageArray[i - 1]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000909 }
910 }
911}
912
Jamie Madilld3d2a342013-10-07 10:46:35 -0400913const rx::Image *Texture2D::getBaseLevelImage() const
914{
915 return mImageArray[0];
916}
917
Geoff Lang8040f572013-07-25 16:49:54 -0400918Renderbuffer *Texture2D::getRenderbuffer(GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000919{
Geoff Lang8040f572013-07-25 16:49:54 -0400920 Renderbuffer *renderBuffer = mRenderbufferProxies.get(level, 0);
921 if (!renderBuffer)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000922 {
Geoff Lang8040f572013-07-25 16:49:54 -0400923 renderBuffer = new Renderbuffer(mRenderer, id(), new RenderbufferTexture2D(this, level));
924 mRenderbufferProxies.add(level, 0, renderBuffer);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000925 }
926
Geoff Lang8040f572013-07-25 16:49:54 -0400927 return renderBuffer;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000928}
929
Geoff Lang8040f572013-07-25 16:49:54 -0400930unsigned int Texture2D::getRenderTargetSerial(GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000931{
Jamie Madille83d1a92013-10-24 17:49:33 -0400932 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(level) : 0);
Geoff Lang8040f572013-07-25 16:49:54 -0400933}
934
935rx::RenderTarget *Texture2D::getRenderTarget(GLint level)
936{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000937 // ensure the underlying texture is created
938 if (getStorage(true) == NULL)
939 {
940 return NULL;
941 }
942
Jamie Madillaee7ad82013-10-10 16:07:32 -0400943 updateTextureLevel(level);
Geoff Lang8040f572013-07-25 16:49:54 -0400944
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000945 // ensure this is NOT a depth texture
Geoff Lang8040f572013-07-25 16:49:54 -0400946 if (isDepth(level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000947 {
948 return NULL;
949 }
daniel@transgaming.com34da3972012-12-20 21:10:29 +0000950
Geoff Lang8040f572013-07-25 16:49:54 -0400951 return mTexStorage->getRenderTarget(level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000952}
953
Geoff Lang8040f572013-07-25 16:49:54 -0400954rx::RenderTarget *Texture2D::getDepthSencil(GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000955{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000956 // ensure the underlying texture is created
957 if (getStorage(true) == NULL)
958 {
959 return NULL;
960 }
961
Jamie Madillaee7ad82013-10-10 16:07:32 -0400962 updateTextureLevel(level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000963
964 // ensure this is actually a depth texture
Geoff Lang8040f572013-07-25 16:49:54 -0400965 if (!isDepth(level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000966 {
967 return NULL;
968 }
Geoff Lang8040f572013-07-25 16:49:54 -0400969
970 return mTexStorage->getRenderTarget(level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000971}
972
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +0000973int Texture2D::levelCount()
974{
shannon.woods@transgaming.com5016f8e2013-02-28 23:20:57 +0000975 return mTexStorage ? mTexStorage->levelCount() : 0;
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +0000976}
977
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000978rx::TextureStorageInterface *Texture2D::getStorage(bool renderTarget)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000979{
980 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
981 {
982 if (renderTarget)
983 {
Jamie Madille83d1a92013-10-24 17:49:33 -0400984 ensureRenderTarget();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000985 }
986 else
987 {
988 createTexture();
989 }
990 }
991
992 return mTexStorage;
993}
994
Geoff Lang4907f2c2013-07-25 12:53:57 -0400995TextureCubeMap::TextureCubeMap(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_CUBE_MAP)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000996{
997 mTexStorage = NULL;
998 for (int i = 0; i < 6; i++)
999 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001000 for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
1001 {
daniel@transgaming.com244e1832012-12-20 20:52:35 +00001002 mImageArray[i][j] = renderer->createImage();
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001003 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001004 }
1005}
1006
1007TextureCubeMap::~TextureCubeMap()
1008{
1009 for (int i = 0; i < 6; i++)
1010 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001011 for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
1012 {
1013 delete mImageArray[i][j];
1014 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001015 }
1016
1017 delete mTexStorage;
1018 mTexStorage = NULL;
1019}
1020
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001021GLsizei TextureCubeMap::getWidth(GLenum target, GLint level) const
1022{
1023 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001024 return mImageArray[faceIndex(target)][level]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001025 else
1026 return 0;
1027}
1028
1029GLsizei TextureCubeMap::getHeight(GLenum target, GLint level) const
1030{
1031 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001032 return mImageArray[faceIndex(target)][level]->getHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001033 else
1034 return 0;
1035}
1036
1037GLenum TextureCubeMap::getInternalFormat(GLenum target, GLint level) const
1038{
1039 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001040 return mImageArray[faceIndex(target)][level]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001041 else
1042 return GL_NONE;
1043}
1044
daniel@transgaming.com20d36662012-10-31 19:51:43 +00001045GLenum TextureCubeMap::getActualFormat(GLenum target, GLint level) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001046{
1047 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001048 return mImageArray[faceIndex(target)][level]->getActualFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001049 else
1050 return D3DFMT_UNKNOWN;
1051}
1052
Geoff Lang005df412013-10-16 14:12:50 -04001053void 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 +00001054{
Jamie Madill88f18f42013-09-18 14:36:19 -04001055 setImage(0, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001056}
1057
Geoff Lang005df412013-10-16 14:12:50 -04001058void 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 +00001059{
Jamie Madill88f18f42013-09-18 14:36:19 -04001060 setImage(1, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001061}
1062
Geoff Lang005df412013-10-16 14:12:50 -04001063void TextureCubeMap::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 +00001064{
Jamie Madill88f18f42013-09-18 14:36:19 -04001065 setImage(2, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001066}
1067
Geoff Lang005df412013-10-16 14:12:50 -04001068void TextureCubeMap::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 +00001069{
Jamie Madill88f18f42013-09-18 14:36:19 -04001070 setImage(3, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001071}
1072
Geoff Lang005df412013-10-16 14:12:50 -04001073void TextureCubeMap::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 +00001074{
Jamie Madill88f18f42013-09-18 14:36:19 -04001075 setImage(4, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001076}
1077
Geoff Lang005df412013-10-16 14:12:50 -04001078void TextureCubeMap::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 +00001079{
Jamie Madill88f18f42013-09-18 14:36:19 -04001080 setImage(5, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001081}
1082
1083void TextureCubeMap::setCompressedImage(GLenum face, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
1084{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001085 // 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 +00001086 redefineImage(faceIndex(face), level, format, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001087
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001088 Texture::setCompressedImage(imageSize, pixels, mImageArray[faceIndex(face)][level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001089}
1090
1091void TextureCubeMap::commitRect(int face, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1092{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001093 if (level < levelCount())
1094 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001095 rx::Image *image = mImageArray[face][level];
daniel@transgaming.com0f195ad2012-10-31 19:51:59 +00001096 if (image->updateSurface(mTexStorage, face, level, xoffset, yoffset, width, height))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001097 image->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001098 }
1099}
1100
Jamie Madill88f18f42013-09-18 14:36:19 -04001101void 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 +00001102{
Jamie Madill88f18f42013-09-18 14:36:19 -04001103 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 +00001104 {
1105 commitRect(faceIndex(target), level, xoffset, yoffset, width, height);
1106 }
1107}
1108
1109void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1110{
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +00001111 if (Texture::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[faceIndex(target)][level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001112 {
1113 commitRect(faceIndex(target), level, xoffset, yoffset, width, height);
1114 }
1115}
1116
1117// Tests for cube map sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 86.
Jamie Madillf8989902013-07-19 16:36:58 -04001118bool TextureCubeMap::isSamplerComplete(const SamplerState &samplerState) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001119{
Jamie Madilld3d2a342013-10-07 10:46:35 -04001120 int size = getBaseLevelWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001121
Jamie Madillf8989902013-07-19 16:36:58 -04001122 bool mipmapping = IsMipmapFiltered(samplerState);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001123
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001124 if (!IsTextureFilteringSupported(getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0), mRenderer))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001125 {
Jamie Madillf8989902013-07-19 16:36:58 -04001126 if (samplerState.magFilter != GL_NEAREST ||
1127 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001128 {
1129 return false;
1130 }
1131 }
1132
daniel@transgaming.comea32d482012-11-28 19:33:18 +00001133 if (!isPow2(size) && !mRenderer->getNonPower2TextureSupport())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001134 {
Jamie Madillf8989902013-07-19 16:36:58 -04001135 if (samplerState.wrapS != GL_CLAMP_TO_EDGE || samplerState.wrapT != GL_CLAMP_TO_EDGE || mipmapping)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001136 {
1137 return false;
1138 }
1139 }
1140
1141 if (!mipmapping)
1142 {
1143 if (!isCubeComplete())
1144 {
1145 return false;
1146 }
1147 }
1148 else
1149 {
1150 if (!isMipmapCubeComplete()) // Also tests for isCubeComplete()
1151 {
1152 return false;
1153 }
1154 }
1155
1156 return true;
1157}
1158
1159// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1160bool TextureCubeMap::isCubeComplete() const
1161{
Jamie Madillc1f8b162013-10-07 10:46:38 -04001162 int baseWidth = getBaseLevelWidth();
1163 int baseHeight = getBaseLevelHeight();
1164 GLenum baseFormat = getBaseLevelInternalFormat();
1165
1166 if (baseWidth <= 0 || baseWidth != baseHeight)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001167 {
1168 return false;
1169 }
1170
1171 for (unsigned int face = 1; face < 6; face++)
1172 {
Jamie Madillc1f8b162013-10-07 10:46:38 -04001173 const rx::Image &faceBaseImage = *mImageArray[face][0];
1174
1175 if (faceBaseImage.getWidth() != baseWidth ||
1176 faceBaseImage.getHeight() != baseHeight ||
1177 faceBaseImage.getInternalFormat() != baseFormat )
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001178 {
1179 return false;
1180 }
1181 }
1182
1183 return true;
1184}
1185
1186bool TextureCubeMap::isMipmapCubeComplete() const
1187{
1188 if (isImmutable())
1189 {
1190 return true;
1191 }
1192
1193 if (!isCubeComplete())
1194 {
1195 return false;
1196 }
1197
Jamie Madilld3d2a342013-10-07 10:46:35 -04001198 GLsizei size = getBaseLevelWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001199 int q = log2(size);
1200
1201 for (int face = 0; face < 6; face++)
1202 {
1203 for (int level = 1; level <= q; level++)
1204 {
Jamie Madill07edd442013-07-19 16:36:58 -04001205 if (!isFaceLevelComplete(face, level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001206 {
1207 return false;
1208 }
1209 }
1210 }
1211
1212 return true;
1213}
1214
Jamie Madill07edd442013-07-19 16:36:58 -04001215bool TextureCubeMap::isFaceLevelComplete(int face, int level) const
1216{
1217 ASSERT(level >= 0 && face < 6 && level < (int)ArraySize(mImageArray[face]) && mImageArray[face][level] != NULL);
1218
1219 if (isImmutable())
1220 {
1221 return true;
1222 }
1223
Jamie Madilld3d2a342013-10-07 10:46:35 -04001224 int baseSize = getBaseLevelWidth();
Jamie Madill07edd442013-07-19 16:36:58 -04001225
Jamie Madilld3d2a342013-10-07 10:46:35 -04001226 if (baseSize <= 0)
Jamie Madill07edd442013-07-19 16:36:58 -04001227 {
1228 return false;
1229 }
1230
Jamie Madilld3d2a342013-10-07 10:46:35 -04001231 // "isCubeComplete" checks for base level completeness and we must call that
1232 // to determine if any face at level 0 is complete. We omit that check here
1233 // to avoid re-checking cube-completeness for every face at level 0.
Jamie Madill07edd442013-07-19 16:36:58 -04001234 if (level == 0)
1235 {
1236 return true;
1237 }
1238
Jamie Madilld3d2a342013-10-07 10:46:35 -04001239 // Check that non-zero levels are consistent with the base level.
1240 const rx::Image *faceLevelImage = mImageArray[face][level];
Jamie Madill07edd442013-07-19 16:36:58 -04001241
Jamie Madilld3d2a342013-10-07 10:46:35 -04001242 if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat())
Jamie Madill07edd442013-07-19 16:36:58 -04001243 {
1244 return false;
1245 }
1246
Jamie Madilld3d2a342013-10-07 10:46:35 -04001247 if (faceLevelImage->getWidth() != std::max(1, baseSize >> level))
Jamie Madill07edd442013-07-19 16:36:58 -04001248 {
1249 return false;
1250 }
1251
1252 return true;
1253}
1254
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001255bool TextureCubeMap::isCompressed(GLenum target, GLint level) const
1256{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001257 return IsFormatCompressed(getInternalFormat(target, level), mRenderer->getCurrentClientVersion());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001258}
1259
Geoff Lang8040f572013-07-25 16:49:54 -04001260bool TextureCubeMap::isDepth(GLenum target, GLint level) const
1261{
1262 return GetDepthBits(getInternalFormat(target, level), mRenderer->getCurrentClientVersion()) > 0;
1263}
1264
daniel@transgaming.comf032cb82012-10-31 19:51:52 +00001265// Constructs a native texture resource from the texture images, or returns an existing one
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001266void TextureCubeMap::createTexture()
1267{
Jamie Madilld3d2a342013-10-07 10:46:35 -04001268 GLsizei size = getBaseLevelWidth();
daniel@transgaming.come6a09842012-09-17 21:28:55 +00001269
1270 if (!(size > 0))
daniel@transgaming.comf032cb82012-10-31 19:51:52 +00001271 return; // do not attempt to create native textures for nonexistant data
daniel@transgaming.come6a09842012-09-17 21:28:55 +00001272
sminns@adobe.comce1189b2012-09-18 20:06:35 +00001273 GLint levels = creationLevels(size);
Jamie Madilld3d2a342013-10-07 10:46:35 -04001274 GLenum internalformat = getBaseLevelInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001275
1276 delete mTexStorage;
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001277 mTexStorage = new rx::TextureStorageInterfaceCube(mRenderer, levels, internalformat, mUsage, false, size);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001278
1279 if (mTexStorage->isManaged())
1280 {
1281 int levels = levelCount();
1282
1283 for (int face = 0; face < 6; face++)
1284 {
1285 for (int level = 0; level < levels; level++)
1286 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001287 mImageArray[face][level]->setManagedSurface(mTexStorage, face, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001288 }
1289 }
1290 }
1291
1292 mDirtyImages = true;
1293}
1294
1295void TextureCubeMap::updateTexture()
1296{
Jamie Madilld9b9a502013-10-10 17:46:13 -04001297 int storageLevels = levelCount();
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +00001298
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001299 for (int face = 0; face < 6; face++)
1300 {
Jamie Madilld9b9a502013-10-10 17:46:13 -04001301 for (int level = 0; level < storageLevels; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001302 {
Jamie Madilld9b9a502013-10-10 17:46:13 -04001303 if (isFaceLevelComplete(face, level))
1304 {
1305 updateTextureFaceLevel(face, level);
1306 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001307 }
1308 }
1309}
1310
Jamie Madill07edd442013-07-19 16:36:58 -04001311void TextureCubeMap::updateTextureFaceLevel(int face, int level)
1312{
1313 ASSERT(level >= 0 && face < 6 && level < (int)ArraySize(mImageArray[face]) && mImageArray[face][level] != NULL);
1314 rx::Image *image = mImageArray[face][level];
1315
1316 if (image->isDirty())
1317 {
1318 commitRect(face, level, 0, 0, image->getWidth(), image->getHeight());
1319 }
1320}
1321
Jamie Madille83d1a92013-10-24 17:49:33 -04001322bool TextureCubeMap::ensureRenderTarget()
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001323{
Jamie Madille83d1a92013-10-24 17:49:33 -04001324 if (mTexStorage && mTexStorage->isRenderTarget())
1325 {
1326 return true;
1327 }
1328
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001329 rx::TextureStorageInterfaceCube *newTexStorage = NULL;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001330
Jamie Madilld3d2a342013-10-07 10:46:35 -04001331 if (getBaseLevelWidth() != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001332 {
Jamie Madilld3d2a342013-10-07 10:46:35 -04001333 GLsizei size = getBaseLevelWidth();
shannon.woods@transgaming.com6bb48862013-02-28 23:09:34 +00001334 GLint levels = mTexStorage != NULL ? mTexStorage->levelCount() : creationLevels(size);
Jamie Madilld3d2a342013-10-07 10:46:35 -04001335 GLenum internalformat = getBaseLevelInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001336
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001337 newTexStorage = new rx::TextureStorageInterfaceCube(mRenderer, levels, internalformat, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, true, size);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001338
1339 if (mTexStorage != NULL)
1340 {
daniel@transgaming.com1d80eee2012-11-28 19:33:31 +00001341 if (!mRenderer->copyToRenderTarget(newTexStorage, mTexStorage))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001342 {
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +00001343 delete newTexStorage;
Jamie Madille83d1a92013-10-24 17:49:33 -04001344 return gl::error(GL_OUT_OF_MEMORY, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001345 }
1346 }
1347 }
1348
1349 delete mTexStorage;
1350 mTexStorage = newTexStorage;
1351
1352 mDirtyImages = true;
Jamie Madille83d1a92013-10-24 17:49:33 -04001353 return (mTexStorage && mTexStorage->isRenderTarget());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001354}
1355
Geoff Lang005df412013-10-16 14:12:50 -04001356void 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 +00001357{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001358 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Geoff Lang005df412013-10-16 14:12:50 -04001359 GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
1360 : GetSizedInternalFormat(format, type, clientVersion);
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001361
1362 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001363
Jamie Madill88f18f42013-09-18 14:36:19 -04001364 Texture::setImage(unpack, type, pixels, mImageArray[faceIndex][level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001365}
1366
1367unsigned int TextureCubeMap::faceIndex(GLenum face)
1368{
1369 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
1370 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
1371 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
1372 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
1373 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
1374
1375 return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
1376}
1377
Geoff Lang005df412013-10-16 14:12:50 -04001378void TextureCubeMap::redefineImage(int face, GLint level, GLenum internalformat, GLsizei width, GLsizei height)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001379{
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001380 // If there currently is a corresponding storage texture image, it has these parameters
Jamie Madilld3d2a342013-10-07 10:46:35 -04001381 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1382 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
Geoff Lang005df412013-10-16 14:12:50 -04001383 const GLenum storageFormat = getBaseLevelInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001384
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001385 mImageArray[face][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, width, height, 1, false);
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001386
1387 if (mTexStorage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001388 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001389 const int storageLevels = mTexStorage->levelCount();
1390
1391 if ((level >= storageLevels && storageLevels != 0) ||
1392 width != storageWidth ||
1393 height != storageHeight ||
1394 internalformat != storageFormat) // Discard mismatched storage
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001395 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001396 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001397 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001398 for (int f = 0; f < 6; f++)
1399 {
1400 mImageArray[f][i]->markDirty();
1401 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001402 }
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001403
1404 delete mTexStorage;
1405 mTexStorage = NULL;
1406
1407 mDirtyImages = true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001408 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001409 }
1410}
1411
1412void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1413{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001414 unsigned int faceindex = faceIndex(target);
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001415 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Geoff Lang005df412013-10-16 14:12:50 -04001416 GLenum sizedInternalFormat = IsSizedInternalFormat(format, clientVersion) ? format
1417 : GetSizedInternalFormat(format, GL_UNSIGNED_BYTE, clientVersion);
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001418 redefineImage(faceindex, level, sizedInternalFormat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001419
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001420 if (!mImageArray[faceindex][level]->isRenderableFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001421 {
shannon.woods%transgaming.com@gtempaccount.come5dcce72013-04-13 03:44:33 +00001422 mImageArray[faceindex][level]->copy(0, 0, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001423 mDirtyImages = true;
1424 }
1425 else
1426 {
Jamie Madille83d1a92013-10-24 17:49:33 -04001427 ensureRenderTarget();
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001428 mImageArray[faceindex][level]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001429
1430 ASSERT(width == height);
1431
1432 if (width > 0 && level < levelCount())
1433 {
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +00001434 gl::Rectangle sourceRect;
1435 sourceRect.x = x;
1436 sourceRect.width = width;
1437 sourceRect.y = y;
1438 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001439
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +00001440 mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001441 }
1442 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001443}
1444
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001445void 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 +00001446{
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001447 GLsizei size = mImageArray[faceIndex(target)][level]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001448
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001449 if (xoffset + width > size || yoffset + height > size || zoffset != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001450 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +00001451 return gl::error(GL_INVALID_VALUE);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001452 }
1453
Jamie Madill07edd442013-07-19 16:36:58 -04001454 unsigned int face = faceIndex(target);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001455
Jamie Madilld3d2a342013-10-07 10:46:35 -04001456 // We can only make our texture storage to a render target if the level we're copying *to* is complete
1457 // and the base level is cube-complete. The base level must be cube complete (common case) because we cannot
1458 // rely on the "getBaseLevel*" methods reliably otherwise.
1459 bool canCreateRenderTarget = isFaceLevelComplete(face, level) && isCubeComplete();
Jamie Madill07edd442013-07-19 16:36:58 -04001460
1461 if (!mImageArray[face][level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001462 {
Jamie Madill07edd442013-07-19 16:36:58 -04001463 mImageArray[face][level]->copy(0, 0, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001464 mDirtyImages = true;
1465 }
1466 else
1467 {
Jamie Madille83d1a92013-10-24 17:49:33 -04001468 ensureRenderTarget();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001469
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{
Jamie Madille83d1a92013-10-24 17:49:33 -04001591 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(faceTarget, level) : 0);
Geoff Lang8040f572013-07-25 16:49:54 -04001592}
1593
1594rx::RenderTarget *TextureCubeMap::getRenderTarget(GLenum target, GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001595{
1596 ASSERT(IsCubemapTextureTarget(target));
1597
1598 // ensure the underlying texture is created
1599 if (getStorage(true) == NULL)
1600 {
1601 return NULL;
1602 }
1603
Jamie Madillaee7ad82013-10-10 16:07:32 -04001604 updateTextureFaceLevel(faceIndex(target), level);
Geoff Lang8040f572013-07-25 16:49:54 -04001605
1606 // ensure this is NOT a depth texture
1607 if (isDepth(target, level))
1608 {
1609 return NULL;
1610 }
1611
1612 return mTexStorage->getRenderTarget(target, level);
1613}
1614
1615rx::RenderTarget *TextureCubeMap::getDepthStencil(GLenum target, GLint level)
1616{
1617 ASSERT(IsCubemapTextureTarget(target));
1618
1619 // ensure the underlying texture is created
1620 if (getStorage(true) == NULL)
1621 {
1622 return NULL;
1623 }
1624
Jamie Madillaee7ad82013-10-10 16:07:32 -04001625 updateTextureFaceLevel(faceIndex(target), level);
Geoff Lang8040f572013-07-25 16:49:54 -04001626
1627 // ensure this is a depth texture
1628 if (!isDepth(target, level))
1629 {
1630 return NULL;
1631 }
1632
1633 return mTexStorage->getRenderTarget(target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001634}
1635
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +00001636int TextureCubeMap::levelCount()
1637{
1638 return mTexStorage ? mTexStorage->levelCount() - getLodOffset() : 0;
1639}
1640
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001641rx::TextureStorageInterface *TextureCubeMap::getStorage(bool renderTarget)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001642{
1643 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
1644 {
1645 if (renderTarget)
1646 {
Jamie Madille83d1a92013-10-24 17:49:33 -04001647 ensureRenderTarget();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001648 }
1649 else
1650 {
1651 createTexture();
1652 }
1653 }
1654
1655 return mTexStorage;
1656}
1657
Geoff Lang4907f2c2013-07-25 12:53:57 -04001658Texture3D::Texture3D(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_3D)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001659{
1660 mTexStorage = NULL;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001661
1662 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1663 {
1664 mImageArray[i] = renderer->createImage();
1665 }
1666}
1667
1668Texture3D::~Texture3D()
1669{
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001670 delete mTexStorage;
1671 mTexStorage = NULL;
1672
1673 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1674 {
1675 delete mImageArray[i];
1676 }
1677}
1678
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001679GLsizei Texture3D::getWidth(GLint level) const
1680{
1681 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getWidth() : 0;
1682}
1683
1684GLsizei Texture3D::getHeight(GLint level) const
1685{
1686 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getHeight() : 0;
1687}
1688
1689GLsizei Texture3D::getDepth(GLint level) const
1690{
1691 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getDepth() : 0;
1692}
1693
1694GLenum Texture3D::getInternalFormat(GLint level) const
1695{
1696 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getInternalFormat() : GL_NONE;
1697}
1698
1699GLenum Texture3D::getActualFormat(GLint level) const
1700{
1701 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getActualFormat() : D3DFMT_UNKNOWN;
1702}
1703
1704bool Texture3D::isCompressed(GLint level) const
1705{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001706 return IsFormatCompressed(getInternalFormat(level), mRenderer->getCurrentClientVersion());
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001707}
1708
1709bool Texture3D::isDepth(GLint level) const
1710{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001711 return GetDepthBits(getInternalFormat(level), mRenderer->getCurrentClientVersion()) > 0;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001712}
1713
Geoff Lang005df412013-10-16 14:12:50 -04001714void 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 +00001715{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001716 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Geoff Lang005df412013-10-16 14:12:50 -04001717 GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
1718 : GetSizedInternalFormat(format, type, clientVersion);
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001719 redefineImage(level, sizedInternalFormat, width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001720
Jamie Madilla2d4e552013-10-10 15:12:01 -04001721 bool fastUnpacked = false;
1722
1723 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1724 if (isFastUnpackable(unpack, sizedInternalFormat))
1725 {
1726 // Will try to create RT storage if it does not exist
1727 rx::RenderTarget *destRenderTarget = getRenderTarget(level);
1728 Box destArea(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1729
1730 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget))
1731 {
1732 // Ensure we don't overwrite our newly initialized data
1733 mImageArray[level]->markClean();
1734
1735 fastUnpacked = true;
1736 }
1737 }
1738
1739 if (!fastUnpacked)
1740 {
1741 Texture::setImage(unpack, type, pixels, mImageArray[level]);
1742 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001743}
1744
1745void Texture3D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
1746{
1747 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1748 redefineImage(level, format, width, height, depth);
1749
1750 Texture::setCompressedImage(imageSize, pixels, mImageArray[level]);
1751}
1752
Jamie Madill88f18f42013-09-18 14:36:19 -04001753void 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 +00001754{
Jamie Madillba4f10a2013-10-10 15:12:20 -04001755 bool fastUnpacked = false;
1756
1757 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1758 if (isFastUnpackable(unpack, getInternalFormat(level)))
1759 {
1760 rx::RenderTarget *destRenderTarget = getRenderTarget(level);
1761 Box destArea(xoffset, yoffset, zoffset, width, height, depth);
1762
1763 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, destRenderTarget))
1764 {
1765 // Ensure we don't overwrite our newly initialized data
1766 mImageArray[level]->markClean();
1767
1768 fastUnpacked = true;
1769 }
1770 }
1771
1772 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 +00001773 {
1774 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1775 }
1776}
1777
1778void Texture3D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
1779{
1780 if (Texture::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth, format, imageSize, pixels, mImageArray[level]))
1781 {
1782 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1783 }
1784}
1785
1786void Texture3D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
1787{
1788 delete mTexStorage;
1789 mTexStorage = new rx::TextureStorageInterface3D(mRenderer, levels, internalformat, mUsage, width, height, depth);
1790 mImmutable = true;
1791
1792 for (int level = 0; level < levels; level++)
1793 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001794 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, true);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001795 width = std::max(1, width >> 1);
1796 height = std::max(1, height >> 1);
1797 depth = std::max(1, depth >> 1);
1798 }
1799
1800 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1801 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001802 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, GL_NONE, 0, 0, 0, true);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001803 }
1804
1805 if (mTexStorage->isManaged())
1806 {
1807 int levels = levelCount();
1808
1809 for (int level = 0; level < levels; level++)
1810 {
1811 mImageArray[level]->setManagedSurface(mTexStorage, level);
1812 }
1813 }
1814}
1815
1816
1817void Texture3D::generateMipmaps()
1818{
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001819 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Jamie Madilld3d2a342013-10-07 10:46:35 -04001820 unsigned int q = log2(std::max(getBaseLevelWidth(), getBaseLevelHeight()));
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001821 for (unsigned int i = 1; i <= q; i++)
1822 {
Jamie Madilld3d2a342013-10-07 10:46:35 -04001823 redefineImage(i, getBaseLevelInternalFormat(),
1824 std::max(getBaseLevelWidth() >> i, 1),
1825 std::max(getBaseLevelHeight() >> i, 1),
1826 std::max(getBaseLevelDepth() >> i, 1));
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001827 }
1828
1829 if (mTexStorage && mTexStorage->isRenderTarget())
1830 {
1831 for (unsigned int i = 1; i <= q; i++)
1832 {
1833 mTexStorage->generateMipmap(i);
1834
1835 mImageArray[i]->markClean();
1836 }
1837 }
1838 else
1839 {
1840 for (unsigned int i = 1; i <= q; i++)
1841 {
1842 mRenderer->generateMipmap(mImageArray[i], mImageArray[i - 1]);
1843 }
1844 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001845}
1846
Jamie Madilld3d2a342013-10-07 10:46:35 -04001847const rx::Image *Texture3D::getBaseLevelImage() const
1848{
1849 return mImageArray[0];
1850}
1851
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001852void Texture3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1853{
1854 if (xoffset + width > mImageArray[level]->getWidth() || yoffset + height > mImageArray[level]->getHeight() || zoffset >= mImageArray[level]->getDepth())
1855 {
1856 return gl::error(GL_INVALID_VALUE);
1857 }
1858
Jamie Madill07edd442013-07-19 16:36:58 -04001859 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
1860 // the current level we're copying to is defined (with appropriate format, width & height)
1861 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
1862
1863 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001864 {
1865 mImageArray[level]->copy(xoffset, yoffset, zoffset, x, y, width, height, source);
1866 mDirtyImages = true;
1867 }
1868 else
1869 {
Jamie Madille83d1a92013-10-24 17:49:33 -04001870 ensureRenderTarget();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001871
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001872 if (level < levelCount())
1873 {
Jamie Madill07edd442013-07-19 16:36:58 -04001874 updateTextureLevel(level);
1875
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001876 gl::Rectangle sourceRect;
1877 sourceRect.x = x;
1878 sourceRect.width = width;
1879 sourceRect.y = y;
1880 sourceRect.height = height;
1881
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001882 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1883
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001884 mRenderer->copyImage(source, sourceRect,
Jamie Madilld3d2a342013-10-07 10:46:35 -04001885 gl::GetFormat(getBaseLevelInternalFormat(), clientVersion),
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001886 xoffset, yoffset, zoffset, mTexStorage, level);
1887 }
1888 }
1889}
1890
Jamie Madillf8989902013-07-19 16:36:58 -04001891bool Texture3D::isSamplerComplete(const SamplerState &samplerState) const
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001892{
Jamie Madilld3d2a342013-10-07 10:46:35 -04001893 GLsizei width = getBaseLevelWidth();
1894 GLsizei height = getBaseLevelHeight();
1895 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001896
1897 if (width <= 0 || height <= 0 || depth <= 0)
1898 {
1899 return false;
1900 }
1901
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001902 if (!IsTextureFilteringSupported(getInternalFormat(0), mRenderer))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001903 {
Jamie Madillf8989902013-07-19 16:36:58 -04001904 if (samplerState.magFilter != GL_NEAREST ||
1905 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001906 {
1907 return false;
1908 }
1909 }
1910
Jamie Madillf8989902013-07-19 16:36:58 -04001911 if (IsMipmapFiltered(samplerState) && !isMipmapComplete())
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001912 {
1913 return false;
1914 }
1915
1916 return true;
1917}
1918
1919bool Texture3D::isMipmapComplete() const
1920{
Jamie Madilld3d2a342013-10-07 10:46:35 -04001921 GLsizei width = getBaseLevelWidth();
1922 GLsizei height = getBaseLevelHeight();
1923 GLsizei depth = getBaseLevelDepth();
Jamie Madill07edd442013-07-19 16:36:58 -04001924
1925 int q = log2(std::max(std::max(width, height), depth));
1926
1927 for (int level = 0; level <= q; level++)
1928 {
1929 if (!isLevelComplete(level))
1930 {
1931 return false;
1932 }
1933 }
1934
1935 return true;
1936}
1937
1938bool Texture3D::isLevelComplete(int level) const
1939{
1940 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1941
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001942 if (isImmutable())
1943 {
1944 return true;
1945 }
1946
Jamie Madilld3d2a342013-10-07 10:46:35 -04001947 GLsizei width = getBaseLevelWidth();
1948 GLsizei height = getBaseLevelHeight();
1949 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001950
1951 if (width <= 0 || height <= 0 || depth <= 0)
1952 {
1953 return false;
1954 }
1955
Jamie Madill07edd442013-07-19 16:36:58 -04001956 if (level == 0)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001957 {
Jamie Madill07edd442013-07-19 16:36:58 -04001958 return true;
1959 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001960
Jamie Madill07edd442013-07-19 16:36:58 -04001961 rx::Image *levelImage = mImageArray[level];
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001962
Jamie Madilld3d2a342013-10-07 10:46:35 -04001963 if (levelImage->getInternalFormat() != getBaseLevelInternalFormat())
Jamie Madill07edd442013-07-19 16:36:58 -04001964 {
1965 return false;
1966 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001967
Jamie Madill07edd442013-07-19 16:36:58 -04001968 if (levelImage->getWidth() != std::max(1, width >> level))
1969 {
1970 return false;
1971 }
1972
1973 if (levelImage->getHeight() != std::max(1, height >> level))
1974 {
1975 return false;
1976 }
1977
1978 if (levelImage->getDepth() != std::max(1, depth >> level))
1979 {
1980 return false;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001981 }
1982
1983 return true;
1984}
1985
Geoff Lang8040f572013-07-25 16:49:54 -04001986Renderbuffer *Texture3D::getRenderbuffer(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001987{
Geoff Lang8040f572013-07-25 16:49:54 -04001988 Renderbuffer *renderBuffer = mRenderbufferProxies.get(level, layer);
1989 if (!renderBuffer)
1990 {
Geoff Langd5d8e392013-07-25 16:53:03 -04001991 renderBuffer = new Renderbuffer(mRenderer, id(), new RenderbufferTexture3DLayer(this, level, layer));
1992 mRenderbufferProxies.add(level, 0, renderBuffer);
Geoff Lang8040f572013-07-25 16:49:54 -04001993 }
1994
1995 return renderBuffer;
1996}
1997
1998unsigned int Texture3D::getRenderTargetSerial(GLint level, GLint layer)
1999{
Jamie Madille83d1a92013-10-24 17:49:33 -04002000 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(level, layer) : 0);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002001}
2002
2003int Texture3D::levelCount()
2004{
2005 return mTexStorage ? mTexStorage->levelCount() : 0;
2006}
2007
2008void Texture3D::createTexture()
2009{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002010 GLsizei width = getBaseLevelWidth();
2011 GLsizei height = getBaseLevelHeight();
2012 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002013
2014 if (!(width > 0 && height > 0 && depth > 0))
2015 return; // do not attempt to create native textures for nonexistant data
2016
2017 GLint levels = creationLevels(width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002018
2019 delete mTexStorage;
Jamie Madilld3d2a342013-10-07 10:46:35 -04002020 mTexStorage = new rx::TextureStorageInterface3D(mRenderer, levels, getBaseLevelInternalFormat(), mUsage, width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002021
2022 if (mTexStorage->isManaged())
2023 {
2024 int levels = levelCount();
2025
2026 for (int level = 0; level < levels; level++)
2027 {
2028 mImageArray[level]->setManagedSurface(mTexStorage, level);
2029 }
2030 }
2031
2032 mDirtyImages = true;
2033}
2034
2035void Texture3D::updateTexture()
2036{
Jamie Madilld9b9a502013-10-10 17:46:13 -04002037 int storageLevels = levelCount();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002038
Jamie Madilld9b9a502013-10-10 17:46:13 -04002039 for (int level = 0; level < storageLevels; level++)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002040 {
Jamie Madilld9b9a502013-10-10 17:46:13 -04002041 if (isLevelComplete(level))
2042 {
2043 updateTextureLevel(level);
2044 }
Jamie Madill07edd442013-07-19 16:36:58 -04002045 }
2046}
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002047
Jamie Madill07edd442013-07-19 16:36:58 -04002048void Texture3D::updateTextureLevel(int level)
2049{
2050 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
Jamie Madillaee7ad82013-10-10 16:07:32 -04002051 ASSERT(isLevelComplete(level));
Jamie Madill07edd442013-07-19 16:36:58 -04002052
Jamie Madillaee7ad82013-10-10 16:07:32 -04002053 if (mImageArray[level]->isDirty())
Jamie Madill07edd442013-07-19 16:36:58 -04002054 {
Jamie Madillaee7ad82013-10-10 16:07:32 -04002055 commitRect(level, 0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002056 }
2057}
2058
Jamie Madille83d1a92013-10-24 17:49:33 -04002059bool Texture3D::ensureRenderTarget()
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002060{
Jamie Madille83d1a92013-10-24 17:49:33 -04002061 if (mTexStorage && mTexStorage->isRenderTarget())
2062 {
2063 return true;
2064 }
2065
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002066 rx::TextureStorageInterface3D *newTexStorage = NULL;
2067
Jamie Madilld3d2a342013-10-07 10:46:35 -04002068 if (getBaseLevelWidth() != 0 && getBaseLevelHeight() != 0 && getBaseLevelDepth() != 0)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002069 {
Jamie Madilld3d2a342013-10-07 10:46:35 -04002070 GLsizei width = getBaseLevelWidth();
2071 GLsizei height = getBaseLevelHeight();
2072 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002073 GLint levels = mTexStorage != NULL ? mTexStorage->levelCount() : creationLevels(width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002074
Jamie Madilld3d2a342013-10-07 10:46:35 -04002075 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 +00002076
2077 if (mTexStorage != NULL)
2078 {
2079 if (!mRenderer->copyToRenderTarget(newTexStorage, mTexStorage))
2080 {
2081 delete newTexStorage;
Jamie Madille83d1a92013-10-24 17:49:33 -04002082 return gl::error(GL_OUT_OF_MEMORY, false);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002083 }
2084 }
2085 }
2086
2087 delete mTexStorage;
2088 mTexStorage = newTexStorage;
2089
2090 mDirtyImages = true;
Jamie Madille83d1a92013-10-24 17:49:33 -04002091 return (mTexStorage && mTexStorage->isRenderTarget());
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002092}
2093
Jamie Madilla2d4e552013-10-10 15:12:01 -04002094rx::RenderTarget *Texture3D::getRenderTarget(GLint level)
2095{
2096 // ensure the underlying texture is created
2097 if (getStorage(true) == NULL)
2098 {
2099 return NULL;
2100 }
2101
Jamie Madillaee7ad82013-10-10 16:07:32 -04002102 updateTextureLevel(level);
Jamie Madilla2d4e552013-10-10 15:12:01 -04002103
2104 // ensure this is NOT a depth texture
2105 if (isDepth(level))
2106 {
2107 return NULL;
2108 }
2109
2110 return mTexStorage->getRenderTarget(level);
2111}
2112
Geoff Lang8040f572013-07-25 16:49:54 -04002113rx::RenderTarget *Texture3D::getRenderTarget(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002114{
Geoff Lang8040f572013-07-25 16:49:54 -04002115 // ensure the underlying texture is created
2116 if (getStorage(true) == NULL)
2117 {
2118 return NULL;
2119 }
2120
2121 updateTexture();
2122
2123 // ensure this is NOT a depth texture
2124 if (isDepth(level))
2125 {
2126 return NULL;
2127 }
2128
2129 return mTexStorage->getRenderTarget(level, layer);
2130}
2131
2132rx::RenderTarget *Texture3D::getDepthStencil(GLint level, GLint layer)
2133{
2134 // ensure the underlying texture is created
2135 if (getStorage(true) == NULL)
2136 {
2137 return NULL;
2138 }
2139
Jamie Madillaee7ad82013-10-10 16:07:32 -04002140 updateTextureLevel(level);
Geoff Lang8040f572013-07-25 16:49:54 -04002141
2142 // ensure this is a depth texture
2143 if (!isDepth(level))
2144 {
2145 return NULL;
2146 }
2147
2148 return mTexStorage->getRenderTarget(level, layer);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002149}
2150
2151rx::TextureStorageInterface *Texture3D::getStorage(bool renderTarget)
2152{
2153 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
2154 {
2155 if (renderTarget)
2156 {
Jamie Madille83d1a92013-10-24 17:49:33 -04002157 ensureRenderTarget();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002158 }
2159 else
2160 {
2161 createTexture();
2162 }
2163 }
2164
2165 return mTexStorage;
2166}
2167
Geoff Lang005df412013-10-16 14:12:50 -04002168void Texture3D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002169{
2170 // If there currently is a corresponding storage texture image, it has these parameters
Jamie Madilld3d2a342013-10-07 10:46:35 -04002171 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2172 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
2173 const int storageDepth = std::max(1, getBaseLevelDepth() >> level);
Geoff Lang005df412013-10-16 14:12:50 -04002174 const GLenum storageFormat = getBaseLevelInternalFormat();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002175
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00002176 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, false);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002177
2178 if (mTexStorage)
2179 {
2180 const int storageLevels = mTexStorage->levelCount();
2181
2182 if ((level >= storageLevels && storageLevels != 0) ||
2183 width != storageWidth ||
2184 height != storageHeight ||
2185 depth != storageDepth ||
2186 internalformat != storageFormat) // Discard mismatched storage
2187 {
2188 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
2189 {
2190 mImageArray[i]->markDirty();
2191 }
2192
2193 delete mTexStorage;
2194 mTexStorage = NULL;
2195 mDirtyImages = true;
2196 }
2197 }
2198}
2199
2200void Texture3D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth)
2201{
2202 if (level < levelCount())
2203 {
2204 rx::Image *image = mImageArray[level];
2205 if (image->updateSurface(mTexStorage, level, xoffset, yoffset, zoffset, width, height, depth))
2206 {
2207 image->markClean();
2208 }
2209 }
2210}
2211
Geoff Lang4907f2c2013-07-25 12:53:57 -04002212Texture2DArray::Texture2DArray(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_2D_ARRAY)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002213{
2214 mTexStorage = NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002215
2216 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2217 {
2218 mLayerCounts[level] = 0;
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002219 mImageArray[level] = NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002220 }
2221}
2222
2223Texture2DArray::~Texture2DArray()
2224{
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002225 delete mTexStorage;
2226 mTexStorage = NULL;
2227 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2228 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002229 for (int layer = 0; layer < mLayerCounts[level]; ++layer)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002230 {
2231 delete mImageArray[level][layer];
2232 }
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002233 delete[] mImageArray[level];
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002234 }
2235}
2236
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002237GLsizei Texture2DArray::getWidth(GLint level) const
2238{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002239 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 +00002240}
2241
2242GLsizei Texture2DArray::getHeight(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]->getHeight() : 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002245}
2246
2247GLsizei Texture2DArray::getDepth(GLint level) const
2248{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002249 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mLayerCounts[level] : 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002250}
2251
2252GLenum Texture2DArray::getInternalFormat(GLint level) const
2253{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002254 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 +00002255}
2256
2257GLenum Texture2DArray::getActualFormat(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]->getActualFormat() : D3DFMT_UNKNOWN;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002260}
2261
2262bool Texture2DArray::isCompressed(GLint level) const
2263{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00002264 return IsFormatCompressed(getInternalFormat(level), mRenderer->getCurrentClientVersion());
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002265}
2266
2267bool Texture2DArray::isDepth(GLint level) const
2268{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00002269 return GetDepthBits(getInternalFormat(level), mRenderer->getCurrentClientVersion()) > 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002270}
2271
Geoff Lang005df412013-10-16 14:12:50 -04002272void 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 +00002273{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00002274 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Geoff Lang005df412013-10-16 14:12:50 -04002275 GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
2276 : GetSizedInternalFormat(format, type, clientVersion);
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00002277 redefineImage(level, sizedInternalFormat, width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002278
Jamie Madill88f18f42013-09-18 14:36:19 -04002279 GLsizei inputDepthPitch = gl::GetDepthPitch(sizedInternalFormat, type, clientVersion, width, height, unpack.alignment);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002280
2281 for (int i = 0; i < depth; i++)
2282 {
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002283 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
Jamie Madill88f18f42013-09-18 14:36:19 -04002284 Texture::setImage(unpack, type, layerPixels, mImageArray[level][i]);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002285 }
2286}
2287
2288void Texture2DArray::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
2289{
2290 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
2291 redefineImage(level, format, width, height, depth);
2292
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002293 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2294 GLsizei inputDepthPitch = gl::GetDepthPitch(format, GL_UNSIGNED_BYTE, clientVersion, width, height, 1);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002295
2296 for (int i = 0; i < depth; i++)
2297 {
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002298 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002299 Texture::setCompressedImage(imageSize, layerPixels, mImageArray[level][i]);
2300 }
2301}
2302
Jamie Madill88f18f42013-09-18 14:36:19 -04002303void 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 +00002304{
Geoff Lang005df412013-10-16 14:12:50 -04002305 GLenum internalformat = getInternalFormat(level);
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002306 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Jamie Madill88f18f42013-09-18 14:36:19 -04002307 GLsizei inputDepthPitch = gl::GetDepthPitch(internalformat, type, clientVersion, width, height, unpack.alignment);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002308
2309 for (int i = 0; i < depth; i++)
2310 {
2311 int layer = zoffset + i;
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002312 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002313
Jamie Madill88f18f42013-09-18 14:36:19 -04002314 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 +00002315 {
2316 commitRect(level, xoffset, yoffset, layer, width, height);
2317 }
2318 }
2319}
2320
2321void Texture2DArray::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
2322{
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002323 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2324 GLsizei inputDepthPitch = gl::GetDepthPitch(format, GL_UNSIGNED_BYTE, clientVersion, width, height, 1);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002325
2326 for (int i = 0; i < depth; i++)
2327 {
2328 int layer = zoffset + i;
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002329 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002330
2331 if (Texture::subImageCompressed(xoffset, yoffset, zoffset, width, height, 1, format, imageSize, layerPixels, mImageArray[level][layer]))
2332 {
2333 commitRect(level, xoffset, yoffset, layer, width, height);
2334 }
2335 }
2336}
2337
2338void Texture2DArray::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2339{
2340 delete mTexStorage;
2341 mTexStorage = new rx::TextureStorageInterface2DArray(mRenderer, levels, internalformat, mUsage, width, height, depth);
2342 mImmutable = true;
2343
2344 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2345 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002346 GLsizei levelWidth = std::max(width >> level, 1);
Geoff Lange836cf22013-08-05 14:12:37 -04002347 GLsizei levelHeight = std::max(height >> level, 1);
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002348
2349 // Clear this level
2350 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002351 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002352 delete mImageArray[level][layer];
2353 }
2354 delete[] mImageArray[level];
2355 mImageArray[level] = NULL;
2356 mLayerCounts[level] = 0;
2357
2358 if (level < levels)
2359 {
2360 // Create new images for this level
2361 mImageArray[level] = new rx::Image*[depth]();
2362 mLayerCounts[level] = depth;
2363
2364 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002365 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002366 mImageArray[level][layer] = mRenderer->createImage();
2367 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, levelWidth,
2368 levelHeight, 1, true);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002369 }
2370 }
2371 }
2372
2373 if (mTexStorage->isManaged())
2374 {
2375 int levels = levelCount();
2376
2377 for (int level = 0; level < levels; level++)
2378 {
2379 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2380 {
2381 mImageArray[level][layer]->setManagedSurface(mTexStorage, layer, level);
2382 }
2383 }
2384 }
2385}
2386
2387void Texture2DArray::generateMipmaps()
2388{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002389 int baseWidth = getBaseLevelWidth();
2390 int baseHeight = getBaseLevelHeight();
2391 int baseDepth = getBaseLevelDepth();
2392 GLenum baseFormat = getBaseLevelInternalFormat();
2393
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00002394 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Jamie Madilld3d2a342013-10-07 10:46:35 -04002395 int q = log2(std::max(baseWidth, baseHeight));
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00002396 for (int i = 1; i <= q; i++)
2397 {
Jamie Madilld3d2a342013-10-07 10:46:35 -04002398 redefineImage(i, baseFormat, std::max(baseWidth >> i, 1), std::max(baseHeight >> i, 1), baseDepth);
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00002399 }
2400
2401 if (mTexStorage && mTexStorage->isRenderTarget())
2402 {
2403 for (int level = 1; level <= q; level++)
2404 {
2405 mTexStorage->generateMipmap(level);
2406
2407 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2408 {
2409 mImageArray[level][layer]->markClean();
2410 }
2411 }
2412 }
2413 else
2414 {
2415 for (int level = 1; level <= q; level++)
2416 {
2417 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2418 {
2419 mRenderer->generateMipmap(mImageArray[level][layer], mImageArray[level - 1][layer]);
2420 }
2421 }
2422 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002423}
2424
Jamie Madilld3d2a342013-10-07 10:46:35 -04002425const rx::Image *Texture2DArray::getBaseLevelImage() const
2426{
Jamie Madill152ed092013-10-09 17:01:15 -04002427 return (mLayerCounts[0] > 0 ? mImageArray[0][0] : NULL);
Jamie Madilld3d2a342013-10-07 10:46:35 -04002428}
2429
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002430void Texture2DArray::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
2431{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002432 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 +00002433 {
2434 return gl::error(GL_INVALID_VALUE);
2435 }
2436
Jamie Madill07edd442013-07-19 16:36:58 -04002437 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
2438 // the current level we're copying to is defined (with appropriate format, width & height)
2439 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
2440
2441 if (!mImageArray[level][0]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002442 {
2443 mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, x, y, width, height, source);
2444 mDirtyImages = true;
2445 }
2446 else
2447 {
Jamie Madille83d1a92013-10-24 17:49:33 -04002448 ensureRenderTarget();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002449
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002450 if (level < levelCount())
2451 {
Jamie Madill07edd442013-07-19 16:36:58 -04002452 updateTextureLevel(level);
2453
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002454 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2455
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002456 gl::Rectangle sourceRect;
2457 sourceRect.x = x;
2458 sourceRect.width = width;
2459 sourceRect.y = y;
2460 sourceRect.height = height;
2461
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002462 mRenderer->copyImage(source, sourceRect, gl::GetFormat(getInternalFormat(0), clientVersion),
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002463 xoffset, yoffset, zoffset, mTexStorage, level);
2464 }
2465 }
2466}
2467
Jamie Madillf8989902013-07-19 16:36:58 -04002468bool Texture2DArray::isSamplerComplete(const SamplerState &samplerState) const
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002469{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002470 GLsizei width = getBaseLevelWidth();
2471 GLsizei height = getBaseLevelHeight();
2472 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002473
2474 if (width <= 0 || height <= 0 || depth <= 0)
2475 {
2476 return false;
2477 }
2478
Jamie Madilld3d2a342013-10-07 10:46:35 -04002479 if (!IsTextureFilteringSupported(getBaseLevelInternalFormat(), mRenderer))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002480 {
Jamie Madillf8989902013-07-19 16:36:58 -04002481 if (samplerState.magFilter != GL_NEAREST ||
2482 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002483 {
2484 return false;
2485 }
2486 }
2487
Jamie Madillf8989902013-07-19 16:36:58 -04002488 if (IsMipmapFiltered(samplerState) && !isMipmapComplete())
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002489 {
2490 return false;
2491 }
2492
2493 return true;
2494}
2495
2496bool Texture2DArray::isMipmapComplete() const
2497{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002498 GLsizei width = getBaseLevelWidth();
2499 GLsizei height = getBaseLevelHeight();
Jamie Madill07edd442013-07-19 16:36:58 -04002500
2501 int q = log2(std::max(width, height));
2502
2503 for (int level = 1; level <= q; level++)
2504 {
2505 if (!isLevelComplete(level))
2506 {
2507 return false;
2508 }
2509 }
2510
2511 return true;
2512}
2513
2514bool Texture2DArray::isLevelComplete(int level) const
2515{
2516 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
2517
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002518 if (isImmutable())
2519 {
2520 return true;
2521 }
2522
Jamie Madilld3d2a342013-10-07 10:46:35 -04002523 GLsizei width = getBaseLevelWidth();
2524 GLsizei height = getBaseLevelHeight();
2525 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002526
2527 if (width <= 0 || height <= 0 || depth <= 0)
2528 {
2529 return false;
2530 }
2531
Jamie Madill07edd442013-07-19 16:36:58 -04002532 if (level == 0)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002533 {
Jamie Madill07edd442013-07-19 16:36:58 -04002534 return true;
2535 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002536
Jamie Madill07edd442013-07-19 16:36:58 -04002537 if (getInternalFormat(level) != getInternalFormat(0))
2538 {
2539 return false;
2540 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002541
Jamie Madill07edd442013-07-19 16:36:58 -04002542 if (getWidth(level) != std::max(1, width >> level))
2543 {
2544 return false;
2545 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002546
Jamie Madill07edd442013-07-19 16:36:58 -04002547 if (getHeight(level) != std::max(1, height >> level))
2548 {
2549 return false;
2550 }
2551
2552 if (getDepth(level) != depth)
2553 {
2554 return false;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002555 }
2556
2557 return true;
2558}
2559
Geoff Lang8040f572013-07-25 16:49:54 -04002560Renderbuffer *Texture2DArray::getRenderbuffer(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002561{
Geoff Lang8040f572013-07-25 16:49:54 -04002562 Renderbuffer *renderBuffer = mRenderbufferProxies.get(level, layer);
2563 if (!renderBuffer)
2564 {
Geoff Langd5d8e392013-07-25 16:53:03 -04002565 renderBuffer = new Renderbuffer(mRenderer, id(), new RenderbufferTexture2DArrayLayer(this, level, layer));
2566 mRenderbufferProxies.add(level, 0, renderBuffer);
Geoff Lang8040f572013-07-25 16:49:54 -04002567 }
2568
2569 return renderBuffer;
2570}
2571
Jamie Madille83d1a92013-10-24 17:49:33 -04002572unsigned int Texture2DArray::getRenderTargetSerial(GLint level, GLint layer)
Geoff Lang8040f572013-07-25 16:49:54 -04002573{
Jamie Madille83d1a92013-10-24 17:49:33 -04002574 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(level, layer) : 0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002575}
2576
2577int Texture2DArray::levelCount()
2578{
2579 return mTexStorage ? mTexStorage->levelCount() : 0;
2580}
2581
2582void Texture2DArray::createTexture()
2583{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002584 GLsizei width = getBaseLevelWidth();
2585 GLsizei height = getBaseLevelHeight();
2586 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002587
2588 if (width <= 0 || height <= 0 || depth <= 0)
2589 {
2590 return; // do not attempt to create native textures for nonexistant data
2591 }
2592
2593 GLint levels = creationLevels(width, height);
Jamie Madilld3d2a342013-10-07 10:46:35 -04002594 GLenum internalformat = getBaseLevelInternalFormat();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002595
2596 delete mTexStorage;
2597 mTexStorage = new rx::TextureStorageInterface2DArray(mRenderer, levels, internalformat, mUsage, width, height, depth);
2598
2599 if (mTexStorage->isManaged())
2600 {
2601 int levels = levelCount();
2602 for (int level = 0; level < levels; level++)
2603 {
2604 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2605 {
2606 mImageArray[level][layer]->setManagedSurface(mTexStorage, layer, level);
2607 }
2608 }
2609 }
2610
2611 mDirtyImages = true;
2612}
2613
2614void Texture2DArray::updateTexture()
2615{
Jamie Madilld9b9a502013-10-10 17:46:13 -04002616 int storageLevels = levelCount();
2617
2618 for (int level = 0; level < storageLevels; level++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002619 {
Jamie Madilld9b9a502013-10-10 17:46:13 -04002620 if (isLevelComplete(level))
2621 {
2622 updateTextureLevel(level);
2623 }
Jamie Madill07edd442013-07-19 16:36:58 -04002624 }
2625}
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002626
Jamie Madill07edd442013-07-19 16:36:58 -04002627void Texture2DArray::updateTextureLevel(int level)
2628{
Jamie Madillaee7ad82013-10-10 16:07:32 -04002629 ASSERT(level >= 0 && level < (int)ArraySize(mLayerCounts));
2630 ASSERT(isLevelComplete(level));
2631
Jamie Madill07edd442013-07-19 16:36:58 -04002632 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2633 {
Jamie Madillaee7ad82013-10-10 16:07:32 -04002634 ASSERT(mImageArray[level] != NULL && mImageArray[level][layer] != NULL);
2635 if (mImageArray[level][layer]->isDirty())
Jamie Madill07edd442013-07-19 16:36:58 -04002636 {
Jamie Madillaee7ad82013-10-10 16:07:32 -04002637 commitRect(level, 0, 0, layer, getWidth(level), getHeight(level));
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002638 }
2639 }
2640}
2641
Jamie Madille83d1a92013-10-24 17:49:33 -04002642bool Texture2DArray::ensureRenderTarget()
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002643{
Jamie Madille83d1a92013-10-24 17:49:33 -04002644 if (mTexStorage && mTexStorage->isRenderTarget())
2645 {
2646 return true;
2647 }
2648
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002649 rx::TextureStorageInterface2DArray *newTexStorage = NULL;
2650
Jamie Madilld3d2a342013-10-07 10:46:35 -04002651 GLsizei width = getBaseLevelWidth();
2652 GLsizei height = getBaseLevelHeight();
2653 GLsizei depth = getBaseLevelDepth();
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002654
2655 if (width != 0 && height != 0 && depth != 0)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002656 {
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002657 GLint levels = mTexStorage != NULL ? mTexStorage->levelCount() : creationLevels(width, height);
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002658 GLenum internalformat = getInternalFormat(0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002659
2660 newTexStorage = new rx::TextureStorageInterface2DArray(mRenderer, levels, internalformat, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, width, height, depth);
2661
2662 if (mTexStorage != NULL)
2663 {
2664 if (!mRenderer->copyToRenderTarget(newTexStorage, mTexStorage))
2665 {
2666 delete newTexStorage;
Jamie Madille83d1a92013-10-24 17:49:33 -04002667 return gl::error(GL_OUT_OF_MEMORY, false);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002668 }
2669 }
2670 }
2671
2672 delete mTexStorage;
2673 mTexStorage = newTexStorage;
2674
2675 mDirtyImages = true;
Jamie Madille83d1a92013-10-24 17:49:33 -04002676 return (mTexStorage && mTexStorage->isRenderTarget());
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002677}
2678
Geoff Lang8040f572013-07-25 16:49:54 -04002679rx::RenderTarget *Texture2DArray::getRenderTarget(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002680{
Geoff Lang8040f572013-07-25 16:49:54 -04002681 // ensure the underlying texture is created
2682 if (getStorage(true) == NULL)
2683 {
2684 return NULL;
2685 }
2686
Jamie Madillaee7ad82013-10-10 16:07:32 -04002687 updateTextureLevel(level);
Geoff Lang8040f572013-07-25 16:49:54 -04002688
2689 // ensure this is NOT a depth texture
2690 if (isDepth(level))
2691 {
2692 return NULL;
2693 }
2694
2695 return mTexStorage->getRenderTarget(level, layer);
2696}
2697
2698rx::RenderTarget *Texture2DArray::getDepthStencil(GLint level, GLint layer)
2699{
2700 // ensure the underlying texture is created
2701 if (getStorage(true) == NULL)
2702 {
2703 return NULL;
2704 }
2705
Jamie Madillaee7ad82013-10-10 16:07:32 -04002706 updateTextureLevel(level);
Geoff Lang8040f572013-07-25 16:49:54 -04002707
2708 // ensure this is a depth texture
2709 if (!isDepth(level))
2710 {
2711 return NULL;
2712 }
2713
2714 return mTexStorage->getRenderTarget(level, layer);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002715}
2716
2717rx::TextureStorageInterface *Texture2DArray::getStorage(bool renderTarget)
2718{
2719 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
2720 {
2721 if (renderTarget)
2722 {
Jamie Madille83d1a92013-10-24 17:49:33 -04002723 ensureRenderTarget();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002724 }
2725 else
2726 {
2727 createTexture();
2728 }
2729 }
2730
2731 return mTexStorage;
2732}
2733
Geoff Lang005df412013-10-16 14:12:50 -04002734void Texture2DArray::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002735{
2736 // If there currently is a corresponding storage texture image, it has these parameters
Jamie Madilld3d2a342013-10-07 10:46:35 -04002737 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2738 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
2739 const int storageDepth = getBaseLevelDepth();
Geoff Lang005df412013-10-16 14:12:50 -04002740 const GLenum storageFormat = getBaseLevelInternalFormat();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002741
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002742 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002743 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002744 delete mImageArray[level][layer];
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002745 }
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002746 delete[] mImageArray[level];
Jamie Madill152ed092013-10-09 17:01:15 -04002747 mImageArray[level] = NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002748 mLayerCounts[level] = depth;
2749
Jamie Madill152ed092013-10-09 17:01:15 -04002750 if (depth > 0)
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002751 {
Jamie Madill152ed092013-10-09 17:01:15 -04002752 mImageArray[level] = new rx::Image*[depth]();
2753
2754 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2755 {
2756 mImageArray[level][layer] = mRenderer->createImage();
2757 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, width, height, 1, false);
2758 }
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002759 }
2760
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002761 if (mTexStorage)
2762 {
2763 const int storageLevels = mTexStorage->levelCount();
2764
2765 if ((level >= storageLevels && storageLevels != 0) ||
2766 width != storageWidth ||
2767 height != storageHeight ||
2768 depth != storageDepth ||
2769 internalformat != storageFormat) // Discard mismatched storage
2770 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002771 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002772 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002773 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002774 {
2775 mImageArray[level][layer]->markDirty();
2776 }
2777 }
2778
2779 delete mTexStorage;
2780 mTexStorage = NULL;
2781 mDirtyImages = true;
2782 }
2783 }
2784}
2785
2786void Texture2DArray::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint layerTarget, GLsizei width, GLsizei height)
2787{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002788 if (level < levelCount() && layerTarget < getDepth(level))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002789 {
2790 rx::Image *image = mImageArray[level][layerTarget];
2791 if (image->updateSurface(mTexStorage, level, xoffset, yoffset, layerTarget, width, height))
2792 {
2793 image->markClean();
2794 }
2795 }
2796}
2797
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00002798}