blob: 0d285f18f42cb9b3ee3b89a47ecdb90e29906cbf [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"
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000025
26namespace gl
27{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000028
Jamie Madillf8989902013-07-19 16:36:58 -040029bool IsMipmapFiltered(const SamplerState &samplerState)
30{
31 switch (samplerState.minFilter)
32 {
33 case GL_NEAREST:
34 case GL_LINEAR:
35 return false;
36 case GL_NEAREST_MIPMAP_NEAREST:
37 case GL_LINEAR_MIPMAP_NEAREST:
38 case GL_NEAREST_MIPMAP_LINEAR:
39 case GL_LINEAR_MIPMAP_LINEAR:
40 return true;
41 default: UNREACHABLE();
42 return false;
43 }
44}
45
Geoff Lang4907f2c2013-07-25 12:53:57 -040046Texture::Texture(rx::Renderer *renderer, GLuint id, GLenum target) : RefCountObject(id)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000047{
daniel@transgaming.com370482e2012-11-28 19:32:13 +000048 mRenderer = renderer;
49
daniel@transgaming.comebf139f2012-10-31 18:07:32 +000050 mSamplerState.minFilter = GL_NEAREST_MIPMAP_LINEAR;
51 mSamplerState.magFilter = GL_LINEAR;
52 mSamplerState.wrapS = GL_REPEAT;
53 mSamplerState.wrapT = GL_REPEAT;
shannon.woods%transgaming.com@gtempaccount.com0b3a8df2013-04-13 03:44:51 +000054 mSamplerState.wrapR = GL_REPEAT;
daniel@transgaming.comebf139f2012-10-31 18:07:32 +000055 mSamplerState.maxAnisotropy = 1.0f;
56 mSamplerState.lodOffset = 0;
Geoff Langc82fc412013-07-10 14:43:42 -040057 mSamplerState.compareMode = GL_NONE;
58 mSamplerState.compareFunc = GL_LEQUAL;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000059 mUsage = GL_NONE;
Geoff Langc82fc412013-07-10 14:43:42 -040060
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000061 mDirtyImages = true;
62
63 mImmutable = false;
Geoff Lang4907f2c2013-07-25 12:53:57 -040064
65 mTarget = target;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000066}
67
68Texture::~Texture()
69{
70}
71
Geoff Lang4907f2c2013-07-25 12:53:57 -040072GLenum Texture::getTarget() const
73{
74 return mTarget;
75}
76
Geoff Lang8040f572013-07-25 16:49:54 -040077void Texture::addProxyRef(const Renderbuffer *proxy)
78{
79 mRenderbufferProxies.addRef(proxy);
80}
81
82void Texture::releaseProxy(const Renderbuffer *proxy)
83{
84 mRenderbufferProxies.release(proxy);
85}
86
Geoff Lang63b5f1f2013-09-23 14:52:14 -040087void Texture::setMinFilter(GLenum filter)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000088{
Geoff Lang63b5f1f2013-09-23 14:52:14 -040089 mSamplerState.minFilter = filter;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000090}
91
Geoff Lang63b5f1f2013-09-23 14:52:14 -040092void Texture::setMagFilter(GLenum filter)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000093{
Geoff Lang63b5f1f2013-09-23 14:52:14 -040094 mSamplerState.magFilter = filter;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000095}
96
Geoff Lang63b5f1f2013-09-23 14:52:14 -040097void Texture::setWrapS(GLenum wrap)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000098{
Geoff Lang63b5f1f2013-09-23 14:52:14 -040099 mSamplerState.wrapS = wrap;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000100}
101
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400102void Texture::setWrapT(GLenum wrap)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000103{
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400104 mSamplerState.wrapT = wrap;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000105}
106
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400107void Texture::setWrapR(GLenum wrap)
shannon.woods%transgaming.com@gtempaccount.com0b3a8df2013-04-13 03:44:51 +0000108{
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400109 mSamplerState.wrapR = wrap;
shannon.woods%transgaming.com@gtempaccount.com0b3a8df2013-04-13 03:44:51 +0000110}
111
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400112void Texture::setMaxAnisotropy(float textureMaxAnisotropy, float contextMaxAnisotropy)
daniel@transgaming.com07ab8412012-07-12 15:17:09 +0000113{
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400114 mSamplerState.maxAnisotropy = std::min(textureMaxAnisotropy, contextMaxAnisotropy);
daniel@transgaming.com07ab8412012-07-12 15:17:09 +0000115}
116
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400117void Texture::setCompareMode(GLenum mode)
Geoff Langc82fc412013-07-10 14:43:42 -0400118{
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400119 mSamplerState.compareMode = mode;
Geoff Langc82fc412013-07-10 14:43:42 -0400120}
121
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400122void Texture::setCompareFunc(GLenum func)
Geoff Langc82fc412013-07-10 14:43:42 -0400123{
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400124 mSamplerState.compareFunc = func;
Geoff Langc82fc412013-07-10 14:43:42 -0400125}
126
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400127void Texture::setUsage(GLenum usage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000128{
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400129 mUsage = usage;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000130}
131
132GLenum Texture::getMinFilter() const
133{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000134 return mSamplerState.minFilter;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000135}
136
137GLenum Texture::getMagFilter() const
138{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000139 return mSamplerState.magFilter;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000140}
141
142GLenum Texture::getWrapS() const
143{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000144 return mSamplerState.wrapS;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000145}
146
147GLenum Texture::getWrapT() const
148{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000149 return mSamplerState.wrapT;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000150}
151
shannon.woods%transgaming.com@gtempaccount.com0b3a8df2013-04-13 03:44:51 +0000152GLenum Texture::getWrapR() const
153{
154 return mSamplerState.wrapR;
155}
156
daniel@transgaming.com07ab8412012-07-12 15:17:09 +0000157float Texture::getMaxAnisotropy() const
158{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000159 return mSamplerState.maxAnisotropy;
160}
161
162int Texture::getLodOffset()
163{
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000164 rx::TextureStorageInterface *texture = getStorage(false);
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000165 return texture ? texture->getLodOffset() : 0;
166}
167
168void Texture::getSamplerState(SamplerState *sampler)
169{
170 *sampler = mSamplerState;
171 sampler->lodOffset = getLodOffset();
daniel@transgaming.com07ab8412012-07-12 15:17:09 +0000172}
173
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000174GLenum Texture::getUsage() const
175{
176 return mUsage;
177}
178
Jamie Madilld3d2a342013-10-07 10:46:35 -0400179GLint Texture::getBaseLevelWidth() const
180{
181 const rx::Image *baseImage = getBaseLevelImage();
182 return (baseImage ? baseImage->getWidth() : 0);
183}
184
185GLint Texture::getBaseLevelHeight() const
186{
187 const rx::Image *baseImage = getBaseLevelImage();
188 return (baseImage ? baseImage->getHeight() : 0);
189}
190
191GLint Texture::getBaseLevelDepth() const
192{
193 const rx::Image *baseImage = getBaseLevelImage();
194 return (baseImage ? baseImage->getDepth() : 0);
195}
196
197GLenum Texture::getBaseLevelInternalFormat() const
198{
199 const rx::Image *baseImage = getBaseLevelImage();
200 return (baseImage ? baseImage->getInternalFormat() : GL_NONE);
201}
202
Jamie Madill88f18f42013-09-18 14:36:19 -0400203void Texture::setImage(const PixelUnpackState &unpack, GLenum type, const void *pixels, rx::Image *image)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000204{
Jamie Madillabef6802013-09-05 16:54:19 -0400205 // We no longer need the "GLenum format" parameter to TexImage to determine what data format "pixels" contains.
206 // 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 -0400207 const void *pixelData = pixels;
208
209 if (unpack.pixelBuffer.id() != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000210 {
Jamie Madill1beb1db2013-09-18 14:36:28 -0400211 // Do a CPU readback here, if we have an unpack buffer bound and the fast GPU path is not supported
212 Buffer *pixelBuffer = unpack.pixelBuffer.get();
213 ptrdiff_t offset = reinterpret_cast<ptrdiff_t>(pixels);
214 const void *bufferData = pixelBuffer->getStorage()->getData();
215 pixelData = static_cast<const unsigned char *>(bufferData) + offset;
216 }
217
218 if (pixelData != NULL)
219 {
220 image->loadData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), unpack.alignment, type, pixelData);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000221 mDirtyImages = true;
222 }
223}
224
Jamie Madill1beb1db2013-09-18 14:36:28 -0400225bool Texture::fastUnpackPixels(const PixelUnpackState &unpack, const void *pixels, const Box &destArea,
226 GLenum sizedInternalFormat, GLenum type, GLint level)
227{
228 if (destArea.width <= 0 && destArea.height <= 0 && destArea.depth <= 0)
229 {
230 return true;
231 }
232
233 // In order to perform the fast copy through the shader, we must have the right format, and be able
234 // to create a render target.
235 if (IsFastCopyBufferToTextureSupported(sizedInternalFormat, mRenderer->getCurrentClientVersion()))
236 {
237 unsigned int offset = reinterpret_cast<unsigned int>(pixels);
238 rx::RenderTarget *destRenderTarget = getStorage(true)->getStorageInstance()->getRenderTarget(level);
239
240 return mRenderer->fastCopyBufferToTexture(unpack, offset, destRenderTarget, sizedInternalFormat, type, destArea);
241 }
242
243 // Return false if we do not support fast unpack
244 return false;
245}
246
daniel@transgaming.com31b13e12012-11-28 19:34:30 +0000247void Texture::setCompressedImage(GLsizei imageSize, const void *pixels, rx::Image *image)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000248{
249 if (pixels != NULL)
250 {
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000251 image->loadCompressedData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000252 mDirtyImages = true;
253 }
254}
255
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000256bool Texture::subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
Jamie Madill88f18f42013-09-18 14:36:19 -0400257 GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels, rx::Image *image)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000258{
259 if (pixels != NULL)
260 {
Jamie Madill88f18f42013-09-18 14:36:19 -0400261 image->loadData(xoffset, yoffset, zoffset, width, height, depth, unpack.alignment, type, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000262 mDirtyImages = true;
263 }
264
265 return true;
266}
267
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000268bool Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
269 GLenum format, GLsizei imageSize, const void *pixels, rx::Image *image)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000270{
271 if (pixels != NULL)
272 {
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000273 image->loadCompressedData(xoffset, yoffset, zoffset, width, height, depth, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000274 mDirtyImages = true;
275 }
276
277 return true;
278}
279
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000280rx::TextureStorageInterface *Texture::getNativeTexture()
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000281{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000282 // ensure the underlying texture is created
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000283
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000284 rx::TextureStorageInterface *storage = getStorage(false);
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000285 if (storage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000286 {
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000287 updateTexture();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000288 }
289
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000290 return storage;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000291}
292
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000293bool Texture::hasDirtyImages() const
294{
295 return mDirtyImages;
296}
297
298void Texture::resetDirty()
299{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000300 mDirtyImages = false;
301}
302
303unsigned int Texture::getTextureSerial()
304{
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000305 rx::TextureStorageInterface *texture = getStorage(false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000306 return texture ? texture->getTextureSerial() : 0;
307}
308
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000309bool Texture::isImmutable() const
310{
311 return mImmutable;
312}
313
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +0000314GLint Texture::creationLevels(GLsizei width, GLsizei height, GLsizei depth) const
315{
316 // NPOT checks are not required in ES 3.0, NPOT texture support is assumed.
317 return 0; // Maximum number of levels
318}
319
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000320GLint Texture::creationLevels(GLsizei width, GLsizei height) const
321{
daniel@transgaming.comea32d482012-11-28 19:33:18 +0000322 if ((isPow2(width) && isPow2(height)) || mRenderer->getNonPower2TextureSupport())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000323 {
324 return 0; // Maximum number of levels
325 }
326 else
327 {
328 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
329 return 1;
330 }
331}
332
333GLint Texture::creationLevels(GLsizei size) const
334{
335 return creationLevels(size, size);
336}
337
Geoff Lang4907f2c2013-07-25 12:53:57 -0400338Texture2D::Texture2D(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_2D)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000339{
340 mTexStorage = NULL;
341 mSurface = NULL;
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000342
343 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
344 {
daniel@transgaming.com244e1832012-12-20 20:52:35 +0000345 mImageArray[i] = renderer->createImage();
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000346 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000347}
348
349Texture2D::~Texture2D()
350{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000351 delete mTexStorage;
352 mTexStorage = NULL;
353
354 if (mSurface)
355 {
356 mSurface->setBoundTexture(NULL);
357 mSurface = NULL;
358 }
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000359
360 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
361 {
362 delete mImageArray[i];
363 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000364}
365
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000366GLsizei Texture2D::getWidth(GLint level) const
367{
368 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000369 return mImageArray[level]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000370 else
371 return 0;
372}
373
374GLsizei Texture2D::getHeight(GLint level) const
375{
376 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000377 return mImageArray[level]->getHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000378 else
379 return 0;
380}
381
382GLenum Texture2D::getInternalFormat(GLint level) const
383{
384 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000385 return mImageArray[level]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000386 else
387 return GL_NONE;
388}
389
daniel@transgaming.com20d36662012-10-31 19:51:43 +0000390GLenum Texture2D::getActualFormat(GLint level) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000391{
392 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000393 return mImageArray[level]->getActualFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000394 else
395 return D3DFMT_UNKNOWN;
396}
397
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000398void Texture2D::redefineImage(GLint level, GLint internalformat, GLsizei width, GLsizei height)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000399{
400 releaseTexImage();
shannon.woods@transgaming.com8a406682013-02-28 23:15:26 +0000401
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000402 // If there currently is a corresponding storage texture image, it has these parameters
Jamie Madilld3d2a342013-10-07 10:46:35 -0400403 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
404 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
405 const int storageFormat = getBaseLevelInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000406
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000407 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, width, height, 1, false);
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000408
409 if (mTexStorage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000410 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000411 const int storageLevels = mTexStorage->levelCount();
412
413 if ((level >= storageLevels && storageLevels != 0) ||
414 width != storageWidth ||
415 height != storageHeight ||
416 internalformat != storageFormat) // Discard mismatched storage
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000417 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000418 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
419 {
420 mImageArray[i]->markDirty();
421 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000422
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000423 delete mTexStorage;
424 mTexStorage = NULL;
425 mDirtyImages = true;
426 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000427 }
428}
429
Jamie Madill88f18f42013-09-18 14:36:19 -0400430void Texture2D::setImage(GLint level, GLsizei width, GLsizei height, GLint internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000431{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +0000432 GLuint clientVersion = mRenderer->getCurrentClientVersion();
433 GLint sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
434 : GetSizedInternalFormat(format, type, clientVersion);
435 redefineImage(level, sizedInternalFormat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000436
Jamie Madill1beb1db2013-09-18 14:36:28 -0400437 // Attempt a fast gpu copy of the pixel data to the surface
438 // If we want to support rendering (which is necessary for GPU unpack buffers), level 0 must be complete
439 Box destArea(0, 0, 0, getWidth(level), getHeight(level), 1);
440 if (unpack.pixelBuffer.id() != 0 && isLevelComplete(0) && fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, level))
441 {
442 // Ensure we don't overwrite our newly initialized data
443 mImageArray[level]->markClean();
444 }
445 else
446 {
447 Texture::setImage(unpack, type, pixels, mImageArray[level]);
448 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000449}
450
451void Texture2D::bindTexImage(egl::Surface *surface)
452{
453 releaseTexImage();
454
daniel@transgaming.com106e1f72012-10-31 18:38:36 +0000455 GLint internalformat = surface->getFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000456
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000457 mImageArray[0]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, surface->getWidth(), surface->getHeight(), 1, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000458
459 delete mTexStorage;
daniel@transgaming.comd8353dd2012-12-20 21:11:14 +0000460 mTexStorage = new rx::TextureStorageInterface2D(mRenderer, surface->getSwapChain());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000461
462 mDirtyImages = true;
463 mSurface = surface;
464 mSurface->setBoundTexture(this);
465}
466
467void Texture2D::releaseTexImage()
468{
469 if (mSurface)
470 {
471 mSurface->setBoundTexture(NULL);
472 mSurface = NULL;
473
474 if (mTexStorage)
475 {
476 delete mTexStorage;
477 mTexStorage = NULL;
478 }
479
480 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
481 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000482 mImageArray[i]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000483 }
484 }
485}
486
487void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
488{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000489 // 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 +0000490 redefineImage(level, format, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000491
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000492 Texture::setCompressedImage(imageSize, pixels, mImageArray[level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000493}
494
495void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
496{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000497 if (level < levelCount())
498 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000499 rx::Image *image = mImageArray[level];
daniel@transgaming.com0f195ad2012-10-31 19:51:59 +0000500 if (image->updateSurface(mTexStorage, level, xoffset, yoffset, width, height))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000501 {
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000502 image->markClean();
503 }
504 }
505}
506
Jamie Madill88f18f42013-09-18 14:36:19 -0400507void 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 +0000508{
Jamie Madill88f18f42013-09-18 14:36:19 -0400509 if (Texture::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, mImageArray[level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000510 {
511 commitRect(level, xoffset, yoffset, width, height);
512 }
513}
514
515void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
516{
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000517 if (Texture::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000518 {
519 commitRect(level, xoffset, yoffset, width, height);
520 }
521}
522
523void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
524{
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +0000525 GLuint clientVersion = mRenderer->getCurrentClientVersion();
526 GLint sizedInternalFormat = IsSizedInternalFormat(format, clientVersion) ? format
527 : GetSizedInternalFormat(format, GL_UNSIGNED_BYTE, clientVersion);
528 redefineImage(level, sizedInternalFormat, width, height);
shannon.woods@transgaming.com8a406682013-02-28 23:15:26 +0000529
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000530 if (!mImageArray[level]->isRenderableFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000531 {
shannon.woods%transgaming.com@gtempaccount.come5dcce72013-04-13 03:44:33 +0000532 mImageArray[level]->copy(0, 0, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000533 mDirtyImages = true;
534 }
535 else
536 {
537 if (!mTexStorage || !mTexStorage->isRenderTarget())
538 {
539 convertToRenderTarget();
540 }
541
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000542 mImageArray[level]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000543
544 if (width != 0 && height != 0 && level < levelCount())
545 {
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +0000546 gl::Rectangle sourceRect;
547 sourceRect.x = x;
548 sourceRect.width = width;
549 sourceRect.y = y;
550 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000551
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +0000552 mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000553 }
554 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000555}
556
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +0000557void 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 +0000558{
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +0000559 if (xoffset + width > mImageArray[level]->getWidth() || yoffset + height > mImageArray[level]->getHeight() || zoffset != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000560 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +0000561 return gl::error(GL_INVALID_VALUE);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000562 }
563
Jamie Madill07edd442013-07-19 16:36:58 -0400564 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
565 // the current level we're copying to is defined (with appropriate format, width & height)
566 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
567
568 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000569 {
shannon.woods%transgaming.com@gtempaccount.come5dcce72013-04-13 03:44:33 +0000570 mImageArray[level]->copy(xoffset, yoffset, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000571 mDirtyImages = true;
572 }
573 else
574 {
575 if (!mTexStorage || !mTexStorage->isRenderTarget())
576 {
577 convertToRenderTarget();
578 }
579
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000580 if (level < levelCount())
581 {
Jamie Madill07edd442013-07-19 16:36:58 -0400582 updateTextureLevel(level);
583
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +0000584 GLuint clientVersion = mRenderer->getCurrentClientVersion();
585
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +0000586 gl::Rectangle sourceRect;
587 sourceRect.x = x;
588 sourceRect.width = width;
589 sourceRect.y = y;
590 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000591
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +0000592 mRenderer->copyImage(source, sourceRect,
Jamie Madilld3d2a342013-10-07 10:46:35 -0400593 gl::GetFormat(getBaseLevelInternalFormat(), clientVersion),
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +0000594 xoffset, yoffset, mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000595 }
596 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000597}
598
599void Texture2D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height)
600{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000601 delete mTexStorage;
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000602 mTexStorage = new rx::TextureStorageInterface2D(mRenderer, levels, internalformat, mUsage, false, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000603 mImmutable = true;
604
605 for (int level = 0; level < levels; level++)
606 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000607 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, width, height, 1, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000608 width = std::max(1, width >> 1);
609 height = std::max(1, height >> 1);
610 }
611
612 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
613 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000614 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000615 }
616
617 if (mTexStorage->isManaged())
618 {
619 int levels = levelCount();
620
621 for (int level = 0; level < levels; level++)
622 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000623 mImageArray[level]->setManagedSurface(mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000624 }
625 }
626}
627
628// Tests for 2D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85.
Jamie Madillf8989902013-07-19 16:36:58 -0400629bool Texture2D::isSamplerComplete(const SamplerState &samplerState) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000630{
Jamie Madilld3d2a342013-10-07 10:46:35 -0400631 GLsizei width = getBaseLevelWidth();
632 GLsizei height = getBaseLevelHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000633
634 if (width <= 0 || height <= 0)
635 {
636 return false;
637 }
638
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000639 if (!IsTextureFilteringSupported(getInternalFormat(0), mRenderer))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000640 {
Jamie Madillf8989902013-07-19 16:36:58 -0400641 if (samplerState.magFilter != GL_NEAREST ||
642 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000643 {
644 return false;
645 }
646 }
647
daniel@transgaming.comea32d482012-11-28 19:33:18 +0000648 bool npotSupport = mRenderer->getNonPower2TextureSupport();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000649
650 if (!npotSupport)
651 {
Jamie Madillf8989902013-07-19 16:36:58 -0400652 if ((samplerState.wrapS != GL_CLAMP_TO_EDGE && !isPow2(width)) ||
653 (samplerState.wrapT != GL_CLAMP_TO_EDGE && !isPow2(height)))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000654 {
655 return false;
656 }
657 }
658
Jamie Madillf8989902013-07-19 16:36:58 -0400659 if (IsMipmapFiltered(samplerState))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000660 {
661 if (!npotSupport)
662 {
663 if (!isPow2(width) || !isPow2(height))
664 {
665 return false;
666 }
667 }
668
669 if (!isMipmapComplete())
670 {
671 return false;
672 }
673 }
674
Geoff Langc82fc412013-07-10 14:43:42 -0400675 // OpenGLES 3.0.2 spec section 3.8.13 states that a texture is not mipmap complete if:
676 // The internalformat specified for the texture arrays is a sized internal depth or
677 // depth and stencil format (see table 3.13), the value of TEXTURE_COMPARE_-
678 // MODE is NONE, and either the magnification filter is not NEAREST or the mini-
679 // fication filter is neither NEAREST nor NEAREST_MIPMAP_NEAREST.
680 if (gl::GetDepthBits(getInternalFormat(0), mRenderer->getCurrentClientVersion()) > 0)
681 {
682 if (mSamplerState.compareMode == GL_NONE)
683 {
684 if ((mSamplerState.minFilter != GL_NEAREST && mSamplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST) ||
685 mSamplerState.magFilter != GL_NEAREST)
686 {
687 return false;
688 }
689 }
690 }
691
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000692 return true;
693}
694
695// Tests for 2D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
696bool Texture2D::isMipmapComplete() const
697{
Jamie Madilld3d2a342013-10-07 10:46:35 -0400698 GLsizei width = getBaseLevelWidth();
699 GLsizei height = getBaseLevelHeight();
Jamie Madill07edd442013-07-19 16:36:58 -0400700
701 int q = log2(std::max(width, height));
702
703 for (int level = 0; level <= q; level++)
704 {
705 if (!isLevelComplete(level))
706 {
707 return false;
708 }
709 }
710
711 return true;
712}
713
714bool Texture2D::isLevelComplete(int level) const
715{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000716 if (isImmutable())
717 {
718 return true;
719 }
720
Jamie Madilld3d2a342013-10-07 10:46:35 -0400721 GLsizei width = getBaseLevelWidth();
722 GLsizei height = getBaseLevelHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000723
724 if (width <= 0 || height <= 0)
725 {
726 return false;
727 }
728
Jamie Madill07edd442013-07-19 16:36:58 -0400729 // The base image level is complete if the width and height are positive
730 if (level == 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000731 {
Jamie Madill07edd442013-07-19 16:36:58 -0400732 return true;
733 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000734
Jamie Madill07edd442013-07-19 16:36:58 -0400735 ASSERT(level >= 1 && level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
736 rx::Image *image = mImageArray[level];
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000737
Jamie Madilld3d2a342013-10-07 10:46:35 -0400738 if (image->getInternalFormat() != getBaseLevelInternalFormat())
Jamie Madill07edd442013-07-19 16:36:58 -0400739 {
740 return false;
741 }
742
743 if (image->getWidth() != std::max(1, width >> level))
744 {
745 return false;
746 }
747
748 if (image->getHeight() != std::max(1, height >> level))
749 {
750 return false;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000751 }
752
753 return true;
754}
755
756bool Texture2D::isCompressed(GLint level) const
757{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000758 return IsFormatCompressed(getInternalFormat(level), mRenderer->getCurrentClientVersion());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000759}
760
761bool Texture2D::isDepth(GLint level) const
762{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000763 return GetDepthBits(getInternalFormat(level), mRenderer->getCurrentClientVersion()) > 0;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000764}
765
daniel@transgaming.comf032cb82012-10-31 19:51:52 +0000766// Constructs a native texture resource from the texture images
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000767void Texture2D::createTexture()
768{
Jamie Madilld3d2a342013-10-07 10:46:35 -0400769 GLsizei width = getBaseLevelWidth();
770 GLsizei height = getBaseLevelHeight();
daniel@transgaming.come6a09842012-09-17 21:28:55 +0000771
772 if (!(width > 0 && height > 0))
daniel@transgaming.comf032cb82012-10-31 19:51:52 +0000773 return; // do not attempt to create native textures for nonexistant data
daniel@transgaming.come6a09842012-09-17 21:28:55 +0000774
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000775 GLint levels = creationLevels(width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000776
777 delete mTexStorage;
Jamie Madilld3d2a342013-10-07 10:46:35 -0400778 mTexStorage = new rx::TextureStorageInterface2D(mRenderer, levels, getBaseLevelInternalFormat(), mUsage, false, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000779
780 if (mTexStorage->isManaged())
781 {
782 int levels = levelCount();
783
784 for (int level = 0; level < levels; level++)
785 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000786 mImageArray[level]->setManagedSurface(mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000787 }
788 }
789
790 mDirtyImages = true;
791}
792
793void Texture2D::updateTexture()
794{
Jamie Madilleb3665c2013-07-19 16:36:57 -0400795 int levels = (isMipmapComplete() ? levelCount() : 1);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000796
797 for (int level = 0; level < levels; level++)
798 {
Jamie Madill07edd442013-07-19 16:36:58 -0400799 updateTextureLevel(level);
800 }
801}
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000802
Jamie Madill07edd442013-07-19 16:36:58 -0400803void Texture2D::updateTextureLevel(int level)
804{
805 ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
806 rx::Image *image = mImageArray[level];
807
808 if (image->isDirty())
809 {
810 commitRect(level, 0, 0, mImageArray[level]->getWidth(), mImageArray[level]->getHeight());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000811 }
812}
813
814void Texture2D::convertToRenderTarget()
815{
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000816 rx::TextureStorageInterface2D *newTexStorage = NULL;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000817
Jamie Madilld3d2a342013-10-07 10:46:35 -0400818 GLsizei width = getBaseLevelWidth();
819 GLsizei height = getBaseLevelHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000820
Jamie Madilld3d2a342013-10-07 10:46:35 -0400821 if (width != 0 && height != 0)
822 {
823 GLint levels = mTexStorage != NULL ? mTexStorage->levelCount() : creationLevels(width, height);
824
825 newTexStorage = new rx::TextureStorageInterface2D(mRenderer, levels, getBaseLevelInternalFormat(), GL_FRAMEBUFFER_ATTACHMENT_ANGLE, true, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000826
827 if (mTexStorage != NULL)
828 {
daniel@transgaming.com1d80eee2012-11-28 19:33:31 +0000829 if (!mRenderer->copyToRenderTarget(newTexStorage, mTexStorage))
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +0000830 {
831 delete newTexStorage;
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +0000832 return gl::error(GL_OUT_OF_MEMORY);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000833 }
834 }
835 }
836
837 delete mTexStorage;
838 mTexStorage = newTexStorage;
839
840 mDirtyImages = true;
841}
842
843void Texture2D::generateMipmaps()
844{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000845 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Jamie Madilld3d2a342013-10-07 10:46:35 -0400846 unsigned int q = log2(std::max(getBaseLevelWidth(), getBaseLevelHeight()));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000847 for (unsigned int i = 1; i <= q; i++)
848 {
Jamie Madilld3d2a342013-10-07 10:46:35 -0400849 redefineImage(i, getBaseLevelInternalFormat(),
850 std::max(getBaseLevelWidth() >> i, 1),
851 std::max(getBaseLevelHeight() >> i, 1));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000852 }
853
854 if (mTexStorage && mTexStorage->isRenderTarget())
855 {
856 for (unsigned int i = 1; i <= q; i++)
857 {
daniel@transgaming.com0ad830b2012-10-31 19:52:12 +0000858 mTexStorage->generateMipmap(i);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000859
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000860 mImageArray[i]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000861 }
862 }
863 else
864 {
865 for (unsigned int i = 1; i <= q; i++)
866 {
daniel@transgaming.com4ba24062012-12-20 20:54:24 +0000867 mRenderer->generateMipmap(mImageArray[i], mImageArray[i - 1]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000868 }
869 }
870}
871
Jamie Madilld3d2a342013-10-07 10:46:35 -0400872const rx::Image *Texture2D::getBaseLevelImage() const
873{
874 return mImageArray[0];
875}
876
Geoff Lang8040f572013-07-25 16:49:54 -0400877Renderbuffer *Texture2D::getRenderbuffer(GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000878{
Geoff Lang8040f572013-07-25 16:49:54 -0400879 Renderbuffer *renderBuffer = mRenderbufferProxies.get(level, 0);
880 if (!renderBuffer)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000881 {
Geoff Lang8040f572013-07-25 16:49:54 -0400882 renderBuffer = new Renderbuffer(mRenderer, id(), new RenderbufferTexture2D(this, level));
883 mRenderbufferProxies.add(level, 0, renderBuffer);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000884 }
885
Geoff Lang8040f572013-07-25 16:49:54 -0400886 return renderBuffer;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000887}
888
Geoff Lang8040f572013-07-25 16:49:54 -0400889unsigned int Texture2D::getRenderTargetSerial(GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000890{
Geoff Lang8040f572013-07-25 16:49:54 -0400891 if (!mTexStorage || !mTexStorage->isRenderTarget())
892 {
893 convertToRenderTarget();
894 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000895
Geoff Lang8040f572013-07-25 16:49:54 -0400896 return mTexStorage ? mTexStorage->getRenderTargetSerial(level) : 0;
897}
898
899rx::RenderTarget *Texture2D::getRenderTarget(GLint level)
900{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000901 // ensure the underlying texture is created
902 if (getStorage(true) == NULL)
903 {
904 return NULL;
905 }
906
907 updateTexture();
Geoff Lang8040f572013-07-25 16:49:54 -0400908
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000909 // ensure this is NOT a depth texture
Geoff Lang8040f572013-07-25 16:49:54 -0400910 if (isDepth(level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000911 {
912 return NULL;
913 }
daniel@transgaming.com34da3972012-12-20 21:10:29 +0000914
Geoff Lang8040f572013-07-25 16:49:54 -0400915 return mTexStorage->getRenderTarget(level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000916}
917
Geoff Lang8040f572013-07-25 16:49:54 -0400918rx::RenderTarget *Texture2D::getDepthSencil(GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000919{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000920 // ensure the underlying texture is created
921 if (getStorage(true) == NULL)
922 {
923 return NULL;
924 }
925
926 updateTexture();
927
928 // ensure this is actually a depth texture
Geoff Lang8040f572013-07-25 16:49:54 -0400929 if (!isDepth(level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000930 {
931 return NULL;
932 }
Geoff Lang8040f572013-07-25 16:49:54 -0400933
934 return mTexStorage->getRenderTarget(level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000935}
936
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +0000937int Texture2D::levelCount()
938{
shannon.woods@transgaming.com5016f8e2013-02-28 23:20:57 +0000939 return mTexStorage ? mTexStorage->levelCount() : 0;
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +0000940}
941
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000942rx::TextureStorageInterface *Texture2D::getStorage(bool renderTarget)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000943{
944 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
945 {
946 if (renderTarget)
947 {
948 convertToRenderTarget();
949 }
950 else
951 {
952 createTexture();
953 }
954 }
955
956 return mTexStorage;
957}
958
Geoff Lang4907f2c2013-07-25 12:53:57 -0400959TextureCubeMap::TextureCubeMap(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_CUBE_MAP)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000960{
961 mTexStorage = NULL;
962 for (int i = 0; i < 6; i++)
963 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000964 for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
965 {
daniel@transgaming.com244e1832012-12-20 20:52:35 +0000966 mImageArray[i][j] = renderer->createImage();
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000967 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000968 }
969}
970
971TextureCubeMap::~TextureCubeMap()
972{
973 for (int i = 0; i < 6; i++)
974 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000975 for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
976 {
977 delete mImageArray[i][j];
978 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000979 }
980
981 delete mTexStorage;
982 mTexStorage = NULL;
983}
984
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000985GLsizei TextureCubeMap::getWidth(GLenum target, GLint level) const
986{
987 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000988 return mImageArray[faceIndex(target)][level]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000989 else
990 return 0;
991}
992
993GLsizei TextureCubeMap::getHeight(GLenum target, GLint level) const
994{
995 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000996 return mImageArray[faceIndex(target)][level]->getHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000997 else
998 return 0;
999}
1000
1001GLenum TextureCubeMap::getInternalFormat(GLenum target, GLint level) const
1002{
1003 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001004 return mImageArray[faceIndex(target)][level]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001005 else
1006 return GL_NONE;
1007}
1008
daniel@transgaming.com20d36662012-10-31 19:51:43 +00001009GLenum TextureCubeMap::getActualFormat(GLenum target, GLint level) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001010{
1011 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001012 return mImageArray[faceIndex(target)][level]->getActualFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001013 else
1014 return D3DFMT_UNKNOWN;
1015}
1016
Jamie Madill88f18f42013-09-18 14:36:19 -04001017void TextureCubeMap::setImagePosX(GLint level, GLsizei width, GLsizei height, GLint internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001018{
Jamie Madill88f18f42013-09-18 14:36:19 -04001019 setImage(0, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001020}
1021
Jamie Madill88f18f42013-09-18 14:36:19 -04001022void TextureCubeMap::setImageNegX(GLint level, GLsizei width, GLsizei height, GLint internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001023{
Jamie Madill88f18f42013-09-18 14:36:19 -04001024 setImage(1, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001025}
1026
Jamie Madill88f18f42013-09-18 14:36:19 -04001027void TextureCubeMap::setImagePosY(GLint level, GLsizei width, GLsizei height, GLint internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001028{
Jamie Madill88f18f42013-09-18 14:36:19 -04001029 setImage(2, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001030}
1031
Jamie Madill88f18f42013-09-18 14:36:19 -04001032void TextureCubeMap::setImageNegY(GLint level, GLsizei width, GLsizei height, GLint internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001033{
Jamie Madill88f18f42013-09-18 14:36:19 -04001034 setImage(3, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001035}
1036
Jamie Madill88f18f42013-09-18 14:36:19 -04001037void TextureCubeMap::setImagePosZ(GLint level, GLsizei width, GLsizei height, GLint internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001038{
Jamie Madill88f18f42013-09-18 14:36:19 -04001039 setImage(4, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001040}
1041
Jamie Madill88f18f42013-09-18 14:36:19 -04001042void TextureCubeMap::setImageNegZ(GLint level, GLsizei width, GLsizei height, GLint internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001043{
Jamie Madill88f18f42013-09-18 14:36:19 -04001044 setImage(5, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001045}
1046
1047void TextureCubeMap::setCompressedImage(GLenum face, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
1048{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001049 // 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 +00001050 redefineImage(faceIndex(face), level, format, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001051
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001052 Texture::setCompressedImage(imageSize, pixels, mImageArray[faceIndex(face)][level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001053}
1054
1055void TextureCubeMap::commitRect(int face, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1056{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001057 if (level < levelCount())
1058 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001059 rx::Image *image = mImageArray[face][level];
daniel@transgaming.com0f195ad2012-10-31 19:51:59 +00001060 if (image->updateSurface(mTexStorage, face, level, xoffset, yoffset, width, height))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001061 image->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001062 }
1063}
1064
Jamie Madill88f18f42013-09-18 14:36:19 -04001065void 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 +00001066{
Jamie Madill88f18f42013-09-18 14:36:19 -04001067 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 +00001068 {
1069 commitRect(faceIndex(target), level, xoffset, yoffset, width, height);
1070 }
1071}
1072
1073void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1074{
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +00001075 if (Texture::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[faceIndex(target)][level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001076 {
1077 commitRect(faceIndex(target), level, xoffset, yoffset, width, height);
1078 }
1079}
1080
1081// Tests for cube map sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 86.
Jamie Madillf8989902013-07-19 16:36:58 -04001082bool TextureCubeMap::isSamplerComplete(const SamplerState &samplerState) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001083{
Jamie Madilld3d2a342013-10-07 10:46:35 -04001084 int size = getBaseLevelWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001085
Jamie Madillf8989902013-07-19 16:36:58 -04001086 bool mipmapping = IsMipmapFiltered(samplerState);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001087
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001088 if (!IsTextureFilteringSupported(getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0), mRenderer))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001089 {
Jamie Madillf8989902013-07-19 16:36:58 -04001090 if (samplerState.magFilter != GL_NEAREST ||
1091 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001092 {
1093 return false;
1094 }
1095 }
1096
daniel@transgaming.comea32d482012-11-28 19:33:18 +00001097 if (!isPow2(size) && !mRenderer->getNonPower2TextureSupport())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001098 {
Jamie Madillf8989902013-07-19 16:36:58 -04001099 if (samplerState.wrapS != GL_CLAMP_TO_EDGE || samplerState.wrapT != GL_CLAMP_TO_EDGE || mipmapping)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001100 {
1101 return false;
1102 }
1103 }
1104
1105 if (!mipmapping)
1106 {
1107 if (!isCubeComplete())
1108 {
1109 return false;
1110 }
1111 }
1112 else
1113 {
1114 if (!isMipmapCubeComplete()) // Also tests for isCubeComplete()
1115 {
1116 return false;
1117 }
1118 }
1119
1120 return true;
1121}
1122
1123// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1124bool TextureCubeMap::isCubeComplete() const
1125{
Jamie Madillc1f8b162013-10-07 10:46:38 -04001126 int baseWidth = getBaseLevelWidth();
1127 int baseHeight = getBaseLevelHeight();
1128 GLenum baseFormat = getBaseLevelInternalFormat();
1129
1130 if (baseWidth <= 0 || baseWidth != baseHeight)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001131 {
1132 return false;
1133 }
1134
1135 for (unsigned int face = 1; face < 6; face++)
1136 {
Jamie Madillc1f8b162013-10-07 10:46:38 -04001137 const rx::Image &faceBaseImage = *mImageArray[face][0];
1138
1139 if (faceBaseImage.getWidth() != baseWidth ||
1140 faceBaseImage.getHeight() != baseHeight ||
1141 faceBaseImage.getInternalFormat() != baseFormat )
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001142 {
1143 return false;
1144 }
1145 }
1146
1147 return true;
1148}
1149
1150bool TextureCubeMap::isMipmapCubeComplete() const
1151{
1152 if (isImmutable())
1153 {
1154 return true;
1155 }
1156
1157 if (!isCubeComplete())
1158 {
1159 return false;
1160 }
1161
Jamie Madilld3d2a342013-10-07 10:46:35 -04001162 GLsizei size = getBaseLevelWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001163 int q = log2(size);
1164
1165 for (int face = 0; face < 6; face++)
1166 {
1167 for (int level = 1; level <= q; level++)
1168 {
Jamie Madill07edd442013-07-19 16:36:58 -04001169 if (!isFaceLevelComplete(face, level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001170 {
1171 return false;
1172 }
1173 }
1174 }
1175
1176 return true;
1177}
1178
Jamie Madill07edd442013-07-19 16:36:58 -04001179bool TextureCubeMap::isFaceLevelComplete(int face, int level) const
1180{
1181 ASSERT(level >= 0 && face < 6 && level < (int)ArraySize(mImageArray[face]) && mImageArray[face][level] != NULL);
1182
1183 if (isImmutable())
1184 {
1185 return true;
1186 }
1187
Jamie Madilld3d2a342013-10-07 10:46:35 -04001188 int baseSize = getBaseLevelWidth();
Jamie Madill07edd442013-07-19 16:36:58 -04001189
Jamie Madilld3d2a342013-10-07 10:46:35 -04001190 if (baseSize <= 0)
Jamie Madill07edd442013-07-19 16:36:58 -04001191 {
1192 return false;
1193 }
1194
Jamie Madilld3d2a342013-10-07 10:46:35 -04001195 // "isCubeComplete" checks for base level completeness and we must call that
1196 // to determine if any face at level 0 is complete. We omit that check here
1197 // to avoid re-checking cube-completeness for every face at level 0.
Jamie Madill07edd442013-07-19 16:36:58 -04001198 if (level == 0)
1199 {
1200 return true;
1201 }
1202
Jamie Madilld3d2a342013-10-07 10:46:35 -04001203 // Check that non-zero levels are consistent with the base level.
1204 const rx::Image *faceLevelImage = mImageArray[face][level];
Jamie Madill07edd442013-07-19 16:36:58 -04001205
Jamie Madilld3d2a342013-10-07 10:46:35 -04001206 if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat())
Jamie Madill07edd442013-07-19 16:36:58 -04001207 {
1208 return false;
1209 }
1210
Jamie Madilld3d2a342013-10-07 10:46:35 -04001211 if (faceLevelImage->getWidth() != std::max(1, baseSize >> level))
Jamie Madill07edd442013-07-19 16:36:58 -04001212 {
1213 return false;
1214 }
1215
1216 return true;
1217}
1218
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001219bool TextureCubeMap::isCompressed(GLenum target, GLint level) const
1220{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001221 return IsFormatCompressed(getInternalFormat(target, level), mRenderer->getCurrentClientVersion());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001222}
1223
Geoff Lang8040f572013-07-25 16:49:54 -04001224bool TextureCubeMap::isDepth(GLenum target, GLint level) const
1225{
1226 return GetDepthBits(getInternalFormat(target, level), mRenderer->getCurrentClientVersion()) > 0;
1227}
1228
daniel@transgaming.comf032cb82012-10-31 19:51:52 +00001229// Constructs a native texture resource from the texture images, or returns an existing one
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001230void TextureCubeMap::createTexture()
1231{
Jamie Madilld3d2a342013-10-07 10:46:35 -04001232 GLsizei size = getBaseLevelWidth();
daniel@transgaming.come6a09842012-09-17 21:28:55 +00001233
1234 if (!(size > 0))
daniel@transgaming.comf032cb82012-10-31 19:51:52 +00001235 return; // do not attempt to create native textures for nonexistant data
daniel@transgaming.come6a09842012-09-17 21:28:55 +00001236
sminns@adobe.comce1189b2012-09-18 20:06:35 +00001237 GLint levels = creationLevels(size);
Jamie Madilld3d2a342013-10-07 10:46:35 -04001238 GLenum internalformat = getBaseLevelInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001239
1240 delete mTexStorage;
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001241 mTexStorage = new rx::TextureStorageInterfaceCube(mRenderer, levels, internalformat, mUsage, false, size);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001242
1243 if (mTexStorage->isManaged())
1244 {
1245 int levels = levelCount();
1246
1247 for (int face = 0; face < 6; face++)
1248 {
1249 for (int level = 0; level < levels; level++)
1250 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001251 mImageArray[face][level]->setManagedSurface(mTexStorage, face, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001252 }
1253 }
1254 }
1255
1256 mDirtyImages = true;
1257}
1258
1259void TextureCubeMap::updateTexture()
1260{
Jamie Madilleb3665c2013-07-19 16:36:57 -04001261 int levels = (isMipmapCubeComplete() ? levelCount() : 1);
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +00001262
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001263 for (int face = 0; face < 6; face++)
1264 {
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001265 for (int level = 0; level < levels; level++)
1266 {
Jamie Madill07edd442013-07-19 16:36:58 -04001267 updateTextureFaceLevel(face, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001268 }
1269 }
1270}
1271
Jamie Madill07edd442013-07-19 16:36:58 -04001272void TextureCubeMap::updateTextureFaceLevel(int face, int level)
1273{
1274 ASSERT(level >= 0 && face < 6 && level < (int)ArraySize(mImageArray[face]) && mImageArray[face][level] != NULL);
1275 rx::Image *image = mImageArray[face][level];
1276
1277 if (image->isDirty())
1278 {
1279 commitRect(face, level, 0, 0, image->getWidth(), image->getHeight());
1280 }
1281}
1282
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001283void TextureCubeMap::convertToRenderTarget()
1284{
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001285 rx::TextureStorageInterfaceCube *newTexStorage = NULL;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001286
Jamie Madilld3d2a342013-10-07 10:46:35 -04001287 if (getBaseLevelWidth() != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001288 {
Jamie Madilld3d2a342013-10-07 10:46:35 -04001289 GLsizei size = getBaseLevelWidth();
shannon.woods@transgaming.com6bb48862013-02-28 23:09:34 +00001290 GLint levels = mTexStorage != NULL ? mTexStorage->levelCount() : creationLevels(size);
Jamie Madilld3d2a342013-10-07 10:46:35 -04001291 GLenum internalformat = getBaseLevelInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001292
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001293 newTexStorage = new rx::TextureStorageInterfaceCube(mRenderer, levels, internalformat, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, true, size);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001294
1295 if (mTexStorage != NULL)
1296 {
daniel@transgaming.com1d80eee2012-11-28 19:33:31 +00001297 if (!mRenderer->copyToRenderTarget(newTexStorage, mTexStorage))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001298 {
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +00001299 delete newTexStorage;
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +00001300 return gl::error(GL_OUT_OF_MEMORY);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001301 }
1302 }
1303 }
1304
1305 delete mTexStorage;
1306 mTexStorage = newTexStorage;
1307
1308 mDirtyImages = true;
1309}
1310
Jamie Madill88f18f42013-09-18 14:36:19 -04001311void TextureCubeMap::setImage(int faceIndex, GLint level, GLsizei width, GLsizei height, GLint internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001312{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001313 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1314 GLint sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
1315 : GetSizedInternalFormat(format, type, clientVersion);
1316
1317 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001318
Jamie Madill88f18f42013-09-18 14:36:19 -04001319 Texture::setImage(unpack, type, pixels, mImageArray[faceIndex][level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001320}
1321
1322unsigned int TextureCubeMap::faceIndex(GLenum face)
1323{
1324 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
1325 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
1326 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
1327 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
1328 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
1329
1330 return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
1331}
1332
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001333void TextureCubeMap::redefineImage(int face, GLint level, GLint internalformat, GLsizei width, GLsizei height)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001334{
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001335 // If there currently is a corresponding storage texture image, it has these parameters
Jamie Madilld3d2a342013-10-07 10:46:35 -04001336 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1337 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1338 const int storageFormat = getBaseLevelInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001339
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001340 mImageArray[face][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, width, height, 1, false);
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001341
1342 if (mTexStorage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001343 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001344 const int storageLevels = mTexStorage->levelCount();
1345
1346 if ((level >= storageLevels && storageLevels != 0) ||
1347 width != storageWidth ||
1348 height != storageHeight ||
1349 internalformat != storageFormat) // Discard mismatched storage
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001350 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001351 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001352 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001353 for (int f = 0; f < 6; f++)
1354 {
1355 mImageArray[f][i]->markDirty();
1356 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001357 }
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001358
1359 delete mTexStorage;
1360 mTexStorage = NULL;
1361
1362 mDirtyImages = true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001363 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001364 }
1365}
1366
1367void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1368{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001369 unsigned int faceindex = faceIndex(target);
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001370 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1371 GLint sizedInternalFormat = IsSizedInternalFormat(format, clientVersion) ? format
1372 : GetSizedInternalFormat(format, GL_UNSIGNED_BYTE, clientVersion);
1373 redefineImage(faceindex, level, sizedInternalFormat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001374
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001375 if (!mImageArray[faceindex][level]->isRenderableFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001376 {
shannon.woods%transgaming.com@gtempaccount.come5dcce72013-04-13 03:44:33 +00001377 mImageArray[faceindex][level]->copy(0, 0, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001378 mDirtyImages = true;
1379 }
1380 else
1381 {
1382 if (!mTexStorage || !mTexStorage->isRenderTarget())
1383 {
1384 convertToRenderTarget();
1385 }
1386
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001387 mImageArray[faceindex][level]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001388
1389 ASSERT(width == height);
1390
1391 if (width > 0 && level < levelCount())
1392 {
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +00001393 gl::Rectangle sourceRect;
1394 sourceRect.x = x;
1395 sourceRect.width = width;
1396 sourceRect.y = y;
1397 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001398
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +00001399 mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001400 }
1401 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001402}
1403
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001404void 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 +00001405{
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001406 GLsizei size = mImageArray[faceIndex(target)][level]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001407
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001408 if (xoffset + width > size || yoffset + height > size || zoffset != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001409 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +00001410 return gl::error(GL_INVALID_VALUE);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001411 }
1412
Jamie Madill07edd442013-07-19 16:36:58 -04001413 unsigned int face = faceIndex(target);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001414
Jamie Madilld3d2a342013-10-07 10:46:35 -04001415 // We can only make our texture storage to a render target if the level we're copying *to* is complete
1416 // and the base level is cube-complete. The base level must be cube complete (common case) because we cannot
1417 // rely on the "getBaseLevel*" methods reliably otherwise.
1418 bool canCreateRenderTarget = isFaceLevelComplete(face, level) && isCubeComplete();
Jamie Madill07edd442013-07-19 16:36:58 -04001419
1420 if (!mImageArray[face][level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001421 {
Jamie Madill07edd442013-07-19 16:36:58 -04001422 mImageArray[face][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 {
1427 if (!mTexStorage || !mTexStorage->isRenderTarget())
1428 {
1429 convertToRenderTarget();
1430 }
1431
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001432 if (level < levelCount())
1433 {
Jamie Madill07edd442013-07-19 16:36:58 -04001434 updateTextureFaceLevel(face, level);
1435
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001436 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1437
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +00001438 gl::Rectangle sourceRect;
1439 sourceRect.x = x;
1440 sourceRect.width = width;
1441 sourceRect.y = y;
1442 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001443
Jamie Madilld3d2a342013-10-07 10:46:35 -04001444 mRenderer->copyImage(source, sourceRect, gl::GetFormat(getBaseLevelInternalFormat(), clientVersion),
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +00001445 xoffset, yoffset, mTexStorage, target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001446 }
1447 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001448}
1449
1450void TextureCubeMap::storage(GLsizei levels, GLenum internalformat, GLsizei size)
1451{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001452 delete mTexStorage;
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001453 mTexStorage = new rx::TextureStorageInterfaceCube(mRenderer, levels, internalformat, mUsage, false, size);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001454 mImmutable = true;
1455
1456 for (int level = 0; level < levels; level++)
1457 {
Geoff Langd3110192013-09-24 11:52:47 -04001458 GLsizei mipSize = std::max(1, size >> level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001459 for (int face = 0; face < 6; face++)
1460 {
Geoff Langd3110192013-09-24 11:52:47 -04001461 mImageArray[face][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, mipSize, mipSize, 1, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001462 }
1463 }
1464
1465 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1466 {
1467 for (int face = 0; face < 6; face++)
1468 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001469 mImageArray[face][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, GL_NONE, 0, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001470 }
1471 }
1472
1473 if (mTexStorage->isManaged())
1474 {
1475 int levels = levelCount();
1476
1477 for (int face = 0; face < 6; face++)
1478 {
1479 for (int level = 0; level < levels; level++)
1480 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001481 mImageArray[face][level]->setManagedSurface(mTexStorage, face, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001482 }
1483 }
1484 }
1485}
1486
1487void TextureCubeMap::generateMipmaps()
1488{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001489 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Jamie Madilld3d2a342013-10-07 10:46:35 -04001490 unsigned int q = log2(getBaseLevelWidth());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001491 for (unsigned int f = 0; f < 6; f++)
1492 {
1493 for (unsigned int i = 1; i <= q; i++)
1494 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001495 redefineImage(f, i, mImageArray[f][0]->getInternalFormat(),
shannon.woods@transgaming.com8a406682013-02-28 23:15:26 +00001496 std::max(mImageArray[f][0]->getWidth() >> i, 1),
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001497 std::max(mImageArray[f][0]->getWidth() >> i, 1));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001498 }
1499 }
1500
1501 if (mTexStorage && mTexStorage->isRenderTarget())
1502 {
1503 for (unsigned int f = 0; f < 6; f++)
1504 {
1505 for (unsigned int i = 1; i <= q; i++)
1506 {
daniel@transgaming.com0ad830b2012-10-31 19:52:12 +00001507 mTexStorage->generateMipmap(f, i);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001508
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001509 mImageArray[f][i]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001510 }
1511 }
1512 }
1513 else
1514 {
1515 for (unsigned int f = 0; f < 6; f++)
1516 {
1517 for (unsigned int i = 1; i <= q; i++)
1518 {
daniel@transgaming.com4ba24062012-12-20 20:54:24 +00001519 mRenderer->generateMipmap(mImageArray[f][i], mImageArray[f][i - 1]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001520 }
1521 }
1522 }
1523}
1524
Jamie Madilld3d2a342013-10-07 10:46:35 -04001525const rx::Image *TextureCubeMap::getBaseLevelImage() const
1526{
1527 // Note: if we are not cube-complete, there is no single base level image that can describe all
1528 // cube faces, so this method is only well-defined for a cube-complete base level.
1529 return mImageArray[0][0];
1530}
1531
Geoff Lang8040f572013-07-25 16:49:54 -04001532Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target, GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001533{
1534 if (!IsCubemapTextureTarget(target))
1535 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +00001536 return gl::error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001537 }
1538
1539 unsigned int face = faceIndex(target);
1540
Geoff Lang8040f572013-07-25 16:49:54 -04001541 Renderbuffer *renderBuffer = mRenderbufferProxies.get(level, face);
1542 if (!renderBuffer)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001543 {
Geoff Lang8040f572013-07-25 16:49:54 -04001544 renderBuffer = new Renderbuffer(mRenderer, id(), new RenderbufferTextureCubeMap(this, target, level));
1545 mRenderbufferProxies.add(level, face, renderBuffer);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001546 }
1547
Geoff Lang8040f572013-07-25 16:49:54 -04001548 return renderBuffer;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001549}
1550
Geoff Lang8040f572013-07-25 16:49:54 -04001551unsigned int TextureCubeMap::getRenderTargetSerial(GLenum faceTarget, GLint level)
1552{
1553 if (!mTexStorage || !mTexStorage->isRenderTarget())
1554 {
1555 convertToRenderTarget();
1556 }
1557
1558 return mTexStorage ? mTexStorage->getRenderTargetSerial(faceTarget, level) : 0;
1559}
1560
1561rx::RenderTarget *TextureCubeMap::getRenderTarget(GLenum target, GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001562{
1563 ASSERT(IsCubemapTextureTarget(target));
1564
1565 // ensure the underlying texture is created
1566 if (getStorage(true) == NULL)
1567 {
1568 return NULL;
1569 }
1570
1571 updateTexture();
Geoff Lang8040f572013-07-25 16:49:54 -04001572
1573 // ensure this is NOT a depth texture
1574 if (isDepth(target, level))
1575 {
1576 return NULL;
1577 }
1578
1579 return mTexStorage->getRenderTarget(target, level);
1580}
1581
1582rx::RenderTarget *TextureCubeMap::getDepthStencil(GLenum target, GLint level)
1583{
1584 ASSERT(IsCubemapTextureTarget(target));
1585
1586 // ensure the underlying texture is created
1587 if (getStorage(true) == NULL)
1588 {
1589 return NULL;
1590 }
1591
1592 updateTexture();
1593
1594 // ensure this is a depth texture
1595 if (!isDepth(target, level))
1596 {
1597 return NULL;
1598 }
1599
1600 return mTexStorage->getRenderTarget(target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001601}
1602
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +00001603int TextureCubeMap::levelCount()
1604{
1605 return mTexStorage ? mTexStorage->levelCount() - getLodOffset() : 0;
1606}
1607
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001608rx::TextureStorageInterface *TextureCubeMap::getStorage(bool renderTarget)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001609{
1610 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
1611 {
1612 if (renderTarget)
1613 {
1614 convertToRenderTarget();
1615 }
1616 else
1617 {
1618 createTexture();
1619 }
1620 }
1621
1622 return mTexStorage;
1623}
1624
Geoff Lang4907f2c2013-07-25 12:53:57 -04001625Texture3D::Texture3D(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_3D)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001626{
1627 mTexStorage = NULL;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001628
1629 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1630 {
1631 mImageArray[i] = renderer->createImage();
1632 }
1633}
1634
1635Texture3D::~Texture3D()
1636{
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001637 delete mTexStorage;
1638 mTexStorage = NULL;
1639
1640 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1641 {
1642 delete mImageArray[i];
1643 }
1644}
1645
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001646GLsizei Texture3D::getWidth(GLint level) const
1647{
1648 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getWidth() : 0;
1649}
1650
1651GLsizei Texture3D::getHeight(GLint level) const
1652{
1653 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getHeight() : 0;
1654}
1655
1656GLsizei Texture3D::getDepth(GLint level) const
1657{
1658 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getDepth() : 0;
1659}
1660
1661GLenum Texture3D::getInternalFormat(GLint level) const
1662{
1663 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getInternalFormat() : GL_NONE;
1664}
1665
1666GLenum Texture3D::getActualFormat(GLint level) const
1667{
1668 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getActualFormat() : D3DFMT_UNKNOWN;
1669}
1670
1671bool Texture3D::isCompressed(GLint level) const
1672{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001673 return IsFormatCompressed(getInternalFormat(level), mRenderer->getCurrentClientVersion());
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001674}
1675
1676bool Texture3D::isDepth(GLint level) const
1677{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001678 return GetDepthBits(getInternalFormat(level), mRenderer->getCurrentClientVersion()) > 0;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001679}
1680
Jamie Madill88f18f42013-09-18 14:36:19 -04001681void Texture3D::setImage(GLint level, GLsizei width, GLsizei height, GLsizei depth, GLint internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001682{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001683 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1684 GLint sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
1685 : GetSizedInternalFormat(format, type, clientVersion);
1686 redefineImage(level, sizedInternalFormat, width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001687
Jamie Madill88f18f42013-09-18 14:36:19 -04001688 Texture::setImage(unpack, type, pixels, mImageArray[level]);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001689}
1690
1691void Texture3D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
1692{
1693 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1694 redefineImage(level, format, width, height, depth);
1695
1696 Texture::setCompressedImage(imageSize, pixels, mImageArray[level]);
1697}
1698
Jamie Madill88f18f42013-09-18 14:36:19 -04001699void 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 +00001700{
Jamie Madill88f18f42013-09-18 14:36:19 -04001701 if (Texture::subImage(xoffset, yoffset, zoffset, width, height, depth, format, type, unpack, pixels, mImageArray[level]))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001702 {
1703 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1704 }
1705}
1706
1707void Texture3D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
1708{
1709 if (Texture::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth, format, imageSize, pixels, mImageArray[level]))
1710 {
1711 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1712 }
1713}
1714
1715void Texture3D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
1716{
1717 delete mTexStorage;
1718 mTexStorage = new rx::TextureStorageInterface3D(mRenderer, levels, internalformat, mUsage, width, height, depth);
1719 mImmutable = true;
1720
1721 for (int level = 0; level < levels; level++)
1722 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001723 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, true);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001724 width = std::max(1, width >> 1);
1725 height = std::max(1, height >> 1);
1726 depth = std::max(1, depth >> 1);
1727 }
1728
1729 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1730 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001731 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, GL_NONE, 0, 0, 0, true);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001732 }
1733
1734 if (mTexStorage->isManaged())
1735 {
1736 int levels = levelCount();
1737
1738 for (int level = 0; level < levels; level++)
1739 {
1740 mImageArray[level]->setManagedSurface(mTexStorage, level);
1741 }
1742 }
1743}
1744
1745
1746void Texture3D::generateMipmaps()
1747{
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001748 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Jamie Madilld3d2a342013-10-07 10:46:35 -04001749 unsigned int q = log2(std::max(getBaseLevelWidth(), getBaseLevelHeight()));
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001750 for (unsigned int i = 1; i <= q; i++)
1751 {
Jamie Madilld3d2a342013-10-07 10:46:35 -04001752 redefineImage(i, getBaseLevelInternalFormat(),
1753 std::max(getBaseLevelWidth() >> i, 1),
1754 std::max(getBaseLevelHeight() >> i, 1),
1755 std::max(getBaseLevelDepth() >> i, 1));
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001756 }
1757
1758 if (mTexStorage && mTexStorage->isRenderTarget())
1759 {
1760 for (unsigned int i = 1; i <= q; i++)
1761 {
1762 mTexStorage->generateMipmap(i);
1763
1764 mImageArray[i]->markClean();
1765 }
1766 }
1767 else
1768 {
1769 for (unsigned int i = 1; i <= q; i++)
1770 {
1771 mRenderer->generateMipmap(mImageArray[i], mImageArray[i - 1]);
1772 }
1773 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001774}
1775
Jamie Madilld3d2a342013-10-07 10:46:35 -04001776const rx::Image *Texture3D::getBaseLevelImage() const
1777{
1778 return mImageArray[0];
1779}
1780
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001781void Texture3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1782{
1783 if (xoffset + width > mImageArray[level]->getWidth() || yoffset + height > mImageArray[level]->getHeight() || zoffset >= mImageArray[level]->getDepth())
1784 {
1785 return gl::error(GL_INVALID_VALUE);
1786 }
1787
Jamie Madill07edd442013-07-19 16:36:58 -04001788 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
1789 // the current level we're copying to is defined (with appropriate format, width & height)
1790 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
1791
1792 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001793 {
1794 mImageArray[level]->copy(xoffset, yoffset, zoffset, x, y, width, height, source);
1795 mDirtyImages = true;
1796 }
1797 else
1798 {
1799 if (!mTexStorage || !mTexStorage->isRenderTarget())
1800 {
1801 convertToRenderTarget();
1802 }
1803
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001804 if (level < levelCount())
1805 {
Jamie Madill07edd442013-07-19 16:36:58 -04001806 updateTextureLevel(level);
1807
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001808 gl::Rectangle sourceRect;
1809 sourceRect.x = x;
1810 sourceRect.width = width;
1811 sourceRect.y = y;
1812 sourceRect.height = height;
1813
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001814 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1815
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001816 mRenderer->copyImage(source, sourceRect,
Jamie Madilld3d2a342013-10-07 10:46:35 -04001817 gl::GetFormat(getBaseLevelInternalFormat(), clientVersion),
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001818 xoffset, yoffset, zoffset, mTexStorage, level);
1819 }
1820 }
1821}
1822
Jamie Madillf8989902013-07-19 16:36:58 -04001823bool Texture3D::isSamplerComplete(const SamplerState &samplerState) const
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001824{
Jamie Madilld3d2a342013-10-07 10:46:35 -04001825 GLsizei width = getBaseLevelWidth();
1826 GLsizei height = getBaseLevelHeight();
1827 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001828
1829 if (width <= 0 || height <= 0 || depth <= 0)
1830 {
1831 return false;
1832 }
1833
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001834 if (!IsTextureFilteringSupported(getInternalFormat(0), mRenderer))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001835 {
Jamie Madillf8989902013-07-19 16:36:58 -04001836 if (samplerState.magFilter != GL_NEAREST ||
1837 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001838 {
1839 return false;
1840 }
1841 }
1842
Jamie Madillf8989902013-07-19 16:36:58 -04001843 if (IsMipmapFiltered(samplerState) && !isMipmapComplete())
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001844 {
1845 return false;
1846 }
1847
1848 return true;
1849}
1850
1851bool Texture3D::isMipmapComplete() const
1852{
Jamie Madilld3d2a342013-10-07 10:46:35 -04001853 GLsizei width = getBaseLevelWidth();
1854 GLsizei height = getBaseLevelHeight();
1855 GLsizei depth = getBaseLevelDepth();
Jamie Madill07edd442013-07-19 16:36:58 -04001856
1857 int q = log2(std::max(std::max(width, height), depth));
1858
1859 for (int level = 0; level <= q; level++)
1860 {
1861 if (!isLevelComplete(level))
1862 {
1863 return false;
1864 }
1865 }
1866
1867 return true;
1868}
1869
1870bool Texture3D::isLevelComplete(int level) const
1871{
1872 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1873
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001874 if (isImmutable())
1875 {
1876 return true;
1877 }
1878
Jamie Madilld3d2a342013-10-07 10:46:35 -04001879 GLsizei width = getBaseLevelWidth();
1880 GLsizei height = getBaseLevelHeight();
1881 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001882
1883 if (width <= 0 || height <= 0 || depth <= 0)
1884 {
1885 return false;
1886 }
1887
Jamie Madill07edd442013-07-19 16:36:58 -04001888 if (level == 0)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001889 {
Jamie Madill07edd442013-07-19 16:36:58 -04001890 return true;
1891 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001892
Jamie Madill07edd442013-07-19 16:36:58 -04001893 rx::Image *levelImage = mImageArray[level];
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001894
Jamie Madilld3d2a342013-10-07 10:46:35 -04001895 if (levelImage->getInternalFormat() != getBaseLevelInternalFormat())
Jamie Madill07edd442013-07-19 16:36:58 -04001896 {
1897 return false;
1898 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001899
Jamie Madill07edd442013-07-19 16:36:58 -04001900 if (levelImage->getWidth() != std::max(1, width >> level))
1901 {
1902 return false;
1903 }
1904
1905 if (levelImage->getHeight() != std::max(1, height >> level))
1906 {
1907 return false;
1908 }
1909
1910 if (levelImage->getDepth() != std::max(1, depth >> level))
1911 {
1912 return false;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001913 }
1914
1915 return true;
1916}
1917
Geoff Lang8040f572013-07-25 16:49:54 -04001918Renderbuffer *Texture3D::getRenderbuffer(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001919{
Geoff Lang8040f572013-07-25 16:49:54 -04001920 Renderbuffer *renderBuffer = mRenderbufferProxies.get(level, layer);
1921 if (!renderBuffer)
1922 {
Geoff Langd5d8e392013-07-25 16:53:03 -04001923 renderBuffer = new Renderbuffer(mRenderer, id(), new RenderbufferTexture3DLayer(this, level, layer));
1924 mRenderbufferProxies.add(level, 0, renderBuffer);
Geoff Lang8040f572013-07-25 16:49:54 -04001925 }
1926
1927 return renderBuffer;
1928}
1929
1930unsigned int Texture3D::getRenderTargetSerial(GLint level, GLint layer)
1931{
1932 if (!mTexStorage || !mTexStorage->isRenderTarget())
1933 {
1934 convertToRenderTarget();
1935 }
1936
1937 return mTexStorage ? mTexStorage->getRenderTargetSerial(level, layer) : 0;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001938}
1939
1940int Texture3D::levelCount()
1941{
1942 return mTexStorage ? mTexStorage->levelCount() : 0;
1943}
1944
1945void Texture3D::createTexture()
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 return; // do not attempt to create native textures for nonexistant data
1953
1954 GLint levels = creationLevels(width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001955
1956 delete mTexStorage;
Jamie Madilld3d2a342013-10-07 10:46:35 -04001957 mTexStorage = new rx::TextureStorageInterface3D(mRenderer, levels, getBaseLevelInternalFormat(), mUsage, width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001958
1959 if (mTexStorage->isManaged())
1960 {
1961 int levels = levelCount();
1962
1963 for (int level = 0; level < levels; level++)
1964 {
1965 mImageArray[level]->setManagedSurface(mTexStorage, level);
1966 }
1967 }
1968
1969 mDirtyImages = true;
1970}
1971
1972void Texture3D::updateTexture()
1973{
Jamie Madilleb3665c2013-07-19 16:36:57 -04001974 int levels = (isMipmapComplete() ? levelCount() : 1);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001975
1976 for (int level = 0; level < levels; level++)
1977 {
Jamie Madill07edd442013-07-19 16:36:58 -04001978 updateTextureLevel(level);
1979 }
1980}
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001981
Jamie Madill07edd442013-07-19 16:36:58 -04001982void Texture3D::updateTextureLevel(int level)
1983{
1984 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1985
1986 rx::Image *image = mImageArray[level];
1987
1988 if (image->isDirty())
1989 {
1990 commitRect(level, 0, 0, 0, mImageArray[level]->getWidth(), mImageArray[level]->getHeight(), mImageArray[level]->getDepth());
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001991 }
1992}
1993
1994void Texture3D::convertToRenderTarget()
1995{
1996 rx::TextureStorageInterface3D *newTexStorage = NULL;
1997
Jamie Madilld3d2a342013-10-07 10:46:35 -04001998 if (getBaseLevelWidth() != 0 && getBaseLevelHeight() != 0 && getBaseLevelDepth() != 0)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001999 {
Jamie Madilld3d2a342013-10-07 10:46:35 -04002000 GLsizei width = getBaseLevelWidth();
2001 GLsizei height = getBaseLevelHeight();
2002 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002003 GLint levels = mTexStorage != NULL ? mTexStorage->levelCount() : creationLevels(width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002004
Jamie Madilld3d2a342013-10-07 10:46:35 -04002005 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 +00002006
2007 if (mTexStorage != NULL)
2008 {
2009 if (!mRenderer->copyToRenderTarget(newTexStorage, mTexStorage))
2010 {
2011 delete newTexStorage;
2012 return gl::error(GL_OUT_OF_MEMORY);
2013 }
2014 }
2015 }
2016
2017 delete mTexStorage;
2018 mTexStorage = newTexStorage;
2019
2020 mDirtyImages = true;
2021}
2022
Geoff Lang8040f572013-07-25 16:49:54 -04002023rx::RenderTarget *Texture3D::getRenderTarget(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002024{
Geoff Lang8040f572013-07-25 16:49:54 -04002025 // ensure the underlying texture is created
2026 if (getStorage(true) == NULL)
2027 {
2028 return NULL;
2029 }
2030
2031 updateTexture();
2032
2033 // ensure this is NOT a depth texture
2034 if (isDepth(level))
2035 {
2036 return NULL;
2037 }
2038
2039 return mTexStorage->getRenderTarget(level, layer);
2040}
2041
2042rx::RenderTarget *Texture3D::getDepthStencil(GLint level, GLint layer)
2043{
2044 // ensure the underlying texture is created
2045 if (getStorage(true) == NULL)
2046 {
2047 return NULL;
2048 }
2049
2050 updateTexture();
2051
2052 // ensure this is a depth texture
2053 if (!isDepth(level))
2054 {
2055 return NULL;
2056 }
2057
2058 return mTexStorage->getRenderTarget(level, layer);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002059}
2060
2061rx::TextureStorageInterface *Texture3D::getStorage(bool renderTarget)
2062{
2063 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
2064 {
2065 if (renderTarget)
2066 {
2067 convertToRenderTarget();
2068 }
2069 else
2070 {
2071 createTexture();
2072 }
2073 }
2074
2075 return mTexStorage;
2076}
2077
2078void Texture3D::redefineImage(GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth)
2079{
2080 // If there currently is a corresponding storage texture image, it has these parameters
Jamie Madilld3d2a342013-10-07 10:46:35 -04002081 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2082 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
2083 const int storageDepth = std::max(1, getBaseLevelDepth() >> level);
2084 const int storageFormat = getBaseLevelInternalFormat();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002085
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00002086 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, false);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002087
2088 if (mTexStorage)
2089 {
2090 const int storageLevels = mTexStorage->levelCount();
2091
2092 if ((level >= storageLevels && storageLevels != 0) ||
2093 width != storageWidth ||
2094 height != storageHeight ||
2095 depth != storageDepth ||
2096 internalformat != storageFormat) // Discard mismatched storage
2097 {
2098 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
2099 {
2100 mImageArray[i]->markDirty();
2101 }
2102
2103 delete mTexStorage;
2104 mTexStorage = NULL;
2105 mDirtyImages = true;
2106 }
2107 }
2108}
2109
2110void Texture3D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth)
2111{
2112 if (level < levelCount())
2113 {
2114 rx::Image *image = mImageArray[level];
2115 if (image->updateSurface(mTexStorage, level, xoffset, yoffset, zoffset, width, height, depth))
2116 {
2117 image->markClean();
2118 }
2119 }
2120}
2121
Geoff Lang4907f2c2013-07-25 12:53:57 -04002122Texture2DArray::Texture2DArray(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_2D_ARRAY)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002123{
2124 mTexStorage = NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002125
2126 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2127 {
2128 mLayerCounts[level] = 0;
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002129 mImageArray[level] = NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002130 }
2131}
2132
2133Texture2DArray::~Texture2DArray()
2134{
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002135 delete mTexStorage;
2136 mTexStorage = NULL;
2137 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2138 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002139 for (int layer = 0; layer < mLayerCounts[level]; ++layer)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002140 {
2141 delete mImageArray[level][layer];
2142 }
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002143 delete[] mImageArray[level];
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002144 }
2145}
2146
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002147GLsizei Texture2DArray::getWidth(GLint level) const
2148{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002149 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 +00002150}
2151
2152GLsizei Texture2DArray::getHeight(GLint level) const
2153{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002154 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 +00002155}
2156
2157GLsizei Texture2DArray::getDepth(GLint level) const
2158{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002159 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mLayerCounts[level] : 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002160}
2161
2162GLenum Texture2DArray::getInternalFormat(GLint level) const
2163{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002164 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 +00002165}
2166
2167GLenum Texture2DArray::getActualFormat(GLint level) const
2168{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002169 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 +00002170}
2171
2172bool Texture2DArray::isCompressed(GLint level) const
2173{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00002174 return IsFormatCompressed(getInternalFormat(level), mRenderer->getCurrentClientVersion());
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002175}
2176
2177bool Texture2DArray::isDepth(GLint level) const
2178{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00002179 return GetDepthBits(getInternalFormat(level), mRenderer->getCurrentClientVersion()) > 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002180}
2181
Jamie Madill88f18f42013-09-18 14:36:19 -04002182void Texture2DArray::setImage(GLint level, GLsizei width, GLsizei height, GLsizei depth, GLint internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002183{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00002184 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2185 GLint sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
2186 : GetSizedInternalFormat(format, type, clientVersion);
2187 redefineImage(level, sizedInternalFormat, width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002188
Jamie Madill88f18f42013-09-18 14:36:19 -04002189 GLsizei inputDepthPitch = gl::GetDepthPitch(sizedInternalFormat, type, clientVersion, width, height, unpack.alignment);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002190
2191 for (int i = 0; i < depth; i++)
2192 {
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002193 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
Jamie Madill88f18f42013-09-18 14:36:19 -04002194 Texture::setImage(unpack, type, layerPixels, mImageArray[level][i]);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002195 }
2196}
2197
2198void Texture2DArray::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
2199{
2200 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
2201 redefineImage(level, format, width, height, depth);
2202
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002203 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2204 GLsizei inputDepthPitch = gl::GetDepthPitch(format, GL_UNSIGNED_BYTE, clientVersion, width, height, 1);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002205
2206 for (int i = 0; i < depth; i++)
2207 {
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002208 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002209 Texture::setCompressedImage(imageSize, layerPixels, mImageArray[level][i]);
2210 }
2211}
2212
Jamie Madill88f18f42013-09-18 14:36:19 -04002213void 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 +00002214{
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002215 GLint internalformat = getInternalFormat(level);
2216 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Jamie Madill88f18f42013-09-18 14:36:19 -04002217 GLsizei inputDepthPitch = gl::GetDepthPitch(internalformat, type, clientVersion, width, height, unpack.alignment);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002218
2219 for (int i = 0; i < depth; i++)
2220 {
2221 int layer = zoffset + i;
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002222 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002223
Jamie Madill88f18f42013-09-18 14:36:19 -04002224 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 +00002225 {
2226 commitRect(level, xoffset, yoffset, layer, width, height);
2227 }
2228 }
2229}
2230
2231void Texture2DArray::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
2232{
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002233 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2234 GLsizei inputDepthPitch = gl::GetDepthPitch(format, GL_UNSIGNED_BYTE, clientVersion, width, height, 1);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002235
2236 for (int i = 0; i < depth; i++)
2237 {
2238 int layer = zoffset + i;
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002239 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002240
2241 if (Texture::subImageCompressed(xoffset, yoffset, zoffset, width, height, 1, format, imageSize, layerPixels, mImageArray[level][layer]))
2242 {
2243 commitRect(level, xoffset, yoffset, layer, width, height);
2244 }
2245 }
2246}
2247
2248void Texture2DArray::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2249{
2250 delete mTexStorage;
2251 mTexStorage = new rx::TextureStorageInterface2DArray(mRenderer, levels, internalformat, mUsage, width, height, depth);
2252 mImmutable = true;
2253
2254 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2255 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002256 GLsizei levelWidth = std::max(width >> level, 1);
Geoff Lange836cf22013-08-05 14:12:37 -04002257 GLsizei levelHeight = std::max(height >> level, 1);
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002258
2259 // Clear this level
2260 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002261 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002262 delete mImageArray[level][layer];
2263 }
2264 delete[] mImageArray[level];
2265 mImageArray[level] = NULL;
2266 mLayerCounts[level] = 0;
2267
2268 if (level < levels)
2269 {
2270 // Create new images for this level
2271 mImageArray[level] = new rx::Image*[depth]();
2272 mLayerCounts[level] = depth;
2273
2274 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002275 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002276 mImageArray[level][layer] = mRenderer->createImage();
2277 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, levelWidth,
2278 levelHeight, 1, true);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002279 }
2280 }
2281 }
2282
2283 if (mTexStorage->isManaged())
2284 {
2285 int levels = levelCount();
2286
2287 for (int level = 0; level < levels; level++)
2288 {
2289 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2290 {
2291 mImageArray[level][layer]->setManagedSurface(mTexStorage, layer, level);
2292 }
2293 }
2294 }
2295}
2296
2297void Texture2DArray::generateMipmaps()
2298{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002299 int baseWidth = getBaseLevelWidth();
2300 int baseHeight = getBaseLevelHeight();
2301 int baseDepth = getBaseLevelDepth();
2302 GLenum baseFormat = getBaseLevelInternalFormat();
2303
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00002304 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Jamie Madilld3d2a342013-10-07 10:46:35 -04002305 int q = log2(std::max(baseWidth, baseHeight));
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00002306 for (int i = 1; i <= q; i++)
2307 {
Jamie Madilld3d2a342013-10-07 10:46:35 -04002308 redefineImage(i, baseFormat, std::max(baseWidth >> i, 1), std::max(baseHeight >> i, 1), baseDepth);
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00002309 }
2310
2311 if (mTexStorage && mTexStorage->isRenderTarget())
2312 {
2313 for (int level = 1; level <= q; level++)
2314 {
2315 mTexStorage->generateMipmap(level);
2316
2317 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2318 {
2319 mImageArray[level][layer]->markClean();
2320 }
2321 }
2322 }
2323 else
2324 {
2325 for (int level = 1; level <= q; level++)
2326 {
2327 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2328 {
2329 mRenderer->generateMipmap(mImageArray[level][layer], mImageArray[level - 1][layer]);
2330 }
2331 }
2332 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002333}
2334
Jamie Madilld3d2a342013-10-07 10:46:35 -04002335const rx::Image *Texture2DArray::getBaseLevelImage() const
2336{
Jamie Madill152ed092013-10-09 17:01:15 -04002337 return (mLayerCounts[0] > 0 ? mImageArray[0][0] : NULL);
Jamie Madilld3d2a342013-10-07 10:46:35 -04002338}
2339
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002340void Texture2DArray::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
2341{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002342 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 +00002343 {
2344 return gl::error(GL_INVALID_VALUE);
2345 }
2346
Jamie Madill07edd442013-07-19 16:36:58 -04002347 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
2348 // the current level we're copying to is defined (with appropriate format, width & height)
2349 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
2350
2351 if (!mImageArray[level][0]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002352 {
2353 mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, x, y, width, height, source);
2354 mDirtyImages = true;
2355 }
2356 else
2357 {
2358 if (!mTexStorage || !mTexStorage->isRenderTarget())
2359 {
2360 convertToRenderTarget();
2361 }
2362
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002363 if (level < levelCount())
2364 {
Jamie Madill07edd442013-07-19 16:36:58 -04002365 updateTextureLevel(level);
2366
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002367 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2368
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002369 gl::Rectangle sourceRect;
2370 sourceRect.x = x;
2371 sourceRect.width = width;
2372 sourceRect.y = y;
2373 sourceRect.height = height;
2374
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002375 mRenderer->copyImage(source, sourceRect, gl::GetFormat(getInternalFormat(0), clientVersion),
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002376 xoffset, yoffset, zoffset, mTexStorage, level);
2377 }
2378 }
2379}
2380
Jamie Madillf8989902013-07-19 16:36:58 -04002381bool Texture2DArray::isSamplerComplete(const SamplerState &samplerState) const
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002382{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002383 GLsizei width = getBaseLevelWidth();
2384 GLsizei height = getBaseLevelHeight();
2385 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002386
2387 if (width <= 0 || height <= 0 || depth <= 0)
2388 {
2389 return false;
2390 }
2391
Jamie Madilld3d2a342013-10-07 10:46:35 -04002392 if (!IsTextureFilteringSupported(getBaseLevelInternalFormat(), mRenderer))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002393 {
Jamie Madillf8989902013-07-19 16:36:58 -04002394 if (samplerState.magFilter != GL_NEAREST ||
2395 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002396 {
2397 return false;
2398 }
2399 }
2400
Jamie Madillf8989902013-07-19 16:36:58 -04002401 if (IsMipmapFiltered(samplerState) && !isMipmapComplete())
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002402 {
2403 return false;
2404 }
2405
2406 return true;
2407}
2408
2409bool Texture2DArray::isMipmapComplete() const
2410{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002411 GLsizei width = getBaseLevelWidth();
2412 GLsizei height = getBaseLevelHeight();
Jamie Madill07edd442013-07-19 16:36:58 -04002413
2414 int q = log2(std::max(width, height));
2415
2416 for (int level = 1; level <= q; level++)
2417 {
2418 if (!isLevelComplete(level))
2419 {
2420 return false;
2421 }
2422 }
2423
2424 return true;
2425}
2426
2427bool Texture2DArray::isLevelComplete(int level) const
2428{
2429 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
2430
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002431 if (isImmutable())
2432 {
2433 return true;
2434 }
2435
Jamie Madilld3d2a342013-10-07 10:46:35 -04002436 GLsizei width = getBaseLevelWidth();
2437 GLsizei height = getBaseLevelHeight();
2438 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002439
2440 if (width <= 0 || height <= 0 || depth <= 0)
2441 {
2442 return false;
2443 }
2444
Jamie Madill07edd442013-07-19 16:36:58 -04002445 if (level == 0)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002446 {
Jamie Madill07edd442013-07-19 16:36:58 -04002447 return true;
2448 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002449
Jamie Madill07edd442013-07-19 16:36:58 -04002450 if (getInternalFormat(level) != getInternalFormat(0))
2451 {
2452 return false;
2453 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002454
Jamie Madill07edd442013-07-19 16:36:58 -04002455 if (getWidth(level) != std::max(1, width >> level))
2456 {
2457 return false;
2458 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002459
Jamie Madill07edd442013-07-19 16:36:58 -04002460 if (getHeight(level) != std::max(1, height >> level))
2461 {
2462 return false;
2463 }
2464
2465 if (getDepth(level) != depth)
2466 {
2467 return false;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002468 }
2469
2470 return true;
2471}
2472
Geoff Lang8040f572013-07-25 16:49:54 -04002473Renderbuffer *Texture2DArray::getRenderbuffer(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002474{
Geoff Lang8040f572013-07-25 16:49:54 -04002475 Renderbuffer *renderBuffer = mRenderbufferProxies.get(level, layer);
2476 if (!renderBuffer)
2477 {
Geoff Langd5d8e392013-07-25 16:53:03 -04002478 renderBuffer = new Renderbuffer(mRenderer, id(), new RenderbufferTexture2DArrayLayer(this, level, layer));
2479 mRenderbufferProxies.add(level, 0, renderBuffer);
Geoff Lang8040f572013-07-25 16:49:54 -04002480 }
2481
2482 return renderBuffer;
2483}
2484
2485unsigned int Texture2DArray::getRenderTargetSerial( GLint level, GLint layer )
2486{
2487 if (!mTexStorage || !mTexStorage->isRenderTarget())
2488 {
2489 convertToRenderTarget();
2490 }
2491
2492 return mTexStorage ? mTexStorage->getRenderTargetSerial(level, layer) : 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002493}
2494
2495int Texture2DArray::levelCount()
2496{
2497 return mTexStorage ? mTexStorage->levelCount() : 0;
2498}
2499
2500void Texture2DArray::createTexture()
2501{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002502 GLsizei width = getBaseLevelWidth();
2503 GLsizei height = getBaseLevelHeight();
2504 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002505
2506 if (width <= 0 || height <= 0 || depth <= 0)
2507 {
2508 return; // do not attempt to create native textures for nonexistant data
2509 }
2510
2511 GLint levels = creationLevels(width, height);
Jamie Madilld3d2a342013-10-07 10:46:35 -04002512 GLenum internalformat = getBaseLevelInternalFormat();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002513
2514 delete mTexStorage;
2515 mTexStorage = new rx::TextureStorageInterface2DArray(mRenderer, levels, internalformat, mUsage, width, height, depth);
2516
2517 if (mTexStorage->isManaged())
2518 {
2519 int levels = levelCount();
2520 for (int level = 0; level < levels; level++)
2521 {
2522 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2523 {
2524 mImageArray[level][layer]->setManagedSurface(mTexStorage, layer, level);
2525 }
2526 }
2527 }
2528
2529 mDirtyImages = true;
2530}
2531
2532void Texture2DArray::updateTexture()
2533{
Jamie Madilleb3665c2013-07-19 16:36:57 -04002534 int levels = (isMipmapComplete() ? levelCount() : 1);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002535 for (int level = 0; level < levels; level++)
2536 {
Jamie Madill07edd442013-07-19 16:36:58 -04002537 updateTextureLevel(level);
2538 }
2539}
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002540
Jamie Madill07edd442013-07-19 16:36:58 -04002541void Texture2DArray::updateTextureLevel(int level)
2542{
2543 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2544 {
2545 rx::Image *image = mImageArray[level][layer];
2546
2547 if (image->isDirty())
2548 {
2549 commitRect(level, 0, 0, layer, image->getWidth(), image->getHeight());
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002550 }
2551 }
2552}
2553
2554void Texture2DArray::convertToRenderTarget()
2555{
2556 rx::TextureStorageInterface2DArray *newTexStorage = NULL;
2557
Jamie Madilld3d2a342013-10-07 10:46:35 -04002558 GLsizei width = getBaseLevelWidth();
2559 GLsizei height = getBaseLevelHeight();
2560 GLsizei depth = getBaseLevelDepth();
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002561
2562 if (width != 0 && height != 0 && depth != 0)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002563 {
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002564 GLint levels = mTexStorage != NULL ? mTexStorage->levelCount() : creationLevels(width, height);
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002565 GLenum internalformat = getInternalFormat(0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002566
2567 newTexStorage = new rx::TextureStorageInterface2DArray(mRenderer, levels, internalformat, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, width, height, depth);
2568
2569 if (mTexStorage != NULL)
2570 {
2571 if (!mRenderer->copyToRenderTarget(newTexStorage, mTexStorage))
2572 {
2573 delete newTexStorage;
2574 return gl::error(GL_OUT_OF_MEMORY);
2575 }
2576 }
2577 }
2578
2579 delete mTexStorage;
2580 mTexStorage = newTexStorage;
2581
2582 mDirtyImages = true;
2583}
2584
Geoff Lang8040f572013-07-25 16:49:54 -04002585rx::RenderTarget *Texture2DArray::getRenderTarget(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002586{
Geoff Lang8040f572013-07-25 16:49:54 -04002587 // ensure the underlying texture is created
2588 if (getStorage(true) == NULL)
2589 {
2590 return NULL;
2591 }
2592
2593 updateTexture();
2594
2595 // ensure this is NOT a depth texture
2596 if (isDepth(level))
2597 {
2598 return NULL;
2599 }
2600
2601 return mTexStorage->getRenderTarget(level, layer);
2602}
2603
2604rx::RenderTarget *Texture2DArray::getDepthStencil(GLint level, GLint layer)
2605{
2606 // ensure the underlying texture is created
2607 if (getStorage(true) == NULL)
2608 {
2609 return NULL;
2610 }
2611
2612 updateTexture();
2613
2614 // ensure this is a depth texture
2615 if (!isDepth(level))
2616 {
2617 return NULL;
2618 }
2619
2620 return mTexStorage->getRenderTarget(level, layer);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002621}
2622
2623rx::TextureStorageInterface *Texture2DArray::getStorage(bool renderTarget)
2624{
2625 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
2626 {
2627 if (renderTarget)
2628 {
2629 convertToRenderTarget();
2630 }
2631 else
2632 {
2633 createTexture();
2634 }
2635 }
2636
2637 return mTexStorage;
2638}
2639
2640void Texture2DArray::redefineImage(GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth)
2641{
2642 // If there currently is a corresponding storage texture image, it has these parameters
Jamie Madilld3d2a342013-10-07 10:46:35 -04002643 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2644 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
2645 const int storageDepth = getBaseLevelDepth();
2646 const int storageFormat = getBaseLevelInternalFormat();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002647
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002648 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002649 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002650 delete mImageArray[level][layer];
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002651 }
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002652 delete[] mImageArray[level];
Jamie Madill152ed092013-10-09 17:01:15 -04002653 mImageArray[level] = NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002654 mLayerCounts[level] = depth;
2655
Jamie Madill152ed092013-10-09 17:01:15 -04002656 if (depth > 0)
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002657 {
Jamie Madill152ed092013-10-09 17:01:15 -04002658 mImageArray[level] = new rx::Image*[depth]();
2659
2660 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2661 {
2662 mImageArray[level][layer] = mRenderer->createImage();
2663 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, width, height, 1, false);
2664 }
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002665 }
2666
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002667 if (mTexStorage)
2668 {
2669 const int storageLevels = mTexStorage->levelCount();
2670
2671 if ((level >= storageLevels && storageLevels != 0) ||
2672 width != storageWidth ||
2673 height != storageHeight ||
2674 depth != storageDepth ||
2675 internalformat != storageFormat) // Discard mismatched storage
2676 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002677 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002678 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002679 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002680 {
2681 mImageArray[level][layer]->markDirty();
2682 }
2683 }
2684
2685 delete mTexStorage;
2686 mTexStorage = NULL;
2687 mDirtyImages = true;
2688 }
2689 }
2690}
2691
2692void Texture2DArray::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint layerTarget, GLsizei width, GLsizei height)
2693{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002694 if (level < levelCount() && layerTarget < getDepth(level))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002695 {
2696 rx::Image *image = mImageArray[level][layerTarget];
2697 if (image->updateSurface(mTexStorage, level, xoffset, yoffset, layerTarget, width, height))
2698 {
2699 image->markClean();
2700 }
2701 }
2702}
2703
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00002704}