blob: a1a447c488a2f5dab03a62a213e3d9d475dacc74 [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
Jamie Madillb8f8b892014-01-07 10:12:50 -0500255// Note: "base level image" is loosely defined to be any image from the base level,
256// where in the base of 2D array textures and cube maps there are several. Don't use
257// the base level image for anything except querying texture format and size.
Jamie Madilld3d2a342013-10-07 10:46:35 -0400258GLenum Texture::getBaseLevelInternalFormat() const
259{
260 const rx::Image *baseImage = getBaseLevelImage();
261 return (baseImage ? baseImage->getInternalFormat() : GL_NONE);
262}
263
Jamie Madill88f18f42013-09-18 14:36:19 -0400264void Texture::setImage(const PixelUnpackState &unpack, GLenum type, const void *pixels, rx::Image *image)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000265{
Jamie Madillc30003d2014-01-10 12:51:23 -0500266 // No-op
267 if (image->getWidth() == 0 || image->getHeight() == 0 || image->getDepth() == 0)
268 {
269 return;
270 }
271
Jamie Madillabef6802013-09-05 16:54:19 -0400272 // We no longer need the "GLenum format" parameter to TexImage to determine what data format "pixels" contains.
273 // 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 -0400274 const void *pixelData = pixels;
275
276 if (unpack.pixelBuffer.id() != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000277 {
Jamie Madill1beb1db2013-09-18 14:36:28 -0400278 // Do a CPU readback here, if we have an unpack buffer bound and the fast GPU path is not supported
279 Buffer *pixelBuffer = unpack.pixelBuffer.get();
280 ptrdiff_t offset = reinterpret_cast<ptrdiff_t>(pixels);
281 const void *bufferData = pixelBuffer->getStorage()->getData();
282 pixelData = static_cast<const unsigned char *>(bufferData) + offset;
283 }
284
285 if (pixelData != NULL)
286 {
287 image->loadData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), unpack.alignment, type, pixelData);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000288 mDirtyImages = true;
289 }
290}
291
Geoff Lang005df412013-10-16 14:12:50 -0400292bool Texture::isFastUnpackable(const PixelUnpackState &unpack, GLenum sizedInternalFormat)
Jamie Madill8cc7d972013-10-10 15:51:55 -0400293{
294 return unpack.pixelBuffer.id() != 0 && mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat);
295}
296
Jamie Madill1beb1db2013-09-18 14:36:28 -0400297bool Texture::fastUnpackPixels(const PixelUnpackState &unpack, const void *pixels, const Box &destArea,
Jamie Madill8cc7d972013-10-10 15:51:55 -0400298 GLenum sizedInternalFormat, GLenum type, rx::RenderTarget *destRenderTarget)
Jamie Madill1beb1db2013-09-18 14:36:28 -0400299{
300 if (destArea.width <= 0 && destArea.height <= 0 && destArea.depth <= 0)
301 {
302 return true;
303 }
304
305 // In order to perform the fast copy through the shader, we must have the right format, and be able
306 // to create a render target.
Jamie Madill8cc7d972013-10-10 15:51:55 -0400307 ASSERT(mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat));
Jamie Madill1beb1db2013-09-18 14:36:28 -0400308
Jamie Madill8cc7d972013-10-10 15:51:55 -0400309 unsigned int offset = reinterpret_cast<unsigned int>(pixels);
Jamie Madill1beb1db2013-09-18 14:36:28 -0400310
Jamie Madill8cc7d972013-10-10 15:51:55 -0400311 return mRenderer->fastCopyBufferToTexture(unpack, offset, destRenderTarget, sizedInternalFormat, type, destArea);
Jamie Madill1beb1db2013-09-18 14:36:28 -0400312}
313
daniel@transgaming.com31b13e12012-11-28 19:34:30 +0000314void Texture::setCompressedImage(GLsizei imageSize, const void *pixels, rx::Image *image)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000315{
316 if (pixels != NULL)
317 {
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000318 image->loadCompressedData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000319 mDirtyImages = true;
320 }
321}
322
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000323bool Texture::subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
Jamie Madill88f18f42013-09-18 14:36:19 -0400324 GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels, rx::Image *image)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000325{
Jamie Madill065e1a32013-10-10 15:11:50 -0400326 const void *pixelData = pixels;
327
328 // CPU readback & copy where direct GPU copy is not supported
329 if (unpack.pixelBuffer.id() != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000330 {
Jamie Madill065e1a32013-10-10 15:11:50 -0400331 Buffer *pixelBuffer = unpack.pixelBuffer.get();
332 unsigned int offset = reinterpret_cast<unsigned int>(pixels);
333 const void *bufferData = pixelBuffer->getStorage()->getData();
334 pixelData = static_cast<const unsigned char *>(bufferData) + offset;
335 }
336
337 if (pixelData != NULL)
338 {
339 image->loadData(xoffset, yoffset, zoffset, width, height, depth, unpack.alignment, type, pixelData);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000340 mDirtyImages = true;
341 }
342
343 return true;
344}
345
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000346bool Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
347 GLenum format, GLsizei imageSize, const void *pixels, rx::Image *image)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000348{
349 if (pixels != NULL)
350 {
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000351 image->loadCompressedData(xoffset, yoffset, zoffset, width, height, depth, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000352 mDirtyImages = true;
353 }
354
355 return true;
356}
357
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000358rx::TextureStorageInterface *Texture::getNativeTexture()
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000359{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000360 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -0400361 initializeStorage(false);
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000362
Jamie Madill2ebab852013-10-24 17:49:42 -0400363 rx::TextureStorageInterface *storage = getBaseLevelStorage();
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000364 if (storage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000365 {
Jamie Madill169d1112013-10-24 17:49:37 -0400366 updateStorage();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000367 }
368
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000369 return storage;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000370}
371
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000372bool Texture::hasDirtyImages() const
373{
374 return mDirtyImages;
375}
376
377void Texture::resetDirty()
378{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000379 mDirtyImages = false;
380}
381
382unsigned int Texture::getTextureSerial()
383{
Jamie Madill2ebab852013-10-24 17:49:42 -0400384 rx::TextureStorageInterface *texture = getNativeTexture();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000385 return texture ? texture->getTextureSerial() : 0;
386}
387
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000388bool Texture::isImmutable() const
389{
390 return mImmutable;
391}
392
Jamie Madill51a94372013-10-24 17:49:43 -0400393int Texture::immutableLevelCount()
394{
Jamie Madill4cfff5f2013-10-24 17:49:46 -0400395 return (mImmutable ? getNativeTexture()->getStorageInstance()->getMaxLevel() : 0);
Jamie Madill51a94372013-10-24 17:49:43 -0400396}
397
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +0000398GLint Texture::creationLevels(GLsizei width, GLsizei height, GLsizei depth) const
399{
Jamie Madill6b7440c2013-10-24 17:49:47 -0400400 if ((isPow2(width) && isPow2(height) && isPow2(depth)) || mRenderer->getNonPower2TextureSupport())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000401 {
Jamie Madill6b7440c2013-10-24 17:49:47 -0400402 // Maximum number of levels
403 return static_cast<GLint>(log2(std::max(std::max(width, height), depth)));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000404 }
405 else
406 {
407 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
408 return 1;
409 }
410}
411
Jamie Madill22f843a2013-10-24 17:49:36 -0400412int Texture::mipLevels() const
413{
Jamie Madill6b7440c2013-10-24 17:49:47 -0400414 return static_cast<int>(log2(std::max(std::max(getBaseLevelWidth(), getBaseLevelHeight()), getBaseLevelDepth())));
Jamie Madill22f843a2013-10-24 17:49:36 -0400415}
416
Geoff Lang4907f2c2013-07-25 12:53:57 -0400417Texture2D::Texture2D(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_2D)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000418{
419 mTexStorage = NULL;
420 mSurface = NULL;
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000421
422 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
423 {
daniel@transgaming.com244e1832012-12-20 20:52:35 +0000424 mImageArray[i] = renderer->createImage();
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000425 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000426}
427
428Texture2D::~Texture2D()
429{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000430 delete mTexStorage;
431 mTexStorage = NULL;
432
433 if (mSurface)
434 {
435 mSurface->setBoundTexture(NULL);
436 mSurface = NULL;
437 }
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000438
439 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
440 {
441 delete mImageArray[i];
442 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000443}
444
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000445GLsizei Texture2D::getWidth(GLint level) const
446{
447 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000448 return mImageArray[level]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000449 else
450 return 0;
451}
452
453GLsizei Texture2D::getHeight(GLint level) const
454{
455 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000456 return mImageArray[level]->getHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000457 else
458 return 0;
459}
460
461GLenum Texture2D::getInternalFormat(GLint level) const
462{
463 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000464 return mImageArray[level]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000465 else
466 return GL_NONE;
467}
468
daniel@transgaming.com20d36662012-10-31 19:51:43 +0000469GLenum Texture2D::getActualFormat(GLint level) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000470{
471 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000472 return mImageArray[level]->getActualFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000473 else
Geoff Langcbf727a2014-02-10 12:50:45 -0500474 return GL_NONE;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000475}
476
Geoff Lang005df412013-10-16 14:12:50 -0400477void Texture2D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000478{
479 releaseTexImage();
shannon.woods@transgaming.com8a406682013-02-28 23:15:26 +0000480
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000481 // If there currently is a corresponding storage texture image, it has these parameters
Jamie Madilld3d2a342013-10-07 10:46:35 -0400482 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
483 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
Geoff Lang005df412013-10-16 14:12:50 -0400484 const GLenum storageFormat = getBaseLevelInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000485
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000486 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, width, height, 1, false);
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000487
488 if (mTexStorage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000489 {
Jamie Madill4cfff5f2013-10-24 17:49:46 -0400490 const int storageLevels = mTexStorage->getMaxLevel();
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000491
492 if ((level >= storageLevels && storageLevels != 0) ||
493 width != storageWidth ||
494 height != storageHeight ||
495 internalformat != storageFormat) // Discard mismatched storage
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000496 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000497 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
498 {
499 mImageArray[i]->markDirty();
500 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000501
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000502 delete mTexStorage;
503 mTexStorage = NULL;
504 mDirtyImages = true;
505 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000506 }
507}
508
Geoff Lang005df412013-10-16 14:12:50 -0400509void 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 +0000510{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +0000511 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Geoff Lang005df412013-10-16 14:12:50 -0400512 GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
513 : GetSizedInternalFormat(format, type, clientVersion);
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +0000514 redefineImage(level, sizedInternalFormat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000515
Jamie Madill8cc7d972013-10-10 15:51:55 -0400516 bool fastUnpacked = false;
517
Jamie Madill1beb1db2013-09-18 14:36:28 -0400518 // Attempt a fast gpu copy of the pixel data to the surface
Jamie Madill8cc7d972013-10-10 15:51:55 -0400519 if (isFastUnpackable(unpack, sizedInternalFormat) && isLevelComplete(level))
Jamie Madill1beb1db2013-09-18 14:36:28 -0400520 {
Jamie Madill8cc7d972013-10-10 15:51:55 -0400521 // Will try to create RT storage if it does not exist
522 rx::RenderTarget *destRenderTarget = getRenderTarget(level);
523 Box destArea(0, 0, 0, getWidth(level), getHeight(level), 1);
524
525 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget))
526 {
527 // Ensure we don't overwrite our newly initialized data
528 mImageArray[level]->markClean();
529
530 fastUnpacked = true;
531 }
Jamie Madill1beb1db2013-09-18 14:36:28 -0400532 }
Jamie Madill8cc7d972013-10-10 15:51:55 -0400533
534 if (!fastUnpacked)
Jamie Madill1beb1db2013-09-18 14:36:28 -0400535 {
536 Texture::setImage(unpack, type, pixels, mImageArray[level]);
537 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000538}
539
540void Texture2D::bindTexImage(egl::Surface *surface)
541{
542 releaseTexImage();
543
Geoff Lang005df412013-10-16 14:12:50 -0400544 GLenum internalformat = surface->getFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000545
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000546 mImageArray[0]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, surface->getWidth(), surface->getHeight(), 1, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000547
548 delete mTexStorage;
daniel@transgaming.comd8353dd2012-12-20 21:11:14 +0000549 mTexStorage = new rx::TextureStorageInterface2D(mRenderer, surface->getSwapChain());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000550
551 mDirtyImages = true;
552 mSurface = surface;
553 mSurface->setBoundTexture(this);
554}
555
556void Texture2D::releaseTexImage()
557{
558 if (mSurface)
559 {
560 mSurface->setBoundTexture(NULL);
561 mSurface = NULL;
562
563 if (mTexStorage)
564 {
565 delete mTexStorage;
566 mTexStorage = NULL;
567 }
568
569 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
570 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000571 mImageArray[i]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000572 }
573 }
574}
575
576void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
577{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000578 // 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 +0000579 redefineImage(level, format, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000580
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000581 Texture::setCompressedImage(imageSize, pixels, mImageArray[level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000582}
583
584void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
585{
Jamie Madill07bb8cf2013-10-24 17:49:44 -0400586 if (isValidLevel(level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000587 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000588 rx::Image *image = mImageArray[level];
Jamie Madill169d1112013-10-24 17:49:37 -0400589 if (image->copyToStorage(mTexStorage, level, xoffset, yoffset, width, height))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000590 {
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000591 image->markClean();
592 }
593 }
594}
595
Jamie Madill88f18f42013-09-18 14:36:19 -0400596void 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 +0000597{
Jamie Madill065e1a32013-10-10 15:11:50 -0400598 bool fastUnpacked = false;
599
600 if (isFastUnpackable(unpack, getInternalFormat(level)) && isLevelComplete(level))
601 {
602 rx::RenderTarget *renderTarget = getRenderTarget(level);
603 Box destArea(xoffset, yoffset, 0, width, height, 1);
604
605 if (renderTarget && fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, renderTarget))
606 {
607 // Ensure we don't overwrite our newly initialized data
608 mImageArray[level]->markClean();
609
610 fastUnpacked = true;
611 }
612 }
613
614 if (!fastUnpacked && Texture::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, mImageArray[level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000615 {
616 commitRect(level, xoffset, yoffset, width, height);
617 }
618}
619
620void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
621{
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000622 if (Texture::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000623 {
624 commitRect(level, xoffset, yoffset, width, height);
625 }
626}
627
628void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
629{
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +0000630 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Geoff Lang005df412013-10-16 14:12:50 -0400631 GLenum sizedInternalFormat = IsSizedInternalFormat(format, clientVersion) ? format
632 : GetSizedInternalFormat(format, GL_UNSIGNED_BYTE, clientVersion);
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +0000633 redefineImage(level, sizedInternalFormat, width, height);
shannon.woods@transgaming.com8a406682013-02-28 23:15:26 +0000634
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000635 if (!mImageArray[level]->isRenderableFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000636 {
shannon.woods%transgaming.com@gtempaccount.come5dcce72013-04-13 03:44:33 +0000637 mImageArray[level]->copy(0, 0, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000638 mDirtyImages = true;
639 }
640 else
641 {
Jamie Madille83d1a92013-10-24 17:49:33 -0400642 ensureRenderTarget();
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000643 mImageArray[level]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000644
Jamie Madill07bb8cf2013-10-24 17:49:44 -0400645 if (width != 0 && height != 0 && isValidLevel(level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000646 {
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +0000647 gl::Rectangle sourceRect;
648 sourceRect.x = x;
649 sourceRect.width = width;
650 sourceRect.y = y;
651 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000652
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +0000653 mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000654 }
655 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000656}
657
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +0000658void 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 +0000659{
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +0000660 if (xoffset + width > mImageArray[level]->getWidth() || yoffset + height > mImageArray[level]->getHeight() || zoffset != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000661 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +0000662 return gl::error(GL_INVALID_VALUE);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000663 }
664
Jamie Madill07edd442013-07-19 16:36:58 -0400665 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
666 // the current level we're copying to is defined (with appropriate format, width & height)
667 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
668
669 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000670 {
shannon.woods%transgaming.com@gtempaccount.come5dcce72013-04-13 03:44:33 +0000671 mImageArray[level]->copy(xoffset, yoffset, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000672 mDirtyImages = true;
673 }
674 else
675 {
Jamie Madille83d1a92013-10-24 17:49:33 -0400676 ensureRenderTarget();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000677
Jamie Madill07bb8cf2013-10-24 17:49:44 -0400678 if (isValidLevel(level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000679 {
Jamie Madill169d1112013-10-24 17:49:37 -0400680 updateStorageLevel(level);
Jamie Madill07edd442013-07-19 16:36:58 -0400681
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +0000682 GLuint clientVersion = mRenderer->getCurrentClientVersion();
683
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +0000684 gl::Rectangle sourceRect;
685 sourceRect.x = x;
686 sourceRect.width = width;
687 sourceRect.y = y;
688 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000689
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +0000690 mRenderer->copyImage(source, sourceRect,
Jamie Madilld3d2a342013-10-07 10:46:35 -0400691 gl::GetFormat(getBaseLevelInternalFormat(), clientVersion),
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +0000692 xoffset, yoffset, mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000693 }
694 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000695}
696
697void Texture2D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height)
698{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000699 for (int level = 0; level < levels; level++)
700 {
Jamie Madill73b5d062013-10-24 17:49:38 -0400701 GLsizei levelWidth = std::max(1, width >> level);
702 GLsizei levelHeight = std::max(1, height >> level);
703 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, levelWidth, levelHeight, 1, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000704 }
705
706 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
707 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000708 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000709 }
710
Jamie Madill73b5d062013-10-24 17:49:38 -0400711 mImmutable = true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000712
Jamie Madill4cfff5f2013-10-24 17:49:46 -0400713 setCompleteTexStorage(new rx::TextureStorageInterface2D(mRenderer, 0, levels, internalformat, IsRenderTargetUsage(mUsage), width, height));
Jamie Madill73b5d062013-10-24 17:49:38 -0400714}
715
716void Texture2D::setCompleteTexStorage(rx::TextureStorageInterface2D *newCompleteTexStorage)
717{
718 SafeDelete(mTexStorage);
719 mTexStorage = newCompleteTexStorage;
720
721 if (mTexStorage && mTexStorage->isManaged())
722 {
Jamie Madill4cfff5f2013-10-24 17:49:46 -0400723 for (int level = 0; level < mTexStorage->getMaxLevel(); level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000724 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000725 mImageArray[level]->setManagedSurface(mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000726 }
727 }
Jamie Madill73b5d062013-10-24 17:49:38 -0400728
729 mDirtyImages = true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000730}
731
732// Tests for 2D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85.
Jamie Madillf8989902013-07-19 16:36:58 -0400733bool Texture2D::isSamplerComplete(const SamplerState &samplerState) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000734{
Jamie Madilld3d2a342013-10-07 10:46:35 -0400735 GLsizei width = getBaseLevelWidth();
736 GLsizei height = getBaseLevelHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000737
738 if (width <= 0 || height <= 0)
739 {
740 return false;
741 }
742
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000743 if (!IsTextureFilteringSupported(getInternalFormat(0), mRenderer))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000744 {
Jamie Madillf8989902013-07-19 16:36:58 -0400745 if (samplerState.magFilter != GL_NEAREST ||
746 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000747 {
748 return false;
749 }
750 }
751
daniel@transgaming.comea32d482012-11-28 19:33:18 +0000752 bool npotSupport = mRenderer->getNonPower2TextureSupport();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000753
754 if (!npotSupport)
755 {
Jamie Madillf8989902013-07-19 16:36:58 -0400756 if ((samplerState.wrapS != GL_CLAMP_TO_EDGE && !isPow2(width)) ||
757 (samplerState.wrapT != GL_CLAMP_TO_EDGE && !isPow2(height)))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000758 {
759 return false;
760 }
761 }
762
Jamie Madillf8989902013-07-19 16:36:58 -0400763 if (IsMipmapFiltered(samplerState))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000764 {
765 if (!npotSupport)
766 {
767 if (!isPow2(width) || !isPow2(height))
768 {
769 return false;
770 }
771 }
772
773 if (!isMipmapComplete())
774 {
775 return false;
776 }
777 }
778
Geoff Langc82fc412013-07-10 14:43:42 -0400779 // OpenGLES 3.0.2 spec section 3.8.13 states that a texture is not mipmap complete if:
780 // The internalformat specified for the texture arrays is a sized internal depth or
781 // depth and stencil format (see table 3.13), the value of TEXTURE_COMPARE_-
782 // MODE is NONE, and either the magnification filter is not NEAREST or the mini-
783 // fication filter is neither NEAREST nor NEAREST_MIPMAP_NEAREST.
Jamie Madill2a205622014-02-12 10:41:24 -0500784 if (gl::GetDepthBits(getInternalFormat(0), mRenderer->getCurrentClientVersion()) > 0 &&
785 mRenderer->getCurrentClientVersion() > 2)
Geoff Langc82fc412013-07-10 14:43:42 -0400786 {
787 if (mSamplerState.compareMode == GL_NONE)
788 {
789 if ((mSamplerState.minFilter != GL_NEAREST && mSamplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST) ||
790 mSamplerState.magFilter != GL_NEAREST)
791 {
792 return false;
793 }
794 }
795 }
796
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000797 return true;
798}
799
800// Tests for 2D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
801bool Texture2D::isMipmapComplete() const
802{
Jamie Madill22f843a2013-10-24 17:49:36 -0400803 int q = mipLevels();
Jamie Madill07edd442013-07-19 16:36:58 -0400804
805 for (int level = 0; level <= q; level++)
806 {
807 if (!isLevelComplete(level))
808 {
809 return false;
810 }
811 }
812
813 return true;
814}
815
816bool Texture2D::isLevelComplete(int level) const
817{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000818 if (isImmutable())
819 {
820 return true;
821 }
822
Jamie Madill648c9682014-01-21 16:50:58 -0500823 const rx::Image *baseImage = getBaseLevelImage();
824
825 GLsizei width = baseImage->getWidth();
826 GLsizei height = baseImage->getHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000827
828 if (width <= 0 || height <= 0)
829 {
830 return false;
831 }
832
Jamie Madill07edd442013-07-19 16:36:58 -0400833 // The base image level is complete if the width and height are positive
834 if (level == 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000835 {
Jamie Madill07edd442013-07-19 16:36:58 -0400836 return true;
837 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000838
Jamie Madill07edd442013-07-19 16:36:58 -0400839 ASSERT(level >= 1 && level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
840 rx::Image *image = mImageArray[level];
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000841
Jamie Madill648c9682014-01-21 16:50:58 -0500842 if (image->getInternalFormat() != baseImage->getInternalFormat())
Jamie Madill07edd442013-07-19 16:36:58 -0400843 {
844 return false;
845 }
846
847 if (image->getWidth() != std::max(1, width >> level))
848 {
849 return false;
850 }
851
852 if (image->getHeight() != std::max(1, height >> level))
853 {
854 return false;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000855 }
856
857 return true;
858}
859
860bool Texture2D::isCompressed(GLint level) const
861{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000862 return IsFormatCompressed(getInternalFormat(level), mRenderer->getCurrentClientVersion());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000863}
864
865bool Texture2D::isDepth(GLint level) const
866{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000867 return GetDepthBits(getInternalFormat(level), mRenderer->getCurrentClientVersion()) > 0;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000868}
869
daniel@transgaming.comf032cb82012-10-31 19:51:52 +0000870// Constructs a native texture resource from the texture images
Jamie Madill73b5d062013-10-24 17:49:38 -0400871void Texture2D::initializeStorage(bool renderTarget)
872{
873 // Only initialize the first time this texture is used as a render target or shader resource
874 if (mTexStorage)
875 {
876 return;
877 }
878
879 // do not attempt to create storage for nonexistant data
880 if (!isLevelComplete(0))
881 {
882 return;
883 }
884
885 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
886
887 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
888 ASSERT(mTexStorage);
889
890 // flush image data to the storage
891 updateStorage();
892}
893
894rx::TextureStorageInterface2D *Texture2D::createCompleteStorage(bool renderTarget) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000895{
Jamie Madilld3d2a342013-10-07 10:46:35 -0400896 GLsizei width = getBaseLevelWidth();
897 GLsizei height = getBaseLevelHeight();
daniel@transgaming.come6a09842012-09-17 21:28:55 +0000898
Jamie Madill73b5d062013-10-24 17:49:38 -0400899 ASSERT(width > 0 && height > 0);
daniel@transgaming.come6a09842012-09-17 21:28:55 +0000900
Jamie Madill73b5d062013-10-24 17:49:38 -0400901 // use existing storage level count, when previously specified by TexStorage*D
Jamie Madill6b7440c2013-10-24 17:49:47 -0400902 GLint levels = (mTexStorage ? mTexStorage->getMaxLevel() : creationLevels(width, height, 1));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000903
Jamie Madill4cfff5f2013-10-24 17:49:46 -0400904 return new rx::TextureStorageInterface2D(mRenderer, 0, levels, getBaseLevelInternalFormat(), renderTarget, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000905}
906
Jamie Madill169d1112013-10-24 17:49:37 -0400907void Texture2D::updateStorage()
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000908{
Jamie Madill4cfff5f2013-10-24 17:49:46 -0400909 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000910 {
Jamie Madill648c9682014-01-21 16:50:58 -0500911 if (mImageArray[level]->isDirty() && isLevelComplete(level))
Jamie Madilld9b9a502013-10-10 17:46:13 -0400912 {
Jamie Madill169d1112013-10-24 17:49:37 -0400913 updateStorageLevel(level);
Jamie Madilld9b9a502013-10-10 17:46:13 -0400914 }
Jamie Madill07edd442013-07-19 16:36:58 -0400915 }
916}
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000917
Jamie Madill169d1112013-10-24 17:49:37 -0400918void Texture2D::updateStorageLevel(int level)
Jamie Madill07edd442013-07-19 16:36:58 -0400919{
920 ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
Jamie Madillaee7ad82013-10-10 16:07:32 -0400921 ASSERT(isLevelComplete(level));
Jamie Madill07edd442013-07-19 16:36:58 -0400922
Jamie Madillaee7ad82013-10-10 16:07:32 -0400923 if (mImageArray[level]->isDirty())
Jamie Madill07edd442013-07-19 16:36:58 -0400924 {
Jamie Madillaee7ad82013-10-10 16:07:32 -0400925 commitRect(level, 0, 0, getWidth(level), getHeight(level));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000926 }
927}
928
Jamie Madille83d1a92013-10-24 17:49:33 -0400929bool Texture2D::ensureRenderTarget()
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000930{
Jamie Madill73b5d062013-10-24 17:49:38 -0400931 initializeStorage(true);
932
933 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0)
Jamie Madille83d1a92013-10-24 17:49:33 -0400934 {
Jamie Madill73b5d062013-10-24 17:49:38 -0400935 ASSERT(mTexStorage);
936 if (!mTexStorage->isRenderTarget())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000937 {
Jamie Madill73b5d062013-10-24 17:49:38 -0400938 rx::TextureStorageInterface2D *newRenderTargetStorage = createCompleteStorage(true);
939
940 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
941 {
942 delete newRenderTargetStorage;
Jamie Madille83d1a92013-10-24 17:49:33 -0400943 return gl::error(GL_OUT_OF_MEMORY, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000944 }
Jamie Madill73b5d062013-10-24 17:49:38 -0400945
946 setCompleteTexStorage(newRenderTargetStorage);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000947 }
948 }
949
Jamie Madille83d1a92013-10-24 17:49:33 -0400950 return (mTexStorage && mTexStorage->isRenderTarget());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000951}
952
953void Texture2D::generateMipmaps()
954{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000955 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Jamie Madill22f843a2013-10-24 17:49:36 -0400956 int q = mipLevels();
957 for (int level = 1; level <= q; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000958 {
Jamie Madill22f843a2013-10-24 17:49:36 -0400959 redefineImage(level, getBaseLevelInternalFormat(),
960 std::max(getBaseLevelWidth() >> level, 1),
961 std::max(getBaseLevelHeight() >> level, 1));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000962 }
963
964 if (mTexStorage && mTexStorage->isRenderTarget())
965 {
Jamie Madill22f843a2013-10-24 17:49:36 -0400966 for (int level = 1; level <= q; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000967 {
Jamie Madill22f843a2013-10-24 17:49:36 -0400968 mTexStorage->generateMipmap(level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000969
Jamie Madill22f843a2013-10-24 17:49:36 -0400970 mImageArray[level]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000971 }
972 }
973 else
974 {
Jamie Madill22f843a2013-10-24 17:49:36 -0400975 for (int level = 1; level <= q; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000976 {
Jamie Madill22f843a2013-10-24 17:49:36 -0400977 mRenderer->generateMipmap(mImageArray[level], mImageArray[level - 1]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000978 }
979 }
980}
981
Jamie Madilld3d2a342013-10-07 10:46:35 -0400982const rx::Image *Texture2D::getBaseLevelImage() const
983{
984 return mImageArray[0];
985}
986
Jamie Madill2ebab852013-10-24 17:49:42 -0400987rx::TextureStorageInterface *Texture2D::getBaseLevelStorage()
988{
989 return mTexStorage;
990}
991
Geoff Lang8040f572013-07-25 16:49:54 -0400992Renderbuffer *Texture2D::getRenderbuffer(GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000993{
Geoff Lang8040f572013-07-25 16:49:54 -0400994 Renderbuffer *renderBuffer = mRenderbufferProxies.get(level, 0);
995 if (!renderBuffer)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000996 {
Geoff Lang8040f572013-07-25 16:49:54 -0400997 renderBuffer = new Renderbuffer(mRenderer, id(), new RenderbufferTexture2D(this, level));
998 mRenderbufferProxies.add(level, 0, renderBuffer);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000999 }
1000
Geoff Lang8040f572013-07-25 16:49:54 -04001001 return renderBuffer;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001002}
1003
Geoff Lang8040f572013-07-25 16:49:54 -04001004unsigned int Texture2D::getRenderTargetSerial(GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001005{
Jamie Madille83d1a92013-10-24 17:49:33 -04001006 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(level) : 0);
Geoff Lang8040f572013-07-25 16:49:54 -04001007}
1008
1009rx::RenderTarget *Texture2D::getRenderTarget(GLint level)
1010{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001011 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04001012 if (!ensureRenderTarget())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001013 {
1014 return NULL;
1015 }
1016
Jamie Madill169d1112013-10-24 17:49:37 -04001017 updateStorageLevel(level);
Geoff Lang8040f572013-07-25 16:49:54 -04001018
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001019 // ensure this is NOT a depth texture
Geoff Lang8040f572013-07-25 16:49:54 -04001020 if (isDepth(level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001021 {
1022 return NULL;
1023 }
daniel@transgaming.com34da3972012-12-20 21:10:29 +00001024
Geoff Lang8040f572013-07-25 16:49:54 -04001025 return mTexStorage->getRenderTarget(level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001026}
1027
Geoff Lang8040f572013-07-25 16:49:54 -04001028rx::RenderTarget *Texture2D::getDepthSencil(GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001029{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001030 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04001031 if (!ensureRenderTarget())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001032 {
1033 return NULL;
1034 }
1035
Jamie Madill169d1112013-10-24 17:49:37 -04001036 updateStorageLevel(level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001037
1038 // ensure this is actually a depth texture
Geoff Lang8040f572013-07-25 16:49:54 -04001039 if (!isDepth(level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001040 {
1041 return NULL;
1042 }
Geoff Lang8040f572013-07-25 16:49:54 -04001043
1044 return mTexStorage->getRenderTarget(level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001045}
1046
Jamie Madill07bb8cf2013-10-24 17:49:44 -04001047bool Texture2D::isValidLevel(int level) const
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +00001048{
Jamie Madill4cfff5f2013-10-24 17:49:46 -04001049 return (mTexStorage ? (level >= mTexStorage->getBaseLevel() && level < mTexStorage->getMaxLevel()) : false);
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +00001050}
1051
Geoff Lang4907f2c2013-07-25 12:53:57 -04001052TextureCubeMap::TextureCubeMap(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_CUBE_MAP)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001053{
1054 mTexStorage = NULL;
1055 for (int i = 0; i < 6; i++)
1056 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001057 for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
1058 {
daniel@transgaming.com244e1832012-12-20 20:52:35 +00001059 mImageArray[i][j] = renderer->createImage();
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001060 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001061 }
1062}
1063
1064TextureCubeMap::~TextureCubeMap()
1065{
1066 for (int i = 0; i < 6; i++)
1067 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001068 for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
1069 {
1070 delete mImageArray[i][j];
1071 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001072 }
1073
1074 delete mTexStorage;
1075 mTexStorage = NULL;
1076}
1077
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001078GLsizei TextureCubeMap::getWidth(GLenum target, GLint level) const
1079{
1080 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Jamie Madill2db197c2013-10-24 17:49:35 -04001081 return mImageArray[targetToIndex(target)][level]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001082 else
1083 return 0;
1084}
1085
1086GLsizei TextureCubeMap::getHeight(GLenum target, GLint level) const
1087{
1088 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Jamie Madill2db197c2013-10-24 17:49:35 -04001089 return mImageArray[targetToIndex(target)][level]->getHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001090 else
1091 return 0;
1092}
1093
1094GLenum TextureCubeMap::getInternalFormat(GLenum target, GLint level) const
1095{
1096 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Jamie Madill2db197c2013-10-24 17:49:35 -04001097 return mImageArray[targetToIndex(target)][level]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001098 else
1099 return GL_NONE;
1100}
1101
daniel@transgaming.com20d36662012-10-31 19:51:43 +00001102GLenum TextureCubeMap::getActualFormat(GLenum target, GLint level) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001103{
1104 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Jamie Madill2db197c2013-10-24 17:49:35 -04001105 return mImageArray[targetToIndex(target)][level]->getActualFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001106 else
Geoff Langcbf727a2014-02-10 12:50:45 -05001107 return GL_NONE;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001108}
1109
Geoff Lang005df412013-10-16 14:12:50 -04001110void 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 +00001111{
Jamie Madill88f18f42013-09-18 14:36:19 -04001112 setImage(0, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001113}
1114
Geoff Lang005df412013-10-16 14:12:50 -04001115void 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 +00001116{
Jamie Madill88f18f42013-09-18 14:36:19 -04001117 setImage(1, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001118}
1119
Geoff Lang005df412013-10-16 14:12:50 -04001120void 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 +00001121{
Jamie Madill88f18f42013-09-18 14:36:19 -04001122 setImage(2, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001123}
1124
Geoff Lang005df412013-10-16 14:12:50 -04001125void 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 +00001126{
Jamie Madill88f18f42013-09-18 14:36:19 -04001127 setImage(3, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001128}
1129
Geoff Lang005df412013-10-16 14:12:50 -04001130void 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 +00001131{
Jamie Madill88f18f42013-09-18 14:36:19 -04001132 setImage(4, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001133}
1134
Geoff Lang005df412013-10-16 14:12:50 -04001135void 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 +00001136{
Jamie Madill88f18f42013-09-18 14:36:19 -04001137 setImage(5, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001138}
1139
Jamie Madill2db197c2013-10-24 17:49:35 -04001140void 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 +00001141{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001142 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
Jamie Madill2db197c2013-10-24 17:49:35 -04001143 int faceIndex = targetToIndex(target);
1144 redefineImage(faceIndex, level, format, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001145
Jamie Madill2db197c2013-10-24 17:49:35 -04001146 Texture::setCompressedImage(imageSize, pixels, mImageArray[faceIndex][level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001147}
1148
Jamie Madill2db197c2013-10-24 17:49:35 -04001149void TextureCubeMap::commitRect(int faceIndex, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001150{
Jamie Madill07bb8cf2013-10-24 17:49:44 -04001151 if (isValidFaceLevel(faceIndex, level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001152 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001153 rx::Image *image = mImageArray[faceIndex][level];
Jamie Madill169d1112013-10-24 17:49:37 -04001154 if (image->copyToStorage(mTexStorage, faceIndex, level, xoffset, yoffset, width, height))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001155 image->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001156 }
1157}
1158
Jamie Madill88f18f42013-09-18 14:36:19 -04001159void 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 +00001160{
Jamie Madill2db197c2013-10-24 17:49:35 -04001161 int faceIndex = targetToIndex(target);
1162 if (Texture::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, mImageArray[faceIndex][level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001163 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001164 commitRect(faceIndex, level, xoffset, yoffset, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001165 }
1166}
1167
1168void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1169{
Jamie Madill2db197c2013-10-24 17:49:35 -04001170 int faceIndex = targetToIndex(target);
1171 if (Texture::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[faceIndex][level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001172 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001173 commitRect(faceIndex, level, xoffset, yoffset, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001174 }
1175}
1176
1177// Tests for cube map sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 86.
Jamie Madillf8989902013-07-19 16:36:58 -04001178bool TextureCubeMap::isSamplerComplete(const SamplerState &samplerState) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001179{
Jamie Madilld3d2a342013-10-07 10:46:35 -04001180 int size = getBaseLevelWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001181
Jamie Madillf8989902013-07-19 16:36:58 -04001182 bool mipmapping = IsMipmapFiltered(samplerState);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001183
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001184 if (!IsTextureFilteringSupported(getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0), mRenderer))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001185 {
Jamie Madillf8989902013-07-19 16:36:58 -04001186 if (samplerState.magFilter != GL_NEAREST ||
1187 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001188 {
1189 return false;
1190 }
1191 }
1192
daniel@transgaming.comea32d482012-11-28 19:33:18 +00001193 if (!isPow2(size) && !mRenderer->getNonPower2TextureSupport())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001194 {
Jamie Madillf8989902013-07-19 16:36:58 -04001195 if (samplerState.wrapS != GL_CLAMP_TO_EDGE || samplerState.wrapT != GL_CLAMP_TO_EDGE || mipmapping)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001196 {
1197 return false;
1198 }
1199 }
1200
1201 if (!mipmapping)
1202 {
1203 if (!isCubeComplete())
1204 {
1205 return false;
1206 }
1207 }
1208 else
1209 {
1210 if (!isMipmapCubeComplete()) // Also tests for isCubeComplete()
1211 {
1212 return false;
1213 }
1214 }
1215
1216 return true;
1217}
1218
1219// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1220bool TextureCubeMap::isCubeComplete() const
1221{
Jamie Madillc1f8b162013-10-07 10:46:38 -04001222 int baseWidth = getBaseLevelWidth();
1223 int baseHeight = getBaseLevelHeight();
1224 GLenum baseFormat = getBaseLevelInternalFormat();
1225
1226 if (baseWidth <= 0 || baseWidth != baseHeight)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001227 {
1228 return false;
1229 }
1230
Jamie Madill2db197c2013-10-24 17:49:35 -04001231 for (int faceIndex = 1; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001232 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001233 const rx::Image &faceBaseImage = *mImageArray[faceIndex][0];
Jamie Madillc1f8b162013-10-07 10:46:38 -04001234
1235 if (faceBaseImage.getWidth() != baseWidth ||
1236 faceBaseImage.getHeight() != baseHeight ||
1237 faceBaseImage.getInternalFormat() != baseFormat )
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001238 {
1239 return false;
1240 }
1241 }
1242
1243 return true;
1244}
1245
1246bool TextureCubeMap::isMipmapCubeComplete() const
1247{
1248 if (isImmutable())
1249 {
1250 return true;
1251 }
1252
1253 if (!isCubeComplete())
1254 {
1255 return false;
1256 }
1257
Jamie Madill22f843a2013-10-24 17:49:36 -04001258 int q = mipLevels();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001259
1260 for (int face = 0; face < 6; face++)
1261 {
1262 for (int level = 1; level <= q; level++)
1263 {
Jamie Madill07edd442013-07-19 16:36:58 -04001264 if (!isFaceLevelComplete(face, level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001265 {
1266 return false;
1267 }
1268 }
1269 }
1270
1271 return true;
1272}
1273
Jamie Madill2db197c2013-10-24 17:49:35 -04001274bool TextureCubeMap::isFaceLevelComplete(int faceIndex, int level) const
Jamie Madill07edd442013-07-19 16:36:58 -04001275{
Jamie Madill2db197c2013-10-24 17:49:35 -04001276 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
Jamie Madill07edd442013-07-19 16:36:58 -04001277
1278 if (isImmutable())
1279 {
1280 return true;
1281 }
1282
Jamie Madilld3d2a342013-10-07 10:46:35 -04001283 int baseSize = getBaseLevelWidth();
Jamie Madill07edd442013-07-19 16:36:58 -04001284
Jamie Madilld3d2a342013-10-07 10:46:35 -04001285 if (baseSize <= 0)
Jamie Madill07edd442013-07-19 16:36:58 -04001286 {
1287 return false;
1288 }
1289
Jamie Madilld3d2a342013-10-07 10:46:35 -04001290 // "isCubeComplete" checks for base level completeness and we must call that
1291 // to determine if any face at level 0 is complete. We omit that check here
1292 // to avoid re-checking cube-completeness for every face at level 0.
Jamie Madill07edd442013-07-19 16:36:58 -04001293 if (level == 0)
1294 {
1295 return true;
1296 }
1297
Jamie Madilld3d2a342013-10-07 10:46:35 -04001298 // Check that non-zero levels are consistent with the base level.
Jamie Madill2db197c2013-10-24 17:49:35 -04001299 const rx::Image *faceLevelImage = mImageArray[faceIndex][level];
Jamie Madill07edd442013-07-19 16:36:58 -04001300
Jamie Madilld3d2a342013-10-07 10:46:35 -04001301 if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat())
Jamie Madill07edd442013-07-19 16:36:58 -04001302 {
1303 return false;
1304 }
1305
Jamie Madilld3d2a342013-10-07 10:46:35 -04001306 if (faceLevelImage->getWidth() != std::max(1, baseSize >> level))
Jamie Madill07edd442013-07-19 16:36:58 -04001307 {
1308 return false;
1309 }
1310
1311 return true;
1312}
1313
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001314bool TextureCubeMap::isCompressed(GLenum target, GLint level) const
1315{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001316 return IsFormatCompressed(getInternalFormat(target, level), mRenderer->getCurrentClientVersion());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001317}
1318
Geoff Lang8040f572013-07-25 16:49:54 -04001319bool TextureCubeMap::isDepth(GLenum target, GLint level) const
1320{
1321 return GetDepthBits(getInternalFormat(target, level), mRenderer->getCurrentClientVersion()) > 0;
1322}
1323
Jamie Madill73b5d062013-10-24 17:49:38 -04001324void TextureCubeMap::initializeStorage(bool renderTarget)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001325{
Jamie Madill3c0989c2013-10-24 17:49:39 -04001326 // Only initialize the first time this texture is used as a render target or shader resource
1327 if (mTexStorage)
1328 {
1329 return;
1330 }
1331
1332 // do not attempt to create storage for nonexistant data
1333 if (!isFaceLevelComplete(0, 0))
1334 {
1335 return;
1336 }
1337
1338 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
1339
1340 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
1341 ASSERT(mTexStorage);
1342
1343 // flush image data to the storage
1344 updateStorage();
1345}
1346
1347rx::TextureStorageInterfaceCube *TextureCubeMap::createCompleteStorage(bool renderTarget) const
1348{
Jamie Madilld3d2a342013-10-07 10:46:35 -04001349 GLsizei size = getBaseLevelWidth();
daniel@transgaming.come6a09842012-09-17 21:28:55 +00001350
Jamie Madill3c0989c2013-10-24 17:49:39 -04001351 ASSERT(size > 0);
daniel@transgaming.come6a09842012-09-17 21:28:55 +00001352
Jamie Madill3c0989c2013-10-24 17:49:39 -04001353 // use existing storage level count, when previously specified by TexStorage*D
Jamie Madill6b7440c2013-10-24 17:49:47 -04001354 GLint levels = (mTexStorage ? mTexStorage->getMaxLevel() : creationLevels(size, size, 1));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001355
Jamie Madill4cfff5f2013-10-24 17:49:46 -04001356 return new rx::TextureStorageInterfaceCube(mRenderer, 0, levels, getBaseLevelInternalFormat(), renderTarget, size);
Jamie Madill3c0989c2013-10-24 17:49:39 -04001357}
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001358
Jamie Madill3c0989c2013-10-24 17:49:39 -04001359void TextureCubeMap::setCompleteTexStorage(rx::TextureStorageInterfaceCube *newCompleteTexStorage)
1360{
1361 SafeDelete(mTexStorage);
1362 mTexStorage = newCompleteTexStorage;
1363
1364 if (mTexStorage && mTexStorage->isManaged())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001365 {
Jamie Madill4cfff5f2013-10-24 17:49:46 -04001366 int levels = mTexStorage->getMaxLevel();
1367
Jamie Madill2db197c2013-10-24 17:49:35 -04001368 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001369 {
Jamie Madill4cfff5f2013-10-24 17:49:46 -04001370 for (int level = 0; level < mTexStorage->getMaxLevel(); level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001371 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001372 mImageArray[faceIndex][level]->setManagedSurface(mTexStorage, faceIndex, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001373 }
1374 }
1375 }
1376
1377 mDirtyImages = true;
1378}
1379
Jamie Madill169d1112013-10-24 17:49:37 -04001380void TextureCubeMap::updateStorage()
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001381{
1382 for (int face = 0; face < 6; face++)
1383 {
Jamie Madill4cfff5f2013-10-24 17:49:46 -04001384 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001385 {
Jamie Madilld9b9a502013-10-10 17:46:13 -04001386 if (isFaceLevelComplete(face, level))
1387 {
Jamie Madill169d1112013-10-24 17:49:37 -04001388 updateStorageFaceLevel(face, level);
Jamie Madilld9b9a502013-10-10 17:46:13 -04001389 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001390 }
1391 }
1392}
1393
Jamie Madill169d1112013-10-24 17:49:37 -04001394void TextureCubeMap::updateStorageFaceLevel(int faceIndex, int level)
Jamie Madill07edd442013-07-19 16:36:58 -04001395{
Jamie Madill2db197c2013-10-24 17:49:35 -04001396 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1397 rx::Image *image = mImageArray[faceIndex][level];
Jamie Madill07edd442013-07-19 16:36:58 -04001398
1399 if (image->isDirty())
1400 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001401 commitRect(faceIndex, level, 0, 0, image->getWidth(), image->getHeight());
Jamie Madill07edd442013-07-19 16:36:58 -04001402 }
1403}
1404
Jamie Madille83d1a92013-10-24 17:49:33 -04001405bool TextureCubeMap::ensureRenderTarget()
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001406{
Jamie Madill3c0989c2013-10-24 17:49:39 -04001407 initializeStorage(true);
1408
1409 if (getBaseLevelWidth() > 0)
Jamie Madille83d1a92013-10-24 17:49:33 -04001410 {
Jamie Madill3c0989c2013-10-24 17:49:39 -04001411 ASSERT(mTexStorage);
1412 if (!mTexStorage->isRenderTarget())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001413 {
Jamie Madill3c0989c2013-10-24 17:49:39 -04001414 rx::TextureStorageInterfaceCube *newRenderTargetStorage = createCompleteStorage(true);
1415
1416 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001417 {
Jamie Madill3c0989c2013-10-24 17:49:39 -04001418 delete newRenderTargetStorage;
Jamie Madille83d1a92013-10-24 17:49:33 -04001419 return gl::error(GL_OUT_OF_MEMORY, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001420 }
Jamie Madill3c0989c2013-10-24 17:49:39 -04001421
1422 setCompleteTexStorage(newRenderTargetStorage);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001423 }
1424 }
1425
Jamie Madille83d1a92013-10-24 17:49:33 -04001426 return (mTexStorage && mTexStorage->isRenderTarget());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001427}
1428
Geoff Lang005df412013-10-16 14:12:50 -04001429void 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 +00001430{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001431 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Geoff Lang005df412013-10-16 14:12:50 -04001432 GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
1433 : GetSizedInternalFormat(format, type, clientVersion);
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001434
1435 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001436
Jamie Madill88f18f42013-09-18 14:36:19 -04001437 Texture::setImage(unpack, type, pixels, mImageArray[faceIndex][level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001438}
1439
Jamie Madill2db197c2013-10-24 17:49:35 -04001440int TextureCubeMap::targetToIndex(GLenum target)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001441{
1442 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
1443 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
1444 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
1445 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
1446 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
1447
Jamie Madill2db197c2013-10-24 17:49:35 -04001448 return target - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001449}
1450
Jamie Madill2db197c2013-10-24 17:49:35 -04001451void TextureCubeMap::redefineImage(int faceIndex, GLint level, GLenum internalformat, GLsizei width, GLsizei height)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001452{
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001453 // If there currently is a corresponding storage texture image, it has these parameters
Jamie Madilld3d2a342013-10-07 10:46:35 -04001454 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1455 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
Geoff Lang005df412013-10-16 14:12:50 -04001456 const GLenum storageFormat = getBaseLevelInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001457
Jamie Madill2db197c2013-10-24 17:49:35 -04001458 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, width, height, 1, false);
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001459
1460 if (mTexStorage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001461 {
Jamie Madill4cfff5f2013-10-24 17:49:46 -04001462 const int storageLevels = mTexStorage->getMaxLevel();
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001463
1464 if ((level >= storageLevels && storageLevels != 0) ||
1465 width != storageWidth ||
1466 height != storageHeight ||
1467 internalformat != storageFormat) // Discard mismatched storage
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001468 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001469 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001470 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001471 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001472 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001473 mImageArray[faceIndex][level]->markDirty();
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001474 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001475 }
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001476
1477 delete mTexStorage;
1478 mTexStorage = NULL;
1479
1480 mDirtyImages = true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001481 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001482 }
1483}
1484
1485void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1486{
Jamie Madill2db197c2013-10-24 17:49:35 -04001487 int faceIndex = targetToIndex(target);
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001488 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Geoff Lang005df412013-10-16 14:12:50 -04001489 GLenum sizedInternalFormat = IsSizedInternalFormat(format, clientVersion) ? format
1490 : GetSizedInternalFormat(format, GL_UNSIGNED_BYTE, clientVersion);
Jamie Madill2db197c2013-10-24 17:49:35 -04001491 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001492
Jamie Madill2db197c2013-10-24 17:49:35 -04001493 if (!mImageArray[faceIndex][level]->isRenderableFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001494 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001495 mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001496 mDirtyImages = true;
1497 }
1498 else
1499 {
Jamie Madille83d1a92013-10-24 17:49:33 -04001500 ensureRenderTarget();
Jamie Madill2db197c2013-10-24 17:49:35 -04001501 mImageArray[faceIndex][level]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001502
1503 ASSERT(width == height);
1504
Jamie Madill07bb8cf2013-10-24 17:49:44 -04001505 if (width > 0 && isValidFaceLevel(faceIndex, level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001506 {
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +00001507 gl::Rectangle sourceRect;
1508 sourceRect.x = x;
1509 sourceRect.width = width;
1510 sourceRect.y = y;
1511 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001512
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +00001513 mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001514 }
1515 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001516}
1517
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001518void 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 +00001519{
Jamie Madill2db197c2013-10-24 17:49:35 -04001520 int faceIndex = targetToIndex(target);
1521
1522 GLsizei size = mImageArray[faceIndex][level]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001523
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001524 if (xoffset + width > size || yoffset + height > size || zoffset != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001525 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +00001526 return gl::error(GL_INVALID_VALUE);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001527 }
1528
Jamie Madilld3d2a342013-10-07 10:46:35 -04001529 // We can only make our texture storage to a render target if the level we're copying *to* is complete
1530 // and the base level is cube-complete. The base level must be cube complete (common case) because we cannot
1531 // rely on the "getBaseLevel*" methods reliably otherwise.
Jamie Madill2db197c2013-10-24 17:49:35 -04001532 bool canCreateRenderTarget = isFaceLevelComplete(faceIndex, level) && isCubeComplete();
Jamie Madill07edd442013-07-19 16:36:58 -04001533
Jamie Madill2db197c2013-10-24 17:49:35 -04001534 if (!mImageArray[faceIndex][level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001535 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001536 mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001537 mDirtyImages = true;
1538 }
1539 else
1540 {
Jamie Madille83d1a92013-10-24 17:49:33 -04001541 ensureRenderTarget();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001542
Jamie Madill07bb8cf2013-10-24 17:49:44 -04001543 if (isValidFaceLevel(faceIndex, level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001544 {
Jamie Madill169d1112013-10-24 17:49:37 -04001545 updateStorageFaceLevel(faceIndex, level);
Jamie Madill07edd442013-07-19 16:36:58 -04001546
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001547 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1548
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +00001549 gl::Rectangle sourceRect;
1550 sourceRect.x = x;
1551 sourceRect.width = width;
1552 sourceRect.y = y;
1553 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001554
Jamie Madilld3d2a342013-10-07 10:46:35 -04001555 mRenderer->copyImage(source, sourceRect, gl::GetFormat(getBaseLevelInternalFormat(), clientVersion),
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +00001556 xoffset, yoffset, mTexStorage, target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001557 }
1558 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001559}
1560
1561void TextureCubeMap::storage(GLsizei levels, GLenum internalformat, GLsizei size)
1562{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001563 for (int level = 0; level < levels; level++)
1564 {
Geoff Langd3110192013-09-24 11:52:47 -04001565 GLsizei mipSize = std::max(1, size >> level);
Jamie Madill2db197c2013-10-24 17:49:35 -04001566 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001567 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001568 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, mipSize, mipSize, 1, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001569 }
1570 }
1571
1572 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1573 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001574 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001575 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001576 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, GL_NONE, 0, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001577 }
1578 }
1579
Jamie Madill3c0989c2013-10-24 17:49:39 -04001580 mImmutable = true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001581
Jamie Madill4cfff5f2013-10-24 17:49:46 -04001582 setCompleteTexStorage(new rx::TextureStorageInterfaceCube(mRenderer, 0, levels, internalformat, IsRenderTargetUsage(mUsage), size));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001583}
1584
1585void TextureCubeMap::generateMipmaps()
1586{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001587 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Jamie Madill22f843a2013-10-24 17:49:36 -04001588 int q = mipLevels();
Jamie Madill2db197c2013-10-24 17:49:35 -04001589 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001590 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001591 for (int level = 1; level <= q; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001592 {
Jamie Madill22f843a2013-10-24 17:49:36 -04001593 int faceLevelSize = (std::max(mImageArray[faceIndex][0]->getWidth() >> level, 1));
1594 redefineImage(faceIndex, level, mImageArray[faceIndex][0]->getInternalFormat(), faceLevelSize, faceLevelSize);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001595 }
1596 }
1597
1598 if (mTexStorage && mTexStorage->isRenderTarget())
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 mTexStorage->generateMipmap(faceIndex, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001605
Jamie Madill2db197c2013-10-24 17:49:35 -04001606 mImageArray[faceIndex][level]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001607 }
1608 }
1609 }
1610 else
1611 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001612 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001613 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001614 for (int level = 1; level <= q; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001615 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001616 mRenderer->generateMipmap(mImageArray[faceIndex][level], mImageArray[faceIndex][level - 1]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001617 }
1618 }
1619 }
1620}
1621
Jamie Madilld3d2a342013-10-07 10:46:35 -04001622const rx::Image *TextureCubeMap::getBaseLevelImage() const
1623{
1624 // Note: if we are not cube-complete, there is no single base level image that can describe all
1625 // cube faces, so this method is only well-defined for a cube-complete base level.
1626 return mImageArray[0][0];
1627}
1628
Jamie Madill2ebab852013-10-24 17:49:42 -04001629rx::TextureStorageInterface *TextureCubeMap::getBaseLevelStorage()
1630{
1631 return mTexStorage;
1632}
1633
Geoff Lang8040f572013-07-25 16:49:54 -04001634Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target, GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001635{
1636 if (!IsCubemapTextureTarget(target))
1637 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +00001638 return gl::error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001639 }
1640
Jamie Madill2db197c2013-10-24 17:49:35 -04001641 int faceIndex = targetToIndex(target);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001642
Jamie Madill2db197c2013-10-24 17:49:35 -04001643 Renderbuffer *renderBuffer = mRenderbufferProxies.get(level, faceIndex);
Geoff Lang8040f572013-07-25 16:49:54 -04001644 if (!renderBuffer)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001645 {
Geoff Lang8040f572013-07-25 16:49:54 -04001646 renderBuffer = new Renderbuffer(mRenderer, id(), new RenderbufferTextureCubeMap(this, target, level));
Jamie Madill2db197c2013-10-24 17:49:35 -04001647 mRenderbufferProxies.add(level, faceIndex, renderBuffer);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001648 }
1649
Geoff Lang8040f572013-07-25 16:49:54 -04001650 return renderBuffer;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001651}
1652
Jamie Madill2db197c2013-10-24 17:49:35 -04001653unsigned int TextureCubeMap::getRenderTargetSerial(GLenum target, GLint level)
Geoff Lang8040f572013-07-25 16:49:54 -04001654{
Jamie Madill2db197c2013-10-24 17:49:35 -04001655 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(target, level) : 0);
Geoff Lang8040f572013-07-25 16:49:54 -04001656}
1657
1658rx::RenderTarget *TextureCubeMap::getRenderTarget(GLenum target, GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001659{
1660 ASSERT(IsCubemapTextureTarget(target));
1661
1662 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04001663 if (!ensureRenderTarget())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001664 {
1665 return NULL;
1666 }
1667
Jamie Madill169d1112013-10-24 17:49:37 -04001668 updateStorageFaceLevel(targetToIndex(target), level);
Geoff Lang8040f572013-07-25 16:49:54 -04001669
1670 // ensure this is NOT a depth texture
1671 if (isDepth(target, level))
1672 {
1673 return NULL;
1674 }
1675
1676 return mTexStorage->getRenderTarget(target, level);
1677}
1678
1679rx::RenderTarget *TextureCubeMap::getDepthStencil(GLenum target, GLint level)
1680{
1681 ASSERT(IsCubemapTextureTarget(target));
1682
1683 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04001684 if (!ensureRenderTarget())
Geoff Lang8040f572013-07-25 16:49:54 -04001685 {
1686 return NULL;
1687 }
1688
Jamie Madill169d1112013-10-24 17:49:37 -04001689 updateStorageFaceLevel(targetToIndex(target), level);
Geoff Lang8040f572013-07-25 16:49:54 -04001690
1691 // ensure this is a depth texture
1692 if (!isDepth(target, level))
1693 {
1694 return NULL;
1695 }
1696
1697 return mTexStorage->getRenderTarget(target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001698}
1699
Jamie Madill07bb8cf2013-10-24 17:49:44 -04001700bool TextureCubeMap::isValidFaceLevel(int faceIndex, int level) const
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +00001701{
Jamie Madill4cfff5f2013-10-24 17:49:46 -04001702 return (mTexStorage ? (level >= mTexStorage->getBaseLevel() && level < mTexStorage->getMaxLevel()) : 0);
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +00001703}
1704
Geoff Lang4907f2c2013-07-25 12:53:57 -04001705Texture3D::Texture3D(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_3D)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001706{
1707 mTexStorage = NULL;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001708
1709 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1710 {
1711 mImageArray[i] = renderer->createImage();
1712 }
1713}
1714
1715Texture3D::~Texture3D()
1716{
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001717 delete mTexStorage;
1718 mTexStorage = NULL;
1719
1720 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1721 {
1722 delete mImageArray[i];
1723 }
1724}
1725
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001726GLsizei Texture3D::getWidth(GLint level) const
1727{
1728 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getWidth() : 0;
1729}
1730
1731GLsizei Texture3D::getHeight(GLint level) const
1732{
1733 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getHeight() : 0;
1734}
1735
1736GLsizei Texture3D::getDepth(GLint level) const
1737{
1738 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getDepth() : 0;
1739}
1740
1741GLenum Texture3D::getInternalFormat(GLint level) const
1742{
1743 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getInternalFormat() : GL_NONE;
1744}
1745
1746GLenum Texture3D::getActualFormat(GLint level) const
1747{
Geoff Langcbf727a2014-02-10 12:50:45 -05001748 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getActualFormat() : GL_NONE;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001749}
1750
1751bool Texture3D::isCompressed(GLint level) const
1752{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001753 return IsFormatCompressed(getInternalFormat(level), mRenderer->getCurrentClientVersion());
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001754}
1755
1756bool Texture3D::isDepth(GLint level) const
1757{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001758 return GetDepthBits(getInternalFormat(level), mRenderer->getCurrentClientVersion()) > 0;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001759}
1760
Geoff Lang005df412013-10-16 14:12:50 -04001761void 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 +00001762{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001763 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Geoff Lang005df412013-10-16 14:12:50 -04001764 GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
1765 : GetSizedInternalFormat(format, type, clientVersion);
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001766 redefineImage(level, sizedInternalFormat, width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001767
Jamie Madilla2d4e552013-10-10 15:12:01 -04001768 bool fastUnpacked = false;
1769
1770 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1771 if (isFastUnpackable(unpack, sizedInternalFormat))
1772 {
1773 // Will try to create RT storage if it does not exist
1774 rx::RenderTarget *destRenderTarget = getRenderTarget(level);
1775 Box destArea(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1776
1777 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget))
1778 {
1779 // Ensure we don't overwrite our newly initialized data
1780 mImageArray[level]->markClean();
1781
1782 fastUnpacked = true;
1783 }
1784 }
1785
1786 if (!fastUnpacked)
1787 {
1788 Texture::setImage(unpack, type, pixels, mImageArray[level]);
1789 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001790}
1791
1792void Texture3D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
1793{
1794 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1795 redefineImage(level, format, width, height, depth);
1796
1797 Texture::setCompressedImage(imageSize, pixels, mImageArray[level]);
1798}
1799
Jamie Madill88f18f42013-09-18 14:36:19 -04001800void 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 +00001801{
Jamie Madillba4f10a2013-10-10 15:12:20 -04001802 bool fastUnpacked = false;
1803
1804 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1805 if (isFastUnpackable(unpack, getInternalFormat(level)))
1806 {
1807 rx::RenderTarget *destRenderTarget = getRenderTarget(level);
1808 Box destArea(xoffset, yoffset, zoffset, width, height, depth);
1809
1810 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, destRenderTarget))
1811 {
1812 // Ensure we don't overwrite our newly initialized data
1813 mImageArray[level]->markClean();
1814
1815 fastUnpacked = true;
1816 }
1817 }
1818
1819 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 +00001820 {
1821 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1822 }
1823}
1824
1825void Texture3D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
1826{
1827 if (Texture::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth, format, imageSize, pixels, mImageArray[level]))
1828 {
1829 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1830 }
1831}
1832
1833void Texture3D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
1834{
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001835 for (int level = 0; level < levels; level++)
1836 {
Jamie Madille664e202013-10-24 17:49:40 -04001837 GLsizei levelWidth = std::max(1, width >> level);
1838 GLsizei levelHeight = std::max(1, height >> level);
1839 GLsizei levelDepth = std::max(1, depth >> level);
1840 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, levelWidth, levelHeight, levelDepth, true);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001841 }
1842
1843 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1844 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001845 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, GL_NONE, 0, 0, 0, true);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001846 }
1847
Jamie Madille664e202013-10-24 17:49:40 -04001848 mImmutable = true;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001849
Jamie Madill4cfff5f2013-10-24 17:49:46 -04001850 setCompleteTexStorage(new rx::TextureStorageInterface3D(mRenderer, 0, levels, internalformat, IsRenderTargetUsage(mUsage), width, height, depth));
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001851}
1852
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001853void Texture3D::generateMipmaps()
1854{
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001855 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Jamie Madill22f843a2013-10-24 17:49:36 -04001856 int q = mipLevels();
1857 for (int level = 1; level <= q; level++)
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001858 {
Jamie Madill22f843a2013-10-24 17:49:36 -04001859 redefineImage(level, getBaseLevelInternalFormat(),
1860 std::max(getBaseLevelWidth() >> level, 1),
1861 std::max(getBaseLevelHeight() >> level, 1),
1862 std::max(getBaseLevelDepth() >> level, 1));
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001863 }
1864
1865 if (mTexStorage && mTexStorage->isRenderTarget())
1866 {
Jamie Madill22f843a2013-10-24 17:49:36 -04001867 for (int level = 1; level <= q; level++)
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001868 {
Jamie Madill22f843a2013-10-24 17:49:36 -04001869 mTexStorage->generateMipmap(level);
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001870
Jamie Madill22f843a2013-10-24 17:49:36 -04001871 mImageArray[level]->markClean();
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001872 }
1873 }
1874 else
1875 {
Jamie Madill22f843a2013-10-24 17:49:36 -04001876 for (int level = 1; level <= q; level++)
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001877 {
Jamie Madill22f843a2013-10-24 17:49:36 -04001878 mRenderer->generateMipmap(mImageArray[level], mImageArray[level - 1]);
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001879 }
1880 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001881}
1882
Jamie Madilld3d2a342013-10-07 10:46:35 -04001883const rx::Image *Texture3D::getBaseLevelImage() const
1884{
1885 return mImageArray[0];
1886}
1887
Jamie Madill2ebab852013-10-24 17:49:42 -04001888rx::TextureStorageInterface *Texture3D::getBaseLevelStorage()
1889{
1890 return mTexStorage;
1891}
1892
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001893void Texture3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1894{
1895 if (xoffset + width > mImageArray[level]->getWidth() || yoffset + height > mImageArray[level]->getHeight() || zoffset >= mImageArray[level]->getDepth())
1896 {
1897 return gl::error(GL_INVALID_VALUE);
1898 }
1899
Jamie Madill07edd442013-07-19 16:36:58 -04001900 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
1901 // the current level we're copying to is defined (with appropriate format, width & height)
1902 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
1903
1904 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001905 {
1906 mImageArray[level]->copy(xoffset, yoffset, zoffset, x, y, width, height, source);
1907 mDirtyImages = true;
1908 }
1909 else
1910 {
Jamie Madille83d1a92013-10-24 17:49:33 -04001911 ensureRenderTarget();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001912
Jamie Madill07bb8cf2013-10-24 17:49:44 -04001913 if (isValidLevel(level))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001914 {
Jamie Madill169d1112013-10-24 17:49:37 -04001915 updateStorageLevel(level);
Jamie Madill07edd442013-07-19 16:36:58 -04001916
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001917 gl::Rectangle sourceRect;
1918 sourceRect.x = x;
1919 sourceRect.width = width;
1920 sourceRect.y = y;
1921 sourceRect.height = height;
1922
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001923 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1924
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001925 mRenderer->copyImage(source, sourceRect,
Jamie Madilld3d2a342013-10-07 10:46:35 -04001926 gl::GetFormat(getBaseLevelInternalFormat(), clientVersion),
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001927 xoffset, yoffset, zoffset, mTexStorage, level);
1928 }
1929 }
1930}
1931
Jamie Madillf8989902013-07-19 16:36:58 -04001932bool Texture3D::isSamplerComplete(const SamplerState &samplerState) const
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001933{
Jamie Madilld3d2a342013-10-07 10:46:35 -04001934 GLsizei width = getBaseLevelWidth();
1935 GLsizei height = getBaseLevelHeight();
1936 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001937
1938 if (width <= 0 || height <= 0 || depth <= 0)
1939 {
1940 return false;
1941 }
1942
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001943 if (!IsTextureFilteringSupported(getInternalFormat(0), mRenderer))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001944 {
Jamie Madillf8989902013-07-19 16:36:58 -04001945 if (samplerState.magFilter != GL_NEAREST ||
1946 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001947 {
1948 return false;
1949 }
1950 }
1951
Jamie Madillf8989902013-07-19 16:36:58 -04001952 if (IsMipmapFiltered(samplerState) && !isMipmapComplete())
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001953 {
1954 return false;
1955 }
1956
1957 return true;
1958}
1959
1960bool Texture3D::isMipmapComplete() const
1961{
Jamie Madill22f843a2013-10-24 17:49:36 -04001962 int q = mipLevels();
Jamie Madill07edd442013-07-19 16:36:58 -04001963
1964 for (int level = 0; level <= q; level++)
1965 {
1966 if (!isLevelComplete(level))
1967 {
1968 return false;
1969 }
1970 }
1971
1972 return true;
1973}
1974
1975bool Texture3D::isLevelComplete(int level) const
1976{
1977 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1978
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001979 if (isImmutable())
1980 {
1981 return true;
1982 }
1983
Jamie Madilld3d2a342013-10-07 10:46:35 -04001984 GLsizei width = getBaseLevelWidth();
1985 GLsizei height = getBaseLevelHeight();
1986 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001987
1988 if (width <= 0 || height <= 0 || depth <= 0)
1989 {
1990 return false;
1991 }
1992
Jamie Madill07edd442013-07-19 16:36:58 -04001993 if (level == 0)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001994 {
Jamie Madill07edd442013-07-19 16:36:58 -04001995 return true;
1996 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001997
Jamie Madill07edd442013-07-19 16:36:58 -04001998 rx::Image *levelImage = mImageArray[level];
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001999
Jamie Madilld3d2a342013-10-07 10:46:35 -04002000 if (levelImage->getInternalFormat() != getBaseLevelInternalFormat())
Jamie Madill07edd442013-07-19 16:36:58 -04002001 {
2002 return false;
2003 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002004
Jamie Madill07edd442013-07-19 16:36:58 -04002005 if (levelImage->getWidth() != std::max(1, width >> level))
2006 {
2007 return false;
2008 }
2009
2010 if (levelImage->getHeight() != std::max(1, height >> level))
2011 {
2012 return false;
2013 }
2014
2015 if (levelImage->getDepth() != std::max(1, depth >> level))
2016 {
2017 return false;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002018 }
2019
2020 return true;
2021}
2022
Geoff Lang8040f572013-07-25 16:49:54 -04002023Renderbuffer *Texture3D::getRenderbuffer(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002024{
Geoff Lang8040f572013-07-25 16:49:54 -04002025 Renderbuffer *renderBuffer = mRenderbufferProxies.get(level, layer);
2026 if (!renderBuffer)
2027 {
Geoff Langd5d8e392013-07-25 16:53:03 -04002028 renderBuffer = new Renderbuffer(mRenderer, id(), new RenderbufferTexture3DLayer(this, level, layer));
2029 mRenderbufferProxies.add(level, 0, renderBuffer);
Geoff Lang8040f572013-07-25 16:49:54 -04002030 }
2031
2032 return renderBuffer;
2033}
2034
2035unsigned int Texture3D::getRenderTargetSerial(GLint level, GLint layer)
2036{
Jamie Madille83d1a92013-10-24 17:49:33 -04002037 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(level, layer) : 0);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002038}
2039
Jamie Madill07bb8cf2013-10-24 17:49:44 -04002040bool Texture3D::isValidLevel(int level) const
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002041{
Jamie Madill4cfff5f2013-10-24 17:49:46 -04002042 return (mTexStorage ? (level >= mTexStorage->getBaseLevel() && level < mTexStorage->getMaxLevel()) : 0);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002043}
2044
Jamie Madill73b5d062013-10-24 17:49:38 -04002045void Texture3D::initializeStorage(bool renderTarget)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002046{
Jamie Madille664e202013-10-24 17:49:40 -04002047 // Only initialize the first time this texture is used as a render target or shader resource
2048 if (mTexStorage)
2049 {
2050 return;
2051 }
2052
2053 // do not attempt to create storage for nonexistant data
2054 if (!isLevelComplete(0))
2055 {
2056 return;
2057 }
2058
2059 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
2060
2061 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
2062 ASSERT(mTexStorage);
2063
2064 // flush image data to the storage
2065 updateStorage();
2066}
2067
2068rx::TextureStorageInterface3D *Texture3D::createCompleteStorage(bool renderTarget) const
2069{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002070 GLsizei width = getBaseLevelWidth();
2071 GLsizei height = getBaseLevelHeight();
2072 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002073
Jamie Madille664e202013-10-24 17:49:40 -04002074 ASSERT(width > 0 && height > 0 && depth > 0);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002075
Jamie Madille664e202013-10-24 17:49:40 -04002076 // use existing storage level count, when previously specified by TexStorage*D
Jamie Madill4cfff5f2013-10-24 17:49:46 -04002077 GLint levels = (mTexStorage ? mTexStorage->getMaxLevel() : creationLevels(width, height, depth));
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002078
Jamie Madill4cfff5f2013-10-24 17:49:46 -04002079 return new rx::TextureStorageInterface3D(mRenderer, 0, levels, getBaseLevelInternalFormat(), renderTarget, width, height, depth);
Jamie Madille664e202013-10-24 17:49:40 -04002080}
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002081
Jamie Madille664e202013-10-24 17:49:40 -04002082void Texture3D::setCompleteTexStorage(rx::TextureStorageInterface3D *newCompleteTexStorage)
2083{
2084 SafeDelete(mTexStorage);
2085 mTexStorage = newCompleteTexStorage;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002086 mDirtyImages = true;
Jamie Madille664e202013-10-24 17:49:40 -04002087
2088 // We do not support managed 3D storage, as that is D3D9/ES2-only
2089 ASSERT(!mTexStorage->isManaged());
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002090}
2091
Jamie Madill169d1112013-10-24 17:49:37 -04002092void Texture3D::updateStorage()
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002093{
Jamie Madill4cfff5f2013-10-24 17:49:46 -04002094 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002095 {
Jamie Madilld9b9a502013-10-10 17:46:13 -04002096 if (isLevelComplete(level))
2097 {
Jamie Madill169d1112013-10-24 17:49:37 -04002098 updateStorageLevel(level);
Jamie Madilld9b9a502013-10-10 17:46:13 -04002099 }
Jamie Madill07edd442013-07-19 16:36:58 -04002100 }
2101}
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002102
Jamie Madill169d1112013-10-24 17:49:37 -04002103void Texture3D::updateStorageLevel(int level)
Jamie Madill07edd442013-07-19 16:36:58 -04002104{
2105 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
Jamie Madillaee7ad82013-10-10 16:07:32 -04002106 ASSERT(isLevelComplete(level));
Jamie Madill07edd442013-07-19 16:36:58 -04002107
Jamie Madillaee7ad82013-10-10 16:07:32 -04002108 if (mImageArray[level]->isDirty())
Jamie Madill07edd442013-07-19 16:36:58 -04002109 {
Jamie Madillaee7ad82013-10-10 16:07:32 -04002110 commitRect(level, 0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002111 }
2112}
2113
Jamie Madille83d1a92013-10-24 17:49:33 -04002114bool Texture3D::ensureRenderTarget()
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002115{
Jamie Madille664e202013-10-24 17:49:40 -04002116 initializeStorage(true);
2117
2118 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0 && getBaseLevelDepth() > 0)
Jamie Madille83d1a92013-10-24 17:49:33 -04002119 {
Jamie Madille664e202013-10-24 17:49:40 -04002120 ASSERT(mTexStorage);
2121 if (!mTexStorage->isRenderTarget())
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002122 {
Jamie Madille664e202013-10-24 17:49:40 -04002123 rx::TextureStorageInterface3D *newRenderTargetStorage = createCompleteStorage(true);
2124
2125 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002126 {
Jamie Madille664e202013-10-24 17:49:40 -04002127 delete newRenderTargetStorage;
Jamie Madille83d1a92013-10-24 17:49:33 -04002128 return gl::error(GL_OUT_OF_MEMORY, false);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002129 }
Jamie Madille664e202013-10-24 17:49:40 -04002130
2131 setCompleteTexStorage(newRenderTargetStorage);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002132 }
2133 }
2134
Jamie Madille83d1a92013-10-24 17:49:33 -04002135 return (mTexStorage && mTexStorage->isRenderTarget());
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002136}
2137
Jamie Madilla2d4e552013-10-10 15:12:01 -04002138rx::RenderTarget *Texture3D::getRenderTarget(GLint level)
2139{
2140 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04002141 if (!ensureRenderTarget())
Jamie Madilla2d4e552013-10-10 15:12:01 -04002142 {
2143 return NULL;
2144 }
2145
Jamie Madill169d1112013-10-24 17:49:37 -04002146 updateStorageLevel(level);
Jamie Madilla2d4e552013-10-10 15:12:01 -04002147
2148 // ensure this is NOT a depth texture
2149 if (isDepth(level))
2150 {
2151 return NULL;
2152 }
2153
2154 return mTexStorage->getRenderTarget(level);
2155}
2156
Geoff Lang8040f572013-07-25 16:49:54 -04002157rx::RenderTarget *Texture3D::getRenderTarget(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002158{
Geoff Lang8040f572013-07-25 16:49:54 -04002159 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04002160 if (!ensureRenderTarget())
Geoff Lang8040f572013-07-25 16:49:54 -04002161 {
2162 return NULL;
2163 }
2164
Jamie Madill169d1112013-10-24 17:49:37 -04002165 updateStorage();
Geoff Lang8040f572013-07-25 16:49:54 -04002166
2167 // ensure this is NOT a depth texture
2168 if (isDepth(level))
2169 {
2170 return NULL;
2171 }
2172
2173 return mTexStorage->getRenderTarget(level, layer);
2174}
2175
2176rx::RenderTarget *Texture3D::getDepthStencil(GLint level, GLint layer)
2177{
2178 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04002179 if (!ensureRenderTarget())
Geoff Lang8040f572013-07-25 16:49:54 -04002180 {
2181 return NULL;
2182 }
2183
Jamie Madill169d1112013-10-24 17:49:37 -04002184 updateStorageLevel(level);
Geoff Lang8040f572013-07-25 16:49:54 -04002185
2186 // ensure this is a depth texture
2187 if (!isDepth(level))
2188 {
2189 return NULL;
2190 }
2191
2192 return mTexStorage->getRenderTarget(level, layer);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002193}
2194
Geoff Lang005df412013-10-16 14:12:50 -04002195void Texture3D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002196{
2197 // If there currently is a corresponding storage texture image, it has these parameters
Jamie Madilld3d2a342013-10-07 10:46:35 -04002198 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2199 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
2200 const int storageDepth = std::max(1, getBaseLevelDepth() >> level);
Geoff Lang005df412013-10-16 14:12:50 -04002201 const GLenum storageFormat = getBaseLevelInternalFormat();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002202
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00002203 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, false);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002204
2205 if (mTexStorage)
2206 {
Jamie Madill4cfff5f2013-10-24 17:49:46 -04002207 const int storageLevels = mTexStorage->getMaxLevel();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002208
2209 if ((level >= storageLevels && storageLevels != 0) ||
2210 width != storageWidth ||
2211 height != storageHeight ||
2212 depth != storageDepth ||
2213 internalformat != storageFormat) // Discard mismatched storage
2214 {
2215 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
2216 {
2217 mImageArray[i]->markDirty();
2218 }
2219
2220 delete mTexStorage;
2221 mTexStorage = NULL;
2222 mDirtyImages = true;
2223 }
2224 }
2225}
2226
2227void Texture3D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth)
2228{
Jamie Madill07bb8cf2013-10-24 17:49:44 -04002229 if (isValidLevel(level))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002230 {
2231 rx::Image *image = mImageArray[level];
Jamie Madill169d1112013-10-24 17:49:37 -04002232 if (image->copyToStorage(mTexStorage, level, xoffset, yoffset, zoffset, width, height, depth))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002233 {
2234 image->markClean();
2235 }
2236 }
2237}
2238
Geoff Lang4907f2c2013-07-25 12:53:57 -04002239Texture2DArray::Texture2DArray(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_2D_ARRAY)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002240{
2241 mTexStorage = NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002242
2243 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2244 {
2245 mLayerCounts[level] = 0;
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002246 mImageArray[level] = NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002247 }
2248}
2249
2250Texture2DArray::~Texture2DArray()
2251{
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002252 delete mTexStorage;
2253 mTexStorage = NULL;
Jamie Madill884a4622013-10-24 17:49:41 -04002254
2255 deleteImages();
2256}
2257
2258void Texture2DArray::deleteImages()
2259{
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002260 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2261 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002262 for (int layer = 0; layer < mLayerCounts[level]; ++layer)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002263 {
2264 delete mImageArray[level][layer];
2265 }
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002266 delete[] mImageArray[level];
Jamie Madill884a4622013-10-24 17:49:41 -04002267 mImageArray[level] = NULL;
2268 mLayerCounts[level] = 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002269 }
2270}
2271
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002272GLsizei Texture2DArray::getWidth(GLint level) const
2273{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002274 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 +00002275}
2276
2277GLsizei Texture2DArray::getHeight(GLint level) const
2278{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002279 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 +00002280}
2281
Jamie Madillb8f8b892014-01-07 10:12:50 -05002282GLsizei Texture2DArray::getLayers(GLint level) const
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002283{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002284 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mLayerCounts[level] : 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002285}
2286
2287GLenum Texture2DArray::getInternalFormat(GLint level) const
2288{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002289 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 +00002290}
2291
2292GLenum Texture2DArray::getActualFormat(GLint level) const
2293{
Geoff Langcbf727a2014-02-10 12:50:45 -05002294 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getActualFormat() : GL_NONE;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002295}
2296
2297bool Texture2DArray::isCompressed(GLint level) const
2298{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00002299 return IsFormatCompressed(getInternalFormat(level), mRenderer->getCurrentClientVersion());
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002300}
2301
2302bool Texture2DArray::isDepth(GLint level) const
2303{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00002304 return GetDepthBits(getInternalFormat(level), mRenderer->getCurrentClientVersion()) > 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002305}
2306
Geoff Lang005df412013-10-16 14:12:50 -04002307void 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 +00002308{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00002309 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Geoff Lang005df412013-10-16 14:12:50 -04002310 GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
2311 : GetSizedInternalFormat(format, type, clientVersion);
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00002312 redefineImage(level, sizedInternalFormat, width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002313
Jamie Madill88f18f42013-09-18 14:36:19 -04002314 GLsizei inputDepthPitch = gl::GetDepthPitch(sizedInternalFormat, type, clientVersion, width, height, unpack.alignment);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002315
2316 for (int i = 0; i < depth; i++)
2317 {
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002318 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
Jamie Madill88f18f42013-09-18 14:36:19 -04002319 Texture::setImage(unpack, type, layerPixels, mImageArray[level][i]);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002320 }
2321}
2322
2323void Texture2DArray::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
2324{
2325 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
2326 redefineImage(level, format, width, height, depth);
2327
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002328 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2329 GLsizei inputDepthPitch = gl::GetDepthPitch(format, GL_UNSIGNED_BYTE, clientVersion, width, height, 1);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002330
2331 for (int i = 0; i < depth; i++)
2332 {
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002333 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002334 Texture::setCompressedImage(imageSize, layerPixels, mImageArray[level][i]);
2335 }
2336}
2337
Jamie Madill88f18f42013-09-18 14:36:19 -04002338void 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 +00002339{
Geoff Lang005df412013-10-16 14:12:50 -04002340 GLenum internalformat = getInternalFormat(level);
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002341 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Jamie Madill88f18f42013-09-18 14:36:19 -04002342 GLsizei inputDepthPitch = gl::GetDepthPitch(internalformat, type, clientVersion, width, height, unpack.alignment);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002343
2344 for (int i = 0; i < depth; i++)
2345 {
2346 int layer = zoffset + i;
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002347 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002348
Jamie Madill88f18f42013-09-18 14:36:19 -04002349 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 +00002350 {
2351 commitRect(level, xoffset, yoffset, layer, width, height);
2352 }
2353 }
2354}
2355
2356void Texture2DArray::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
2357{
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002358 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2359 GLsizei inputDepthPitch = gl::GetDepthPitch(format, GL_UNSIGNED_BYTE, clientVersion, width, height, 1);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002360
2361 for (int i = 0; i < depth; i++)
2362 {
2363 int layer = zoffset + i;
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002364 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002365
2366 if (Texture::subImageCompressed(xoffset, yoffset, zoffset, width, height, 1, format, imageSize, layerPixels, mImageArray[level][layer]))
2367 {
2368 commitRect(level, xoffset, yoffset, layer, width, height);
2369 }
2370 }
2371}
2372
2373void Texture2DArray::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2374{
Jamie Madill884a4622013-10-24 17:49:41 -04002375 deleteImages();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002376
2377 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2378 {
Jamie Madill884a4622013-10-24 17:49:41 -04002379 GLsizei levelWidth = std::max(1, width >> level);
2380 GLsizei levelHeight = std::max(1, height >> level);
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002381
Jamie Madill884a4622013-10-24 17:49:41 -04002382 mLayerCounts[level] = (level < levels ? depth : 0);
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002383
Jamie Madill884a4622013-10-24 17:49:41 -04002384 if (mLayerCounts[level] > 0)
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002385 {
2386 // Create new images for this level
Jamie Madill884a4622013-10-24 17:49:41 -04002387 mImageArray[level] = new rx::Image*[mLayerCounts[level]];
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002388
2389 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002390 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002391 mImageArray[level][layer] = mRenderer->createImage();
2392 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, levelWidth,
2393 levelHeight, 1, true);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002394 }
2395 }
2396 }
2397
Jamie Madill884a4622013-10-24 17:49:41 -04002398 mImmutable = true;
Jamie Madill4cfff5f2013-10-24 17:49:46 -04002399 setCompleteTexStorage(new rx::TextureStorageInterface2DArray(mRenderer, 0, levels, internalformat, IsRenderTargetUsage(mUsage), width, height, depth));
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002400}
2401
2402void Texture2DArray::generateMipmaps()
2403{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002404 int baseWidth = getBaseLevelWidth();
2405 int baseHeight = getBaseLevelHeight();
2406 int baseDepth = getBaseLevelDepth();
2407 GLenum baseFormat = getBaseLevelInternalFormat();
2408
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00002409 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Jamie Madill22f843a2013-10-24 17:49:36 -04002410 int q = mipLevels();
2411 for (int level = 1; level <= q; level++)
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00002412 {
Jamie Madill22f843a2013-10-24 17:49:36 -04002413 redefineImage(level, baseFormat, std::max(baseWidth >> level, 1), std::max(baseHeight >> level, 1), baseDepth);
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00002414 }
2415
2416 if (mTexStorage && mTexStorage->isRenderTarget())
2417 {
2418 for (int level = 1; level <= q; level++)
2419 {
2420 mTexStorage->generateMipmap(level);
2421
2422 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2423 {
2424 mImageArray[level][layer]->markClean();
2425 }
2426 }
2427 }
2428 else
2429 {
2430 for (int level = 1; level <= q; level++)
2431 {
2432 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2433 {
2434 mRenderer->generateMipmap(mImageArray[level][layer], mImageArray[level - 1][layer]);
2435 }
2436 }
2437 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002438}
2439
Jamie Madilld3d2a342013-10-07 10:46:35 -04002440const rx::Image *Texture2DArray::getBaseLevelImage() const
2441{
Jamie Madill152ed092013-10-09 17:01:15 -04002442 return (mLayerCounts[0] > 0 ? mImageArray[0][0] : NULL);
Jamie Madilld3d2a342013-10-07 10:46:35 -04002443}
2444
Jamie Madill2ebab852013-10-24 17:49:42 -04002445rx::TextureStorageInterface *Texture2DArray::getBaseLevelStorage()
2446{
2447 return mTexStorage;
2448}
2449
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002450void Texture2DArray::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
2451{
Jamie Madillb8f8b892014-01-07 10:12:50 -05002452 if (xoffset + width > getWidth(level) || yoffset + height > getHeight(level) || zoffset >= getLayers(level) || getLayers(level) == 0)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002453 {
2454 return gl::error(GL_INVALID_VALUE);
2455 }
2456
Jamie Madill07edd442013-07-19 16:36:58 -04002457 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
2458 // the current level we're copying to is defined (with appropriate format, width & height)
2459 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
2460
2461 if (!mImageArray[level][0]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002462 {
2463 mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, x, y, width, height, source);
2464 mDirtyImages = true;
2465 }
2466 else
2467 {
Jamie Madille83d1a92013-10-24 17:49:33 -04002468 ensureRenderTarget();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002469
Jamie Madill07bb8cf2013-10-24 17:49:44 -04002470 if (isValidLevel(level))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002471 {
Jamie Madill169d1112013-10-24 17:49:37 -04002472 updateStorageLevel(level);
Jamie Madill07edd442013-07-19 16:36:58 -04002473
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002474 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2475
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002476 gl::Rectangle sourceRect;
2477 sourceRect.x = x;
2478 sourceRect.width = width;
2479 sourceRect.y = y;
2480 sourceRect.height = height;
2481
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002482 mRenderer->copyImage(source, sourceRect, gl::GetFormat(getInternalFormat(0), clientVersion),
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002483 xoffset, yoffset, zoffset, mTexStorage, level);
2484 }
2485 }
2486}
2487
Jamie Madillf8989902013-07-19 16:36:58 -04002488bool Texture2DArray::isSamplerComplete(const SamplerState &samplerState) const
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002489{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002490 GLsizei width = getBaseLevelWidth();
2491 GLsizei height = getBaseLevelHeight();
Jamie Madillb8f8b892014-01-07 10:12:50 -05002492 GLsizei depth = getLayers(0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002493
2494 if (width <= 0 || height <= 0 || depth <= 0)
2495 {
2496 return false;
2497 }
2498
Jamie Madilld3d2a342013-10-07 10:46:35 -04002499 if (!IsTextureFilteringSupported(getBaseLevelInternalFormat(), mRenderer))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002500 {
Jamie Madillf8989902013-07-19 16:36:58 -04002501 if (samplerState.magFilter != GL_NEAREST ||
2502 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002503 {
2504 return false;
2505 }
2506 }
2507
Jamie Madillf8989902013-07-19 16:36:58 -04002508 if (IsMipmapFiltered(samplerState) && !isMipmapComplete())
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002509 {
2510 return false;
2511 }
2512
2513 return true;
2514}
2515
2516bool Texture2DArray::isMipmapComplete() const
2517{
Jamie Madill22f843a2013-10-24 17:49:36 -04002518 int q = mipLevels();
Jamie Madill07edd442013-07-19 16:36:58 -04002519
2520 for (int level = 1; level <= q; level++)
2521 {
2522 if (!isLevelComplete(level))
2523 {
2524 return false;
2525 }
2526 }
2527
2528 return true;
2529}
2530
2531bool Texture2DArray::isLevelComplete(int level) const
2532{
Jamie Madillb8f8b892014-01-07 10:12:50 -05002533 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray));
Jamie Madill07edd442013-07-19 16:36:58 -04002534
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002535 if (isImmutable())
2536 {
2537 return true;
2538 }
2539
Jamie Madilld3d2a342013-10-07 10:46:35 -04002540 GLsizei width = getBaseLevelWidth();
2541 GLsizei height = getBaseLevelHeight();
Jamie Madillb8f8b892014-01-07 10:12:50 -05002542 GLsizei layers = getLayers(0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002543
Jamie Madillb8f8b892014-01-07 10:12:50 -05002544 if (width <= 0 || height <= 0 || layers <= 0)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002545 {
2546 return false;
2547 }
2548
Jamie Madill07edd442013-07-19 16:36:58 -04002549 if (level == 0)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002550 {
Jamie Madill07edd442013-07-19 16:36:58 -04002551 return true;
2552 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002553
Jamie Madill07edd442013-07-19 16:36:58 -04002554 if (getInternalFormat(level) != getInternalFormat(0))
2555 {
2556 return false;
2557 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002558
Jamie Madill07edd442013-07-19 16:36:58 -04002559 if (getWidth(level) != std::max(1, width >> level))
2560 {
2561 return false;
2562 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002563
Jamie Madill07edd442013-07-19 16:36:58 -04002564 if (getHeight(level) != std::max(1, height >> level))
2565 {
2566 return false;
2567 }
2568
Jamie Madillb8f8b892014-01-07 10:12:50 -05002569 if (getLayers(level) != layers)
Jamie Madill07edd442013-07-19 16:36:58 -04002570 {
2571 return false;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002572 }
2573
2574 return true;
2575}
2576
Geoff Lang8040f572013-07-25 16:49:54 -04002577Renderbuffer *Texture2DArray::getRenderbuffer(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002578{
Geoff Lang8040f572013-07-25 16:49:54 -04002579 Renderbuffer *renderBuffer = mRenderbufferProxies.get(level, layer);
2580 if (!renderBuffer)
2581 {
Geoff Langd5d8e392013-07-25 16:53:03 -04002582 renderBuffer = new Renderbuffer(mRenderer, id(), new RenderbufferTexture2DArrayLayer(this, level, layer));
2583 mRenderbufferProxies.add(level, 0, renderBuffer);
Geoff Lang8040f572013-07-25 16:49:54 -04002584 }
2585
2586 return renderBuffer;
2587}
2588
Jamie Madille83d1a92013-10-24 17:49:33 -04002589unsigned int Texture2DArray::getRenderTargetSerial(GLint level, GLint layer)
Geoff Lang8040f572013-07-25 16:49:54 -04002590{
Jamie Madille83d1a92013-10-24 17:49:33 -04002591 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(level, layer) : 0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002592}
2593
Jamie Madill07bb8cf2013-10-24 17:49:44 -04002594bool Texture2DArray::isValidLevel(int level) const
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002595{
Jamie Madill4cfff5f2013-10-24 17:49:46 -04002596 return (mTexStorage ? (level >= mTexStorage->getBaseLevel() && level < mTexStorage->getMaxLevel()) : 0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002597}
2598
Jamie Madill73b5d062013-10-24 17:49:38 -04002599void Texture2DArray::initializeStorage(bool renderTarget)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002600{
Jamie Madill884a4622013-10-24 17:49:41 -04002601 // Only initialize the first time this texture is used as a render target or shader resource
2602 if (mTexStorage)
2603 {
2604 return;
2605 }
2606
2607 // do not attempt to create storage for nonexistant data
2608 if (!isLevelComplete(0))
2609 {
2610 return;
2611 }
2612
2613 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
2614
2615 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
2616 ASSERT(mTexStorage);
2617
2618 // flush image data to the storage
2619 updateStorage();
2620}
2621
2622rx::TextureStorageInterface2DArray *Texture2DArray::createCompleteStorage(bool renderTarget) const
2623{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002624 GLsizei width = getBaseLevelWidth();
2625 GLsizei height = getBaseLevelHeight();
Jamie Madillb8f8b892014-01-07 10:12:50 -05002626 GLsizei depth = getLayers(0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002627
Jamie Madill884a4622013-10-24 17:49:41 -04002628 ASSERT(width > 0 && height > 0 && depth > 0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002629
Jamie Madill884a4622013-10-24 17:49:41 -04002630 // use existing storage level count, when previously specified by TexStorage*D
Jamie Madill6b7440c2013-10-24 17:49:47 -04002631 GLint levels = (mTexStorage ? mTexStorage->getMaxLevel() : creationLevels(width, height, 1));
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002632
Jamie Madill4cfff5f2013-10-24 17:49:46 -04002633 return new rx::TextureStorageInterface2DArray(mRenderer, 0, levels, getBaseLevelInternalFormat(), renderTarget, width, height, depth);
Jamie Madill884a4622013-10-24 17:49:41 -04002634}
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002635
Jamie Madill884a4622013-10-24 17:49:41 -04002636void Texture2DArray::setCompleteTexStorage(rx::TextureStorageInterface2DArray *newCompleteTexStorage)
2637{
2638 SafeDelete(mTexStorage);
2639 mTexStorage = newCompleteTexStorage;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002640 mDirtyImages = true;
Jamie Madill884a4622013-10-24 17:49:41 -04002641
2642 // We do not support managed 2D array storage, as managed storage is ES2/D3D9 only
2643 ASSERT(!mTexStorage->isManaged());
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002644}
2645
Jamie Madill169d1112013-10-24 17:49:37 -04002646void Texture2DArray::updateStorage()
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002647{
Jamie Madill4cfff5f2013-10-24 17:49:46 -04002648 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002649 {
Jamie Madilld9b9a502013-10-10 17:46:13 -04002650 if (isLevelComplete(level))
2651 {
Jamie Madill169d1112013-10-24 17:49:37 -04002652 updateStorageLevel(level);
Jamie Madilld9b9a502013-10-10 17:46:13 -04002653 }
Jamie Madill07edd442013-07-19 16:36:58 -04002654 }
2655}
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002656
Jamie Madill169d1112013-10-24 17:49:37 -04002657void Texture2DArray::updateStorageLevel(int level)
Jamie Madill07edd442013-07-19 16:36:58 -04002658{
Jamie Madillaee7ad82013-10-10 16:07:32 -04002659 ASSERT(level >= 0 && level < (int)ArraySize(mLayerCounts));
2660 ASSERT(isLevelComplete(level));
2661
Jamie Madill07edd442013-07-19 16:36:58 -04002662 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2663 {
Jamie Madillaee7ad82013-10-10 16:07:32 -04002664 ASSERT(mImageArray[level] != NULL && mImageArray[level][layer] != NULL);
2665 if (mImageArray[level][layer]->isDirty())
Jamie Madill07edd442013-07-19 16:36:58 -04002666 {
Jamie Madillaee7ad82013-10-10 16:07:32 -04002667 commitRect(level, 0, 0, layer, getWidth(level), getHeight(level));
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002668 }
2669 }
2670}
2671
Jamie Madille83d1a92013-10-24 17:49:33 -04002672bool Texture2DArray::ensureRenderTarget()
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002673{
Jamie Madill884a4622013-10-24 17:49:41 -04002674 initializeStorage(true);
2675
Jamie Madillb8f8b892014-01-07 10:12:50 -05002676 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0 && getLayers(0) > 0)
Jamie Madille83d1a92013-10-24 17:49:33 -04002677 {
Jamie Madill884a4622013-10-24 17:49:41 -04002678 ASSERT(mTexStorage);
2679 if (!mTexStorage->isRenderTarget())
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002680 {
Jamie Madill884a4622013-10-24 17:49:41 -04002681 rx::TextureStorageInterface2DArray *newRenderTargetStorage = createCompleteStorage(true);
2682
2683 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002684 {
Jamie Madill884a4622013-10-24 17:49:41 -04002685 delete newRenderTargetStorage;
Jamie Madille83d1a92013-10-24 17:49:33 -04002686 return gl::error(GL_OUT_OF_MEMORY, false);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002687 }
Jamie Madill884a4622013-10-24 17:49:41 -04002688
2689 setCompleteTexStorage(newRenderTargetStorage);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002690 }
2691 }
2692
Jamie Madille83d1a92013-10-24 17:49:33 -04002693 return (mTexStorage && mTexStorage->isRenderTarget());
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002694}
2695
Geoff Lang8040f572013-07-25 16:49:54 -04002696rx::RenderTarget *Texture2DArray::getRenderTarget(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002697{
Geoff Lang8040f572013-07-25 16:49:54 -04002698 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04002699 if (!ensureRenderTarget())
Geoff Lang8040f572013-07-25 16:49:54 -04002700 {
2701 return NULL;
2702 }
2703
Jamie Madill169d1112013-10-24 17:49:37 -04002704 updateStorageLevel(level);
Geoff Lang8040f572013-07-25 16:49:54 -04002705
2706 // ensure this is NOT a depth texture
2707 if (isDepth(level))
2708 {
2709 return NULL;
2710 }
2711
2712 return mTexStorage->getRenderTarget(level, layer);
2713}
2714
2715rx::RenderTarget *Texture2DArray::getDepthStencil(GLint level, GLint layer)
2716{
2717 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04002718 if (!ensureRenderTarget())
Geoff Lang8040f572013-07-25 16:49:54 -04002719 {
2720 return NULL;
2721 }
2722
Jamie Madill169d1112013-10-24 17:49:37 -04002723 updateStorageLevel(level);
Geoff Lang8040f572013-07-25 16:49:54 -04002724
2725 // ensure this is a depth texture
2726 if (!isDepth(level))
2727 {
2728 return NULL;
2729 }
2730
2731 return mTexStorage->getRenderTarget(level, layer);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002732}
2733
Geoff Lang005df412013-10-16 14:12:50 -04002734void Texture2DArray::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002735{
2736 // If there currently is a corresponding storage texture image, it has these parameters
Jamie Madilld3d2a342013-10-07 10:46:35 -04002737 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2738 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
Jamie Madillb8f8b892014-01-07 10:12:50 -05002739 const int storageDepth = getLayers(0);
Geoff Lang005df412013-10-16 14:12:50 -04002740 const GLenum storageFormat = getBaseLevelInternalFormat();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002741
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002742 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002743 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002744 delete mImageArray[level][layer];
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002745 }
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002746 delete[] mImageArray[level];
Jamie Madill152ed092013-10-09 17:01:15 -04002747 mImageArray[level] = NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002748 mLayerCounts[level] = depth;
2749
Jamie Madill152ed092013-10-09 17:01:15 -04002750 if (depth > 0)
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002751 {
Jamie Madill152ed092013-10-09 17:01:15 -04002752 mImageArray[level] = new rx::Image*[depth]();
2753
2754 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2755 {
2756 mImageArray[level][layer] = mRenderer->createImage();
2757 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, width, height, 1, false);
2758 }
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002759 }
2760
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002761 if (mTexStorage)
2762 {
Jamie Madill4cfff5f2013-10-24 17:49:46 -04002763 const int storageLevels = mTexStorage->getMaxLevel();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002764
2765 if ((level >= storageLevels && storageLevels != 0) ||
2766 width != storageWidth ||
2767 height != storageHeight ||
2768 depth != storageDepth ||
2769 internalformat != storageFormat) // Discard mismatched storage
2770 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002771 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002772 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002773 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002774 {
2775 mImageArray[level][layer]->markDirty();
2776 }
2777 }
2778
2779 delete mTexStorage;
2780 mTexStorage = NULL;
2781 mDirtyImages = true;
2782 }
2783 }
2784}
2785
2786void Texture2DArray::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint layerTarget, GLsizei width, GLsizei height)
2787{
Jamie Madillb8f8b892014-01-07 10:12:50 -05002788 if (isValidLevel(level) && layerTarget < getLayers(level))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002789 {
2790 rx::Image *image = mImageArray[level][layerTarget];
Jamie Madill169d1112013-10-24 17:49:37 -04002791 if (image->copyToStorage(mTexStorage, level, xoffset, yoffset, layerTarget, width, height))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002792 {
2793 image->markClean();
2794 }
2795 }
2796}
2797
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00002798}