blob: 605823dc57cd6d1f3f205b93551912b7f70b75fe [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//
Geoff Langcec35902014-04-16 10:52:36 -04003// Copyright (c) 2002-2014 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
Jamie Madill3c7fa222014-06-05 13:08:51 -040090void Texture::addProxyRef(const FramebufferAttachment *proxy)
Geoff Lang8040f572013-07-25 16:49:54 -040091{
92 mRenderbufferProxies.addRef(proxy);
93}
94
Jamie Madill3c7fa222014-06-05 13:08:51 -040095void Texture::releaseProxy(const FramebufferAttachment *proxy)
Geoff Lang8040f572013-07-25 16:49:54 -040096{
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{
Geoff Langcec35902014-04-16 10:52:36 -0400441 if ((isPow2(width) && isPow2(height) && isPow2(depth)) || mRenderer->getCaps().extensions.textureNPOT)
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{
Jamie Madill07edd442013-07-19 16:36:58 -0400701 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
702 // the current level we're copying to is defined (with appropriate format, width & height)
703 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
704
705 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000706 {
shannon.woods%transgaming.com@gtempaccount.come5dcce72013-04-13 03:44:33 +0000707 mImageArray[level]->copy(xoffset, yoffset, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000708 mDirtyImages = true;
709 }
710 else
711 {
Jamie Madille83d1a92013-10-24 17:49:33 -0400712 ensureRenderTarget();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000713
Jamie Madill07bb8cf2013-10-24 17:49:44 -0400714 if (isValidLevel(level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000715 {
Jamie Madill169d1112013-10-24 17:49:37 -0400716 updateStorageLevel(level);
Jamie Madill07edd442013-07-19 16:36:58 -0400717
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +0000718 GLuint clientVersion = mRenderer->getCurrentClientVersion();
719
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +0000720 gl::Rectangle sourceRect;
721 sourceRect.x = x;
722 sourceRect.width = width;
723 sourceRect.y = y;
724 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000725
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +0000726 mRenderer->copyImage(source, sourceRect,
Jamie Madilld3d2a342013-10-07 10:46:35 -0400727 gl::GetFormat(getBaseLevelInternalFormat(), clientVersion),
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +0000728 xoffset, yoffset, mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000729 }
730 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000731}
732
733void Texture2D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height)
734{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000735 for (int level = 0; level < levels; level++)
736 {
Jamie Madill73b5d062013-10-24 17:49:38 -0400737 GLsizei levelWidth = std::max(1, width >> level);
738 GLsizei levelHeight = std::max(1, height >> level);
739 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, levelWidth, levelHeight, 1, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000740 }
741
742 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
743 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000744 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000745 }
746
Jamie Madill73b5d062013-10-24 17:49:38 -0400747 mImmutable = true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000748
Nicolas Capensbf712d02014-03-31 14:23:35 -0400749 setCompleteTexStorage(new rx::TextureStorageInterface2D(mRenderer, internalformat, IsRenderTargetUsage(mUsage), width, height, levels));
Jamie Madill73b5d062013-10-24 17:49:38 -0400750}
751
752void Texture2D::setCompleteTexStorage(rx::TextureStorageInterface2D *newCompleteTexStorage)
753{
754 SafeDelete(mTexStorage);
755 mTexStorage = newCompleteTexStorage;
756
757 if (mTexStorage && mTexStorage->isManaged())
758 {
Nicolas Capensbf712d02014-03-31 14:23:35 -0400759 for (int level = 0; level < mTexStorage->getLevelCount(); level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000760 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000761 mImageArray[level]->setManagedSurface(mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000762 }
763 }
Jamie Madill73b5d062013-10-24 17:49:38 -0400764
765 mDirtyImages = true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000766}
767
768// Tests for 2D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85.
Jamie Madillf8989902013-07-19 16:36:58 -0400769bool Texture2D::isSamplerComplete(const SamplerState &samplerState) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000770{
Jamie Madilld3d2a342013-10-07 10:46:35 -0400771 GLsizei width = getBaseLevelWidth();
772 GLsizei height = getBaseLevelHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000773
774 if (width <= 0 || height <= 0)
775 {
776 return false;
777 }
778
Geoff Langcec35902014-04-16 10:52:36 -0400779 if (!mRenderer->getCaps().textureCaps.get(getInternalFormat(0)).filtering)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000780 {
Jamie Madillf8989902013-07-19 16:36:58 -0400781 if (samplerState.magFilter != GL_NEAREST ||
782 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000783 {
784 return false;
785 }
786 }
787
Geoff Langcec35902014-04-16 10:52:36 -0400788 bool npotSupport = mRenderer->getCaps().extensions.textureNPOT;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000789
790 if (!npotSupport)
791 {
Jamie Madillf8989902013-07-19 16:36:58 -0400792 if ((samplerState.wrapS != GL_CLAMP_TO_EDGE && !isPow2(width)) ||
793 (samplerState.wrapT != GL_CLAMP_TO_EDGE && !isPow2(height)))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000794 {
795 return false;
796 }
797 }
798
Jamie Madillf8989902013-07-19 16:36:58 -0400799 if (IsMipmapFiltered(samplerState))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000800 {
801 if (!npotSupport)
802 {
803 if (!isPow2(width) || !isPow2(height))
804 {
805 return false;
806 }
807 }
808
809 if (!isMipmapComplete())
810 {
811 return false;
812 }
813 }
814
Geoff Langc82fc412013-07-10 14:43:42 -0400815 // OpenGLES 3.0.2 spec section 3.8.13 states that a texture is not mipmap complete if:
816 // The internalformat specified for the texture arrays is a sized internal depth or
817 // depth and stencil format (see table 3.13), the value of TEXTURE_COMPARE_-
818 // MODE is NONE, and either the magnification filter is not NEAREST or the mini-
819 // fication filter is neither NEAREST nor NEAREST_MIPMAP_NEAREST.
Jamie Madill2a205622014-02-12 10:41:24 -0500820 if (gl::GetDepthBits(getInternalFormat(0), mRenderer->getCurrentClientVersion()) > 0 &&
821 mRenderer->getCurrentClientVersion() > 2)
Geoff Langc82fc412013-07-10 14:43:42 -0400822 {
823 if (mSamplerState.compareMode == GL_NONE)
824 {
825 if ((mSamplerState.minFilter != GL_NEAREST && mSamplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST) ||
826 mSamplerState.magFilter != GL_NEAREST)
827 {
828 return false;
829 }
830 }
831 }
832
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000833 return true;
834}
835
836// Tests for 2D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
837bool Texture2D::isMipmapComplete() const
838{
Geoff Lang98705b72014-03-31 16:00:03 -0400839 int levelCount = mipLevels();
Jamie Madill07edd442013-07-19 16:36:58 -0400840
Geoff Lang98705b72014-03-31 16:00:03 -0400841 for (int level = 0; level < levelCount; level++)
Jamie Madill07edd442013-07-19 16:36:58 -0400842 {
843 if (!isLevelComplete(level))
844 {
845 return false;
846 }
847 }
848
849 return true;
850}
851
852bool Texture2D::isLevelComplete(int level) const
853{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000854 if (isImmutable())
855 {
856 return true;
857 }
858
Jamie Madill648c9682014-01-21 16:50:58 -0500859 const rx::Image *baseImage = getBaseLevelImage();
860
861 GLsizei width = baseImage->getWidth();
862 GLsizei height = baseImage->getHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000863
864 if (width <= 0 || height <= 0)
865 {
866 return false;
867 }
868
Jamie Madill07edd442013-07-19 16:36:58 -0400869 // The base image level is complete if the width and height are positive
870 if (level == 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000871 {
Jamie Madill07edd442013-07-19 16:36:58 -0400872 return true;
873 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000874
Jamie Madill07edd442013-07-19 16:36:58 -0400875 ASSERT(level >= 1 && level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
876 rx::Image *image = mImageArray[level];
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000877
Jamie Madill648c9682014-01-21 16:50:58 -0500878 if (image->getInternalFormat() != baseImage->getInternalFormat())
Jamie Madill07edd442013-07-19 16:36:58 -0400879 {
880 return false;
881 }
882
883 if (image->getWidth() != std::max(1, width >> level))
884 {
885 return false;
886 }
887
888 if (image->getHeight() != std::max(1, height >> level))
889 {
890 return false;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000891 }
892
893 return true;
894}
895
896bool Texture2D::isCompressed(GLint level) const
897{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000898 return IsFormatCompressed(getInternalFormat(level), mRenderer->getCurrentClientVersion());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000899}
900
901bool Texture2D::isDepth(GLint level) const
902{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000903 return GetDepthBits(getInternalFormat(level), mRenderer->getCurrentClientVersion()) > 0;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000904}
905
daniel@transgaming.comf032cb82012-10-31 19:51:52 +0000906// Constructs a native texture resource from the texture images
Jamie Madill73b5d062013-10-24 17:49:38 -0400907void Texture2D::initializeStorage(bool renderTarget)
908{
909 // Only initialize the first time this texture is used as a render target or shader resource
910 if (mTexStorage)
911 {
912 return;
913 }
914
915 // do not attempt to create storage for nonexistant data
916 if (!isLevelComplete(0))
917 {
918 return;
919 }
920
921 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
922
923 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
924 ASSERT(mTexStorage);
925
926 // flush image data to the storage
927 updateStorage();
928}
929
930rx::TextureStorageInterface2D *Texture2D::createCompleteStorage(bool renderTarget) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000931{
Jamie Madilld3d2a342013-10-07 10:46:35 -0400932 GLsizei width = getBaseLevelWidth();
933 GLsizei height = getBaseLevelHeight();
daniel@transgaming.come6a09842012-09-17 21:28:55 +0000934
Jamie Madill73b5d062013-10-24 17:49:38 -0400935 ASSERT(width > 0 && height > 0);
daniel@transgaming.come6a09842012-09-17 21:28:55 +0000936
Jamie Madill73b5d062013-10-24 17:49:38 -0400937 // use existing storage level count, when previously specified by TexStorage*D
Nicolas Capensbf712d02014-03-31 14:23:35 -0400938 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000939
Nicolas Capensbf712d02014-03-31 14:23:35 -0400940 return new rx::TextureStorageInterface2D(mRenderer, getBaseLevelInternalFormat(), renderTarget, width, height, levels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000941}
942
Jamie Madill169d1112013-10-24 17:49:37 -0400943void Texture2D::updateStorage()
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000944{
Geoff Lang946b9482014-05-12 16:37:25 -0400945 ASSERT(mTexStorage != NULL);
946 GLint storageLevels = mTexStorage->getLevelCount();
947 for (int level = 0; level < storageLevels; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000948 {
Jamie Madill648c9682014-01-21 16:50:58 -0500949 if (mImageArray[level]->isDirty() && isLevelComplete(level))
Jamie Madilld9b9a502013-10-10 17:46:13 -0400950 {
Jamie Madill169d1112013-10-24 17:49:37 -0400951 updateStorageLevel(level);
Jamie Madilld9b9a502013-10-10 17:46:13 -0400952 }
Jamie Madill07edd442013-07-19 16:36:58 -0400953 }
954}
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000955
Jamie Madill169d1112013-10-24 17:49:37 -0400956void Texture2D::updateStorageLevel(int level)
Jamie Madill07edd442013-07-19 16:36:58 -0400957{
958 ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
Jamie Madillaee7ad82013-10-10 16:07:32 -0400959 ASSERT(isLevelComplete(level));
Jamie Madill07edd442013-07-19 16:36:58 -0400960
Jamie Madillaee7ad82013-10-10 16:07:32 -0400961 if (mImageArray[level]->isDirty())
Jamie Madill07edd442013-07-19 16:36:58 -0400962 {
Jamie Madillaee7ad82013-10-10 16:07:32 -0400963 commitRect(level, 0, 0, getWidth(level), getHeight(level));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000964 }
965}
966
Jamie Madille83d1a92013-10-24 17:49:33 -0400967bool Texture2D::ensureRenderTarget()
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000968{
Jamie Madill73b5d062013-10-24 17:49:38 -0400969 initializeStorage(true);
970
971 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0)
Jamie Madille83d1a92013-10-24 17:49:33 -0400972 {
Jamie Madill73b5d062013-10-24 17:49:38 -0400973 ASSERT(mTexStorage);
974 if (!mTexStorage->isRenderTarget())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000975 {
Jamie Madill73b5d062013-10-24 17:49:38 -0400976 rx::TextureStorageInterface2D *newRenderTargetStorage = createCompleteStorage(true);
977
978 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
979 {
980 delete newRenderTargetStorage;
Jamie Madille83d1a92013-10-24 17:49:33 -0400981 return gl::error(GL_OUT_OF_MEMORY, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000982 }
Jamie Madill73b5d062013-10-24 17:49:38 -0400983
984 setCompleteTexStorage(newRenderTargetStorage);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000985 }
986 }
987
Jamie Madille83d1a92013-10-24 17:49:33 -0400988 return (mTexStorage && mTexStorage->isRenderTarget());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000989}
990
991void Texture2D::generateMipmaps()
992{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000993 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Geoff Lang98705b72014-03-31 16:00:03 -0400994 int levelCount = mipLevels();
995 for (int level = 1; level < levelCount; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000996 {
Jamie Madill22f843a2013-10-24 17:49:36 -0400997 redefineImage(level, getBaseLevelInternalFormat(),
998 std::max(getBaseLevelWidth() >> level, 1),
999 std::max(getBaseLevelHeight() >> level, 1));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001000 }
1001
1002 if (mTexStorage && mTexStorage->isRenderTarget())
1003 {
Geoff Lang98705b72014-03-31 16:00:03 -04001004 for (int level = 1; level < levelCount; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001005 {
Jamie Madill22f843a2013-10-24 17:49:36 -04001006 mTexStorage->generateMipmap(level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001007
Jamie Madill22f843a2013-10-24 17:49:36 -04001008 mImageArray[level]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001009 }
1010 }
1011 else
1012 {
Geoff Lang98705b72014-03-31 16:00:03 -04001013 for (int level = 1; level < levelCount; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001014 {
Jamie Madill22f843a2013-10-24 17:49:36 -04001015 mRenderer->generateMipmap(mImageArray[level], mImageArray[level - 1]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001016 }
1017 }
1018}
1019
Jamie Madilld3d2a342013-10-07 10:46:35 -04001020const rx::Image *Texture2D::getBaseLevelImage() const
1021{
1022 return mImageArray[0];
1023}
1024
Jamie Madill2ebab852013-10-24 17:49:42 -04001025rx::TextureStorageInterface *Texture2D::getBaseLevelStorage()
1026{
1027 return mTexStorage;
1028}
1029
Jamie Madill3c7fa222014-06-05 13:08:51 -04001030FramebufferAttachment *Texture2D::getAttachment(GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001031{
Jamie Madill3c7fa222014-06-05 13:08:51 -04001032 FramebufferAttachment *attachment = mRenderbufferProxies.get(level, 0);
1033 if (!attachment)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001034 {
Jamie Madill3c7fa222014-06-05 13:08:51 -04001035 attachment = new FramebufferAttachment(mRenderer, id(), new Texture2DAttachment(this, level));
1036 mRenderbufferProxies.add(level, 0, attachment);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001037 }
1038
Jamie Madill3c7fa222014-06-05 13:08:51 -04001039 return attachment;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001040}
1041
Geoff Lang8040f572013-07-25 16:49:54 -04001042unsigned int Texture2D::getRenderTargetSerial(GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001043{
Jamie Madille83d1a92013-10-24 17:49:33 -04001044 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(level) : 0);
Geoff Lang8040f572013-07-25 16:49:54 -04001045}
1046
1047rx::RenderTarget *Texture2D::getRenderTarget(GLint level)
1048{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001049 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04001050 if (!ensureRenderTarget())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001051 {
1052 return NULL;
1053 }
1054
Jamie Madill169d1112013-10-24 17:49:37 -04001055 updateStorageLevel(level);
Geoff Lang8040f572013-07-25 16:49:54 -04001056
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001057 // ensure this is NOT a depth texture
Geoff Lang8040f572013-07-25 16:49:54 -04001058 if (isDepth(level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001059 {
1060 return NULL;
1061 }
daniel@transgaming.com34da3972012-12-20 21:10:29 +00001062
Geoff Lang8040f572013-07-25 16:49:54 -04001063 return mTexStorage->getRenderTarget(level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001064}
1065
Geoff Lang8040f572013-07-25 16:49:54 -04001066rx::RenderTarget *Texture2D::getDepthSencil(GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001067{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001068 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04001069 if (!ensureRenderTarget())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001070 {
1071 return NULL;
1072 }
1073
Jamie Madill169d1112013-10-24 17:49:37 -04001074 updateStorageLevel(level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001075
1076 // ensure this is actually a depth texture
Geoff Lang8040f572013-07-25 16:49:54 -04001077 if (!isDepth(level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001078 {
1079 return NULL;
1080 }
Geoff Lang8040f572013-07-25 16:49:54 -04001081
1082 return mTexStorage->getRenderTarget(level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001083}
1084
Jamie Madill07bb8cf2013-10-24 17:49:44 -04001085bool Texture2D::isValidLevel(int level) const
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +00001086{
Nicolas Capensbf712d02014-03-31 14:23:35 -04001087 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : false);
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +00001088}
1089
Geoff Lang4907f2c2013-07-25 12:53:57 -04001090TextureCubeMap::TextureCubeMap(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_CUBE_MAP)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001091{
1092 mTexStorage = NULL;
1093 for (int i = 0; i < 6; i++)
1094 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001095 for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
1096 {
daniel@transgaming.com244e1832012-12-20 20:52:35 +00001097 mImageArray[i][j] = renderer->createImage();
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001098 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001099 }
1100}
1101
1102TextureCubeMap::~TextureCubeMap()
1103{
1104 for (int i = 0; i < 6; i++)
1105 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001106 for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
1107 {
1108 delete mImageArray[i][j];
1109 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001110 }
1111
1112 delete mTexStorage;
1113 mTexStorage = NULL;
1114}
1115
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001116GLsizei TextureCubeMap::getWidth(GLenum target, GLint level) const
1117{
1118 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Jamie Madill2db197c2013-10-24 17:49:35 -04001119 return mImageArray[targetToIndex(target)][level]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001120 else
1121 return 0;
1122}
1123
1124GLsizei TextureCubeMap::getHeight(GLenum target, GLint level) const
1125{
1126 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Jamie Madill2db197c2013-10-24 17:49:35 -04001127 return mImageArray[targetToIndex(target)][level]->getHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001128 else
1129 return 0;
1130}
1131
1132GLenum TextureCubeMap::getInternalFormat(GLenum target, GLint level) const
1133{
1134 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Jamie Madill2db197c2013-10-24 17:49:35 -04001135 return mImageArray[targetToIndex(target)][level]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001136 else
1137 return GL_NONE;
1138}
1139
daniel@transgaming.com20d36662012-10-31 19:51:43 +00001140GLenum TextureCubeMap::getActualFormat(GLenum target, GLint level) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001141{
1142 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Jamie Madill2db197c2013-10-24 17:49:35 -04001143 return mImageArray[targetToIndex(target)][level]->getActualFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001144 else
Geoff Langcbf727a2014-02-10 12:50:45 -05001145 return GL_NONE;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001146}
1147
Geoff Lang005df412013-10-16 14:12:50 -04001148void 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 +00001149{
Jamie Madill88f18f42013-09-18 14:36:19 -04001150 setImage(0, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001151}
1152
Geoff Lang005df412013-10-16 14:12:50 -04001153void 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 +00001154{
Jamie Madill88f18f42013-09-18 14:36:19 -04001155 setImage(1, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001156}
1157
Geoff Lang005df412013-10-16 14:12:50 -04001158void 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 +00001159{
Jamie Madill88f18f42013-09-18 14:36:19 -04001160 setImage(2, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001161}
1162
Geoff Lang005df412013-10-16 14:12:50 -04001163void 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 +00001164{
Jamie Madill88f18f42013-09-18 14:36:19 -04001165 setImage(3, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001166}
1167
Geoff Lang005df412013-10-16 14:12:50 -04001168void 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 +00001169{
Jamie Madill88f18f42013-09-18 14:36:19 -04001170 setImage(4, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001171}
1172
Geoff Lang005df412013-10-16 14:12:50 -04001173void 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 +00001174{
Jamie Madill88f18f42013-09-18 14:36:19 -04001175 setImage(5, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001176}
1177
Jamie Madill2db197c2013-10-24 17:49:35 -04001178void 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 +00001179{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001180 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
Jamie Madill2db197c2013-10-24 17:49:35 -04001181 int faceIndex = targetToIndex(target);
1182 redefineImage(faceIndex, level, format, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001183
Jamie Madill2db197c2013-10-24 17:49:35 -04001184 Texture::setCompressedImage(imageSize, pixels, mImageArray[faceIndex][level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001185}
1186
Jamie Madill2db197c2013-10-24 17:49:35 -04001187void TextureCubeMap::commitRect(int faceIndex, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001188{
Jamie Madill07bb8cf2013-10-24 17:49:44 -04001189 if (isValidFaceLevel(faceIndex, level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001190 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001191 rx::Image *image = mImageArray[faceIndex][level];
Jamie Madill169d1112013-10-24 17:49:37 -04001192 if (image->copyToStorage(mTexStorage, faceIndex, level, xoffset, yoffset, width, height))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001193 image->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001194 }
1195}
1196
Jamie Madill88f18f42013-09-18 14:36:19 -04001197void 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 +00001198{
Jamie Madill2db197c2013-10-24 17:49:35 -04001199 int faceIndex = targetToIndex(target);
1200 if (Texture::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, mImageArray[faceIndex][level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001201 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001202 commitRect(faceIndex, level, xoffset, yoffset, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001203 }
1204}
1205
1206void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1207{
Jamie Madill2db197c2013-10-24 17:49:35 -04001208 int faceIndex = targetToIndex(target);
1209 if (Texture::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[faceIndex][level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001210 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001211 commitRect(faceIndex, level, xoffset, yoffset, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001212 }
1213}
1214
1215// Tests for cube map sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 86.
Jamie Madillf8989902013-07-19 16:36:58 -04001216bool TextureCubeMap::isSamplerComplete(const SamplerState &samplerState) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001217{
Jamie Madilld3d2a342013-10-07 10:46:35 -04001218 int size = getBaseLevelWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001219
Jamie Madillf8989902013-07-19 16:36:58 -04001220 bool mipmapping = IsMipmapFiltered(samplerState);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001221
Geoff Langcec35902014-04-16 10:52:36 -04001222 if (!mRenderer->getCaps().textureCaps.get(getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0)).filtering)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001223 {
Jamie Madillf8989902013-07-19 16:36:58 -04001224 if (samplerState.magFilter != GL_NEAREST ||
1225 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001226 {
1227 return false;
1228 }
1229 }
1230
Geoff Langcec35902014-04-16 10:52:36 -04001231 if (!isPow2(size) && !mRenderer->getCaps().extensions.textureNPOT)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001232 {
Jamie Madillf8989902013-07-19 16:36:58 -04001233 if (samplerState.wrapS != GL_CLAMP_TO_EDGE || samplerState.wrapT != GL_CLAMP_TO_EDGE || mipmapping)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001234 {
1235 return false;
1236 }
1237 }
1238
1239 if (!mipmapping)
1240 {
1241 if (!isCubeComplete())
1242 {
1243 return false;
1244 }
1245 }
1246 else
1247 {
1248 if (!isMipmapCubeComplete()) // Also tests for isCubeComplete()
1249 {
1250 return false;
1251 }
1252 }
1253
1254 return true;
1255}
1256
1257// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1258bool TextureCubeMap::isCubeComplete() const
1259{
Jamie Madillc1f8b162013-10-07 10:46:38 -04001260 int baseWidth = getBaseLevelWidth();
1261 int baseHeight = getBaseLevelHeight();
1262 GLenum baseFormat = getBaseLevelInternalFormat();
1263
1264 if (baseWidth <= 0 || baseWidth != baseHeight)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001265 {
1266 return false;
1267 }
1268
Jamie Madill2db197c2013-10-24 17:49:35 -04001269 for (int faceIndex = 1; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001270 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001271 const rx::Image &faceBaseImage = *mImageArray[faceIndex][0];
Jamie Madillc1f8b162013-10-07 10:46:38 -04001272
1273 if (faceBaseImage.getWidth() != baseWidth ||
1274 faceBaseImage.getHeight() != baseHeight ||
1275 faceBaseImage.getInternalFormat() != baseFormat )
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001276 {
1277 return false;
1278 }
1279 }
1280
1281 return true;
1282}
1283
1284bool TextureCubeMap::isMipmapCubeComplete() const
1285{
1286 if (isImmutable())
1287 {
1288 return true;
1289 }
1290
1291 if (!isCubeComplete())
1292 {
1293 return false;
1294 }
1295
Geoff Lang98705b72014-03-31 16:00:03 -04001296 int levelCount = mipLevels();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001297
1298 for (int face = 0; face < 6; face++)
1299 {
Geoff Lang98705b72014-03-31 16:00:03 -04001300 for (int level = 1; level < levelCount; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001301 {
Jamie Madill07edd442013-07-19 16:36:58 -04001302 if (!isFaceLevelComplete(face, level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001303 {
1304 return false;
1305 }
1306 }
1307 }
1308
1309 return true;
1310}
1311
Jamie Madill2db197c2013-10-24 17:49:35 -04001312bool TextureCubeMap::isFaceLevelComplete(int faceIndex, int level) const
Jamie Madill07edd442013-07-19 16:36:58 -04001313{
Jamie Madill2db197c2013-10-24 17:49:35 -04001314 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
Jamie Madill07edd442013-07-19 16:36:58 -04001315
1316 if (isImmutable())
1317 {
1318 return true;
1319 }
1320
Jamie Madilld3d2a342013-10-07 10:46:35 -04001321 int baseSize = getBaseLevelWidth();
Jamie Madill07edd442013-07-19 16:36:58 -04001322
Jamie Madilld3d2a342013-10-07 10:46:35 -04001323 if (baseSize <= 0)
Jamie Madill07edd442013-07-19 16:36:58 -04001324 {
1325 return false;
1326 }
1327
Jamie Madilld3d2a342013-10-07 10:46:35 -04001328 // "isCubeComplete" checks for base level completeness and we must call that
1329 // to determine if any face at level 0 is complete. We omit that check here
1330 // to avoid re-checking cube-completeness for every face at level 0.
Jamie Madill07edd442013-07-19 16:36:58 -04001331 if (level == 0)
1332 {
1333 return true;
1334 }
1335
Jamie Madilld3d2a342013-10-07 10:46:35 -04001336 // Check that non-zero levels are consistent with the base level.
Jamie Madill2db197c2013-10-24 17:49:35 -04001337 const rx::Image *faceLevelImage = mImageArray[faceIndex][level];
Jamie Madill07edd442013-07-19 16:36:58 -04001338
Jamie Madilld3d2a342013-10-07 10:46:35 -04001339 if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat())
Jamie Madill07edd442013-07-19 16:36:58 -04001340 {
1341 return false;
1342 }
1343
Jamie Madilld3d2a342013-10-07 10:46:35 -04001344 if (faceLevelImage->getWidth() != std::max(1, baseSize >> level))
Jamie Madill07edd442013-07-19 16:36:58 -04001345 {
1346 return false;
1347 }
1348
1349 return true;
1350}
1351
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001352bool TextureCubeMap::isCompressed(GLenum target, GLint level) const
1353{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001354 return IsFormatCompressed(getInternalFormat(target, level), mRenderer->getCurrentClientVersion());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001355}
1356
Geoff Lang8040f572013-07-25 16:49:54 -04001357bool TextureCubeMap::isDepth(GLenum target, GLint level) const
1358{
1359 return GetDepthBits(getInternalFormat(target, level), mRenderer->getCurrentClientVersion()) > 0;
1360}
1361
Jamie Madill73b5d062013-10-24 17:49:38 -04001362void TextureCubeMap::initializeStorage(bool renderTarget)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001363{
Jamie Madill3c0989c2013-10-24 17:49:39 -04001364 // Only initialize the first time this texture is used as a render target or shader resource
1365 if (mTexStorage)
1366 {
1367 return;
1368 }
1369
1370 // do not attempt to create storage for nonexistant data
1371 if (!isFaceLevelComplete(0, 0))
1372 {
1373 return;
1374 }
1375
1376 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
1377
1378 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
1379 ASSERT(mTexStorage);
1380
1381 // flush image data to the storage
1382 updateStorage();
1383}
1384
1385rx::TextureStorageInterfaceCube *TextureCubeMap::createCompleteStorage(bool renderTarget) const
1386{
Jamie Madilld3d2a342013-10-07 10:46:35 -04001387 GLsizei size = getBaseLevelWidth();
daniel@transgaming.come6a09842012-09-17 21:28:55 +00001388
Jamie Madill3c0989c2013-10-24 17:49:39 -04001389 ASSERT(size > 0);
daniel@transgaming.come6a09842012-09-17 21:28:55 +00001390
Jamie Madill3c0989c2013-10-24 17:49:39 -04001391 // use existing storage level count, when previously specified by TexStorage*D
Nicolas Capensbf712d02014-03-31 14:23:35 -04001392 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(size, size, 1));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001393
Nicolas Capensbf712d02014-03-31 14:23:35 -04001394 return new rx::TextureStorageInterfaceCube(mRenderer, getBaseLevelInternalFormat(), renderTarget, size, levels);
Jamie Madill3c0989c2013-10-24 17:49:39 -04001395}
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001396
Jamie Madill3c0989c2013-10-24 17:49:39 -04001397void TextureCubeMap::setCompleteTexStorage(rx::TextureStorageInterfaceCube *newCompleteTexStorage)
1398{
1399 SafeDelete(mTexStorage);
1400 mTexStorage = newCompleteTexStorage;
1401
1402 if (mTexStorage && mTexStorage->isManaged())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001403 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001404 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001405 {
Nicolas Capensbf712d02014-03-31 14:23:35 -04001406 for (int level = 0; level < mTexStorage->getLevelCount(); level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001407 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001408 mImageArray[faceIndex][level]->setManagedSurface(mTexStorage, faceIndex, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001409 }
1410 }
1411 }
1412
1413 mDirtyImages = true;
1414}
1415
Jamie Madill169d1112013-10-24 17:49:37 -04001416void TextureCubeMap::updateStorage()
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001417{
Geoff Lang946b9482014-05-12 16:37:25 -04001418 ASSERT(mTexStorage != NULL);
1419 GLint storageLevels = mTexStorage->getLevelCount();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001420 for (int face = 0; face < 6; face++)
1421 {
Geoff Lang946b9482014-05-12 16:37:25 -04001422 for (int level = 0; level < storageLevels; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001423 {
Geoff Lang946b9482014-05-12 16:37:25 -04001424 if (mImageArray[face][level]->isDirty() && isFaceLevelComplete(face, level))
Jamie Madilld9b9a502013-10-10 17:46:13 -04001425 {
Jamie Madill169d1112013-10-24 17:49:37 -04001426 updateStorageFaceLevel(face, level);
Jamie Madilld9b9a502013-10-10 17:46:13 -04001427 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001428 }
1429 }
1430}
1431
Jamie Madill169d1112013-10-24 17:49:37 -04001432void TextureCubeMap::updateStorageFaceLevel(int faceIndex, int level)
Jamie Madill07edd442013-07-19 16:36:58 -04001433{
Jamie Madill2db197c2013-10-24 17:49:35 -04001434 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1435 rx::Image *image = mImageArray[faceIndex][level];
Jamie Madill07edd442013-07-19 16:36:58 -04001436
1437 if (image->isDirty())
1438 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001439 commitRect(faceIndex, level, 0, 0, image->getWidth(), image->getHeight());
Jamie Madill07edd442013-07-19 16:36:58 -04001440 }
1441}
1442
Jamie Madille83d1a92013-10-24 17:49:33 -04001443bool TextureCubeMap::ensureRenderTarget()
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001444{
Jamie Madill3c0989c2013-10-24 17:49:39 -04001445 initializeStorage(true);
1446
1447 if (getBaseLevelWidth() > 0)
Jamie Madille83d1a92013-10-24 17:49:33 -04001448 {
Jamie Madill3c0989c2013-10-24 17:49:39 -04001449 ASSERT(mTexStorage);
1450 if (!mTexStorage->isRenderTarget())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001451 {
Jamie Madill3c0989c2013-10-24 17:49:39 -04001452 rx::TextureStorageInterfaceCube *newRenderTargetStorage = createCompleteStorage(true);
1453
1454 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001455 {
Jamie Madill3c0989c2013-10-24 17:49:39 -04001456 delete newRenderTargetStorage;
Jamie Madille83d1a92013-10-24 17:49:33 -04001457 return gl::error(GL_OUT_OF_MEMORY, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001458 }
Jamie Madill3c0989c2013-10-24 17:49:39 -04001459
1460 setCompleteTexStorage(newRenderTargetStorage);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001461 }
1462 }
1463
Jamie Madille83d1a92013-10-24 17:49:33 -04001464 return (mTexStorage && mTexStorage->isRenderTarget());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001465}
1466
Geoff Lang005df412013-10-16 14:12:50 -04001467void 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 +00001468{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001469 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Geoff Lang005df412013-10-16 14:12:50 -04001470 GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
1471 : GetSizedInternalFormat(format, type, clientVersion);
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001472
1473 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001474
Jamie Madill88f18f42013-09-18 14:36:19 -04001475 Texture::setImage(unpack, type, pixels, mImageArray[faceIndex][level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001476}
1477
Jamie Madill2db197c2013-10-24 17:49:35 -04001478int TextureCubeMap::targetToIndex(GLenum target)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001479{
1480 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
1481 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
1482 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
1483 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
1484 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
1485
Jamie Madill2db197c2013-10-24 17:49:35 -04001486 return target - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001487}
1488
Jamie Madill2db197c2013-10-24 17:49:35 -04001489void TextureCubeMap::redefineImage(int faceIndex, GLint level, GLenum internalformat, GLsizei width, GLsizei height)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001490{
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001491 // If there currently is a corresponding storage texture image, it has these parameters
Jamie Madilld3d2a342013-10-07 10:46:35 -04001492 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1493 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
Geoff Lang005df412013-10-16 14:12:50 -04001494 const GLenum storageFormat = getBaseLevelInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001495
Jamie Madill2db197c2013-10-24 17:49:35 -04001496 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, width, height, 1, false);
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001497
1498 if (mTexStorage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001499 {
Nicolas Capensbf712d02014-03-31 14:23:35 -04001500 const int storageLevels = mTexStorage->getLevelCount();
1501
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001502 if ((level >= storageLevels && storageLevels != 0) ||
1503 width != storageWidth ||
1504 height != storageHeight ||
1505 internalformat != storageFormat) // Discard mismatched storage
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001506 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001507 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001508 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001509 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001510 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001511 mImageArray[faceIndex][level]->markDirty();
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001512 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001513 }
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001514
1515 delete mTexStorage;
1516 mTexStorage = NULL;
1517
1518 mDirtyImages = true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001519 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001520 }
1521}
1522
1523void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1524{
Jamie Madill2db197c2013-10-24 17:49:35 -04001525 int faceIndex = targetToIndex(target);
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001526 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Geoff Lang005df412013-10-16 14:12:50 -04001527 GLenum sizedInternalFormat = IsSizedInternalFormat(format, clientVersion) ? format
1528 : GetSizedInternalFormat(format, GL_UNSIGNED_BYTE, clientVersion);
Jamie Madill2db197c2013-10-24 17:49:35 -04001529 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001530
Jamie Madill2db197c2013-10-24 17:49:35 -04001531 if (!mImageArray[faceIndex][level]->isRenderableFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001532 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001533 mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001534 mDirtyImages = true;
1535 }
1536 else
1537 {
Jamie Madille83d1a92013-10-24 17:49:33 -04001538 ensureRenderTarget();
Jamie Madill2db197c2013-10-24 17:49:35 -04001539 mImageArray[faceIndex][level]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001540
1541 ASSERT(width == height);
1542
Jamie Madill07bb8cf2013-10-24 17:49:44 -04001543 if (width > 0 && isValidFaceLevel(faceIndex, level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001544 {
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +00001545 gl::Rectangle sourceRect;
1546 sourceRect.x = x;
1547 sourceRect.width = width;
1548 sourceRect.y = y;
1549 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001550
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +00001551 mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001552 }
1553 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001554}
1555
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001556void 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 +00001557{
Jamie Madill2db197c2013-10-24 17:49:35 -04001558 int faceIndex = targetToIndex(target);
1559
Jamie Madilld3d2a342013-10-07 10:46:35 -04001560 // We can only make our texture storage to a render target if the level we're copying *to* is complete
1561 // and the base level is cube-complete. The base level must be cube complete (common case) because we cannot
1562 // rely on the "getBaseLevel*" methods reliably otherwise.
Jamie Madill2db197c2013-10-24 17:49:35 -04001563 bool canCreateRenderTarget = isFaceLevelComplete(faceIndex, level) && isCubeComplete();
Jamie Madill07edd442013-07-19 16:36:58 -04001564
Jamie Madill2db197c2013-10-24 17:49:35 -04001565 if (!mImageArray[faceIndex][level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001566 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001567 mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001568 mDirtyImages = true;
1569 }
1570 else
1571 {
Jamie Madille83d1a92013-10-24 17:49:33 -04001572 ensureRenderTarget();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001573
Jamie Madill07bb8cf2013-10-24 17:49:44 -04001574 if (isValidFaceLevel(faceIndex, level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001575 {
Jamie Madill169d1112013-10-24 17:49:37 -04001576 updateStorageFaceLevel(faceIndex, level);
Jamie Madill07edd442013-07-19 16:36:58 -04001577
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001578 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1579
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +00001580 gl::Rectangle sourceRect;
1581 sourceRect.x = x;
1582 sourceRect.width = width;
1583 sourceRect.y = y;
1584 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001585
Jamie Madilld3d2a342013-10-07 10:46:35 -04001586 mRenderer->copyImage(source, sourceRect, gl::GetFormat(getBaseLevelInternalFormat(), clientVersion),
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +00001587 xoffset, yoffset, mTexStorage, target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001588 }
1589 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001590}
1591
1592void TextureCubeMap::storage(GLsizei levels, GLenum internalformat, GLsizei size)
1593{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001594 for (int level = 0; level < levels; level++)
1595 {
Geoff Langd3110192013-09-24 11:52:47 -04001596 GLsizei mipSize = std::max(1, size >> level);
Jamie Madill2db197c2013-10-24 17:49:35 -04001597 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001598 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001599 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, mipSize, mipSize, 1, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001600 }
1601 }
1602
1603 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1604 {
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, GL_NONE, 0, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001608 }
1609 }
1610
Jamie Madill3c0989c2013-10-24 17:49:39 -04001611 mImmutable = true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001612
Nicolas Capensbf712d02014-03-31 14:23:35 -04001613 setCompleteTexStorage(new rx::TextureStorageInterfaceCube(mRenderer, internalformat, IsRenderTargetUsage(mUsage), size, levels));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001614}
1615
1616void TextureCubeMap::generateMipmaps()
1617{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001618 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Geoff Lang98705b72014-03-31 16:00:03 -04001619 int levelCount = mipLevels();
Jamie Madill2db197c2013-10-24 17:49:35 -04001620 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001621 {
Geoff Lang98705b72014-03-31 16:00:03 -04001622 for (int level = 1; level < levelCount; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001623 {
Jamie Madill22f843a2013-10-24 17:49:36 -04001624 int faceLevelSize = (std::max(mImageArray[faceIndex][0]->getWidth() >> level, 1));
1625 redefineImage(faceIndex, level, mImageArray[faceIndex][0]->getInternalFormat(), faceLevelSize, faceLevelSize);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001626 }
1627 }
1628
1629 if (mTexStorage && mTexStorage->isRenderTarget())
1630 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001631 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001632 {
Geoff Lang98705b72014-03-31 16:00:03 -04001633 for (int level = 1; level < levelCount; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001634 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001635 mTexStorage->generateMipmap(faceIndex, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001636
Jamie Madill2db197c2013-10-24 17:49:35 -04001637 mImageArray[faceIndex][level]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001638 }
1639 }
1640 }
1641 else
1642 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001643 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001644 {
Geoff Lang98705b72014-03-31 16:00:03 -04001645 for (int level = 1; level < levelCount; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001646 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001647 mRenderer->generateMipmap(mImageArray[faceIndex][level], mImageArray[faceIndex][level - 1]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001648 }
1649 }
1650 }
1651}
1652
Jamie Madilld3d2a342013-10-07 10:46:35 -04001653const rx::Image *TextureCubeMap::getBaseLevelImage() const
1654{
1655 // Note: if we are not cube-complete, there is no single base level image that can describe all
1656 // cube faces, so this method is only well-defined for a cube-complete base level.
1657 return mImageArray[0][0];
1658}
1659
Jamie Madill2ebab852013-10-24 17:49:42 -04001660rx::TextureStorageInterface *TextureCubeMap::getBaseLevelStorage()
1661{
1662 return mTexStorage;
1663}
1664
Jamie Madill3c7fa222014-06-05 13:08:51 -04001665FramebufferAttachment *TextureCubeMap::getAttachment(GLenum target, GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001666{
Jamie Madill560a8d82014-05-21 13:06:20 -04001667 ASSERT(!IsCubemapTextureTarget(target));
Jamie Madill2db197c2013-10-24 17:49:35 -04001668 int faceIndex = targetToIndex(target);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001669
Jamie Madill3c7fa222014-06-05 13:08:51 -04001670 FramebufferAttachment *attachment = mRenderbufferProxies.get(level, faceIndex);
1671 if (!attachment)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001672 {
Jamie Madill3c7fa222014-06-05 13:08:51 -04001673 attachment = new FramebufferAttachment(mRenderer, id(), new TextureCubeMapAttachment(this, target, level));
1674 mRenderbufferProxies.add(level, faceIndex, attachment);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001675 }
1676
Jamie Madill3c7fa222014-06-05 13:08:51 -04001677 return attachment;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001678}
1679
Jamie Madill2db197c2013-10-24 17:49:35 -04001680unsigned int TextureCubeMap::getRenderTargetSerial(GLenum target, GLint level)
Geoff Lang8040f572013-07-25 16:49:54 -04001681{
Jamie Madill2db197c2013-10-24 17:49:35 -04001682 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(target, level) : 0);
Geoff Lang8040f572013-07-25 16:49:54 -04001683}
1684
1685rx::RenderTarget *TextureCubeMap::getRenderTarget(GLenum target, GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001686{
1687 ASSERT(IsCubemapTextureTarget(target));
1688
1689 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04001690 if (!ensureRenderTarget())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001691 {
1692 return NULL;
1693 }
1694
Jamie Madill169d1112013-10-24 17:49:37 -04001695 updateStorageFaceLevel(targetToIndex(target), level);
Geoff Lang8040f572013-07-25 16:49:54 -04001696
1697 // ensure this is NOT a depth texture
1698 if (isDepth(target, level))
1699 {
1700 return NULL;
1701 }
1702
1703 return mTexStorage->getRenderTarget(target, level);
1704}
1705
1706rx::RenderTarget *TextureCubeMap::getDepthStencil(GLenum target, GLint level)
1707{
1708 ASSERT(IsCubemapTextureTarget(target));
1709
1710 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04001711 if (!ensureRenderTarget())
Geoff Lang8040f572013-07-25 16:49:54 -04001712 {
1713 return NULL;
1714 }
1715
Jamie Madill169d1112013-10-24 17:49:37 -04001716 updateStorageFaceLevel(targetToIndex(target), level);
Geoff Lang8040f572013-07-25 16:49:54 -04001717
1718 // ensure this is a depth texture
1719 if (!isDepth(target, level))
1720 {
1721 return NULL;
1722 }
1723
1724 return mTexStorage->getRenderTarget(target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001725}
1726
Jamie Madill07bb8cf2013-10-24 17:49:44 -04001727bool TextureCubeMap::isValidFaceLevel(int faceIndex, int level) const
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +00001728{
Nicolas Capensbf712d02014-03-31 14:23:35 -04001729 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +00001730}
1731
Geoff Lang4907f2c2013-07-25 12:53:57 -04001732Texture3D::Texture3D(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_3D)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001733{
1734 mTexStorage = NULL;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001735
1736 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1737 {
1738 mImageArray[i] = renderer->createImage();
1739 }
1740}
1741
1742Texture3D::~Texture3D()
1743{
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001744 delete mTexStorage;
1745 mTexStorage = NULL;
1746
1747 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1748 {
1749 delete mImageArray[i];
1750 }
1751}
1752
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001753GLsizei Texture3D::getWidth(GLint level) const
1754{
1755 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getWidth() : 0;
1756}
1757
1758GLsizei Texture3D::getHeight(GLint level) const
1759{
1760 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getHeight() : 0;
1761}
1762
1763GLsizei Texture3D::getDepth(GLint level) const
1764{
1765 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getDepth() : 0;
1766}
1767
1768GLenum Texture3D::getInternalFormat(GLint level) const
1769{
1770 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getInternalFormat() : GL_NONE;
1771}
1772
1773GLenum Texture3D::getActualFormat(GLint level) const
1774{
Geoff Langcbf727a2014-02-10 12:50:45 -05001775 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getActualFormat() : GL_NONE;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001776}
1777
1778bool Texture3D::isCompressed(GLint level) const
1779{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001780 return IsFormatCompressed(getInternalFormat(level), mRenderer->getCurrentClientVersion());
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001781}
1782
1783bool Texture3D::isDepth(GLint level) const
1784{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001785 return GetDepthBits(getInternalFormat(level), mRenderer->getCurrentClientVersion()) > 0;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001786}
1787
Geoff Lang005df412013-10-16 14:12:50 -04001788void 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 +00001789{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001790 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Geoff Lang005df412013-10-16 14:12:50 -04001791 GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
1792 : GetSizedInternalFormat(format, type, clientVersion);
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001793 redefineImage(level, sizedInternalFormat, width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001794
Jamie Madilla2d4e552013-10-10 15:12:01 -04001795 bool fastUnpacked = false;
1796
1797 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1798 if (isFastUnpackable(unpack, sizedInternalFormat))
1799 {
1800 // Will try to create RT storage if it does not exist
1801 rx::RenderTarget *destRenderTarget = getRenderTarget(level);
1802 Box destArea(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1803
1804 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget))
1805 {
1806 // Ensure we don't overwrite our newly initialized data
1807 mImageArray[level]->markClean();
1808
1809 fastUnpacked = true;
1810 }
1811 }
1812
1813 if (!fastUnpacked)
1814 {
1815 Texture::setImage(unpack, type, pixels, mImageArray[level]);
1816 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001817}
1818
1819void Texture3D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
1820{
1821 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1822 redefineImage(level, format, width, height, depth);
1823
1824 Texture::setCompressedImage(imageSize, pixels, mImageArray[level]);
1825}
1826
Jamie Madill88f18f42013-09-18 14:36:19 -04001827void 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 +00001828{
Jamie Madillba4f10a2013-10-10 15:12:20 -04001829 bool fastUnpacked = false;
1830
1831 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1832 if (isFastUnpackable(unpack, getInternalFormat(level)))
1833 {
1834 rx::RenderTarget *destRenderTarget = getRenderTarget(level);
1835 Box destArea(xoffset, yoffset, zoffset, width, height, depth);
1836
1837 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, destRenderTarget))
1838 {
1839 // Ensure we don't overwrite our newly initialized data
1840 mImageArray[level]->markClean();
1841
1842 fastUnpacked = true;
1843 }
1844 }
1845
1846 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 +00001847 {
1848 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1849 }
1850}
1851
1852void Texture3D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
1853{
1854 if (Texture::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth, format, imageSize, pixels, mImageArray[level]))
1855 {
1856 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1857 }
1858}
1859
1860void Texture3D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
1861{
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001862 for (int level = 0; level < levels; level++)
1863 {
Jamie Madille664e202013-10-24 17:49:40 -04001864 GLsizei levelWidth = std::max(1, width >> level);
1865 GLsizei levelHeight = std::max(1, height >> level);
1866 GLsizei levelDepth = std::max(1, depth >> level);
1867 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, levelWidth, levelHeight, levelDepth, true);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001868 }
1869
1870 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1871 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001872 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, GL_NONE, 0, 0, 0, true);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001873 }
1874
Jamie Madille664e202013-10-24 17:49:40 -04001875 mImmutable = true;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001876
Nicolas Capensbf712d02014-03-31 14:23:35 -04001877 setCompleteTexStorage(new rx::TextureStorageInterface3D(mRenderer, internalformat, IsRenderTargetUsage(mUsage), width, height, depth, levels));
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001878}
1879
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001880void Texture3D::generateMipmaps()
1881{
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001882 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Geoff Lang98705b72014-03-31 16:00:03 -04001883 int levelCount = mipLevels();
1884 for (int level = 1; level < levelCount; level++)
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001885 {
Jamie Madill22f843a2013-10-24 17:49:36 -04001886 redefineImage(level, getBaseLevelInternalFormat(),
1887 std::max(getBaseLevelWidth() >> level, 1),
1888 std::max(getBaseLevelHeight() >> level, 1),
1889 std::max(getBaseLevelDepth() >> level, 1));
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001890 }
1891
1892 if (mTexStorage && mTexStorage->isRenderTarget())
1893 {
Geoff Lang98705b72014-03-31 16:00:03 -04001894 for (int level = 1; level < levelCount; level++)
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001895 {
Jamie Madill22f843a2013-10-24 17:49:36 -04001896 mTexStorage->generateMipmap(level);
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001897
Jamie Madill22f843a2013-10-24 17:49:36 -04001898 mImageArray[level]->markClean();
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001899 }
1900 }
1901 else
1902 {
Geoff Lang98705b72014-03-31 16:00:03 -04001903 for (int level = 1; level < levelCount; level++)
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001904 {
Jamie Madill22f843a2013-10-24 17:49:36 -04001905 mRenderer->generateMipmap(mImageArray[level], mImageArray[level - 1]);
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001906 }
1907 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001908}
1909
Jamie Madilld3d2a342013-10-07 10:46:35 -04001910const rx::Image *Texture3D::getBaseLevelImage() const
1911{
1912 return mImageArray[0];
1913}
1914
Jamie Madill2ebab852013-10-24 17:49:42 -04001915rx::TextureStorageInterface *Texture3D::getBaseLevelStorage()
1916{
1917 return mTexStorage;
1918}
1919
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001920void Texture3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1921{
Jamie Madill07edd442013-07-19 16:36:58 -04001922 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
1923 // the current level we're copying to is defined (with appropriate format, width & height)
1924 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
1925
1926 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001927 {
1928 mImageArray[level]->copy(xoffset, yoffset, zoffset, x, y, width, height, source);
1929 mDirtyImages = true;
1930 }
1931 else
1932 {
Jamie Madille83d1a92013-10-24 17:49:33 -04001933 ensureRenderTarget();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001934
Jamie Madill07bb8cf2013-10-24 17:49:44 -04001935 if (isValidLevel(level))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001936 {
Jamie Madill169d1112013-10-24 17:49:37 -04001937 updateStorageLevel(level);
Jamie Madill07edd442013-07-19 16:36:58 -04001938
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001939 gl::Rectangle sourceRect;
1940 sourceRect.x = x;
1941 sourceRect.width = width;
1942 sourceRect.y = y;
1943 sourceRect.height = height;
1944
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001945 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1946
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001947 mRenderer->copyImage(source, sourceRect,
Jamie Madilld3d2a342013-10-07 10:46:35 -04001948 gl::GetFormat(getBaseLevelInternalFormat(), clientVersion),
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001949 xoffset, yoffset, zoffset, mTexStorage, level);
1950 }
1951 }
1952}
1953
Jamie Madillf8989902013-07-19 16:36:58 -04001954bool Texture3D::isSamplerComplete(const SamplerState &samplerState) const
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001955{
Jamie Madilld3d2a342013-10-07 10:46:35 -04001956 GLsizei width = getBaseLevelWidth();
1957 GLsizei height = getBaseLevelHeight();
1958 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001959
1960 if (width <= 0 || height <= 0 || depth <= 0)
1961 {
1962 return false;
1963 }
1964
Geoff Langcec35902014-04-16 10:52:36 -04001965 if (!mRenderer->getCaps().textureCaps.get(getInternalFormat(0)).filtering)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001966 {
Jamie Madillf8989902013-07-19 16:36:58 -04001967 if (samplerState.magFilter != GL_NEAREST ||
1968 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001969 {
1970 return false;
1971 }
1972 }
1973
Jamie Madillf8989902013-07-19 16:36:58 -04001974 if (IsMipmapFiltered(samplerState) && !isMipmapComplete())
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001975 {
1976 return false;
1977 }
1978
1979 return true;
1980}
1981
1982bool Texture3D::isMipmapComplete() const
1983{
Geoff Lang98705b72014-03-31 16:00:03 -04001984 int levelCount = mipLevels();
Jamie Madill07edd442013-07-19 16:36:58 -04001985
Geoff Lang98705b72014-03-31 16:00:03 -04001986 for (int level = 0; level < levelCount; level++)
Jamie Madill07edd442013-07-19 16:36:58 -04001987 {
1988 if (!isLevelComplete(level))
1989 {
1990 return false;
1991 }
1992 }
1993
1994 return true;
1995}
1996
1997bool Texture3D::isLevelComplete(int level) const
1998{
1999 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
2000
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002001 if (isImmutable())
2002 {
2003 return true;
2004 }
2005
Jamie Madilld3d2a342013-10-07 10:46:35 -04002006 GLsizei width = getBaseLevelWidth();
2007 GLsizei height = getBaseLevelHeight();
2008 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002009
2010 if (width <= 0 || height <= 0 || depth <= 0)
2011 {
2012 return false;
2013 }
2014
Jamie Madill07edd442013-07-19 16:36:58 -04002015 if (level == 0)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002016 {
Jamie Madill07edd442013-07-19 16:36:58 -04002017 return true;
2018 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002019
Jamie Madill07edd442013-07-19 16:36:58 -04002020 rx::Image *levelImage = mImageArray[level];
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002021
Jamie Madilld3d2a342013-10-07 10:46:35 -04002022 if (levelImage->getInternalFormat() != getBaseLevelInternalFormat())
Jamie Madill07edd442013-07-19 16:36:58 -04002023 {
2024 return false;
2025 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002026
Jamie Madill07edd442013-07-19 16:36:58 -04002027 if (levelImage->getWidth() != std::max(1, width >> level))
2028 {
2029 return false;
2030 }
2031
2032 if (levelImage->getHeight() != std::max(1, height >> level))
2033 {
2034 return false;
2035 }
2036
2037 if (levelImage->getDepth() != std::max(1, depth >> level))
2038 {
2039 return false;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002040 }
2041
2042 return true;
2043}
2044
Jamie Madill3c7fa222014-06-05 13:08:51 -04002045FramebufferAttachment *Texture3D::getAttachment(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002046{
Jamie Madill3c7fa222014-06-05 13:08:51 -04002047 FramebufferAttachment *attachment = mRenderbufferProxies.get(level, layer);
2048 if (!attachment)
Geoff Lang8040f572013-07-25 16:49:54 -04002049 {
Jamie Madill3c7fa222014-06-05 13:08:51 -04002050 attachment = new FramebufferAttachment(mRenderer, id(), new Texture3DAttachment(this, level, layer));
2051 mRenderbufferProxies.add(level, 0, attachment);
Geoff Lang8040f572013-07-25 16:49:54 -04002052 }
2053
Jamie Madill3c7fa222014-06-05 13:08:51 -04002054 return attachment;
Geoff Lang8040f572013-07-25 16:49:54 -04002055}
2056
2057unsigned int Texture3D::getRenderTargetSerial(GLint level, GLint layer)
2058{
Jamie Madille83d1a92013-10-24 17:49:33 -04002059 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(level, layer) : 0);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002060}
2061
Jamie Madill07bb8cf2013-10-24 17:49:44 -04002062bool Texture3D::isValidLevel(int level) const
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002063{
Nicolas Capensbf712d02014-03-31 14:23:35 -04002064 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002065}
2066
Jamie Madill73b5d062013-10-24 17:49:38 -04002067void Texture3D::initializeStorage(bool renderTarget)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002068{
Jamie Madille664e202013-10-24 17:49:40 -04002069 // Only initialize the first time this texture is used as a render target or shader resource
2070 if (mTexStorage)
2071 {
2072 return;
2073 }
2074
2075 // do not attempt to create storage for nonexistant data
2076 if (!isLevelComplete(0))
2077 {
2078 return;
2079 }
2080
2081 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
2082
2083 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
2084 ASSERT(mTexStorage);
2085
2086 // flush image data to the storage
2087 updateStorage();
2088}
2089
2090rx::TextureStorageInterface3D *Texture3D::createCompleteStorage(bool renderTarget) const
2091{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002092 GLsizei width = getBaseLevelWidth();
2093 GLsizei height = getBaseLevelHeight();
2094 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002095
Jamie Madille664e202013-10-24 17:49:40 -04002096 ASSERT(width > 0 && height > 0 && depth > 0);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002097
Jamie Madille664e202013-10-24 17:49:40 -04002098 // use existing storage level count, when previously specified by TexStorage*D
Nicolas Capensbf712d02014-03-31 14:23:35 -04002099 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, depth));
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002100
Nicolas Capensbf712d02014-03-31 14:23:35 -04002101 return new rx::TextureStorageInterface3D(mRenderer, getBaseLevelInternalFormat(), renderTarget, width, height, depth, levels);
Jamie Madille664e202013-10-24 17:49:40 -04002102}
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002103
Jamie Madille664e202013-10-24 17:49:40 -04002104void Texture3D::setCompleteTexStorage(rx::TextureStorageInterface3D *newCompleteTexStorage)
2105{
2106 SafeDelete(mTexStorage);
2107 mTexStorage = newCompleteTexStorage;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002108 mDirtyImages = true;
Jamie Madille664e202013-10-24 17:49:40 -04002109
2110 // We do not support managed 3D storage, as that is D3D9/ES2-only
2111 ASSERT(!mTexStorage->isManaged());
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002112}
2113
Jamie Madill169d1112013-10-24 17:49:37 -04002114void Texture3D::updateStorage()
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002115{
Geoff Lang946b9482014-05-12 16:37:25 -04002116 ASSERT(mTexStorage != NULL);
2117 GLint storageLevels = mTexStorage->getLevelCount();
2118 for (int level = 0; level < storageLevels; level++)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002119 {
Geoff Lang946b9482014-05-12 16:37:25 -04002120 if (mImageArray[level]->isDirty() && isLevelComplete(level))
Jamie Madilld9b9a502013-10-10 17:46:13 -04002121 {
Jamie Madill169d1112013-10-24 17:49:37 -04002122 updateStorageLevel(level);
Jamie Madilld9b9a502013-10-10 17:46:13 -04002123 }
Jamie Madill07edd442013-07-19 16:36:58 -04002124 }
2125}
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002126
Jamie Madill169d1112013-10-24 17:49:37 -04002127void Texture3D::updateStorageLevel(int level)
Jamie Madill07edd442013-07-19 16:36:58 -04002128{
2129 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
Jamie Madillaee7ad82013-10-10 16:07:32 -04002130 ASSERT(isLevelComplete(level));
Jamie Madill07edd442013-07-19 16:36:58 -04002131
Jamie Madillaee7ad82013-10-10 16:07:32 -04002132 if (mImageArray[level]->isDirty())
Jamie Madill07edd442013-07-19 16:36:58 -04002133 {
Jamie Madillaee7ad82013-10-10 16:07:32 -04002134 commitRect(level, 0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002135 }
2136}
2137
Jamie Madille83d1a92013-10-24 17:49:33 -04002138bool Texture3D::ensureRenderTarget()
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002139{
Jamie Madille664e202013-10-24 17:49:40 -04002140 initializeStorage(true);
2141
2142 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0 && getBaseLevelDepth() > 0)
Jamie Madille83d1a92013-10-24 17:49:33 -04002143 {
Jamie Madille664e202013-10-24 17:49:40 -04002144 ASSERT(mTexStorage);
2145 if (!mTexStorage->isRenderTarget())
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002146 {
Jamie Madille664e202013-10-24 17:49:40 -04002147 rx::TextureStorageInterface3D *newRenderTargetStorage = createCompleteStorage(true);
2148
2149 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002150 {
Jamie Madille664e202013-10-24 17:49:40 -04002151 delete newRenderTargetStorage;
Jamie Madille83d1a92013-10-24 17:49:33 -04002152 return gl::error(GL_OUT_OF_MEMORY, false);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002153 }
Jamie Madille664e202013-10-24 17:49:40 -04002154
2155 setCompleteTexStorage(newRenderTargetStorage);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002156 }
2157 }
2158
Jamie Madille83d1a92013-10-24 17:49:33 -04002159 return (mTexStorage && mTexStorage->isRenderTarget());
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002160}
2161
Jamie Madilla2d4e552013-10-10 15:12:01 -04002162rx::RenderTarget *Texture3D::getRenderTarget(GLint level)
2163{
2164 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04002165 if (!ensureRenderTarget())
Jamie Madilla2d4e552013-10-10 15:12:01 -04002166 {
2167 return NULL;
2168 }
2169
Jamie Madill169d1112013-10-24 17:49:37 -04002170 updateStorageLevel(level);
Jamie Madilla2d4e552013-10-10 15:12:01 -04002171
2172 // ensure this is NOT a depth texture
2173 if (isDepth(level))
2174 {
2175 return NULL;
2176 }
2177
2178 return mTexStorage->getRenderTarget(level);
2179}
2180
Geoff Lang8040f572013-07-25 16:49:54 -04002181rx::RenderTarget *Texture3D::getRenderTarget(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002182{
Geoff Lang8040f572013-07-25 16:49:54 -04002183 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04002184 if (!ensureRenderTarget())
Geoff Lang8040f572013-07-25 16:49:54 -04002185 {
2186 return NULL;
2187 }
2188
Jamie Madill169d1112013-10-24 17:49:37 -04002189 updateStorage();
Geoff Lang8040f572013-07-25 16:49:54 -04002190
2191 // ensure this is NOT a depth texture
2192 if (isDepth(level))
2193 {
2194 return NULL;
2195 }
2196
2197 return mTexStorage->getRenderTarget(level, layer);
2198}
2199
2200rx::RenderTarget *Texture3D::getDepthStencil(GLint level, GLint layer)
2201{
2202 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04002203 if (!ensureRenderTarget())
Geoff Lang8040f572013-07-25 16:49:54 -04002204 {
2205 return NULL;
2206 }
2207
Jamie Madill169d1112013-10-24 17:49:37 -04002208 updateStorageLevel(level);
Geoff Lang8040f572013-07-25 16:49:54 -04002209
2210 // ensure this is a depth texture
2211 if (!isDepth(level))
2212 {
2213 return NULL;
2214 }
2215
2216 return mTexStorage->getRenderTarget(level, layer);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002217}
2218
Geoff Lang005df412013-10-16 14:12:50 -04002219void Texture3D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002220{
2221 // If there currently is a corresponding storage texture image, it has these parameters
Jamie Madilld3d2a342013-10-07 10:46:35 -04002222 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2223 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
2224 const int storageDepth = std::max(1, getBaseLevelDepth() >> level);
Geoff Lang005df412013-10-16 14:12:50 -04002225 const GLenum storageFormat = getBaseLevelInternalFormat();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002226
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00002227 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, false);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002228
2229 if (mTexStorage)
2230 {
Nicolas Capensbf712d02014-03-31 14:23:35 -04002231 const int storageLevels = mTexStorage->getLevelCount();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002232
2233 if ((level >= storageLevels && storageLevels != 0) ||
2234 width != storageWidth ||
2235 height != storageHeight ||
2236 depth != storageDepth ||
2237 internalformat != storageFormat) // Discard mismatched storage
2238 {
2239 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
2240 {
2241 mImageArray[i]->markDirty();
2242 }
2243
2244 delete mTexStorage;
2245 mTexStorage = NULL;
2246 mDirtyImages = true;
2247 }
2248 }
2249}
2250
2251void Texture3D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth)
2252{
Jamie Madill07bb8cf2013-10-24 17:49:44 -04002253 if (isValidLevel(level))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002254 {
2255 rx::Image *image = mImageArray[level];
Jamie Madill169d1112013-10-24 17:49:37 -04002256 if (image->copyToStorage(mTexStorage, level, xoffset, yoffset, zoffset, width, height, depth))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002257 {
2258 image->markClean();
2259 }
2260 }
2261}
2262
Geoff Lang4907f2c2013-07-25 12:53:57 -04002263Texture2DArray::Texture2DArray(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_2D_ARRAY)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002264{
2265 mTexStorage = NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002266
2267 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2268 {
2269 mLayerCounts[level] = 0;
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002270 mImageArray[level] = NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002271 }
2272}
2273
2274Texture2DArray::~Texture2DArray()
2275{
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002276 delete mTexStorage;
2277 mTexStorage = NULL;
Jamie Madill884a4622013-10-24 17:49:41 -04002278
2279 deleteImages();
2280}
2281
2282void Texture2DArray::deleteImages()
2283{
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002284 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2285 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002286 for (int layer = 0; layer < mLayerCounts[level]; ++layer)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002287 {
2288 delete mImageArray[level][layer];
2289 }
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002290 delete[] mImageArray[level];
Jamie Madill884a4622013-10-24 17:49:41 -04002291 mImageArray[level] = NULL;
2292 mLayerCounts[level] = 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002293 }
2294}
2295
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002296GLsizei Texture2DArray::getWidth(GLint level) const
2297{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002298 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 +00002299}
2300
2301GLsizei Texture2DArray::getHeight(GLint level) const
2302{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002303 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 +00002304}
2305
Jamie Madillb8f8b892014-01-07 10:12:50 -05002306GLsizei Texture2DArray::getLayers(GLint level) const
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002307{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002308 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mLayerCounts[level] : 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002309}
2310
2311GLenum Texture2DArray::getInternalFormat(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]->getInternalFormat() : GL_NONE;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002314}
2315
2316GLenum Texture2DArray::getActualFormat(GLint level) const
2317{
Geoff Langcbf727a2014-02-10 12:50:45 -05002318 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 +00002319}
2320
2321bool Texture2DArray::isCompressed(GLint level) const
2322{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00002323 return IsFormatCompressed(getInternalFormat(level), mRenderer->getCurrentClientVersion());
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002324}
2325
2326bool Texture2DArray::isDepth(GLint level) const
2327{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00002328 return GetDepthBits(getInternalFormat(level), mRenderer->getCurrentClientVersion()) > 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002329}
2330
Geoff Lang005df412013-10-16 14:12:50 -04002331void 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 +00002332{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00002333 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Geoff Lang005df412013-10-16 14:12:50 -04002334 GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
2335 : GetSizedInternalFormat(format, type, clientVersion);
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00002336 redefineImage(level, sizedInternalFormat, width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002337
Jamie Madill88f18f42013-09-18 14:36:19 -04002338 GLsizei inputDepthPitch = gl::GetDepthPitch(sizedInternalFormat, type, clientVersion, width, height, unpack.alignment);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002339
2340 for (int i = 0; i < depth; i++)
2341 {
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002342 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
Jamie Madill88f18f42013-09-18 14:36:19 -04002343 Texture::setImage(unpack, type, layerPixels, mImageArray[level][i]);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002344 }
2345}
2346
2347void Texture2DArray::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
2348{
2349 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
2350 redefineImage(level, format, width, height, depth);
2351
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002352 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2353 GLsizei inputDepthPitch = gl::GetDepthPitch(format, GL_UNSIGNED_BYTE, clientVersion, width, height, 1);
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;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002358 Texture::setCompressedImage(imageSize, layerPixels, mImageArray[level][i]);
2359 }
2360}
2361
Jamie Madill88f18f42013-09-18 14:36:19 -04002362void 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 +00002363{
Geoff Lang005df412013-10-16 14:12:50 -04002364 GLenum internalformat = getInternalFormat(level);
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002365 GLuint clientVersion = mRenderer->getCurrentClientVersion();
Jamie Madill88f18f42013-09-18 14:36:19 -04002366 GLsizei inputDepthPitch = gl::GetDepthPitch(internalformat, type, clientVersion, width, height, unpack.alignment);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002367
2368 for (int i = 0; i < depth; i++)
2369 {
2370 int layer = zoffset + i;
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002371 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002372
Jamie Madill88f18f42013-09-18 14:36:19 -04002373 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 +00002374 {
2375 commitRect(level, xoffset, yoffset, layer, width, height);
2376 }
2377 }
2378}
2379
2380void Texture2DArray::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
2381{
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002382 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2383 GLsizei inputDepthPitch = gl::GetDepthPitch(format, GL_UNSIGNED_BYTE, clientVersion, width, height, 1);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002384
2385 for (int i = 0; i < depth; i++)
2386 {
2387 int layer = zoffset + i;
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002388 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002389
2390 if (Texture::subImageCompressed(xoffset, yoffset, zoffset, width, height, 1, format, imageSize, layerPixels, mImageArray[level][layer]))
2391 {
2392 commitRect(level, xoffset, yoffset, layer, width, height);
2393 }
2394 }
2395}
2396
2397void Texture2DArray::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2398{
Jamie Madill884a4622013-10-24 17:49:41 -04002399 deleteImages();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002400
2401 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2402 {
Jamie Madill884a4622013-10-24 17:49:41 -04002403 GLsizei levelWidth = std::max(1, width >> level);
2404 GLsizei levelHeight = std::max(1, height >> level);
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002405
Jamie Madill884a4622013-10-24 17:49:41 -04002406 mLayerCounts[level] = (level < levels ? depth : 0);
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002407
Jamie Madill884a4622013-10-24 17:49:41 -04002408 if (mLayerCounts[level] > 0)
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002409 {
2410 // Create new images for this level
Jamie Madill884a4622013-10-24 17:49:41 -04002411 mImageArray[level] = new rx::Image*[mLayerCounts[level]];
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002412
2413 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002414 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002415 mImageArray[level][layer] = mRenderer->createImage();
2416 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, levelWidth,
2417 levelHeight, 1, true);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002418 }
2419 }
2420 }
2421
Jamie Madill884a4622013-10-24 17:49:41 -04002422 mImmutable = true;
Nicolas Capensbf712d02014-03-31 14:23:35 -04002423 setCompleteTexStorage(new rx::TextureStorageInterface2DArray(mRenderer, internalformat, IsRenderTargetUsage(mUsage), width, height, depth, levels));
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002424}
2425
2426void Texture2DArray::generateMipmaps()
2427{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002428 int baseWidth = getBaseLevelWidth();
2429 int baseHeight = getBaseLevelHeight();
2430 int baseDepth = getBaseLevelDepth();
2431 GLenum baseFormat = getBaseLevelInternalFormat();
2432
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00002433 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Geoff Lang98705b72014-03-31 16:00:03 -04002434 int levelCount = mipLevels();
2435 for (int level = 1; level < levelCount; level++)
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00002436 {
Jamie Madill22f843a2013-10-24 17:49:36 -04002437 redefineImage(level, baseFormat, std::max(baseWidth >> level, 1), std::max(baseHeight >> level, 1), baseDepth);
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00002438 }
2439
2440 if (mTexStorage && mTexStorage->isRenderTarget())
2441 {
Geoff Lang98705b72014-03-31 16:00:03 -04002442 for (int level = 1; level < levelCount; level++)
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00002443 {
2444 mTexStorage->generateMipmap(level);
2445
2446 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2447 {
2448 mImageArray[level][layer]->markClean();
2449 }
2450 }
2451 }
2452 else
2453 {
Geoff Lang98705b72014-03-31 16:00:03 -04002454 for (int level = 1; level < levelCount; level++)
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00002455 {
2456 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2457 {
2458 mRenderer->generateMipmap(mImageArray[level][layer], mImageArray[level - 1][layer]);
2459 }
2460 }
2461 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002462}
2463
Jamie Madilld3d2a342013-10-07 10:46:35 -04002464const rx::Image *Texture2DArray::getBaseLevelImage() const
2465{
Jamie Madill152ed092013-10-09 17:01:15 -04002466 return (mLayerCounts[0] > 0 ? mImageArray[0][0] : NULL);
Jamie Madilld3d2a342013-10-07 10:46:35 -04002467}
2468
Jamie Madill2ebab852013-10-24 17:49:42 -04002469rx::TextureStorageInterface *Texture2DArray::getBaseLevelStorage()
2470{
2471 return mTexStorage;
2472}
2473
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002474void Texture2DArray::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
2475{
Jamie Madill07edd442013-07-19 16:36:58 -04002476 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
2477 // the current level we're copying to is defined (with appropriate format, width & height)
2478 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
2479
2480 if (!mImageArray[level][0]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002481 {
2482 mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, x, y, width, height, source);
2483 mDirtyImages = true;
2484 }
2485 else
2486 {
Jamie Madille83d1a92013-10-24 17:49:33 -04002487 ensureRenderTarget();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002488
Jamie Madill07bb8cf2013-10-24 17:49:44 -04002489 if (isValidLevel(level))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002490 {
Jamie Madill169d1112013-10-24 17:49:37 -04002491 updateStorageLevel(level);
Jamie Madill07edd442013-07-19 16:36:58 -04002492
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002493 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2494
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002495 gl::Rectangle sourceRect;
2496 sourceRect.x = x;
2497 sourceRect.width = width;
2498 sourceRect.y = y;
2499 sourceRect.height = height;
2500
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002501 mRenderer->copyImage(source, sourceRect, gl::GetFormat(getInternalFormat(0), clientVersion),
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002502 xoffset, yoffset, zoffset, mTexStorage, level);
2503 }
2504 }
2505}
2506
Jamie Madillf8989902013-07-19 16:36:58 -04002507bool Texture2DArray::isSamplerComplete(const SamplerState &samplerState) const
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002508{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002509 GLsizei width = getBaseLevelWidth();
2510 GLsizei height = getBaseLevelHeight();
Jamie Madillb8f8b892014-01-07 10:12:50 -05002511 GLsizei depth = getLayers(0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002512
2513 if (width <= 0 || height <= 0 || depth <= 0)
2514 {
2515 return false;
2516 }
2517
Geoff Langcec35902014-04-16 10:52:36 -04002518 if (!mRenderer->getCaps().textureCaps.get(getBaseLevelInternalFormat()).filtering)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002519 {
Jamie Madillf8989902013-07-19 16:36:58 -04002520 if (samplerState.magFilter != GL_NEAREST ||
2521 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002522 {
2523 return false;
2524 }
2525 }
2526
Jamie Madillf8989902013-07-19 16:36:58 -04002527 if (IsMipmapFiltered(samplerState) && !isMipmapComplete())
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002528 {
2529 return false;
2530 }
2531
2532 return true;
2533}
2534
2535bool Texture2DArray::isMipmapComplete() const
2536{
Geoff Lang98705b72014-03-31 16:00:03 -04002537 int levelCount = mipLevels();
Jamie Madill07edd442013-07-19 16:36:58 -04002538
Geoff Lang98705b72014-03-31 16:00:03 -04002539 for (int level = 1; level < levelCount; level++)
Jamie Madill07edd442013-07-19 16:36:58 -04002540 {
2541 if (!isLevelComplete(level))
2542 {
2543 return false;
2544 }
2545 }
2546
2547 return true;
2548}
2549
2550bool Texture2DArray::isLevelComplete(int level) const
2551{
Jamie Madillb8f8b892014-01-07 10:12:50 -05002552 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray));
Jamie Madill07edd442013-07-19 16:36:58 -04002553
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002554 if (isImmutable())
2555 {
2556 return true;
2557 }
2558
Jamie Madilld3d2a342013-10-07 10:46:35 -04002559 GLsizei width = getBaseLevelWidth();
2560 GLsizei height = getBaseLevelHeight();
Jamie Madillb8f8b892014-01-07 10:12:50 -05002561 GLsizei layers = getLayers(0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002562
Jamie Madillb8f8b892014-01-07 10:12:50 -05002563 if (width <= 0 || height <= 0 || layers <= 0)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002564 {
2565 return false;
2566 }
2567
Jamie Madill07edd442013-07-19 16:36:58 -04002568 if (level == 0)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002569 {
Jamie Madill07edd442013-07-19 16:36:58 -04002570 return true;
2571 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002572
Jamie Madill07edd442013-07-19 16:36:58 -04002573 if (getInternalFormat(level) != getInternalFormat(0))
2574 {
2575 return false;
2576 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002577
Jamie Madill07edd442013-07-19 16:36:58 -04002578 if (getWidth(level) != std::max(1, width >> level))
2579 {
2580 return false;
2581 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002582
Jamie Madill07edd442013-07-19 16:36:58 -04002583 if (getHeight(level) != std::max(1, height >> level))
2584 {
2585 return false;
2586 }
2587
Jamie Madillb8f8b892014-01-07 10:12:50 -05002588 if (getLayers(level) != layers)
Jamie Madill07edd442013-07-19 16:36:58 -04002589 {
2590 return false;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002591 }
2592
2593 return true;
2594}
2595
Jamie Madill3c7fa222014-06-05 13:08:51 -04002596FramebufferAttachment *Texture2DArray::getAttachment(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002597{
Jamie Madill3c7fa222014-06-05 13:08:51 -04002598 FramebufferAttachment *attachment = mRenderbufferProxies.get(level, layer);
2599 if (!attachment)
Geoff Lang8040f572013-07-25 16:49:54 -04002600 {
Jamie Madill3c7fa222014-06-05 13:08:51 -04002601 attachment = new FramebufferAttachment(mRenderer, id(), new Texture2DArrayAttachment(this, level, layer));
2602 mRenderbufferProxies.add(level, 0, attachment);
Geoff Lang8040f572013-07-25 16:49:54 -04002603 }
2604
Jamie Madill3c7fa222014-06-05 13:08:51 -04002605 return attachment;
Geoff Lang8040f572013-07-25 16:49:54 -04002606}
2607
Jamie Madille83d1a92013-10-24 17:49:33 -04002608unsigned int Texture2DArray::getRenderTargetSerial(GLint level, GLint layer)
Geoff Lang8040f572013-07-25 16:49:54 -04002609{
Jamie Madille83d1a92013-10-24 17:49:33 -04002610 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(level, layer) : 0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002611}
2612
Jamie Madill07bb8cf2013-10-24 17:49:44 -04002613bool Texture2DArray::isValidLevel(int level) const
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002614{
Nicolas Capensbf712d02014-03-31 14:23:35 -04002615 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002616}
2617
Jamie Madill73b5d062013-10-24 17:49:38 -04002618void Texture2DArray::initializeStorage(bool renderTarget)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002619{
Jamie Madill884a4622013-10-24 17:49:41 -04002620 // Only initialize the first time this texture is used as a render target or shader resource
2621 if (mTexStorage)
2622 {
2623 return;
2624 }
2625
2626 // do not attempt to create storage for nonexistant data
2627 if (!isLevelComplete(0))
2628 {
2629 return;
2630 }
2631
2632 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
2633
2634 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
2635 ASSERT(mTexStorage);
2636
2637 // flush image data to the storage
2638 updateStorage();
2639}
2640
2641rx::TextureStorageInterface2DArray *Texture2DArray::createCompleteStorage(bool renderTarget) const
2642{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002643 GLsizei width = getBaseLevelWidth();
2644 GLsizei height = getBaseLevelHeight();
Jamie Madillb8f8b892014-01-07 10:12:50 -05002645 GLsizei depth = getLayers(0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002646
Jamie Madill884a4622013-10-24 17:49:41 -04002647 ASSERT(width > 0 && height > 0 && depth > 0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002648
Jamie Madill884a4622013-10-24 17:49:41 -04002649 // use existing storage level count, when previously specified by TexStorage*D
Nicolas Capensbf712d02014-03-31 14:23:35 -04002650 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002651
Nicolas Capensbf712d02014-03-31 14:23:35 -04002652 return new rx::TextureStorageInterface2DArray(mRenderer, getBaseLevelInternalFormat(), renderTarget, width, height, depth, levels);
Jamie Madill884a4622013-10-24 17:49:41 -04002653}
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002654
Jamie Madill884a4622013-10-24 17:49:41 -04002655void Texture2DArray::setCompleteTexStorage(rx::TextureStorageInterface2DArray *newCompleteTexStorage)
2656{
2657 SafeDelete(mTexStorage);
2658 mTexStorage = newCompleteTexStorage;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002659 mDirtyImages = true;
Jamie Madill884a4622013-10-24 17:49:41 -04002660
2661 // We do not support managed 2D array storage, as managed storage is ES2/D3D9 only
2662 ASSERT(!mTexStorage->isManaged());
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002663}
2664
Jamie Madill169d1112013-10-24 17:49:37 -04002665void Texture2DArray::updateStorage()
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002666{
Geoff Lang946b9482014-05-12 16:37:25 -04002667 ASSERT(mTexStorage != NULL);
2668 GLint storageLevels = mTexStorage->getLevelCount();
2669 for (int level = 0; level < storageLevels; level++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002670 {
Jamie Madilld9b9a502013-10-10 17:46:13 -04002671 if (isLevelComplete(level))
2672 {
Jamie Madill169d1112013-10-24 17:49:37 -04002673 updateStorageLevel(level);
Jamie Madilld9b9a502013-10-10 17:46:13 -04002674 }
Jamie Madill07edd442013-07-19 16:36:58 -04002675 }
2676}
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002677
Jamie Madill169d1112013-10-24 17:49:37 -04002678void Texture2DArray::updateStorageLevel(int level)
Jamie Madill07edd442013-07-19 16:36:58 -04002679{
Jamie Madillaee7ad82013-10-10 16:07:32 -04002680 ASSERT(level >= 0 && level < (int)ArraySize(mLayerCounts));
2681 ASSERT(isLevelComplete(level));
2682
Jamie Madill07edd442013-07-19 16:36:58 -04002683 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2684 {
Jamie Madillaee7ad82013-10-10 16:07:32 -04002685 ASSERT(mImageArray[level] != NULL && mImageArray[level][layer] != NULL);
2686 if (mImageArray[level][layer]->isDirty())
Jamie Madill07edd442013-07-19 16:36:58 -04002687 {
Jamie Madillaee7ad82013-10-10 16:07:32 -04002688 commitRect(level, 0, 0, layer, getWidth(level), getHeight(level));
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002689 }
2690 }
2691}
2692
Jamie Madille83d1a92013-10-24 17:49:33 -04002693bool Texture2DArray::ensureRenderTarget()
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002694{
Jamie Madill884a4622013-10-24 17:49:41 -04002695 initializeStorage(true);
2696
Jamie Madillb8f8b892014-01-07 10:12:50 -05002697 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0 && getLayers(0) > 0)
Jamie Madille83d1a92013-10-24 17:49:33 -04002698 {
Jamie Madill884a4622013-10-24 17:49:41 -04002699 ASSERT(mTexStorage);
2700 if (!mTexStorage->isRenderTarget())
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002701 {
Jamie Madill884a4622013-10-24 17:49:41 -04002702 rx::TextureStorageInterface2DArray *newRenderTargetStorage = createCompleteStorage(true);
2703
2704 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002705 {
Jamie Madill884a4622013-10-24 17:49:41 -04002706 delete newRenderTargetStorage;
Jamie Madille83d1a92013-10-24 17:49:33 -04002707 return gl::error(GL_OUT_OF_MEMORY, false);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002708 }
Jamie Madill884a4622013-10-24 17:49:41 -04002709
2710 setCompleteTexStorage(newRenderTargetStorage);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002711 }
2712 }
2713
Jamie Madille83d1a92013-10-24 17:49:33 -04002714 return (mTexStorage && mTexStorage->isRenderTarget());
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002715}
2716
Geoff Lang8040f572013-07-25 16:49:54 -04002717rx::RenderTarget *Texture2DArray::getRenderTarget(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002718{
Geoff Lang8040f572013-07-25 16:49:54 -04002719 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04002720 if (!ensureRenderTarget())
Geoff Lang8040f572013-07-25 16:49:54 -04002721 {
2722 return NULL;
2723 }
2724
Jamie Madill169d1112013-10-24 17:49:37 -04002725 updateStorageLevel(level);
Geoff Lang8040f572013-07-25 16:49:54 -04002726
2727 // ensure this is NOT a depth texture
2728 if (isDepth(level))
2729 {
2730 return NULL;
2731 }
2732
2733 return mTexStorage->getRenderTarget(level, layer);
2734}
2735
2736rx::RenderTarget *Texture2DArray::getDepthStencil(GLint level, GLint layer)
2737{
2738 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04002739 if (!ensureRenderTarget())
Geoff Lang8040f572013-07-25 16:49:54 -04002740 {
2741 return NULL;
2742 }
2743
Jamie Madill169d1112013-10-24 17:49:37 -04002744 updateStorageLevel(level);
Geoff Lang8040f572013-07-25 16:49:54 -04002745
2746 // ensure this is a depth texture
2747 if (!isDepth(level))
2748 {
2749 return NULL;
2750 }
2751
2752 return mTexStorage->getRenderTarget(level, layer);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002753}
2754
Geoff Lang005df412013-10-16 14:12:50 -04002755void Texture2DArray::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002756{
2757 // If there currently is a corresponding storage texture image, it has these parameters
Jamie Madilld3d2a342013-10-07 10:46:35 -04002758 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2759 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
Jamie Madillb8f8b892014-01-07 10:12:50 -05002760 const int storageDepth = getLayers(0);
Geoff Lang005df412013-10-16 14:12:50 -04002761 const GLenum storageFormat = getBaseLevelInternalFormat();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002762
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002763 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002764 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002765 delete mImageArray[level][layer];
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002766 }
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002767 delete[] mImageArray[level];
Jamie Madill152ed092013-10-09 17:01:15 -04002768 mImageArray[level] = NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002769 mLayerCounts[level] = depth;
2770
Jamie Madill152ed092013-10-09 17:01:15 -04002771 if (depth > 0)
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002772 {
Jamie Madill152ed092013-10-09 17:01:15 -04002773 mImageArray[level] = new rx::Image*[depth]();
2774
2775 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2776 {
2777 mImageArray[level][layer] = mRenderer->createImage();
2778 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, width, height, 1, false);
2779 }
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002780 }
2781
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002782 if (mTexStorage)
2783 {
Nicolas Capensbf712d02014-03-31 14:23:35 -04002784 const int storageLevels = mTexStorage->getLevelCount();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002785
2786 if ((level >= storageLevels && storageLevels != 0) ||
2787 width != storageWidth ||
2788 height != storageHeight ||
2789 depth != storageDepth ||
2790 internalformat != storageFormat) // Discard mismatched storage
2791 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002792 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002793 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002794 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002795 {
2796 mImageArray[level][layer]->markDirty();
2797 }
2798 }
2799
2800 delete mTexStorage;
2801 mTexStorage = NULL;
2802 mDirtyImages = true;
2803 }
2804 }
2805}
2806
2807void Texture2DArray::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint layerTarget, GLsizei width, GLsizei height)
2808{
Jamie Madillb8f8b892014-01-07 10:12:50 -05002809 if (isValidLevel(level) && layerTarget < getLayers(level))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002810 {
2811 rx::Image *image = mImageArray[level][layerTarget];
Jamie Madill169d1112013-10-24 17:49:37 -04002812 if (image->copyToStorage(mTexStorage, level, xoffset, yoffset, layerTarget, width, height))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002813 {
2814 image->markClean();
2815 }
2816 }
2817}
2818
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00002819}