blob: 546f830d94fbb02539884d6b89847348e392e7dc [file] [log] [blame]
shannon.woods@transgaming.combdf2d802013-02-28 23:16:20 +00001#include "precompiled.h"
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00002//
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00003// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00004// Use of this source code is governed by a BSD-style license that can be
5// found in the LICENSE file.
6//
7
8// Texture.cpp: Implements the gl::Texture class and its derived classes
9// Texture2D and TextureCubeMap. Implements GL texture objects and related
10// functionality. [OpenGL ES 2.0.24] section 3.7 page 63.
11
12#include "libGLESv2/Texture.h"
13
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000014#include "libGLESv2/main.h"
shannonwoods@chromium.orga2ecfcc2013-05-30 00:11:59 +000015#include "common/mathutil.h"
16#include "common/utilities.h"
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +000017#include "libGLESv2/formatutils.h"
shannon.woods@transgaming.com486d9e92013-02-28 23:15:41 +000018#include "libGLESv2/Renderbuffer.h"
19#include "libGLESv2/renderer/Image.h"
20#include "libGLESv2/renderer/Renderer.h"
21#include "libGLESv2/renderer/TextureStorage.h"
22#include "libEGL/Surface.h"
Jamie Madill1beb1db2013-09-18 14:36:28 -040023#include "libGLESv2/Buffer.h"
24#include "libGLESv2/renderer/BufferStorage.h"
Jamie Madill0e0510f2013-10-10 15:46:23 -040025#include "libGLESv2/renderer/RenderTarget.h"
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000026
27namespace gl
28{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000029
Jamie Madillf8989902013-07-19 16:36:58 -040030bool IsMipmapFiltered(const SamplerState &samplerState)
31{
32 switch (samplerState.minFilter)
33 {
34 case GL_NEAREST:
35 case GL_LINEAR:
36 return false;
37 case GL_NEAREST_MIPMAP_NEAREST:
38 case GL_LINEAR_MIPMAP_NEAREST:
39 case GL_NEAREST_MIPMAP_LINEAR:
40 case GL_LINEAR_MIPMAP_LINEAR:
41 return true;
42 default: UNREACHABLE();
43 return false;
44 }
45}
46
Jamie Madilld4589c92013-10-24 17:49:34 -040047bool IsRenderTargetUsage(GLenum usage)
48{
49 return (usage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
50}
51
Geoff Lang4907f2c2013-07-25 12:53:57 -040052Texture::Texture(rx::Renderer *renderer, GLuint id, GLenum target) : RefCountObject(id)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000053{
daniel@transgaming.com370482e2012-11-28 19:32:13 +000054 mRenderer = renderer;
55
daniel@transgaming.comebf139f2012-10-31 18:07:32 +000056 mSamplerState.minFilter = GL_NEAREST_MIPMAP_LINEAR;
57 mSamplerState.magFilter = GL_LINEAR;
58 mSamplerState.wrapS = GL_REPEAT;
59 mSamplerState.wrapT = GL_REPEAT;
shannon.woods%transgaming.com@gtempaccount.com0b3a8df2013-04-13 03:44:51 +000060 mSamplerState.wrapR = GL_REPEAT;
daniel@transgaming.comebf139f2012-10-31 18:07:32 +000061 mSamplerState.maxAnisotropy = 1.0f;
62 mSamplerState.lodOffset = 0;
Geoff Langc82fc412013-07-10 14:43:42 -040063 mSamplerState.compareMode = GL_NONE;
64 mSamplerState.compareFunc = GL_LEQUAL;
Geoff Langbc90a482013-09-17 16:51:27 -040065 mSamplerState.swizzleRed = GL_RED;
66 mSamplerState.swizzleGreen = GL_GREEN;
67 mSamplerState.swizzleBlue = GL_BLUE;
68 mSamplerState.swizzleAlpha = GL_ALPHA;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000069 mUsage = GL_NONE;
Geoff Langc82fc412013-07-10 14:43:42 -040070
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000071 mDirtyImages = true;
72
73 mImmutable = false;
Geoff Lang4907f2c2013-07-25 12:53:57 -040074
75 mTarget = target;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000076}
77
78Texture::~Texture()
79{
80}
81
Geoff Lang4907f2c2013-07-25 12:53:57 -040082GLenum Texture::getTarget() const
83{
84 return mTarget;
85}
86
Geoff Lang8040f572013-07-25 16:49:54 -040087void Texture::addProxyRef(const Renderbuffer *proxy)
88{
89 mRenderbufferProxies.addRef(proxy);
90}
91
92void Texture::releaseProxy(const Renderbuffer *proxy)
93{
94 mRenderbufferProxies.release(proxy);
95}
96
Geoff Lang63b5f1f2013-09-23 14:52:14 -040097void Texture::setMinFilter(GLenum filter)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000098{
Geoff Lang63b5f1f2013-09-23 14:52:14 -040099 mSamplerState.minFilter = filter;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000100}
101
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400102void Texture::setMagFilter(GLenum filter)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000103{
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400104 mSamplerState.magFilter = filter;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000105}
106
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400107void Texture::setWrapS(GLenum wrap)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000108{
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400109 mSamplerState.wrapS = wrap;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000110}
111
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400112void Texture::setWrapT(GLenum wrap)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000113{
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400114 mSamplerState.wrapT = wrap;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000115}
116
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400117void Texture::setWrapR(GLenum wrap)
shannon.woods%transgaming.com@gtempaccount.com0b3a8df2013-04-13 03:44:51 +0000118{
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400119 mSamplerState.wrapR = wrap;
shannon.woods%transgaming.com@gtempaccount.com0b3a8df2013-04-13 03:44:51 +0000120}
121
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400122void Texture::setMaxAnisotropy(float textureMaxAnisotropy, float contextMaxAnisotropy)
daniel@transgaming.com07ab8412012-07-12 15:17:09 +0000123{
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400124 mSamplerState.maxAnisotropy = std::min(textureMaxAnisotropy, contextMaxAnisotropy);
daniel@transgaming.com07ab8412012-07-12 15:17:09 +0000125}
126
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400127void Texture::setCompareMode(GLenum mode)
Geoff Langc82fc412013-07-10 14:43:42 -0400128{
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400129 mSamplerState.compareMode = mode;
Geoff Langc82fc412013-07-10 14:43:42 -0400130}
131
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400132void Texture::setCompareFunc(GLenum func)
Geoff Langc82fc412013-07-10 14:43:42 -0400133{
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400134 mSamplerState.compareFunc = func;
Geoff Langc82fc412013-07-10 14:43:42 -0400135}
136
Geoff Langbc90a482013-09-17 16:51:27 -0400137void Texture::setSwizzleRed(GLenum swizzle)
138{
139 mSamplerState.swizzleRed = swizzle;
140}
141
142void Texture::setSwizzleGreen(GLenum swizzle)
143{
144 mSamplerState.swizzleGreen = swizzle;
145}
146
147void Texture::setSwizzleBlue(GLenum swizzle)
148{
149 mSamplerState.swizzleBlue = swizzle;
150}
151
152void Texture::setSwizzleAlpha(GLenum swizzle)
153{
154 mSamplerState.swizzleAlpha = swizzle;
155}
156
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400157void Texture::setUsage(GLenum usage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000158{
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400159 mUsage = usage;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000160}
161
162GLenum Texture::getMinFilter() const
163{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000164 return mSamplerState.minFilter;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000165}
166
167GLenum Texture::getMagFilter() const
168{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000169 return mSamplerState.magFilter;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000170}
171
172GLenum Texture::getWrapS() const
173{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000174 return mSamplerState.wrapS;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000175}
176
177GLenum Texture::getWrapT() const
178{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000179 return mSamplerState.wrapT;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000180}
181
shannon.woods%transgaming.com@gtempaccount.com0b3a8df2013-04-13 03:44:51 +0000182GLenum Texture::getWrapR() const
183{
184 return mSamplerState.wrapR;
185}
186
daniel@transgaming.com07ab8412012-07-12 15:17:09 +0000187float Texture::getMaxAnisotropy() const
188{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000189 return mSamplerState.maxAnisotropy;
190}
191
Geoff Langbc90a482013-09-17 16:51:27 -0400192GLenum Texture::getSwizzleRed() const
193{
194 return mSamplerState.swizzleRed;
195}
196
197GLenum Texture::getSwizzleGreen() const
198{
199 return mSamplerState.swizzleGreen;
200}
201
202GLenum Texture::getSwizzleBlue() const
203{
204 return mSamplerState.swizzleBlue;
205}
206
207GLenum Texture::getSwizzleAlpha() const
208{
209 return mSamplerState.swizzleAlpha;
210}
211
212bool Texture::isSwizzled() const
213{
214 return mSamplerState.swizzleRed != GL_RED ||
215 mSamplerState.swizzleGreen != GL_GREEN ||
216 mSamplerState.swizzleBlue != GL_BLUE ||
217 mSamplerState.swizzleAlpha != GL_ALPHA;
218}
219
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000220int Texture::getLodOffset()
221{
Jamie Madill2ebab852013-10-24 17:49:42 -0400222 rx::TextureStorageInterface *texture = getNativeTexture();
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000223 return texture ? texture->getLodOffset() : 0;
224}
225
226void Texture::getSamplerState(SamplerState *sampler)
227{
228 *sampler = mSamplerState;
229 sampler->lodOffset = getLodOffset();
daniel@transgaming.com07ab8412012-07-12 15:17:09 +0000230}
231
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000232GLenum Texture::getUsage() const
233{
234 return mUsage;
235}
236
Jamie Madilld3d2a342013-10-07 10:46:35 -0400237GLint Texture::getBaseLevelWidth() const
238{
239 const rx::Image *baseImage = getBaseLevelImage();
240 return (baseImage ? baseImage->getWidth() : 0);
241}
242
243GLint Texture::getBaseLevelHeight() const
244{
245 const rx::Image *baseImage = getBaseLevelImage();
246 return (baseImage ? baseImage->getHeight() : 0);
247}
248
249GLint Texture::getBaseLevelDepth() const
250{
251 const rx::Image *baseImage = getBaseLevelImage();
252 return (baseImage ? baseImage->getDepth() : 0);
253}
254
255GLenum Texture::getBaseLevelInternalFormat() const
256{
257 const rx::Image *baseImage = getBaseLevelImage();
258 return (baseImage ? baseImage->getInternalFormat() : GL_NONE);
259}
260
Jamie Madill88f18f42013-09-18 14:36:19 -0400261void Texture::setImage(const PixelUnpackState &unpack, GLenum type, const void *pixels, rx::Image *image)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000262{
Jamie Madillabef6802013-09-05 16:54:19 -0400263 // We no longer need the "GLenum format" parameter to TexImage to determine what data format "pixels" contains.
264 // 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 -0400265 const void *pixelData = pixels;
266
267 if (unpack.pixelBuffer.id() != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000268 {
Jamie Madill1beb1db2013-09-18 14:36:28 -0400269 // Do a CPU readback here, if we have an unpack buffer bound and the fast GPU path is not supported
270 Buffer *pixelBuffer = unpack.pixelBuffer.get();
271 ptrdiff_t offset = reinterpret_cast<ptrdiff_t>(pixels);
272 const void *bufferData = pixelBuffer->getStorage()->getData();
273 pixelData = static_cast<const unsigned char *>(bufferData) + offset;
274 }
275
276 if (pixelData != NULL)
277 {
278 image->loadData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), unpack.alignment, type, pixelData);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000279 mDirtyImages = true;
280 }
281}
282
Geoff Lang005df412013-10-16 14:12:50 -0400283bool Texture::isFastUnpackable(const PixelUnpackState &unpack, GLenum sizedInternalFormat)
Jamie Madill8cc7d972013-10-10 15:51:55 -0400284{
285 return unpack.pixelBuffer.id() != 0 && mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat);
286}
287
Jamie Madill1beb1db2013-09-18 14:36:28 -0400288bool Texture::fastUnpackPixels(const PixelUnpackState &unpack, const void *pixels, const Box &destArea,
Jamie Madill8cc7d972013-10-10 15:51:55 -0400289 GLenum sizedInternalFormat, GLenum type, rx::RenderTarget *destRenderTarget)
Jamie Madill1beb1db2013-09-18 14:36:28 -0400290{
291 if (destArea.width <= 0 && destArea.height <= 0 && destArea.depth <= 0)
292 {
293 return true;
294 }
295
296 // In order to perform the fast copy through the shader, we must have the right format, and be able
297 // to create a render target.
Jamie Madill8cc7d972013-10-10 15:51:55 -0400298 ASSERT(mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat));
Jamie Madill1beb1db2013-09-18 14:36:28 -0400299
Jamie Madill8cc7d972013-10-10 15:51:55 -0400300 unsigned int offset = reinterpret_cast<unsigned int>(pixels);
Jamie Madill1beb1db2013-09-18 14:36:28 -0400301
Jamie Madill8cc7d972013-10-10 15:51:55 -0400302 return mRenderer->fastCopyBufferToTexture(unpack, offset, destRenderTarget, sizedInternalFormat, type, destArea);
Jamie Madill1beb1db2013-09-18 14:36:28 -0400303}
304
daniel@transgaming.com31b13e12012-11-28 19:34:30 +0000305void Texture::setCompressedImage(GLsizei imageSize, const void *pixels, rx::Image *image)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000306{
307 if (pixels != NULL)
308 {
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000309 image->loadCompressedData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000310 mDirtyImages = true;
311 }
312}
313
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000314bool Texture::subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
Jamie Madill88f18f42013-09-18 14:36:19 -0400315 GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels, rx::Image *image)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000316{
Jamie Madill065e1a32013-10-10 15:11:50 -0400317 const void *pixelData = pixels;
318
319 // CPU readback & copy where direct GPU copy is not supported
320 if (unpack.pixelBuffer.id() != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000321 {
Jamie Madill065e1a32013-10-10 15:11:50 -0400322 Buffer *pixelBuffer = unpack.pixelBuffer.get();
323 unsigned int offset = reinterpret_cast<unsigned int>(pixels);
324 const void *bufferData = pixelBuffer->getStorage()->getData();
325 pixelData = static_cast<const unsigned char *>(bufferData) + offset;
326 }
327
328 if (pixelData != NULL)
329 {
330 image->loadData(xoffset, yoffset, zoffset, width, height, depth, unpack.alignment, type, pixelData);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000331 mDirtyImages = true;
332 }
333
334 return true;
335}
336
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000337bool Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
338 GLenum format, GLsizei imageSize, const void *pixels, rx::Image *image)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000339{
340 if (pixels != NULL)
341 {
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000342 image->loadCompressedData(xoffset, yoffset, zoffset, width, height, depth, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000343 mDirtyImages = true;
344 }
345
346 return true;
347}
348
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000349rx::TextureStorageInterface *Texture::getNativeTexture()
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000350{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000351 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -0400352 initializeStorage(false);
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000353
Jamie Madill2ebab852013-10-24 17:49:42 -0400354 rx::TextureStorageInterface *storage = getBaseLevelStorage();
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000355 if (storage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000356 {
Jamie Madill169d1112013-10-24 17:49:37 -0400357 updateStorage();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000358 }
359
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000360 return storage;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000361}
362
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000363bool Texture::hasDirtyImages() const
364{
365 return mDirtyImages;
366}
367
368void Texture::resetDirty()
369{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000370 mDirtyImages = false;
371}
372
373unsigned int Texture::getTextureSerial()
374{
Jamie Madill2ebab852013-10-24 17:49:42 -0400375 rx::TextureStorageInterface *texture = getNativeTexture();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000376 return texture ? texture->getTextureSerial() : 0;
377}
378
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000379bool Texture::isImmutable() const
380{
381 return mImmutable;
382}
383
Jamie Madill51a94372013-10-24 17:49:43 -0400384int Texture::immutableLevelCount()
385{
Jamie Madill4cfff5f2013-10-24 17:49:46 -0400386 return (mImmutable ? getNativeTexture()->getStorageInstance()->getMaxLevel() : 0);
Jamie Madill51a94372013-10-24 17:49:43 -0400387}
388
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +0000389GLint Texture::creationLevels(GLsizei width, GLsizei height, GLsizei depth) const
390{
Jamie Madill6b7440c2013-10-24 17:49:47 -0400391 if ((isPow2(width) && isPow2(height) && isPow2(depth)) || mRenderer->getNonPower2TextureSupport())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000392 {
Jamie Madill6b7440c2013-10-24 17:49:47 -0400393 // Maximum number of levels
394 return static_cast<GLint>(log2(std::max(std::max(width, height), depth)));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000395 }
396 else
397 {
398 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
399 return 1;
400 }
401}
402
Jamie Madill22f843a2013-10-24 17:49:36 -0400403int Texture::mipLevels() const
404{
Jamie Madill6b7440c2013-10-24 17:49:47 -0400405 return static_cast<int>(log2(std::max(std::max(getBaseLevelWidth(), getBaseLevelHeight()), getBaseLevelDepth())));
Jamie Madill22f843a2013-10-24 17:49:36 -0400406}
407
Geoff Lang4907f2c2013-07-25 12:53:57 -0400408Texture2D::Texture2D(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_2D)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000409{
410 mTexStorage = NULL;
411 mSurface = NULL;
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000412
413 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
414 {
daniel@transgaming.com244e1832012-12-20 20:52:35 +0000415 mImageArray[i] = renderer->createImage();
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000416 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000417}
418
419Texture2D::~Texture2D()
420{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000421 delete mTexStorage;
422 mTexStorage = NULL;
423
424 if (mSurface)
425 {
426 mSurface->setBoundTexture(NULL);
427 mSurface = NULL;
428 }
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000429
430 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
431 {
432 delete mImageArray[i];
433 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000434}
435
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000436GLsizei Texture2D::getWidth(GLint level) const
437{
438 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000439 return mImageArray[level]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000440 else
441 return 0;
442}
443
444GLsizei Texture2D::getHeight(GLint level) const
445{
446 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000447 return mImageArray[level]->getHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000448 else
449 return 0;
450}
451
452GLenum Texture2D::getInternalFormat(GLint level) const
453{
454 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000455 return mImageArray[level]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000456 else
457 return GL_NONE;
458}
459
daniel@transgaming.com20d36662012-10-31 19:51:43 +0000460GLenum Texture2D::getActualFormat(GLint level) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000461{
462 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000463 return mImageArray[level]->getActualFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000464 else
465 return D3DFMT_UNKNOWN;
466}
467
Geoff Lang005df412013-10-16 14:12:50 -0400468void Texture2D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000469{
470 releaseTexImage();
shannon.woods@transgaming.com8a406682013-02-28 23:15:26 +0000471
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000472 // If there currently is a corresponding storage texture image, it has these parameters
Jamie Madilld3d2a342013-10-07 10:46:35 -0400473 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
474 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
Geoff Lang005df412013-10-16 14:12:50 -0400475 const GLenum storageFormat = getBaseLevelInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000476
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000477 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, width, height, 1, false);
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000478
479 if (mTexStorage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000480 {
Jamie Madill4cfff5f2013-10-24 17:49:46 -0400481 const int storageLevels = mTexStorage->getMaxLevel();
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000482
483 if ((level >= storageLevels && storageLevels != 0) ||
484 width != storageWidth ||
485 height != storageHeight ||
486 internalformat != storageFormat) // Discard mismatched storage
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000487 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000488 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
489 {
490 mImageArray[i]->markDirty();
491 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000492
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000493 delete mTexStorage;
494 mTexStorage = NULL;
495 mDirtyImages = true;
496 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000497 }
498}
499
Geoff Lang005df412013-10-16 14:12:50 -0400500void Texture2D::setImage(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000501{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +0000502 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Geoff Lang005df412013-10-16 14:12:50 -0400503 GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
504 : GetSizedInternalFormat(format, type, clientVersion);
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +0000505 redefineImage(level, sizedInternalFormat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000506
Jamie Madill8cc7d972013-10-10 15:51:55 -0400507 bool fastUnpacked = false;
508
Jamie Madill1beb1db2013-09-18 14:36:28 -0400509 // Attempt a fast gpu copy of the pixel data to the surface
Jamie Madill8cc7d972013-10-10 15:51:55 -0400510 if (isFastUnpackable(unpack, sizedInternalFormat) && isLevelComplete(level))
Jamie Madill1beb1db2013-09-18 14:36:28 -0400511 {
Jamie Madill8cc7d972013-10-10 15:51:55 -0400512 // Will try to create RT storage if it does not exist
513 rx::RenderTarget *destRenderTarget = getRenderTarget(level);
514 Box destArea(0, 0, 0, getWidth(level), getHeight(level), 1);
515
516 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget))
517 {
518 // Ensure we don't overwrite our newly initialized data
519 mImageArray[level]->markClean();
520
521 fastUnpacked = true;
522 }
Jamie Madill1beb1db2013-09-18 14:36:28 -0400523 }
Jamie Madill8cc7d972013-10-10 15:51:55 -0400524
525 if (!fastUnpacked)
Jamie Madill1beb1db2013-09-18 14:36:28 -0400526 {
527 Texture::setImage(unpack, type, pixels, mImageArray[level]);
528 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000529}
530
531void Texture2D::bindTexImage(egl::Surface *surface)
532{
533 releaseTexImage();
534
Geoff Lang005df412013-10-16 14:12:50 -0400535 GLenum internalformat = surface->getFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000536
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000537 mImageArray[0]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, surface->getWidth(), surface->getHeight(), 1, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000538
539 delete mTexStorage;
daniel@transgaming.comd8353dd2012-12-20 21:11:14 +0000540 mTexStorage = new rx::TextureStorageInterface2D(mRenderer, surface->getSwapChain());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000541
542 mDirtyImages = true;
543 mSurface = surface;
544 mSurface->setBoundTexture(this);
545}
546
547void Texture2D::releaseTexImage()
548{
549 if (mSurface)
550 {
551 mSurface->setBoundTexture(NULL);
552 mSurface = NULL;
553
554 if (mTexStorage)
555 {
556 delete mTexStorage;
557 mTexStorage = NULL;
558 }
559
560 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
561 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000562 mImageArray[i]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000563 }
564 }
565}
566
567void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
568{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000569 // 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 +0000570 redefineImage(level, format, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000571
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000572 Texture::setCompressedImage(imageSize, pixels, mImageArray[level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000573}
574
575void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
576{
Jamie Madill07bb8cf2013-10-24 17:49:44 -0400577 if (isValidLevel(level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000578 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000579 rx::Image *image = mImageArray[level];
Jamie Madill169d1112013-10-24 17:49:37 -0400580 if (image->copyToStorage(mTexStorage, level, xoffset, yoffset, width, height))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000581 {
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000582 image->markClean();
583 }
584 }
585}
586
Jamie Madill88f18f42013-09-18 14:36:19 -0400587void 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 +0000588{
Jamie Madill065e1a32013-10-10 15:11:50 -0400589 bool fastUnpacked = false;
590
591 if (isFastUnpackable(unpack, getInternalFormat(level)) && isLevelComplete(level))
592 {
593 rx::RenderTarget *renderTarget = getRenderTarget(level);
594 Box destArea(xoffset, yoffset, 0, width, height, 1);
595
596 if (renderTarget && fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, renderTarget))
597 {
598 // Ensure we don't overwrite our newly initialized data
599 mImageArray[level]->markClean();
600
601 fastUnpacked = true;
602 }
603 }
604
605 if (!fastUnpacked && Texture::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, mImageArray[level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000606 {
607 commitRect(level, xoffset, yoffset, width, height);
608 }
609}
610
611void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
612{
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000613 if (Texture::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000614 {
615 commitRect(level, xoffset, yoffset, width, height);
616 }
617}
618
619void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
620{
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +0000621 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Geoff Lang005df412013-10-16 14:12:50 -0400622 GLenum sizedInternalFormat = IsSizedInternalFormat(format, clientVersion) ? format
623 : GetSizedInternalFormat(format, GL_UNSIGNED_BYTE, clientVersion);
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +0000624 redefineImage(level, sizedInternalFormat, width, height);
shannon.woods@transgaming.com8a406682013-02-28 23:15:26 +0000625
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000626 if (!mImageArray[level]->isRenderableFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000627 {
shannon.woods%transgaming.com@gtempaccount.come5dcce72013-04-13 03:44:33 +0000628 mImageArray[level]->copy(0, 0, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000629 mDirtyImages = true;
630 }
631 else
632 {
Jamie Madille83d1a92013-10-24 17:49:33 -0400633 ensureRenderTarget();
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000634 mImageArray[level]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000635
Jamie Madill07bb8cf2013-10-24 17:49:44 -0400636 if (width != 0 && height != 0 && isValidLevel(level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000637 {
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +0000638 gl::Rectangle sourceRect;
639 sourceRect.x = x;
640 sourceRect.width = width;
641 sourceRect.y = y;
642 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000643
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +0000644 mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000645 }
646 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000647}
648
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +0000649void 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 +0000650{
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +0000651 if (xoffset + width > mImageArray[level]->getWidth() || yoffset + height > mImageArray[level]->getHeight() || zoffset != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000652 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +0000653 return gl::error(GL_INVALID_VALUE);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000654 }
655
Jamie Madill07edd442013-07-19 16:36:58 -0400656 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
657 // the current level we're copying to is defined (with appropriate format, width & height)
658 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
659
660 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000661 {
shannon.woods%transgaming.com@gtempaccount.come5dcce72013-04-13 03:44:33 +0000662 mImageArray[level]->copy(xoffset, yoffset, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000663 mDirtyImages = true;
664 }
665 else
666 {
Jamie Madille83d1a92013-10-24 17:49:33 -0400667 ensureRenderTarget();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000668
Jamie Madill07bb8cf2013-10-24 17:49:44 -0400669 if (isValidLevel(level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000670 {
Jamie Madill169d1112013-10-24 17:49:37 -0400671 updateStorageLevel(level);
Jamie Madill07edd442013-07-19 16:36:58 -0400672
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +0000673 GLuint clientVersion = mRenderer->getCurrentClientVersion();
674
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +0000675 gl::Rectangle sourceRect;
676 sourceRect.x = x;
677 sourceRect.width = width;
678 sourceRect.y = y;
679 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000680
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +0000681 mRenderer->copyImage(source, sourceRect,
Jamie Madilld3d2a342013-10-07 10:46:35 -0400682 gl::GetFormat(getBaseLevelInternalFormat(), clientVersion),
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +0000683 xoffset, yoffset, mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000684 }
685 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000686}
687
688void Texture2D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height)
689{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000690 for (int level = 0; level < levels; level++)
691 {
Jamie Madill73b5d062013-10-24 17:49:38 -0400692 GLsizei levelWidth = std::max(1, width >> level);
693 GLsizei levelHeight = std::max(1, height >> level);
694 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, levelWidth, levelHeight, 1, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000695 }
696
697 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
698 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000699 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000700 }
701
Jamie Madill73b5d062013-10-24 17:49:38 -0400702 mImmutable = true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000703
Jamie Madill4cfff5f2013-10-24 17:49:46 -0400704 setCompleteTexStorage(new rx::TextureStorageInterface2D(mRenderer, 0, levels, internalformat, IsRenderTargetUsage(mUsage), width, height));
Jamie Madill73b5d062013-10-24 17:49:38 -0400705}
706
707void Texture2D::setCompleteTexStorage(rx::TextureStorageInterface2D *newCompleteTexStorage)
708{
709 SafeDelete(mTexStorage);
710 mTexStorage = newCompleteTexStorage;
711
712 if (mTexStorage && mTexStorage->isManaged())
713 {
Jamie Madill4cfff5f2013-10-24 17:49:46 -0400714 for (int level = 0; level < mTexStorage->getMaxLevel(); level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000715 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000716 mImageArray[level]->setManagedSurface(mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000717 }
718 }
Jamie Madill73b5d062013-10-24 17:49:38 -0400719
720 mDirtyImages = true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000721}
722
723// Tests for 2D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85.
Jamie Madillf8989902013-07-19 16:36:58 -0400724bool Texture2D::isSamplerComplete(const SamplerState &samplerState) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000725{
Jamie Madilld3d2a342013-10-07 10:46:35 -0400726 GLsizei width = getBaseLevelWidth();
727 GLsizei height = getBaseLevelHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000728
729 if (width <= 0 || height <= 0)
730 {
731 return false;
732 }
733
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000734 if (!IsTextureFilteringSupported(getInternalFormat(0), mRenderer))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000735 {
Jamie Madillf8989902013-07-19 16:36:58 -0400736 if (samplerState.magFilter != GL_NEAREST ||
737 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000738 {
739 return false;
740 }
741 }
742
daniel@transgaming.comea32d482012-11-28 19:33:18 +0000743 bool npotSupport = mRenderer->getNonPower2TextureSupport();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000744
745 if (!npotSupport)
746 {
Jamie Madillf8989902013-07-19 16:36:58 -0400747 if ((samplerState.wrapS != GL_CLAMP_TO_EDGE && !isPow2(width)) ||
748 (samplerState.wrapT != GL_CLAMP_TO_EDGE && !isPow2(height)))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000749 {
750 return false;
751 }
752 }
753
Jamie Madillf8989902013-07-19 16:36:58 -0400754 if (IsMipmapFiltered(samplerState))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000755 {
756 if (!npotSupport)
757 {
758 if (!isPow2(width) || !isPow2(height))
759 {
760 return false;
761 }
762 }
763
764 if (!isMipmapComplete())
765 {
766 return false;
767 }
768 }
769
Geoff Langc82fc412013-07-10 14:43:42 -0400770 // OpenGLES 3.0.2 spec section 3.8.13 states that a texture is not mipmap complete if:
771 // The internalformat specified for the texture arrays is a sized internal depth or
772 // depth and stencil format (see table 3.13), the value of TEXTURE_COMPARE_-
773 // MODE is NONE, and either the magnification filter is not NEAREST or the mini-
774 // fication filter is neither NEAREST nor NEAREST_MIPMAP_NEAREST.
775 if (gl::GetDepthBits(getInternalFormat(0), mRenderer->getCurrentClientVersion()) > 0)
776 {
777 if (mSamplerState.compareMode == GL_NONE)
778 {
779 if ((mSamplerState.minFilter != GL_NEAREST && mSamplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST) ||
780 mSamplerState.magFilter != GL_NEAREST)
781 {
782 return false;
783 }
784 }
785 }
786
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000787 return true;
788}
789
790// Tests for 2D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
791bool Texture2D::isMipmapComplete() const
792{
Jamie Madill22f843a2013-10-24 17:49:36 -0400793 int q = mipLevels();
Jamie Madill07edd442013-07-19 16:36:58 -0400794
795 for (int level = 0; level <= q; level++)
796 {
797 if (!isLevelComplete(level))
798 {
799 return false;
800 }
801 }
802
803 return true;
804}
805
806bool Texture2D::isLevelComplete(int level) const
807{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000808 if (isImmutable())
809 {
810 return true;
811 }
812
Jamie Madilld3d2a342013-10-07 10:46:35 -0400813 GLsizei width = getBaseLevelWidth();
814 GLsizei height = getBaseLevelHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000815
816 if (width <= 0 || height <= 0)
817 {
818 return false;
819 }
820
Jamie Madill07edd442013-07-19 16:36:58 -0400821 // The base image level is complete if the width and height are positive
822 if (level == 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000823 {
Jamie Madill07edd442013-07-19 16:36:58 -0400824 return true;
825 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000826
Jamie Madill07edd442013-07-19 16:36:58 -0400827 ASSERT(level >= 1 && level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
828 rx::Image *image = mImageArray[level];
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000829
Jamie Madilld3d2a342013-10-07 10:46:35 -0400830 if (image->getInternalFormat() != getBaseLevelInternalFormat())
Jamie Madill07edd442013-07-19 16:36:58 -0400831 {
832 return false;
833 }
834
835 if (image->getWidth() != std::max(1, width >> level))
836 {
837 return false;
838 }
839
840 if (image->getHeight() != std::max(1, height >> level))
841 {
842 return false;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000843 }
844
845 return true;
846}
847
848bool Texture2D::isCompressed(GLint level) const
849{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000850 return IsFormatCompressed(getInternalFormat(level), mRenderer->getCurrentClientVersion());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000851}
852
853bool Texture2D::isDepth(GLint level) const
854{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000855 return GetDepthBits(getInternalFormat(level), mRenderer->getCurrentClientVersion()) > 0;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000856}
857
daniel@transgaming.comf032cb82012-10-31 19:51:52 +0000858// Constructs a native texture resource from the texture images
Jamie Madill73b5d062013-10-24 17:49:38 -0400859void Texture2D::initializeStorage(bool renderTarget)
860{
861 // Only initialize the first time this texture is used as a render target or shader resource
862 if (mTexStorage)
863 {
864 return;
865 }
866
867 // do not attempt to create storage for nonexistant data
868 if (!isLevelComplete(0))
869 {
870 return;
871 }
872
873 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
874
875 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
876 ASSERT(mTexStorage);
877
878 // flush image data to the storage
879 updateStorage();
880}
881
882rx::TextureStorageInterface2D *Texture2D::createCompleteStorage(bool renderTarget) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000883{
Jamie Madilld3d2a342013-10-07 10:46:35 -0400884 GLsizei width = getBaseLevelWidth();
885 GLsizei height = getBaseLevelHeight();
daniel@transgaming.come6a09842012-09-17 21:28:55 +0000886
Jamie Madill73b5d062013-10-24 17:49:38 -0400887 ASSERT(width > 0 && height > 0);
daniel@transgaming.come6a09842012-09-17 21:28:55 +0000888
Jamie Madill73b5d062013-10-24 17:49:38 -0400889 // use existing storage level count, when previously specified by TexStorage*D
Jamie Madill6b7440c2013-10-24 17:49:47 -0400890 GLint levels = (mTexStorage ? mTexStorage->getMaxLevel() : creationLevels(width, height, 1));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000891
Jamie Madill4cfff5f2013-10-24 17:49:46 -0400892 return new rx::TextureStorageInterface2D(mRenderer, 0, levels, getBaseLevelInternalFormat(), renderTarget, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000893}
894
Jamie Madill169d1112013-10-24 17:49:37 -0400895void Texture2D::updateStorage()
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000896{
Jamie Madill4cfff5f2013-10-24 17:49:46 -0400897 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000898 {
Jamie Madilld9b9a502013-10-10 17:46:13 -0400899 if (isLevelComplete(level))
900 {
Jamie Madill169d1112013-10-24 17:49:37 -0400901 updateStorageLevel(level);
Jamie Madilld9b9a502013-10-10 17:46:13 -0400902 }
Jamie Madill07edd442013-07-19 16:36:58 -0400903 }
904}
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000905
Jamie Madill169d1112013-10-24 17:49:37 -0400906void Texture2D::updateStorageLevel(int level)
Jamie Madill07edd442013-07-19 16:36:58 -0400907{
908 ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
Jamie Madillaee7ad82013-10-10 16:07:32 -0400909 ASSERT(isLevelComplete(level));
Jamie Madill07edd442013-07-19 16:36:58 -0400910
Jamie Madillaee7ad82013-10-10 16:07:32 -0400911 if (mImageArray[level]->isDirty())
Jamie Madill07edd442013-07-19 16:36:58 -0400912 {
Jamie Madillaee7ad82013-10-10 16:07:32 -0400913 commitRect(level, 0, 0, getWidth(level), getHeight(level));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000914 }
915}
916
Jamie Madille83d1a92013-10-24 17:49:33 -0400917bool Texture2D::ensureRenderTarget()
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000918{
Jamie Madill73b5d062013-10-24 17:49:38 -0400919 initializeStorage(true);
920
921 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0)
Jamie Madille83d1a92013-10-24 17:49:33 -0400922 {
Jamie Madill73b5d062013-10-24 17:49:38 -0400923 ASSERT(mTexStorage);
924 if (!mTexStorage->isRenderTarget())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000925 {
Jamie Madill73b5d062013-10-24 17:49:38 -0400926 rx::TextureStorageInterface2D *newRenderTargetStorage = createCompleteStorage(true);
927
928 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
929 {
930 delete newRenderTargetStorage;
Jamie Madille83d1a92013-10-24 17:49:33 -0400931 return gl::error(GL_OUT_OF_MEMORY, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000932 }
Jamie Madill73b5d062013-10-24 17:49:38 -0400933
934 setCompleteTexStorage(newRenderTargetStorage);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000935 }
936 }
937
Jamie Madille83d1a92013-10-24 17:49:33 -0400938 return (mTexStorage && mTexStorage->isRenderTarget());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000939}
940
941void Texture2D::generateMipmaps()
942{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000943 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Jamie Madill22f843a2013-10-24 17:49:36 -0400944 int q = mipLevels();
945 for (int level = 1; level <= q; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000946 {
Jamie Madill22f843a2013-10-24 17:49:36 -0400947 redefineImage(level, getBaseLevelInternalFormat(),
948 std::max(getBaseLevelWidth() >> level, 1),
949 std::max(getBaseLevelHeight() >> level, 1));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000950 }
951
952 if (mTexStorage && mTexStorage->isRenderTarget())
953 {
Jamie Madill22f843a2013-10-24 17:49:36 -0400954 for (int level = 1; level <= q; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000955 {
Jamie Madill22f843a2013-10-24 17:49:36 -0400956 mTexStorage->generateMipmap(level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000957
Jamie Madill22f843a2013-10-24 17:49:36 -0400958 mImageArray[level]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000959 }
960 }
961 else
962 {
Jamie Madill22f843a2013-10-24 17:49:36 -0400963 for (int level = 1; level <= q; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000964 {
Jamie Madill22f843a2013-10-24 17:49:36 -0400965 mRenderer->generateMipmap(mImageArray[level], mImageArray[level - 1]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000966 }
967 }
968}
969
Jamie Madilld3d2a342013-10-07 10:46:35 -0400970const rx::Image *Texture2D::getBaseLevelImage() const
971{
972 return mImageArray[0];
973}
974
Jamie Madill2ebab852013-10-24 17:49:42 -0400975rx::TextureStorageInterface *Texture2D::getBaseLevelStorage()
976{
977 return mTexStorage;
978}
979
Geoff Lang8040f572013-07-25 16:49:54 -0400980Renderbuffer *Texture2D::getRenderbuffer(GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000981{
Geoff Lang8040f572013-07-25 16:49:54 -0400982 Renderbuffer *renderBuffer = mRenderbufferProxies.get(level, 0);
983 if (!renderBuffer)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000984 {
Geoff Lang8040f572013-07-25 16:49:54 -0400985 renderBuffer = new Renderbuffer(mRenderer, id(), new RenderbufferTexture2D(this, level));
986 mRenderbufferProxies.add(level, 0, renderBuffer);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000987 }
988
Geoff Lang8040f572013-07-25 16:49:54 -0400989 return renderBuffer;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000990}
991
Geoff Lang8040f572013-07-25 16:49:54 -0400992unsigned int Texture2D::getRenderTargetSerial(GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000993{
Jamie Madille83d1a92013-10-24 17:49:33 -0400994 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(level) : 0);
Geoff Lang8040f572013-07-25 16:49:54 -0400995}
996
997rx::RenderTarget *Texture2D::getRenderTarget(GLint level)
998{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000999 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04001000 if (!ensureRenderTarget())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001001 {
1002 return NULL;
1003 }
1004
Jamie Madill169d1112013-10-24 17:49:37 -04001005 updateStorageLevel(level);
Geoff Lang8040f572013-07-25 16:49:54 -04001006
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001007 // ensure this is NOT a depth texture
Geoff Lang8040f572013-07-25 16:49:54 -04001008 if (isDepth(level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001009 {
1010 return NULL;
1011 }
daniel@transgaming.com34da3972012-12-20 21:10:29 +00001012
Geoff Lang8040f572013-07-25 16:49:54 -04001013 return mTexStorage->getRenderTarget(level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001014}
1015
Geoff Lang8040f572013-07-25 16:49:54 -04001016rx::RenderTarget *Texture2D::getDepthSencil(GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001017{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001018 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04001019 if (!ensureRenderTarget())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001020 {
1021 return NULL;
1022 }
1023
Jamie Madill169d1112013-10-24 17:49:37 -04001024 updateStorageLevel(level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001025
1026 // ensure this is actually a depth texture
Geoff Lang8040f572013-07-25 16:49:54 -04001027 if (!isDepth(level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001028 {
1029 return NULL;
1030 }
Geoff Lang8040f572013-07-25 16:49:54 -04001031
1032 return mTexStorage->getRenderTarget(level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001033}
1034
Jamie Madill07bb8cf2013-10-24 17:49:44 -04001035bool Texture2D::isValidLevel(int level) const
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +00001036{
Jamie Madill4cfff5f2013-10-24 17:49:46 -04001037 return (mTexStorage ? (level >= mTexStorage->getBaseLevel() && level < mTexStorage->getMaxLevel()) : false);
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +00001038}
1039
Geoff Lang4907f2c2013-07-25 12:53:57 -04001040TextureCubeMap::TextureCubeMap(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_CUBE_MAP)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001041{
1042 mTexStorage = NULL;
1043 for (int i = 0; i < 6; i++)
1044 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001045 for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
1046 {
daniel@transgaming.com244e1832012-12-20 20:52:35 +00001047 mImageArray[i][j] = renderer->createImage();
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001048 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001049 }
1050}
1051
1052TextureCubeMap::~TextureCubeMap()
1053{
1054 for (int i = 0; i < 6; i++)
1055 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001056 for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
1057 {
1058 delete mImageArray[i][j];
1059 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001060 }
1061
1062 delete mTexStorage;
1063 mTexStorage = NULL;
1064}
1065
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001066GLsizei TextureCubeMap::getWidth(GLenum target, GLint level) const
1067{
1068 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Jamie Madill2db197c2013-10-24 17:49:35 -04001069 return mImageArray[targetToIndex(target)][level]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001070 else
1071 return 0;
1072}
1073
1074GLsizei TextureCubeMap::getHeight(GLenum target, GLint level) const
1075{
1076 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Jamie Madill2db197c2013-10-24 17:49:35 -04001077 return mImageArray[targetToIndex(target)][level]->getHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001078 else
1079 return 0;
1080}
1081
1082GLenum TextureCubeMap::getInternalFormat(GLenum target, GLint level) const
1083{
1084 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Jamie Madill2db197c2013-10-24 17:49:35 -04001085 return mImageArray[targetToIndex(target)][level]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001086 else
1087 return GL_NONE;
1088}
1089
daniel@transgaming.com20d36662012-10-31 19:51:43 +00001090GLenum TextureCubeMap::getActualFormat(GLenum target, GLint level) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001091{
1092 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Jamie Madill2db197c2013-10-24 17:49:35 -04001093 return mImageArray[targetToIndex(target)][level]->getActualFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001094 else
1095 return D3DFMT_UNKNOWN;
1096}
1097
Geoff Lang005df412013-10-16 14:12:50 -04001098void TextureCubeMap::setImagePosX(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001099{
Jamie Madill88f18f42013-09-18 14:36:19 -04001100 setImage(0, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001101}
1102
Geoff Lang005df412013-10-16 14:12:50 -04001103void TextureCubeMap::setImageNegX(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001104{
Jamie Madill88f18f42013-09-18 14:36:19 -04001105 setImage(1, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001106}
1107
Geoff Lang005df412013-10-16 14:12:50 -04001108void TextureCubeMap::setImagePosY(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001109{
Jamie Madill88f18f42013-09-18 14:36:19 -04001110 setImage(2, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001111}
1112
Geoff Lang005df412013-10-16 14:12:50 -04001113void TextureCubeMap::setImageNegY(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001114{
Jamie Madill88f18f42013-09-18 14:36:19 -04001115 setImage(3, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001116}
1117
Geoff Lang005df412013-10-16 14:12:50 -04001118void TextureCubeMap::setImagePosZ(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001119{
Jamie Madill88f18f42013-09-18 14:36:19 -04001120 setImage(4, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001121}
1122
Geoff Lang005df412013-10-16 14:12:50 -04001123void TextureCubeMap::setImageNegZ(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001124{
Jamie Madill88f18f42013-09-18 14:36:19 -04001125 setImage(5, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001126}
1127
Jamie Madill2db197c2013-10-24 17:49:35 -04001128void TextureCubeMap::setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001129{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001130 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
Jamie Madill2db197c2013-10-24 17:49:35 -04001131 int faceIndex = targetToIndex(target);
1132 redefineImage(faceIndex, level, format, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001133
Jamie Madill2db197c2013-10-24 17:49:35 -04001134 Texture::setCompressedImage(imageSize, pixels, mImageArray[faceIndex][level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001135}
1136
Jamie Madill2db197c2013-10-24 17:49:35 -04001137void TextureCubeMap::commitRect(int faceIndex, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001138{
Jamie Madill07bb8cf2013-10-24 17:49:44 -04001139 if (isValidFaceLevel(faceIndex, level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001140 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001141 rx::Image *image = mImageArray[faceIndex][level];
Jamie Madill169d1112013-10-24 17:49:37 -04001142 if (image->copyToStorage(mTexStorage, faceIndex, level, xoffset, yoffset, width, height))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001143 image->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001144 }
1145}
1146
Jamie Madill88f18f42013-09-18 14:36:19 -04001147void 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 +00001148{
Jamie Madill2db197c2013-10-24 17:49:35 -04001149 int faceIndex = targetToIndex(target);
1150 if (Texture::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, mImageArray[faceIndex][level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001151 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001152 commitRect(faceIndex, level, xoffset, yoffset, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001153 }
1154}
1155
1156void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1157{
Jamie Madill2db197c2013-10-24 17:49:35 -04001158 int faceIndex = targetToIndex(target);
1159 if (Texture::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[faceIndex][level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001160 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001161 commitRect(faceIndex, level, xoffset, yoffset, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001162 }
1163}
1164
1165// Tests for cube map sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 86.
Jamie Madillf8989902013-07-19 16:36:58 -04001166bool TextureCubeMap::isSamplerComplete(const SamplerState &samplerState) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001167{
Jamie Madilld3d2a342013-10-07 10:46:35 -04001168 int size = getBaseLevelWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001169
Jamie Madillf8989902013-07-19 16:36:58 -04001170 bool mipmapping = IsMipmapFiltered(samplerState);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001171
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001172 if (!IsTextureFilteringSupported(getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0), mRenderer))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001173 {
Jamie Madillf8989902013-07-19 16:36:58 -04001174 if (samplerState.magFilter != GL_NEAREST ||
1175 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001176 {
1177 return false;
1178 }
1179 }
1180
daniel@transgaming.comea32d482012-11-28 19:33:18 +00001181 if (!isPow2(size) && !mRenderer->getNonPower2TextureSupport())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001182 {
Jamie Madillf8989902013-07-19 16:36:58 -04001183 if (samplerState.wrapS != GL_CLAMP_TO_EDGE || samplerState.wrapT != GL_CLAMP_TO_EDGE || mipmapping)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001184 {
1185 return false;
1186 }
1187 }
1188
1189 if (!mipmapping)
1190 {
1191 if (!isCubeComplete())
1192 {
1193 return false;
1194 }
1195 }
1196 else
1197 {
1198 if (!isMipmapCubeComplete()) // Also tests for isCubeComplete()
1199 {
1200 return false;
1201 }
1202 }
1203
1204 return true;
1205}
1206
1207// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1208bool TextureCubeMap::isCubeComplete() const
1209{
Jamie Madillc1f8b162013-10-07 10:46:38 -04001210 int baseWidth = getBaseLevelWidth();
1211 int baseHeight = getBaseLevelHeight();
1212 GLenum baseFormat = getBaseLevelInternalFormat();
1213
1214 if (baseWidth <= 0 || baseWidth != baseHeight)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001215 {
1216 return false;
1217 }
1218
Jamie Madill2db197c2013-10-24 17:49:35 -04001219 for (int faceIndex = 1; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001220 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001221 const rx::Image &faceBaseImage = *mImageArray[faceIndex][0];
Jamie Madillc1f8b162013-10-07 10:46:38 -04001222
1223 if (faceBaseImage.getWidth() != baseWidth ||
1224 faceBaseImage.getHeight() != baseHeight ||
1225 faceBaseImage.getInternalFormat() != baseFormat )
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001226 {
1227 return false;
1228 }
1229 }
1230
1231 return true;
1232}
1233
1234bool TextureCubeMap::isMipmapCubeComplete() const
1235{
1236 if (isImmutable())
1237 {
1238 return true;
1239 }
1240
1241 if (!isCubeComplete())
1242 {
1243 return false;
1244 }
1245
Jamie Madill22f843a2013-10-24 17:49:36 -04001246 int q = mipLevels();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001247
1248 for (int face = 0; face < 6; face++)
1249 {
1250 for (int level = 1; level <= q; level++)
1251 {
Jamie Madill07edd442013-07-19 16:36:58 -04001252 if (!isFaceLevelComplete(face, level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001253 {
1254 return false;
1255 }
1256 }
1257 }
1258
1259 return true;
1260}
1261
Jamie Madill2db197c2013-10-24 17:49:35 -04001262bool TextureCubeMap::isFaceLevelComplete(int faceIndex, int level) const
Jamie Madill07edd442013-07-19 16:36:58 -04001263{
Jamie Madill2db197c2013-10-24 17:49:35 -04001264 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
Jamie Madill07edd442013-07-19 16:36:58 -04001265
1266 if (isImmutable())
1267 {
1268 return true;
1269 }
1270
Jamie Madilld3d2a342013-10-07 10:46:35 -04001271 int baseSize = getBaseLevelWidth();
Jamie Madill07edd442013-07-19 16:36:58 -04001272
Jamie Madilld3d2a342013-10-07 10:46:35 -04001273 if (baseSize <= 0)
Jamie Madill07edd442013-07-19 16:36:58 -04001274 {
1275 return false;
1276 }
1277
Jamie Madilld3d2a342013-10-07 10:46:35 -04001278 // "isCubeComplete" checks for base level completeness and we must call that
1279 // to determine if any face at level 0 is complete. We omit that check here
1280 // to avoid re-checking cube-completeness for every face at level 0.
Jamie Madill07edd442013-07-19 16:36:58 -04001281 if (level == 0)
1282 {
1283 return true;
1284 }
1285
Jamie Madilld3d2a342013-10-07 10:46:35 -04001286 // Check that non-zero levels are consistent with the base level.
Jamie Madill2db197c2013-10-24 17:49:35 -04001287 const rx::Image *faceLevelImage = mImageArray[faceIndex][level];
Jamie Madill07edd442013-07-19 16:36:58 -04001288
Jamie Madilld3d2a342013-10-07 10:46:35 -04001289 if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat())
Jamie Madill07edd442013-07-19 16:36:58 -04001290 {
1291 return false;
1292 }
1293
Jamie Madilld3d2a342013-10-07 10:46:35 -04001294 if (faceLevelImage->getWidth() != std::max(1, baseSize >> level))
Jamie Madill07edd442013-07-19 16:36:58 -04001295 {
1296 return false;
1297 }
1298
1299 return true;
1300}
1301
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001302bool TextureCubeMap::isCompressed(GLenum target, GLint level) const
1303{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001304 return IsFormatCompressed(getInternalFormat(target, level), mRenderer->getCurrentClientVersion());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001305}
1306
Geoff Lang8040f572013-07-25 16:49:54 -04001307bool TextureCubeMap::isDepth(GLenum target, GLint level) const
1308{
1309 return GetDepthBits(getInternalFormat(target, level), mRenderer->getCurrentClientVersion()) > 0;
1310}
1311
Jamie Madill73b5d062013-10-24 17:49:38 -04001312void TextureCubeMap::initializeStorage(bool renderTarget)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001313{
Jamie Madill3c0989c2013-10-24 17:49:39 -04001314 // Only initialize the first time this texture is used as a render target or shader resource
1315 if (mTexStorage)
1316 {
1317 return;
1318 }
1319
1320 // do not attempt to create storage for nonexistant data
1321 if (!isFaceLevelComplete(0, 0))
1322 {
1323 return;
1324 }
1325
1326 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
1327
1328 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
1329 ASSERT(mTexStorage);
1330
1331 // flush image data to the storage
1332 updateStorage();
1333}
1334
1335rx::TextureStorageInterfaceCube *TextureCubeMap::createCompleteStorage(bool renderTarget) const
1336{
Jamie Madilld3d2a342013-10-07 10:46:35 -04001337 GLsizei size = getBaseLevelWidth();
daniel@transgaming.come6a09842012-09-17 21:28:55 +00001338
Jamie Madill3c0989c2013-10-24 17:49:39 -04001339 ASSERT(size > 0);
daniel@transgaming.come6a09842012-09-17 21:28:55 +00001340
Jamie Madill3c0989c2013-10-24 17:49:39 -04001341 // use existing storage level count, when previously specified by TexStorage*D
Jamie Madill6b7440c2013-10-24 17:49:47 -04001342 GLint levels = (mTexStorage ? mTexStorage->getMaxLevel() : creationLevels(size, size, 1));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001343
Jamie Madill4cfff5f2013-10-24 17:49:46 -04001344 return new rx::TextureStorageInterfaceCube(mRenderer, 0, levels, getBaseLevelInternalFormat(), renderTarget, size);
Jamie Madill3c0989c2013-10-24 17:49:39 -04001345}
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001346
Jamie Madill3c0989c2013-10-24 17:49:39 -04001347void TextureCubeMap::setCompleteTexStorage(rx::TextureStorageInterfaceCube *newCompleteTexStorage)
1348{
1349 SafeDelete(mTexStorage);
1350 mTexStorage = newCompleteTexStorage;
1351
1352 if (mTexStorage && mTexStorage->isManaged())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001353 {
Jamie Madill4cfff5f2013-10-24 17:49:46 -04001354 int levels = mTexStorage->getMaxLevel();
1355
Jamie Madill2db197c2013-10-24 17:49:35 -04001356 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001357 {
Jamie Madill4cfff5f2013-10-24 17:49:46 -04001358 for (int level = 0; level < mTexStorage->getMaxLevel(); level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001359 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001360 mImageArray[faceIndex][level]->setManagedSurface(mTexStorage, faceIndex, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001361 }
1362 }
1363 }
1364
1365 mDirtyImages = true;
1366}
1367
Jamie Madill169d1112013-10-24 17:49:37 -04001368void TextureCubeMap::updateStorage()
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001369{
1370 for (int face = 0; face < 6; face++)
1371 {
Jamie Madill4cfff5f2013-10-24 17:49:46 -04001372 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001373 {
Jamie Madilld9b9a502013-10-10 17:46:13 -04001374 if (isFaceLevelComplete(face, level))
1375 {
Jamie Madill169d1112013-10-24 17:49:37 -04001376 updateStorageFaceLevel(face, level);
Jamie Madilld9b9a502013-10-10 17:46:13 -04001377 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001378 }
1379 }
1380}
1381
Jamie Madill169d1112013-10-24 17:49:37 -04001382void TextureCubeMap::updateStorageFaceLevel(int faceIndex, int level)
Jamie Madill07edd442013-07-19 16:36:58 -04001383{
Jamie Madill2db197c2013-10-24 17:49:35 -04001384 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1385 rx::Image *image = mImageArray[faceIndex][level];
Jamie Madill07edd442013-07-19 16:36:58 -04001386
1387 if (image->isDirty())
1388 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001389 commitRect(faceIndex, level, 0, 0, image->getWidth(), image->getHeight());
Jamie Madill07edd442013-07-19 16:36:58 -04001390 }
1391}
1392
Jamie Madille83d1a92013-10-24 17:49:33 -04001393bool TextureCubeMap::ensureRenderTarget()
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001394{
Jamie Madill3c0989c2013-10-24 17:49:39 -04001395 initializeStorage(true);
1396
1397 if (getBaseLevelWidth() > 0)
Jamie Madille83d1a92013-10-24 17:49:33 -04001398 {
Jamie Madill3c0989c2013-10-24 17:49:39 -04001399 ASSERT(mTexStorage);
1400 if (!mTexStorage->isRenderTarget())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001401 {
Jamie Madill3c0989c2013-10-24 17:49:39 -04001402 rx::TextureStorageInterfaceCube *newRenderTargetStorage = createCompleteStorage(true);
1403
1404 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001405 {
Jamie Madill3c0989c2013-10-24 17:49:39 -04001406 delete newRenderTargetStorage;
Jamie Madille83d1a92013-10-24 17:49:33 -04001407 return gl::error(GL_OUT_OF_MEMORY, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001408 }
Jamie Madill3c0989c2013-10-24 17:49:39 -04001409
1410 setCompleteTexStorage(newRenderTargetStorage);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001411 }
1412 }
1413
Jamie Madille83d1a92013-10-24 17:49:33 -04001414 return (mTexStorage && mTexStorage->isRenderTarget());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001415}
1416
Geoff Lang005df412013-10-16 14:12:50 -04001417void TextureCubeMap::setImage(int faceIndex, GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001418{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001419 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Geoff Lang005df412013-10-16 14:12:50 -04001420 GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
1421 : GetSizedInternalFormat(format, type, clientVersion);
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001422
1423 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001424
Jamie Madill88f18f42013-09-18 14:36:19 -04001425 Texture::setImage(unpack, type, pixels, mImageArray[faceIndex][level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001426}
1427
Jamie Madill2db197c2013-10-24 17:49:35 -04001428int TextureCubeMap::targetToIndex(GLenum target)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001429{
1430 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
1431 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
1432 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
1433 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
1434 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
1435
Jamie Madill2db197c2013-10-24 17:49:35 -04001436 return target - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001437}
1438
Jamie Madill2db197c2013-10-24 17:49:35 -04001439void TextureCubeMap::redefineImage(int faceIndex, GLint level, GLenum internalformat, GLsizei width, GLsizei height)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001440{
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001441 // If there currently is a corresponding storage texture image, it has these parameters
Jamie Madilld3d2a342013-10-07 10:46:35 -04001442 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1443 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
Geoff Lang005df412013-10-16 14:12:50 -04001444 const GLenum storageFormat = getBaseLevelInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001445
Jamie Madill2db197c2013-10-24 17:49:35 -04001446 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, width, height, 1, false);
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001447
1448 if (mTexStorage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001449 {
Jamie Madill4cfff5f2013-10-24 17:49:46 -04001450 const int storageLevels = mTexStorage->getMaxLevel();
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001451
1452 if ((level >= storageLevels && storageLevels != 0) ||
1453 width != storageWidth ||
1454 height != storageHeight ||
1455 internalformat != storageFormat) // Discard mismatched storage
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001456 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001457 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001458 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001459 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001460 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001461 mImageArray[faceIndex][level]->markDirty();
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001462 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001463 }
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001464
1465 delete mTexStorage;
1466 mTexStorage = NULL;
1467
1468 mDirtyImages = true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001469 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001470 }
1471}
1472
1473void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1474{
Jamie Madill2db197c2013-10-24 17:49:35 -04001475 int faceIndex = targetToIndex(target);
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001476 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Geoff Lang005df412013-10-16 14:12:50 -04001477 GLenum sizedInternalFormat = IsSizedInternalFormat(format, clientVersion) ? format
1478 : GetSizedInternalFormat(format, GL_UNSIGNED_BYTE, clientVersion);
Jamie Madill2db197c2013-10-24 17:49:35 -04001479 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001480
Jamie Madill2db197c2013-10-24 17:49:35 -04001481 if (!mImageArray[faceIndex][level]->isRenderableFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001482 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001483 mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001484 mDirtyImages = true;
1485 }
1486 else
1487 {
Jamie Madille83d1a92013-10-24 17:49:33 -04001488 ensureRenderTarget();
Jamie Madill2db197c2013-10-24 17:49:35 -04001489 mImageArray[faceIndex][level]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001490
1491 ASSERT(width == height);
1492
Jamie Madill07bb8cf2013-10-24 17:49:44 -04001493 if (width > 0 && isValidFaceLevel(faceIndex, level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001494 {
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +00001495 gl::Rectangle sourceRect;
1496 sourceRect.x = x;
1497 sourceRect.width = width;
1498 sourceRect.y = y;
1499 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001500
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +00001501 mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001502 }
1503 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001504}
1505
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001506void 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 +00001507{
Jamie Madill2db197c2013-10-24 17:49:35 -04001508 int faceIndex = targetToIndex(target);
1509
1510 GLsizei size = mImageArray[faceIndex][level]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001511
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001512 if (xoffset + width > size || yoffset + height > size || zoffset != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001513 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +00001514 return gl::error(GL_INVALID_VALUE);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001515 }
1516
Jamie Madilld3d2a342013-10-07 10:46:35 -04001517 // We can only make our texture storage to a render target if the level we're copying *to* is complete
1518 // and the base level is cube-complete. The base level must be cube complete (common case) because we cannot
1519 // rely on the "getBaseLevel*" methods reliably otherwise.
Jamie Madill2db197c2013-10-24 17:49:35 -04001520 bool canCreateRenderTarget = isFaceLevelComplete(faceIndex, level) && isCubeComplete();
Jamie Madill07edd442013-07-19 16:36:58 -04001521
Jamie Madill2db197c2013-10-24 17:49:35 -04001522 if (!mImageArray[faceIndex][level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001523 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001524 mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001525 mDirtyImages = true;
1526 }
1527 else
1528 {
Jamie Madille83d1a92013-10-24 17:49:33 -04001529 ensureRenderTarget();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001530
Jamie Madill07bb8cf2013-10-24 17:49:44 -04001531 if (isValidFaceLevel(faceIndex, level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001532 {
Jamie Madill169d1112013-10-24 17:49:37 -04001533 updateStorageFaceLevel(faceIndex, level);
Jamie Madill07edd442013-07-19 16:36:58 -04001534
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001535 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1536
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +00001537 gl::Rectangle sourceRect;
1538 sourceRect.x = x;
1539 sourceRect.width = width;
1540 sourceRect.y = y;
1541 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001542
Jamie Madilld3d2a342013-10-07 10:46:35 -04001543 mRenderer->copyImage(source, sourceRect, gl::GetFormat(getBaseLevelInternalFormat(), clientVersion),
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +00001544 xoffset, yoffset, mTexStorage, target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001545 }
1546 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001547}
1548
1549void TextureCubeMap::storage(GLsizei levels, GLenum internalformat, GLsizei size)
1550{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001551 for (int level = 0; level < levels; level++)
1552 {
Geoff Langd3110192013-09-24 11:52:47 -04001553 GLsizei mipSize = std::max(1, size >> level);
Jamie Madill2db197c2013-10-24 17:49:35 -04001554 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001555 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001556 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, mipSize, mipSize, 1, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001557 }
1558 }
1559
1560 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1561 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001562 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001563 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001564 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, GL_NONE, 0, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001565 }
1566 }
1567
Jamie Madill3c0989c2013-10-24 17:49:39 -04001568 mImmutable = true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001569
Jamie Madill4cfff5f2013-10-24 17:49:46 -04001570 setCompleteTexStorage(new rx::TextureStorageInterfaceCube(mRenderer, 0, levels, internalformat, IsRenderTargetUsage(mUsage), size));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001571}
1572
1573void TextureCubeMap::generateMipmaps()
1574{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001575 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Jamie Madill22f843a2013-10-24 17:49:36 -04001576 int q = mipLevels();
Jamie Madill2db197c2013-10-24 17:49:35 -04001577 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001578 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001579 for (int level = 1; level <= q; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001580 {
Jamie Madill22f843a2013-10-24 17:49:36 -04001581 int faceLevelSize = (std::max(mImageArray[faceIndex][0]->getWidth() >> level, 1));
1582 redefineImage(faceIndex, level, mImageArray[faceIndex][0]->getInternalFormat(), faceLevelSize, faceLevelSize);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001583 }
1584 }
1585
1586 if (mTexStorage && mTexStorage->isRenderTarget())
1587 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001588 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001589 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001590 for (int level = 1; level <= q; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001591 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001592 mTexStorage->generateMipmap(faceIndex, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001593
Jamie Madill2db197c2013-10-24 17:49:35 -04001594 mImageArray[faceIndex][level]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001595 }
1596 }
1597 }
1598 else
1599 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001600 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001601 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001602 for (int level = 1; level <= q; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001603 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001604 mRenderer->generateMipmap(mImageArray[faceIndex][level], mImageArray[faceIndex][level - 1]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001605 }
1606 }
1607 }
1608}
1609
Jamie Madilld3d2a342013-10-07 10:46:35 -04001610const rx::Image *TextureCubeMap::getBaseLevelImage() const
1611{
1612 // Note: if we are not cube-complete, there is no single base level image that can describe all
1613 // cube faces, so this method is only well-defined for a cube-complete base level.
1614 return mImageArray[0][0];
1615}
1616
Jamie Madill2ebab852013-10-24 17:49:42 -04001617rx::TextureStorageInterface *TextureCubeMap::getBaseLevelStorage()
1618{
1619 return mTexStorage;
1620}
1621
Geoff Lang8040f572013-07-25 16:49:54 -04001622Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target, GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001623{
1624 if (!IsCubemapTextureTarget(target))
1625 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +00001626 return gl::error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001627 }
1628
Jamie Madill2db197c2013-10-24 17:49:35 -04001629 int faceIndex = targetToIndex(target);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001630
Jamie Madill2db197c2013-10-24 17:49:35 -04001631 Renderbuffer *renderBuffer = mRenderbufferProxies.get(level, faceIndex);
Geoff Lang8040f572013-07-25 16:49:54 -04001632 if (!renderBuffer)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001633 {
Geoff Lang8040f572013-07-25 16:49:54 -04001634 renderBuffer = new Renderbuffer(mRenderer, id(), new RenderbufferTextureCubeMap(this, target, level));
Jamie Madill2db197c2013-10-24 17:49:35 -04001635 mRenderbufferProxies.add(level, faceIndex, renderBuffer);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001636 }
1637
Geoff Lang8040f572013-07-25 16:49:54 -04001638 return renderBuffer;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001639}
1640
Jamie Madill2db197c2013-10-24 17:49:35 -04001641unsigned int TextureCubeMap::getRenderTargetSerial(GLenum target, GLint level)
Geoff Lang8040f572013-07-25 16:49:54 -04001642{
Jamie Madill2db197c2013-10-24 17:49:35 -04001643 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(target, level) : 0);
Geoff Lang8040f572013-07-25 16:49:54 -04001644}
1645
1646rx::RenderTarget *TextureCubeMap::getRenderTarget(GLenum target, GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001647{
1648 ASSERT(IsCubemapTextureTarget(target));
1649
1650 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04001651 if (!ensureRenderTarget())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001652 {
1653 return NULL;
1654 }
1655
Jamie Madill169d1112013-10-24 17:49:37 -04001656 updateStorageFaceLevel(targetToIndex(target), level);
Geoff Lang8040f572013-07-25 16:49:54 -04001657
1658 // ensure this is NOT a depth texture
1659 if (isDepth(target, level))
1660 {
1661 return NULL;
1662 }
1663
1664 return mTexStorage->getRenderTarget(target, level);
1665}
1666
1667rx::RenderTarget *TextureCubeMap::getDepthStencil(GLenum target, GLint level)
1668{
1669 ASSERT(IsCubemapTextureTarget(target));
1670
1671 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04001672 if (!ensureRenderTarget())
Geoff Lang8040f572013-07-25 16:49:54 -04001673 {
1674 return NULL;
1675 }
1676
Jamie Madill169d1112013-10-24 17:49:37 -04001677 updateStorageFaceLevel(targetToIndex(target), level);
Geoff Lang8040f572013-07-25 16:49:54 -04001678
1679 // ensure this is a depth texture
1680 if (!isDepth(target, level))
1681 {
1682 return NULL;
1683 }
1684
1685 return mTexStorage->getRenderTarget(target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001686}
1687
Jamie Madill07bb8cf2013-10-24 17:49:44 -04001688bool TextureCubeMap::isValidFaceLevel(int faceIndex, int level) const
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +00001689{
Jamie Madill4cfff5f2013-10-24 17:49:46 -04001690 return (mTexStorage ? (level >= mTexStorage->getBaseLevel() && level < mTexStorage->getMaxLevel()) : 0);
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +00001691}
1692
Geoff Lang4907f2c2013-07-25 12:53:57 -04001693Texture3D::Texture3D(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_3D)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001694{
1695 mTexStorage = NULL;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001696
1697 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1698 {
1699 mImageArray[i] = renderer->createImage();
1700 }
1701}
1702
1703Texture3D::~Texture3D()
1704{
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001705 delete mTexStorage;
1706 mTexStorage = NULL;
1707
1708 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1709 {
1710 delete mImageArray[i];
1711 }
1712}
1713
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001714GLsizei Texture3D::getWidth(GLint level) const
1715{
1716 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getWidth() : 0;
1717}
1718
1719GLsizei Texture3D::getHeight(GLint level) const
1720{
1721 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getHeight() : 0;
1722}
1723
1724GLsizei Texture3D::getDepth(GLint level) const
1725{
1726 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getDepth() : 0;
1727}
1728
1729GLenum Texture3D::getInternalFormat(GLint level) const
1730{
1731 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getInternalFormat() : GL_NONE;
1732}
1733
1734GLenum Texture3D::getActualFormat(GLint level) const
1735{
1736 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getActualFormat() : D3DFMT_UNKNOWN;
1737}
1738
1739bool Texture3D::isCompressed(GLint level) const
1740{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001741 return IsFormatCompressed(getInternalFormat(level), mRenderer->getCurrentClientVersion());
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001742}
1743
1744bool Texture3D::isDepth(GLint level) const
1745{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001746 return GetDepthBits(getInternalFormat(level), mRenderer->getCurrentClientVersion()) > 0;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001747}
1748
Geoff Lang005df412013-10-16 14:12:50 -04001749void Texture3D::setImage(GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001750{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001751 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Geoff Lang005df412013-10-16 14:12:50 -04001752 GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
1753 : GetSizedInternalFormat(format, type, clientVersion);
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001754 redefineImage(level, sizedInternalFormat, width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001755
Jamie Madilla2d4e552013-10-10 15:12:01 -04001756 bool fastUnpacked = false;
1757
1758 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1759 if (isFastUnpackable(unpack, sizedInternalFormat))
1760 {
1761 // Will try to create RT storage if it does not exist
1762 rx::RenderTarget *destRenderTarget = getRenderTarget(level);
1763 Box destArea(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1764
1765 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget))
1766 {
1767 // Ensure we don't overwrite our newly initialized data
1768 mImageArray[level]->markClean();
1769
1770 fastUnpacked = true;
1771 }
1772 }
1773
1774 if (!fastUnpacked)
1775 {
1776 Texture::setImage(unpack, type, pixels, mImageArray[level]);
1777 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001778}
1779
1780void Texture3D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
1781{
1782 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1783 redefineImage(level, format, width, height, depth);
1784
1785 Texture::setCompressedImage(imageSize, pixels, mImageArray[level]);
1786}
1787
Jamie Madill88f18f42013-09-18 14:36:19 -04001788void 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 +00001789{
Jamie Madillba4f10a2013-10-10 15:12:20 -04001790 bool fastUnpacked = false;
1791
1792 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1793 if (isFastUnpackable(unpack, getInternalFormat(level)))
1794 {
1795 rx::RenderTarget *destRenderTarget = getRenderTarget(level);
1796 Box destArea(xoffset, yoffset, zoffset, width, height, depth);
1797
1798 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, destRenderTarget))
1799 {
1800 // Ensure we don't overwrite our newly initialized data
1801 mImageArray[level]->markClean();
1802
1803 fastUnpacked = true;
1804 }
1805 }
1806
1807 if (!fastUnpacked && Texture::subImage(xoffset, yoffset, zoffset, width, height, depth, format, type, unpack, pixels, mImageArray[level]))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001808 {
1809 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1810 }
1811}
1812
1813void Texture3D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
1814{
1815 if (Texture::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth, format, imageSize, pixels, mImageArray[level]))
1816 {
1817 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1818 }
1819}
1820
1821void Texture3D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
1822{
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001823 for (int level = 0; level < levels; level++)
1824 {
Jamie Madille664e202013-10-24 17:49:40 -04001825 GLsizei levelWidth = std::max(1, width >> level);
1826 GLsizei levelHeight = std::max(1, height >> level);
1827 GLsizei levelDepth = std::max(1, depth >> level);
1828 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, levelWidth, levelHeight, levelDepth, true);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001829 }
1830
1831 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1832 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001833 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, GL_NONE, 0, 0, 0, true);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001834 }
1835
Jamie Madille664e202013-10-24 17:49:40 -04001836 mImmutable = true;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001837
Jamie Madill4cfff5f2013-10-24 17:49:46 -04001838 setCompleteTexStorage(new rx::TextureStorageInterface3D(mRenderer, 0, levels, internalformat, IsRenderTargetUsage(mUsage), width, height, depth));
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001839}
1840
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001841void Texture3D::generateMipmaps()
1842{
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001843 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Jamie Madill22f843a2013-10-24 17:49:36 -04001844 int q = mipLevels();
1845 for (int level = 1; level <= q; level++)
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001846 {
Jamie Madill22f843a2013-10-24 17:49:36 -04001847 redefineImage(level, getBaseLevelInternalFormat(),
1848 std::max(getBaseLevelWidth() >> level, 1),
1849 std::max(getBaseLevelHeight() >> level, 1),
1850 std::max(getBaseLevelDepth() >> level, 1));
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001851 }
1852
1853 if (mTexStorage && mTexStorage->isRenderTarget())
1854 {
Jamie Madill22f843a2013-10-24 17:49:36 -04001855 for (int level = 1; level <= q; level++)
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001856 {
Jamie Madill22f843a2013-10-24 17:49:36 -04001857 mTexStorage->generateMipmap(level);
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001858
Jamie Madill22f843a2013-10-24 17:49:36 -04001859 mImageArray[level]->markClean();
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001860 }
1861 }
1862 else
1863 {
Jamie Madill22f843a2013-10-24 17:49:36 -04001864 for (int level = 1; level <= q; level++)
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001865 {
Jamie Madill22f843a2013-10-24 17:49:36 -04001866 mRenderer->generateMipmap(mImageArray[level], mImageArray[level - 1]);
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001867 }
1868 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001869}
1870
Jamie Madilld3d2a342013-10-07 10:46:35 -04001871const rx::Image *Texture3D::getBaseLevelImage() const
1872{
1873 return mImageArray[0];
1874}
1875
Jamie Madill2ebab852013-10-24 17:49:42 -04001876rx::TextureStorageInterface *Texture3D::getBaseLevelStorage()
1877{
1878 return mTexStorage;
1879}
1880
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001881void Texture3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1882{
1883 if (xoffset + width > mImageArray[level]->getWidth() || yoffset + height > mImageArray[level]->getHeight() || zoffset >= mImageArray[level]->getDepth())
1884 {
1885 return gl::error(GL_INVALID_VALUE);
1886 }
1887
Jamie Madill07edd442013-07-19 16:36:58 -04001888 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
1889 // the current level we're copying to is defined (with appropriate format, width & height)
1890 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
1891
1892 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001893 {
1894 mImageArray[level]->copy(xoffset, yoffset, zoffset, x, y, width, height, source);
1895 mDirtyImages = true;
1896 }
1897 else
1898 {
Jamie Madille83d1a92013-10-24 17:49:33 -04001899 ensureRenderTarget();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001900
Jamie Madill07bb8cf2013-10-24 17:49:44 -04001901 if (isValidLevel(level))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001902 {
Jamie Madill169d1112013-10-24 17:49:37 -04001903 updateStorageLevel(level);
Jamie Madill07edd442013-07-19 16:36:58 -04001904
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001905 gl::Rectangle sourceRect;
1906 sourceRect.x = x;
1907 sourceRect.width = width;
1908 sourceRect.y = y;
1909 sourceRect.height = height;
1910
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001911 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1912
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001913 mRenderer->copyImage(source, sourceRect,
Jamie Madilld3d2a342013-10-07 10:46:35 -04001914 gl::GetFormat(getBaseLevelInternalFormat(), clientVersion),
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001915 xoffset, yoffset, zoffset, mTexStorage, level);
1916 }
1917 }
1918}
1919
Jamie Madillf8989902013-07-19 16:36:58 -04001920bool Texture3D::isSamplerComplete(const SamplerState &samplerState) const
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001921{
Jamie Madilld3d2a342013-10-07 10:46:35 -04001922 GLsizei width = getBaseLevelWidth();
1923 GLsizei height = getBaseLevelHeight();
1924 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001925
1926 if (width <= 0 || height <= 0 || depth <= 0)
1927 {
1928 return false;
1929 }
1930
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001931 if (!IsTextureFilteringSupported(getInternalFormat(0), mRenderer))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001932 {
Jamie Madillf8989902013-07-19 16:36:58 -04001933 if (samplerState.magFilter != GL_NEAREST ||
1934 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001935 {
1936 return false;
1937 }
1938 }
1939
Jamie Madillf8989902013-07-19 16:36:58 -04001940 if (IsMipmapFiltered(samplerState) && !isMipmapComplete())
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001941 {
1942 return false;
1943 }
1944
1945 return true;
1946}
1947
1948bool Texture3D::isMipmapComplete() const
1949{
Jamie Madill22f843a2013-10-24 17:49:36 -04001950 int q = mipLevels();
Jamie Madill07edd442013-07-19 16:36:58 -04001951
1952 for (int level = 0; level <= q; level++)
1953 {
1954 if (!isLevelComplete(level))
1955 {
1956 return false;
1957 }
1958 }
1959
1960 return true;
1961}
1962
1963bool Texture3D::isLevelComplete(int level) const
1964{
1965 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1966
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001967 if (isImmutable())
1968 {
1969 return true;
1970 }
1971
Jamie Madilld3d2a342013-10-07 10:46:35 -04001972 GLsizei width = getBaseLevelWidth();
1973 GLsizei height = getBaseLevelHeight();
1974 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001975
1976 if (width <= 0 || height <= 0 || depth <= 0)
1977 {
1978 return false;
1979 }
1980
Jamie Madill07edd442013-07-19 16:36:58 -04001981 if (level == 0)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001982 {
Jamie Madill07edd442013-07-19 16:36:58 -04001983 return true;
1984 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001985
Jamie Madill07edd442013-07-19 16:36:58 -04001986 rx::Image *levelImage = mImageArray[level];
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001987
Jamie Madilld3d2a342013-10-07 10:46:35 -04001988 if (levelImage->getInternalFormat() != getBaseLevelInternalFormat())
Jamie Madill07edd442013-07-19 16:36:58 -04001989 {
1990 return false;
1991 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001992
Jamie Madill07edd442013-07-19 16:36:58 -04001993 if (levelImage->getWidth() != std::max(1, width >> level))
1994 {
1995 return false;
1996 }
1997
1998 if (levelImage->getHeight() != std::max(1, height >> level))
1999 {
2000 return false;
2001 }
2002
2003 if (levelImage->getDepth() != std::max(1, depth >> level))
2004 {
2005 return false;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002006 }
2007
2008 return true;
2009}
2010
Geoff Lang8040f572013-07-25 16:49:54 -04002011Renderbuffer *Texture3D::getRenderbuffer(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002012{
Geoff Lang8040f572013-07-25 16:49:54 -04002013 Renderbuffer *renderBuffer = mRenderbufferProxies.get(level, layer);
2014 if (!renderBuffer)
2015 {
Geoff Langd5d8e392013-07-25 16:53:03 -04002016 renderBuffer = new Renderbuffer(mRenderer, id(), new RenderbufferTexture3DLayer(this, level, layer));
2017 mRenderbufferProxies.add(level, 0, renderBuffer);
Geoff Lang8040f572013-07-25 16:49:54 -04002018 }
2019
2020 return renderBuffer;
2021}
2022
2023unsigned int Texture3D::getRenderTargetSerial(GLint level, GLint layer)
2024{
Jamie Madille83d1a92013-10-24 17:49:33 -04002025 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(level, layer) : 0);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002026}
2027
Jamie Madill07bb8cf2013-10-24 17:49:44 -04002028bool Texture3D::isValidLevel(int level) const
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002029{
Jamie Madill4cfff5f2013-10-24 17:49:46 -04002030 return (mTexStorage ? (level >= mTexStorage->getBaseLevel() && level < mTexStorage->getMaxLevel()) : 0);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002031}
2032
Jamie Madill73b5d062013-10-24 17:49:38 -04002033void Texture3D::initializeStorage(bool renderTarget)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002034{
Jamie Madille664e202013-10-24 17:49:40 -04002035 // Only initialize the first time this texture is used as a render target or shader resource
2036 if (mTexStorage)
2037 {
2038 return;
2039 }
2040
2041 // do not attempt to create storage for nonexistant data
2042 if (!isLevelComplete(0))
2043 {
2044 return;
2045 }
2046
2047 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
2048
2049 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
2050 ASSERT(mTexStorage);
2051
2052 // flush image data to the storage
2053 updateStorage();
2054}
2055
2056rx::TextureStorageInterface3D *Texture3D::createCompleteStorage(bool renderTarget) const
2057{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002058 GLsizei width = getBaseLevelWidth();
2059 GLsizei height = getBaseLevelHeight();
2060 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002061
Jamie Madille664e202013-10-24 17:49:40 -04002062 ASSERT(width > 0 && height > 0 && depth > 0);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002063
Jamie Madille664e202013-10-24 17:49:40 -04002064 // use existing storage level count, when previously specified by TexStorage*D
Jamie Madill4cfff5f2013-10-24 17:49:46 -04002065 GLint levels = (mTexStorage ? mTexStorage->getMaxLevel() : creationLevels(width, height, depth));
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002066
Jamie Madill4cfff5f2013-10-24 17:49:46 -04002067 return new rx::TextureStorageInterface3D(mRenderer, 0, levels, getBaseLevelInternalFormat(), renderTarget, width, height, depth);
Jamie Madille664e202013-10-24 17:49:40 -04002068}
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002069
Jamie Madille664e202013-10-24 17:49:40 -04002070void Texture3D::setCompleteTexStorage(rx::TextureStorageInterface3D *newCompleteTexStorage)
2071{
2072 SafeDelete(mTexStorage);
2073 mTexStorage = newCompleteTexStorage;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002074 mDirtyImages = true;
Jamie Madille664e202013-10-24 17:49:40 -04002075
2076 // We do not support managed 3D storage, as that is D3D9/ES2-only
2077 ASSERT(!mTexStorage->isManaged());
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002078}
2079
Jamie Madill169d1112013-10-24 17:49:37 -04002080void Texture3D::updateStorage()
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002081{
Jamie Madill4cfff5f2013-10-24 17:49:46 -04002082 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002083 {
Jamie Madilld9b9a502013-10-10 17:46:13 -04002084 if (isLevelComplete(level))
2085 {
Jamie Madill169d1112013-10-24 17:49:37 -04002086 updateStorageLevel(level);
Jamie Madilld9b9a502013-10-10 17:46:13 -04002087 }
Jamie Madill07edd442013-07-19 16:36:58 -04002088 }
2089}
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002090
Jamie Madill169d1112013-10-24 17:49:37 -04002091void Texture3D::updateStorageLevel(int level)
Jamie Madill07edd442013-07-19 16:36:58 -04002092{
2093 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
Jamie Madillaee7ad82013-10-10 16:07:32 -04002094 ASSERT(isLevelComplete(level));
Jamie Madill07edd442013-07-19 16:36:58 -04002095
Jamie Madillaee7ad82013-10-10 16:07:32 -04002096 if (mImageArray[level]->isDirty())
Jamie Madill07edd442013-07-19 16:36:58 -04002097 {
Jamie Madillaee7ad82013-10-10 16:07:32 -04002098 commitRect(level, 0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002099 }
2100}
2101
Jamie Madille83d1a92013-10-24 17:49:33 -04002102bool Texture3D::ensureRenderTarget()
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002103{
Jamie Madille664e202013-10-24 17:49:40 -04002104 initializeStorage(true);
2105
2106 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0 && getBaseLevelDepth() > 0)
Jamie Madille83d1a92013-10-24 17:49:33 -04002107 {
Jamie Madille664e202013-10-24 17:49:40 -04002108 ASSERT(mTexStorage);
2109 if (!mTexStorage->isRenderTarget())
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002110 {
Jamie Madille664e202013-10-24 17:49:40 -04002111 rx::TextureStorageInterface3D *newRenderTargetStorage = createCompleteStorage(true);
2112
2113 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002114 {
Jamie Madille664e202013-10-24 17:49:40 -04002115 delete newRenderTargetStorage;
Jamie Madille83d1a92013-10-24 17:49:33 -04002116 return gl::error(GL_OUT_OF_MEMORY, false);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002117 }
Jamie Madille664e202013-10-24 17:49:40 -04002118
2119 setCompleteTexStorage(newRenderTargetStorage);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002120 }
2121 }
2122
Jamie Madille83d1a92013-10-24 17:49:33 -04002123 return (mTexStorage && mTexStorage->isRenderTarget());
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002124}
2125
Jamie Madilla2d4e552013-10-10 15:12:01 -04002126rx::RenderTarget *Texture3D::getRenderTarget(GLint level)
2127{
2128 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04002129 if (!ensureRenderTarget())
Jamie Madilla2d4e552013-10-10 15:12:01 -04002130 {
2131 return NULL;
2132 }
2133
Jamie Madill169d1112013-10-24 17:49:37 -04002134 updateStorageLevel(level);
Jamie Madilla2d4e552013-10-10 15:12:01 -04002135
2136 // ensure this is NOT a depth texture
2137 if (isDepth(level))
2138 {
2139 return NULL;
2140 }
2141
2142 return mTexStorage->getRenderTarget(level);
2143}
2144
Geoff Lang8040f572013-07-25 16:49:54 -04002145rx::RenderTarget *Texture3D::getRenderTarget(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002146{
Geoff Lang8040f572013-07-25 16:49:54 -04002147 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04002148 if (!ensureRenderTarget())
Geoff Lang8040f572013-07-25 16:49:54 -04002149 {
2150 return NULL;
2151 }
2152
Jamie Madill169d1112013-10-24 17:49:37 -04002153 updateStorage();
Geoff Lang8040f572013-07-25 16:49:54 -04002154
2155 // ensure this is NOT a depth texture
2156 if (isDepth(level))
2157 {
2158 return NULL;
2159 }
2160
2161 return mTexStorage->getRenderTarget(level, layer);
2162}
2163
2164rx::RenderTarget *Texture3D::getDepthStencil(GLint level, GLint layer)
2165{
2166 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04002167 if (!ensureRenderTarget())
Geoff Lang8040f572013-07-25 16:49:54 -04002168 {
2169 return NULL;
2170 }
2171
Jamie Madill169d1112013-10-24 17:49:37 -04002172 updateStorageLevel(level);
Geoff Lang8040f572013-07-25 16:49:54 -04002173
2174 // ensure this is a depth texture
2175 if (!isDepth(level))
2176 {
2177 return NULL;
2178 }
2179
2180 return mTexStorage->getRenderTarget(level, layer);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002181}
2182
Geoff Lang005df412013-10-16 14:12:50 -04002183void Texture3D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002184{
2185 // If there currently is a corresponding storage texture image, it has these parameters
Jamie Madilld3d2a342013-10-07 10:46:35 -04002186 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2187 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
2188 const int storageDepth = std::max(1, getBaseLevelDepth() >> level);
Geoff Lang005df412013-10-16 14:12:50 -04002189 const GLenum storageFormat = getBaseLevelInternalFormat();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002190
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00002191 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, false);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002192
2193 if (mTexStorage)
2194 {
Jamie Madill4cfff5f2013-10-24 17:49:46 -04002195 const int storageLevels = mTexStorage->getMaxLevel();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002196
2197 if ((level >= storageLevels && storageLevels != 0) ||
2198 width != storageWidth ||
2199 height != storageHeight ||
2200 depth != storageDepth ||
2201 internalformat != storageFormat) // Discard mismatched storage
2202 {
2203 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
2204 {
2205 mImageArray[i]->markDirty();
2206 }
2207
2208 delete mTexStorage;
2209 mTexStorage = NULL;
2210 mDirtyImages = true;
2211 }
2212 }
2213}
2214
2215void Texture3D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth)
2216{
Jamie Madill07bb8cf2013-10-24 17:49:44 -04002217 if (isValidLevel(level))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002218 {
2219 rx::Image *image = mImageArray[level];
Jamie Madill169d1112013-10-24 17:49:37 -04002220 if (image->copyToStorage(mTexStorage, level, xoffset, yoffset, zoffset, width, height, depth))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002221 {
2222 image->markClean();
2223 }
2224 }
2225}
2226
Geoff Lang4907f2c2013-07-25 12:53:57 -04002227Texture2DArray::Texture2DArray(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_2D_ARRAY)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002228{
2229 mTexStorage = NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002230
2231 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2232 {
2233 mLayerCounts[level] = 0;
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002234 mImageArray[level] = NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002235 }
2236}
2237
2238Texture2DArray::~Texture2DArray()
2239{
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002240 delete mTexStorage;
2241 mTexStorage = NULL;
Jamie Madill884a4622013-10-24 17:49:41 -04002242
2243 deleteImages();
2244}
2245
2246void Texture2DArray::deleteImages()
2247{
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002248 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2249 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002250 for (int layer = 0; layer < mLayerCounts[level]; ++layer)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002251 {
2252 delete mImageArray[level][layer];
2253 }
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002254 delete[] mImageArray[level];
Jamie Madill884a4622013-10-24 17:49:41 -04002255 mImageArray[level] = NULL;
2256 mLayerCounts[level] = 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002257 }
2258}
2259
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002260GLsizei Texture2DArray::getWidth(GLint level) const
2261{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002262 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 +00002263}
2264
2265GLsizei Texture2DArray::getHeight(GLint level) const
2266{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002267 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getHeight() : 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002268}
2269
2270GLsizei Texture2DArray::getDepth(GLint level) const
2271{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002272 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mLayerCounts[level] : 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002273}
2274
2275GLenum Texture2DArray::getInternalFormat(GLint level) const
2276{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002277 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 +00002278}
2279
2280GLenum Texture2DArray::getActualFormat(GLint level) const
2281{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002282 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 +00002283}
2284
2285bool Texture2DArray::isCompressed(GLint level) const
2286{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00002287 return IsFormatCompressed(getInternalFormat(level), mRenderer->getCurrentClientVersion());
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002288}
2289
2290bool Texture2DArray::isDepth(GLint level) const
2291{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00002292 return GetDepthBits(getInternalFormat(level), mRenderer->getCurrentClientVersion()) > 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002293}
2294
Geoff Lang005df412013-10-16 14:12:50 -04002295void Texture2DArray::setImage(GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002296{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00002297 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Geoff Lang005df412013-10-16 14:12:50 -04002298 GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
2299 : GetSizedInternalFormat(format, type, clientVersion);
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00002300 redefineImage(level, sizedInternalFormat, width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002301
Jamie Madill88f18f42013-09-18 14:36:19 -04002302 GLsizei inputDepthPitch = gl::GetDepthPitch(sizedInternalFormat, type, clientVersion, width, height, unpack.alignment);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002303
2304 for (int i = 0; i < depth; i++)
2305 {
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002306 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
Jamie Madill88f18f42013-09-18 14:36:19 -04002307 Texture::setImage(unpack, type, layerPixels, mImageArray[level][i]);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002308 }
2309}
2310
2311void Texture2DArray::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
2312{
2313 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
2314 redefineImage(level, format, width, height, depth);
2315
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002316 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2317 GLsizei inputDepthPitch = gl::GetDepthPitch(format, GL_UNSIGNED_BYTE, clientVersion, width, height, 1);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002318
2319 for (int i = 0; i < depth; i++)
2320 {
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002321 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002322 Texture::setCompressedImage(imageSize, layerPixels, mImageArray[level][i]);
2323 }
2324}
2325
Jamie Madill88f18f42013-09-18 14:36:19 -04002326void 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 +00002327{
Geoff Lang005df412013-10-16 14:12:50 -04002328 GLenum internalformat = getInternalFormat(level);
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002329 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Jamie Madill88f18f42013-09-18 14:36:19 -04002330 GLsizei inputDepthPitch = gl::GetDepthPitch(internalformat, type, clientVersion, width, height, unpack.alignment);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002331
2332 for (int i = 0; i < depth; i++)
2333 {
2334 int layer = zoffset + i;
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002335 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002336
Jamie Madill88f18f42013-09-18 14:36:19 -04002337 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 +00002338 {
2339 commitRect(level, xoffset, yoffset, layer, width, height);
2340 }
2341 }
2342}
2343
2344void Texture2DArray::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
2345{
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002346 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2347 GLsizei inputDepthPitch = gl::GetDepthPitch(format, GL_UNSIGNED_BYTE, clientVersion, width, height, 1);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002348
2349 for (int i = 0; i < depth; i++)
2350 {
2351 int layer = zoffset + i;
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002352 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002353
2354 if (Texture::subImageCompressed(xoffset, yoffset, zoffset, width, height, 1, format, imageSize, layerPixels, mImageArray[level][layer]))
2355 {
2356 commitRect(level, xoffset, yoffset, layer, width, height);
2357 }
2358 }
2359}
2360
2361void Texture2DArray::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2362{
Jamie Madill884a4622013-10-24 17:49:41 -04002363 deleteImages();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002364
2365 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2366 {
Jamie Madill884a4622013-10-24 17:49:41 -04002367 GLsizei levelWidth = std::max(1, width >> level);
2368 GLsizei levelHeight = std::max(1, height >> level);
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002369
Jamie Madill884a4622013-10-24 17:49:41 -04002370 mLayerCounts[level] = (level < levels ? depth : 0);
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002371
Jamie Madill884a4622013-10-24 17:49:41 -04002372 if (mLayerCounts[level] > 0)
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002373 {
2374 // Create new images for this level
Jamie Madill884a4622013-10-24 17:49:41 -04002375 mImageArray[level] = new rx::Image*[mLayerCounts[level]];
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002376
2377 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002378 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002379 mImageArray[level][layer] = mRenderer->createImage();
2380 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, levelWidth,
2381 levelHeight, 1, true);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002382 }
2383 }
2384 }
2385
Jamie Madill884a4622013-10-24 17:49:41 -04002386 mImmutable = true;
Jamie Madill4cfff5f2013-10-24 17:49:46 -04002387 setCompleteTexStorage(new rx::TextureStorageInterface2DArray(mRenderer, 0, levels, internalformat, IsRenderTargetUsage(mUsage), width, height, depth));
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002388}
2389
2390void Texture2DArray::generateMipmaps()
2391{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002392 int baseWidth = getBaseLevelWidth();
2393 int baseHeight = getBaseLevelHeight();
2394 int baseDepth = getBaseLevelDepth();
2395 GLenum baseFormat = getBaseLevelInternalFormat();
2396
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00002397 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Jamie Madill22f843a2013-10-24 17:49:36 -04002398 int q = mipLevels();
2399 for (int level = 1; level <= q; level++)
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00002400 {
Jamie Madill22f843a2013-10-24 17:49:36 -04002401 redefineImage(level, baseFormat, std::max(baseWidth >> level, 1), std::max(baseHeight >> level, 1), baseDepth);
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00002402 }
2403
2404 if (mTexStorage && mTexStorage->isRenderTarget())
2405 {
2406 for (int level = 1; level <= q; level++)
2407 {
2408 mTexStorage->generateMipmap(level);
2409
2410 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2411 {
2412 mImageArray[level][layer]->markClean();
2413 }
2414 }
2415 }
2416 else
2417 {
2418 for (int level = 1; level <= q; level++)
2419 {
2420 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2421 {
2422 mRenderer->generateMipmap(mImageArray[level][layer], mImageArray[level - 1][layer]);
2423 }
2424 }
2425 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002426}
2427
Jamie Madilld3d2a342013-10-07 10:46:35 -04002428const rx::Image *Texture2DArray::getBaseLevelImage() const
2429{
Jamie Madill152ed092013-10-09 17:01:15 -04002430 return (mLayerCounts[0] > 0 ? mImageArray[0][0] : NULL);
Jamie Madilld3d2a342013-10-07 10:46:35 -04002431}
2432
Jamie Madill2ebab852013-10-24 17:49:42 -04002433rx::TextureStorageInterface *Texture2DArray::getBaseLevelStorage()
2434{
2435 return mTexStorage;
2436}
2437
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002438void Texture2DArray::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
2439{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002440 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 +00002441 {
2442 return gl::error(GL_INVALID_VALUE);
2443 }
2444
Jamie Madill07edd442013-07-19 16:36:58 -04002445 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
2446 // the current level we're copying to is defined (with appropriate format, width & height)
2447 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
2448
2449 if (!mImageArray[level][0]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002450 {
2451 mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, x, y, width, height, source);
2452 mDirtyImages = true;
2453 }
2454 else
2455 {
Jamie Madille83d1a92013-10-24 17:49:33 -04002456 ensureRenderTarget();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002457
Jamie Madill07bb8cf2013-10-24 17:49:44 -04002458 if (isValidLevel(level))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002459 {
Jamie Madill169d1112013-10-24 17:49:37 -04002460 updateStorageLevel(level);
Jamie Madill07edd442013-07-19 16:36:58 -04002461
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002462 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2463
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002464 gl::Rectangle sourceRect;
2465 sourceRect.x = x;
2466 sourceRect.width = width;
2467 sourceRect.y = y;
2468 sourceRect.height = height;
2469
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002470 mRenderer->copyImage(source, sourceRect, gl::GetFormat(getInternalFormat(0), clientVersion),
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002471 xoffset, yoffset, zoffset, mTexStorage, level);
2472 }
2473 }
2474}
2475
Jamie Madillf8989902013-07-19 16:36:58 -04002476bool Texture2DArray::isSamplerComplete(const SamplerState &samplerState) const
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002477{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002478 GLsizei width = getBaseLevelWidth();
2479 GLsizei height = getBaseLevelHeight();
2480 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002481
2482 if (width <= 0 || height <= 0 || depth <= 0)
2483 {
2484 return false;
2485 }
2486
Jamie Madilld3d2a342013-10-07 10:46:35 -04002487 if (!IsTextureFilteringSupported(getBaseLevelInternalFormat(), mRenderer))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002488 {
Jamie Madillf8989902013-07-19 16:36:58 -04002489 if (samplerState.magFilter != GL_NEAREST ||
2490 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002491 {
2492 return false;
2493 }
2494 }
2495
Jamie Madillf8989902013-07-19 16:36:58 -04002496 if (IsMipmapFiltered(samplerState) && !isMipmapComplete())
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002497 {
2498 return false;
2499 }
2500
2501 return true;
2502}
2503
2504bool Texture2DArray::isMipmapComplete() const
2505{
Jamie Madill22f843a2013-10-24 17:49:36 -04002506 int q = mipLevels();
Jamie Madill07edd442013-07-19 16:36:58 -04002507
2508 for (int level = 1; level <= q; level++)
2509 {
2510 if (!isLevelComplete(level))
2511 {
2512 return false;
2513 }
2514 }
2515
2516 return true;
2517}
2518
2519bool Texture2DArray::isLevelComplete(int level) const
2520{
2521 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
2522
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002523 if (isImmutable())
2524 {
2525 return true;
2526 }
2527
Jamie Madilld3d2a342013-10-07 10:46:35 -04002528 GLsizei width = getBaseLevelWidth();
2529 GLsizei height = getBaseLevelHeight();
2530 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002531
2532 if (width <= 0 || height <= 0 || depth <= 0)
2533 {
2534 return false;
2535 }
2536
Jamie Madill07edd442013-07-19 16:36:58 -04002537 if (level == 0)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002538 {
Jamie Madill07edd442013-07-19 16:36:58 -04002539 return true;
2540 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002541
Jamie Madill07edd442013-07-19 16:36:58 -04002542 if (getInternalFormat(level) != getInternalFormat(0))
2543 {
2544 return false;
2545 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002546
Jamie Madill07edd442013-07-19 16:36:58 -04002547 if (getWidth(level) != std::max(1, width >> level))
2548 {
2549 return false;
2550 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002551
Jamie Madill07edd442013-07-19 16:36:58 -04002552 if (getHeight(level) != std::max(1, height >> level))
2553 {
2554 return false;
2555 }
2556
2557 if (getDepth(level) != depth)
2558 {
2559 return false;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002560 }
2561
2562 return true;
2563}
2564
Geoff Lang8040f572013-07-25 16:49:54 -04002565Renderbuffer *Texture2DArray::getRenderbuffer(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002566{
Geoff Lang8040f572013-07-25 16:49:54 -04002567 Renderbuffer *renderBuffer = mRenderbufferProxies.get(level, layer);
2568 if (!renderBuffer)
2569 {
Geoff Langd5d8e392013-07-25 16:53:03 -04002570 renderBuffer = new Renderbuffer(mRenderer, id(), new RenderbufferTexture2DArrayLayer(this, level, layer));
2571 mRenderbufferProxies.add(level, 0, renderBuffer);
Geoff Lang8040f572013-07-25 16:49:54 -04002572 }
2573
2574 return renderBuffer;
2575}
2576
Jamie Madille83d1a92013-10-24 17:49:33 -04002577unsigned int Texture2DArray::getRenderTargetSerial(GLint level, GLint layer)
Geoff Lang8040f572013-07-25 16:49:54 -04002578{
Jamie Madille83d1a92013-10-24 17:49:33 -04002579 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(level, layer) : 0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002580}
2581
Jamie Madill07bb8cf2013-10-24 17:49:44 -04002582bool Texture2DArray::isValidLevel(int level) const
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002583{
Jamie Madill4cfff5f2013-10-24 17:49:46 -04002584 return (mTexStorage ? (level >= mTexStorage->getBaseLevel() && level < mTexStorage->getMaxLevel()) : 0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002585}
2586
Jamie Madill73b5d062013-10-24 17:49:38 -04002587void Texture2DArray::initializeStorage(bool renderTarget)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002588{
Jamie Madill884a4622013-10-24 17:49:41 -04002589 // Only initialize the first time this texture is used as a render target or shader resource
2590 if (mTexStorage)
2591 {
2592 return;
2593 }
2594
2595 // do not attempt to create storage for nonexistant data
2596 if (!isLevelComplete(0))
2597 {
2598 return;
2599 }
2600
2601 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
2602
2603 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
2604 ASSERT(mTexStorage);
2605
2606 // flush image data to the storage
2607 updateStorage();
2608}
2609
2610rx::TextureStorageInterface2DArray *Texture2DArray::createCompleteStorage(bool renderTarget) const
2611{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002612 GLsizei width = getBaseLevelWidth();
2613 GLsizei height = getBaseLevelHeight();
2614 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002615
Jamie Madill884a4622013-10-24 17:49:41 -04002616 ASSERT(width > 0 && height > 0 && depth > 0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002617
Jamie Madill884a4622013-10-24 17:49:41 -04002618 // use existing storage level count, when previously specified by TexStorage*D
Jamie Madill6b7440c2013-10-24 17:49:47 -04002619 GLint levels = (mTexStorage ? mTexStorage->getMaxLevel() : creationLevels(width, height, 1));
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002620
Jamie Madill4cfff5f2013-10-24 17:49:46 -04002621 return new rx::TextureStorageInterface2DArray(mRenderer, 0, levels, getBaseLevelInternalFormat(), renderTarget, width, height, depth);
Jamie Madill884a4622013-10-24 17:49:41 -04002622}
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002623
Jamie Madill884a4622013-10-24 17:49:41 -04002624void Texture2DArray::setCompleteTexStorage(rx::TextureStorageInterface2DArray *newCompleteTexStorage)
2625{
2626 SafeDelete(mTexStorage);
2627 mTexStorage = newCompleteTexStorage;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002628 mDirtyImages = true;
Jamie Madill884a4622013-10-24 17:49:41 -04002629
2630 // We do not support managed 2D array storage, as managed storage is ES2/D3D9 only
2631 ASSERT(!mTexStorage->isManaged());
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002632}
2633
Jamie Madill169d1112013-10-24 17:49:37 -04002634void Texture2DArray::updateStorage()
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002635{
Jamie Madill4cfff5f2013-10-24 17:49:46 -04002636 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002637 {
Jamie Madilld9b9a502013-10-10 17:46:13 -04002638 if (isLevelComplete(level))
2639 {
Jamie Madill169d1112013-10-24 17:49:37 -04002640 updateStorageLevel(level);
Jamie Madilld9b9a502013-10-10 17:46:13 -04002641 }
Jamie Madill07edd442013-07-19 16:36:58 -04002642 }
2643}
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002644
Jamie Madill169d1112013-10-24 17:49:37 -04002645void Texture2DArray::updateStorageLevel(int level)
Jamie Madill07edd442013-07-19 16:36:58 -04002646{
Jamie Madillaee7ad82013-10-10 16:07:32 -04002647 ASSERT(level >= 0 && level < (int)ArraySize(mLayerCounts));
2648 ASSERT(isLevelComplete(level));
2649
Jamie Madill07edd442013-07-19 16:36:58 -04002650 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2651 {
Jamie Madillaee7ad82013-10-10 16:07:32 -04002652 ASSERT(mImageArray[level] != NULL && mImageArray[level][layer] != NULL);
2653 if (mImageArray[level][layer]->isDirty())
Jamie Madill07edd442013-07-19 16:36:58 -04002654 {
Jamie Madillaee7ad82013-10-10 16:07:32 -04002655 commitRect(level, 0, 0, layer, getWidth(level), getHeight(level));
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002656 }
2657 }
2658}
2659
Jamie Madille83d1a92013-10-24 17:49:33 -04002660bool Texture2DArray::ensureRenderTarget()
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002661{
Jamie Madill884a4622013-10-24 17:49:41 -04002662 initializeStorage(true);
2663
2664 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0 && getBaseLevelDepth() > 0)
Jamie Madille83d1a92013-10-24 17:49:33 -04002665 {
Jamie Madill884a4622013-10-24 17:49:41 -04002666 ASSERT(mTexStorage);
2667 if (!mTexStorage->isRenderTarget())
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002668 {
Jamie Madill884a4622013-10-24 17:49:41 -04002669 rx::TextureStorageInterface2DArray *newRenderTargetStorage = createCompleteStorage(true);
2670
2671 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002672 {
Jamie Madill884a4622013-10-24 17:49:41 -04002673 delete newRenderTargetStorage;
Jamie Madille83d1a92013-10-24 17:49:33 -04002674 return gl::error(GL_OUT_OF_MEMORY, false);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002675 }
Jamie Madill884a4622013-10-24 17:49:41 -04002676
2677 setCompleteTexStorage(newRenderTargetStorage);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002678 }
2679 }
2680
Jamie Madille83d1a92013-10-24 17:49:33 -04002681 return (mTexStorage && mTexStorage->isRenderTarget());
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002682}
2683
Geoff Lang8040f572013-07-25 16:49:54 -04002684rx::RenderTarget *Texture2DArray::getRenderTarget(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002685{
Geoff Lang8040f572013-07-25 16:49:54 -04002686 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04002687 if (!ensureRenderTarget())
Geoff Lang8040f572013-07-25 16:49:54 -04002688 {
2689 return NULL;
2690 }
2691
Jamie Madill169d1112013-10-24 17:49:37 -04002692 updateStorageLevel(level);
Geoff Lang8040f572013-07-25 16:49:54 -04002693
2694 // ensure this is NOT a depth texture
2695 if (isDepth(level))
2696 {
2697 return NULL;
2698 }
2699
2700 return mTexStorage->getRenderTarget(level, layer);
2701}
2702
2703rx::RenderTarget *Texture2DArray::getDepthStencil(GLint level, GLint layer)
2704{
2705 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04002706 if (!ensureRenderTarget())
Geoff Lang8040f572013-07-25 16:49:54 -04002707 {
2708 return NULL;
2709 }
2710
Jamie Madill169d1112013-10-24 17:49:37 -04002711 updateStorageLevel(level);
Geoff Lang8040f572013-07-25 16:49:54 -04002712
2713 // ensure this is a depth texture
2714 if (!isDepth(level))
2715 {
2716 return NULL;
2717 }
2718
2719 return mTexStorage->getRenderTarget(level, layer);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002720}
2721
Geoff Lang005df412013-10-16 14:12:50 -04002722void Texture2DArray::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002723{
2724 // If there currently is a corresponding storage texture image, it has these parameters
Jamie Madilld3d2a342013-10-07 10:46:35 -04002725 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2726 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
2727 const int storageDepth = getBaseLevelDepth();
Geoff Lang005df412013-10-16 14:12:50 -04002728 const GLenum storageFormat = getBaseLevelInternalFormat();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002729
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002730 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002731 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002732 delete mImageArray[level][layer];
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002733 }
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002734 delete[] mImageArray[level];
Jamie Madill152ed092013-10-09 17:01:15 -04002735 mImageArray[level] = NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002736 mLayerCounts[level] = depth;
2737
Jamie Madill152ed092013-10-09 17:01:15 -04002738 if (depth > 0)
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002739 {
Jamie Madill152ed092013-10-09 17:01:15 -04002740 mImageArray[level] = new rx::Image*[depth]();
2741
2742 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2743 {
2744 mImageArray[level][layer] = mRenderer->createImage();
2745 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, width, height, 1, false);
2746 }
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002747 }
2748
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002749 if (mTexStorage)
2750 {
Jamie Madill4cfff5f2013-10-24 17:49:46 -04002751 const int storageLevels = mTexStorage->getMaxLevel();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002752
2753 if ((level >= storageLevels && storageLevels != 0) ||
2754 width != storageWidth ||
2755 height != storageHeight ||
2756 depth != storageDepth ||
2757 internalformat != storageFormat) // Discard mismatched storage
2758 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002759 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002760 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002761 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002762 {
2763 mImageArray[level][layer]->markDirty();
2764 }
2765 }
2766
2767 delete mTexStorage;
2768 mTexStorage = NULL;
2769 mDirtyImages = true;
2770 }
2771 }
2772}
2773
2774void Texture2DArray::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint layerTarget, GLsizei width, GLsizei height)
2775{
Jamie Madill07bb8cf2013-10-24 17:49:44 -04002776 if (isValidLevel(level) && layerTarget < getDepth(level))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002777 {
2778 rx::Image *image = mImageArray[level][layerTarget];
Jamie Madill169d1112013-10-24 17:49:37 -04002779 if (image->copyToStorage(mTexStorage, level, xoffset, yoffset, layerTarget, width, height))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002780 {
2781 image->markClean();
2782 }
2783 }
2784}
2785
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00002786}