blob: 9a7740819f6fbfa22ef42c23a3b7ed429123a5d6 [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
Nicolas Capensf61738a2014-03-31 14:50:18 -0400220int Texture::getTopLevel()
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000221{
Jamie Madill2ebab852013-10-24 17:49:42 -0400222 rx::TextureStorageInterface *texture = getNativeTexture();
Nicolas Capensf61738a2014-03-31 14:50:18 -0400223 return texture ? texture->getTopLevel() : 0;
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000224}
225
226void Texture::getSamplerState(SamplerState *sampler)
227{
228 *sampler = mSamplerState;
Nicolas Capensf61738a2014-03-31 14:50:18 -0400229 sampler->lodOffset = getTopLevel();
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{
Nicolas Capensbf712d02014-03-31 14:23:35 -0400395 return (mImmutable ? getNativeTexture()->getStorageInstance()->getLevelCount() : 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
Geoff Lang98705b72014-03-31 16:00:03 -0400403 return log2(std::max(std::max(width, height), depth)) + 1;
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{
Geoff Lang98705b72014-03-31 16:00:03 -0400414 return log2(std::max(std::max(getBaseLevelWidth(), getBaseLevelHeight()), getBaseLevelDepth())) + 1;
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 {
Nicolas Capensbf712d02014-03-31 14:23:35 -0400490 const int storageLevels = mTexStorage->getLevelCount();
491
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000492 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
Nicolas Capensbf712d02014-03-31 14:23:35 -0400713 setCompleteTexStorage(new rx::TextureStorageInterface2D(mRenderer, internalformat, IsRenderTargetUsage(mUsage), width, height, levels));
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 {
Nicolas Capensbf712d02014-03-31 14:23:35 -0400723 for (int level = 0; level < mTexStorage->getLevelCount(); level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000724 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000725 mImageArray[level]->setManagedSurface(mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000726 }
727 }
Jamie Madill73b5d062013-10-24 17:49:38 -0400728
729 mDirtyImages = true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000730}
731
732// Tests for 2D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85.
Jamie Madillf8989902013-07-19 16:36:58 -0400733bool Texture2D::isSamplerComplete(const SamplerState &samplerState) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000734{
Jamie Madilld3d2a342013-10-07 10:46:35 -0400735 GLsizei width = getBaseLevelWidth();
736 GLsizei height = getBaseLevelHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000737
738 if (width <= 0 || height <= 0)
739 {
740 return false;
741 }
742
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000743 if (!IsTextureFilteringSupported(getInternalFormat(0), mRenderer))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000744 {
Jamie Madillf8989902013-07-19 16:36:58 -0400745 if (samplerState.magFilter != GL_NEAREST ||
746 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000747 {
748 return false;
749 }
750 }
751
daniel@transgaming.comea32d482012-11-28 19:33:18 +0000752 bool npotSupport = mRenderer->getNonPower2TextureSupport();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000753
754 if (!npotSupport)
755 {
Jamie Madillf8989902013-07-19 16:36:58 -0400756 if ((samplerState.wrapS != GL_CLAMP_TO_EDGE && !isPow2(width)) ||
757 (samplerState.wrapT != GL_CLAMP_TO_EDGE && !isPow2(height)))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000758 {
759 return false;
760 }
761 }
762
Jamie Madillf8989902013-07-19 16:36:58 -0400763 if (IsMipmapFiltered(samplerState))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000764 {
765 if (!npotSupport)
766 {
767 if (!isPow2(width) || !isPow2(height))
768 {
769 return false;
770 }
771 }
772
773 if (!isMipmapComplete())
774 {
775 return false;
776 }
777 }
778
Geoff Langc82fc412013-07-10 14:43:42 -0400779 // OpenGLES 3.0.2 spec section 3.8.13 states that a texture is not mipmap complete if:
780 // The internalformat specified for the texture arrays is a sized internal depth or
781 // depth and stencil format (see table 3.13), the value of TEXTURE_COMPARE_-
782 // MODE is NONE, and either the magnification filter is not NEAREST or the mini-
783 // fication filter is neither NEAREST nor NEAREST_MIPMAP_NEAREST.
Jamie Madill2a205622014-02-12 10:41:24 -0500784 if (gl::GetDepthBits(getInternalFormat(0), mRenderer->getCurrentClientVersion()) > 0 &&
785 mRenderer->getCurrentClientVersion() > 2)
Geoff Langc82fc412013-07-10 14:43:42 -0400786 {
787 if (mSamplerState.compareMode == GL_NONE)
788 {
789 if ((mSamplerState.minFilter != GL_NEAREST && mSamplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST) ||
790 mSamplerState.magFilter != GL_NEAREST)
791 {
792 return false;
793 }
794 }
795 }
796
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000797 return true;
798}
799
800// Tests for 2D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
801bool Texture2D::isMipmapComplete() const
802{
Geoff Lang98705b72014-03-31 16:00:03 -0400803 int levelCount = mipLevels();
Jamie Madill07edd442013-07-19 16:36:58 -0400804
Geoff Lang98705b72014-03-31 16:00:03 -0400805 for (int level = 0; level < levelCount; level++)
Jamie Madill07edd442013-07-19 16:36:58 -0400806 {
807 if (!isLevelComplete(level))
808 {
809 return false;
810 }
811 }
812
813 return true;
814}
815
816bool Texture2D::isLevelComplete(int level) const
817{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000818 if (isImmutable())
819 {
820 return true;
821 }
822
Jamie Madill648c9682014-01-21 16:50:58 -0500823 const rx::Image *baseImage = getBaseLevelImage();
824
825 GLsizei width = baseImage->getWidth();
826 GLsizei height = baseImage->getHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000827
828 if (width <= 0 || height <= 0)
829 {
830 return false;
831 }
832
Jamie Madill07edd442013-07-19 16:36:58 -0400833 // The base image level is complete if the width and height are positive
834 if (level == 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000835 {
Jamie Madill07edd442013-07-19 16:36:58 -0400836 return true;
837 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000838
Jamie Madill07edd442013-07-19 16:36:58 -0400839 ASSERT(level >= 1 && level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
840 rx::Image *image = mImageArray[level];
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000841
Jamie Madill648c9682014-01-21 16:50:58 -0500842 if (image->getInternalFormat() != baseImage->getInternalFormat())
Jamie Madill07edd442013-07-19 16:36:58 -0400843 {
844 return false;
845 }
846
847 if (image->getWidth() != std::max(1, width >> level))
848 {
849 return false;
850 }
851
852 if (image->getHeight() != std::max(1, height >> level))
853 {
854 return false;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000855 }
856
857 return true;
858}
859
860bool Texture2D::isCompressed(GLint level) const
861{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000862 return IsFormatCompressed(getInternalFormat(level), mRenderer->getCurrentClientVersion());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000863}
864
865bool Texture2D::isDepth(GLint level) const
866{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000867 return GetDepthBits(getInternalFormat(level), mRenderer->getCurrentClientVersion()) > 0;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000868}
869
daniel@transgaming.comf032cb82012-10-31 19:51:52 +0000870// Constructs a native texture resource from the texture images
Jamie Madill73b5d062013-10-24 17:49:38 -0400871void Texture2D::initializeStorage(bool renderTarget)
872{
873 // Only initialize the first time this texture is used as a render target or shader resource
874 if (mTexStorage)
875 {
876 return;
877 }
878
879 // do not attempt to create storage for nonexistant data
880 if (!isLevelComplete(0))
881 {
882 return;
883 }
884
885 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
886
887 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
888 ASSERT(mTexStorage);
889
890 // flush image data to the storage
891 updateStorage();
892}
893
894rx::TextureStorageInterface2D *Texture2D::createCompleteStorage(bool renderTarget) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000895{
Jamie Madilld3d2a342013-10-07 10:46:35 -0400896 GLsizei width = getBaseLevelWidth();
897 GLsizei height = getBaseLevelHeight();
daniel@transgaming.come6a09842012-09-17 21:28:55 +0000898
Jamie Madill73b5d062013-10-24 17:49:38 -0400899 ASSERT(width > 0 && height > 0);
daniel@transgaming.come6a09842012-09-17 21:28:55 +0000900
Jamie Madill73b5d062013-10-24 17:49:38 -0400901 // use existing storage level count, when previously specified by TexStorage*D
Nicolas Capensbf712d02014-03-31 14:23:35 -0400902 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000903
Nicolas Capensbf712d02014-03-31 14:23:35 -0400904 return new rx::TextureStorageInterface2D(mRenderer, getBaseLevelInternalFormat(), renderTarget, width, height, levels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000905}
906
Jamie Madill169d1112013-10-24 17:49:37 -0400907void Texture2D::updateStorage()
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000908{
Jamie Madill4cfff5f2013-10-24 17:49:46 -0400909 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000910 {
Jamie Madill648c9682014-01-21 16:50:58 -0500911 if (mImageArray[level]->isDirty() && isLevelComplete(level))
Jamie Madilld9b9a502013-10-10 17:46:13 -0400912 {
Jamie Madill169d1112013-10-24 17:49:37 -0400913 updateStorageLevel(level);
Jamie Madilld9b9a502013-10-10 17:46:13 -0400914 }
Jamie Madill07edd442013-07-19 16:36:58 -0400915 }
916}
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000917
Jamie Madill169d1112013-10-24 17:49:37 -0400918void Texture2D::updateStorageLevel(int level)
Jamie Madill07edd442013-07-19 16:36:58 -0400919{
920 ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
Jamie Madillaee7ad82013-10-10 16:07:32 -0400921 ASSERT(isLevelComplete(level));
Jamie Madill07edd442013-07-19 16:36:58 -0400922
Jamie Madillaee7ad82013-10-10 16:07:32 -0400923 if (mImageArray[level]->isDirty())
Jamie Madill07edd442013-07-19 16:36:58 -0400924 {
Jamie Madillaee7ad82013-10-10 16:07:32 -0400925 commitRect(level, 0, 0, getWidth(level), getHeight(level));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000926 }
927}
928
Jamie Madille83d1a92013-10-24 17:49:33 -0400929bool Texture2D::ensureRenderTarget()
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000930{
Jamie Madill73b5d062013-10-24 17:49:38 -0400931 initializeStorage(true);
932
933 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0)
Jamie Madille83d1a92013-10-24 17:49:33 -0400934 {
Jamie Madill73b5d062013-10-24 17:49:38 -0400935 ASSERT(mTexStorage);
936 if (!mTexStorage->isRenderTarget())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000937 {
Jamie Madill73b5d062013-10-24 17:49:38 -0400938 rx::TextureStorageInterface2D *newRenderTargetStorage = createCompleteStorage(true);
939
940 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
941 {
942 delete newRenderTargetStorage;
Jamie Madille83d1a92013-10-24 17:49:33 -0400943 return gl::error(GL_OUT_OF_MEMORY, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000944 }
Jamie Madill73b5d062013-10-24 17:49:38 -0400945
946 setCompleteTexStorage(newRenderTargetStorage);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000947 }
948 }
949
Jamie Madille83d1a92013-10-24 17:49:33 -0400950 return (mTexStorage && mTexStorage->isRenderTarget());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000951}
952
953void Texture2D::generateMipmaps()
954{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000955 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Geoff Lang98705b72014-03-31 16:00:03 -0400956 int levelCount = mipLevels();
957 for (int level = 1; level < levelCount; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000958 {
Jamie Madill22f843a2013-10-24 17:49:36 -0400959 redefineImage(level, getBaseLevelInternalFormat(),
960 std::max(getBaseLevelWidth() >> level, 1),
961 std::max(getBaseLevelHeight() >> level, 1));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000962 }
963
964 if (mTexStorage && mTexStorage->isRenderTarget())
965 {
Geoff Lang98705b72014-03-31 16:00:03 -0400966 for (int level = 1; level < levelCount; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000967 {
Jamie Madill22f843a2013-10-24 17:49:36 -0400968 mTexStorage->generateMipmap(level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000969
Jamie Madill22f843a2013-10-24 17:49:36 -0400970 mImageArray[level]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000971 }
972 }
973 else
974 {
Geoff Lang98705b72014-03-31 16:00:03 -0400975 for (int level = 1; level < levelCount; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000976 {
Jamie Madill22f843a2013-10-24 17:49:36 -0400977 mRenderer->generateMipmap(mImageArray[level], mImageArray[level - 1]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000978 }
979 }
980}
981
Jamie Madilld3d2a342013-10-07 10:46:35 -0400982const rx::Image *Texture2D::getBaseLevelImage() const
983{
984 return mImageArray[0];
985}
986
Jamie Madill2ebab852013-10-24 17:49:42 -0400987rx::TextureStorageInterface *Texture2D::getBaseLevelStorage()
988{
989 return mTexStorage;
990}
991
Geoff Lang8040f572013-07-25 16:49:54 -0400992Renderbuffer *Texture2D::getRenderbuffer(GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000993{
Geoff Lang8040f572013-07-25 16:49:54 -0400994 Renderbuffer *renderBuffer = mRenderbufferProxies.get(level, 0);
995 if (!renderBuffer)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000996 {
Geoff Lang8040f572013-07-25 16:49:54 -0400997 renderBuffer = new Renderbuffer(mRenderer, id(), new RenderbufferTexture2D(this, level));
998 mRenderbufferProxies.add(level, 0, renderBuffer);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000999 }
1000
Geoff Lang8040f572013-07-25 16:49:54 -04001001 return renderBuffer;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001002}
1003
Geoff Lang8040f572013-07-25 16:49:54 -04001004unsigned int Texture2D::getRenderTargetSerial(GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001005{
Jamie Madille83d1a92013-10-24 17:49:33 -04001006 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(level) : 0);
Geoff Lang8040f572013-07-25 16:49:54 -04001007}
1008
1009rx::RenderTarget *Texture2D::getRenderTarget(GLint level)
1010{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001011 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04001012 if (!ensureRenderTarget())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001013 {
1014 return NULL;
1015 }
1016
Jamie Madill169d1112013-10-24 17:49:37 -04001017 updateStorageLevel(level);
Geoff Lang8040f572013-07-25 16:49:54 -04001018
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001019 // ensure this is NOT a depth texture
Geoff Lang8040f572013-07-25 16:49:54 -04001020 if (isDepth(level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001021 {
1022 return NULL;
1023 }
daniel@transgaming.com34da3972012-12-20 21:10:29 +00001024
Geoff Lang8040f572013-07-25 16:49:54 -04001025 return mTexStorage->getRenderTarget(level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001026}
1027
Geoff Lang8040f572013-07-25 16:49:54 -04001028rx::RenderTarget *Texture2D::getDepthSencil(GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001029{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001030 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04001031 if (!ensureRenderTarget())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001032 {
1033 return NULL;
1034 }
1035
Jamie Madill169d1112013-10-24 17:49:37 -04001036 updateStorageLevel(level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001037
1038 // ensure this is actually a depth texture
Geoff Lang8040f572013-07-25 16:49:54 -04001039 if (!isDepth(level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001040 {
1041 return NULL;
1042 }
Geoff Lang8040f572013-07-25 16:49:54 -04001043
1044 return mTexStorage->getRenderTarget(level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001045}
1046
Jamie Madill07bb8cf2013-10-24 17:49:44 -04001047bool Texture2D::isValidLevel(int level) const
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +00001048{
Nicolas Capensbf712d02014-03-31 14:23:35 -04001049 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : false);
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +00001050}
1051
Geoff Lang4907f2c2013-07-25 12:53:57 -04001052TextureCubeMap::TextureCubeMap(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_CUBE_MAP)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001053{
1054 mTexStorage = NULL;
1055 for (int i = 0; i < 6; i++)
1056 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001057 for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
1058 {
daniel@transgaming.com244e1832012-12-20 20:52:35 +00001059 mImageArray[i][j] = renderer->createImage();
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001060 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001061 }
1062}
1063
1064TextureCubeMap::~TextureCubeMap()
1065{
1066 for (int i = 0; i < 6; i++)
1067 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001068 for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
1069 {
1070 delete mImageArray[i][j];
1071 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001072 }
1073
1074 delete mTexStorage;
1075 mTexStorage = NULL;
1076}
1077
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001078GLsizei TextureCubeMap::getWidth(GLenum target, GLint level) const
1079{
1080 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Jamie Madill2db197c2013-10-24 17:49:35 -04001081 return mImageArray[targetToIndex(target)][level]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001082 else
1083 return 0;
1084}
1085
1086GLsizei TextureCubeMap::getHeight(GLenum target, GLint level) const
1087{
1088 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Jamie Madill2db197c2013-10-24 17:49:35 -04001089 return mImageArray[targetToIndex(target)][level]->getHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001090 else
1091 return 0;
1092}
1093
1094GLenum TextureCubeMap::getInternalFormat(GLenum target, GLint level) const
1095{
1096 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Jamie Madill2db197c2013-10-24 17:49:35 -04001097 return mImageArray[targetToIndex(target)][level]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001098 else
1099 return GL_NONE;
1100}
1101
daniel@transgaming.com20d36662012-10-31 19:51:43 +00001102GLenum TextureCubeMap::getActualFormat(GLenum target, GLint level) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001103{
1104 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Jamie Madill2db197c2013-10-24 17:49:35 -04001105 return mImageArray[targetToIndex(target)][level]->getActualFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001106 else
Geoff Langcbf727a2014-02-10 12:50:45 -05001107 return GL_NONE;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001108}
1109
Geoff Lang005df412013-10-16 14:12:50 -04001110void TextureCubeMap::setImagePosX(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001111{
Jamie Madill88f18f42013-09-18 14:36:19 -04001112 setImage(0, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001113}
1114
Geoff Lang005df412013-10-16 14:12:50 -04001115void TextureCubeMap::setImageNegX(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001116{
Jamie Madill88f18f42013-09-18 14:36:19 -04001117 setImage(1, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001118}
1119
Geoff Lang005df412013-10-16 14:12:50 -04001120void TextureCubeMap::setImagePosY(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001121{
Jamie Madill88f18f42013-09-18 14:36:19 -04001122 setImage(2, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001123}
1124
Geoff Lang005df412013-10-16 14:12:50 -04001125void TextureCubeMap::setImageNegY(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001126{
Jamie Madill88f18f42013-09-18 14:36:19 -04001127 setImage(3, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001128}
1129
Geoff Lang005df412013-10-16 14:12:50 -04001130void TextureCubeMap::setImagePosZ(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001131{
Jamie Madill88f18f42013-09-18 14:36:19 -04001132 setImage(4, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001133}
1134
Geoff Lang005df412013-10-16 14:12:50 -04001135void TextureCubeMap::setImageNegZ(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001136{
Jamie Madill88f18f42013-09-18 14:36:19 -04001137 setImage(5, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001138}
1139
Jamie Madill2db197c2013-10-24 17:49:35 -04001140void TextureCubeMap::setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001141{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001142 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
Jamie Madill2db197c2013-10-24 17:49:35 -04001143 int faceIndex = targetToIndex(target);
1144 redefineImage(faceIndex, level, format, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001145
Jamie Madill2db197c2013-10-24 17:49:35 -04001146 Texture::setCompressedImage(imageSize, pixels, mImageArray[faceIndex][level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001147}
1148
Jamie Madill2db197c2013-10-24 17:49:35 -04001149void TextureCubeMap::commitRect(int faceIndex, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001150{
Jamie Madill07bb8cf2013-10-24 17:49:44 -04001151 if (isValidFaceLevel(faceIndex, level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001152 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001153 rx::Image *image = mImageArray[faceIndex][level];
Jamie Madill169d1112013-10-24 17:49:37 -04001154 if (image->copyToStorage(mTexStorage, faceIndex, level, xoffset, yoffset, width, height))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001155 image->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001156 }
1157}
1158
Jamie Madill88f18f42013-09-18 14:36:19 -04001159void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001160{
Jamie Madill2db197c2013-10-24 17:49:35 -04001161 int faceIndex = targetToIndex(target);
1162 if (Texture::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, mImageArray[faceIndex][level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001163 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001164 commitRect(faceIndex, level, xoffset, yoffset, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001165 }
1166}
1167
1168void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1169{
Jamie Madill2db197c2013-10-24 17:49:35 -04001170 int faceIndex = targetToIndex(target);
1171 if (Texture::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[faceIndex][level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001172 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001173 commitRect(faceIndex, level, xoffset, yoffset, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001174 }
1175}
1176
1177// Tests for cube map sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 86.
Jamie Madillf8989902013-07-19 16:36:58 -04001178bool TextureCubeMap::isSamplerComplete(const SamplerState &samplerState) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001179{
Jamie Madilld3d2a342013-10-07 10:46:35 -04001180 int size = getBaseLevelWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001181
Jamie Madillf8989902013-07-19 16:36:58 -04001182 bool mipmapping = IsMipmapFiltered(samplerState);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001183
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001184 if (!IsTextureFilteringSupported(getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0), mRenderer))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001185 {
Jamie Madillf8989902013-07-19 16:36:58 -04001186 if (samplerState.magFilter != GL_NEAREST ||
1187 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001188 {
1189 return false;
1190 }
1191 }
1192
daniel@transgaming.comea32d482012-11-28 19:33:18 +00001193 if (!isPow2(size) && !mRenderer->getNonPower2TextureSupport())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001194 {
Jamie Madillf8989902013-07-19 16:36:58 -04001195 if (samplerState.wrapS != GL_CLAMP_TO_EDGE || samplerState.wrapT != GL_CLAMP_TO_EDGE || mipmapping)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001196 {
1197 return false;
1198 }
1199 }
1200
1201 if (!mipmapping)
1202 {
1203 if (!isCubeComplete())
1204 {
1205 return false;
1206 }
1207 }
1208 else
1209 {
1210 if (!isMipmapCubeComplete()) // Also tests for isCubeComplete()
1211 {
1212 return false;
1213 }
1214 }
1215
1216 return true;
1217}
1218
1219// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1220bool TextureCubeMap::isCubeComplete() const
1221{
Jamie Madillc1f8b162013-10-07 10:46:38 -04001222 int baseWidth = getBaseLevelWidth();
1223 int baseHeight = getBaseLevelHeight();
1224 GLenum baseFormat = getBaseLevelInternalFormat();
1225
1226 if (baseWidth <= 0 || baseWidth != baseHeight)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001227 {
1228 return false;
1229 }
1230
Jamie Madill2db197c2013-10-24 17:49:35 -04001231 for (int faceIndex = 1; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001232 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001233 const rx::Image &faceBaseImage = *mImageArray[faceIndex][0];
Jamie Madillc1f8b162013-10-07 10:46:38 -04001234
1235 if (faceBaseImage.getWidth() != baseWidth ||
1236 faceBaseImage.getHeight() != baseHeight ||
1237 faceBaseImage.getInternalFormat() != baseFormat )
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001238 {
1239 return false;
1240 }
1241 }
1242
1243 return true;
1244}
1245
1246bool TextureCubeMap::isMipmapCubeComplete() const
1247{
1248 if (isImmutable())
1249 {
1250 return true;
1251 }
1252
1253 if (!isCubeComplete())
1254 {
1255 return false;
1256 }
1257
Geoff Lang98705b72014-03-31 16:00:03 -04001258 int levelCount = mipLevels();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001259
1260 for (int face = 0; face < 6; face++)
1261 {
Geoff Lang98705b72014-03-31 16:00:03 -04001262 for (int level = 1; level < levelCount; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001263 {
Jamie Madill07edd442013-07-19 16:36:58 -04001264 if (!isFaceLevelComplete(face, level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001265 {
1266 return false;
1267 }
1268 }
1269 }
1270
1271 return true;
1272}
1273
Jamie Madill2db197c2013-10-24 17:49:35 -04001274bool TextureCubeMap::isFaceLevelComplete(int faceIndex, int level) const
Jamie Madill07edd442013-07-19 16:36:58 -04001275{
Jamie Madill2db197c2013-10-24 17:49:35 -04001276 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
Jamie Madill07edd442013-07-19 16:36:58 -04001277
1278 if (isImmutable())
1279 {
1280 return true;
1281 }
1282
Jamie Madilld3d2a342013-10-07 10:46:35 -04001283 int baseSize = getBaseLevelWidth();
Jamie Madill07edd442013-07-19 16:36:58 -04001284
Jamie Madilld3d2a342013-10-07 10:46:35 -04001285 if (baseSize <= 0)
Jamie Madill07edd442013-07-19 16:36:58 -04001286 {
1287 return false;
1288 }
1289
Jamie Madilld3d2a342013-10-07 10:46:35 -04001290 // "isCubeComplete" checks for base level completeness and we must call that
1291 // to determine if any face at level 0 is complete. We omit that check here
1292 // to avoid re-checking cube-completeness for every face at level 0.
Jamie Madill07edd442013-07-19 16:36:58 -04001293 if (level == 0)
1294 {
1295 return true;
1296 }
1297
Jamie Madilld3d2a342013-10-07 10:46:35 -04001298 // Check that non-zero levels are consistent with the base level.
Jamie Madill2db197c2013-10-24 17:49:35 -04001299 const rx::Image *faceLevelImage = mImageArray[faceIndex][level];
Jamie Madill07edd442013-07-19 16:36:58 -04001300
Jamie Madilld3d2a342013-10-07 10:46:35 -04001301 if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat())
Jamie Madill07edd442013-07-19 16:36:58 -04001302 {
1303 return false;
1304 }
1305
Jamie Madilld3d2a342013-10-07 10:46:35 -04001306 if (faceLevelImage->getWidth() != std::max(1, baseSize >> level))
Jamie Madill07edd442013-07-19 16:36:58 -04001307 {
1308 return false;
1309 }
1310
1311 return true;
1312}
1313
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001314bool TextureCubeMap::isCompressed(GLenum target, GLint level) const
1315{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001316 return IsFormatCompressed(getInternalFormat(target, level), mRenderer->getCurrentClientVersion());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001317}
1318
Geoff Lang8040f572013-07-25 16:49:54 -04001319bool TextureCubeMap::isDepth(GLenum target, GLint level) const
1320{
1321 return GetDepthBits(getInternalFormat(target, level), mRenderer->getCurrentClientVersion()) > 0;
1322}
1323
Jamie Madill73b5d062013-10-24 17:49:38 -04001324void TextureCubeMap::initializeStorage(bool renderTarget)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001325{
Jamie Madill3c0989c2013-10-24 17:49:39 -04001326 // Only initialize the first time this texture is used as a render target or shader resource
1327 if (mTexStorage)
1328 {
1329 return;
1330 }
1331
1332 // do not attempt to create storage for nonexistant data
1333 if (!isFaceLevelComplete(0, 0))
1334 {
1335 return;
1336 }
1337
1338 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
1339
1340 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
1341 ASSERT(mTexStorage);
1342
1343 // flush image data to the storage
1344 updateStorage();
1345}
1346
1347rx::TextureStorageInterfaceCube *TextureCubeMap::createCompleteStorage(bool renderTarget) const
1348{
Jamie Madilld3d2a342013-10-07 10:46:35 -04001349 GLsizei size = getBaseLevelWidth();
daniel@transgaming.come6a09842012-09-17 21:28:55 +00001350
Jamie Madill3c0989c2013-10-24 17:49:39 -04001351 ASSERT(size > 0);
daniel@transgaming.come6a09842012-09-17 21:28:55 +00001352
Jamie Madill3c0989c2013-10-24 17:49:39 -04001353 // use existing storage level count, when previously specified by TexStorage*D
Nicolas Capensbf712d02014-03-31 14:23:35 -04001354 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(size, size, 1));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001355
Nicolas Capensbf712d02014-03-31 14:23:35 -04001356 return new rx::TextureStorageInterfaceCube(mRenderer, getBaseLevelInternalFormat(), renderTarget, size, levels);
Jamie Madill3c0989c2013-10-24 17:49:39 -04001357}
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001358
Jamie Madill3c0989c2013-10-24 17:49:39 -04001359void TextureCubeMap::setCompleteTexStorage(rx::TextureStorageInterfaceCube *newCompleteTexStorage)
1360{
1361 SafeDelete(mTexStorage);
1362 mTexStorage = newCompleteTexStorage;
1363
1364 if (mTexStorage && mTexStorage->isManaged())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001365 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001366 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001367 {
Nicolas Capensbf712d02014-03-31 14:23:35 -04001368 for (int level = 0; level < mTexStorage->getLevelCount(); level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001369 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001370 mImageArray[faceIndex][level]->setManagedSurface(mTexStorage, faceIndex, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001371 }
1372 }
1373 }
1374
1375 mDirtyImages = true;
1376}
1377
Jamie Madill169d1112013-10-24 17:49:37 -04001378void TextureCubeMap::updateStorage()
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001379{
1380 for (int face = 0; face < 6; face++)
1381 {
Jamie Madill4cfff5f2013-10-24 17:49:46 -04001382 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001383 {
Jamie Madilld9b9a502013-10-10 17:46:13 -04001384 if (isFaceLevelComplete(face, level))
1385 {
Jamie Madill169d1112013-10-24 17:49:37 -04001386 updateStorageFaceLevel(face, level);
Jamie Madilld9b9a502013-10-10 17:46:13 -04001387 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001388 }
1389 }
1390}
1391
Jamie Madill169d1112013-10-24 17:49:37 -04001392void TextureCubeMap::updateStorageFaceLevel(int faceIndex, int level)
Jamie Madill07edd442013-07-19 16:36:58 -04001393{
Jamie Madill2db197c2013-10-24 17:49:35 -04001394 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1395 rx::Image *image = mImageArray[faceIndex][level];
Jamie Madill07edd442013-07-19 16:36:58 -04001396
1397 if (image->isDirty())
1398 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001399 commitRect(faceIndex, level, 0, 0, image->getWidth(), image->getHeight());
Jamie Madill07edd442013-07-19 16:36:58 -04001400 }
1401}
1402
Jamie Madille83d1a92013-10-24 17:49:33 -04001403bool TextureCubeMap::ensureRenderTarget()
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001404{
Jamie Madill3c0989c2013-10-24 17:49:39 -04001405 initializeStorage(true);
1406
1407 if (getBaseLevelWidth() > 0)
Jamie Madille83d1a92013-10-24 17:49:33 -04001408 {
Jamie Madill3c0989c2013-10-24 17:49:39 -04001409 ASSERT(mTexStorage);
1410 if (!mTexStorage->isRenderTarget())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001411 {
Jamie Madill3c0989c2013-10-24 17:49:39 -04001412 rx::TextureStorageInterfaceCube *newRenderTargetStorage = createCompleteStorage(true);
1413
1414 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001415 {
Jamie Madill3c0989c2013-10-24 17:49:39 -04001416 delete newRenderTargetStorage;
Jamie Madille83d1a92013-10-24 17:49:33 -04001417 return gl::error(GL_OUT_OF_MEMORY, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001418 }
Jamie Madill3c0989c2013-10-24 17:49:39 -04001419
1420 setCompleteTexStorage(newRenderTargetStorage);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001421 }
1422 }
1423
Jamie Madille83d1a92013-10-24 17:49:33 -04001424 return (mTexStorage && mTexStorage->isRenderTarget());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001425}
1426
Geoff Lang005df412013-10-16 14:12:50 -04001427void 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 +00001428{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001429 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Geoff Lang005df412013-10-16 14:12:50 -04001430 GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
1431 : GetSizedInternalFormat(format, type, clientVersion);
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001432
1433 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001434
Jamie Madill88f18f42013-09-18 14:36:19 -04001435 Texture::setImage(unpack, type, pixels, mImageArray[faceIndex][level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001436}
1437
Jamie Madill2db197c2013-10-24 17:49:35 -04001438int TextureCubeMap::targetToIndex(GLenum target)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001439{
1440 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
1441 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
1442 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
1443 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
1444 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
1445
Jamie Madill2db197c2013-10-24 17:49:35 -04001446 return target - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001447}
1448
Jamie Madill2db197c2013-10-24 17:49:35 -04001449void TextureCubeMap::redefineImage(int faceIndex, GLint level, GLenum internalformat, GLsizei width, GLsizei height)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001450{
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001451 // If there currently is a corresponding storage texture image, it has these parameters
Jamie Madilld3d2a342013-10-07 10:46:35 -04001452 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1453 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
Geoff Lang005df412013-10-16 14:12:50 -04001454 const GLenum storageFormat = getBaseLevelInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001455
Jamie Madill2db197c2013-10-24 17:49:35 -04001456 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, width, height, 1, false);
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001457
1458 if (mTexStorage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001459 {
Nicolas Capensbf712d02014-03-31 14:23:35 -04001460 const int storageLevels = mTexStorage->getLevelCount();
1461
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001462 if ((level >= storageLevels && storageLevels != 0) ||
1463 width != storageWidth ||
1464 height != storageHeight ||
1465 internalformat != storageFormat) // Discard mismatched storage
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001466 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001467 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001468 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001469 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001470 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001471 mImageArray[faceIndex][level]->markDirty();
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001472 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001473 }
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001474
1475 delete mTexStorage;
1476 mTexStorage = NULL;
1477
1478 mDirtyImages = true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001479 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001480 }
1481}
1482
1483void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1484{
Jamie Madill2db197c2013-10-24 17:49:35 -04001485 int faceIndex = targetToIndex(target);
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001486 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Geoff Lang005df412013-10-16 14:12:50 -04001487 GLenum sizedInternalFormat = IsSizedInternalFormat(format, clientVersion) ? format
1488 : GetSizedInternalFormat(format, GL_UNSIGNED_BYTE, clientVersion);
Jamie Madill2db197c2013-10-24 17:49:35 -04001489 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001490
Jamie Madill2db197c2013-10-24 17:49:35 -04001491 if (!mImageArray[faceIndex][level]->isRenderableFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001492 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001493 mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001494 mDirtyImages = true;
1495 }
1496 else
1497 {
Jamie Madille83d1a92013-10-24 17:49:33 -04001498 ensureRenderTarget();
Jamie Madill2db197c2013-10-24 17:49:35 -04001499 mImageArray[faceIndex][level]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001500
1501 ASSERT(width == height);
1502
Jamie Madill07bb8cf2013-10-24 17:49:44 -04001503 if (width > 0 && isValidFaceLevel(faceIndex, level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001504 {
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +00001505 gl::Rectangle sourceRect;
1506 sourceRect.x = x;
1507 sourceRect.width = width;
1508 sourceRect.y = y;
1509 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001510
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +00001511 mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001512 }
1513 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001514}
1515
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001516void 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 +00001517{
Jamie Madill2db197c2013-10-24 17:49:35 -04001518 int faceIndex = targetToIndex(target);
1519
1520 GLsizei size = mImageArray[faceIndex][level]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001521
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001522 if (xoffset + width > size || yoffset + height > size || zoffset != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001523 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +00001524 return gl::error(GL_INVALID_VALUE);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001525 }
1526
Jamie Madilld3d2a342013-10-07 10:46:35 -04001527 // We can only make our texture storage to a render target if the level we're copying *to* is complete
1528 // and the base level is cube-complete. The base level must be cube complete (common case) because we cannot
1529 // rely on the "getBaseLevel*" methods reliably otherwise.
Jamie Madill2db197c2013-10-24 17:49:35 -04001530 bool canCreateRenderTarget = isFaceLevelComplete(faceIndex, level) && isCubeComplete();
Jamie Madill07edd442013-07-19 16:36:58 -04001531
Jamie Madill2db197c2013-10-24 17:49:35 -04001532 if (!mImageArray[faceIndex][level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001533 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001534 mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001535 mDirtyImages = true;
1536 }
1537 else
1538 {
Jamie Madille83d1a92013-10-24 17:49:33 -04001539 ensureRenderTarget();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001540
Jamie Madill07bb8cf2013-10-24 17:49:44 -04001541 if (isValidFaceLevel(faceIndex, level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001542 {
Jamie Madill169d1112013-10-24 17:49:37 -04001543 updateStorageFaceLevel(faceIndex, level);
Jamie Madill07edd442013-07-19 16:36:58 -04001544
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001545 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1546
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +00001547 gl::Rectangle sourceRect;
1548 sourceRect.x = x;
1549 sourceRect.width = width;
1550 sourceRect.y = y;
1551 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001552
Jamie Madilld3d2a342013-10-07 10:46:35 -04001553 mRenderer->copyImage(source, sourceRect, gl::GetFormat(getBaseLevelInternalFormat(), clientVersion),
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +00001554 xoffset, yoffset, mTexStorage, target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001555 }
1556 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001557}
1558
1559void TextureCubeMap::storage(GLsizei levels, GLenum internalformat, GLsizei size)
1560{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001561 for (int level = 0; level < levels; level++)
1562 {
Geoff Langd3110192013-09-24 11:52:47 -04001563 GLsizei mipSize = std::max(1, size >> level);
Jamie Madill2db197c2013-10-24 17:49:35 -04001564 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001565 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001566 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, mipSize, mipSize, 1, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001567 }
1568 }
1569
1570 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1571 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001572 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001573 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001574 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, GL_NONE, 0, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001575 }
1576 }
1577
Jamie Madill3c0989c2013-10-24 17:49:39 -04001578 mImmutable = true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001579
Nicolas Capensbf712d02014-03-31 14:23:35 -04001580 setCompleteTexStorage(new rx::TextureStorageInterfaceCube(mRenderer, internalformat, IsRenderTargetUsage(mUsage), size, levels));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001581}
1582
1583void TextureCubeMap::generateMipmaps()
1584{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001585 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Geoff Lang98705b72014-03-31 16:00:03 -04001586 int levelCount = mipLevels();
Jamie Madill2db197c2013-10-24 17:49:35 -04001587 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001588 {
Geoff Lang98705b72014-03-31 16:00:03 -04001589 for (int level = 1; level < levelCount; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001590 {
Jamie Madill22f843a2013-10-24 17:49:36 -04001591 int faceLevelSize = (std::max(mImageArray[faceIndex][0]->getWidth() >> level, 1));
1592 redefineImage(faceIndex, level, mImageArray[faceIndex][0]->getInternalFormat(), faceLevelSize, faceLevelSize);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001593 }
1594 }
1595
1596 if (mTexStorage && mTexStorage->isRenderTarget())
1597 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001598 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001599 {
Geoff Lang98705b72014-03-31 16:00:03 -04001600 for (int level = 1; level < levelCount; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001601 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001602 mTexStorage->generateMipmap(faceIndex, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001603
Jamie Madill2db197c2013-10-24 17:49:35 -04001604 mImageArray[faceIndex][level]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001605 }
1606 }
1607 }
1608 else
1609 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001610 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001611 {
Geoff Lang98705b72014-03-31 16:00:03 -04001612 for (int level = 1; level < levelCount; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001613 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001614 mRenderer->generateMipmap(mImageArray[faceIndex][level], mImageArray[faceIndex][level - 1]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001615 }
1616 }
1617 }
1618}
1619
Jamie Madilld3d2a342013-10-07 10:46:35 -04001620const rx::Image *TextureCubeMap::getBaseLevelImage() const
1621{
1622 // Note: if we are not cube-complete, there is no single base level image that can describe all
1623 // cube faces, so this method is only well-defined for a cube-complete base level.
1624 return mImageArray[0][0];
1625}
1626
Jamie Madill2ebab852013-10-24 17:49:42 -04001627rx::TextureStorageInterface *TextureCubeMap::getBaseLevelStorage()
1628{
1629 return mTexStorage;
1630}
1631
Geoff Lang8040f572013-07-25 16:49:54 -04001632Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target, GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001633{
1634 if (!IsCubemapTextureTarget(target))
1635 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +00001636 return gl::error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001637 }
1638
Jamie Madill2db197c2013-10-24 17:49:35 -04001639 int faceIndex = targetToIndex(target);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001640
Jamie Madill2db197c2013-10-24 17:49:35 -04001641 Renderbuffer *renderBuffer = mRenderbufferProxies.get(level, faceIndex);
Geoff Lang8040f572013-07-25 16:49:54 -04001642 if (!renderBuffer)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001643 {
Geoff Lang8040f572013-07-25 16:49:54 -04001644 renderBuffer = new Renderbuffer(mRenderer, id(), new RenderbufferTextureCubeMap(this, target, level));
Jamie Madill2db197c2013-10-24 17:49:35 -04001645 mRenderbufferProxies.add(level, faceIndex, renderBuffer);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001646 }
1647
Geoff Lang8040f572013-07-25 16:49:54 -04001648 return renderBuffer;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001649}
1650
Jamie Madill2db197c2013-10-24 17:49:35 -04001651unsigned int TextureCubeMap::getRenderTargetSerial(GLenum target, GLint level)
Geoff Lang8040f572013-07-25 16:49:54 -04001652{
Jamie Madill2db197c2013-10-24 17:49:35 -04001653 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(target, level) : 0);
Geoff Lang8040f572013-07-25 16:49:54 -04001654}
1655
1656rx::RenderTarget *TextureCubeMap::getRenderTarget(GLenum target, GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001657{
1658 ASSERT(IsCubemapTextureTarget(target));
1659
1660 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04001661 if (!ensureRenderTarget())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001662 {
1663 return NULL;
1664 }
1665
Jamie Madill169d1112013-10-24 17:49:37 -04001666 updateStorageFaceLevel(targetToIndex(target), level);
Geoff Lang8040f572013-07-25 16:49:54 -04001667
1668 // ensure this is NOT a depth texture
1669 if (isDepth(target, level))
1670 {
1671 return NULL;
1672 }
1673
1674 return mTexStorage->getRenderTarget(target, level);
1675}
1676
1677rx::RenderTarget *TextureCubeMap::getDepthStencil(GLenum target, GLint level)
1678{
1679 ASSERT(IsCubemapTextureTarget(target));
1680
1681 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04001682 if (!ensureRenderTarget())
Geoff Lang8040f572013-07-25 16:49:54 -04001683 {
1684 return NULL;
1685 }
1686
Jamie Madill169d1112013-10-24 17:49:37 -04001687 updateStorageFaceLevel(targetToIndex(target), level);
Geoff Lang8040f572013-07-25 16:49:54 -04001688
1689 // ensure this is a depth texture
1690 if (!isDepth(target, level))
1691 {
1692 return NULL;
1693 }
1694
1695 return mTexStorage->getRenderTarget(target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001696}
1697
Jamie Madill07bb8cf2013-10-24 17:49:44 -04001698bool TextureCubeMap::isValidFaceLevel(int faceIndex, int level) const
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +00001699{
Nicolas Capensbf712d02014-03-31 14:23:35 -04001700 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +00001701}
1702
Geoff Lang4907f2c2013-07-25 12:53:57 -04001703Texture3D::Texture3D(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_3D)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001704{
1705 mTexStorage = NULL;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001706
1707 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1708 {
1709 mImageArray[i] = renderer->createImage();
1710 }
1711}
1712
1713Texture3D::~Texture3D()
1714{
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001715 delete mTexStorage;
1716 mTexStorage = NULL;
1717
1718 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1719 {
1720 delete mImageArray[i];
1721 }
1722}
1723
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001724GLsizei Texture3D::getWidth(GLint level) const
1725{
1726 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getWidth() : 0;
1727}
1728
1729GLsizei Texture3D::getHeight(GLint level) const
1730{
1731 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getHeight() : 0;
1732}
1733
1734GLsizei Texture3D::getDepth(GLint level) const
1735{
1736 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getDepth() : 0;
1737}
1738
1739GLenum Texture3D::getInternalFormat(GLint level) const
1740{
1741 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getInternalFormat() : GL_NONE;
1742}
1743
1744GLenum Texture3D::getActualFormat(GLint level) const
1745{
Geoff Langcbf727a2014-02-10 12:50:45 -05001746 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getActualFormat() : GL_NONE;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001747}
1748
1749bool Texture3D::isCompressed(GLint level) const
1750{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001751 return IsFormatCompressed(getInternalFormat(level), mRenderer->getCurrentClientVersion());
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001752}
1753
1754bool Texture3D::isDepth(GLint level) const
1755{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001756 return GetDepthBits(getInternalFormat(level), mRenderer->getCurrentClientVersion()) > 0;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001757}
1758
Geoff Lang005df412013-10-16 14:12:50 -04001759void 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 +00001760{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001761 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Geoff Lang005df412013-10-16 14:12:50 -04001762 GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
1763 : GetSizedInternalFormat(format, type, clientVersion);
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001764 redefineImage(level, sizedInternalFormat, width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001765
Jamie Madilla2d4e552013-10-10 15:12:01 -04001766 bool fastUnpacked = false;
1767
1768 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1769 if (isFastUnpackable(unpack, sizedInternalFormat))
1770 {
1771 // Will try to create RT storage if it does not exist
1772 rx::RenderTarget *destRenderTarget = getRenderTarget(level);
1773 Box destArea(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1774
1775 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget))
1776 {
1777 // Ensure we don't overwrite our newly initialized data
1778 mImageArray[level]->markClean();
1779
1780 fastUnpacked = true;
1781 }
1782 }
1783
1784 if (!fastUnpacked)
1785 {
1786 Texture::setImage(unpack, type, pixels, mImageArray[level]);
1787 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001788}
1789
1790void Texture3D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
1791{
1792 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1793 redefineImage(level, format, width, height, depth);
1794
1795 Texture::setCompressedImage(imageSize, pixels, mImageArray[level]);
1796}
1797
Jamie Madill88f18f42013-09-18 14:36:19 -04001798void 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 +00001799{
Jamie Madillba4f10a2013-10-10 15:12:20 -04001800 bool fastUnpacked = false;
1801
1802 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1803 if (isFastUnpackable(unpack, getInternalFormat(level)))
1804 {
1805 rx::RenderTarget *destRenderTarget = getRenderTarget(level);
1806 Box destArea(xoffset, yoffset, zoffset, width, height, depth);
1807
1808 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, destRenderTarget))
1809 {
1810 // Ensure we don't overwrite our newly initialized data
1811 mImageArray[level]->markClean();
1812
1813 fastUnpacked = true;
1814 }
1815 }
1816
1817 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 +00001818 {
1819 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1820 }
1821}
1822
1823void Texture3D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
1824{
1825 if (Texture::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth, format, imageSize, pixels, mImageArray[level]))
1826 {
1827 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1828 }
1829}
1830
1831void Texture3D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
1832{
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001833 for (int level = 0; level < levels; level++)
1834 {
Jamie Madille664e202013-10-24 17:49:40 -04001835 GLsizei levelWidth = std::max(1, width >> level);
1836 GLsizei levelHeight = std::max(1, height >> level);
1837 GLsizei levelDepth = std::max(1, depth >> level);
1838 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, levelWidth, levelHeight, levelDepth, true);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001839 }
1840
1841 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1842 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001843 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, GL_NONE, 0, 0, 0, true);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001844 }
1845
Jamie Madille664e202013-10-24 17:49:40 -04001846 mImmutable = true;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001847
Nicolas Capensbf712d02014-03-31 14:23:35 -04001848 setCompleteTexStorage(new rx::TextureStorageInterface3D(mRenderer, internalformat, IsRenderTargetUsage(mUsage), width, height, depth, levels));
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001849}
1850
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001851void Texture3D::generateMipmaps()
1852{
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001853 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Geoff Lang98705b72014-03-31 16:00:03 -04001854 int levelCount = mipLevels();
1855 for (int level = 1; level < levelCount; level++)
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001856 {
Jamie Madill22f843a2013-10-24 17:49:36 -04001857 redefineImage(level, getBaseLevelInternalFormat(),
1858 std::max(getBaseLevelWidth() >> level, 1),
1859 std::max(getBaseLevelHeight() >> level, 1),
1860 std::max(getBaseLevelDepth() >> level, 1));
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001861 }
1862
1863 if (mTexStorage && mTexStorage->isRenderTarget())
1864 {
Geoff Lang98705b72014-03-31 16:00:03 -04001865 for (int level = 1; level < levelCount; level++)
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001866 {
Jamie Madill22f843a2013-10-24 17:49:36 -04001867 mTexStorage->generateMipmap(level);
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001868
Jamie Madill22f843a2013-10-24 17:49:36 -04001869 mImageArray[level]->markClean();
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001870 }
1871 }
1872 else
1873 {
Geoff Lang98705b72014-03-31 16:00:03 -04001874 for (int level = 1; level < levelCount; level++)
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001875 {
Jamie Madill22f843a2013-10-24 17:49:36 -04001876 mRenderer->generateMipmap(mImageArray[level], mImageArray[level - 1]);
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001877 }
1878 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001879}
1880
Jamie Madilld3d2a342013-10-07 10:46:35 -04001881const rx::Image *Texture3D::getBaseLevelImage() const
1882{
1883 return mImageArray[0];
1884}
1885
Jamie Madill2ebab852013-10-24 17:49:42 -04001886rx::TextureStorageInterface *Texture3D::getBaseLevelStorage()
1887{
1888 return mTexStorage;
1889}
1890
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001891void Texture3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1892{
1893 if (xoffset + width > mImageArray[level]->getWidth() || yoffset + height > mImageArray[level]->getHeight() || zoffset >= mImageArray[level]->getDepth())
1894 {
1895 return gl::error(GL_INVALID_VALUE);
1896 }
1897
Jamie Madill07edd442013-07-19 16:36:58 -04001898 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
1899 // the current level we're copying to is defined (with appropriate format, width & height)
1900 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
1901
1902 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001903 {
1904 mImageArray[level]->copy(xoffset, yoffset, zoffset, x, y, width, height, source);
1905 mDirtyImages = true;
1906 }
1907 else
1908 {
Jamie Madille83d1a92013-10-24 17:49:33 -04001909 ensureRenderTarget();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001910
Jamie Madill07bb8cf2013-10-24 17:49:44 -04001911 if (isValidLevel(level))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001912 {
Jamie Madill169d1112013-10-24 17:49:37 -04001913 updateStorageLevel(level);
Jamie Madill07edd442013-07-19 16:36:58 -04001914
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001915 gl::Rectangle sourceRect;
1916 sourceRect.x = x;
1917 sourceRect.width = width;
1918 sourceRect.y = y;
1919 sourceRect.height = height;
1920
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001921 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1922
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001923 mRenderer->copyImage(source, sourceRect,
Jamie Madilld3d2a342013-10-07 10:46:35 -04001924 gl::GetFormat(getBaseLevelInternalFormat(), clientVersion),
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001925 xoffset, yoffset, zoffset, mTexStorage, level);
1926 }
1927 }
1928}
1929
Jamie Madillf8989902013-07-19 16:36:58 -04001930bool Texture3D::isSamplerComplete(const SamplerState &samplerState) const
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001931{
Jamie Madilld3d2a342013-10-07 10:46:35 -04001932 GLsizei width = getBaseLevelWidth();
1933 GLsizei height = getBaseLevelHeight();
1934 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001935
1936 if (width <= 0 || height <= 0 || depth <= 0)
1937 {
1938 return false;
1939 }
1940
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001941 if (!IsTextureFilteringSupported(getInternalFormat(0), mRenderer))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001942 {
Jamie Madillf8989902013-07-19 16:36:58 -04001943 if (samplerState.magFilter != GL_NEAREST ||
1944 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001945 {
1946 return false;
1947 }
1948 }
1949
Jamie Madillf8989902013-07-19 16:36:58 -04001950 if (IsMipmapFiltered(samplerState) && !isMipmapComplete())
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001951 {
1952 return false;
1953 }
1954
1955 return true;
1956}
1957
1958bool Texture3D::isMipmapComplete() const
1959{
Geoff Lang98705b72014-03-31 16:00:03 -04001960 int levelCount = mipLevels();
Jamie Madill07edd442013-07-19 16:36:58 -04001961
Geoff Lang98705b72014-03-31 16:00:03 -04001962 for (int level = 0; level < levelCount; level++)
Jamie Madill07edd442013-07-19 16:36:58 -04001963 {
1964 if (!isLevelComplete(level))
1965 {
1966 return false;
1967 }
1968 }
1969
1970 return true;
1971}
1972
1973bool Texture3D::isLevelComplete(int level) const
1974{
1975 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1976
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001977 if (isImmutable())
1978 {
1979 return true;
1980 }
1981
Jamie Madilld3d2a342013-10-07 10:46:35 -04001982 GLsizei width = getBaseLevelWidth();
1983 GLsizei height = getBaseLevelHeight();
1984 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001985
1986 if (width <= 0 || height <= 0 || depth <= 0)
1987 {
1988 return false;
1989 }
1990
Jamie Madill07edd442013-07-19 16:36:58 -04001991 if (level == 0)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001992 {
Jamie Madill07edd442013-07-19 16:36:58 -04001993 return true;
1994 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001995
Jamie Madill07edd442013-07-19 16:36:58 -04001996 rx::Image *levelImage = mImageArray[level];
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001997
Jamie Madilld3d2a342013-10-07 10:46:35 -04001998 if (levelImage->getInternalFormat() != getBaseLevelInternalFormat())
Jamie Madill07edd442013-07-19 16:36:58 -04001999 {
2000 return false;
2001 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002002
Jamie Madill07edd442013-07-19 16:36:58 -04002003 if (levelImage->getWidth() != std::max(1, width >> level))
2004 {
2005 return false;
2006 }
2007
2008 if (levelImage->getHeight() != std::max(1, height >> level))
2009 {
2010 return false;
2011 }
2012
2013 if (levelImage->getDepth() != std::max(1, depth >> level))
2014 {
2015 return false;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002016 }
2017
2018 return true;
2019}
2020
Geoff Lang8040f572013-07-25 16:49:54 -04002021Renderbuffer *Texture3D::getRenderbuffer(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002022{
Geoff Lang8040f572013-07-25 16:49:54 -04002023 Renderbuffer *renderBuffer = mRenderbufferProxies.get(level, layer);
2024 if (!renderBuffer)
2025 {
Geoff Langd5d8e392013-07-25 16:53:03 -04002026 renderBuffer = new Renderbuffer(mRenderer, id(), new RenderbufferTexture3DLayer(this, level, layer));
2027 mRenderbufferProxies.add(level, 0, renderBuffer);
Geoff Lang8040f572013-07-25 16:49:54 -04002028 }
2029
2030 return renderBuffer;
2031}
2032
2033unsigned int Texture3D::getRenderTargetSerial(GLint level, GLint layer)
2034{
Jamie Madille83d1a92013-10-24 17:49:33 -04002035 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(level, layer) : 0);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002036}
2037
Jamie Madill07bb8cf2013-10-24 17:49:44 -04002038bool Texture3D::isValidLevel(int level) const
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002039{
Nicolas Capensbf712d02014-03-31 14:23:35 -04002040 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002041}
2042
Jamie Madill73b5d062013-10-24 17:49:38 -04002043void Texture3D::initializeStorage(bool renderTarget)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002044{
Jamie Madille664e202013-10-24 17:49:40 -04002045 // Only initialize the first time this texture is used as a render target or shader resource
2046 if (mTexStorage)
2047 {
2048 return;
2049 }
2050
2051 // do not attempt to create storage for nonexistant data
2052 if (!isLevelComplete(0))
2053 {
2054 return;
2055 }
2056
2057 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
2058
2059 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
2060 ASSERT(mTexStorage);
2061
2062 // flush image data to the storage
2063 updateStorage();
2064}
2065
2066rx::TextureStorageInterface3D *Texture3D::createCompleteStorage(bool renderTarget) const
2067{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002068 GLsizei width = getBaseLevelWidth();
2069 GLsizei height = getBaseLevelHeight();
2070 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002071
Jamie Madille664e202013-10-24 17:49:40 -04002072 ASSERT(width > 0 && height > 0 && depth > 0);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002073
Jamie Madille664e202013-10-24 17:49:40 -04002074 // use existing storage level count, when previously specified by TexStorage*D
Nicolas Capensbf712d02014-03-31 14:23:35 -04002075 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, depth));
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002076
Nicolas Capensbf712d02014-03-31 14:23:35 -04002077 return new rx::TextureStorageInterface3D(mRenderer, getBaseLevelInternalFormat(), renderTarget, width, height, depth, levels);
Jamie Madille664e202013-10-24 17:49:40 -04002078}
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002079
Jamie Madille664e202013-10-24 17:49:40 -04002080void Texture3D::setCompleteTexStorage(rx::TextureStorageInterface3D *newCompleteTexStorage)
2081{
2082 SafeDelete(mTexStorage);
2083 mTexStorage = newCompleteTexStorage;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002084 mDirtyImages = true;
Jamie Madille664e202013-10-24 17:49:40 -04002085
2086 // We do not support managed 3D storage, as that is D3D9/ES2-only
2087 ASSERT(!mTexStorage->isManaged());
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002088}
2089
Jamie Madill169d1112013-10-24 17:49:37 -04002090void Texture3D::updateStorage()
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002091{
Jamie Madill4cfff5f2013-10-24 17:49:46 -04002092 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002093 {
Jamie Madilld9b9a502013-10-10 17:46:13 -04002094 if (isLevelComplete(level))
2095 {
Jamie Madill169d1112013-10-24 17:49:37 -04002096 updateStorageLevel(level);
Jamie Madilld9b9a502013-10-10 17:46:13 -04002097 }
Jamie Madill07edd442013-07-19 16:36:58 -04002098 }
2099}
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002100
Jamie Madill169d1112013-10-24 17:49:37 -04002101void Texture3D::updateStorageLevel(int level)
Jamie Madill07edd442013-07-19 16:36:58 -04002102{
2103 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
Jamie Madillaee7ad82013-10-10 16:07:32 -04002104 ASSERT(isLevelComplete(level));
Jamie Madill07edd442013-07-19 16:36:58 -04002105
Jamie Madillaee7ad82013-10-10 16:07:32 -04002106 if (mImageArray[level]->isDirty())
Jamie Madill07edd442013-07-19 16:36:58 -04002107 {
Jamie Madillaee7ad82013-10-10 16:07:32 -04002108 commitRect(level, 0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002109 }
2110}
2111
Jamie Madille83d1a92013-10-24 17:49:33 -04002112bool Texture3D::ensureRenderTarget()
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002113{
Jamie Madille664e202013-10-24 17:49:40 -04002114 initializeStorage(true);
2115
2116 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0 && getBaseLevelDepth() > 0)
Jamie Madille83d1a92013-10-24 17:49:33 -04002117 {
Jamie Madille664e202013-10-24 17:49:40 -04002118 ASSERT(mTexStorage);
2119 if (!mTexStorage->isRenderTarget())
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002120 {
Jamie Madille664e202013-10-24 17:49:40 -04002121 rx::TextureStorageInterface3D *newRenderTargetStorage = createCompleteStorage(true);
2122
2123 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002124 {
Jamie Madille664e202013-10-24 17:49:40 -04002125 delete newRenderTargetStorage;
Jamie Madille83d1a92013-10-24 17:49:33 -04002126 return gl::error(GL_OUT_OF_MEMORY, false);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002127 }
Jamie Madille664e202013-10-24 17:49:40 -04002128
2129 setCompleteTexStorage(newRenderTargetStorage);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002130 }
2131 }
2132
Jamie Madille83d1a92013-10-24 17:49:33 -04002133 return (mTexStorage && mTexStorage->isRenderTarget());
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002134}
2135
Jamie Madilla2d4e552013-10-10 15:12:01 -04002136rx::RenderTarget *Texture3D::getRenderTarget(GLint level)
2137{
2138 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04002139 if (!ensureRenderTarget())
Jamie Madilla2d4e552013-10-10 15:12:01 -04002140 {
2141 return NULL;
2142 }
2143
Jamie Madill169d1112013-10-24 17:49:37 -04002144 updateStorageLevel(level);
Jamie Madilla2d4e552013-10-10 15:12:01 -04002145
2146 // ensure this is NOT a depth texture
2147 if (isDepth(level))
2148 {
2149 return NULL;
2150 }
2151
2152 return mTexStorage->getRenderTarget(level);
2153}
2154
Geoff Lang8040f572013-07-25 16:49:54 -04002155rx::RenderTarget *Texture3D::getRenderTarget(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002156{
Geoff Lang8040f572013-07-25 16:49:54 -04002157 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04002158 if (!ensureRenderTarget())
Geoff Lang8040f572013-07-25 16:49:54 -04002159 {
2160 return NULL;
2161 }
2162
Jamie Madill169d1112013-10-24 17:49:37 -04002163 updateStorage();
Geoff Lang8040f572013-07-25 16:49:54 -04002164
2165 // ensure this is NOT a depth texture
2166 if (isDepth(level))
2167 {
2168 return NULL;
2169 }
2170
2171 return mTexStorage->getRenderTarget(level, layer);
2172}
2173
2174rx::RenderTarget *Texture3D::getDepthStencil(GLint level, GLint layer)
2175{
2176 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04002177 if (!ensureRenderTarget())
Geoff Lang8040f572013-07-25 16:49:54 -04002178 {
2179 return NULL;
2180 }
2181
Jamie Madill169d1112013-10-24 17:49:37 -04002182 updateStorageLevel(level);
Geoff Lang8040f572013-07-25 16:49:54 -04002183
2184 // ensure this is a depth texture
2185 if (!isDepth(level))
2186 {
2187 return NULL;
2188 }
2189
2190 return mTexStorage->getRenderTarget(level, layer);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002191}
2192
Geoff Lang005df412013-10-16 14:12:50 -04002193void Texture3D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002194{
2195 // If there currently is a corresponding storage texture image, it has these parameters
Jamie Madilld3d2a342013-10-07 10:46:35 -04002196 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2197 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
2198 const int storageDepth = std::max(1, getBaseLevelDepth() >> level);
Geoff Lang005df412013-10-16 14:12:50 -04002199 const GLenum storageFormat = getBaseLevelInternalFormat();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002200
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00002201 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, false);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002202
2203 if (mTexStorage)
2204 {
Nicolas Capensbf712d02014-03-31 14:23:35 -04002205 const int storageLevels = mTexStorage->getLevelCount();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002206
2207 if ((level >= storageLevels && storageLevels != 0) ||
2208 width != storageWidth ||
2209 height != storageHeight ||
2210 depth != storageDepth ||
2211 internalformat != storageFormat) // Discard mismatched storage
2212 {
2213 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
2214 {
2215 mImageArray[i]->markDirty();
2216 }
2217
2218 delete mTexStorage;
2219 mTexStorage = NULL;
2220 mDirtyImages = true;
2221 }
2222 }
2223}
2224
2225void Texture3D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth)
2226{
Jamie Madill07bb8cf2013-10-24 17:49:44 -04002227 if (isValidLevel(level))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002228 {
2229 rx::Image *image = mImageArray[level];
Jamie Madill169d1112013-10-24 17:49:37 -04002230 if (image->copyToStorage(mTexStorage, level, xoffset, yoffset, zoffset, width, height, depth))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002231 {
2232 image->markClean();
2233 }
2234 }
2235}
2236
Geoff Lang4907f2c2013-07-25 12:53:57 -04002237Texture2DArray::Texture2DArray(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_2D_ARRAY)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002238{
2239 mTexStorage = NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002240
2241 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2242 {
2243 mLayerCounts[level] = 0;
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002244 mImageArray[level] = NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002245 }
2246}
2247
2248Texture2DArray::~Texture2DArray()
2249{
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002250 delete mTexStorage;
2251 mTexStorage = NULL;
Jamie Madill884a4622013-10-24 17:49:41 -04002252
2253 deleteImages();
2254}
2255
2256void Texture2DArray::deleteImages()
2257{
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002258 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2259 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002260 for (int layer = 0; layer < mLayerCounts[level]; ++layer)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002261 {
2262 delete mImageArray[level][layer];
2263 }
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002264 delete[] mImageArray[level];
Jamie Madill884a4622013-10-24 17:49:41 -04002265 mImageArray[level] = NULL;
2266 mLayerCounts[level] = 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002267 }
2268}
2269
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002270GLsizei Texture2DArray::getWidth(GLint level) const
2271{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002272 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 +00002273}
2274
2275GLsizei Texture2DArray::getHeight(GLint level) const
2276{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002277 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getHeight() : 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002278}
2279
Jamie Madillb8f8b892014-01-07 10:12:50 -05002280GLsizei Texture2DArray::getLayers(GLint level) const
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002281{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002282 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mLayerCounts[level] : 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002283}
2284
2285GLenum Texture2DArray::getInternalFormat(GLint level) const
2286{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002287 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 +00002288}
2289
2290GLenum Texture2DArray::getActualFormat(GLint level) const
2291{
Geoff Langcbf727a2014-02-10 12:50:45 -05002292 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 +00002293}
2294
2295bool Texture2DArray::isCompressed(GLint level) const
2296{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00002297 return IsFormatCompressed(getInternalFormat(level), mRenderer->getCurrentClientVersion());
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002298}
2299
2300bool Texture2DArray::isDepth(GLint level) const
2301{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00002302 return GetDepthBits(getInternalFormat(level), mRenderer->getCurrentClientVersion()) > 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002303}
2304
Geoff Lang005df412013-10-16 14:12:50 -04002305void 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 +00002306{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00002307 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Geoff Lang005df412013-10-16 14:12:50 -04002308 GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
2309 : GetSizedInternalFormat(format, type, clientVersion);
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00002310 redefineImage(level, sizedInternalFormat, width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002311
Jamie Madill88f18f42013-09-18 14:36:19 -04002312 GLsizei inputDepthPitch = gl::GetDepthPitch(sizedInternalFormat, type, clientVersion, width, height, unpack.alignment);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002313
2314 for (int i = 0; i < depth; i++)
2315 {
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002316 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
Jamie Madill88f18f42013-09-18 14:36:19 -04002317 Texture::setImage(unpack, type, layerPixels, mImageArray[level][i]);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002318 }
2319}
2320
2321void Texture2DArray::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
2322{
2323 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
2324 redefineImage(level, format, width, height, depth);
2325
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002326 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2327 GLsizei inputDepthPitch = gl::GetDepthPitch(format, GL_UNSIGNED_BYTE, clientVersion, width, height, 1);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002328
2329 for (int i = 0; i < depth; i++)
2330 {
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002331 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002332 Texture::setCompressedImage(imageSize, layerPixels, mImageArray[level][i]);
2333 }
2334}
2335
Jamie Madill88f18f42013-09-18 14:36:19 -04002336void 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 +00002337{
Geoff Lang005df412013-10-16 14:12:50 -04002338 GLenum internalformat = getInternalFormat(level);
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002339 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Jamie Madill88f18f42013-09-18 14:36:19 -04002340 GLsizei inputDepthPitch = gl::GetDepthPitch(internalformat, type, clientVersion, width, height, unpack.alignment);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002341
2342 for (int i = 0; i < depth; i++)
2343 {
2344 int layer = zoffset + i;
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002345 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002346
Jamie Madill88f18f42013-09-18 14:36:19 -04002347 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 +00002348 {
2349 commitRect(level, xoffset, yoffset, layer, width, height);
2350 }
2351 }
2352}
2353
2354void Texture2DArray::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
2355{
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002356 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2357 GLsizei inputDepthPitch = gl::GetDepthPitch(format, GL_UNSIGNED_BYTE, clientVersion, width, height, 1);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002358
2359 for (int i = 0; i < depth; i++)
2360 {
2361 int layer = zoffset + i;
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002362 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002363
2364 if (Texture::subImageCompressed(xoffset, yoffset, zoffset, width, height, 1, format, imageSize, layerPixels, mImageArray[level][layer]))
2365 {
2366 commitRect(level, xoffset, yoffset, layer, width, height);
2367 }
2368 }
2369}
2370
2371void Texture2DArray::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2372{
Jamie Madill884a4622013-10-24 17:49:41 -04002373 deleteImages();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002374
2375 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2376 {
Jamie Madill884a4622013-10-24 17:49:41 -04002377 GLsizei levelWidth = std::max(1, width >> level);
2378 GLsizei levelHeight = std::max(1, height >> level);
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002379
Jamie Madill884a4622013-10-24 17:49:41 -04002380 mLayerCounts[level] = (level < levels ? depth : 0);
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002381
Jamie Madill884a4622013-10-24 17:49:41 -04002382 if (mLayerCounts[level] > 0)
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002383 {
2384 // Create new images for this level
Jamie Madill884a4622013-10-24 17:49:41 -04002385 mImageArray[level] = new rx::Image*[mLayerCounts[level]];
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002386
2387 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002388 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002389 mImageArray[level][layer] = mRenderer->createImage();
2390 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, levelWidth,
2391 levelHeight, 1, true);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002392 }
2393 }
2394 }
2395
Jamie Madill884a4622013-10-24 17:49:41 -04002396 mImmutable = true;
Nicolas Capensbf712d02014-03-31 14:23:35 -04002397 setCompleteTexStorage(new rx::TextureStorageInterface2DArray(mRenderer, internalformat, IsRenderTargetUsage(mUsage), width, height, depth, levels));
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002398}
2399
2400void Texture2DArray::generateMipmaps()
2401{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002402 int baseWidth = getBaseLevelWidth();
2403 int baseHeight = getBaseLevelHeight();
2404 int baseDepth = getBaseLevelDepth();
2405 GLenum baseFormat = getBaseLevelInternalFormat();
2406
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00002407 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Geoff Lang98705b72014-03-31 16:00:03 -04002408 int levelCount = mipLevels();
2409 for (int level = 1; level < levelCount; level++)
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00002410 {
Jamie Madill22f843a2013-10-24 17:49:36 -04002411 redefineImage(level, baseFormat, std::max(baseWidth >> level, 1), std::max(baseHeight >> level, 1), baseDepth);
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00002412 }
2413
2414 if (mTexStorage && mTexStorage->isRenderTarget())
2415 {
Geoff Lang98705b72014-03-31 16:00:03 -04002416 for (int level = 1; level < levelCount; level++)
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00002417 {
2418 mTexStorage->generateMipmap(level);
2419
2420 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2421 {
2422 mImageArray[level][layer]->markClean();
2423 }
2424 }
2425 }
2426 else
2427 {
Geoff Lang98705b72014-03-31 16:00:03 -04002428 for (int level = 1; level < levelCount; level++)
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00002429 {
2430 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2431 {
2432 mRenderer->generateMipmap(mImageArray[level][layer], mImageArray[level - 1][layer]);
2433 }
2434 }
2435 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002436}
2437
Jamie Madilld3d2a342013-10-07 10:46:35 -04002438const rx::Image *Texture2DArray::getBaseLevelImage() const
2439{
Jamie Madill152ed092013-10-09 17:01:15 -04002440 return (mLayerCounts[0] > 0 ? mImageArray[0][0] : NULL);
Jamie Madilld3d2a342013-10-07 10:46:35 -04002441}
2442
Jamie Madill2ebab852013-10-24 17:49:42 -04002443rx::TextureStorageInterface *Texture2DArray::getBaseLevelStorage()
2444{
2445 return mTexStorage;
2446}
2447
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002448void Texture2DArray::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
2449{
Jamie Madillb8f8b892014-01-07 10:12:50 -05002450 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 +00002451 {
2452 return gl::error(GL_INVALID_VALUE);
2453 }
2454
Jamie Madill07edd442013-07-19 16:36:58 -04002455 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
2456 // the current level we're copying to is defined (with appropriate format, width & height)
2457 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
2458
2459 if (!mImageArray[level][0]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002460 {
2461 mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, x, y, width, height, source);
2462 mDirtyImages = true;
2463 }
2464 else
2465 {
Jamie Madille83d1a92013-10-24 17:49:33 -04002466 ensureRenderTarget();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002467
Jamie Madill07bb8cf2013-10-24 17:49:44 -04002468 if (isValidLevel(level))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002469 {
Jamie Madill169d1112013-10-24 17:49:37 -04002470 updateStorageLevel(level);
Jamie Madill07edd442013-07-19 16:36:58 -04002471
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002472 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2473
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002474 gl::Rectangle sourceRect;
2475 sourceRect.x = x;
2476 sourceRect.width = width;
2477 sourceRect.y = y;
2478 sourceRect.height = height;
2479
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002480 mRenderer->copyImage(source, sourceRect, gl::GetFormat(getInternalFormat(0), clientVersion),
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002481 xoffset, yoffset, zoffset, mTexStorage, level);
2482 }
2483 }
2484}
2485
Jamie Madillf8989902013-07-19 16:36:58 -04002486bool Texture2DArray::isSamplerComplete(const SamplerState &samplerState) const
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002487{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002488 GLsizei width = getBaseLevelWidth();
2489 GLsizei height = getBaseLevelHeight();
Jamie Madillb8f8b892014-01-07 10:12:50 -05002490 GLsizei depth = getLayers(0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002491
2492 if (width <= 0 || height <= 0 || depth <= 0)
2493 {
2494 return false;
2495 }
2496
Jamie Madilld3d2a342013-10-07 10:46:35 -04002497 if (!IsTextureFilteringSupported(getBaseLevelInternalFormat(), mRenderer))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002498 {
Jamie Madillf8989902013-07-19 16:36:58 -04002499 if (samplerState.magFilter != GL_NEAREST ||
2500 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002501 {
2502 return false;
2503 }
2504 }
2505
Jamie Madillf8989902013-07-19 16:36:58 -04002506 if (IsMipmapFiltered(samplerState) && !isMipmapComplete())
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002507 {
2508 return false;
2509 }
2510
2511 return true;
2512}
2513
2514bool Texture2DArray::isMipmapComplete() const
2515{
Geoff Lang98705b72014-03-31 16:00:03 -04002516 int levelCount = mipLevels();
Jamie Madill07edd442013-07-19 16:36:58 -04002517
Geoff Lang98705b72014-03-31 16:00:03 -04002518 for (int level = 1; level < levelCount; level++)
Jamie Madill07edd442013-07-19 16:36:58 -04002519 {
2520 if (!isLevelComplete(level))
2521 {
2522 return false;
2523 }
2524 }
2525
2526 return true;
2527}
2528
2529bool Texture2DArray::isLevelComplete(int level) const
2530{
Jamie Madillb8f8b892014-01-07 10:12:50 -05002531 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray));
Jamie Madill07edd442013-07-19 16:36:58 -04002532
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002533 if (isImmutable())
2534 {
2535 return true;
2536 }
2537
Jamie Madilld3d2a342013-10-07 10:46:35 -04002538 GLsizei width = getBaseLevelWidth();
2539 GLsizei height = getBaseLevelHeight();
Jamie Madillb8f8b892014-01-07 10:12:50 -05002540 GLsizei layers = getLayers(0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002541
Jamie Madillb8f8b892014-01-07 10:12:50 -05002542 if (width <= 0 || height <= 0 || layers <= 0)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002543 {
2544 return false;
2545 }
2546
Jamie Madill07edd442013-07-19 16:36:58 -04002547 if (level == 0)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002548 {
Jamie Madill07edd442013-07-19 16:36:58 -04002549 return true;
2550 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002551
Jamie Madill07edd442013-07-19 16:36:58 -04002552 if (getInternalFormat(level) != getInternalFormat(0))
2553 {
2554 return false;
2555 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002556
Jamie Madill07edd442013-07-19 16:36:58 -04002557 if (getWidth(level) != std::max(1, width >> level))
2558 {
2559 return false;
2560 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002561
Jamie Madill07edd442013-07-19 16:36:58 -04002562 if (getHeight(level) != std::max(1, height >> level))
2563 {
2564 return false;
2565 }
2566
Jamie Madillb8f8b892014-01-07 10:12:50 -05002567 if (getLayers(level) != layers)
Jamie Madill07edd442013-07-19 16:36:58 -04002568 {
2569 return false;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002570 }
2571
2572 return true;
2573}
2574
Geoff Lang8040f572013-07-25 16:49:54 -04002575Renderbuffer *Texture2DArray::getRenderbuffer(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002576{
Geoff Lang8040f572013-07-25 16:49:54 -04002577 Renderbuffer *renderBuffer = mRenderbufferProxies.get(level, layer);
2578 if (!renderBuffer)
2579 {
Geoff Langd5d8e392013-07-25 16:53:03 -04002580 renderBuffer = new Renderbuffer(mRenderer, id(), new RenderbufferTexture2DArrayLayer(this, level, layer));
2581 mRenderbufferProxies.add(level, 0, renderBuffer);
Geoff Lang8040f572013-07-25 16:49:54 -04002582 }
2583
2584 return renderBuffer;
2585}
2586
Jamie Madille83d1a92013-10-24 17:49:33 -04002587unsigned int Texture2DArray::getRenderTargetSerial(GLint level, GLint layer)
Geoff Lang8040f572013-07-25 16:49:54 -04002588{
Jamie Madille83d1a92013-10-24 17:49:33 -04002589 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(level, layer) : 0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002590}
2591
Jamie Madill07bb8cf2013-10-24 17:49:44 -04002592bool Texture2DArray::isValidLevel(int level) const
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002593{
Nicolas Capensbf712d02014-03-31 14:23:35 -04002594 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002595}
2596
Jamie Madill73b5d062013-10-24 17:49:38 -04002597void Texture2DArray::initializeStorage(bool renderTarget)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002598{
Jamie Madill884a4622013-10-24 17:49:41 -04002599 // Only initialize the first time this texture is used as a render target or shader resource
2600 if (mTexStorage)
2601 {
2602 return;
2603 }
2604
2605 // do not attempt to create storage for nonexistant data
2606 if (!isLevelComplete(0))
2607 {
2608 return;
2609 }
2610
2611 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
2612
2613 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
2614 ASSERT(mTexStorage);
2615
2616 // flush image data to the storage
2617 updateStorage();
2618}
2619
2620rx::TextureStorageInterface2DArray *Texture2DArray::createCompleteStorage(bool renderTarget) const
2621{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002622 GLsizei width = getBaseLevelWidth();
2623 GLsizei height = getBaseLevelHeight();
Jamie Madillb8f8b892014-01-07 10:12:50 -05002624 GLsizei depth = getLayers(0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002625
Jamie Madill884a4622013-10-24 17:49:41 -04002626 ASSERT(width > 0 && height > 0 && depth > 0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002627
Jamie Madill884a4622013-10-24 17:49:41 -04002628 // use existing storage level count, when previously specified by TexStorage*D
Nicolas Capensbf712d02014-03-31 14:23:35 -04002629 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002630
Nicolas Capensbf712d02014-03-31 14:23:35 -04002631 return new rx::TextureStorageInterface2DArray(mRenderer, getBaseLevelInternalFormat(), renderTarget, width, height, depth, levels);
Jamie Madill884a4622013-10-24 17:49:41 -04002632}
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002633
Jamie Madill884a4622013-10-24 17:49:41 -04002634void Texture2DArray::setCompleteTexStorage(rx::TextureStorageInterface2DArray *newCompleteTexStorage)
2635{
2636 SafeDelete(mTexStorage);
2637 mTexStorage = newCompleteTexStorage;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002638 mDirtyImages = true;
Jamie Madill884a4622013-10-24 17:49:41 -04002639
2640 // We do not support managed 2D array storage, as managed storage is ES2/D3D9 only
2641 ASSERT(!mTexStorage->isManaged());
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002642}
2643
Jamie Madill169d1112013-10-24 17:49:37 -04002644void Texture2DArray::updateStorage()
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002645{
Jamie Madill4cfff5f2013-10-24 17:49:46 -04002646 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002647 {
Jamie Madilld9b9a502013-10-10 17:46:13 -04002648 if (isLevelComplete(level))
2649 {
Jamie Madill169d1112013-10-24 17:49:37 -04002650 updateStorageLevel(level);
Jamie Madilld9b9a502013-10-10 17:46:13 -04002651 }
Jamie Madill07edd442013-07-19 16:36:58 -04002652 }
2653}
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002654
Jamie Madill169d1112013-10-24 17:49:37 -04002655void Texture2DArray::updateStorageLevel(int level)
Jamie Madill07edd442013-07-19 16:36:58 -04002656{
Jamie Madillaee7ad82013-10-10 16:07:32 -04002657 ASSERT(level >= 0 && level < (int)ArraySize(mLayerCounts));
2658 ASSERT(isLevelComplete(level));
2659
Jamie Madill07edd442013-07-19 16:36:58 -04002660 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2661 {
Jamie Madillaee7ad82013-10-10 16:07:32 -04002662 ASSERT(mImageArray[level] != NULL && mImageArray[level][layer] != NULL);
2663 if (mImageArray[level][layer]->isDirty())
Jamie Madill07edd442013-07-19 16:36:58 -04002664 {
Jamie Madillaee7ad82013-10-10 16:07:32 -04002665 commitRect(level, 0, 0, layer, getWidth(level), getHeight(level));
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002666 }
2667 }
2668}
2669
Jamie Madille83d1a92013-10-24 17:49:33 -04002670bool Texture2DArray::ensureRenderTarget()
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002671{
Jamie Madill884a4622013-10-24 17:49:41 -04002672 initializeStorage(true);
2673
Jamie Madillb8f8b892014-01-07 10:12:50 -05002674 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0 && getLayers(0) > 0)
Jamie Madille83d1a92013-10-24 17:49:33 -04002675 {
Jamie Madill884a4622013-10-24 17:49:41 -04002676 ASSERT(mTexStorage);
2677 if (!mTexStorage->isRenderTarget())
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002678 {
Jamie Madill884a4622013-10-24 17:49:41 -04002679 rx::TextureStorageInterface2DArray *newRenderTargetStorage = createCompleteStorage(true);
2680
2681 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002682 {
Jamie Madill884a4622013-10-24 17:49:41 -04002683 delete newRenderTargetStorage;
Jamie Madille83d1a92013-10-24 17:49:33 -04002684 return gl::error(GL_OUT_OF_MEMORY, false);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002685 }
Jamie Madill884a4622013-10-24 17:49:41 -04002686
2687 setCompleteTexStorage(newRenderTargetStorage);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002688 }
2689 }
2690
Jamie Madille83d1a92013-10-24 17:49:33 -04002691 return (mTexStorage && mTexStorage->isRenderTarget());
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002692}
2693
Geoff Lang8040f572013-07-25 16:49:54 -04002694rx::RenderTarget *Texture2DArray::getRenderTarget(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002695{
Geoff Lang8040f572013-07-25 16:49:54 -04002696 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04002697 if (!ensureRenderTarget())
Geoff Lang8040f572013-07-25 16:49:54 -04002698 {
2699 return NULL;
2700 }
2701
Jamie Madill169d1112013-10-24 17:49:37 -04002702 updateStorageLevel(level);
Geoff Lang8040f572013-07-25 16:49:54 -04002703
2704 // ensure this is NOT a depth texture
2705 if (isDepth(level))
2706 {
2707 return NULL;
2708 }
2709
2710 return mTexStorage->getRenderTarget(level, layer);
2711}
2712
2713rx::RenderTarget *Texture2DArray::getDepthStencil(GLint level, GLint layer)
2714{
2715 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04002716 if (!ensureRenderTarget())
Geoff Lang8040f572013-07-25 16:49:54 -04002717 {
2718 return NULL;
2719 }
2720
Jamie Madill169d1112013-10-24 17:49:37 -04002721 updateStorageLevel(level);
Geoff Lang8040f572013-07-25 16:49:54 -04002722
2723 // ensure this is a depth texture
2724 if (!isDepth(level))
2725 {
2726 return NULL;
2727 }
2728
2729 return mTexStorage->getRenderTarget(level, layer);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002730}
2731
Geoff Lang005df412013-10-16 14:12:50 -04002732void Texture2DArray::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002733{
2734 // If there currently is a corresponding storage texture image, it has these parameters
Jamie Madilld3d2a342013-10-07 10:46:35 -04002735 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2736 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
Jamie Madillb8f8b892014-01-07 10:12:50 -05002737 const int storageDepth = getLayers(0);
Geoff Lang005df412013-10-16 14:12:50 -04002738 const GLenum storageFormat = getBaseLevelInternalFormat();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002739
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002740 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002741 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002742 delete mImageArray[level][layer];
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002743 }
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002744 delete[] mImageArray[level];
Jamie Madill152ed092013-10-09 17:01:15 -04002745 mImageArray[level] = NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002746 mLayerCounts[level] = depth;
2747
Jamie Madill152ed092013-10-09 17:01:15 -04002748 if (depth > 0)
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002749 {
Jamie Madill152ed092013-10-09 17:01:15 -04002750 mImageArray[level] = new rx::Image*[depth]();
2751
2752 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2753 {
2754 mImageArray[level][layer] = mRenderer->createImage();
2755 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, width, height, 1, false);
2756 }
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002757 }
2758
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002759 if (mTexStorage)
2760 {
Nicolas Capensbf712d02014-03-31 14:23:35 -04002761 const int storageLevels = mTexStorage->getLevelCount();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002762
2763 if ((level >= storageLevels && storageLevels != 0) ||
2764 width != storageWidth ||
2765 height != storageHeight ||
2766 depth != storageDepth ||
2767 internalformat != storageFormat) // Discard mismatched storage
2768 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002769 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002770 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002771 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002772 {
2773 mImageArray[level][layer]->markDirty();
2774 }
2775 }
2776
2777 delete mTexStorage;
2778 mTexStorage = NULL;
2779 mDirtyImages = true;
2780 }
2781 }
2782}
2783
2784void Texture2DArray::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint layerTarget, GLsizei width, GLsizei height)
2785{
Jamie Madillb8f8b892014-01-07 10:12:50 -05002786 if (isValidLevel(level) && layerTarget < getLayers(level))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002787 {
2788 rx::Image *image = mImageArray[level][layerTarget];
Jamie Madill169d1112013-10-24 17:49:37 -04002789 if (image->copyToStorage(mTexStorage, level, xoffset, yoffset, layerTarget, width, height))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002790 {
2791 image->markClean();
2792 }
2793 }
2794}
2795
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00002796}