blob: 76f1dd22268cbc9e563a0013293c9a17d76428a2 [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.
784 if (gl::GetDepthBits(getInternalFormat(0), mRenderer->getCurrentClientVersion()) > 0)
785 {
786 if (mSamplerState.compareMode == GL_NONE)
787 {
788 if ((mSamplerState.minFilter != GL_NEAREST && mSamplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST) ||
789 mSamplerState.magFilter != GL_NEAREST)
790 {
791 return false;
792 }
793 }
794 }
795
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000796 return true;
797}
798
799// Tests for 2D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
800bool Texture2D::isMipmapComplete() const
801{
Jamie Madill22f843a2013-10-24 17:49:36 -0400802 int q = mipLevels();
Jamie Madill07edd442013-07-19 16:36:58 -0400803
804 for (int level = 0; level <= q; level++)
805 {
806 if (!isLevelComplete(level))
807 {
808 return false;
809 }
810 }
811
812 return true;
813}
814
815bool Texture2D::isLevelComplete(int level) const
816{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000817 if (isImmutable())
818 {
819 return true;
820 }
821
Jamie Madill648c9682014-01-21 16:50:58 -0500822 const rx::Image *baseImage = getBaseLevelImage();
823
824 GLsizei width = baseImage->getWidth();
825 GLsizei height = baseImage->getHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000826
827 if (width <= 0 || height <= 0)
828 {
829 return false;
830 }
831
Jamie Madill07edd442013-07-19 16:36:58 -0400832 // The base image level is complete if the width and height are positive
833 if (level == 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000834 {
Jamie Madill07edd442013-07-19 16:36:58 -0400835 return true;
836 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000837
Jamie Madill07edd442013-07-19 16:36:58 -0400838 ASSERT(level >= 1 && level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
839 rx::Image *image = mImageArray[level];
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000840
Jamie Madill648c9682014-01-21 16:50:58 -0500841 if (image->getInternalFormat() != baseImage->getInternalFormat())
Jamie Madill07edd442013-07-19 16:36:58 -0400842 {
843 return false;
844 }
845
846 if (image->getWidth() != std::max(1, width >> level))
847 {
848 return false;
849 }
850
851 if (image->getHeight() != std::max(1, height >> level))
852 {
853 return false;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000854 }
855
856 return true;
857}
858
859bool Texture2D::isCompressed(GLint level) const
860{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000861 return IsFormatCompressed(getInternalFormat(level), mRenderer->getCurrentClientVersion());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000862}
863
864bool Texture2D::isDepth(GLint level) const
865{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000866 return GetDepthBits(getInternalFormat(level), mRenderer->getCurrentClientVersion()) > 0;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000867}
868
daniel@transgaming.comf032cb82012-10-31 19:51:52 +0000869// Constructs a native texture resource from the texture images
Jamie Madill73b5d062013-10-24 17:49:38 -0400870void Texture2D::initializeStorage(bool renderTarget)
871{
872 // Only initialize the first time this texture is used as a render target or shader resource
873 if (mTexStorage)
874 {
875 return;
876 }
877
878 // do not attempt to create storage for nonexistant data
879 if (!isLevelComplete(0))
880 {
881 return;
882 }
883
884 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
885
886 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
887 ASSERT(mTexStorage);
888
889 // flush image data to the storage
890 updateStorage();
891}
892
893rx::TextureStorageInterface2D *Texture2D::createCompleteStorage(bool renderTarget) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000894{
Jamie Madilld3d2a342013-10-07 10:46:35 -0400895 GLsizei width = getBaseLevelWidth();
896 GLsizei height = getBaseLevelHeight();
daniel@transgaming.come6a09842012-09-17 21:28:55 +0000897
Jamie Madill73b5d062013-10-24 17:49:38 -0400898 ASSERT(width > 0 && height > 0);
daniel@transgaming.come6a09842012-09-17 21:28:55 +0000899
Jamie Madill73b5d062013-10-24 17:49:38 -0400900 // use existing storage level count, when previously specified by TexStorage*D
Jamie Madill6b7440c2013-10-24 17:49:47 -0400901 GLint levels = (mTexStorage ? mTexStorage->getMaxLevel() : creationLevels(width, height, 1));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000902
Jamie Madill4cfff5f2013-10-24 17:49:46 -0400903 return new rx::TextureStorageInterface2D(mRenderer, 0, levels, getBaseLevelInternalFormat(), renderTarget, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000904}
905
Jamie Madill169d1112013-10-24 17:49:37 -0400906void Texture2D::updateStorage()
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000907{
Jamie Madill4cfff5f2013-10-24 17:49:46 -0400908 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000909 {
Jamie Madill648c9682014-01-21 16:50:58 -0500910 if (mImageArray[level]->isDirty() && isLevelComplete(level))
Jamie Madilld9b9a502013-10-10 17:46:13 -0400911 {
Jamie Madill169d1112013-10-24 17:49:37 -0400912 updateStorageLevel(level);
Jamie Madilld9b9a502013-10-10 17:46:13 -0400913 }
Jamie Madill07edd442013-07-19 16:36:58 -0400914 }
915}
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000916
Jamie Madill169d1112013-10-24 17:49:37 -0400917void Texture2D::updateStorageLevel(int level)
Jamie Madill07edd442013-07-19 16:36:58 -0400918{
919 ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
Jamie Madillaee7ad82013-10-10 16:07:32 -0400920 ASSERT(isLevelComplete(level));
Jamie Madill07edd442013-07-19 16:36:58 -0400921
Jamie Madillaee7ad82013-10-10 16:07:32 -0400922 if (mImageArray[level]->isDirty())
Jamie Madill07edd442013-07-19 16:36:58 -0400923 {
Jamie Madillaee7ad82013-10-10 16:07:32 -0400924 commitRect(level, 0, 0, getWidth(level), getHeight(level));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000925 }
926}
927
Jamie Madille83d1a92013-10-24 17:49:33 -0400928bool Texture2D::ensureRenderTarget()
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000929{
Jamie Madill73b5d062013-10-24 17:49:38 -0400930 initializeStorage(true);
931
932 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0)
Jamie Madille83d1a92013-10-24 17:49:33 -0400933 {
Jamie Madill73b5d062013-10-24 17:49:38 -0400934 ASSERT(mTexStorage);
935 if (!mTexStorage->isRenderTarget())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000936 {
Jamie Madill73b5d062013-10-24 17:49:38 -0400937 rx::TextureStorageInterface2D *newRenderTargetStorage = createCompleteStorage(true);
938
939 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
940 {
941 delete newRenderTargetStorage;
Jamie Madille83d1a92013-10-24 17:49:33 -0400942 return gl::error(GL_OUT_OF_MEMORY, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000943 }
Jamie Madill73b5d062013-10-24 17:49:38 -0400944
945 setCompleteTexStorage(newRenderTargetStorage);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000946 }
947 }
948
Jamie Madille83d1a92013-10-24 17:49:33 -0400949 return (mTexStorage && mTexStorage->isRenderTarget());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000950}
951
952void Texture2D::generateMipmaps()
953{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000954 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Jamie Madill22f843a2013-10-24 17:49:36 -0400955 int q = mipLevels();
956 for (int level = 1; level <= q; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000957 {
Jamie Madill22f843a2013-10-24 17:49:36 -0400958 redefineImage(level, getBaseLevelInternalFormat(),
959 std::max(getBaseLevelWidth() >> level, 1),
960 std::max(getBaseLevelHeight() >> level, 1));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000961 }
962
963 if (mTexStorage && mTexStorage->isRenderTarget())
964 {
Jamie Madill22f843a2013-10-24 17:49:36 -0400965 for (int level = 1; level <= q; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000966 {
Jamie Madill22f843a2013-10-24 17:49:36 -0400967 mTexStorage->generateMipmap(level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000968
Jamie Madill22f843a2013-10-24 17:49:36 -0400969 mImageArray[level]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000970 }
971 }
972 else
973 {
Jamie Madill22f843a2013-10-24 17:49:36 -0400974 for (int level = 1; level <= q; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000975 {
Jamie Madill22f843a2013-10-24 17:49:36 -0400976 mRenderer->generateMipmap(mImageArray[level], mImageArray[level - 1]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000977 }
978 }
979}
980
Jamie Madilld3d2a342013-10-07 10:46:35 -0400981const rx::Image *Texture2D::getBaseLevelImage() const
982{
983 return mImageArray[0];
984}
985
Jamie Madill2ebab852013-10-24 17:49:42 -0400986rx::TextureStorageInterface *Texture2D::getBaseLevelStorage()
987{
988 return mTexStorage;
989}
990
Geoff Lang8040f572013-07-25 16:49:54 -0400991Renderbuffer *Texture2D::getRenderbuffer(GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000992{
Geoff Lang8040f572013-07-25 16:49:54 -0400993 Renderbuffer *renderBuffer = mRenderbufferProxies.get(level, 0);
994 if (!renderBuffer)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000995 {
Geoff Lang8040f572013-07-25 16:49:54 -0400996 renderBuffer = new Renderbuffer(mRenderer, id(), new RenderbufferTexture2D(this, level));
997 mRenderbufferProxies.add(level, 0, renderBuffer);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000998 }
999
Geoff Lang8040f572013-07-25 16:49:54 -04001000 return renderBuffer;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001001}
1002
Geoff Lang8040f572013-07-25 16:49:54 -04001003unsigned int Texture2D::getRenderTargetSerial(GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001004{
Jamie Madille83d1a92013-10-24 17:49:33 -04001005 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(level) : 0);
Geoff Lang8040f572013-07-25 16:49:54 -04001006}
1007
1008rx::RenderTarget *Texture2D::getRenderTarget(GLint level)
1009{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001010 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04001011 if (!ensureRenderTarget())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001012 {
1013 return NULL;
1014 }
1015
Jamie Madill169d1112013-10-24 17:49:37 -04001016 updateStorageLevel(level);
Geoff Lang8040f572013-07-25 16:49:54 -04001017
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001018 // ensure this is NOT a depth texture
Geoff Lang8040f572013-07-25 16:49:54 -04001019 if (isDepth(level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001020 {
1021 return NULL;
1022 }
daniel@transgaming.com34da3972012-12-20 21:10:29 +00001023
Geoff Lang8040f572013-07-25 16:49:54 -04001024 return mTexStorage->getRenderTarget(level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001025}
1026
Geoff Lang8040f572013-07-25 16:49:54 -04001027rx::RenderTarget *Texture2D::getDepthSencil(GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001028{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001029 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04001030 if (!ensureRenderTarget())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001031 {
1032 return NULL;
1033 }
1034
Jamie Madill169d1112013-10-24 17:49:37 -04001035 updateStorageLevel(level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001036
1037 // ensure this is actually a depth texture
Geoff Lang8040f572013-07-25 16:49:54 -04001038 if (!isDepth(level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001039 {
1040 return NULL;
1041 }
Geoff Lang8040f572013-07-25 16:49:54 -04001042
1043 return mTexStorage->getRenderTarget(level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001044}
1045
Jamie Madill07bb8cf2013-10-24 17:49:44 -04001046bool Texture2D::isValidLevel(int level) const
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +00001047{
Jamie Madill4cfff5f2013-10-24 17:49:46 -04001048 return (mTexStorage ? (level >= mTexStorage->getBaseLevel() && level < mTexStorage->getMaxLevel()) : false);
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +00001049}
1050
Geoff Lang4907f2c2013-07-25 12:53:57 -04001051TextureCubeMap::TextureCubeMap(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_CUBE_MAP)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001052{
1053 mTexStorage = NULL;
1054 for (int i = 0; i < 6; i++)
1055 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001056 for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
1057 {
daniel@transgaming.com244e1832012-12-20 20:52:35 +00001058 mImageArray[i][j] = renderer->createImage();
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001059 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001060 }
1061}
1062
1063TextureCubeMap::~TextureCubeMap()
1064{
1065 for (int i = 0; i < 6; i++)
1066 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001067 for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
1068 {
1069 delete mImageArray[i][j];
1070 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001071 }
1072
1073 delete mTexStorage;
1074 mTexStorage = NULL;
1075}
1076
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001077GLsizei TextureCubeMap::getWidth(GLenum target, GLint level) const
1078{
1079 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Jamie Madill2db197c2013-10-24 17:49:35 -04001080 return mImageArray[targetToIndex(target)][level]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001081 else
1082 return 0;
1083}
1084
1085GLsizei TextureCubeMap::getHeight(GLenum target, GLint level) const
1086{
1087 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Jamie Madill2db197c2013-10-24 17:49:35 -04001088 return mImageArray[targetToIndex(target)][level]->getHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001089 else
1090 return 0;
1091}
1092
1093GLenum TextureCubeMap::getInternalFormat(GLenum target, GLint level) const
1094{
1095 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Jamie Madill2db197c2013-10-24 17:49:35 -04001096 return mImageArray[targetToIndex(target)][level]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001097 else
1098 return GL_NONE;
1099}
1100
daniel@transgaming.com20d36662012-10-31 19:51:43 +00001101GLenum TextureCubeMap::getActualFormat(GLenum target, GLint level) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001102{
1103 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Jamie Madill2db197c2013-10-24 17:49:35 -04001104 return mImageArray[targetToIndex(target)][level]->getActualFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001105 else
Geoff Langcbf727a2014-02-10 12:50:45 -05001106 return GL_NONE;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001107}
1108
Geoff Lang005df412013-10-16 14:12:50 -04001109void 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 +00001110{
Jamie Madill88f18f42013-09-18 14:36:19 -04001111 setImage(0, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001112}
1113
Geoff Lang005df412013-10-16 14:12:50 -04001114void 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 +00001115{
Jamie Madill88f18f42013-09-18 14:36:19 -04001116 setImage(1, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001117}
1118
Geoff Lang005df412013-10-16 14:12:50 -04001119void 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 +00001120{
Jamie Madill88f18f42013-09-18 14:36:19 -04001121 setImage(2, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001122}
1123
Geoff Lang005df412013-10-16 14:12:50 -04001124void 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 +00001125{
Jamie Madill88f18f42013-09-18 14:36:19 -04001126 setImage(3, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001127}
1128
Geoff Lang005df412013-10-16 14:12:50 -04001129void 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 +00001130{
Jamie Madill88f18f42013-09-18 14:36:19 -04001131 setImage(4, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001132}
1133
Geoff Lang005df412013-10-16 14:12:50 -04001134void 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 +00001135{
Jamie Madill88f18f42013-09-18 14:36:19 -04001136 setImage(5, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001137}
1138
Jamie Madill2db197c2013-10-24 17:49:35 -04001139void 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 +00001140{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001141 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
Jamie Madill2db197c2013-10-24 17:49:35 -04001142 int faceIndex = targetToIndex(target);
1143 redefineImage(faceIndex, level, format, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001144
Jamie Madill2db197c2013-10-24 17:49:35 -04001145 Texture::setCompressedImage(imageSize, pixels, mImageArray[faceIndex][level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001146}
1147
Jamie Madill2db197c2013-10-24 17:49:35 -04001148void TextureCubeMap::commitRect(int faceIndex, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001149{
Jamie Madill07bb8cf2013-10-24 17:49:44 -04001150 if (isValidFaceLevel(faceIndex, level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001151 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001152 rx::Image *image = mImageArray[faceIndex][level];
Jamie Madill169d1112013-10-24 17:49:37 -04001153 if (image->copyToStorage(mTexStorage, faceIndex, level, xoffset, yoffset, width, height))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001154 image->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001155 }
1156}
1157
Jamie Madill88f18f42013-09-18 14:36:19 -04001158void 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 +00001159{
Jamie Madill2db197c2013-10-24 17:49:35 -04001160 int faceIndex = targetToIndex(target);
1161 if (Texture::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, mImageArray[faceIndex][level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001162 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001163 commitRect(faceIndex, level, xoffset, yoffset, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001164 }
1165}
1166
1167void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1168{
Jamie Madill2db197c2013-10-24 17:49:35 -04001169 int faceIndex = targetToIndex(target);
1170 if (Texture::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[faceIndex][level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001171 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001172 commitRect(faceIndex, level, xoffset, yoffset, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001173 }
1174}
1175
1176// Tests for cube map sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 86.
Jamie Madillf8989902013-07-19 16:36:58 -04001177bool TextureCubeMap::isSamplerComplete(const SamplerState &samplerState) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001178{
Jamie Madilld3d2a342013-10-07 10:46:35 -04001179 int size = getBaseLevelWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001180
Jamie Madillf8989902013-07-19 16:36:58 -04001181 bool mipmapping = IsMipmapFiltered(samplerState);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001182
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001183 if (!IsTextureFilteringSupported(getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0), mRenderer))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001184 {
Jamie Madillf8989902013-07-19 16:36:58 -04001185 if (samplerState.magFilter != GL_NEAREST ||
1186 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001187 {
1188 return false;
1189 }
1190 }
1191
daniel@transgaming.comea32d482012-11-28 19:33:18 +00001192 if (!isPow2(size) && !mRenderer->getNonPower2TextureSupport())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001193 {
Jamie Madillf8989902013-07-19 16:36:58 -04001194 if (samplerState.wrapS != GL_CLAMP_TO_EDGE || samplerState.wrapT != GL_CLAMP_TO_EDGE || mipmapping)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001195 {
1196 return false;
1197 }
1198 }
1199
1200 if (!mipmapping)
1201 {
1202 if (!isCubeComplete())
1203 {
1204 return false;
1205 }
1206 }
1207 else
1208 {
1209 if (!isMipmapCubeComplete()) // Also tests for isCubeComplete()
1210 {
1211 return false;
1212 }
1213 }
1214
1215 return true;
1216}
1217
1218// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1219bool TextureCubeMap::isCubeComplete() const
1220{
Jamie Madillc1f8b162013-10-07 10:46:38 -04001221 int baseWidth = getBaseLevelWidth();
1222 int baseHeight = getBaseLevelHeight();
1223 GLenum baseFormat = getBaseLevelInternalFormat();
1224
1225 if (baseWidth <= 0 || baseWidth != baseHeight)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001226 {
1227 return false;
1228 }
1229
Jamie Madill2db197c2013-10-24 17:49:35 -04001230 for (int faceIndex = 1; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001231 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001232 const rx::Image &faceBaseImage = *mImageArray[faceIndex][0];
Jamie Madillc1f8b162013-10-07 10:46:38 -04001233
1234 if (faceBaseImage.getWidth() != baseWidth ||
1235 faceBaseImage.getHeight() != baseHeight ||
1236 faceBaseImage.getInternalFormat() != baseFormat )
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001237 {
1238 return false;
1239 }
1240 }
1241
1242 return true;
1243}
1244
1245bool TextureCubeMap::isMipmapCubeComplete() const
1246{
1247 if (isImmutable())
1248 {
1249 return true;
1250 }
1251
1252 if (!isCubeComplete())
1253 {
1254 return false;
1255 }
1256
Jamie Madill22f843a2013-10-24 17:49:36 -04001257 int q = mipLevels();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001258
1259 for (int face = 0; face < 6; face++)
1260 {
1261 for (int level = 1; level <= q; level++)
1262 {
Jamie Madill07edd442013-07-19 16:36:58 -04001263 if (!isFaceLevelComplete(face, level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001264 {
1265 return false;
1266 }
1267 }
1268 }
1269
1270 return true;
1271}
1272
Jamie Madill2db197c2013-10-24 17:49:35 -04001273bool TextureCubeMap::isFaceLevelComplete(int faceIndex, int level) const
Jamie Madill07edd442013-07-19 16:36:58 -04001274{
Jamie Madill2db197c2013-10-24 17:49:35 -04001275 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
Jamie Madill07edd442013-07-19 16:36:58 -04001276
1277 if (isImmutable())
1278 {
1279 return true;
1280 }
1281
Jamie Madilld3d2a342013-10-07 10:46:35 -04001282 int baseSize = getBaseLevelWidth();
Jamie Madill07edd442013-07-19 16:36:58 -04001283
Jamie Madilld3d2a342013-10-07 10:46:35 -04001284 if (baseSize <= 0)
Jamie Madill07edd442013-07-19 16:36:58 -04001285 {
1286 return false;
1287 }
1288
Jamie Madilld3d2a342013-10-07 10:46:35 -04001289 // "isCubeComplete" checks for base level completeness and we must call that
1290 // to determine if any face at level 0 is complete. We omit that check here
1291 // to avoid re-checking cube-completeness for every face at level 0.
Jamie Madill07edd442013-07-19 16:36:58 -04001292 if (level == 0)
1293 {
1294 return true;
1295 }
1296
Jamie Madilld3d2a342013-10-07 10:46:35 -04001297 // Check that non-zero levels are consistent with the base level.
Jamie Madill2db197c2013-10-24 17:49:35 -04001298 const rx::Image *faceLevelImage = mImageArray[faceIndex][level];
Jamie Madill07edd442013-07-19 16:36:58 -04001299
Jamie Madilld3d2a342013-10-07 10:46:35 -04001300 if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat())
Jamie Madill07edd442013-07-19 16:36:58 -04001301 {
1302 return false;
1303 }
1304
Jamie Madilld3d2a342013-10-07 10:46:35 -04001305 if (faceLevelImage->getWidth() != std::max(1, baseSize >> level))
Jamie Madill07edd442013-07-19 16:36:58 -04001306 {
1307 return false;
1308 }
1309
1310 return true;
1311}
1312
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001313bool TextureCubeMap::isCompressed(GLenum target, GLint level) const
1314{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001315 return IsFormatCompressed(getInternalFormat(target, level), mRenderer->getCurrentClientVersion());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001316}
1317
Geoff Lang8040f572013-07-25 16:49:54 -04001318bool TextureCubeMap::isDepth(GLenum target, GLint level) const
1319{
1320 return GetDepthBits(getInternalFormat(target, level), mRenderer->getCurrentClientVersion()) > 0;
1321}
1322
Jamie Madill73b5d062013-10-24 17:49:38 -04001323void TextureCubeMap::initializeStorage(bool renderTarget)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001324{
Jamie Madill3c0989c2013-10-24 17:49:39 -04001325 // Only initialize the first time this texture is used as a render target or shader resource
1326 if (mTexStorage)
1327 {
1328 return;
1329 }
1330
1331 // do not attempt to create storage for nonexistant data
1332 if (!isFaceLevelComplete(0, 0))
1333 {
1334 return;
1335 }
1336
1337 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
1338
1339 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
1340 ASSERT(mTexStorage);
1341
1342 // flush image data to the storage
1343 updateStorage();
1344}
1345
1346rx::TextureStorageInterfaceCube *TextureCubeMap::createCompleteStorage(bool renderTarget) const
1347{
Jamie Madilld3d2a342013-10-07 10:46:35 -04001348 GLsizei size = getBaseLevelWidth();
daniel@transgaming.come6a09842012-09-17 21:28:55 +00001349
Jamie Madill3c0989c2013-10-24 17:49:39 -04001350 ASSERT(size > 0);
daniel@transgaming.come6a09842012-09-17 21:28:55 +00001351
Jamie Madill3c0989c2013-10-24 17:49:39 -04001352 // use existing storage level count, when previously specified by TexStorage*D
Jamie Madill6b7440c2013-10-24 17:49:47 -04001353 GLint levels = (mTexStorage ? mTexStorage->getMaxLevel() : creationLevels(size, size, 1));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001354
Jamie Madill4cfff5f2013-10-24 17:49:46 -04001355 return new rx::TextureStorageInterfaceCube(mRenderer, 0, levels, getBaseLevelInternalFormat(), renderTarget, size);
Jamie Madill3c0989c2013-10-24 17:49:39 -04001356}
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001357
Jamie Madill3c0989c2013-10-24 17:49:39 -04001358void TextureCubeMap::setCompleteTexStorage(rx::TextureStorageInterfaceCube *newCompleteTexStorage)
1359{
1360 SafeDelete(mTexStorage);
1361 mTexStorage = newCompleteTexStorage;
1362
1363 if (mTexStorage && mTexStorage->isManaged())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001364 {
Jamie Madill4cfff5f2013-10-24 17:49:46 -04001365 int levels = mTexStorage->getMaxLevel();
1366
Jamie Madill2db197c2013-10-24 17:49:35 -04001367 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001368 {
Jamie Madill4cfff5f2013-10-24 17:49:46 -04001369 for (int level = 0; level < mTexStorage->getMaxLevel(); level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001370 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001371 mImageArray[faceIndex][level]->setManagedSurface(mTexStorage, faceIndex, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001372 }
1373 }
1374 }
1375
1376 mDirtyImages = true;
1377}
1378
Jamie Madill169d1112013-10-24 17:49:37 -04001379void TextureCubeMap::updateStorage()
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001380{
1381 for (int face = 0; face < 6; face++)
1382 {
Jamie Madill4cfff5f2013-10-24 17:49:46 -04001383 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001384 {
Jamie Madilld9b9a502013-10-10 17:46:13 -04001385 if (isFaceLevelComplete(face, level))
1386 {
Jamie Madill169d1112013-10-24 17:49:37 -04001387 updateStorageFaceLevel(face, level);
Jamie Madilld9b9a502013-10-10 17:46:13 -04001388 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001389 }
1390 }
1391}
1392
Jamie Madill169d1112013-10-24 17:49:37 -04001393void TextureCubeMap::updateStorageFaceLevel(int faceIndex, int level)
Jamie Madill07edd442013-07-19 16:36:58 -04001394{
Jamie Madill2db197c2013-10-24 17:49:35 -04001395 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1396 rx::Image *image = mImageArray[faceIndex][level];
Jamie Madill07edd442013-07-19 16:36:58 -04001397
1398 if (image->isDirty())
1399 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001400 commitRect(faceIndex, level, 0, 0, image->getWidth(), image->getHeight());
Jamie Madill07edd442013-07-19 16:36:58 -04001401 }
1402}
1403
Jamie Madille83d1a92013-10-24 17:49:33 -04001404bool TextureCubeMap::ensureRenderTarget()
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001405{
Jamie Madill3c0989c2013-10-24 17:49:39 -04001406 initializeStorage(true);
1407
1408 if (getBaseLevelWidth() > 0)
Jamie Madille83d1a92013-10-24 17:49:33 -04001409 {
Jamie Madill3c0989c2013-10-24 17:49:39 -04001410 ASSERT(mTexStorage);
1411 if (!mTexStorage->isRenderTarget())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001412 {
Jamie Madill3c0989c2013-10-24 17:49:39 -04001413 rx::TextureStorageInterfaceCube *newRenderTargetStorage = createCompleteStorage(true);
1414
1415 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001416 {
Jamie Madill3c0989c2013-10-24 17:49:39 -04001417 delete newRenderTargetStorage;
Jamie Madille83d1a92013-10-24 17:49:33 -04001418 return gl::error(GL_OUT_OF_MEMORY, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001419 }
Jamie Madill3c0989c2013-10-24 17:49:39 -04001420
1421 setCompleteTexStorage(newRenderTargetStorage);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001422 }
1423 }
1424
Jamie Madille83d1a92013-10-24 17:49:33 -04001425 return (mTexStorage && mTexStorage->isRenderTarget());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001426}
1427
Geoff Lang005df412013-10-16 14:12:50 -04001428void 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 +00001429{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001430 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Geoff Lang005df412013-10-16 14:12:50 -04001431 GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
1432 : GetSizedInternalFormat(format, type, clientVersion);
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001433
1434 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001435
Jamie Madill88f18f42013-09-18 14:36:19 -04001436 Texture::setImage(unpack, type, pixels, mImageArray[faceIndex][level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001437}
1438
Jamie Madill2db197c2013-10-24 17:49:35 -04001439int TextureCubeMap::targetToIndex(GLenum target)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001440{
1441 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
1442 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
1443 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
1444 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
1445 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
1446
Jamie Madill2db197c2013-10-24 17:49:35 -04001447 return target - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001448}
1449
Jamie Madill2db197c2013-10-24 17:49:35 -04001450void TextureCubeMap::redefineImage(int faceIndex, GLint level, GLenum internalformat, GLsizei width, GLsizei height)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001451{
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001452 // If there currently is a corresponding storage texture image, it has these parameters
Jamie Madilld3d2a342013-10-07 10:46:35 -04001453 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1454 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
Geoff Lang005df412013-10-16 14:12:50 -04001455 const GLenum storageFormat = getBaseLevelInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001456
Jamie Madill2db197c2013-10-24 17:49:35 -04001457 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, width, height, 1, false);
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001458
1459 if (mTexStorage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001460 {
Jamie Madill4cfff5f2013-10-24 17:49:46 -04001461 const int storageLevels = mTexStorage->getMaxLevel();
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001462
1463 if ((level >= storageLevels && storageLevels != 0) ||
1464 width != storageWidth ||
1465 height != storageHeight ||
1466 internalformat != storageFormat) // Discard mismatched storage
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001467 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001468 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001469 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001470 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001471 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001472 mImageArray[faceIndex][level]->markDirty();
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001473 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001474 }
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001475
1476 delete mTexStorage;
1477 mTexStorage = NULL;
1478
1479 mDirtyImages = true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001480 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001481 }
1482}
1483
1484void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1485{
Jamie Madill2db197c2013-10-24 17:49:35 -04001486 int faceIndex = targetToIndex(target);
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001487 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Geoff Lang005df412013-10-16 14:12:50 -04001488 GLenum sizedInternalFormat = IsSizedInternalFormat(format, clientVersion) ? format
1489 : GetSizedInternalFormat(format, GL_UNSIGNED_BYTE, clientVersion);
Jamie Madill2db197c2013-10-24 17:49:35 -04001490 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001491
Jamie Madill2db197c2013-10-24 17:49:35 -04001492 if (!mImageArray[faceIndex][level]->isRenderableFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001493 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001494 mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001495 mDirtyImages = true;
1496 }
1497 else
1498 {
Jamie Madille83d1a92013-10-24 17:49:33 -04001499 ensureRenderTarget();
Jamie Madill2db197c2013-10-24 17:49:35 -04001500 mImageArray[faceIndex][level]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001501
1502 ASSERT(width == height);
1503
Jamie Madill07bb8cf2013-10-24 17:49:44 -04001504 if (width > 0 && isValidFaceLevel(faceIndex, level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001505 {
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +00001506 gl::Rectangle sourceRect;
1507 sourceRect.x = x;
1508 sourceRect.width = width;
1509 sourceRect.y = y;
1510 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001511
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +00001512 mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001513 }
1514 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001515}
1516
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001517void 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 +00001518{
Jamie Madill2db197c2013-10-24 17:49:35 -04001519 int faceIndex = targetToIndex(target);
1520
1521 GLsizei size = mImageArray[faceIndex][level]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001522
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001523 if (xoffset + width > size || yoffset + height > size || zoffset != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001524 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +00001525 return gl::error(GL_INVALID_VALUE);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001526 }
1527
Jamie Madilld3d2a342013-10-07 10:46:35 -04001528 // We can only make our texture storage to a render target if the level we're copying *to* is complete
1529 // and the base level is cube-complete. The base level must be cube complete (common case) because we cannot
1530 // rely on the "getBaseLevel*" methods reliably otherwise.
Jamie Madill2db197c2013-10-24 17:49:35 -04001531 bool canCreateRenderTarget = isFaceLevelComplete(faceIndex, level) && isCubeComplete();
Jamie Madill07edd442013-07-19 16:36:58 -04001532
Jamie Madill2db197c2013-10-24 17:49:35 -04001533 if (!mImageArray[faceIndex][level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001534 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001535 mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001536 mDirtyImages = true;
1537 }
1538 else
1539 {
Jamie Madille83d1a92013-10-24 17:49:33 -04001540 ensureRenderTarget();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001541
Jamie Madill07bb8cf2013-10-24 17:49:44 -04001542 if (isValidFaceLevel(faceIndex, level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001543 {
Jamie Madill169d1112013-10-24 17:49:37 -04001544 updateStorageFaceLevel(faceIndex, level);
Jamie Madill07edd442013-07-19 16:36:58 -04001545
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001546 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1547
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +00001548 gl::Rectangle sourceRect;
1549 sourceRect.x = x;
1550 sourceRect.width = width;
1551 sourceRect.y = y;
1552 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001553
Jamie Madilld3d2a342013-10-07 10:46:35 -04001554 mRenderer->copyImage(source, sourceRect, gl::GetFormat(getBaseLevelInternalFormat(), clientVersion),
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +00001555 xoffset, yoffset, mTexStorage, target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001556 }
1557 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001558}
1559
1560void TextureCubeMap::storage(GLsizei levels, GLenum internalformat, GLsizei size)
1561{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001562 for (int level = 0; level < levels; level++)
1563 {
Geoff Langd3110192013-09-24 11:52:47 -04001564 GLsizei mipSize = std::max(1, size >> level);
Jamie Madill2db197c2013-10-24 17:49:35 -04001565 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001566 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001567 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, mipSize, mipSize, 1, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001568 }
1569 }
1570
1571 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1572 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001573 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001574 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001575 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, GL_NONE, 0, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001576 }
1577 }
1578
Jamie Madill3c0989c2013-10-24 17:49:39 -04001579 mImmutable = true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001580
Jamie Madill4cfff5f2013-10-24 17:49:46 -04001581 setCompleteTexStorage(new rx::TextureStorageInterfaceCube(mRenderer, 0, levels, internalformat, IsRenderTargetUsage(mUsage), size));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001582}
1583
1584void TextureCubeMap::generateMipmaps()
1585{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001586 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Jamie Madill22f843a2013-10-24 17:49:36 -04001587 int q = mipLevels();
Jamie Madill2db197c2013-10-24 17:49:35 -04001588 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001589 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001590 for (int level = 1; level <= q; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001591 {
Jamie Madill22f843a2013-10-24 17:49:36 -04001592 int faceLevelSize = (std::max(mImageArray[faceIndex][0]->getWidth() >> level, 1));
1593 redefineImage(faceIndex, level, mImageArray[faceIndex][0]->getInternalFormat(), faceLevelSize, faceLevelSize);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001594 }
1595 }
1596
1597 if (mTexStorage && mTexStorage->isRenderTarget())
1598 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001599 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001600 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001601 for (int level = 1; level <= q; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001602 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001603 mTexStorage->generateMipmap(faceIndex, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001604
Jamie Madill2db197c2013-10-24 17:49:35 -04001605 mImageArray[faceIndex][level]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001606 }
1607 }
1608 }
1609 else
1610 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001611 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001612 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001613 for (int level = 1; level <= q; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001614 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001615 mRenderer->generateMipmap(mImageArray[faceIndex][level], mImageArray[faceIndex][level - 1]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001616 }
1617 }
1618 }
1619}
1620
Jamie Madilld3d2a342013-10-07 10:46:35 -04001621const rx::Image *TextureCubeMap::getBaseLevelImage() const
1622{
1623 // Note: if we are not cube-complete, there is no single base level image that can describe all
1624 // cube faces, so this method is only well-defined for a cube-complete base level.
1625 return mImageArray[0][0];
1626}
1627
Jamie Madill2ebab852013-10-24 17:49:42 -04001628rx::TextureStorageInterface *TextureCubeMap::getBaseLevelStorage()
1629{
1630 return mTexStorage;
1631}
1632
Geoff Lang8040f572013-07-25 16:49:54 -04001633Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target, GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001634{
1635 if (!IsCubemapTextureTarget(target))
1636 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +00001637 return gl::error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001638 }
1639
Jamie Madill2db197c2013-10-24 17:49:35 -04001640 int faceIndex = targetToIndex(target);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001641
Jamie Madill2db197c2013-10-24 17:49:35 -04001642 Renderbuffer *renderBuffer = mRenderbufferProxies.get(level, faceIndex);
Geoff Lang8040f572013-07-25 16:49:54 -04001643 if (!renderBuffer)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001644 {
Geoff Lang8040f572013-07-25 16:49:54 -04001645 renderBuffer = new Renderbuffer(mRenderer, id(), new RenderbufferTextureCubeMap(this, target, level));
Jamie Madill2db197c2013-10-24 17:49:35 -04001646 mRenderbufferProxies.add(level, faceIndex, renderBuffer);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001647 }
1648
Geoff Lang8040f572013-07-25 16:49:54 -04001649 return renderBuffer;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001650}
1651
Jamie Madill2db197c2013-10-24 17:49:35 -04001652unsigned int TextureCubeMap::getRenderTargetSerial(GLenum target, GLint level)
Geoff Lang8040f572013-07-25 16:49:54 -04001653{
Jamie Madill2db197c2013-10-24 17:49:35 -04001654 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(target, level) : 0);
Geoff Lang8040f572013-07-25 16:49:54 -04001655}
1656
1657rx::RenderTarget *TextureCubeMap::getRenderTarget(GLenum target, GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001658{
1659 ASSERT(IsCubemapTextureTarget(target));
1660
1661 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04001662 if (!ensureRenderTarget())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001663 {
1664 return NULL;
1665 }
1666
Jamie Madill169d1112013-10-24 17:49:37 -04001667 updateStorageFaceLevel(targetToIndex(target), level);
Geoff Lang8040f572013-07-25 16:49:54 -04001668
1669 // ensure this is NOT a depth texture
1670 if (isDepth(target, level))
1671 {
1672 return NULL;
1673 }
1674
1675 return mTexStorage->getRenderTarget(target, level);
1676}
1677
1678rx::RenderTarget *TextureCubeMap::getDepthStencil(GLenum target, GLint level)
1679{
1680 ASSERT(IsCubemapTextureTarget(target));
1681
1682 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04001683 if (!ensureRenderTarget())
Geoff Lang8040f572013-07-25 16:49:54 -04001684 {
1685 return NULL;
1686 }
1687
Jamie Madill169d1112013-10-24 17:49:37 -04001688 updateStorageFaceLevel(targetToIndex(target), level);
Geoff Lang8040f572013-07-25 16:49:54 -04001689
1690 // ensure this is a depth texture
1691 if (!isDepth(target, level))
1692 {
1693 return NULL;
1694 }
1695
1696 return mTexStorage->getRenderTarget(target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001697}
1698
Jamie Madill07bb8cf2013-10-24 17:49:44 -04001699bool TextureCubeMap::isValidFaceLevel(int faceIndex, int level) const
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +00001700{
Jamie Madill4cfff5f2013-10-24 17:49:46 -04001701 return (mTexStorage ? (level >= mTexStorage->getBaseLevel() && level < mTexStorage->getMaxLevel()) : 0);
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +00001702}
1703
Geoff Lang4907f2c2013-07-25 12:53:57 -04001704Texture3D::Texture3D(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_3D)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001705{
1706 mTexStorage = NULL;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001707
1708 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1709 {
1710 mImageArray[i] = renderer->createImage();
1711 }
1712}
1713
1714Texture3D::~Texture3D()
1715{
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001716 delete mTexStorage;
1717 mTexStorage = NULL;
1718
1719 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1720 {
1721 delete mImageArray[i];
1722 }
1723}
1724
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001725GLsizei Texture3D::getWidth(GLint level) const
1726{
1727 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getWidth() : 0;
1728}
1729
1730GLsizei Texture3D::getHeight(GLint level) const
1731{
1732 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getHeight() : 0;
1733}
1734
1735GLsizei Texture3D::getDepth(GLint level) const
1736{
1737 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getDepth() : 0;
1738}
1739
1740GLenum Texture3D::getInternalFormat(GLint level) const
1741{
1742 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getInternalFormat() : GL_NONE;
1743}
1744
1745GLenum Texture3D::getActualFormat(GLint level) const
1746{
Geoff Langcbf727a2014-02-10 12:50:45 -05001747 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getActualFormat() : GL_NONE;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001748}
1749
1750bool Texture3D::isCompressed(GLint level) const
1751{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001752 return IsFormatCompressed(getInternalFormat(level), mRenderer->getCurrentClientVersion());
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001753}
1754
1755bool Texture3D::isDepth(GLint level) const
1756{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001757 return GetDepthBits(getInternalFormat(level), mRenderer->getCurrentClientVersion()) > 0;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001758}
1759
Geoff Lang005df412013-10-16 14:12:50 -04001760void 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 +00001761{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001762 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Geoff Lang005df412013-10-16 14:12:50 -04001763 GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
1764 : GetSizedInternalFormat(format, type, clientVersion);
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001765 redefineImage(level, sizedInternalFormat, width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001766
Jamie Madilla2d4e552013-10-10 15:12:01 -04001767 bool fastUnpacked = false;
1768
1769 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1770 if (isFastUnpackable(unpack, sizedInternalFormat))
1771 {
1772 // Will try to create RT storage if it does not exist
1773 rx::RenderTarget *destRenderTarget = getRenderTarget(level);
1774 Box destArea(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1775
1776 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget))
1777 {
1778 // Ensure we don't overwrite our newly initialized data
1779 mImageArray[level]->markClean();
1780
1781 fastUnpacked = true;
1782 }
1783 }
1784
1785 if (!fastUnpacked)
1786 {
1787 Texture::setImage(unpack, type, pixels, mImageArray[level]);
1788 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001789}
1790
1791void Texture3D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
1792{
1793 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1794 redefineImage(level, format, width, height, depth);
1795
1796 Texture::setCompressedImage(imageSize, pixels, mImageArray[level]);
1797}
1798
Jamie Madill88f18f42013-09-18 14:36:19 -04001799void 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 +00001800{
Jamie Madillba4f10a2013-10-10 15:12:20 -04001801 bool fastUnpacked = false;
1802
1803 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1804 if (isFastUnpackable(unpack, getInternalFormat(level)))
1805 {
1806 rx::RenderTarget *destRenderTarget = getRenderTarget(level);
1807 Box destArea(xoffset, yoffset, zoffset, width, height, depth);
1808
1809 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, destRenderTarget))
1810 {
1811 // Ensure we don't overwrite our newly initialized data
1812 mImageArray[level]->markClean();
1813
1814 fastUnpacked = true;
1815 }
1816 }
1817
1818 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 +00001819 {
1820 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1821 }
1822}
1823
1824void Texture3D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
1825{
1826 if (Texture::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth, format, imageSize, pixels, mImageArray[level]))
1827 {
1828 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1829 }
1830}
1831
1832void Texture3D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
1833{
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001834 for (int level = 0; level < levels; level++)
1835 {
Jamie Madille664e202013-10-24 17:49:40 -04001836 GLsizei levelWidth = std::max(1, width >> level);
1837 GLsizei levelHeight = std::max(1, height >> level);
1838 GLsizei levelDepth = std::max(1, depth >> level);
1839 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, levelWidth, levelHeight, levelDepth, true);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001840 }
1841
1842 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1843 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001844 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, GL_NONE, 0, 0, 0, true);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001845 }
1846
Jamie Madille664e202013-10-24 17:49:40 -04001847 mImmutable = true;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001848
Jamie Madill4cfff5f2013-10-24 17:49:46 -04001849 setCompleteTexStorage(new rx::TextureStorageInterface3D(mRenderer, 0, levels, internalformat, IsRenderTargetUsage(mUsage), width, height, depth));
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001850}
1851
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001852void Texture3D::generateMipmaps()
1853{
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001854 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Jamie Madill22f843a2013-10-24 17:49:36 -04001855 int q = mipLevels();
1856 for (int level = 1; level <= q; level++)
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001857 {
Jamie Madill22f843a2013-10-24 17:49:36 -04001858 redefineImage(level, getBaseLevelInternalFormat(),
1859 std::max(getBaseLevelWidth() >> level, 1),
1860 std::max(getBaseLevelHeight() >> level, 1),
1861 std::max(getBaseLevelDepth() >> level, 1));
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001862 }
1863
1864 if (mTexStorage && mTexStorage->isRenderTarget())
1865 {
Jamie Madill22f843a2013-10-24 17:49:36 -04001866 for (int level = 1; level <= q; level++)
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001867 {
Jamie Madill22f843a2013-10-24 17:49:36 -04001868 mTexStorage->generateMipmap(level);
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001869
Jamie Madill22f843a2013-10-24 17:49:36 -04001870 mImageArray[level]->markClean();
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001871 }
1872 }
1873 else
1874 {
Jamie Madill22f843a2013-10-24 17:49:36 -04001875 for (int level = 1; level <= q; level++)
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001876 {
Jamie Madill22f843a2013-10-24 17:49:36 -04001877 mRenderer->generateMipmap(mImageArray[level], mImageArray[level - 1]);
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001878 }
1879 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001880}
1881
Jamie Madilld3d2a342013-10-07 10:46:35 -04001882const rx::Image *Texture3D::getBaseLevelImage() const
1883{
1884 return mImageArray[0];
1885}
1886
Jamie Madill2ebab852013-10-24 17:49:42 -04001887rx::TextureStorageInterface *Texture3D::getBaseLevelStorage()
1888{
1889 return mTexStorage;
1890}
1891
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001892void Texture3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1893{
1894 if (xoffset + width > mImageArray[level]->getWidth() || yoffset + height > mImageArray[level]->getHeight() || zoffset >= mImageArray[level]->getDepth())
1895 {
1896 return gl::error(GL_INVALID_VALUE);
1897 }
1898
Jamie Madill07edd442013-07-19 16:36:58 -04001899 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
1900 // the current level we're copying to is defined (with appropriate format, width & height)
1901 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
1902
1903 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001904 {
1905 mImageArray[level]->copy(xoffset, yoffset, zoffset, x, y, width, height, source);
1906 mDirtyImages = true;
1907 }
1908 else
1909 {
Jamie Madille83d1a92013-10-24 17:49:33 -04001910 ensureRenderTarget();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001911
Jamie Madill07bb8cf2013-10-24 17:49:44 -04001912 if (isValidLevel(level))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001913 {
Jamie Madill169d1112013-10-24 17:49:37 -04001914 updateStorageLevel(level);
Jamie Madill07edd442013-07-19 16:36:58 -04001915
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001916 gl::Rectangle sourceRect;
1917 sourceRect.x = x;
1918 sourceRect.width = width;
1919 sourceRect.y = y;
1920 sourceRect.height = height;
1921
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001922 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1923
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001924 mRenderer->copyImage(source, sourceRect,
Jamie Madilld3d2a342013-10-07 10:46:35 -04001925 gl::GetFormat(getBaseLevelInternalFormat(), clientVersion),
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001926 xoffset, yoffset, zoffset, mTexStorage, level);
1927 }
1928 }
1929}
1930
Jamie Madillf8989902013-07-19 16:36:58 -04001931bool Texture3D::isSamplerComplete(const SamplerState &samplerState) const
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001932{
Jamie Madilld3d2a342013-10-07 10:46:35 -04001933 GLsizei width = getBaseLevelWidth();
1934 GLsizei height = getBaseLevelHeight();
1935 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001936
1937 if (width <= 0 || height <= 0 || depth <= 0)
1938 {
1939 return false;
1940 }
1941
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001942 if (!IsTextureFilteringSupported(getInternalFormat(0), mRenderer))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001943 {
Jamie Madillf8989902013-07-19 16:36:58 -04001944 if (samplerState.magFilter != GL_NEAREST ||
1945 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001946 {
1947 return false;
1948 }
1949 }
1950
Jamie Madillf8989902013-07-19 16:36:58 -04001951 if (IsMipmapFiltered(samplerState) && !isMipmapComplete())
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001952 {
1953 return false;
1954 }
1955
1956 return true;
1957}
1958
1959bool Texture3D::isMipmapComplete() const
1960{
Jamie Madill22f843a2013-10-24 17:49:36 -04001961 int q = mipLevels();
Jamie Madill07edd442013-07-19 16:36:58 -04001962
1963 for (int level = 0; level <= q; level++)
1964 {
1965 if (!isLevelComplete(level))
1966 {
1967 return false;
1968 }
1969 }
1970
1971 return true;
1972}
1973
1974bool Texture3D::isLevelComplete(int level) const
1975{
1976 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1977
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001978 if (isImmutable())
1979 {
1980 return true;
1981 }
1982
Jamie Madilld3d2a342013-10-07 10:46:35 -04001983 GLsizei width = getBaseLevelWidth();
1984 GLsizei height = getBaseLevelHeight();
1985 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001986
1987 if (width <= 0 || height <= 0 || depth <= 0)
1988 {
1989 return false;
1990 }
1991
Jamie Madill07edd442013-07-19 16:36:58 -04001992 if (level == 0)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001993 {
Jamie Madill07edd442013-07-19 16:36:58 -04001994 return true;
1995 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001996
Jamie Madill07edd442013-07-19 16:36:58 -04001997 rx::Image *levelImage = mImageArray[level];
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001998
Jamie Madilld3d2a342013-10-07 10:46:35 -04001999 if (levelImage->getInternalFormat() != getBaseLevelInternalFormat())
Jamie Madill07edd442013-07-19 16:36:58 -04002000 {
2001 return false;
2002 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002003
Jamie Madill07edd442013-07-19 16:36:58 -04002004 if (levelImage->getWidth() != std::max(1, width >> level))
2005 {
2006 return false;
2007 }
2008
2009 if (levelImage->getHeight() != std::max(1, height >> level))
2010 {
2011 return false;
2012 }
2013
2014 if (levelImage->getDepth() != std::max(1, depth >> level))
2015 {
2016 return false;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002017 }
2018
2019 return true;
2020}
2021
Geoff Lang8040f572013-07-25 16:49:54 -04002022Renderbuffer *Texture3D::getRenderbuffer(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002023{
Geoff Lang8040f572013-07-25 16:49:54 -04002024 Renderbuffer *renderBuffer = mRenderbufferProxies.get(level, layer);
2025 if (!renderBuffer)
2026 {
Geoff Langd5d8e392013-07-25 16:53:03 -04002027 renderBuffer = new Renderbuffer(mRenderer, id(), new RenderbufferTexture3DLayer(this, level, layer));
2028 mRenderbufferProxies.add(level, 0, renderBuffer);
Geoff Lang8040f572013-07-25 16:49:54 -04002029 }
2030
2031 return renderBuffer;
2032}
2033
2034unsigned int Texture3D::getRenderTargetSerial(GLint level, GLint layer)
2035{
Jamie Madille83d1a92013-10-24 17:49:33 -04002036 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(level, layer) : 0);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002037}
2038
Jamie Madill07bb8cf2013-10-24 17:49:44 -04002039bool Texture3D::isValidLevel(int level) const
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002040{
Jamie Madill4cfff5f2013-10-24 17:49:46 -04002041 return (mTexStorage ? (level >= mTexStorage->getBaseLevel() && level < mTexStorage->getMaxLevel()) : 0);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002042}
2043
Jamie Madill73b5d062013-10-24 17:49:38 -04002044void Texture3D::initializeStorage(bool renderTarget)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002045{
Jamie Madille664e202013-10-24 17:49:40 -04002046 // Only initialize the first time this texture is used as a render target or shader resource
2047 if (mTexStorage)
2048 {
2049 return;
2050 }
2051
2052 // do not attempt to create storage for nonexistant data
2053 if (!isLevelComplete(0))
2054 {
2055 return;
2056 }
2057
2058 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
2059
2060 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
2061 ASSERT(mTexStorage);
2062
2063 // flush image data to the storage
2064 updateStorage();
2065}
2066
2067rx::TextureStorageInterface3D *Texture3D::createCompleteStorage(bool renderTarget) const
2068{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002069 GLsizei width = getBaseLevelWidth();
2070 GLsizei height = getBaseLevelHeight();
2071 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002072
Jamie Madille664e202013-10-24 17:49:40 -04002073 ASSERT(width > 0 && height > 0 && depth > 0);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002074
Jamie Madille664e202013-10-24 17:49:40 -04002075 // use existing storage level count, when previously specified by TexStorage*D
Jamie Madill4cfff5f2013-10-24 17:49:46 -04002076 GLint levels = (mTexStorage ? mTexStorage->getMaxLevel() : creationLevels(width, height, depth));
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002077
Jamie Madill4cfff5f2013-10-24 17:49:46 -04002078 return new rx::TextureStorageInterface3D(mRenderer, 0, levels, getBaseLevelInternalFormat(), renderTarget, width, height, depth);
Jamie Madille664e202013-10-24 17:49:40 -04002079}
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002080
Jamie Madille664e202013-10-24 17:49:40 -04002081void Texture3D::setCompleteTexStorage(rx::TextureStorageInterface3D *newCompleteTexStorage)
2082{
2083 SafeDelete(mTexStorage);
2084 mTexStorage = newCompleteTexStorage;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002085 mDirtyImages = true;
Jamie Madille664e202013-10-24 17:49:40 -04002086
2087 // We do not support managed 3D storage, as that is D3D9/ES2-only
2088 ASSERT(!mTexStorage->isManaged());
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002089}
2090
Jamie Madill169d1112013-10-24 17:49:37 -04002091void Texture3D::updateStorage()
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002092{
Jamie Madill4cfff5f2013-10-24 17:49:46 -04002093 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002094 {
Jamie Madilld9b9a502013-10-10 17:46:13 -04002095 if (isLevelComplete(level))
2096 {
Jamie Madill169d1112013-10-24 17:49:37 -04002097 updateStorageLevel(level);
Jamie Madilld9b9a502013-10-10 17:46:13 -04002098 }
Jamie Madill07edd442013-07-19 16:36:58 -04002099 }
2100}
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002101
Jamie Madill169d1112013-10-24 17:49:37 -04002102void Texture3D::updateStorageLevel(int level)
Jamie Madill07edd442013-07-19 16:36:58 -04002103{
2104 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
Jamie Madillaee7ad82013-10-10 16:07:32 -04002105 ASSERT(isLevelComplete(level));
Jamie Madill07edd442013-07-19 16:36:58 -04002106
Jamie Madillaee7ad82013-10-10 16:07:32 -04002107 if (mImageArray[level]->isDirty())
Jamie Madill07edd442013-07-19 16:36:58 -04002108 {
Jamie Madillaee7ad82013-10-10 16:07:32 -04002109 commitRect(level, 0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002110 }
2111}
2112
Jamie Madille83d1a92013-10-24 17:49:33 -04002113bool Texture3D::ensureRenderTarget()
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002114{
Jamie Madille664e202013-10-24 17:49:40 -04002115 initializeStorage(true);
2116
2117 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0 && getBaseLevelDepth() > 0)
Jamie Madille83d1a92013-10-24 17:49:33 -04002118 {
Jamie Madille664e202013-10-24 17:49:40 -04002119 ASSERT(mTexStorage);
2120 if (!mTexStorage->isRenderTarget())
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002121 {
Jamie Madille664e202013-10-24 17:49:40 -04002122 rx::TextureStorageInterface3D *newRenderTargetStorage = createCompleteStorage(true);
2123
2124 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002125 {
Jamie Madille664e202013-10-24 17:49:40 -04002126 delete newRenderTargetStorage;
Jamie Madille83d1a92013-10-24 17:49:33 -04002127 return gl::error(GL_OUT_OF_MEMORY, false);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002128 }
Jamie Madille664e202013-10-24 17:49:40 -04002129
2130 setCompleteTexStorage(newRenderTargetStorage);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002131 }
2132 }
2133
Jamie Madille83d1a92013-10-24 17:49:33 -04002134 return (mTexStorage && mTexStorage->isRenderTarget());
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002135}
2136
Jamie Madilla2d4e552013-10-10 15:12:01 -04002137rx::RenderTarget *Texture3D::getRenderTarget(GLint level)
2138{
2139 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04002140 if (!ensureRenderTarget())
Jamie Madilla2d4e552013-10-10 15:12:01 -04002141 {
2142 return NULL;
2143 }
2144
Jamie Madill169d1112013-10-24 17:49:37 -04002145 updateStorageLevel(level);
Jamie Madilla2d4e552013-10-10 15:12:01 -04002146
2147 // ensure this is NOT a depth texture
2148 if (isDepth(level))
2149 {
2150 return NULL;
2151 }
2152
2153 return mTexStorage->getRenderTarget(level);
2154}
2155
Geoff Lang8040f572013-07-25 16:49:54 -04002156rx::RenderTarget *Texture3D::getRenderTarget(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002157{
Geoff Lang8040f572013-07-25 16:49:54 -04002158 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04002159 if (!ensureRenderTarget())
Geoff Lang8040f572013-07-25 16:49:54 -04002160 {
2161 return NULL;
2162 }
2163
Jamie Madill169d1112013-10-24 17:49:37 -04002164 updateStorage();
Geoff Lang8040f572013-07-25 16:49:54 -04002165
2166 // ensure this is NOT a depth texture
2167 if (isDepth(level))
2168 {
2169 return NULL;
2170 }
2171
2172 return mTexStorage->getRenderTarget(level, layer);
2173}
2174
2175rx::RenderTarget *Texture3D::getDepthStencil(GLint level, GLint layer)
2176{
2177 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04002178 if (!ensureRenderTarget())
Geoff Lang8040f572013-07-25 16:49:54 -04002179 {
2180 return NULL;
2181 }
2182
Jamie Madill169d1112013-10-24 17:49:37 -04002183 updateStorageLevel(level);
Geoff Lang8040f572013-07-25 16:49:54 -04002184
2185 // ensure this is a depth texture
2186 if (!isDepth(level))
2187 {
2188 return NULL;
2189 }
2190
2191 return mTexStorage->getRenderTarget(level, layer);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002192}
2193
Geoff Lang005df412013-10-16 14:12:50 -04002194void Texture3D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002195{
2196 // If there currently is a corresponding storage texture image, it has these parameters
Jamie Madilld3d2a342013-10-07 10:46:35 -04002197 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2198 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
2199 const int storageDepth = std::max(1, getBaseLevelDepth() >> level);
Geoff Lang005df412013-10-16 14:12:50 -04002200 const GLenum storageFormat = getBaseLevelInternalFormat();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002201
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00002202 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, false);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002203
2204 if (mTexStorage)
2205 {
Jamie Madill4cfff5f2013-10-24 17:49:46 -04002206 const int storageLevels = mTexStorage->getMaxLevel();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002207
2208 if ((level >= storageLevels && storageLevels != 0) ||
2209 width != storageWidth ||
2210 height != storageHeight ||
2211 depth != storageDepth ||
2212 internalformat != storageFormat) // Discard mismatched storage
2213 {
2214 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
2215 {
2216 mImageArray[i]->markDirty();
2217 }
2218
2219 delete mTexStorage;
2220 mTexStorage = NULL;
2221 mDirtyImages = true;
2222 }
2223 }
2224}
2225
2226void Texture3D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth)
2227{
Jamie Madill07bb8cf2013-10-24 17:49:44 -04002228 if (isValidLevel(level))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002229 {
2230 rx::Image *image = mImageArray[level];
Jamie Madill169d1112013-10-24 17:49:37 -04002231 if (image->copyToStorage(mTexStorage, level, xoffset, yoffset, zoffset, width, height, depth))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002232 {
2233 image->markClean();
2234 }
2235 }
2236}
2237
Geoff Lang4907f2c2013-07-25 12:53:57 -04002238Texture2DArray::Texture2DArray(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_2D_ARRAY)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002239{
2240 mTexStorage = NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002241
2242 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2243 {
2244 mLayerCounts[level] = 0;
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002245 mImageArray[level] = NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002246 }
2247}
2248
2249Texture2DArray::~Texture2DArray()
2250{
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002251 delete mTexStorage;
2252 mTexStorage = NULL;
Jamie Madill884a4622013-10-24 17:49:41 -04002253
2254 deleteImages();
2255}
2256
2257void Texture2DArray::deleteImages()
2258{
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002259 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2260 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002261 for (int layer = 0; layer < mLayerCounts[level]; ++layer)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002262 {
2263 delete mImageArray[level][layer];
2264 }
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002265 delete[] mImageArray[level];
Jamie Madill884a4622013-10-24 17:49:41 -04002266 mImageArray[level] = NULL;
2267 mLayerCounts[level] = 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002268 }
2269}
2270
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002271GLsizei Texture2DArray::getWidth(GLint level) const
2272{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002273 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 +00002274}
2275
2276GLsizei Texture2DArray::getHeight(GLint level) const
2277{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002278 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 +00002279}
2280
Jamie Madillb8f8b892014-01-07 10:12:50 -05002281GLsizei Texture2DArray::getLayers(GLint level) const
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002282{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002283 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mLayerCounts[level] : 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002284}
2285
2286GLenum Texture2DArray::getInternalFormat(GLint level) const
2287{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002288 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 +00002289}
2290
2291GLenum Texture2DArray::getActualFormat(GLint level) const
2292{
Geoff Langcbf727a2014-02-10 12:50:45 -05002293 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 +00002294}
2295
2296bool Texture2DArray::isCompressed(GLint level) const
2297{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00002298 return IsFormatCompressed(getInternalFormat(level), mRenderer->getCurrentClientVersion());
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002299}
2300
2301bool Texture2DArray::isDepth(GLint level) const
2302{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00002303 return GetDepthBits(getInternalFormat(level), mRenderer->getCurrentClientVersion()) > 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002304}
2305
Geoff Lang005df412013-10-16 14:12:50 -04002306void 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 +00002307{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00002308 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Geoff Lang005df412013-10-16 14:12:50 -04002309 GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
2310 : GetSizedInternalFormat(format, type, clientVersion);
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00002311 redefineImage(level, sizedInternalFormat, width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002312
Jamie Madill88f18f42013-09-18 14:36:19 -04002313 GLsizei inputDepthPitch = gl::GetDepthPitch(sizedInternalFormat, type, clientVersion, width, height, unpack.alignment);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002314
2315 for (int i = 0; i < depth; i++)
2316 {
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002317 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
Jamie Madill88f18f42013-09-18 14:36:19 -04002318 Texture::setImage(unpack, type, layerPixels, mImageArray[level][i]);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002319 }
2320}
2321
2322void Texture2DArray::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
2323{
2324 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
2325 redefineImage(level, format, width, height, depth);
2326
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002327 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2328 GLsizei inputDepthPitch = gl::GetDepthPitch(format, GL_UNSIGNED_BYTE, clientVersion, width, height, 1);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002329
2330 for (int i = 0; i < depth; i++)
2331 {
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002332 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002333 Texture::setCompressedImage(imageSize, layerPixels, mImageArray[level][i]);
2334 }
2335}
2336
Jamie Madill88f18f42013-09-18 14:36:19 -04002337void 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 +00002338{
Geoff Lang005df412013-10-16 14:12:50 -04002339 GLenum internalformat = getInternalFormat(level);
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002340 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Jamie Madill88f18f42013-09-18 14:36:19 -04002341 GLsizei inputDepthPitch = gl::GetDepthPitch(internalformat, type, clientVersion, width, height, unpack.alignment);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002342
2343 for (int i = 0; i < depth; i++)
2344 {
2345 int layer = zoffset + i;
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002346 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002347
Jamie Madill88f18f42013-09-18 14:36:19 -04002348 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 +00002349 {
2350 commitRect(level, xoffset, yoffset, layer, width, height);
2351 }
2352 }
2353}
2354
2355void Texture2DArray::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
2356{
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002357 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2358 GLsizei inputDepthPitch = gl::GetDepthPitch(format, GL_UNSIGNED_BYTE, clientVersion, width, height, 1);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002359
2360 for (int i = 0; i < depth; i++)
2361 {
2362 int layer = zoffset + i;
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002363 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002364
2365 if (Texture::subImageCompressed(xoffset, yoffset, zoffset, width, height, 1, format, imageSize, layerPixels, mImageArray[level][layer]))
2366 {
2367 commitRect(level, xoffset, yoffset, layer, width, height);
2368 }
2369 }
2370}
2371
2372void Texture2DArray::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2373{
Jamie Madill884a4622013-10-24 17:49:41 -04002374 deleteImages();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002375
2376 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2377 {
Jamie Madill884a4622013-10-24 17:49:41 -04002378 GLsizei levelWidth = std::max(1, width >> level);
2379 GLsizei levelHeight = std::max(1, height >> level);
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002380
Jamie Madill884a4622013-10-24 17:49:41 -04002381 mLayerCounts[level] = (level < levels ? depth : 0);
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002382
Jamie Madill884a4622013-10-24 17:49:41 -04002383 if (mLayerCounts[level] > 0)
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002384 {
2385 // Create new images for this level
Jamie Madill884a4622013-10-24 17:49:41 -04002386 mImageArray[level] = new rx::Image*[mLayerCounts[level]];
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002387
2388 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002389 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002390 mImageArray[level][layer] = mRenderer->createImage();
2391 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, levelWidth,
2392 levelHeight, 1, true);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002393 }
2394 }
2395 }
2396
Jamie Madill884a4622013-10-24 17:49:41 -04002397 mImmutable = true;
Jamie Madill4cfff5f2013-10-24 17:49:46 -04002398 setCompleteTexStorage(new rx::TextureStorageInterface2DArray(mRenderer, 0, levels, internalformat, IsRenderTargetUsage(mUsage), width, height, depth));
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002399}
2400
2401void Texture2DArray::generateMipmaps()
2402{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002403 int baseWidth = getBaseLevelWidth();
2404 int baseHeight = getBaseLevelHeight();
2405 int baseDepth = getBaseLevelDepth();
2406 GLenum baseFormat = getBaseLevelInternalFormat();
2407
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00002408 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Jamie Madill22f843a2013-10-24 17:49:36 -04002409 int q = mipLevels();
2410 for (int level = 1; level <= q; level++)
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00002411 {
Jamie Madill22f843a2013-10-24 17:49:36 -04002412 redefineImage(level, baseFormat, std::max(baseWidth >> level, 1), std::max(baseHeight >> level, 1), baseDepth);
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00002413 }
2414
2415 if (mTexStorage && mTexStorage->isRenderTarget())
2416 {
2417 for (int level = 1; level <= q; level++)
2418 {
2419 mTexStorage->generateMipmap(level);
2420
2421 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2422 {
2423 mImageArray[level][layer]->markClean();
2424 }
2425 }
2426 }
2427 else
2428 {
2429 for (int level = 1; level <= q; level++)
2430 {
2431 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2432 {
2433 mRenderer->generateMipmap(mImageArray[level][layer], mImageArray[level - 1][layer]);
2434 }
2435 }
2436 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002437}
2438
Jamie Madilld3d2a342013-10-07 10:46:35 -04002439const rx::Image *Texture2DArray::getBaseLevelImage() const
2440{
Jamie Madill152ed092013-10-09 17:01:15 -04002441 return (mLayerCounts[0] > 0 ? mImageArray[0][0] : NULL);
Jamie Madilld3d2a342013-10-07 10:46:35 -04002442}
2443
Jamie Madill2ebab852013-10-24 17:49:42 -04002444rx::TextureStorageInterface *Texture2DArray::getBaseLevelStorage()
2445{
2446 return mTexStorage;
2447}
2448
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002449void Texture2DArray::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
2450{
Jamie Madillb8f8b892014-01-07 10:12:50 -05002451 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 +00002452 {
2453 return gl::error(GL_INVALID_VALUE);
2454 }
2455
Jamie Madill07edd442013-07-19 16:36:58 -04002456 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
2457 // the current level we're copying to is defined (with appropriate format, width & height)
2458 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
2459
2460 if (!mImageArray[level][0]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002461 {
2462 mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, x, y, width, height, source);
2463 mDirtyImages = true;
2464 }
2465 else
2466 {
Jamie Madille83d1a92013-10-24 17:49:33 -04002467 ensureRenderTarget();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002468
Jamie Madill07bb8cf2013-10-24 17:49:44 -04002469 if (isValidLevel(level))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002470 {
Jamie Madill169d1112013-10-24 17:49:37 -04002471 updateStorageLevel(level);
Jamie Madill07edd442013-07-19 16:36:58 -04002472
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002473 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2474
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002475 gl::Rectangle sourceRect;
2476 sourceRect.x = x;
2477 sourceRect.width = width;
2478 sourceRect.y = y;
2479 sourceRect.height = height;
2480
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002481 mRenderer->copyImage(source, sourceRect, gl::GetFormat(getInternalFormat(0), clientVersion),
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002482 xoffset, yoffset, zoffset, mTexStorage, level);
2483 }
2484 }
2485}
2486
Jamie Madillf8989902013-07-19 16:36:58 -04002487bool Texture2DArray::isSamplerComplete(const SamplerState &samplerState) const
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002488{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002489 GLsizei width = getBaseLevelWidth();
2490 GLsizei height = getBaseLevelHeight();
Jamie Madillb8f8b892014-01-07 10:12:50 -05002491 GLsizei depth = getLayers(0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002492
2493 if (width <= 0 || height <= 0 || depth <= 0)
2494 {
2495 return false;
2496 }
2497
Jamie Madilld3d2a342013-10-07 10:46:35 -04002498 if (!IsTextureFilteringSupported(getBaseLevelInternalFormat(), mRenderer))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002499 {
Jamie Madillf8989902013-07-19 16:36:58 -04002500 if (samplerState.magFilter != GL_NEAREST ||
2501 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002502 {
2503 return false;
2504 }
2505 }
2506
Jamie Madillf8989902013-07-19 16:36:58 -04002507 if (IsMipmapFiltered(samplerState) && !isMipmapComplete())
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002508 {
2509 return false;
2510 }
2511
2512 return true;
2513}
2514
2515bool Texture2DArray::isMipmapComplete() const
2516{
Jamie Madill22f843a2013-10-24 17:49:36 -04002517 int q = mipLevels();
Jamie Madill07edd442013-07-19 16:36:58 -04002518
2519 for (int level = 1; level <= q; level++)
2520 {
2521 if (!isLevelComplete(level))
2522 {
2523 return false;
2524 }
2525 }
2526
2527 return true;
2528}
2529
2530bool Texture2DArray::isLevelComplete(int level) const
2531{
Jamie Madillb8f8b892014-01-07 10:12:50 -05002532 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray));
Jamie Madill07edd442013-07-19 16:36:58 -04002533
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002534 if (isImmutable())
2535 {
2536 return true;
2537 }
2538
Jamie Madilld3d2a342013-10-07 10:46:35 -04002539 GLsizei width = getBaseLevelWidth();
2540 GLsizei height = getBaseLevelHeight();
Jamie Madillb8f8b892014-01-07 10:12:50 -05002541 GLsizei layers = getLayers(0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002542
Jamie Madillb8f8b892014-01-07 10:12:50 -05002543 if (width <= 0 || height <= 0 || layers <= 0)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002544 {
2545 return false;
2546 }
2547
Jamie Madill07edd442013-07-19 16:36:58 -04002548 if (level == 0)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002549 {
Jamie Madill07edd442013-07-19 16:36:58 -04002550 return true;
2551 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002552
Jamie Madill07edd442013-07-19 16:36:58 -04002553 if (getInternalFormat(level) != getInternalFormat(0))
2554 {
2555 return false;
2556 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002557
Jamie Madill07edd442013-07-19 16:36:58 -04002558 if (getWidth(level) != std::max(1, width >> level))
2559 {
2560 return false;
2561 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002562
Jamie Madill07edd442013-07-19 16:36:58 -04002563 if (getHeight(level) != std::max(1, height >> level))
2564 {
2565 return false;
2566 }
2567
Jamie Madillb8f8b892014-01-07 10:12:50 -05002568 if (getLayers(level) != layers)
Jamie Madill07edd442013-07-19 16:36:58 -04002569 {
2570 return false;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002571 }
2572
2573 return true;
2574}
2575
Geoff Lang8040f572013-07-25 16:49:54 -04002576Renderbuffer *Texture2DArray::getRenderbuffer(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002577{
Geoff Lang8040f572013-07-25 16:49:54 -04002578 Renderbuffer *renderBuffer = mRenderbufferProxies.get(level, layer);
2579 if (!renderBuffer)
2580 {
Geoff Langd5d8e392013-07-25 16:53:03 -04002581 renderBuffer = new Renderbuffer(mRenderer, id(), new RenderbufferTexture2DArrayLayer(this, level, layer));
2582 mRenderbufferProxies.add(level, 0, renderBuffer);
Geoff Lang8040f572013-07-25 16:49:54 -04002583 }
2584
2585 return renderBuffer;
2586}
2587
Jamie Madille83d1a92013-10-24 17:49:33 -04002588unsigned int Texture2DArray::getRenderTargetSerial(GLint level, GLint layer)
Geoff Lang8040f572013-07-25 16:49:54 -04002589{
Jamie Madille83d1a92013-10-24 17:49:33 -04002590 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(level, layer) : 0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002591}
2592
Jamie Madill07bb8cf2013-10-24 17:49:44 -04002593bool Texture2DArray::isValidLevel(int level) const
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002594{
Jamie Madill4cfff5f2013-10-24 17:49:46 -04002595 return (mTexStorage ? (level >= mTexStorage->getBaseLevel() && level < mTexStorage->getMaxLevel()) : 0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002596}
2597
Jamie Madill73b5d062013-10-24 17:49:38 -04002598void Texture2DArray::initializeStorage(bool renderTarget)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002599{
Jamie Madill884a4622013-10-24 17:49:41 -04002600 // Only initialize the first time this texture is used as a render target or shader resource
2601 if (mTexStorage)
2602 {
2603 return;
2604 }
2605
2606 // do not attempt to create storage for nonexistant data
2607 if (!isLevelComplete(0))
2608 {
2609 return;
2610 }
2611
2612 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
2613
2614 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
2615 ASSERT(mTexStorage);
2616
2617 // flush image data to the storage
2618 updateStorage();
2619}
2620
2621rx::TextureStorageInterface2DArray *Texture2DArray::createCompleteStorage(bool renderTarget) const
2622{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002623 GLsizei width = getBaseLevelWidth();
2624 GLsizei height = getBaseLevelHeight();
Jamie Madillb8f8b892014-01-07 10:12:50 -05002625 GLsizei depth = getLayers(0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002626
Jamie Madill884a4622013-10-24 17:49:41 -04002627 ASSERT(width > 0 && height > 0 && depth > 0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002628
Jamie Madill884a4622013-10-24 17:49:41 -04002629 // use existing storage level count, when previously specified by TexStorage*D
Jamie Madill6b7440c2013-10-24 17:49:47 -04002630 GLint levels = (mTexStorage ? mTexStorage->getMaxLevel() : creationLevels(width, height, 1));
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002631
Jamie Madill4cfff5f2013-10-24 17:49:46 -04002632 return new rx::TextureStorageInterface2DArray(mRenderer, 0, levels, getBaseLevelInternalFormat(), renderTarget, width, height, depth);
Jamie Madill884a4622013-10-24 17:49:41 -04002633}
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002634
Jamie Madill884a4622013-10-24 17:49:41 -04002635void Texture2DArray::setCompleteTexStorage(rx::TextureStorageInterface2DArray *newCompleteTexStorage)
2636{
2637 SafeDelete(mTexStorage);
2638 mTexStorage = newCompleteTexStorage;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002639 mDirtyImages = true;
Jamie Madill884a4622013-10-24 17:49:41 -04002640
2641 // We do not support managed 2D array storage, as managed storage is ES2/D3D9 only
2642 ASSERT(!mTexStorage->isManaged());
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002643}
2644
Jamie Madill169d1112013-10-24 17:49:37 -04002645void Texture2DArray::updateStorage()
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002646{
Jamie Madill4cfff5f2013-10-24 17:49:46 -04002647 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002648 {
Jamie Madilld9b9a502013-10-10 17:46:13 -04002649 if (isLevelComplete(level))
2650 {
Jamie Madill169d1112013-10-24 17:49:37 -04002651 updateStorageLevel(level);
Jamie Madilld9b9a502013-10-10 17:46:13 -04002652 }
Jamie Madill07edd442013-07-19 16:36:58 -04002653 }
2654}
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002655
Jamie Madill169d1112013-10-24 17:49:37 -04002656void Texture2DArray::updateStorageLevel(int level)
Jamie Madill07edd442013-07-19 16:36:58 -04002657{
Jamie Madillaee7ad82013-10-10 16:07:32 -04002658 ASSERT(level >= 0 && level < (int)ArraySize(mLayerCounts));
2659 ASSERT(isLevelComplete(level));
2660
Jamie Madill07edd442013-07-19 16:36:58 -04002661 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2662 {
Jamie Madillaee7ad82013-10-10 16:07:32 -04002663 ASSERT(mImageArray[level] != NULL && mImageArray[level][layer] != NULL);
2664 if (mImageArray[level][layer]->isDirty())
Jamie Madill07edd442013-07-19 16:36:58 -04002665 {
Jamie Madillaee7ad82013-10-10 16:07:32 -04002666 commitRect(level, 0, 0, layer, getWidth(level), getHeight(level));
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002667 }
2668 }
2669}
2670
Jamie Madille83d1a92013-10-24 17:49:33 -04002671bool Texture2DArray::ensureRenderTarget()
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002672{
Jamie Madill884a4622013-10-24 17:49:41 -04002673 initializeStorage(true);
2674
Jamie Madillb8f8b892014-01-07 10:12:50 -05002675 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0 && getLayers(0) > 0)
Jamie Madille83d1a92013-10-24 17:49:33 -04002676 {
Jamie Madill884a4622013-10-24 17:49:41 -04002677 ASSERT(mTexStorage);
2678 if (!mTexStorage->isRenderTarget())
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002679 {
Jamie Madill884a4622013-10-24 17:49:41 -04002680 rx::TextureStorageInterface2DArray *newRenderTargetStorage = createCompleteStorage(true);
2681
2682 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002683 {
Jamie Madill884a4622013-10-24 17:49:41 -04002684 delete newRenderTargetStorage;
Jamie Madille83d1a92013-10-24 17:49:33 -04002685 return gl::error(GL_OUT_OF_MEMORY, false);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002686 }
Jamie Madill884a4622013-10-24 17:49:41 -04002687
2688 setCompleteTexStorage(newRenderTargetStorage);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002689 }
2690 }
2691
Jamie Madille83d1a92013-10-24 17:49:33 -04002692 return (mTexStorage && mTexStorage->isRenderTarget());
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002693}
2694
Geoff Lang8040f572013-07-25 16:49:54 -04002695rx::RenderTarget *Texture2DArray::getRenderTarget(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002696{
Geoff Lang8040f572013-07-25 16:49:54 -04002697 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04002698 if (!ensureRenderTarget())
Geoff Lang8040f572013-07-25 16:49:54 -04002699 {
2700 return NULL;
2701 }
2702
Jamie Madill169d1112013-10-24 17:49:37 -04002703 updateStorageLevel(level);
Geoff Lang8040f572013-07-25 16:49:54 -04002704
2705 // ensure this is NOT a depth texture
2706 if (isDepth(level))
2707 {
2708 return NULL;
2709 }
2710
2711 return mTexStorage->getRenderTarget(level, layer);
2712}
2713
2714rx::RenderTarget *Texture2DArray::getDepthStencil(GLint level, GLint layer)
2715{
2716 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04002717 if (!ensureRenderTarget())
Geoff Lang8040f572013-07-25 16:49:54 -04002718 {
2719 return NULL;
2720 }
2721
Jamie Madill169d1112013-10-24 17:49:37 -04002722 updateStorageLevel(level);
Geoff Lang8040f572013-07-25 16:49:54 -04002723
2724 // ensure this is a depth texture
2725 if (!isDepth(level))
2726 {
2727 return NULL;
2728 }
2729
2730 return mTexStorage->getRenderTarget(level, layer);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002731}
2732
Geoff Lang005df412013-10-16 14:12:50 -04002733void Texture2DArray::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002734{
2735 // If there currently is a corresponding storage texture image, it has these parameters
Jamie Madilld3d2a342013-10-07 10:46:35 -04002736 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2737 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
Jamie Madillb8f8b892014-01-07 10:12:50 -05002738 const int storageDepth = getLayers(0);
Geoff Lang005df412013-10-16 14:12:50 -04002739 const GLenum storageFormat = getBaseLevelInternalFormat();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002740
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002741 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002742 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002743 delete mImageArray[level][layer];
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002744 }
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002745 delete[] mImageArray[level];
Jamie Madill152ed092013-10-09 17:01:15 -04002746 mImageArray[level] = NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002747 mLayerCounts[level] = depth;
2748
Jamie Madill152ed092013-10-09 17:01:15 -04002749 if (depth > 0)
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002750 {
Jamie Madill152ed092013-10-09 17:01:15 -04002751 mImageArray[level] = new rx::Image*[depth]();
2752
2753 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2754 {
2755 mImageArray[level][layer] = mRenderer->createImage();
2756 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, width, height, 1, false);
2757 }
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002758 }
2759
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002760 if (mTexStorage)
2761 {
Jamie Madill4cfff5f2013-10-24 17:49:46 -04002762 const int storageLevels = mTexStorage->getMaxLevel();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002763
2764 if ((level >= storageLevels && storageLevels != 0) ||
2765 width != storageWidth ||
2766 height != storageHeight ||
2767 depth != storageDepth ||
2768 internalformat != storageFormat) // Discard mismatched storage
2769 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002770 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002771 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002772 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002773 {
2774 mImageArray[level][layer]->markDirty();
2775 }
2776 }
2777
2778 delete mTexStorage;
2779 mTexStorage = NULL;
2780 mDirtyImages = true;
2781 }
2782 }
2783}
2784
2785void Texture2DArray::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint layerTarget, GLsizei width, GLsizei height)
2786{
Jamie Madillb8f8b892014-01-07 10:12:50 -05002787 if (isValidLevel(level) && layerTarget < getLayers(level))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002788 {
2789 rx::Image *image = mImageArray[level][layerTarget];
Jamie Madill169d1112013-10-24 17:49:37 -04002790 if (image->copyToStorage(mTexStorage, level, xoffset, yoffset, layerTarget, width, height))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002791 {
2792 image->markClean();
2793 }
2794 }
2795}
2796
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00002797}