blob: 25ba855012c2827424bdc7ecc1df5641f8bbb8a9 [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;
Nicolas Capens8de68282014-04-04 11:10:27 -040062 mSamplerState.baseLevel = 0;
63 mSamplerState.maxLevel = 1000;
64 mSamplerState.minLod = -1000.0f;
65 mSamplerState.maxLod = 1000.0f;
Geoff Langc82fc412013-07-10 14:43:42 -040066 mSamplerState.compareMode = GL_NONE;
67 mSamplerState.compareFunc = GL_LEQUAL;
Geoff Langbc90a482013-09-17 16:51:27 -040068 mSamplerState.swizzleRed = GL_RED;
69 mSamplerState.swizzleGreen = GL_GREEN;
70 mSamplerState.swizzleBlue = GL_BLUE;
71 mSamplerState.swizzleAlpha = GL_ALPHA;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000072 mUsage = GL_NONE;
Geoff Langc82fc412013-07-10 14:43:42 -040073
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000074 mDirtyImages = true;
75
76 mImmutable = false;
Geoff Lang4907f2c2013-07-25 12:53:57 -040077
78 mTarget = target;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000079}
80
81Texture::~Texture()
82{
83}
84
Geoff Lang4907f2c2013-07-25 12:53:57 -040085GLenum Texture::getTarget() const
86{
87 return mTarget;
88}
89
Geoff Lang8040f572013-07-25 16:49:54 -040090void Texture::addProxyRef(const Renderbuffer *proxy)
91{
92 mRenderbufferProxies.addRef(proxy);
93}
94
95void Texture::releaseProxy(const Renderbuffer *proxy)
96{
97 mRenderbufferProxies.release(proxy);
98}
99
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400100void Texture::setMinFilter(GLenum filter)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000101{
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400102 mSamplerState.minFilter = filter;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000103}
104
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400105void Texture::setMagFilter(GLenum filter)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000106{
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400107 mSamplerState.magFilter = filter;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000108}
109
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400110void Texture::setWrapS(GLenum wrap)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000111{
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400112 mSamplerState.wrapS = wrap;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000113}
114
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400115void Texture::setWrapT(GLenum wrap)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000116{
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400117 mSamplerState.wrapT = wrap;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000118}
119
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400120void Texture::setWrapR(GLenum wrap)
shannon.woods%transgaming.com@gtempaccount.com0b3a8df2013-04-13 03:44:51 +0000121{
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400122 mSamplerState.wrapR = wrap;
shannon.woods%transgaming.com@gtempaccount.com0b3a8df2013-04-13 03:44:51 +0000123}
124
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400125void Texture::setMaxAnisotropy(float textureMaxAnisotropy, float contextMaxAnisotropy)
daniel@transgaming.com07ab8412012-07-12 15:17:09 +0000126{
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400127 mSamplerState.maxAnisotropy = std::min(textureMaxAnisotropy, contextMaxAnisotropy);
daniel@transgaming.com07ab8412012-07-12 15:17:09 +0000128}
129
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400130void Texture::setCompareMode(GLenum mode)
Geoff Langc82fc412013-07-10 14:43:42 -0400131{
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400132 mSamplerState.compareMode = mode;
Geoff Langc82fc412013-07-10 14:43:42 -0400133}
134
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400135void Texture::setCompareFunc(GLenum func)
Geoff Langc82fc412013-07-10 14:43:42 -0400136{
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400137 mSamplerState.compareFunc = func;
Geoff Langc82fc412013-07-10 14:43:42 -0400138}
139
Geoff Langbc90a482013-09-17 16:51:27 -0400140void Texture::setSwizzleRed(GLenum swizzle)
141{
142 mSamplerState.swizzleRed = swizzle;
143}
144
145void Texture::setSwizzleGreen(GLenum swizzle)
146{
147 mSamplerState.swizzleGreen = swizzle;
148}
149
150void Texture::setSwizzleBlue(GLenum swizzle)
151{
152 mSamplerState.swizzleBlue = swizzle;
153}
154
155void Texture::setSwizzleAlpha(GLenum swizzle)
156{
157 mSamplerState.swizzleAlpha = swizzle;
158}
159
Nicolas Capens8de68282014-04-04 11:10:27 -0400160void Texture::setBaseLevel(GLint baseLevel)
161{
162 mSamplerState.baseLevel = baseLevel;
163}
164
165void Texture::setMaxLevel(GLint maxLevel)
166{
167 mSamplerState.maxLevel = maxLevel;
168}
169
170void Texture::setMinLod(GLfloat minLod)
171{
172 mSamplerState.minLod = minLod;
173}
174
175void Texture::setMaxLod(GLfloat maxLod)
176{
177 mSamplerState.maxLod = maxLod;
178}
179
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400180void Texture::setUsage(GLenum usage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000181{
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400182 mUsage = usage;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000183}
184
185GLenum Texture::getMinFilter() const
186{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000187 return mSamplerState.minFilter;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000188}
189
190GLenum Texture::getMagFilter() const
191{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000192 return mSamplerState.magFilter;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000193}
194
195GLenum Texture::getWrapS() const
196{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000197 return mSamplerState.wrapS;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000198}
199
200GLenum Texture::getWrapT() const
201{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000202 return mSamplerState.wrapT;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000203}
204
shannon.woods%transgaming.com@gtempaccount.com0b3a8df2013-04-13 03:44:51 +0000205GLenum Texture::getWrapR() const
206{
207 return mSamplerState.wrapR;
208}
209
daniel@transgaming.com07ab8412012-07-12 15:17:09 +0000210float Texture::getMaxAnisotropy() const
211{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000212 return mSamplerState.maxAnisotropy;
213}
214
Geoff Langbc90a482013-09-17 16:51:27 -0400215GLenum Texture::getSwizzleRed() const
216{
217 return mSamplerState.swizzleRed;
218}
219
220GLenum Texture::getSwizzleGreen() const
221{
222 return mSamplerState.swizzleGreen;
223}
224
225GLenum Texture::getSwizzleBlue() const
226{
227 return mSamplerState.swizzleBlue;
228}
229
230GLenum Texture::getSwizzleAlpha() const
231{
232 return mSamplerState.swizzleAlpha;
233}
234
Nicolas Capens8de68282014-04-04 11:10:27 -0400235GLint Texture::getBaseLevel() const
236{
237 return mSamplerState.baseLevel;
238}
239
240GLint Texture::getMaxLevel() const
241{
242 return mSamplerState.maxLevel;
243}
244
245GLfloat Texture::getMinLod() const
246{
247 return mSamplerState.minLod;
248}
249
250GLfloat Texture::getMaxLod() const
251{
252 return mSamplerState.maxLod;
253}
254
Geoff Langbc90a482013-09-17 16:51:27 -0400255bool Texture::isSwizzled() const
256{
257 return mSamplerState.swizzleRed != GL_RED ||
258 mSamplerState.swizzleGreen != GL_GREEN ||
259 mSamplerState.swizzleBlue != GL_BLUE ||
260 mSamplerState.swizzleAlpha != GL_ALPHA;
261}
262
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000263void Texture::getSamplerState(SamplerState *sampler)
264{
265 *sampler = mSamplerState;
Nicolas Capens8de68282014-04-04 11:10:27 -0400266
267 // Offset the effective base level by the texture storage's top level
268 rx::TextureStorageInterface *texture = getNativeTexture();
269 int topLevel = texture ? texture->getTopLevel() : 0;
270 sampler->baseLevel = topLevel + mSamplerState.baseLevel;
daniel@transgaming.com07ab8412012-07-12 15:17:09 +0000271}
272
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000273GLenum Texture::getUsage() const
274{
275 return mUsage;
276}
277
Jamie Madilld3d2a342013-10-07 10:46:35 -0400278GLint Texture::getBaseLevelWidth() const
279{
280 const rx::Image *baseImage = getBaseLevelImage();
281 return (baseImage ? baseImage->getWidth() : 0);
282}
283
284GLint Texture::getBaseLevelHeight() const
285{
286 const rx::Image *baseImage = getBaseLevelImage();
287 return (baseImage ? baseImage->getHeight() : 0);
288}
289
290GLint Texture::getBaseLevelDepth() const
291{
292 const rx::Image *baseImage = getBaseLevelImage();
293 return (baseImage ? baseImage->getDepth() : 0);
294}
295
Jamie Madillb8f8b892014-01-07 10:12:50 -0500296// Note: "base level image" is loosely defined to be any image from the base level,
297// where in the base of 2D array textures and cube maps there are several. Don't use
298// the base level image for anything except querying texture format and size.
Jamie Madilld3d2a342013-10-07 10:46:35 -0400299GLenum Texture::getBaseLevelInternalFormat() const
300{
301 const rx::Image *baseImage = getBaseLevelImage();
302 return (baseImage ? baseImage->getInternalFormat() : GL_NONE);
303}
304
Jamie Madill88f18f42013-09-18 14:36:19 -0400305void Texture::setImage(const PixelUnpackState &unpack, GLenum type, const void *pixels, rx::Image *image)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000306{
Jamie Madillc30003d2014-01-10 12:51:23 -0500307 // No-op
308 if (image->getWidth() == 0 || image->getHeight() == 0 || image->getDepth() == 0)
309 {
310 return;
311 }
312
Jamie Madillabef6802013-09-05 16:54:19 -0400313 // We no longer need the "GLenum format" parameter to TexImage to determine what data format "pixels" contains.
314 // 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 -0400315 const void *pixelData = pixels;
316
317 if (unpack.pixelBuffer.id() != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000318 {
Jamie Madill1beb1db2013-09-18 14:36:28 -0400319 // Do a CPU readback here, if we have an unpack buffer bound and the fast GPU path is not supported
320 Buffer *pixelBuffer = unpack.pixelBuffer.get();
321 ptrdiff_t offset = reinterpret_cast<ptrdiff_t>(pixels);
322 const void *bufferData = pixelBuffer->getStorage()->getData();
323 pixelData = static_cast<const unsigned char *>(bufferData) + offset;
324 }
325
326 if (pixelData != NULL)
327 {
328 image->loadData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), unpack.alignment, type, pixelData);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000329 mDirtyImages = true;
330 }
331}
332
Geoff Lang005df412013-10-16 14:12:50 -0400333bool Texture::isFastUnpackable(const PixelUnpackState &unpack, GLenum sizedInternalFormat)
Jamie Madill8cc7d972013-10-10 15:51:55 -0400334{
335 return unpack.pixelBuffer.id() != 0 && mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat);
336}
337
Jamie Madill1beb1db2013-09-18 14:36:28 -0400338bool Texture::fastUnpackPixels(const PixelUnpackState &unpack, const void *pixels, const Box &destArea,
Jamie Madill8cc7d972013-10-10 15:51:55 -0400339 GLenum sizedInternalFormat, GLenum type, rx::RenderTarget *destRenderTarget)
Jamie Madill1beb1db2013-09-18 14:36:28 -0400340{
341 if (destArea.width <= 0 && destArea.height <= 0 && destArea.depth <= 0)
342 {
343 return true;
344 }
345
346 // In order to perform the fast copy through the shader, we must have the right format, and be able
347 // to create a render target.
Jamie Madill8cc7d972013-10-10 15:51:55 -0400348 ASSERT(mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat));
Jamie Madill1beb1db2013-09-18 14:36:28 -0400349
Jamie Madill8cc7d972013-10-10 15:51:55 -0400350 unsigned int offset = reinterpret_cast<unsigned int>(pixels);
Jamie Madill1beb1db2013-09-18 14:36:28 -0400351
Jamie Madill8cc7d972013-10-10 15:51:55 -0400352 return mRenderer->fastCopyBufferToTexture(unpack, offset, destRenderTarget, sizedInternalFormat, type, destArea);
Jamie Madill1beb1db2013-09-18 14:36:28 -0400353}
354
daniel@transgaming.com31b13e12012-11-28 19:34:30 +0000355void Texture::setCompressedImage(GLsizei imageSize, const void *pixels, rx::Image *image)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000356{
357 if (pixels != NULL)
358 {
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000359 image->loadCompressedData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000360 mDirtyImages = true;
361 }
362}
363
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000364bool Texture::subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
Jamie Madill88f18f42013-09-18 14:36:19 -0400365 GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels, rx::Image *image)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000366{
Jamie Madill065e1a32013-10-10 15:11:50 -0400367 const void *pixelData = pixels;
368
369 // CPU readback & copy where direct GPU copy is not supported
370 if (unpack.pixelBuffer.id() != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000371 {
Jamie Madill065e1a32013-10-10 15:11:50 -0400372 Buffer *pixelBuffer = unpack.pixelBuffer.get();
373 unsigned int offset = reinterpret_cast<unsigned int>(pixels);
374 const void *bufferData = pixelBuffer->getStorage()->getData();
375 pixelData = static_cast<const unsigned char *>(bufferData) + offset;
376 }
377
378 if (pixelData != NULL)
379 {
380 image->loadData(xoffset, yoffset, zoffset, width, height, depth, unpack.alignment, type, pixelData);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000381 mDirtyImages = true;
382 }
383
384 return true;
385}
386
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000387bool Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
388 GLenum format, GLsizei imageSize, const void *pixels, rx::Image *image)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000389{
390 if (pixels != NULL)
391 {
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000392 image->loadCompressedData(xoffset, yoffset, zoffset, width, height, depth, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000393 mDirtyImages = true;
394 }
395
396 return true;
397}
398
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000399rx::TextureStorageInterface *Texture::getNativeTexture()
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000400{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000401 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -0400402 initializeStorage(false);
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000403
Jamie Madill2ebab852013-10-24 17:49:42 -0400404 rx::TextureStorageInterface *storage = getBaseLevelStorage();
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000405 if (storage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000406 {
Jamie Madill169d1112013-10-24 17:49:37 -0400407 updateStorage();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000408 }
409
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000410 return storage;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000411}
412
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000413bool Texture::hasDirtyImages() const
414{
415 return mDirtyImages;
416}
417
418void Texture::resetDirty()
419{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000420 mDirtyImages = false;
421}
422
423unsigned int Texture::getTextureSerial()
424{
Jamie Madill2ebab852013-10-24 17:49:42 -0400425 rx::TextureStorageInterface *texture = getNativeTexture();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000426 return texture ? texture->getTextureSerial() : 0;
427}
428
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000429bool Texture::isImmutable() const
430{
431 return mImmutable;
432}
433
Jamie Madill51a94372013-10-24 17:49:43 -0400434int Texture::immutableLevelCount()
435{
Nicolas Capensbf712d02014-03-31 14:23:35 -0400436 return (mImmutable ? getNativeTexture()->getStorageInstance()->getLevelCount() : 0);
Jamie Madill51a94372013-10-24 17:49:43 -0400437}
438
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +0000439GLint Texture::creationLevels(GLsizei width, GLsizei height, GLsizei depth) const
440{
Jamie Madill6b7440c2013-10-24 17:49:47 -0400441 if ((isPow2(width) && isPow2(height) && isPow2(depth)) || mRenderer->getNonPower2TextureSupport())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000442 {
Jamie Madill6b7440c2013-10-24 17:49:47 -0400443 // Maximum number of levels
Geoff Lang98705b72014-03-31 16:00:03 -0400444 return log2(std::max(std::max(width, height), depth)) + 1;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000445 }
446 else
447 {
448 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
449 return 1;
450 }
451}
452
Jamie Madill22f843a2013-10-24 17:49:36 -0400453int Texture::mipLevels() const
454{
Geoff Lang98705b72014-03-31 16:00:03 -0400455 return log2(std::max(std::max(getBaseLevelWidth(), getBaseLevelHeight()), getBaseLevelDepth())) + 1;
Jamie Madill22f843a2013-10-24 17:49:36 -0400456}
457
Geoff Lang4907f2c2013-07-25 12:53:57 -0400458Texture2D::Texture2D(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_2D)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000459{
460 mTexStorage = NULL;
461 mSurface = NULL;
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000462
463 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
464 {
daniel@transgaming.com244e1832012-12-20 20:52:35 +0000465 mImageArray[i] = renderer->createImage();
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000466 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000467}
468
469Texture2D::~Texture2D()
470{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000471 delete mTexStorage;
472 mTexStorage = NULL;
473
474 if (mSurface)
475 {
476 mSurface->setBoundTexture(NULL);
477 mSurface = NULL;
478 }
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000479
480 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
481 {
482 delete mImageArray[i];
483 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000484}
485
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000486GLsizei Texture2D::getWidth(GLint level) const
487{
488 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000489 return mImageArray[level]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000490 else
491 return 0;
492}
493
494GLsizei Texture2D::getHeight(GLint level) const
495{
496 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000497 return mImageArray[level]->getHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000498 else
499 return 0;
500}
501
502GLenum Texture2D::getInternalFormat(GLint level) const
503{
504 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000505 return mImageArray[level]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000506 else
507 return GL_NONE;
508}
509
daniel@transgaming.com20d36662012-10-31 19:51:43 +0000510GLenum Texture2D::getActualFormat(GLint level) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000511{
512 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000513 return mImageArray[level]->getActualFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000514 else
Geoff Langcbf727a2014-02-10 12:50:45 -0500515 return GL_NONE;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000516}
517
Geoff Lang005df412013-10-16 14:12:50 -0400518void Texture2D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000519{
520 releaseTexImage();
shannon.woods@transgaming.com8a406682013-02-28 23:15:26 +0000521
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000522 // If there currently is a corresponding storage texture image, it has these parameters
Jamie Madilld3d2a342013-10-07 10:46:35 -0400523 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
524 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
Geoff Lang005df412013-10-16 14:12:50 -0400525 const GLenum storageFormat = getBaseLevelInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000526
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000527 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, width, height, 1, false);
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000528
529 if (mTexStorage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000530 {
Nicolas Capensbf712d02014-03-31 14:23:35 -0400531 const int storageLevels = mTexStorage->getLevelCount();
532
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000533 if ((level >= storageLevels && storageLevels != 0) ||
534 width != storageWidth ||
535 height != storageHeight ||
536 internalformat != storageFormat) // Discard mismatched storage
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000537 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000538 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
539 {
540 mImageArray[i]->markDirty();
541 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000542
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000543 delete mTexStorage;
544 mTexStorage = NULL;
545 mDirtyImages = true;
546 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000547 }
548}
549
Geoff Lang005df412013-10-16 14:12:50 -0400550void 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 +0000551{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +0000552 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Geoff Lang005df412013-10-16 14:12:50 -0400553 GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
554 : GetSizedInternalFormat(format, type, clientVersion);
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +0000555 redefineImage(level, sizedInternalFormat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000556
Jamie Madill8cc7d972013-10-10 15:51:55 -0400557 bool fastUnpacked = false;
558
Jamie Madill1beb1db2013-09-18 14:36:28 -0400559 // Attempt a fast gpu copy of the pixel data to the surface
Jamie Madill8cc7d972013-10-10 15:51:55 -0400560 if (isFastUnpackable(unpack, sizedInternalFormat) && isLevelComplete(level))
Jamie Madill1beb1db2013-09-18 14:36:28 -0400561 {
Jamie Madill8cc7d972013-10-10 15:51:55 -0400562 // Will try to create RT storage if it does not exist
563 rx::RenderTarget *destRenderTarget = getRenderTarget(level);
564 Box destArea(0, 0, 0, getWidth(level), getHeight(level), 1);
565
566 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget))
567 {
568 // Ensure we don't overwrite our newly initialized data
569 mImageArray[level]->markClean();
570
571 fastUnpacked = true;
572 }
Jamie Madill1beb1db2013-09-18 14:36:28 -0400573 }
Jamie Madill8cc7d972013-10-10 15:51:55 -0400574
575 if (!fastUnpacked)
Jamie Madill1beb1db2013-09-18 14:36:28 -0400576 {
577 Texture::setImage(unpack, type, pixels, mImageArray[level]);
578 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000579}
580
581void Texture2D::bindTexImage(egl::Surface *surface)
582{
583 releaseTexImage();
584
Geoff Lang005df412013-10-16 14:12:50 -0400585 GLenum internalformat = surface->getFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000586
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000587 mImageArray[0]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, surface->getWidth(), surface->getHeight(), 1, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000588
589 delete mTexStorage;
daniel@transgaming.comd8353dd2012-12-20 21:11:14 +0000590 mTexStorage = new rx::TextureStorageInterface2D(mRenderer, surface->getSwapChain());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000591
592 mDirtyImages = true;
593 mSurface = surface;
594 mSurface->setBoundTexture(this);
595}
596
597void Texture2D::releaseTexImage()
598{
599 if (mSurface)
600 {
601 mSurface->setBoundTexture(NULL);
602 mSurface = NULL;
603
604 if (mTexStorage)
605 {
606 delete mTexStorage;
607 mTexStorage = NULL;
608 }
609
610 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
611 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000612 mImageArray[i]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000613 }
614 }
615}
616
617void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
618{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000619 // 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 +0000620 redefineImage(level, format, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000621
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000622 Texture::setCompressedImage(imageSize, pixels, mImageArray[level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000623}
624
625void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
626{
Jamie Madill07bb8cf2013-10-24 17:49:44 -0400627 if (isValidLevel(level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000628 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000629 rx::Image *image = mImageArray[level];
Jamie Madill169d1112013-10-24 17:49:37 -0400630 if (image->copyToStorage(mTexStorage, level, xoffset, yoffset, width, height))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000631 {
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000632 image->markClean();
633 }
634 }
635}
636
Jamie Madill88f18f42013-09-18 14:36:19 -0400637void 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 +0000638{
Jamie Madill065e1a32013-10-10 15:11:50 -0400639 bool fastUnpacked = false;
640
641 if (isFastUnpackable(unpack, getInternalFormat(level)) && isLevelComplete(level))
642 {
643 rx::RenderTarget *renderTarget = getRenderTarget(level);
644 Box destArea(xoffset, yoffset, 0, width, height, 1);
645
646 if (renderTarget && fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, renderTarget))
647 {
648 // Ensure we don't overwrite our newly initialized data
649 mImageArray[level]->markClean();
650
651 fastUnpacked = true;
652 }
653 }
654
655 if (!fastUnpacked && Texture::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, mImageArray[level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000656 {
657 commitRect(level, xoffset, yoffset, width, height);
658 }
659}
660
661void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
662{
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000663 if (Texture::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000664 {
665 commitRect(level, xoffset, yoffset, width, height);
666 }
667}
668
669void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
670{
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +0000671 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Geoff Lang005df412013-10-16 14:12:50 -0400672 GLenum sizedInternalFormat = IsSizedInternalFormat(format, clientVersion) ? format
673 : GetSizedInternalFormat(format, GL_UNSIGNED_BYTE, clientVersion);
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +0000674 redefineImage(level, sizedInternalFormat, width, height);
shannon.woods@transgaming.com8a406682013-02-28 23:15:26 +0000675
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000676 if (!mImageArray[level]->isRenderableFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000677 {
shannon.woods%transgaming.com@gtempaccount.come5dcce72013-04-13 03:44:33 +0000678 mImageArray[level]->copy(0, 0, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000679 mDirtyImages = true;
680 }
681 else
682 {
Jamie Madille83d1a92013-10-24 17:49:33 -0400683 ensureRenderTarget();
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000684 mImageArray[level]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000685
Jamie Madill07bb8cf2013-10-24 17:49:44 -0400686 if (width != 0 && height != 0 && isValidLevel(level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000687 {
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +0000688 gl::Rectangle sourceRect;
689 sourceRect.x = x;
690 sourceRect.width = width;
691 sourceRect.y = y;
692 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000693
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +0000694 mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000695 }
696 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000697}
698
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +0000699void 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 +0000700{
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +0000701 if (xoffset + width > mImageArray[level]->getWidth() || yoffset + height > mImageArray[level]->getHeight() || zoffset != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000702 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +0000703 return gl::error(GL_INVALID_VALUE);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000704 }
705
Jamie Madill07edd442013-07-19 16:36:58 -0400706 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
707 // the current level we're copying to is defined (with appropriate format, width & height)
708 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
709
710 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000711 {
shannon.woods%transgaming.com@gtempaccount.come5dcce72013-04-13 03:44:33 +0000712 mImageArray[level]->copy(xoffset, yoffset, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000713 mDirtyImages = true;
714 }
715 else
716 {
Jamie Madille83d1a92013-10-24 17:49:33 -0400717 ensureRenderTarget();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000718
Jamie Madill07bb8cf2013-10-24 17:49:44 -0400719 if (isValidLevel(level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000720 {
Jamie Madill169d1112013-10-24 17:49:37 -0400721 updateStorageLevel(level);
Jamie Madill07edd442013-07-19 16:36:58 -0400722
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +0000723 GLuint clientVersion = mRenderer->getCurrentClientVersion();
724
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +0000725 gl::Rectangle sourceRect;
726 sourceRect.x = x;
727 sourceRect.width = width;
728 sourceRect.y = y;
729 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000730
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +0000731 mRenderer->copyImage(source, sourceRect,
Jamie Madilld3d2a342013-10-07 10:46:35 -0400732 gl::GetFormat(getBaseLevelInternalFormat(), clientVersion),
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +0000733 xoffset, yoffset, mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000734 }
735 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000736}
737
738void Texture2D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height)
739{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000740 for (int level = 0; level < levels; level++)
741 {
Jamie Madill73b5d062013-10-24 17:49:38 -0400742 GLsizei levelWidth = std::max(1, width >> level);
743 GLsizei levelHeight = std::max(1, height >> level);
744 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, levelWidth, levelHeight, 1, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000745 }
746
747 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
748 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000749 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000750 }
751
Jamie Madill73b5d062013-10-24 17:49:38 -0400752 mImmutable = true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000753
Nicolas Capensbf712d02014-03-31 14:23:35 -0400754 setCompleteTexStorage(new rx::TextureStorageInterface2D(mRenderer, internalformat, IsRenderTargetUsage(mUsage), width, height, levels));
Jamie Madill73b5d062013-10-24 17:49:38 -0400755}
756
757void Texture2D::setCompleteTexStorage(rx::TextureStorageInterface2D *newCompleteTexStorage)
758{
759 SafeDelete(mTexStorage);
760 mTexStorage = newCompleteTexStorage;
761
762 if (mTexStorage && mTexStorage->isManaged())
763 {
Nicolas Capensbf712d02014-03-31 14:23:35 -0400764 for (int level = 0; level < mTexStorage->getLevelCount(); level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000765 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000766 mImageArray[level]->setManagedSurface(mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000767 }
768 }
Jamie Madill73b5d062013-10-24 17:49:38 -0400769
770 mDirtyImages = true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000771}
772
773// Tests for 2D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85.
Jamie Madillf8989902013-07-19 16:36:58 -0400774bool Texture2D::isSamplerComplete(const SamplerState &samplerState) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000775{
Jamie Madilld3d2a342013-10-07 10:46:35 -0400776 GLsizei width = getBaseLevelWidth();
777 GLsizei height = getBaseLevelHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000778
779 if (width <= 0 || height <= 0)
780 {
781 return false;
782 }
783
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000784 if (!IsTextureFilteringSupported(getInternalFormat(0), mRenderer))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000785 {
Jamie Madillf8989902013-07-19 16:36:58 -0400786 if (samplerState.magFilter != GL_NEAREST ||
787 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000788 {
789 return false;
790 }
791 }
792
daniel@transgaming.comea32d482012-11-28 19:33:18 +0000793 bool npotSupport = mRenderer->getNonPower2TextureSupport();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000794
795 if (!npotSupport)
796 {
Jamie Madillf8989902013-07-19 16:36:58 -0400797 if ((samplerState.wrapS != GL_CLAMP_TO_EDGE && !isPow2(width)) ||
798 (samplerState.wrapT != GL_CLAMP_TO_EDGE && !isPow2(height)))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000799 {
800 return false;
801 }
802 }
803
Jamie Madillf8989902013-07-19 16:36:58 -0400804 if (IsMipmapFiltered(samplerState))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000805 {
806 if (!npotSupport)
807 {
808 if (!isPow2(width) || !isPow2(height))
809 {
810 return false;
811 }
812 }
813
814 if (!isMipmapComplete())
815 {
816 return false;
817 }
818 }
819
Geoff Langc82fc412013-07-10 14:43:42 -0400820 // OpenGLES 3.0.2 spec section 3.8.13 states that a texture is not mipmap complete if:
821 // The internalformat specified for the texture arrays is a sized internal depth or
822 // depth and stencil format (see table 3.13), the value of TEXTURE_COMPARE_-
823 // MODE is NONE, and either the magnification filter is not NEAREST or the mini-
824 // fication filter is neither NEAREST nor NEAREST_MIPMAP_NEAREST.
Jamie Madill2a205622014-02-12 10:41:24 -0500825 if (gl::GetDepthBits(getInternalFormat(0), mRenderer->getCurrentClientVersion()) > 0 &&
826 mRenderer->getCurrentClientVersion() > 2)
Geoff Langc82fc412013-07-10 14:43:42 -0400827 {
828 if (mSamplerState.compareMode == GL_NONE)
829 {
830 if ((mSamplerState.minFilter != GL_NEAREST && mSamplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST) ||
831 mSamplerState.magFilter != GL_NEAREST)
832 {
833 return false;
834 }
835 }
836 }
837
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000838 return true;
839}
840
841// Tests for 2D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
842bool Texture2D::isMipmapComplete() const
843{
Geoff Lang98705b72014-03-31 16:00:03 -0400844 int levelCount = mipLevels();
Jamie Madill07edd442013-07-19 16:36:58 -0400845
Geoff Lang98705b72014-03-31 16:00:03 -0400846 for (int level = 0; level < levelCount; level++)
Jamie Madill07edd442013-07-19 16:36:58 -0400847 {
848 if (!isLevelComplete(level))
849 {
850 return false;
851 }
852 }
853
854 return true;
855}
856
857bool Texture2D::isLevelComplete(int level) const
858{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000859 if (isImmutable())
860 {
861 return true;
862 }
863
Jamie Madill648c9682014-01-21 16:50:58 -0500864 const rx::Image *baseImage = getBaseLevelImage();
865
866 GLsizei width = baseImage->getWidth();
867 GLsizei height = baseImage->getHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000868
869 if (width <= 0 || height <= 0)
870 {
871 return false;
872 }
873
Jamie Madill07edd442013-07-19 16:36:58 -0400874 // The base image level is complete if the width and height are positive
875 if (level == 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000876 {
Jamie Madill07edd442013-07-19 16:36:58 -0400877 return true;
878 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000879
Jamie Madill07edd442013-07-19 16:36:58 -0400880 ASSERT(level >= 1 && level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
881 rx::Image *image = mImageArray[level];
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000882
Jamie Madill648c9682014-01-21 16:50:58 -0500883 if (image->getInternalFormat() != baseImage->getInternalFormat())
Jamie Madill07edd442013-07-19 16:36:58 -0400884 {
885 return false;
886 }
887
888 if (image->getWidth() != std::max(1, width >> level))
889 {
890 return false;
891 }
892
893 if (image->getHeight() != std::max(1, height >> level))
894 {
895 return false;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000896 }
897
898 return true;
899}
900
901bool Texture2D::isCompressed(GLint level) const
902{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000903 return IsFormatCompressed(getInternalFormat(level), mRenderer->getCurrentClientVersion());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000904}
905
906bool Texture2D::isDepth(GLint level) const
907{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000908 return GetDepthBits(getInternalFormat(level), mRenderer->getCurrentClientVersion()) > 0;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000909}
910
daniel@transgaming.comf032cb82012-10-31 19:51:52 +0000911// Constructs a native texture resource from the texture images
Jamie Madill73b5d062013-10-24 17:49:38 -0400912void Texture2D::initializeStorage(bool renderTarget)
913{
914 // Only initialize the first time this texture is used as a render target or shader resource
915 if (mTexStorage)
916 {
917 return;
918 }
919
920 // do not attempt to create storage for nonexistant data
921 if (!isLevelComplete(0))
922 {
923 return;
924 }
925
926 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
927
928 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
929 ASSERT(mTexStorage);
930
931 // flush image data to the storage
932 updateStorage();
933}
934
935rx::TextureStorageInterface2D *Texture2D::createCompleteStorage(bool renderTarget) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000936{
Jamie Madilld3d2a342013-10-07 10:46:35 -0400937 GLsizei width = getBaseLevelWidth();
938 GLsizei height = getBaseLevelHeight();
daniel@transgaming.come6a09842012-09-17 21:28:55 +0000939
Jamie Madill73b5d062013-10-24 17:49:38 -0400940 ASSERT(width > 0 && height > 0);
daniel@transgaming.come6a09842012-09-17 21:28:55 +0000941
Jamie Madill73b5d062013-10-24 17:49:38 -0400942 // use existing storage level count, when previously specified by TexStorage*D
Nicolas Capensbf712d02014-03-31 14:23:35 -0400943 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000944
Nicolas Capensbf712d02014-03-31 14:23:35 -0400945 return new rx::TextureStorageInterface2D(mRenderer, getBaseLevelInternalFormat(), renderTarget, width, height, levels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000946}
947
Jamie Madill169d1112013-10-24 17:49:37 -0400948void Texture2D::updateStorage()
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000949{
Jamie Madill4cfff5f2013-10-24 17:49:46 -0400950 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000951 {
Jamie Madill648c9682014-01-21 16:50:58 -0500952 if (mImageArray[level]->isDirty() && isLevelComplete(level))
Jamie Madilld9b9a502013-10-10 17:46:13 -0400953 {
Jamie Madill169d1112013-10-24 17:49:37 -0400954 updateStorageLevel(level);
Jamie Madilld9b9a502013-10-10 17:46:13 -0400955 }
Jamie Madill07edd442013-07-19 16:36:58 -0400956 }
957}
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000958
Jamie Madill169d1112013-10-24 17:49:37 -0400959void Texture2D::updateStorageLevel(int level)
Jamie Madill07edd442013-07-19 16:36:58 -0400960{
961 ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
Jamie Madillaee7ad82013-10-10 16:07:32 -0400962 ASSERT(isLevelComplete(level));
Jamie Madill07edd442013-07-19 16:36:58 -0400963
Jamie Madillaee7ad82013-10-10 16:07:32 -0400964 if (mImageArray[level]->isDirty())
Jamie Madill07edd442013-07-19 16:36:58 -0400965 {
Jamie Madillaee7ad82013-10-10 16:07:32 -0400966 commitRect(level, 0, 0, getWidth(level), getHeight(level));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000967 }
968}
969
Jamie Madille83d1a92013-10-24 17:49:33 -0400970bool Texture2D::ensureRenderTarget()
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000971{
Jamie Madill73b5d062013-10-24 17:49:38 -0400972 initializeStorage(true);
973
974 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0)
Jamie Madille83d1a92013-10-24 17:49:33 -0400975 {
Jamie Madill73b5d062013-10-24 17:49:38 -0400976 ASSERT(mTexStorage);
977 if (!mTexStorage->isRenderTarget())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000978 {
Jamie Madill73b5d062013-10-24 17:49:38 -0400979 rx::TextureStorageInterface2D *newRenderTargetStorage = createCompleteStorage(true);
980
981 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
982 {
983 delete newRenderTargetStorage;
Jamie Madille83d1a92013-10-24 17:49:33 -0400984 return gl::error(GL_OUT_OF_MEMORY, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000985 }
Jamie Madill73b5d062013-10-24 17:49:38 -0400986
987 setCompleteTexStorage(newRenderTargetStorage);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000988 }
989 }
990
Jamie Madille83d1a92013-10-24 17:49:33 -0400991 return (mTexStorage && mTexStorage->isRenderTarget());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000992}
993
994void Texture2D::generateMipmaps()
995{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000996 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Geoff Lang98705b72014-03-31 16:00:03 -0400997 int levelCount = mipLevels();
998 for (int level = 1; level < levelCount; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000999 {
Jamie Madill22f843a2013-10-24 17:49:36 -04001000 redefineImage(level, getBaseLevelInternalFormat(),
1001 std::max(getBaseLevelWidth() >> level, 1),
1002 std::max(getBaseLevelHeight() >> level, 1));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001003 }
1004
1005 if (mTexStorage && mTexStorage->isRenderTarget())
1006 {
Geoff Lang98705b72014-03-31 16:00:03 -04001007 for (int level = 1; level < levelCount; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001008 {
Jamie Madill22f843a2013-10-24 17:49:36 -04001009 mTexStorage->generateMipmap(level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001010
Jamie Madill22f843a2013-10-24 17:49:36 -04001011 mImageArray[level]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001012 }
1013 }
1014 else
1015 {
Geoff Lang98705b72014-03-31 16:00:03 -04001016 for (int level = 1; level < levelCount; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001017 {
Jamie Madill22f843a2013-10-24 17:49:36 -04001018 mRenderer->generateMipmap(mImageArray[level], mImageArray[level - 1]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001019 }
1020 }
1021}
1022
Jamie Madilld3d2a342013-10-07 10:46:35 -04001023const rx::Image *Texture2D::getBaseLevelImage() const
1024{
1025 return mImageArray[0];
1026}
1027
Jamie Madill2ebab852013-10-24 17:49:42 -04001028rx::TextureStorageInterface *Texture2D::getBaseLevelStorage()
1029{
1030 return mTexStorage;
1031}
1032
Geoff Lang8040f572013-07-25 16:49:54 -04001033Renderbuffer *Texture2D::getRenderbuffer(GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001034{
Geoff Lang8040f572013-07-25 16:49:54 -04001035 Renderbuffer *renderBuffer = mRenderbufferProxies.get(level, 0);
1036 if (!renderBuffer)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001037 {
Geoff Lang8040f572013-07-25 16:49:54 -04001038 renderBuffer = new Renderbuffer(mRenderer, id(), new RenderbufferTexture2D(this, level));
1039 mRenderbufferProxies.add(level, 0, renderBuffer);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001040 }
1041
Geoff Lang8040f572013-07-25 16:49:54 -04001042 return renderBuffer;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001043}
1044
Geoff Lang8040f572013-07-25 16:49:54 -04001045unsigned int Texture2D::getRenderTargetSerial(GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001046{
Jamie Madille83d1a92013-10-24 17:49:33 -04001047 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(level) : 0);
Geoff Lang8040f572013-07-25 16:49:54 -04001048}
1049
1050rx::RenderTarget *Texture2D::getRenderTarget(GLint level)
1051{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001052 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04001053 if (!ensureRenderTarget())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001054 {
1055 return NULL;
1056 }
1057
Jamie Madill169d1112013-10-24 17:49:37 -04001058 updateStorageLevel(level);
Geoff Lang8040f572013-07-25 16:49:54 -04001059
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001060 // ensure this is NOT a depth texture
Geoff Lang8040f572013-07-25 16:49:54 -04001061 if (isDepth(level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001062 {
1063 return NULL;
1064 }
daniel@transgaming.com34da3972012-12-20 21:10:29 +00001065
Geoff Lang8040f572013-07-25 16:49:54 -04001066 return mTexStorage->getRenderTarget(level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001067}
1068
Geoff Lang8040f572013-07-25 16:49:54 -04001069rx::RenderTarget *Texture2D::getDepthSencil(GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001070{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001071 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04001072 if (!ensureRenderTarget())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001073 {
1074 return NULL;
1075 }
1076
Jamie Madill169d1112013-10-24 17:49:37 -04001077 updateStorageLevel(level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001078
1079 // ensure this is actually a depth texture
Geoff Lang8040f572013-07-25 16:49:54 -04001080 if (!isDepth(level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001081 {
1082 return NULL;
1083 }
Geoff Lang8040f572013-07-25 16:49:54 -04001084
1085 return mTexStorage->getRenderTarget(level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001086}
1087
Jamie Madill07bb8cf2013-10-24 17:49:44 -04001088bool Texture2D::isValidLevel(int level) const
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +00001089{
Nicolas Capensbf712d02014-03-31 14:23:35 -04001090 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : false);
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +00001091}
1092
Geoff Lang4907f2c2013-07-25 12:53:57 -04001093TextureCubeMap::TextureCubeMap(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_CUBE_MAP)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001094{
1095 mTexStorage = NULL;
1096 for (int i = 0; i < 6; i++)
1097 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001098 for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
1099 {
daniel@transgaming.com244e1832012-12-20 20:52:35 +00001100 mImageArray[i][j] = renderer->createImage();
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001101 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001102 }
1103}
1104
1105TextureCubeMap::~TextureCubeMap()
1106{
1107 for (int i = 0; i < 6; i++)
1108 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001109 for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
1110 {
1111 delete mImageArray[i][j];
1112 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001113 }
1114
1115 delete mTexStorage;
1116 mTexStorage = NULL;
1117}
1118
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001119GLsizei TextureCubeMap::getWidth(GLenum target, GLint level) const
1120{
1121 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Jamie Madill2db197c2013-10-24 17:49:35 -04001122 return mImageArray[targetToIndex(target)][level]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001123 else
1124 return 0;
1125}
1126
1127GLsizei TextureCubeMap::getHeight(GLenum target, GLint level) const
1128{
1129 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Jamie Madill2db197c2013-10-24 17:49:35 -04001130 return mImageArray[targetToIndex(target)][level]->getHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001131 else
1132 return 0;
1133}
1134
1135GLenum TextureCubeMap::getInternalFormat(GLenum target, GLint level) const
1136{
1137 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Jamie Madill2db197c2013-10-24 17:49:35 -04001138 return mImageArray[targetToIndex(target)][level]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001139 else
1140 return GL_NONE;
1141}
1142
daniel@transgaming.com20d36662012-10-31 19:51:43 +00001143GLenum TextureCubeMap::getActualFormat(GLenum target, GLint level) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001144{
1145 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Jamie Madill2db197c2013-10-24 17:49:35 -04001146 return mImageArray[targetToIndex(target)][level]->getActualFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001147 else
Geoff Langcbf727a2014-02-10 12:50:45 -05001148 return GL_NONE;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001149}
1150
Geoff Lang005df412013-10-16 14:12:50 -04001151void 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 +00001152{
Jamie Madill88f18f42013-09-18 14:36:19 -04001153 setImage(0, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001154}
1155
Geoff Lang005df412013-10-16 14:12:50 -04001156void 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 +00001157{
Jamie Madill88f18f42013-09-18 14:36:19 -04001158 setImage(1, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001159}
1160
Geoff Lang005df412013-10-16 14:12:50 -04001161void 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 +00001162{
Jamie Madill88f18f42013-09-18 14:36:19 -04001163 setImage(2, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001164}
1165
Geoff Lang005df412013-10-16 14:12:50 -04001166void 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 +00001167{
Jamie Madill88f18f42013-09-18 14:36:19 -04001168 setImage(3, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001169}
1170
Geoff Lang005df412013-10-16 14:12:50 -04001171void 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 +00001172{
Jamie Madill88f18f42013-09-18 14:36:19 -04001173 setImage(4, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001174}
1175
Geoff Lang005df412013-10-16 14:12:50 -04001176void 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 +00001177{
Jamie Madill88f18f42013-09-18 14:36:19 -04001178 setImage(5, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001179}
1180
Jamie Madill2db197c2013-10-24 17:49:35 -04001181void 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 +00001182{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001183 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
Jamie Madill2db197c2013-10-24 17:49:35 -04001184 int faceIndex = targetToIndex(target);
1185 redefineImage(faceIndex, level, format, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001186
Jamie Madill2db197c2013-10-24 17:49:35 -04001187 Texture::setCompressedImage(imageSize, pixels, mImageArray[faceIndex][level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001188}
1189
Jamie Madill2db197c2013-10-24 17:49:35 -04001190void TextureCubeMap::commitRect(int faceIndex, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001191{
Jamie Madill07bb8cf2013-10-24 17:49:44 -04001192 if (isValidFaceLevel(faceIndex, level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001193 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001194 rx::Image *image = mImageArray[faceIndex][level];
Jamie Madill169d1112013-10-24 17:49:37 -04001195 if (image->copyToStorage(mTexStorage, faceIndex, level, xoffset, yoffset, width, height))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001196 image->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001197 }
1198}
1199
Jamie Madill88f18f42013-09-18 14:36:19 -04001200void 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 +00001201{
Jamie Madill2db197c2013-10-24 17:49:35 -04001202 int faceIndex = targetToIndex(target);
1203 if (Texture::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, mImageArray[faceIndex][level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001204 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001205 commitRect(faceIndex, level, xoffset, yoffset, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001206 }
1207}
1208
1209void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1210{
Jamie Madill2db197c2013-10-24 17:49:35 -04001211 int faceIndex = targetToIndex(target);
1212 if (Texture::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[faceIndex][level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001213 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001214 commitRect(faceIndex, level, xoffset, yoffset, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001215 }
1216}
1217
1218// Tests for cube map sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 86.
Jamie Madillf8989902013-07-19 16:36:58 -04001219bool TextureCubeMap::isSamplerComplete(const SamplerState &samplerState) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001220{
Jamie Madilld3d2a342013-10-07 10:46:35 -04001221 int size = getBaseLevelWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001222
Jamie Madillf8989902013-07-19 16:36:58 -04001223 bool mipmapping = IsMipmapFiltered(samplerState);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001224
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001225 if (!IsTextureFilteringSupported(getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0), mRenderer))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001226 {
Jamie Madillf8989902013-07-19 16:36:58 -04001227 if (samplerState.magFilter != GL_NEAREST ||
1228 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001229 {
1230 return false;
1231 }
1232 }
1233
daniel@transgaming.comea32d482012-11-28 19:33:18 +00001234 if (!isPow2(size) && !mRenderer->getNonPower2TextureSupport())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001235 {
Jamie Madillf8989902013-07-19 16:36:58 -04001236 if (samplerState.wrapS != GL_CLAMP_TO_EDGE || samplerState.wrapT != GL_CLAMP_TO_EDGE || mipmapping)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001237 {
1238 return false;
1239 }
1240 }
1241
1242 if (!mipmapping)
1243 {
1244 if (!isCubeComplete())
1245 {
1246 return false;
1247 }
1248 }
1249 else
1250 {
1251 if (!isMipmapCubeComplete()) // Also tests for isCubeComplete()
1252 {
1253 return false;
1254 }
1255 }
1256
1257 return true;
1258}
1259
1260// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1261bool TextureCubeMap::isCubeComplete() const
1262{
Jamie Madillc1f8b162013-10-07 10:46:38 -04001263 int baseWidth = getBaseLevelWidth();
1264 int baseHeight = getBaseLevelHeight();
1265 GLenum baseFormat = getBaseLevelInternalFormat();
1266
1267 if (baseWidth <= 0 || baseWidth != baseHeight)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001268 {
1269 return false;
1270 }
1271
Jamie Madill2db197c2013-10-24 17:49:35 -04001272 for (int faceIndex = 1; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001273 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001274 const rx::Image &faceBaseImage = *mImageArray[faceIndex][0];
Jamie Madillc1f8b162013-10-07 10:46:38 -04001275
1276 if (faceBaseImage.getWidth() != baseWidth ||
1277 faceBaseImage.getHeight() != baseHeight ||
1278 faceBaseImage.getInternalFormat() != baseFormat )
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001279 {
1280 return false;
1281 }
1282 }
1283
1284 return true;
1285}
1286
1287bool TextureCubeMap::isMipmapCubeComplete() const
1288{
1289 if (isImmutable())
1290 {
1291 return true;
1292 }
1293
1294 if (!isCubeComplete())
1295 {
1296 return false;
1297 }
1298
Geoff Lang98705b72014-03-31 16:00:03 -04001299 int levelCount = mipLevels();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001300
1301 for (int face = 0; face < 6; face++)
1302 {
Geoff Lang98705b72014-03-31 16:00:03 -04001303 for (int level = 1; level < levelCount; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001304 {
Jamie Madill07edd442013-07-19 16:36:58 -04001305 if (!isFaceLevelComplete(face, level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001306 {
1307 return false;
1308 }
1309 }
1310 }
1311
1312 return true;
1313}
1314
Jamie Madill2db197c2013-10-24 17:49:35 -04001315bool TextureCubeMap::isFaceLevelComplete(int faceIndex, int level) const
Jamie Madill07edd442013-07-19 16:36:58 -04001316{
Jamie Madill2db197c2013-10-24 17:49:35 -04001317 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
Jamie Madill07edd442013-07-19 16:36:58 -04001318
1319 if (isImmutable())
1320 {
1321 return true;
1322 }
1323
Jamie Madilld3d2a342013-10-07 10:46:35 -04001324 int baseSize = getBaseLevelWidth();
Jamie Madill07edd442013-07-19 16:36:58 -04001325
Jamie Madilld3d2a342013-10-07 10:46:35 -04001326 if (baseSize <= 0)
Jamie Madill07edd442013-07-19 16:36:58 -04001327 {
1328 return false;
1329 }
1330
Jamie Madilld3d2a342013-10-07 10:46:35 -04001331 // "isCubeComplete" checks for base level completeness and we must call that
1332 // to determine if any face at level 0 is complete. We omit that check here
1333 // to avoid re-checking cube-completeness for every face at level 0.
Jamie Madill07edd442013-07-19 16:36:58 -04001334 if (level == 0)
1335 {
1336 return true;
1337 }
1338
Jamie Madilld3d2a342013-10-07 10:46:35 -04001339 // Check that non-zero levels are consistent with the base level.
Jamie Madill2db197c2013-10-24 17:49:35 -04001340 const rx::Image *faceLevelImage = mImageArray[faceIndex][level];
Jamie Madill07edd442013-07-19 16:36:58 -04001341
Jamie Madilld3d2a342013-10-07 10:46:35 -04001342 if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat())
Jamie Madill07edd442013-07-19 16:36:58 -04001343 {
1344 return false;
1345 }
1346
Jamie Madilld3d2a342013-10-07 10:46:35 -04001347 if (faceLevelImage->getWidth() != std::max(1, baseSize >> level))
Jamie Madill07edd442013-07-19 16:36:58 -04001348 {
1349 return false;
1350 }
1351
1352 return true;
1353}
1354
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001355bool TextureCubeMap::isCompressed(GLenum target, GLint level) const
1356{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001357 return IsFormatCompressed(getInternalFormat(target, level), mRenderer->getCurrentClientVersion());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001358}
1359
Geoff Lang8040f572013-07-25 16:49:54 -04001360bool TextureCubeMap::isDepth(GLenum target, GLint level) const
1361{
1362 return GetDepthBits(getInternalFormat(target, level), mRenderer->getCurrentClientVersion()) > 0;
1363}
1364
Jamie Madill73b5d062013-10-24 17:49:38 -04001365void TextureCubeMap::initializeStorage(bool renderTarget)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001366{
Jamie Madill3c0989c2013-10-24 17:49:39 -04001367 // Only initialize the first time this texture is used as a render target or shader resource
1368 if (mTexStorage)
1369 {
1370 return;
1371 }
1372
1373 // do not attempt to create storage for nonexistant data
1374 if (!isFaceLevelComplete(0, 0))
1375 {
1376 return;
1377 }
1378
1379 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
1380
1381 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
1382 ASSERT(mTexStorage);
1383
1384 // flush image data to the storage
1385 updateStorage();
1386}
1387
1388rx::TextureStorageInterfaceCube *TextureCubeMap::createCompleteStorage(bool renderTarget) const
1389{
Jamie Madilld3d2a342013-10-07 10:46:35 -04001390 GLsizei size = getBaseLevelWidth();
daniel@transgaming.come6a09842012-09-17 21:28:55 +00001391
Jamie Madill3c0989c2013-10-24 17:49:39 -04001392 ASSERT(size > 0);
daniel@transgaming.come6a09842012-09-17 21:28:55 +00001393
Jamie Madill3c0989c2013-10-24 17:49:39 -04001394 // use existing storage level count, when previously specified by TexStorage*D
Nicolas Capensbf712d02014-03-31 14:23:35 -04001395 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(size, size, 1));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001396
Nicolas Capensbf712d02014-03-31 14:23:35 -04001397 return new rx::TextureStorageInterfaceCube(mRenderer, getBaseLevelInternalFormat(), renderTarget, size, levels);
Jamie Madill3c0989c2013-10-24 17:49:39 -04001398}
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001399
Jamie Madill3c0989c2013-10-24 17:49:39 -04001400void TextureCubeMap::setCompleteTexStorage(rx::TextureStorageInterfaceCube *newCompleteTexStorage)
1401{
1402 SafeDelete(mTexStorage);
1403 mTexStorage = newCompleteTexStorage;
1404
1405 if (mTexStorage && mTexStorage->isManaged())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001406 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001407 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001408 {
Nicolas Capensbf712d02014-03-31 14:23:35 -04001409 for (int level = 0; level < mTexStorage->getLevelCount(); level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001410 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001411 mImageArray[faceIndex][level]->setManagedSurface(mTexStorage, faceIndex, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001412 }
1413 }
1414 }
1415
1416 mDirtyImages = true;
1417}
1418
Jamie Madill169d1112013-10-24 17:49:37 -04001419void TextureCubeMap::updateStorage()
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001420{
1421 for (int face = 0; face < 6; face++)
1422 {
Jamie Madill4cfff5f2013-10-24 17:49:46 -04001423 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001424 {
Jamie Madilld9b9a502013-10-10 17:46:13 -04001425 if (isFaceLevelComplete(face, level))
1426 {
Jamie Madill169d1112013-10-24 17:49:37 -04001427 updateStorageFaceLevel(face, level);
Jamie Madilld9b9a502013-10-10 17:46:13 -04001428 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001429 }
1430 }
1431}
1432
Jamie Madill169d1112013-10-24 17:49:37 -04001433void TextureCubeMap::updateStorageFaceLevel(int faceIndex, int level)
Jamie Madill07edd442013-07-19 16:36:58 -04001434{
Jamie Madill2db197c2013-10-24 17:49:35 -04001435 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1436 rx::Image *image = mImageArray[faceIndex][level];
Jamie Madill07edd442013-07-19 16:36:58 -04001437
1438 if (image->isDirty())
1439 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001440 commitRect(faceIndex, level, 0, 0, image->getWidth(), image->getHeight());
Jamie Madill07edd442013-07-19 16:36:58 -04001441 }
1442}
1443
Jamie Madille83d1a92013-10-24 17:49:33 -04001444bool TextureCubeMap::ensureRenderTarget()
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001445{
Jamie Madill3c0989c2013-10-24 17:49:39 -04001446 initializeStorage(true);
1447
1448 if (getBaseLevelWidth() > 0)
Jamie Madille83d1a92013-10-24 17:49:33 -04001449 {
Jamie Madill3c0989c2013-10-24 17:49:39 -04001450 ASSERT(mTexStorage);
1451 if (!mTexStorage->isRenderTarget())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001452 {
Jamie Madill3c0989c2013-10-24 17:49:39 -04001453 rx::TextureStorageInterfaceCube *newRenderTargetStorage = createCompleteStorage(true);
1454
1455 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001456 {
Jamie Madill3c0989c2013-10-24 17:49:39 -04001457 delete newRenderTargetStorage;
Jamie Madille83d1a92013-10-24 17:49:33 -04001458 return gl::error(GL_OUT_OF_MEMORY, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001459 }
Jamie Madill3c0989c2013-10-24 17:49:39 -04001460
1461 setCompleteTexStorage(newRenderTargetStorage);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001462 }
1463 }
1464
Jamie Madille83d1a92013-10-24 17:49:33 -04001465 return (mTexStorage && mTexStorage->isRenderTarget());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001466}
1467
Geoff Lang005df412013-10-16 14:12:50 -04001468void 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 +00001469{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001470 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Geoff Lang005df412013-10-16 14:12:50 -04001471 GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
1472 : GetSizedInternalFormat(format, type, clientVersion);
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001473
1474 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001475
Jamie Madill88f18f42013-09-18 14:36:19 -04001476 Texture::setImage(unpack, type, pixels, mImageArray[faceIndex][level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001477}
1478
Jamie Madill2db197c2013-10-24 17:49:35 -04001479int TextureCubeMap::targetToIndex(GLenum target)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001480{
1481 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
1482 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
1483 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
1484 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
1485 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
1486
Jamie Madill2db197c2013-10-24 17:49:35 -04001487 return target - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001488}
1489
Jamie Madill2db197c2013-10-24 17:49:35 -04001490void TextureCubeMap::redefineImage(int faceIndex, GLint level, GLenum internalformat, GLsizei width, GLsizei height)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001491{
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001492 // If there currently is a corresponding storage texture image, it has these parameters
Jamie Madilld3d2a342013-10-07 10:46:35 -04001493 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1494 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
Geoff Lang005df412013-10-16 14:12:50 -04001495 const GLenum storageFormat = getBaseLevelInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001496
Jamie Madill2db197c2013-10-24 17:49:35 -04001497 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, width, height, 1, false);
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001498
1499 if (mTexStorage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001500 {
Nicolas Capensbf712d02014-03-31 14:23:35 -04001501 const int storageLevels = mTexStorage->getLevelCount();
1502
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001503 if ((level >= storageLevels && storageLevels != 0) ||
1504 width != storageWidth ||
1505 height != storageHeight ||
1506 internalformat != storageFormat) // Discard mismatched storage
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001507 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001508 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001509 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001510 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001511 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001512 mImageArray[faceIndex][level]->markDirty();
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001513 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001514 }
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001515
1516 delete mTexStorage;
1517 mTexStorage = NULL;
1518
1519 mDirtyImages = true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001520 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001521 }
1522}
1523
1524void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1525{
Jamie Madill2db197c2013-10-24 17:49:35 -04001526 int faceIndex = targetToIndex(target);
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001527 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Geoff Lang005df412013-10-16 14:12:50 -04001528 GLenum sizedInternalFormat = IsSizedInternalFormat(format, clientVersion) ? format
1529 : GetSizedInternalFormat(format, GL_UNSIGNED_BYTE, clientVersion);
Jamie Madill2db197c2013-10-24 17:49:35 -04001530 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001531
Jamie Madill2db197c2013-10-24 17:49:35 -04001532 if (!mImageArray[faceIndex][level]->isRenderableFormat())
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();
Jamie Madill2db197c2013-10-24 17:49:35 -04001540 mImageArray[faceIndex][level]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001541
1542 ASSERT(width == height);
1543
Jamie Madill07bb8cf2013-10-24 17:49:44 -04001544 if (width > 0 && isValidFaceLevel(faceIndex, level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001545 {
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +00001546 gl::Rectangle sourceRect;
1547 sourceRect.x = x;
1548 sourceRect.width = width;
1549 sourceRect.y = y;
1550 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001551
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +00001552 mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001553 }
1554 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001555}
1556
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001557void 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 +00001558{
Jamie Madill2db197c2013-10-24 17:49:35 -04001559 int faceIndex = targetToIndex(target);
1560
1561 GLsizei size = mImageArray[faceIndex][level]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001562
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001563 if (xoffset + width > size || yoffset + height > size || zoffset != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001564 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +00001565 return gl::error(GL_INVALID_VALUE);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001566 }
1567
Jamie Madilld3d2a342013-10-07 10:46:35 -04001568 // We can only make our texture storage to a render target if the level we're copying *to* is complete
1569 // and the base level is cube-complete. The base level must be cube complete (common case) because we cannot
1570 // rely on the "getBaseLevel*" methods reliably otherwise.
Jamie Madill2db197c2013-10-24 17:49:35 -04001571 bool canCreateRenderTarget = isFaceLevelComplete(faceIndex, level) && isCubeComplete();
Jamie Madill07edd442013-07-19 16:36:58 -04001572
Jamie Madill2db197c2013-10-24 17:49:35 -04001573 if (!mImageArray[faceIndex][level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001574 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001575 mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001576 mDirtyImages = true;
1577 }
1578 else
1579 {
Jamie Madille83d1a92013-10-24 17:49:33 -04001580 ensureRenderTarget();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001581
Jamie Madill07bb8cf2013-10-24 17:49:44 -04001582 if (isValidFaceLevel(faceIndex, level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001583 {
Jamie Madill169d1112013-10-24 17:49:37 -04001584 updateStorageFaceLevel(faceIndex, level);
Jamie Madill07edd442013-07-19 16:36:58 -04001585
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001586 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1587
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +00001588 gl::Rectangle sourceRect;
1589 sourceRect.x = x;
1590 sourceRect.width = width;
1591 sourceRect.y = y;
1592 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001593
Jamie Madilld3d2a342013-10-07 10:46:35 -04001594 mRenderer->copyImage(source, sourceRect, gl::GetFormat(getBaseLevelInternalFormat(), clientVersion),
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +00001595 xoffset, yoffset, mTexStorage, target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001596 }
1597 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001598}
1599
1600void TextureCubeMap::storage(GLsizei levels, GLenum internalformat, GLsizei size)
1601{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001602 for (int level = 0; level < levels; level++)
1603 {
Geoff Langd3110192013-09-24 11:52:47 -04001604 GLsizei mipSize = std::max(1, size >> level);
Jamie Madill2db197c2013-10-24 17:49:35 -04001605 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001606 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001607 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, mipSize, mipSize, 1, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001608 }
1609 }
1610
1611 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1612 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001613 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001614 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001615 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, GL_NONE, 0, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001616 }
1617 }
1618
Jamie Madill3c0989c2013-10-24 17:49:39 -04001619 mImmutable = true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001620
Nicolas Capensbf712d02014-03-31 14:23:35 -04001621 setCompleteTexStorage(new rx::TextureStorageInterfaceCube(mRenderer, internalformat, IsRenderTargetUsage(mUsage), size, levels));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001622}
1623
1624void TextureCubeMap::generateMipmaps()
1625{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001626 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Geoff Lang98705b72014-03-31 16:00:03 -04001627 int levelCount = mipLevels();
Jamie Madill2db197c2013-10-24 17:49:35 -04001628 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001629 {
Geoff Lang98705b72014-03-31 16:00:03 -04001630 for (int level = 1; level < levelCount; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001631 {
Jamie Madill22f843a2013-10-24 17:49:36 -04001632 int faceLevelSize = (std::max(mImageArray[faceIndex][0]->getWidth() >> level, 1));
1633 redefineImage(faceIndex, level, mImageArray[faceIndex][0]->getInternalFormat(), faceLevelSize, faceLevelSize);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001634 }
1635 }
1636
1637 if (mTexStorage && mTexStorage->isRenderTarget())
1638 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001639 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001640 {
Geoff Lang98705b72014-03-31 16:00:03 -04001641 for (int level = 1; level < levelCount; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001642 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001643 mTexStorage->generateMipmap(faceIndex, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001644
Jamie Madill2db197c2013-10-24 17:49:35 -04001645 mImageArray[faceIndex][level]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001646 }
1647 }
1648 }
1649 else
1650 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001651 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001652 {
Geoff Lang98705b72014-03-31 16:00:03 -04001653 for (int level = 1; level < levelCount; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001654 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001655 mRenderer->generateMipmap(mImageArray[faceIndex][level], mImageArray[faceIndex][level - 1]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001656 }
1657 }
1658 }
1659}
1660
Jamie Madilld3d2a342013-10-07 10:46:35 -04001661const rx::Image *TextureCubeMap::getBaseLevelImage() const
1662{
1663 // Note: if we are not cube-complete, there is no single base level image that can describe all
1664 // cube faces, so this method is only well-defined for a cube-complete base level.
1665 return mImageArray[0][0];
1666}
1667
Jamie Madill2ebab852013-10-24 17:49:42 -04001668rx::TextureStorageInterface *TextureCubeMap::getBaseLevelStorage()
1669{
1670 return mTexStorage;
1671}
1672
Geoff Lang8040f572013-07-25 16:49:54 -04001673Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target, GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001674{
1675 if (!IsCubemapTextureTarget(target))
1676 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +00001677 return gl::error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001678 }
1679
Jamie Madill2db197c2013-10-24 17:49:35 -04001680 int faceIndex = targetToIndex(target);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001681
Jamie Madill2db197c2013-10-24 17:49:35 -04001682 Renderbuffer *renderBuffer = mRenderbufferProxies.get(level, faceIndex);
Geoff Lang8040f572013-07-25 16:49:54 -04001683 if (!renderBuffer)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001684 {
Geoff Lang8040f572013-07-25 16:49:54 -04001685 renderBuffer = new Renderbuffer(mRenderer, id(), new RenderbufferTextureCubeMap(this, target, level));
Jamie Madill2db197c2013-10-24 17:49:35 -04001686 mRenderbufferProxies.add(level, faceIndex, renderBuffer);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001687 }
1688
Geoff Lang8040f572013-07-25 16:49:54 -04001689 return renderBuffer;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001690}
1691
Jamie Madill2db197c2013-10-24 17:49:35 -04001692unsigned int TextureCubeMap::getRenderTargetSerial(GLenum target, GLint level)
Geoff Lang8040f572013-07-25 16:49:54 -04001693{
Jamie Madill2db197c2013-10-24 17:49:35 -04001694 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(target, level) : 0);
Geoff Lang8040f572013-07-25 16:49:54 -04001695}
1696
1697rx::RenderTarget *TextureCubeMap::getRenderTarget(GLenum target, GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001698{
1699 ASSERT(IsCubemapTextureTarget(target));
1700
1701 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04001702 if (!ensureRenderTarget())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001703 {
1704 return NULL;
1705 }
1706
Jamie Madill169d1112013-10-24 17:49:37 -04001707 updateStorageFaceLevel(targetToIndex(target), level);
Geoff Lang8040f572013-07-25 16:49:54 -04001708
1709 // ensure this is NOT a depth texture
1710 if (isDepth(target, level))
1711 {
1712 return NULL;
1713 }
1714
1715 return mTexStorage->getRenderTarget(target, level);
1716}
1717
1718rx::RenderTarget *TextureCubeMap::getDepthStencil(GLenum target, GLint level)
1719{
1720 ASSERT(IsCubemapTextureTarget(target));
1721
1722 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04001723 if (!ensureRenderTarget())
Geoff Lang8040f572013-07-25 16:49:54 -04001724 {
1725 return NULL;
1726 }
1727
Jamie Madill169d1112013-10-24 17:49:37 -04001728 updateStorageFaceLevel(targetToIndex(target), level);
Geoff Lang8040f572013-07-25 16:49:54 -04001729
1730 // ensure this is a depth texture
1731 if (!isDepth(target, level))
1732 {
1733 return NULL;
1734 }
1735
1736 return mTexStorage->getRenderTarget(target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001737}
1738
Jamie Madill07bb8cf2013-10-24 17:49:44 -04001739bool TextureCubeMap::isValidFaceLevel(int faceIndex, int level) const
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +00001740{
Nicolas Capensbf712d02014-03-31 14:23:35 -04001741 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +00001742}
1743
Geoff Lang4907f2c2013-07-25 12:53:57 -04001744Texture3D::Texture3D(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_3D)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001745{
1746 mTexStorage = NULL;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001747
1748 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1749 {
1750 mImageArray[i] = renderer->createImage();
1751 }
1752}
1753
1754Texture3D::~Texture3D()
1755{
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001756 delete mTexStorage;
1757 mTexStorage = NULL;
1758
1759 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1760 {
1761 delete mImageArray[i];
1762 }
1763}
1764
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001765GLsizei Texture3D::getWidth(GLint level) const
1766{
1767 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getWidth() : 0;
1768}
1769
1770GLsizei Texture3D::getHeight(GLint level) const
1771{
1772 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getHeight() : 0;
1773}
1774
1775GLsizei Texture3D::getDepth(GLint level) const
1776{
1777 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getDepth() : 0;
1778}
1779
1780GLenum Texture3D::getInternalFormat(GLint level) const
1781{
1782 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getInternalFormat() : GL_NONE;
1783}
1784
1785GLenum Texture3D::getActualFormat(GLint level) const
1786{
Geoff Langcbf727a2014-02-10 12:50:45 -05001787 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getActualFormat() : GL_NONE;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001788}
1789
1790bool Texture3D::isCompressed(GLint level) const
1791{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001792 return IsFormatCompressed(getInternalFormat(level), mRenderer->getCurrentClientVersion());
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001793}
1794
1795bool Texture3D::isDepth(GLint level) const
1796{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001797 return GetDepthBits(getInternalFormat(level), mRenderer->getCurrentClientVersion()) > 0;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001798}
1799
Geoff Lang005df412013-10-16 14:12:50 -04001800void 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 +00001801{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001802 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Geoff Lang005df412013-10-16 14:12:50 -04001803 GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
1804 : GetSizedInternalFormat(format, type, clientVersion);
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001805 redefineImage(level, sizedInternalFormat, width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001806
Jamie Madilla2d4e552013-10-10 15:12:01 -04001807 bool fastUnpacked = false;
1808
1809 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1810 if (isFastUnpackable(unpack, sizedInternalFormat))
1811 {
1812 // Will try to create RT storage if it does not exist
1813 rx::RenderTarget *destRenderTarget = getRenderTarget(level);
1814 Box destArea(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1815
1816 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget))
1817 {
1818 // Ensure we don't overwrite our newly initialized data
1819 mImageArray[level]->markClean();
1820
1821 fastUnpacked = true;
1822 }
1823 }
1824
1825 if (!fastUnpacked)
1826 {
1827 Texture::setImage(unpack, type, pixels, mImageArray[level]);
1828 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001829}
1830
1831void Texture3D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
1832{
1833 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1834 redefineImage(level, format, width, height, depth);
1835
1836 Texture::setCompressedImage(imageSize, pixels, mImageArray[level]);
1837}
1838
Jamie Madill88f18f42013-09-18 14:36:19 -04001839void 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 +00001840{
Jamie Madillba4f10a2013-10-10 15:12:20 -04001841 bool fastUnpacked = false;
1842
1843 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1844 if (isFastUnpackable(unpack, getInternalFormat(level)))
1845 {
1846 rx::RenderTarget *destRenderTarget = getRenderTarget(level);
1847 Box destArea(xoffset, yoffset, zoffset, width, height, depth);
1848
1849 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, destRenderTarget))
1850 {
1851 // Ensure we don't overwrite our newly initialized data
1852 mImageArray[level]->markClean();
1853
1854 fastUnpacked = true;
1855 }
1856 }
1857
1858 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 +00001859 {
1860 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1861 }
1862}
1863
1864void Texture3D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
1865{
1866 if (Texture::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth, format, imageSize, pixels, mImageArray[level]))
1867 {
1868 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1869 }
1870}
1871
1872void Texture3D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
1873{
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001874 for (int level = 0; level < levels; level++)
1875 {
Jamie Madille664e202013-10-24 17:49:40 -04001876 GLsizei levelWidth = std::max(1, width >> level);
1877 GLsizei levelHeight = std::max(1, height >> level);
1878 GLsizei levelDepth = std::max(1, depth >> level);
1879 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, levelWidth, levelHeight, levelDepth, true);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001880 }
1881
1882 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1883 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001884 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, GL_NONE, 0, 0, 0, true);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001885 }
1886
Jamie Madille664e202013-10-24 17:49:40 -04001887 mImmutable = true;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001888
Nicolas Capensbf712d02014-03-31 14:23:35 -04001889 setCompleteTexStorage(new rx::TextureStorageInterface3D(mRenderer, internalformat, IsRenderTargetUsage(mUsage), width, height, depth, levels));
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001890}
1891
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001892void Texture3D::generateMipmaps()
1893{
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001894 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Geoff Lang98705b72014-03-31 16:00:03 -04001895 int levelCount = mipLevels();
1896 for (int level = 1; level < levelCount; level++)
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001897 {
Jamie Madill22f843a2013-10-24 17:49:36 -04001898 redefineImage(level, getBaseLevelInternalFormat(),
1899 std::max(getBaseLevelWidth() >> level, 1),
1900 std::max(getBaseLevelHeight() >> level, 1),
1901 std::max(getBaseLevelDepth() >> level, 1));
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001902 }
1903
1904 if (mTexStorage && mTexStorage->isRenderTarget())
1905 {
Geoff Lang98705b72014-03-31 16:00:03 -04001906 for (int level = 1; level < levelCount; level++)
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001907 {
Jamie Madill22f843a2013-10-24 17:49:36 -04001908 mTexStorage->generateMipmap(level);
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001909
Jamie Madill22f843a2013-10-24 17:49:36 -04001910 mImageArray[level]->markClean();
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001911 }
1912 }
1913 else
1914 {
Geoff Lang98705b72014-03-31 16:00:03 -04001915 for (int level = 1; level < levelCount; level++)
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001916 {
Jamie Madill22f843a2013-10-24 17:49:36 -04001917 mRenderer->generateMipmap(mImageArray[level], mImageArray[level - 1]);
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001918 }
1919 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001920}
1921
Jamie Madilld3d2a342013-10-07 10:46:35 -04001922const rx::Image *Texture3D::getBaseLevelImage() const
1923{
1924 return mImageArray[0];
1925}
1926
Jamie Madill2ebab852013-10-24 17:49:42 -04001927rx::TextureStorageInterface *Texture3D::getBaseLevelStorage()
1928{
1929 return mTexStorage;
1930}
1931
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001932void Texture3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1933{
1934 if (xoffset + width > mImageArray[level]->getWidth() || yoffset + height > mImageArray[level]->getHeight() || zoffset >= mImageArray[level]->getDepth())
1935 {
1936 return gl::error(GL_INVALID_VALUE);
1937 }
1938
Jamie Madill07edd442013-07-19 16:36:58 -04001939 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
1940 // the current level we're copying to is defined (with appropriate format, width & height)
1941 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
1942
1943 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001944 {
1945 mImageArray[level]->copy(xoffset, yoffset, zoffset, x, y, width, height, source);
1946 mDirtyImages = true;
1947 }
1948 else
1949 {
Jamie Madille83d1a92013-10-24 17:49:33 -04001950 ensureRenderTarget();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001951
Jamie Madill07bb8cf2013-10-24 17:49:44 -04001952 if (isValidLevel(level))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001953 {
Jamie Madill169d1112013-10-24 17:49:37 -04001954 updateStorageLevel(level);
Jamie Madill07edd442013-07-19 16:36:58 -04001955
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001956 gl::Rectangle sourceRect;
1957 sourceRect.x = x;
1958 sourceRect.width = width;
1959 sourceRect.y = y;
1960 sourceRect.height = height;
1961
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001962 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1963
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001964 mRenderer->copyImage(source, sourceRect,
Jamie Madilld3d2a342013-10-07 10:46:35 -04001965 gl::GetFormat(getBaseLevelInternalFormat(), clientVersion),
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001966 xoffset, yoffset, zoffset, mTexStorage, level);
1967 }
1968 }
1969}
1970
Jamie Madillf8989902013-07-19 16:36:58 -04001971bool Texture3D::isSamplerComplete(const SamplerState &samplerState) const
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001972{
Jamie Madilld3d2a342013-10-07 10:46:35 -04001973 GLsizei width = getBaseLevelWidth();
1974 GLsizei height = getBaseLevelHeight();
1975 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001976
1977 if (width <= 0 || height <= 0 || depth <= 0)
1978 {
1979 return false;
1980 }
1981
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001982 if (!IsTextureFilteringSupported(getInternalFormat(0), mRenderer))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001983 {
Jamie Madillf8989902013-07-19 16:36:58 -04001984 if (samplerState.magFilter != GL_NEAREST ||
1985 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001986 {
1987 return false;
1988 }
1989 }
1990
Jamie Madillf8989902013-07-19 16:36:58 -04001991 if (IsMipmapFiltered(samplerState) && !isMipmapComplete())
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001992 {
1993 return false;
1994 }
1995
1996 return true;
1997}
1998
1999bool Texture3D::isMipmapComplete() const
2000{
Geoff Lang98705b72014-03-31 16:00:03 -04002001 int levelCount = mipLevels();
Jamie Madill07edd442013-07-19 16:36:58 -04002002
Geoff Lang98705b72014-03-31 16:00:03 -04002003 for (int level = 0; level < levelCount; level++)
Jamie Madill07edd442013-07-19 16:36:58 -04002004 {
2005 if (!isLevelComplete(level))
2006 {
2007 return false;
2008 }
2009 }
2010
2011 return true;
2012}
2013
2014bool Texture3D::isLevelComplete(int level) const
2015{
2016 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
2017
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002018 if (isImmutable())
2019 {
2020 return true;
2021 }
2022
Jamie Madilld3d2a342013-10-07 10:46:35 -04002023 GLsizei width = getBaseLevelWidth();
2024 GLsizei height = getBaseLevelHeight();
2025 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002026
2027 if (width <= 0 || height <= 0 || depth <= 0)
2028 {
2029 return false;
2030 }
2031
Jamie Madill07edd442013-07-19 16:36:58 -04002032 if (level == 0)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002033 {
Jamie Madill07edd442013-07-19 16:36:58 -04002034 return true;
2035 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002036
Jamie Madill07edd442013-07-19 16:36:58 -04002037 rx::Image *levelImage = mImageArray[level];
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002038
Jamie Madilld3d2a342013-10-07 10:46:35 -04002039 if (levelImage->getInternalFormat() != getBaseLevelInternalFormat())
Jamie Madill07edd442013-07-19 16:36:58 -04002040 {
2041 return false;
2042 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002043
Jamie Madill07edd442013-07-19 16:36:58 -04002044 if (levelImage->getWidth() != std::max(1, width >> level))
2045 {
2046 return false;
2047 }
2048
2049 if (levelImage->getHeight() != std::max(1, height >> level))
2050 {
2051 return false;
2052 }
2053
2054 if (levelImage->getDepth() != std::max(1, depth >> level))
2055 {
2056 return false;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002057 }
2058
2059 return true;
2060}
2061
Geoff Lang8040f572013-07-25 16:49:54 -04002062Renderbuffer *Texture3D::getRenderbuffer(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002063{
Geoff Lang8040f572013-07-25 16:49:54 -04002064 Renderbuffer *renderBuffer = mRenderbufferProxies.get(level, layer);
2065 if (!renderBuffer)
2066 {
Geoff Langd5d8e392013-07-25 16:53:03 -04002067 renderBuffer = new Renderbuffer(mRenderer, id(), new RenderbufferTexture3DLayer(this, level, layer));
2068 mRenderbufferProxies.add(level, 0, renderBuffer);
Geoff Lang8040f572013-07-25 16:49:54 -04002069 }
2070
2071 return renderBuffer;
2072}
2073
2074unsigned int Texture3D::getRenderTargetSerial(GLint level, GLint layer)
2075{
Jamie Madille83d1a92013-10-24 17:49:33 -04002076 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(level, layer) : 0);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002077}
2078
Jamie Madill07bb8cf2013-10-24 17:49:44 -04002079bool Texture3D::isValidLevel(int level) const
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002080{
Nicolas Capensbf712d02014-03-31 14:23:35 -04002081 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002082}
2083
Jamie Madill73b5d062013-10-24 17:49:38 -04002084void Texture3D::initializeStorage(bool renderTarget)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002085{
Jamie Madille664e202013-10-24 17:49:40 -04002086 // Only initialize the first time this texture is used as a render target or shader resource
2087 if (mTexStorage)
2088 {
2089 return;
2090 }
2091
2092 // do not attempt to create storage for nonexistant data
2093 if (!isLevelComplete(0))
2094 {
2095 return;
2096 }
2097
2098 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
2099
2100 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
2101 ASSERT(mTexStorage);
2102
2103 // flush image data to the storage
2104 updateStorage();
2105}
2106
2107rx::TextureStorageInterface3D *Texture3D::createCompleteStorage(bool renderTarget) const
2108{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002109 GLsizei width = getBaseLevelWidth();
2110 GLsizei height = getBaseLevelHeight();
2111 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002112
Jamie Madille664e202013-10-24 17:49:40 -04002113 ASSERT(width > 0 && height > 0 && depth > 0);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002114
Jamie Madille664e202013-10-24 17:49:40 -04002115 // use existing storage level count, when previously specified by TexStorage*D
Nicolas Capensbf712d02014-03-31 14:23:35 -04002116 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, depth));
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002117
Nicolas Capensbf712d02014-03-31 14:23:35 -04002118 return new rx::TextureStorageInterface3D(mRenderer, getBaseLevelInternalFormat(), renderTarget, width, height, depth, levels);
Jamie Madille664e202013-10-24 17:49:40 -04002119}
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002120
Jamie Madille664e202013-10-24 17:49:40 -04002121void Texture3D::setCompleteTexStorage(rx::TextureStorageInterface3D *newCompleteTexStorage)
2122{
2123 SafeDelete(mTexStorage);
2124 mTexStorage = newCompleteTexStorage;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002125 mDirtyImages = true;
Jamie Madille664e202013-10-24 17:49:40 -04002126
2127 // We do not support managed 3D storage, as that is D3D9/ES2-only
2128 ASSERT(!mTexStorage->isManaged());
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002129}
2130
Jamie Madill169d1112013-10-24 17:49:37 -04002131void Texture3D::updateStorage()
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002132{
Jamie Madill4cfff5f2013-10-24 17:49:46 -04002133 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002134 {
Jamie Madilld9b9a502013-10-10 17:46:13 -04002135 if (isLevelComplete(level))
2136 {
Jamie Madill169d1112013-10-24 17:49:37 -04002137 updateStorageLevel(level);
Jamie Madilld9b9a502013-10-10 17:46:13 -04002138 }
Jamie Madill07edd442013-07-19 16:36:58 -04002139 }
2140}
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002141
Jamie Madill169d1112013-10-24 17:49:37 -04002142void Texture3D::updateStorageLevel(int level)
Jamie Madill07edd442013-07-19 16:36:58 -04002143{
2144 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
Jamie Madillaee7ad82013-10-10 16:07:32 -04002145 ASSERT(isLevelComplete(level));
Jamie Madill07edd442013-07-19 16:36:58 -04002146
Jamie Madillaee7ad82013-10-10 16:07:32 -04002147 if (mImageArray[level]->isDirty())
Jamie Madill07edd442013-07-19 16:36:58 -04002148 {
Jamie Madillaee7ad82013-10-10 16:07:32 -04002149 commitRect(level, 0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002150 }
2151}
2152
Jamie Madille83d1a92013-10-24 17:49:33 -04002153bool Texture3D::ensureRenderTarget()
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002154{
Jamie Madille664e202013-10-24 17:49:40 -04002155 initializeStorage(true);
2156
2157 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0 && getBaseLevelDepth() > 0)
Jamie Madille83d1a92013-10-24 17:49:33 -04002158 {
Jamie Madille664e202013-10-24 17:49:40 -04002159 ASSERT(mTexStorage);
2160 if (!mTexStorage->isRenderTarget())
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002161 {
Jamie Madille664e202013-10-24 17:49:40 -04002162 rx::TextureStorageInterface3D *newRenderTargetStorage = createCompleteStorage(true);
2163
2164 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002165 {
Jamie Madille664e202013-10-24 17:49:40 -04002166 delete newRenderTargetStorage;
Jamie Madille83d1a92013-10-24 17:49:33 -04002167 return gl::error(GL_OUT_OF_MEMORY, false);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002168 }
Jamie Madille664e202013-10-24 17:49:40 -04002169
2170 setCompleteTexStorage(newRenderTargetStorage);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002171 }
2172 }
2173
Jamie Madille83d1a92013-10-24 17:49:33 -04002174 return (mTexStorage && mTexStorage->isRenderTarget());
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002175}
2176
Jamie Madilla2d4e552013-10-10 15:12:01 -04002177rx::RenderTarget *Texture3D::getRenderTarget(GLint level)
2178{
2179 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04002180 if (!ensureRenderTarget())
Jamie Madilla2d4e552013-10-10 15:12:01 -04002181 {
2182 return NULL;
2183 }
2184
Jamie Madill169d1112013-10-24 17:49:37 -04002185 updateStorageLevel(level);
Jamie Madilla2d4e552013-10-10 15:12:01 -04002186
2187 // ensure this is NOT a depth texture
2188 if (isDepth(level))
2189 {
2190 return NULL;
2191 }
2192
2193 return mTexStorage->getRenderTarget(level);
2194}
2195
Geoff Lang8040f572013-07-25 16:49:54 -04002196rx::RenderTarget *Texture3D::getRenderTarget(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002197{
Geoff Lang8040f572013-07-25 16:49:54 -04002198 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04002199 if (!ensureRenderTarget())
Geoff Lang8040f572013-07-25 16:49:54 -04002200 {
2201 return NULL;
2202 }
2203
Jamie Madill169d1112013-10-24 17:49:37 -04002204 updateStorage();
Geoff Lang8040f572013-07-25 16:49:54 -04002205
2206 // ensure this is NOT a depth texture
2207 if (isDepth(level))
2208 {
2209 return NULL;
2210 }
2211
2212 return mTexStorage->getRenderTarget(level, layer);
2213}
2214
2215rx::RenderTarget *Texture3D::getDepthStencil(GLint level, GLint layer)
2216{
2217 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04002218 if (!ensureRenderTarget())
Geoff Lang8040f572013-07-25 16:49:54 -04002219 {
2220 return NULL;
2221 }
2222
Jamie Madill169d1112013-10-24 17:49:37 -04002223 updateStorageLevel(level);
Geoff Lang8040f572013-07-25 16:49:54 -04002224
2225 // ensure this is a depth texture
2226 if (!isDepth(level))
2227 {
2228 return NULL;
2229 }
2230
2231 return mTexStorage->getRenderTarget(level, layer);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002232}
2233
Geoff Lang005df412013-10-16 14:12:50 -04002234void Texture3D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002235{
2236 // If there currently is a corresponding storage texture image, it has these parameters
Jamie Madilld3d2a342013-10-07 10:46:35 -04002237 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2238 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
2239 const int storageDepth = std::max(1, getBaseLevelDepth() >> level);
Geoff Lang005df412013-10-16 14:12:50 -04002240 const GLenum storageFormat = getBaseLevelInternalFormat();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002241
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00002242 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, false);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002243
2244 if (mTexStorage)
2245 {
Nicolas Capensbf712d02014-03-31 14:23:35 -04002246 const int storageLevels = mTexStorage->getLevelCount();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002247
2248 if ((level >= storageLevels && storageLevels != 0) ||
2249 width != storageWidth ||
2250 height != storageHeight ||
2251 depth != storageDepth ||
2252 internalformat != storageFormat) // Discard mismatched storage
2253 {
2254 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
2255 {
2256 mImageArray[i]->markDirty();
2257 }
2258
2259 delete mTexStorage;
2260 mTexStorage = NULL;
2261 mDirtyImages = true;
2262 }
2263 }
2264}
2265
2266void Texture3D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth)
2267{
Jamie Madill07bb8cf2013-10-24 17:49:44 -04002268 if (isValidLevel(level))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002269 {
2270 rx::Image *image = mImageArray[level];
Jamie Madill169d1112013-10-24 17:49:37 -04002271 if (image->copyToStorage(mTexStorage, level, xoffset, yoffset, zoffset, width, height, depth))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002272 {
2273 image->markClean();
2274 }
2275 }
2276}
2277
Geoff Lang4907f2c2013-07-25 12:53:57 -04002278Texture2DArray::Texture2DArray(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_2D_ARRAY)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002279{
2280 mTexStorage = NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002281
2282 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2283 {
2284 mLayerCounts[level] = 0;
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002285 mImageArray[level] = NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002286 }
2287}
2288
2289Texture2DArray::~Texture2DArray()
2290{
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002291 delete mTexStorage;
2292 mTexStorage = NULL;
Jamie Madill884a4622013-10-24 17:49:41 -04002293
2294 deleteImages();
2295}
2296
2297void Texture2DArray::deleteImages()
2298{
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002299 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2300 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002301 for (int layer = 0; layer < mLayerCounts[level]; ++layer)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002302 {
2303 delete mImageArray[level][layer];
2304 }
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002305 delete[] mImageArray[level];
Jamie Madill884a4622013-10-24 17:49:41 -04002306 mImageArray[level] = NULL;
2307 mLayerCounts[level] = 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002308 }
2309}
2310
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002311GLsizei Texture2DArray::getWidth(GLint level) const
2312{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002313 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 +00002314}
2315
2316GLsizei Texture2DArray::getHeight(GLint level) const
2317{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002318 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 +00002319}
2320
Jamie Madillb8f8b892014-01-07 10:12:50 -05002321GLsizei Texture2DArray::getLayers(GLint level) const
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002322{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002323 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mLayerCounts[level] : 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002324}
2325
2326GLenum Texture2DArray::getInternalFormat(GLint level) const
2327{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002328 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 +00002329}
2330
2331GLenum Texture2DArray::getActualFormat(GLint level) const
2332{
Geoff Langcbf727a2014-02-10 12:50:45 -05002333 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 +00002334}
2335
2336bool Texture2DArray::isCompressed(GLint level) const
2337{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00002338 return IsFormatCompressed(getInternalFormat(level), mRenderer->getCurrentClientVersion());
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002339}
2340
2341bool Texture2DArray::isDepth(GLint level) const
2342{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00002343 return GetDepthBits(getInternalFormat(level), mRenderer->getCurrentClientVersion()) > 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002344}
2345
Geoff Lang005df412013-10-16 14:12:50 -04002346void 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 +00002347{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00002348 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Geoff Lang005df412013-10-16 14:12:50 -04002349 GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
2350 : GetSizedInternalFormat(format, type, clientVersion);
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00002351 redefineImage(level, sizedInternalFormat, width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002352
Jamie Madill88f18f42013-09-18 14:36:19 -04002353 GLsizei inputDepthPitch = gl::GetDepthPitch(sizedInternalFormat, type, clientVersion, width, height, unpack.alignment);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002354
2355 for (int i = 0; i < depth; i++)
2356 {
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002357 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
Jamie Madill88f18f42013-09-18 14:36:19 -04002358 Texture::setImage(unpack, type, layerPixels, mImageArray[level][i]);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002359 }
2360}
2361
2362void Texture2DArray::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
2363{
2364 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
2365 redefineImage(level, format, width, height, depth);
2366
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002367 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2368 GLsizei inputDepthPitch = gl::GetDepthPitch(format, GL_UNSIGNED_BYTE, clientVersion, width, height, 1);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002369
2370 for (int i = 0; i < depth; i++)
2371 {
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002372 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002373 Texture::setCompressedImage(imageSize, layerPixels, mImageArray[level][i]);
2374 }
2375}
2376
Jamie Madill88f18f42013-09-18 14:36:19 -04002377void 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 +00002378{
Geoff Lang005df412013-10-16 14:12:50 -04002379 GLenum internalformat = getInternalFormat(level);
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002380 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Jamie Madill88f18f42013-09-18 14:36:19 -04002381 GLsizei inputDepthPitch = gl::GetDepthPitch(internalformat, type, clientVersion, width, height, unpack.alignment);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002382
2383 for (int i = 0; i < depth; i++)
2384 {
2385 int layer = zoffset + i;
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002386 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002387
Jamie Madill88f18f42013-09-18 14:36:19 -04002388 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 +00002389 {
2390 commitRect(level, xoffset, yoffset, layer, width, height);
2391 }
2392 }
2393}
2394
2395void Texture2DArray::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
2396{
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002397 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2398 GLsizei inputDepthPitch = gl::GetDepthPitch(format, GL_UNSIGNED_BYTE, clientVersion, width, height, 1);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002399
2400 for (int i = 0; i < depth; i++)
2401 {
2402 int layer = zoffset + i;
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002403 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002404
2405 if (Texture::subImageCompressed(xoffset, yoffset, zoffset, width, height, 1, format, imageSize, layerPixels, mImageArray[level][layer]))
2406 {
2407 commitRect(level, xoffset, yoffset, layer, width, height);
2408 }
2409 }
2410}
2411
2412void Texture2DArray::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2413{
Jamie Madill884a4622013-10-24 17:49:41 -04002414 deleteImages();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002415
2416 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2417 {
Jamie Madill884a4622013-10-24 17:49:41 -04002418 GLsizei levelWidth = std::max(1, width >> level);
2419 GLsizei levelHeight = std::max(1, height >> level);
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002420
Jamie Madill884a4622013-10-24 17:49:41 -04002421 mLayerCounts[level] = (level < levels ? depth : 0);
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002422
Jamie Madill884a4622013-10-24 17:49:41 -04002423 if (mLayerCounts[level] > 0)
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002424 {
2425 // Create new images for this level
Jamie Madill884a4622013-10-24 17:49:41 -04002426 mImageArray[level] = new rx::Image*[mLayerCounts[level]];
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002427
2428 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002429 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002430 mImageArray[level][layer] = mRenderer->createImage();
2431 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, levelWidth,
2432 levelHeight, 1, true);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002433 }
2434 }
2435 }
2436
Jamie Madill884a4622013-10-24 17:49:41 -04002437 mImmutable = true;
Nicolas Capensbf712d02014-03-31 14:23:35 -04002438 setCompleteTexStorage(new rx::TextureStorageInterface2DArray(mRenderer, internalformat, IsRenderTargetUsage(mUsage), width, height, depth, levels));
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002439}
2440
2441void Texture2DArray::generateMipmaps()
2442{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002443 int baseWidth = getBaseLevelWidth();
2444 int baseHeight = getBaseLevelHeight();
2445 int baseDepth = getBaseLevelDepth();
2446 GLenum baseFormat = getBaseLevelInternalFormat();
2447
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00002448 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Geoff Lang98705b72014-03-31 16:00:03 -04002449 int levelCount = mipLevels();
2450 for (int level = 1; level < levelCount; level++)
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00002451 {
Jamie Madill22f843a2013-10-24 17:49:36 -04002452 redefineImage(level, baseFormat, std::max(baseWidth >> level, 1), std::max(baseHeight >> level, 1), baseDepth);
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00002453 }
2454
2455 if (mTexStorage && mTexStorage->isRenderTarget())
2456 {
Geoff Lang98705b72014-03-31 16:00:03 -04002457 for (int level = 1; level < levelCount; level++)
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00002458 {
2459 mTexStorage->generateMipmap(level);
2460
2461 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2462 {
2463 mImageArray[level][layer]->markClean();
2464 }
2465 }
2466 }
2467 else
2468 {
Geoff Lang98705b72014-03-31 16:00:03 -04002469 for (int level = 1; level < levelCount; level++)
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00002470 {
2471 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2472 {
2473 mRenderer->generateMipmap(mImageArray[level][layer], mImageArray[level - 1][layer]);
2474 }
2475 }
2476 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002477}
2478
Jamie Madilld3d2a342013-10-07 10:46:35 -04002479const rx::Image *Texture2DArray::getBaseLevelImage() const
2480{
Jamie Madill152ed092013-10-09 17:01:15 -04002481 return (mLayerCounts[0] > 0 ? mImageArray[0][0] : NULL);
Jamie Madilld3d2a342013-10-07 10:46:35 -04002482}
2483
Jamie Madill2ebab852013-10-24 17:49:42 -04002484rx::TextureStorageInterface *Texture2DArray::getBaseLevelStorage()
2485{
2486 return mTexStorage;
2487}
2488
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002489void Texture2DArray::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
2490{
Jamie Madillb8f8b892014-01-07 10:12:50 -05002491 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 +00002492 {
2493 return gl::error(GL_INVALID_VALUE);
2494 }
2495
Jamie Madill07edd442013-07-19 16:36:58 -04002496 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
2497 // the current level we're copying to is defined (with appropriate format, width & height)
2498 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
2499
2500 if (!mImageArray[level][0]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002501 {
2502 mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, x, y, width, height, source);
2503 mDirtyImages = true;
2504 }
2505 else
2506 {
Jamie Madille83d1a92013-10-24 17:49:33 -04002507 ensureRenderTarget();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002508
Jamie Madill07bb8cf2013-10-24 17:49:44 -04002509 if (isValidLevel(level))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002510 {
Jamie Madill169d1112013-10-24 17:49:37 -04002511 updateStorageLevel(level);
Jamie Madill07edd442013-07-19 16:36:58 -04002512
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002513 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2514
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002515 gl::Rectangle sourceRect;
2516 sourceRect.x = x;
2517 sourceRect.width = width;
2518 sourceRect.y = y;
2519 sourceRect.height = height;
2520
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002521 mRenderer->copyImage(source, sourceRect, gl::GetFormat(getInternalFormat(0), clientVersion),
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002522 xoffset, yoffset, zoffset, mTexStorage, level);
2523 }
2524 }
2525}
2526
Jamie Madillf8989902013-07-19 16:36:58 -04002527bool Texture2DArray::isSamplerComplete(const SamplerState &samplerState) const
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002528{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002529 GLsizei width = getBaseLevelWidth();
2530 GLsizei height = getBaseLevelHeight();
Jamie Madillb8f8b892014-01-07 10:12:50 -05002531 GLsizei depth = getLayers(0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002532
2533 if (width <= 0 || height <= 0 || depth <= 0)
2534 {
2535 return false;
2536 }
2537
Jamie Madilld3d2a342013-10-07 10:46:35 -04002538 if (!IsTextureFilteringSupported(getBaseLevelInternalFormat(), mRenderer))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002539 {
Jamie Madillf8989902013-07-19 16:36:58 -04002540 if (samplerState.magFilter != GL_NEAREST ||
2541 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002542 {
2543 return false;
2544 }
2545 }
2546
Jamie Madillf8989902013-07-19 16:36:58 -04002547 if (IsMipmapFiltered(samplerState) && !isMipmapComplete())
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002548 {
2549 return false;
2550 }
2551
2552 return true;
2553}
2554
2555bool Texture2DArray::isMipmapComplete() const
2556{
Geoff Lang98705b72014-03-31 16:00:03 -04002557 int levelCount = mipLevels();
Jamie Madill07edd442013-07-19 16:36:58 -04002558
Geoff Lang98705b72014-03-31 16:00:03 -04002559 for (int level = 1; level < levelCount; level++)
Jamie Madill07edd442013-07-19 16:36:58 -04002560 {
2561 if (!isLevelComplete(level))
2562 {
2563 return false;
2564 }
2565 }
2566
2567 return true;
2568}
2569
2570bool Texture2DArray::isLevelComplete(int level) const
2571{
Jamie Madillb8f8b892014-01-07 10:12:50 -05002572 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray));
Jamie Madill07edd442013-07-19 16:36:58 -04002573
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002574 if (isImmutable())
2575 {
2576 return true;
2577 }
2578
Jamie Madilld3d2a342013-10-07 10:46:35 -04002579 GLsizei width = getBaseLevelWidth();
2580 GLsizei height = getBaseLevelHeight();
Jamie Madillb8f8b892014-01-07 10:12:50 -05002581 GLsizei layers = getLayers(0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002582
Jamie Madillb8f8b892014-01-07 10:12:50 -05002583 if (width <= 0 || height <= 0 || layers <= 0)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002584 {
2585 return false;
2586 }
2587
Jamie Madill07edd442013-07-19 16:36:58 -04002588 if (level == 0)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002589 {
Jamie Madill07edd442013-07-19 16:36:58 -04002590 return true;
2591 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002592
Jamie Madill07edd442013-07-19 16:36:58 -04002593 if (getInternalFormat(level) != getInternalFormat(0))
2594 {
2595 return false;
2596 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002597
Jamie Madill07edd442013-07-19 16:36:58 -04002598 if (getWidth(level) != std::max(1, width >> level))
2599 {
2600 return false;
2601 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002602
Jamie Madill07edd442013-07-19 16:36:58 -04002603 if (getHeight(level) != std::max(1, height >> level))
2604 {
2605 return false;
2606 }
2607
Jamie Madillb8f8b892014-01-07 10:12:50 -05002608 if (getLayers(level) != layers)
Jamie Madill07edd442013-07-19 16:36:58 -04002609 {
2610 return false;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002611 }
2612
2613 return true;
2614}
2615
Geoff Lang8040f572013-07-25 16:49:54 -04002616Renderbuffer *Texture2DArray::getRenderbuffer(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002617{
Geoff Lang8040f572013-07-25 16:49:54 -04002618 Renderbuffer *renderBuffer = mRenderbufferProxies.get(level, layer);
2619 if (!renderBuffer)
2620 {
Geoff Langd5d8e392013-07-25 16:53:03 -04002621 renderBuffer = new Renderbuffer(mRenderer, id(), new RenderbufferTexture2DArrayLayer(this, level, layer));
2622 mRenderbufferProxies.add(level, 0, renderBuffer);
Geoff Lang8040f572013-07-25 16:49:54 -04002623 }
2624
2625 return renderBuffer;
2626}
2627
Jamie Madille83d1a92013-10-24 17:49:33 -04002628unsigned int Texture2DArray::getRenderTargetSerial(GLint level, GLint layer)
Geoff Lang8040f572013-07-25 16:49:54 -04002629{
Jamie Madille83d1a92013-10-24 17:49:33 -04002630 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(level, layer) : 0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002631}
2632
Jamie Madill07bb8cf2013-10-24 17:49:44 -04002633bool Texture2DArray::isValidLevel(int level) const
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002634{
Nicolas Capensbf712d02014-03-31 14:23:35 -04002635 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002636}
2637
Jamie Madill73b5d062013-10-24 17:49:38 -04002638void Texture2DArray::initializeStorage(bool renderTarget)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002639{
Jamie Madill884a4622013-10-24 17:49:41 -04002640 // Only initialize the first time this texture is used as a render target or shader resource
2641 if (mTexStorage)
2642 {
2643 return;
2644 }
2645
2646 // do not attempt to create storage for nonexistant data
2647 if (!isLevelComplete(0))
2648 {
2649 return;
2650 }
2651
2652 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
2653
2654 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
2655 ASSERT(mTexStorage);
2656
2657 // flush image data to the storage
2658 updateStorage();
2659}
2660
2661rx::TextureStorageInterface2DArray *Texture2DArray::createCompleteStorage(bool renderTarget) const
2662{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002663 GLsizei width = getBaseLevelWidth();
2664 GLsizei height = getBaseLevelHeight();
Jamie Madillb8f8b892014-01-07 10:12:50 -05002665 GLsizei depth = getLayers(0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002666
Jamie Madill884a4622013-10-24 17:49:41 -04002667 ASSERT(width > 0 && height > 0 && depth > 0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002668
Jamie Madill884a4622013-10-24 17:49:41 -04002669 // use existing storage level count, when previously specified by TexStorage*D
Nicolas Capensbf712d02014-03-31 14:23:35 -04002670 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002671
Nicolas Capensbf712d02014-03-31 14:23:35 -04002672 return new rx::TextureStorageInterface2DArray(mRenderer, getBaseLevelInternalFormat(), renderTarget, width, height, depth, levels);
Jamie Madill884a4622013-10-24 17:49:41 -04002673}
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002674
Jamie Madill884a4622013-10-24 17:49:41 -04002675void Texture2DArray::setCompleteTexStorage(rx::TextureStorageInterface2DArray *newCompleteTexStorage)
2676{
2677 SafeDelete(mTexStorage);
2678 mTexStorage = newCompleteTexStorage;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002679 mDirtyImages = true;
Jamie Madill884a4622013-10-24 17:49:41 -04002680
2681 // We do not support managed 2D array storage, as managed storage is ES2/D3D9 only
2682 ASSERT(!mTexStorage->isManaged());
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002683}
2684
Jamie Madill169d1112013-10-24 17:49:37 -04002685void Texture2DArray::updateStorage()
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002686{
Jamie Madill4cfff5f2013-10-24 17:49:46 -04002687 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002688 {
Jamie Madilld9b9a502013-10-10 17:46:13 -04002689 if (isLevelComplete(level))
2690 {
Jamie Madill169d1112013-10-24 17:49:37 -04002691 updateStorageLevel(level);
Jamie Madilld9b9a502013-10-10 17:46:13 -04002692 }
Jamie Madill07edd442013-07-19 16:36:58 -04002693 }
2694}
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002695
Jamie Madill169d1112013-10-24 17:49:37 -04002696void Texture2DArray::updateStorageLevel(int level)
Jamie Madill07edd442013-07-19 16:36:58 -04002697{
Jamie Madillaee7ad82013-10-10 16:07:32 -04002698 ASSERT(level >= 0 && level < (int)ArraySize(mLayerCounts));
2699 ASSERT(isLevelComplete(level));
2700
Jamie Madill07edd442013-07-19 16:36:58 -04002701 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2702 {
Jamie Madillaee7ad82013-10-10 16:07:32 -04002703 ASSERT(mImageArray[level] != NULL && mImageArray[level][layer] != NULL);
2704 if (mImageArray[level][layer]->isDirty())
Jamie Madill07edd442013-07-19 16:36:58 -04002705 {
Jamie Madillaee7ad82013-10-10 16:07:32 -04002706 commitRect(level, 0, 0, layer, getWidth(level), getHeight(level));
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002707 }
2708 }
2709}
2710
Jamie Madille83d1a92013-10-24 17:49:33 -04002711bool Texture2DArray::ensureRenderTarget()
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002712{
Jamie Madill884a4622013-10-24 17:49:41 -04002713 initializeStorage(true);
2714
Jamie Madillb8f8b892014-01-07 10:12:50 -05002715 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0 && getLayers(0) > 0)
Jamie Madille83d1a92013-10-24 17:49:33 -04002716 {
Jamie Madill884a4622013-10-24 17:49:41 -04002717 ASSERT(mTexStorage);
2718 if (!mTexStorage->isRenderTarget())
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002719 {
Jamie Madill884a4622013-10-24 17:49:41 -04002720 rx::TextureStorageInterface2DArray *newRenderTargetStorage = createCompleteStorage(true);
2721
2722 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002723 {
Jamie Madill884a4622013-10-24 17:49:41 -04002724 delete newRenderTargetStorage;
Jamie Madille83d1a92013-10-24 17:49:33 -04002725 return gl::error(GL_OUT_OF_MEMORY, false);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002726 }
Jamie Madill884a4622013-10-24 17:49:41 -04002727
2728 setCompleteTexStorage(newRenderTargetStorage);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002729 }
2730 }
2731
Jamie Madille83d1a92013-10-24 17:49:33 -04002732 return (mTexStorage && mTexStorage->isRenderTarget());
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002733}
2734
Geoff Lang8040f572013-07-25 16:49:54 -04002735rx::RenderTarget *Texture2DArray::getRenderTarget(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002736{
Geoff Lang8040f572013-07-25 16:49:54 -04002737 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04002738 if (!ensureRenderTarget())
Geoff Lang8040f572013-07-25 16:49:54 -04002739 {
2740 return NULL;
2741 }
2742
Jamie Madill169d1112013-10-24 17:49:37 -04002743 updateStorageLevel(level);
Geoff Lang8040f572013-07-25 16:49:54 -04002744
2745 // ensure this is NOT a depth texture
2746 if (isDepth(level))
2747 {
2748 return NULL;
2749 }
2750
2751 return mTexStorage->getRenderTarget(level, layer);
2752}
2753
2754rx::RenderTarget *Texture2DArray::getDepthStencil(GLint level, GLint layer)
2755{
2756 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04002757 if (!ensureRenderTarget())
Geoff Lang8040f572013-07-25 16:49:54 -04002758 {
2759 return NULL;
2760 }
2761
Jamie Madill169d1112013-10-24 17:49:37 -04002762 updateStorageLevel(level);
Geoff Lang8040f572013-07-25 16:49:54 -04002763
2764 // ensure this is a depth texture
2765 if (!isDepth(level))
2766 {
2767 return NULL;
2768 }
2769
2770 return mTexStorage->getRenderTarget(level, layer);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002771}
2772
Geoff Lang005df412013-10-16 14:12:50 -04002773void Texture2DArray::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002774{
2775 // If there currently is a corresponding storage texture image, it has these parameters
Jamie Madilld3d2a342013-10-07 10:46:35 -04002776 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2777 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
Jamie Madillb8f8b892014-01-07 10:12:50 -05002778 const int storageDepth = getLayers(0);
Geoff Lang005df412013-10-16 14:12:50 -04002779 const GLenum storageFormat = getBaseLevelInternalFormat();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002780
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002781 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002782 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002783 delete mImageArray[level][layer];
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002784 }
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002785 delete[] mImageArray[level];
Jamie Madill152ed092013-10-09 17:01:15 -04002786 mImageArray[level] = NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002787 mLayerCounts[level] = depth;
2788
Jamie Madill152ed092013-10-09 17:01:15 -04002789 if (depth > 0)
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002790 {
Jamie Madill152ed092013-10-09 17:01:15 -04002791 mImageArray[level] = new rx::Image*[depth]();
2792
2793 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2794 {
2795 mImageArray[level][layer] = mRenderer->createImage();
2796 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, width, height, 1, false);
2797 }
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002798 }
2799
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002800 if (mTexStorage)
2801 {
Nicolas Capensbf712d02014-03-31 14:23:35 -04002802 const int storageLevels = mTexStorage->getLevelCount();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002803
2804 if ((level >= storageLevels && storageLevels != 0) ||
2805 width != storageWidth ||
2806 height != storageHeight ||
2807 depth != storageDepth ||
2808 internalformat != storageFormat) // Discard mismatched storage
2809 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002810 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002811 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002812 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002813 {
2814 mImageArray[level][layer]->markDirty();
2815 }
2816 }
2817
2818 delete mTexStorage;
2819 mTexStorage = NULL;
2820 mDirtyImages = true;
2821 }
2822 }
2823}
2824
2825void Texture2DArray::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint layerTarget, GLsizei width, GLsizei height)
2826{
Jamie Madillb8f8b892014-01-07 10:12:50 -05002827 if (isValidLevel(level) && layerTarget < getLayers(level))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002828 {
2829 rx::Image *image = mImageArray[level][layerTarget];
Jamie Madill169d1112013-10-24 17:49:37 -04002830 if (image->copyToStorage(mTexStorage, level, xoffset, yoffset, layerTarget, width, height))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002831 {
2832 image->markClean();
2833 }
2834 }
2835}
2836
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00002837}