blob: 55210ec920e835bf26fa565243b7ee9ae1f21613 [file] [log] [blame]
shannon.woods@transgaming.combdf2d802013-02-28 23:16:20 +00001#include "precompiled.h"
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00002//
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00003// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00004// Use of this source code is governed by a BSD-style license that can be
5// found in the LICENSE file.
6//
7
8// Texture.cpp: Implements the gl::Texture class and its derived classes
9// Texture2D and TextureCubeMap. Implements GL texture objects and related
10// functionality. [OpenGL ES 2.0.24] section 3.7 page 63.
11
12#include "libGLESv2/Texture.h"
13
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000014#include "libGLESv2/main.h"
shannonwoods@chromium.orga2ecfcc2013-05-30 00:11:59 +000015#include "common/mathutil.h"
16#include "common/utilities.h"
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +000017#include "libGLESv2/formatutils.h"
Geoff Langdce735c2013-06-04 10:21:18 -040018#include "libGLESv2/renderer/Blit9.h"
shannon.woods@transgaming.com486d9e92013-02-28 23:15:41 +000019#include "libGLESv2/Renderbuffer.h"
20#include "libGLESv2/renderer/Image.h"
21#include "libGLESv2/renderer/Renderer.h"
22#include "libGLESv2/renderer/TextureStorage.h"
23#include "libEGL/Surface.h"
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000024
25namespace gl
26{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000027
daniel@transgaming.com370482e2012-11-28 19:32:13 +000028Texture::Texture(rx::Renderer *renderer, GLuint id) : RefCountObject(id)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000029{
daniel@transgaming.com370482e2012-11-28 19:32:13 +000030 mRenderer = renderer;
31
daniel@transgaming.comebf139f2012-10-31 18:07:32 +000032 mSamplerState.minFilter = GL_NEAREST_MIPMAP_LINEAR;
33 mSamplerState.magFilter = GL_LINEAR;
34 mSamplerState.wrapS = GL_REPEAT;
35 mSamplerState.wrapT = GL_REPEAT;
shannon.woods%transgaming.com@gtempaccount.com0b3a8df2013-04-13 03:44:51 +000036 mSamplerState.wrapR = GL_REPEAT;
daniel@transgaming.comebf139f2012-10-31 18:07:32 +000037 mSamplerState.maxAnisotropy = 1.0f;
38 mSamplerState.lodOffset = 0;
Geoff Langc82fc412013-07-10 14:43:42 -040039 mSamplerState.compareMode = GL_NONE;
40 mSamplerState.compareFunc = GL_LEQUAL;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000041 mUsage = GL_NONE;
Geoff Langc82fc412013-07-10 14:43:42 -040042
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000043 mDirtyImages = true;
44
45 mImmutable = false;
46}
47
48Texture::~Texture()
49{
50}
51
52// Returns true on successful filter state update (valid enum parameter)
53bool Texture::setMinFilter(GLenum filter)
54{
55 switch (filter)
56 {
57 case GL_NEAREST:
58 case GL_LINEAR:
59 case GL_NEAREST_MIPMAP_NEAREST:
60 case GL_LINEAR_MIPMAP_NEAREST:
61 case GL_NEAREST_MIPMAP_LINEAR:
62 case GL_LINEAR_MIPMAP_LINEAR:
daniel@transgaming.com3c17ba62013-01-11 04:11:41 +000063 mSamplerState.minFilter = filter;
64 return true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000065 default:
66 return false;
67 }
68}
69
70// Returns true on successful filter state update (valid enum parameter)
71bool Texture::setMagFilter(GLenum filter)
72{
73 switch (filter)
74 {
75 case GL_NEAREST:
76 case GL_LINEAR:
daniel@transgaming.com3c17ba62013-01-11 04:11:41 +000077 mSamplerState.magFilter = filter;
78 return true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000079 default:
80 return false;
81 }
82}
83
84// Returns true on successful wrap state update (valid enum parameter)
85bool Texture::setWrapS(GLenum wrap)
86{
87 switch (wrap)
88 {
89 case GL_REPEAT:
90 case GL_CLAMP_TO_EDGE:
91 case GL_MIRRORED_REPEAT:
daniel@transgaming.com3c17ba62013-01-11 04:11:41 +000092 mSamplerState.wrapS = wrap;
93 return true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000094 default:
95 return false;
96 }
97}
98
99// Returns true on successful wrap state update (valid enum parameter)
100bool Texture::setWrapT(GLenum wrap)
101{
102 switch (wrap)
103 {
104 case GL_REPEAT:
105 case GL_CLAMP_TO_EDGE:
106 case GL_MIRRORED_REPEAT:
daniel@transgaming.com3c17ba62013-01-11 04:11:41 +0000107 mSamplerState.wrapT = wrap;
108 return true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000109 default:
110 return false;
111 }
112}
113
shannon.woods%transgaming.com@gtempaccount.com0b3a8df2013-04-13 03:44:51 +0000114// Returns true on successful wrap state update (valid enum parameter)
115bool Texture::setWrapR(GLenum wrap)
116{
117 switch (wrap)
118 {
119 case GL_REPEAT:
120 case GL_CLAMP_TO_EDGE:
121 case GL_MIRRORED_REPEAT:
122 mSamplerState.wrapR = wrap;
123 return true;
124 default:
125 return false;
126 }
127}
128
daniel@transgaming.com07ab8412012-07-12 15:17:09 +0000129// Returns true on successful max anisotropy update (valid anisotropy value)
130bool Texture::setMaxAnisotropy(float textureMaxAnisotropy, float contextMaxAnisotropy)
131{
132 textureMaxAnisotropy = std::min(textureMaxAnisotropy, contextMaxAnisotropy);
133 if (textureMaxAnisotropy < 1.0f)
134 {
135 return false;
136 }
daniel@transgaming.com3c17ba62013-01-11 04:11:41 +0000137
138 mSamplerState.maxAnisotropy = textureMaxAnisotropy;
139
daniel@transgaming.com07ab8412012-07-12 15:17:09 +0000140 return true;
141}
142
Geoff Langc82fc412013-07-10 14:43:42 -0400143bool Texture::setCompareMode(GLenum mode)
144{
145 // Acceptable mode parameters from GLES 3.0.2 spec, table 3.17
146 switch (mode)
147 {
148 case GL_NONE:
149 case GL_COMPARE_REF_TO_TEXTURE:
150 mSamplerState.compareMode = mode;
151 return true;
152 default:
153 return false;
154 }
155}
156
157bool Texture::setCompareFunc(GLenum func)
158{
159 // Acceptable function parameters from GLES 3.0.2 spec, table 3.17
160 switch (func)
161 {
162 case GL_LEQUAL:
163 case GL_GEQUAL:
164 case GL_LESS:
165 case GL_GREATER:
166 case GL_EQUAL:
167 case GL_NOTEQUAL:
168 case GL_ALWAYS:
169 case GL_NEVER:
170 mSamplerState.compareFunc = func;
171 return true;
172 default:
173 return false;
174 }
175}
176
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000177// Returns true on successful usage state update (valid enum parameter)
178bool Texture::setUsage(GLenum usage)
179{
180 switch (usage)
181 {
182 case GL_NONE:
183 case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
184 mUsage = usage;
185 return true;
186 default:
187 return false;
188 }
189}
190
191GLenum Texture::getMinFilter() const
192{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000193 return mSamplerState.minFilter;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000194}
195
196GLenum Texture::getMagFilter() const
197{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000198 return mSamplerState.magFilter;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000199}
200
201GLenum Texture::getWrapS() const
202{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000203 return mSamplerState.wrapS;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000204}
205
206GLenum Texture::getWrapT() const
207{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000208 return mSamplerState.wrapT;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000209}
210
shannon.woods%transgaming.com@gtempaccount.com0b3a8df2013-04-13 03:44:51 +0000211GLenum Texture::getWrapR() const
212{
213 return mSamplerState.wrapR;
214}
215
daniel@transgaming.com07ab8412012-07-12 15:17:09 +0000216float Texture::getMaxAnisotropy() const
217{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000218 return mSamplerState.maxAnisotropy;
219}
220
221int Texture::getLodOffset()
222{
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000223 rx::TextureStorageInterface *texture = getStorage(false);
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000224 return texture ? texture->getLodOffset() : 0;
225}
226
227void Texture::getSamplerState(SamplerState *sampler)
228{
229 *sampler = mSamplerState;
230 sampler->lodOffset = getLodOffset();
daniel@transgaming.com07ab8412012-07-12 15:17:09 +0000231}
232
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000233GLenum Texture::getUsage() const
234{
235 return mUsage;
236}
237
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +0000238bool Texture::isMipmapFiltered() const
239{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000240 switch (mSamplerState.minFilter)
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +0000241 {
242 case GL_NEAREST:
243 case GL_LINEAR:
244 return false;
245 case GL_NEAREST_MIPMAP_NEAREST:
246 case GL_LINEAR_MIPMAP_NEAREST:
247 case GL_NEAREST_MIPMAP_LINEAR:
248 case GL_LINEAR_MIPMAP_LINEAR:
249 return true;
250 default: UNREACHABLE();
251 return false;
252 }
253}
254
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +0000255void Texture::setImage(GLint unpackAlignment, GLenum type, const void *pixels, rx::Image *image)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000256{
257 if (pixels != NULL)
258 {
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +0000259 image->loadData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), unpackAlignment, type, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000260 mDirtyImages = true;
261 }
262}
263
daniel@transgaming.com31b13e12012-11-28 19:34:30 +0000264void Texture::setCompressedImage(GLsizei imageSize, const void *pixels, rx::Image *image)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000265{
266 if (pixels != NULL)
267 {
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000268 image->loadCompressedData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000269 mDirtyImages = true;
270 }
271}
272
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000273bool Texture::subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
274 GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, rx::Image *image)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000275{
276 if (pixels != NULL)
277 {
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +0000278 image->loadData(xoffset, yoffset, zoffset, width, height, depth, unpackAlignment, type, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000279 mDirtyImages = true;
280 }
281
282 return true;
283}
284
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000285bool Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
286 GLenum format, GLsizei imageSize, const void *pixels, rx::Image *image)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000287{
288 if (pixels != NULL)
289 {
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000290 image->loadCompressedData(xoffset, yoffset, zoffset, width, height, depth, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000291 mDirtyImages = true;
292 }
293
294 return true;
295}
296
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000297rx::TextureStorageInterface *Texture::getNativeTexture()
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000298{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000299 // ensure the underlying texture is created
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000300
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000301 rx::TextureStorageInterface *storage = getStorage(false);
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000302 if (storage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000303 {
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000304 updateTexture();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000305 }
306
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000307 return storage;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000308}
309
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000310bool Texture::hasDirtyImages() const
311{
312 return mDirtyImages;
313}
314
315void Texture::resetDirty()
316{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000317 mDirtyImages = false;
318}
319
320unsigned int Texture::getTextureSerial()
321{
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000322 rx::TextureStorageInterface *texture = getStorage(false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000323 return texture ? texture->getTextureSerial() : 0;
324}
325
326unsigned int Texture::getRenderTargetSerial(GLenum target)
327{
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000328 rx::TextureStorageInterface *texture = getStorage(true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000329 return texture ? texture->getRenderTargetSerial(target) : 0;
330}
331
332bool Texture::isImmutable() const
333{
334 return mImmutable;
335}
336
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +0000337GLint Texture::creationLevels(GLsizei width, GLsizei height, GLsizei depth) const
338{
339 // NPOT checks are not required in ES 3.0, NPOT texture support is assumed.
340 return 0; // Maximum number of levels
341}
342
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000343GLint Texture::creationLevels(GLsizei width, GLsizei height) const
344{
daniel@transgaming.comea32d482012-11-28 19:33:18 +0000345 if ((isPow2(width) && isPow2(height)) || mRenderer->getNonPower2TextureSupport())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000346 {
347 return 0; // Maximum number of levels
348 }
349 else
350 {
351 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
352 return 1;
353 }
354}
355
356GLint Texture::creationLevels(GLsizei size) const
357{
358 return creationLevels(size, size);
359}
360
daniel@transgaming.com370482e2012-11-28 19:32:13 +0000361Texture2D::Texture2D(rx::Renderer *renderer, GLuint id) : Texture(renderer, id)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000362{
363 mTexStorage = NULL;
364 mSurface = NULL;
365 mColorbufferProxy = NULL;
366 mProxyRefs = 0;
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000367
368 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
369 {
daniel@transgaming.com244e1832012-12-20 20:52:35 +0000370 mImageArray[i] = renderer->createImage();
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000371 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000372}
373
374Texture2D::~Texture2D()
375{
376 mColorbufferProxy = NULL;
377
378 delete mTexStorage;
379 mTexStorage = NULL;
380
381 if (mSurface)
382 {
383 mSurface->setBoundTexture(NULL);
384 mSurface = NULL;
385 }
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000386
387 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
388 {
389 delete mImageArray[i];
390 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000391}
392
393// We need to maintain a count of references to renderbuffers acting as
394// proxies for this texture, so that we do not attempt to use a pointer
395// to a renderbuffer proxy which has been deleted.
396void Texture2D::addProxyRef(const Renderbuffer *proxy)
397{
398 mProxyRefs++;
399}
400
401void Texture2D::releaseProxy(const Renderbuffer *proxy)
402{
403 if (mProxyRefs > 0)
404 mProxyRefs--;
405
406 if (mProxyRefs == 0)
407 mColorbufferProxy = NULL;
408}
409
410GLenum Texture2D::getTarget() const
411{
412 return GL_TEXTURE_2D;
413}
414
415GLsizei Texture2D::getWidth(GLint level) const
416{
417 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000418 return mImageArray[level]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000419 else
420 return 0;
421}
422
423GLsizei Texture2D::getHeight(GLint level) const
424{
425 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000426 return mImageArray[level]->getHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000427 else
428 return 0;
429}
430
431GLenum Texture2D::getInternalFormat(GLint level) const
432{
433 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000434 return mImageArray[level]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000435 else
436 return GL_NONE;
437}
438
daniel@transgaming.com20d36662012-10-31 19:51:43 +0000439GLenum Texture2D::getActualFormat(GLint level) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000440{
441 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000442 return mImageArray[level]->getActualFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000443 else
444 return D3DFMT_UNKNOWN;
445}
446
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000447void Texture2D::redefineImage(GLint level, GLint internalformat, GLsizei width, GLsizei height)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000448{
449 releaseTexImage();
shannon.woods@transgaming.com8a406682013-02-28 23:15:26 +0000450
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000451 // If there currently is a corresponding storage texture image, it has these parameters
452 const int storageWidth = std::max(1, mImageArray[0]->getWidth() >> level);
453 const int storageHeight = std::max(1, mImageArray[0]->getHeight() >> level);
454 const int storageFormat = mImageArray[0]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000455
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000456 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, width, height, 1, false);
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000457
458 if (mTexStorage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000459 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000460 const int storageLevels = mTexStorage->levelCount();
461
462 if ((level >= storageLevels && storageLevels != 0) ||
463 width != storageWidth ||
464 height != storageHeight ||
465 internalformat != storageFormat) // Discard mismatched storage
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000466 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000467 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
468 {
469 mImageArray[i]->markDirty();
470 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000471
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000472 delete mTexStorage;
473 mTexStorage = NULL;
474 mDirtyImages = true;
475 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000476 }
477}
478
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +0000479void Texture2D::setImage(GLint level, GLsizei width, GLsizei height, GLint internalFormat, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000480{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +0000481 GLuint clientVersion = mRenderer->getCurrentClientVersion();
482 GLint sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
483 : GetSizedInternalFormat(format, type, clientVersion);
484 redefineImage(level, sizedInternalFormat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000485
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +0000486 Texture::setImage(unpackAlignment, type, pixels, mImageArray[level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000487}
488
489void Texture2D::bindTexImage(egl::Surface *surface)
490{
491 releaseTexImage();
492
daniel@transgaming.com106e1f72012-10-31 18:38:36 +0000493 GLint internalformat = surface->getFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000494
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000495 mImageArray[0]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, surface->getWidth(), surface->getHeight(), 1, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000496
497 delete mTexStorage;
daniel@transgaming.comd8353dd2012-12-20 21:11:14 +0000498 mTexStorage = new rx::TextureStorageInterface2D(mRenderer, surface->getSwapChain());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000499
500 mDirtyImages = true;
501 mSurface = surface;
502 mSurface->setBoundTexture(this);
503}
504
505void Texture2D::releaseTexImage()
506{
507 if (mSurface)
508 {
509 mSurface->setBoundTexture(NULL);
510 mSurface = NULL;
511
512 if (mTexStorage)
513 {
514 delete mTexStorage;
515 mTexStorage = NULL;
516 }
517
518 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
519 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000520 mImageArray[i]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000521 }
522 }
523}
524
525void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
526{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000527 // 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 +0000528 redefineImage(level, format, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000529
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000530 Texture::setCompressedImage(imageSize, pixels, mImageArray[level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000531}
532
533void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
534{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000535 if (level < levelCount())
536 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000537 rx::Image *image = mImageArray[level];
daniel@transgaming.com0f195ad2012-10-31 19:51:59 +0000538 if (image->updateSurface(mTexStorage, level, xoffset, yoffset, width, height))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000539 {
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000540 image->markClean();
541 }
542 }
543}
544
545void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
546{
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000547 if (Texture::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpackAlignment, pixels, mImageArray[level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000548 {
549 commitRect(level, xoffset, yoffset, width, height);
550 }
551}
552
553void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
554{
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000555 if (Texture::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000556 {
557 commitRect(level, xoffset, yoffset, width, height);
558 }
559}
560
561void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
562{
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +0000563 GLuint clientVersion = mRenderer->getCurrentClientVersion();
564 GLint sizedInternalFormat = IsSizedInternalFormat(format, clientVersion) ? format
565 : GetSizedInternalFormat(format, GL_UNSIGNED_BYTE, clientVersion);
566 redefineImage(level, sizedInternalFormat, width, height);
shannon.woods@transgaming.com8a406682013-02-28 23:15:26 +0000567
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000568 if (!mImageArray[level]->isRenderableFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000569 {
shannon.woods%transgaming.com@gtempaccount.come5dcce72013-04-13 03:44:33 +0000570 mImageArray[level]->copy(0, 0, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000571 mDirtyImages = true;
572 }
573 else
574 {
575 if (!mTexStorage || !mTexStorage->isRenderTarget())
576 {
577 convertToRenderTarget();
578 }
579
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000580 mImageArray[level]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000581
582 if (width != 0 && height != 0 && level < levelCount())
583 {
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +0000584 gl::Rectangle sourceRect;
585 sourceRect.x = x;
586 sourceRect.width = width;
587 sourceRect.y = y;
588 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000589
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +0000590 mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000591 }
592 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000593}
594
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +0000595void 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 +0000596{
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +0000597 if (xoffset + width > mImageArray[level]->getWidth() || yoffset + height > mImageArray[level]->getHeight() || zoffset != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000598 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +0000599 return gl::error(GL_INVALID_VALUE);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000600 }
601
Jamie Madill07edd442013-07-19 16:36:58 -0400602 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
603 // the current level we're copying to is defined (with appropriate format, width & height)
604 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
605
606 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000607 {
shannon.woods%transgaming.com@gtempaccount.come5dcce72013-04-13 03:44:33 +0000608 mImageArray[level]->copy(xoffset, yoffset, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000609 mDirtyImages = true;
610 }
611 else
612 {
613 if (!mTexStorage || !mTexStorage->isRenderTarget())
614 {
615 convertToRenderTarget();
616 }
617
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000618 if (level < levelCount())
619 {
Jamie Madill07edd442013-07-19 16:36:58 -0400620 updateTextureLevel(level);
621
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +0000622 GLuint clientVersion = mRenderer->getCurrentClientVersion();
623
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +0000624 gl::Rectangle sourceRect;
625 sourceRect.x = x;
626 sourceRect.width = width;
627 sourceRect.y = y;
628 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000629
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +0000630 mRenderer->copyImage(source, sourceRect,
631 gl::GetFormat(mImageArray[0]->getInternalFormat(), clientVersion),
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +0000632 xoffset, yoffset, mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000633 }
634 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000635}
636
637void Texture2D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height)
638{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000639 delete mTexStorage;
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000640 mTexStorage = new rx::TextureStorageInterface2D(mRenderer, levels, internalformat, mUsage, false, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000641 mImmutable = true;
642
643 for (int level = 0; level < levels; level++)
644 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000645 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, width, height, 1, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000646 width = std::max(1, width >> 1);
647 height = std::max(1, height >> 1);
648 }
649
650 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
651 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000652 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000653 }
654
655 if (mTexStorage->isManaged())
656 {
657 int levels = levelCount();
658
659 for (int level = 0; level < levels; level++)
660 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000661 mImageArray[level]->setManagedSurface(mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000662 }
663 }
664}
665
666// Tests for 2D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85.
667bool Texture2D::isSamplerComplete() const
668{
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000669 GLsizei width = mImageArray[0]->getWidth();
670 GLsizei height = mImageArray[0]->getHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000671
672 if (width <= 0 || height <= 0)
673 {
674 return false;
675 }
676
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +0000677 bool mipmapping = isMipmapFiltered();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000678
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000679 if (!IsTextureFilteringSupported(getInternalFormat(0), mRenderer))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000680 {
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000681 if (mSamplerState.magFilter != GL_NEAREST ||
682 (mSamplerState.minFilter != GL_NEAREST && mSamplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000683 {
684 return false;
685 }
686 }
687
daniel@transgaming.comea32d482012-11-28 19:33:18 +0000688 bool npotSupport = mRenderer->getNonPower2TextureSupport();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000689
690 if (!npotSupport)
691 {
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000692 if ((mSamplerState.wrapS != GL_CLAMP_TO_EDGE && !isPow2(width)) ||
693 (mSamplerState.wrapT != GL_CLAMP_TO_EDGE && !isPow2(height)))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000694 {
695 return false;
696 }
697 }
698
699 if (mipmapping)
700 {
701 if (!npotSupport)
702 {
703 if (!isPow2(width) || !isPow2(height))
704 {
705 return false;
706 }
707 }
708
709 if (!isMipmapComplete())
710 {
711 return false;
712 }
713 }
714
Geoff Langc82fc412013-07-10 14:43:42 -0400715 // OpenGLES 3.0.2 spec section 3.8.13 states that a texture is not mipmap complete if:
716 // The internalformat specified for the texture arrays is a sized internal depth or
717 // depth and stencil format (see table 3.13), the value of TEXTURE_COMPARE_-
718 // MODE is NONE, and either the magnification filter is not NEAREST or the mini-
719 // fication filter is neither NEAREST nor NEAREST_MIPMAP_NEAREST.
720 if (gl::GetDepthBits(getInternalFormat(0), mRenderer->getCurrentClientVersion()) > 0)
721 {
722 if (mSamplerState.compareMode == GL_NONE)
723 {
724 if ((mSamplerState.minFilter != GL_NEAREST && mSamplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST) ||
725 mSamplerState.magFilter != GL_NEAREST)
726 {
727 return false;
728 }
729 }
730 }
731
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000732 return true;
733}
734
735// Tests for 2D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
736bool Texture2D::isMipmapComplete() const
737{
Jamie Madill07edd442013-07-19 16:36:58 -0400738 GLsizei width = mImageArray[0]->getWidth();
739 GLsizei height = mImageArray[0]->getHeight();
740
741 int q = log2(std::max(width, height));
742
743 for (int level = 0; level <= q; level++)
744 {
745 if (!isLevelComplete(level))
746 {
747 return false;
748 }
749 }
750
751 return true;
752}
753
754bool Texture2D::isLevelComplete(int level) const
755{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000756 if (isImmutable())
757 {
758 return true;
759 }
760
Jamie Madill07edd442013-07-19 16:36:58 -0400761 const rx::Image *baseImage = mImageArray[0];
762 GLsizei width = baseImage->getWidth();
763 GLsizei height = baseImage->getHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000764
765 if (width <= 0 || height <= 0)
766 {
767 return false;
768 }
769
Jamie Madill07edd442013-07-19 16:36:58 -0400770 // The base image level is complete if the width and height are positive
771 if (level == 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000772 {
Jamie Madill07edd442013-07-19 16:36:58 -0400773 return true;
774 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000775
Jamie Madill07edd442013-07-19 16:36:58 -0400776 ASSERT(level >= 1 && level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
777 rx::Image *image = mImageArray[level];
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000778
Jamie Madill07edd442013-07-19 16:36:58 -0400779 if (image->getInternalFormat() != baseImage->getInternalFormat())
780 {
781 return false;
782 }
783
784 if (image->getWidth() != std::max(1, width >> level))
785 {
786 return false;
787 }
788
789 if (image->getHeight() != std::max(1, height >> level))
790 {
791 return false;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000792 }
793
794 return true;
795}
796
797bool Texture2D::isCompressed(GLint level) const
798{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000799 return IsFormatCompressed(getInternalFormat(level), mRenderer->getCurrentClientVersion());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000800}
801
802bool Texture2D::isDepth(GLint level) const
803{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000804 return GetDepthBits(getInternalFormat(level), mRenderer->getCurrentClientVersion()) > 0;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000805}
806
daniel@transgaming.comf032cb82012-10-31 19:51:52 +0000807// Constructs a native texture resource from the texture images
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000808void Texture2D::createTexture()
809{
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000810 GLsizei width = mImageArray[0]->getWidth();
811 GLsizei height = mImageArray[0]->getHeight();
daniel@transgaming.come6a09842012-09-17 21:28:55 +0000812
813 if (!(width > 0 && height > 0))
daniel@transgaming.comf032cb82012-10-31 19:51:52 +0000814 return; // do not attempt to create native textures for nonexistant data
daniel@transgaming.come6a09842012-09-17 21:28:55 +0000815
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000816 GLint levels = creationLevels(width, height);
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000817 GLenum internalformat = mImageArray[0]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000818
819 delete mTexStorage;
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000820 mTexStorage = new rx::TextureStorageInterface2D(mRenderer, levels, internalformat, mUsage, false, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000821
822 if (mTexStorage->isManaged())
823 {
824 int levels = levelCount();
825
826 for (int level = 0; level < levels; level++)
827 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000828 mImageArray[level]->setManagedSurface(mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000829 }
830 }
831
832 mDirtyImages = true;
833}
834
835void Texture2D::updateTexture()
836{
Jamie Madilleb3665c2013-07-19 16:36:57 -0400837 int levels = (isMipmapComplete() ? levelCount() : 1);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000838
839 for (int level = 0; level < levels; level++)
840 {
Jamie Madill07edd442013-07-19 16:36:58 -0400841 updateTextureLevel(level);
842 }
843}
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000844
Jamie Madill07edd442013-07-19 16:36:58 -0400845void Texture2D::updateTextureLevel(int level)
846{
847 ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
848 rx::Image *image = mImageArray[level];
849
850 if (image->isDirty())
851 {
852 commitRect(level, 0, 0, mImageArray[level]->getWidth(), mImageArray[level]->getHeight());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000853 }
854}
855
856void Texture2D::convertToRenderTarget()
857{
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000858 rx::TextureStorageInterface2D *newTexStorage = NULL;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000859
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000860 if (mImageArray[0]->getWidth() != 0 && mImageArray[0]->getHeight() != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000861 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000862 GLsizei width = mImageArray[0]->getWidth();
863 GLsizei height = mImageArray[0]->getHeight();
shannon.woods@transgaming.com6bb48862013-02-28 23:09:34 +0000864 GLint levels = mTexStorage != NULL ? mTexStorage->levelCount() : creationLevels(width, height);
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000865 GLenum internalformat = mImageArray[0]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000866
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000867 newTexStorage = new rx::TextureStorageInterface2D(mRenderer, levels, internalformat, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, true, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000868
869 if (mTexStorage != NULL)
870 {
daniel@transgaming.com1d80eee2012-11-28 19:33:31 +0000871 if (!mRenderer->copyToRenderTarget(newTexStorage, mTexStorage))
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +0000872 {
873 delete newTexStorage;
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +0000874 return gl::error(GL_OUT_OF_MEMORY);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000875 }
876 }
877 }
878
879 delete mTexStorage;
880 mTexStorage = newTexStorage;
881
882 mDirtyImages = true;
883}
884
885void Texture2D::generateMipmaps()
886{
daniel@transgaming.comea32d482012-11-28 19:33:18 +0000887 if (!mRenderer->getNonPower2TextureSupport())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000888 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000889 if (!isPow2(mImageArray[0]->getWidth()) || !isPow2(mImageArray[0]->getHeight()))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000890 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +0000891 return gl::error(GL_INVALID_OPERATION);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000892 }
893 }
894
895 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000896 unsigned int q = log2(std::max(mImageArray[0]->getWidth(), mImageArray[0]->getHeight()));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000897 for (unsigned int i = 1; i <= q; i++)
898 {
shannon.woods@transgaming.com8a406682013-02-28 23:15:26 +0000899 redefineImage(i, mImageArray[0]->getInternalFormat(),
900 std::max(mImageArray[0]->getWidth() >> i, 1),
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000901 std::max(mImageArray[0]->getHeight() >> i, 1));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000902 }
903
904 if (mTexStorage && mTexStorage->isRenderTarget())
905 {
906 for (unsigned int i = 1; i <= q; i++)
907 {
daniel@transgaming.com0ad830b2012-10-31 19:52:12 +0000908 mTexStorage->generateMipmap(i);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000909
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000910 mImageArray[i]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000911 }
912 }
913 else
914 {
915 for (unsigned int i = 1; i <= q; i++)
916 {
daniel@transgaming.com4ba24062012-12-20 20:54:24 +0000917 mRenderer->generateMipmap(mImageArray[i], mImageArray[i - 1]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000918 }
919 }
920}
921
922Renderbuffer *Texture2D::getRenderbuffer(GLenum target)
923{
924 if (target != GL_TEXTURE_2D)
925 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +0000926 return gl::error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000927 }
928
929 if (mColorbufferProxy == NULL)
930 {
daniel@transgaming.com70062c92012-11-28 19:32:30 +0000931 mColorbufferProxy = new Renderbuffer(mRenderer, id(), new RenderbufferTexture2D(this, target));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000932 }
933
934 return mColorbufferProxy;
935}
936
daniel@transgaming.comd186dc72012-11-28 19:40:16 +0000937rx::RenderTarget *Texture2D::getRenderTarget(GLenum target)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000938{
939 ASSERT(target == GL_TEXTURE_2D);
940
941 // ensure the underlying texture is created
942 if (getStorage(true) == NULL)
943 {
944 return NULL;
945 }
946
947 updateTexture();
948
949 // ensure this is NOT a depth texture
950 if (isDepth(0))
951 {
952 return NULL;
953 }
daniel@transgaming.com34da3972012-12-20 21:10:29 +0000954
daniel@transgaming.comd186dc72012-11-28 19:40:16 +0000955 return mTexStorage->getRenderTarget();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000956}
957
daniel@transgaming.comd186dc72012-11-28 19:40:16 +0000958rx::RenderTarget *Texture2D::getDepthStencil(GLenum target)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000959{
960 ASSERT(target == GL_TEXTURE_2D);
961
962 // ensure the underlying texture is created
963 if (getStorage(true) == NULL)
964 {
965 return NULL;
966 }
967
968 updateTexture();
969
970 // ensure this is actually a depth texture
971 if (!isDepth(0))
972 {
973 return NULL;
974 }
daniel@transgaming.comd186dc72012-11-28 19:40:16 +0000975 return mTexStorage->getRenderTarget();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000976}
977
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +0000978int Texture2D::levelCount()
979{
shannon.woods@transgaming.com5016f8e2013-02-28 23:20:57 +0000980 return mTexStorage ? mTexStorage->levelCount() : 0;
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +0000981}
982
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000983rx::TextureStorageInterface *Texture2D::getStorage(bool renderTarget)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000984{
985 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
986 {
987 if (renderTarget)
988 {
989 convertToRenderTarget();
990 }
991 else
992 {
993 createTexture();
994 }
995 }
996
997 return mTexStorage;
998}
999
daniel@transgaming.com370482e2012-11-28 19:32:13 +00001000TextureCubeMap::TextureCubeMap(rx::Renderer *renderer, GLuint id) : Texture(renderer, id)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001001{
1002 mTexStorage = NULL;
1003 for (int i = 0; i < 6; i++)
1004 {
1005 mFaceProxies[i] = NULL;
1006 mFaceProxyRefs[i] = 0;
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001007
1008 for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
1009 {
daniel@transgaming.com244e1832012-12-20 20:52:35 +00001010 mImageArray[i][j] = renderer->createImage();
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001011 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001012 }
1013}
1014
1015TextureCubeMap::~TextureCubeMap()
1016{
1017 for (int i = 0; i < 6; i++)
1018 {
1019 mFaceProxies[i] = NULL;
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001020
1021 for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
1022 {
1023 delete mImageArray[i][j];
1024 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001025 }
1026
1027 delete mTexStorage;
1028 mTexStorage = NULL;
1029}
1030
1031// We need to maintain a count of references to renderbuffers acting as
1032// proxies for this texture, so that the texture is not deleted while
1033// proxy references still exist. If the reference count drops to zero,
1034// we set our proxy pointer NULL, so that a new attempt at referencing
1035// will cause recreation.
1036void TextureCubeMap::addProxyRef(const Renderbuffer *proxy)
1037{
1038 for (int i = 0; i < 6; i++)
1039 {
1040 if (mFaceProxies[i] == proxy)
1041 mFaceProxyRefs[i]++;
1042 }
1043}
1044
1045void TextureCubeMap::releaseProxy(const Renderbuffer *proxy)
1046{
1047 for (int i = 0; i < 6; i++)
1048 {
1049 if (mFaceProxies[i] == proxy)
1050 {
1051 if (mFaceProxyRefs[i] > 0)
1052 mFaceProxyRefs[i]--;
1053
1054 if (mFaceProxyRefs[i] == 0)
1055 mFaceProxies[i] = NULL;
1056 }
1057 }
1058}
1059
1060GLenum TextureCubeMap::getTarget() const
1061{
1062 return GL_TEXTURE_CUBE_MAP;
1063}
1064
1065GLsizei TextureCubeMap::getWidth(GLenum target, GLint level) const
1066{
1067 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001068 return mImageArray[faceIndex(target)][level]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001069 else
1070 return 0;
1071}
1072
1073GLsizei TextureCubeMap::getHeight(GLenum target, GLint level) const
1074{
1075 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001076 return mImageArray[faceIndex(target)][level]->getHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001077 else
1078 return 0;
1079}
1080
1081GLenum TextureCubeMap::getInternalFormat(GLenum target, GLint level) const
1082{
1083 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001084 return mImageArray[faceIndex(target)][level]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001085 else
1086 return GL_NONE;
1087}
1088
daniel@transgaming.com20d36662012-10-31 19:51:43 +00001089GLenum TextureCubeMap::getActualFormat(GLenum target, GLint level) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001090{
1091 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001092 return mImageArray[faceIndex(target)][level]->getActualFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001093 else
1094 return D3DFMT_UNKNOWN;
1095}
1096
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001097void TextureCubeMap::setImagePosX(GLint level, GLsizei width, GLsizei height, GLint internalFormat, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001098{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001099 setImage(0, level, width, height, internalFormat, format, type, unpackAlignment, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001100}
1101
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001102void TextureCubeMap::setImageNegX(GLint level, GLsizei width, GLsizei height, GLint internalFormat, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001103{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001104 setImage(1, level, width, height, internalFormat, format, type, unpackAlignment, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001105}
1106
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001107void TextureCubeMap::setImagePosY(GLint level, GLsizei width, GLsizei height, GLint internalFormat, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001108{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001109 setImage(2, level, width, height, internalFormat, format, type, unpackAlignment, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001110}
1111
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001112void TextureCubeMap::setImageNegY(GLint level, GLsizei width, GLsizei height, GLint internalFormat, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001113{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001114 setImage(3, level, width, height, internalFormat, format, type, unpackAlignment, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001115}
1116
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001117void TextureCubeMap::setImagePosZ(GLint level, GLsizei width, GLsizei height, GLint internalFormat, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001118{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001119 setImage(4, level, width, height, internalFormat, format, type, unpackAlignment, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001120}
1121
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001122void TextureCubeMap::setImageNegZ(GLint level, GLsizei width, GLsizei height, GLint internalFormat, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001123{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001124 setImage(5, level, width, height, internalFormat, format, type, unpackAlignment, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001125}
1126
1127void TextureCubeMap::setCompressedImage(GLenum face, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
1128{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001129 // 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 +00001130 redefineImage(faceIndex(face), level, format, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001131
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001132 Texture::setCompressedImage(imageSize, pixels, mImageArray[faceIndex(face)][level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001133}
1134
1135void TextureCubeMap::commitRect(int face, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1136{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001137 if (level < levelCount())
1138 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001139 rx::Image *image = mImageArray[face][level];
daniel@transgaming.com0f195ad2012-10-31 19:51:59 +00001140 if (image->updateSurface(mTexStorage, face, level, xoffset, yoffset, width, height))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001141 image->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001142 }
1143}
1144
1145void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1146{
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +00001147 if (Texture::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpackAlignment, pixels, mImageArray[faceIndex(target)][level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001148 {
1149 commitRect(faceIndex(target), level, xoffset, yoffset, width, height);
1150 }
1151}
1152
1153void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1154{
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +00001155 if (Texture::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[faceIndex(target)][level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001156 {
1157 commitRect(faceIndex(target), level, xoffset, yoffset, width, height);
1158 }
1159}
1160
1161// Tests for cube map sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 86.
1162bool TextureCubeMap::isSamplerComplete() const
1163{
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001164 int size = mImageArray[0][0]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001165
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +00001166 bool mipmapping = isMipmapFiltered();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001167
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001168 if (!IsTextureFilteringSupported(getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0), mRenderer))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001169 {
daniel@transgaming.comebf139f2012-10-31 18:07:32 +00001170 if (mSamplerState.magFilter != GL_NEAREST ||
1171 (mSamplerState.minFilter != GL_NEAREST && mSamplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001172 {
1173 return false;
1174 }
1175 }
1176
daniel@transgaming.comea32d482012-11-28 19:33:18 +00001177 if (!isPow2(size) && !mRenderer->getNonPower2TextureSupport())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001178 {
daniel@transgaming.comebf139f2012-10-31 18:07:32 +00001179 if (mSamplerState.wrapS != GL_CLAMP_TO_EDGE || mSamplerState.wrapT != GL_CLAMP_TO_EDGE || mipmapping)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001180 {
1181 return false;
1182 }
1183 }
1184
1185 if (!mipmapping)
1186 {
1187 if (!isCubeComplete())
1188 {
1189 return false;
1190 }
1191 }
1192 else
1193 {
1194 if (!isMipmapCubeComplete()) // Also tests for isCubeComplete()
1195 {
1196 return false;
1197 }
1198 }
1199
1200 return true;
1201}
1202
1203// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1204bool TextureCubeMap::isCubeComplete() const
1205{
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001206 if (mImageArray[0][0]->getWidth() <= 0 || mImageArray[0][0]->getHeight() != mImageArray[0][0]->getWidth())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001207 {
1208 return false;
1209 }
1210
1211 for (unsigned int face = 1; face < 6; face++)
1212 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001213 if (mImageArray[face][0]->getWidth() != mImageArray[0][0]->getWidth() ||
1214 mImageArray[face][0]->getWidth() != mImageArray[0][0]->getHeight() ||
1215 mImageArray[face][0]->getInternalFormat() != mImageArray[0][0]->getInternalFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001216 {
1217 return false;
1218 }
1219 }
1220
1221 return true;
1222}
1223
1224bool TextureCubeMap::isMipmapCubeComplete() const
1225{
1226 if (isImmutable())
1227 {
1228 return true;
1229 }
1230
1231 if (!isCubeComplete())
1232 {
1233 return false;
1234 }
1235
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001236 GLsizei size = mImageArray[0][0]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001237 int q = log2(size);
1238
1239 for (int face = 0; face < 6; face++)
1240 {
1241 for (int level = 1; level <= q; level++)
1242 {
Jamie Madill07edd442013-07-19 16:36:58 -04001243 if (!isFaceLevelComplete(face, level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001244 {
1245 return false;
1246 }
1247 }
1248 }
1249
1250 return true;
1251}
1252
Jamie Madill07edd442013-07-19 16:36:58 -04001253bool TextureCubeMap::isFaceLevelComplete(int face, int level) const
1254{
1255 ASSERT(level >= 0 && face < 6 && level < (int)ArraySize(mImageArray[face]) && mImageArray[face][level] != NULL);
1256
1257 if (isImmutable())
1258 {
1259 return true;
1260 }
1261
1262 const rx::Image *baseImage = mImageArray[face][0];
1263 GLsizei size = baseImage->getWidth();
1264
1265 if (size <= 0)
1266 {
1267 return false;
1268 }
1269
1270 // The base image level is complete if the width and height are positive
1271 if (level == 0)
1272 {
1273 return true;
1274 }
1275
1276 rx::Image *image = mImageArray[face][level];
1277
1278 if (image->getInternalFormat() != baseImage->getInternalFormat())
1279 {
1280 return false;
1281 }
1282
1283 if (mImageArray[face][level]->getWidth() != std::max(1, size >> level))
1284 {
1285 return false;
1286 }
1287
1288 return true;
1289}
1290
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001291bool TextureCubeMap::isCompressed(GLenum target, GLint level) const
1292{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001293 return IsFormatCompressed(getInternalFormat(target, level), mRenderer->getCurrentClientVersion());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001294}
1295
daniel@transgaming.comf032cb82012-10-31 19:51:52 +00001296// Constructs a native texture resource from the texture images, or returns an existing one
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001297void TextureCubeMap::createTexture()
1298{
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001299 GLsizei size = mImageArray[0][0]->getWidth();
daniel@transgaming.come6a09842012-09-17 21:28:55 +00001300
1301 if (!(size > 0))
daniel@transgaming.comf032cb82012-10-31 19:51:52 +00001302 return; // do not attempt to create native textures for nonexistant data
daniel@transgaming.come6a09842012-09-17 21:28:55 +00001303
sminns@adobe.comce1189b2012-09-18 20:06:35 +00001304 GLint levels = creationLevels(size);
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001305 GLenum internalformat = mImageArray[0][0]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001306
1307 delete mTexStorage;
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001308 mTexStorage = new rx::TextureStorageInterfaceCube(mRenderer, levels, internalformat, mUsage, false, size);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001309
1310 if (mTexStorage->isManaged())
1311 {
1312 int levels = levelCount();
1313
1314 for (int face = 0; face < 6; face++)
1315 {
1316 for (int level = 0; level < levels; level++)
1317 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001318 mImageArray[face][level]->setManagedSurface(mTexStorage, face, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001319 }
1320 }
1321 }
1322
1323 mDirtyImages = true;
1324}
1325
1326void TextureCubeMap::updateTexture()
1327{
Jamie Madilleb3665c2013-07-19 16:36:57 -04001328 int levels = (isMipmapCubeComplete() ? levelCount() : 1);
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +00001329
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001330 for (int face = 0; face < 6; face++)
1331 {
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001332 for (int level = 0; level < levels; level++)
1333 {
Jamie Madill07edd442013-07-19 16:36:58 -04001334 updateTextureFaceLevel(face, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001335 }
1336 }
1337}
1338
Jamie Madill07edd442013-07-19 16:36:58 -04001339void TextureCubeMap::updateTextureFaceLevel(int face, int level)
1340{
1341 ASSERT(level >= 0 && face < 6 && level < (int)ArraySize(mImageArray[face]) && mImageArray[face][level] != NULL);
1342 rx::Image *image = mImageArray[face][level];
1343
1344 if (image->isDirty())
1345 {
1346 commitRect(face, level, 0, 0, image->getWidth(), image->getHeight());
1347 }
1348}
1349
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001350void TextureCubeMap::convertToRenderTarget()
1351{
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001352 rx::TextureStorageInterfaceCube *newTexStorage = NULL;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001353
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001354 if (mImageArray[0][0]->getWidth() != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001355 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001356 GLsizei size = mImageArray[0][0]->getWidth();
shannon.woods@transgaming.com6bb48862013-02-28 23:09:34 +00001357 GLint levels = mTexStorage != NULL ? mTexStorage->levelCount() : creationLevels(size);
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001358 GLenum internalformat = mImageArray[0][0]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001359
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001360 newTexStorage = new rx::TextureStorageInterfaceCube(mRenderer, levels, internalformat, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, true, size);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001361
1362 if (mTexStorage != NULL)
1363 {
daniel@transgaming.com1d80eee2012-11-28 19:33:31 +00001364 if (!mRenderer->copyToRenderTarget(newTexStorage, mTexStorage))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001365 {
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +00001366 delete newTexStorage;
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +00001367 return gl::error(GL_OUT_OF_MEMORY);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001368 }
1369 }
1370 }
1371
1372 delete mTexStorage;
1373 mTexStorage = newTexStorage;
1374
1375 mDirtyImages = true;
1376}
1377
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001378void TextureCubeMap::setImage(int faceIndex, GLint level, GLsizei width, GLsizei height, GLint internalFormat, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001379{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001380 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1381 GLint sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
1382 : GetSizedInternalFormat(format, type, clientVersion);
1383
1384 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001385
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001386 Texture::setImage(unpackAlignment, type, pixels, mImageArray[faceIndex][level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001387}
1388
1389unsigned int TextureCubeMap::faceIndex(GLenum face)
1390{
1391 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
1392 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
1393 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
1394 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
1395 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
1396
1397 return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
1398}
1399
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001400void TextureCubeMap::redefineImage(int face, GLint level, GLint internalformat, GLsizei width, GLsizei height)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001401{
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001402 // If there currently is a corresponding storage texture image, it has these parameters
1403 const int storageWidth = std::max(1, mImageArray[0][0]->getWidth() >> level);
1404 const int storageHeight = std::max(1, mImageArray[0][0]->getHeight() >> level);
1405 const int storageFormat = mImageArray[0][0]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001406
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001407 mImageArray[face][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, width, height, 1, false);
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001408
1409 if (mTexStorage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001410 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001411 const int storageLevels = mTexStorage->levelCount();
1412
1413 if ((level >= storageLevels && storageLevels != 0) ||
1414 width != storageWidth ||
1415 height != storageHeight ||
1416 internalformat != storageFormat) // Discard mismatched storage
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001417 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001418 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001419 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001420 for (int f = 0; f < 6; f++)
1421 {
1422 mImageArray[f][i]->markDirty();
1423 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001424 }
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001425
1426 delete mTexStorage;
1427 mTexStorage = NULL;
1428
1429 mDirtyImages = true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001430 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001431 }
1432}
1433
1434void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1435{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001436 unsigned int faceindex = faceIndex(target);
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001437 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1438 GLint sizedInternalFormat = IsSizedInternalFormat(format, clientVersion) ? format
1439 : GetSizedInternalFormat(format, GL_UNSIGNED_BYTE, clientVersion);
1440 redefineImage(faceindex, level, sizedInternalFormat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001441
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001442 if (!mImageArray[faceindex][level]->isRenderableFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001443 {
shannon.woods%transgaming.com@gtempaccount.come5dcce72013-04-13 03:44:33 +00001444 mImageArray[faceindex][level]->copy(0, 0, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001445 mDirtyImages = true;
1446 }
1447 else
1448 {
1449 if (!mTexStorage || !mTexStorage->isRenderTarget())
1450 {
1451 convertToRenderTarget();
1452 }
1453
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001454 mImageArray[faceindex][level]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001455
1456 ASSERT(width == height);
1457
1458 if (width > 0 && level < levelCount())
1459 {
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +00001460 gl::Rectangle sourceRect;
1461 sourceRect.x = x;
1462 sourceRect.width = width;
1463 sourceRect.y = y;
1464 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001465
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +00001466 mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001467 }
1468 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001469}
1470
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001471void 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 +00001472{
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001473 GLsizei size = mImageArray[faceIndex(target)][level]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001474
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001475 if (xoffset + width > size || yoffset + height > size || zoffset != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001476 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +00001477 return gl::error(GL_INVALID_VALUE);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001478 }
1479
Jamie Madill07edd442013-07-19 16:36:58 -04001480 unsigned int face = faceIndex(target);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001481
Jamie Madill07edd442013-07-19 16:36:58 -04001482 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
1483 // the current level we're copying to is defined (with appropriate format, width & height)
1484 bool canCreateRenderTarget = isFaceLevelComplete(face, level) && isFaceLevelComplete(face, 0);
1485
1486 if (!mImageArray[face][level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001487 {
Jamie Madill07edd442013-07-19 16:36:58 -04001488 mImageArray[face][level]->copy(0, 0, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001489 mDirtyImages = true;
1490 }
1491 else
1492 {
1493 if (!mTexStorage || !mTexStorage->isRenderTarget())
1494 {
1495 convertToRenderTarget();
1496 }
1497
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001498 if (level < levelCount())
1499 {
Jamie Madill07edd442013-07-19 16:36:58 -04001500 updateTextureFaceLevel(face, level);
1501
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001502 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1503
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +00001504 gl::Rectangle sourceRect;
1505 sourceRect.x = x;
1506 sourceRect.width = width;
1507 sourceRect.y = y;
1508 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001509
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001510 mRenderer->copyImage(source, sourceRect, gl::GetFormat(mImageArray[0][0]->getInternalFormat(), clientVersion),
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +00001511 xoffset, yoffset, mTexStorage, target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001512 }
1513 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001514}
1515
1516void TextureCubeMap::storage(GLsizei levels, GLenum internalformat, GLsizei size)
1517{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001518 delete mTexStorage;
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001519 mTexStorage = new rx::TextureStorageInterfaceCube(mRenderer, levels, internalformat, mUsage, false, size);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001520 mImmutable = true;
1521
1522 for (int level = 0; level < levels; level++)
1523 {
1524 for (int face = 0; face < 6; face++)
1525 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001526 mImageArray[face][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, size, size, 1, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001527 size = std::max(1, size >> 1);
1528 }
1529 }
1530
1531 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1532 {
1533 for (int face = 0; face < 6; face++)
1534 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001535 mImageArray[face][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, GL_NONE, 0, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001536 }
1537 }
1538
1539 if (mTexStorage->isManaged())
1540 {
1541 int levels = levelCount();
1542
1543 for (int face = 0; face < 6; face++)
1544 {
1545 for (int level = 0; level < levels; level++)
1546 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001547 mImageArray[face][level]->setManagedSurface(mTexStorage, face, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001548 }
1549 }
1550 }
1551}
1552
1553void TextureCubeMap::generateMipmaps()
1554{
1555 if (!isCubeComplete())
1556 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +00001557 return gl::error(GL_INVALID_OPERATION);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001558 }
1559
daniel@transgaming.comea32d482012-11-28 19:33:18 +00001560 if (!mRenderer->getNonPower2TextureSupport())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001561 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001562 if (!isPow2(mImageArray[0][0]->getWidth()))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001563 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +00001564 return gl::error(GL_INVALID_OPERATION);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001565 }
1566 }
1567
1568 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001569 unsigned int q = log2(mImageArray[0][0]->getWidth());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001570 for (unsigned int f = 0; f < 6; f++)
1571 {
1572 for (unsigned int i = 1; i <= q; i++)
1573 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001574 redefineImage(f, i, mImageArray[f][0]->getInternalFormat(),
shannon.woods@transgaming.com8a406682013-02-28 23:15:26 +00001575 std::max(mImageArray[f][0]->getWidth() >> i, 1),
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001576 std::max(mImageArray[f][0]->getWidth() >> i, 1));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001577 }
1578 }
1579
1580 if (mTexStorage && mTexStorage->isRenderTarget())
1581 {
1582 for (unsigned int f = 0; f < 6; f++)
1583 {
1584 for (unsigned int i = 1; i <= q; i++)
1585 {
daniel@transgaming.com0ad830b2012-10-31 19:52:12 +00001586 mTexStorage->generateMipmap(f, i);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001587
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001588 mImageArray[f][i]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001589 }
1590 }
1591 }
1592 else
1593 {
1594 for (unsigned int f = 0; f < 6; f++)
1595 {
1596 for (unsigned int i = 1; i <= q; i++)
1597 {
daniel@transgaming.com4ba24062012-12-20 20:54:24 +00001598 mRenderer->generateMipmap(mImageArray[f][i], mImageArray[f][i - 1]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001599 }
1600 }
1601 }
1602}
1603
1604Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target)
1605{
1606 if (!IsCubemapTextureTarget(target))
1607 {
shannon.woods@transgaming.com779aa262013-02-28 23:04:58 +00001608 return gl::error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001609 }
1610
1611 unsigned int face = faceIndex(target);
1612
1613 if (mFaceProxies[face] == NULL)
1614 {
daniel@transgaming.com70062c92012-11-28 19:32:30 +00001615 mFaceProxies[face] = new Renderbuffer(mRenderer, id(), new RenderbufferTextureCubeMap(this, target));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001616 }
1617
1618 return mFaceProxies[face];
1619}
1620
daniel@transgaming.comd186dc72012-11-28 19:40:16 +00001621rx::RenderTarget *TextureCubeMap::getRenderTarget(GLenum target)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001622{
1623 ASSERT(IsCubemapTextureTarget(target));
1624
1625 // ensure the underlying texture is created
1626 if (getStorage(true) == NULL)
1627 {
1628 return NULL;
1629 }
1630
1631 updateTexture();
1632
daniel@transgaming.comd186dc72012-11-28 19:40:16 +00001633 return mTexStorage->getRenderTarget(target);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001634}
1635
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +00001636int TextureCubeMap::levelCount()
1637{
1638 return mTexStorage ? mTexStorage->levelCount() - getLodOffset() : 0;
1639}
1640
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001641rx::TextureStorageInterface *TextureCubeMap::getStorage(bool renderTarget)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001642{
1643 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
1644 {
1645 if (renderTarget)
1646 {
1647 convertToRenderTarget();
1648 }
1649 else
1650 {
1651 createTexture();
1652 }
1653 }
1654
1655 return mTexStorage;
1656}
1657
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001658Texture3D::Texture3D(rx::Renderer *renderer, GLuint id) : Texture(renderer, id)
1659{
1660 mTexStorage = NULL;
1661 mColorbufferProxy = NULL;
1662 mProxyRefs = 0;
1663
1664 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1665 {
1666 mImageArray[i] = renderer->createImage();
1667 }
1668}
1669
1670Texture3D::~Texture3D()
1671{
1672 mColorbufferProxy = NULL;
1673
1674 delete mTexStorage;
1675 mTexStorage = NULL;
1676
1677 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1678 {
1679 delete mImageArray[i];
1680 }
1681}
1682
1683void Texture3D::addProxyRef(const Renderbuffer *proxy)
1684{
1685 mProxyRefs++;
1686}
1687
1688void Texture3D::releaseProxy(const Renderbuffer *proxy)
1689{
1690 if (mProxyRefs > 0)
1691 mProxyRefs--;
1692
1693 if (mProxyRefs == 0)
1694 mColorbufferProxy = NULL;
1695}
1696
1697GLenum Texture3D::getTarget() const
1698{
1699 return GL_TEXTURE_3D;
1700}
1701
1702GLsizei Texture3D::getWidth(GLint level) const
1703{
1704 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getWidth() : 0;
1705}
1706
1707GLsizei Texture3D::getHeight(GLint level) const
1708{
1709 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getHeight() : 0;
1710}
1711
1712GLsizei Texture3D::getDepth(GLint level) const
1713{
1714 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getDepth() : 0;
1715}
1716
1717GLenum Texture3D::getInternalFormat(GLint level) const
1718{
1719 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getInternalFormat() : GL_NONE;
1720}
1721
1722GLenum Texture3D::getActualFormat(GLint level) const
1723{
1724 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getActualFormat() : D3DFMT_UNKNOWN;
1725}
1726
1727bool Texture3D::isCompressed(GLint level) const
1728{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001729 return IsFormatCompressed(getInternalFormat(level), mRenderer->getCurrentClientVersion());
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001730}
1731
1732bool Texture3D::isDepth(GLint level) const
1733{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001734 return GetDepthBits(getInternalFormat(level), mRenderer->getCurrentClientVersion()) > 0;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001735}
1736
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001737void Texture3D::setImage(GLint level, GLsizei width, GLsizei height, GLsizei depth, GLint internalFormat, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001738{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001739 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1740 GLint sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
1741 : GetSizedInternalFormat(format, type, clientVersion);
1742 redefineImage(level, sizedInternalFormat, width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001743
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001744 Texture::setImage(unpackAlignment, type, pixels, mImageArray[level]);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001745}
1746
1747void Texture3D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
1748{
1749 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1750 redefineImage(level, format, width, height, depth);
1751
1752 Texture::setCompressedImage(imageSize, pixels, mImageArray[level]);
1753}
1754
1755void Texture3D::subImage(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1756{
1757 if (Texture::subImage(xoffset, yoffset, zoffset, width, height, depth, format, type, unpackAlignment, pixels, mImageArray[level]))
1758 {
1759 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1760 }
1761}
1762
1763void Texture3D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
1764{
1765 if (Texture::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth, format, imageSize, pixels, mImageArray[level]))
1766 {
1767 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1768 }
1769}
1770
1771void Texture3D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
1772{
1773 delete mTexStorage;
1774 mTexStorage = new rx::TextureStorageInterface3D(mRenderer, levels, internalformat, mUsage, width, height, depth);
1775 mImmutable = true;
1776
1777 for (int level = 0; level < levels; level++)
1778 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001779 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, true);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001780 width = std::max(1, width >> 1);
1781 height = std::max(1, height >> 1);
1782 depth = std::max(1, depth >> 1);
1783 }
1784
1785 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1786 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001787 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, GL_NONE, 0, 0, 0, true);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001788 }
1789
1790 if (mTexStorage->isManaged())
1791 {
1792 int levels = levelCount();
1793
1794 for (int level = 0; level < levels; level++)
1795 {
1796 mImageArray[level]->setManagedSurface(mTexStorage, level);
1797 }
1798 }
1799}
1800
1801
1802void Texture3D::generateMipmaps()
1803{
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001804 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1805 unsigned int q = log2(std::max(mImageArray[0]->getWidth(), mImageArray[0]->getHeight()));
1806 for (unsigned int i = 1; i <= q; i++)
1807 {
1808 redefineImage(i, mImageArray[0]->getInternalFormat(),
1809 std::max(mImageArray[0]->getWidth() >> i, 1),
1810 std::max(mImageArray[0]->getHeight() >> i, 1),
1811 std::max(mImageArray[0]->getDepth() >> i, 1));
1812 }
1813
1814 if (mTexStorage && mTexStorage->isRenderTarget())
1815 {
1816 for (unsigned int i = 1; i <= q; i++)
1817 {
1818 mTexStorage->generateMipmap(i);
1819
1820 mImageArray[i]->markClean();
1821 }
1822 }
1823 else
1824 {
1825 for (unsigned int i = 1; i <= q; i++)
1826 {
1827 mRenderer->generateMipmap(mImageArray[i], mImageArray[i - 1]);
1828 }
1829 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001830}
1831
1832void Texture3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1833{
1834 if (xoffset + width > mImageArray[level]->getWidth() || yoffset + height > mImageArray[level]->getHeight() || zoffset >= mImageArray[level]->getDepth())
1835 {
1836 return gl::error(GL_INVALID_VALUE);
1837 }
1838
Jamie Madill07edd442013-07-19 16:36:58 -04001839 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
1840 // the current level we're copying to is defined (with appropriate format, width & height)
1841 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
1842
1843 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001844 {
1845 mImageArray[level]->copy(xoffset, yoffset, zoffset, x, y, width, height, source);
1846 mDirtyImages = true;
1847 }
1848 else
1849 {
1850 if (!mTexStorage || !mTexStorage->isRenderTarget())
1851 {
1852 convertToRenderTarget();
1853 }
1854
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001855 if (level < levelCount())
1856 {
Jamie Madill07edd442013-07-19 16:36:58 -04001857 updateTextureLevel(level);
1858
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001859 gl::Rectangle sourceRect;
1860 sourceRect.x = x;
1861 sourceRect.width = width;
1862 sourceRect.y = y;
1863 sourceRect.height = height;
1864
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001865 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1866
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001867 mRenderer->copyImage(source, sourceRect,
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00001868 gl::GetFormat(mImageArray[0]->getInternalFormat(), clientVersion),
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001869 xoffset, yoffset, zoffset, mTexStorage, level);
1870 }
1871 }
1872}
1873
1874bool Texture3D::isSamplerComplete() const
1875{
1876 GLsizei width = mImageArray[0]->getWidth();
1877 GLsizei height = mImageArray[0]->getHeight();
1878 GLsizei depth = mImageArray[0]->getDepth();
1879
1880 if (width <= 0 || height <= 0 || depth <= 0)
1881 {
1882 return false;
1883 }
1884
1885 bool mipmapping = isMipmapFiltered();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001886
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00001887 if (!IsTextureFilteringSupported(getInternalFormat(0), mRenderer))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001888 {
1889 if (mSamplerState.magFilter != GL_NEAREST ||
1890 (mSamplerState.minFilter != GL_NEAREST && mSamplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
1891 {
1892 return false;
1893 }
1894 }
1895
1896 if (mipmapping && !isMipmapComplete())
1897 {
1898 return false;
1899 }
1900
1901 return true;
1902}
1903
1904bool Texture3D::isMipmapComplete() const
1905{
Jamie Madill07edd442013-07-19 16:36:58 -04001906 GLsizei width = mImageArray[0]->getWidth();
1907 GLsizei height = mImageArray[0]->getHeight();
1908 GLsizei depth = mImageArray[0]->getDepth();
1909
1910 int q = log2(std::max(std::max(width, height), depth));
1911
1912 for (int level = 0; level <= q; level++)
1913 {
1914 if (!isLevelComplete(level))
1915 {
1916 return false;
1917 }
1918 }
1919
1920 return true;
1921}
1922
1923bool Texture3D::isLevelComplete(int level) const
1924{
1925 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1926
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001927 if (isImmutable())
1928 {
1929 return true;
1930 }
1931
Jamie Madill07edd442013-07-19 16:36:58 -04001932 rx::Image *baseImage = mImageArray[0];
1933
1934 GLsizei width = baseImage->getWidth();
1935 GLsizei height = baseImage->getHeight();
1936 GLsizei depth = baseImage->getDepth();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001937
1938 if (width <= 0 || height <= 0 || depth <= 0)
1939 {
1940 return false;
1941 }
1942
Jamie Madill07edd442013-07-19 16:36:58 -04001943 if (level == 0)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001944 {
Jamie Madill07edd442013-07-19 16:36:58 -04001945 return true;
1946 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001947
Jamie Madill07edd442013-07-19 16:36:58 -04001948 rx::Image *levelImage = mImageArray[level];
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001949
Jamie Madill07edd442013-07-19 16:36:58 -04001950 if (levelImage->getInternalFormat() != baseImage->getInternalFormat())
1951 {
1952 return false;
1953 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001954
Jamie Madill07edd442013-07-19 16:36:58 -04001955 if (levelImage->getWidth() != std::max(1, width >> level))
1956 {
1957 return false;
1958 }
1959
1960 if (levelImage->getHeight() != std::max(1, height >> level))
1961 {
1962 return false;
1963 }
1964
1965 if (levelImage->getDepth() != std::max(1, depth >> level))
1966 {
1967 return false;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001968 }
1969
1970 return true;
1971}
1972
1973Renderbuffer *Texture3D::getRenderbuffer(GLenum target)
1974{
1975 UNIMPLEMENTED();
1976 return NULL;
1977}
1978
1979int Texture3D::levelCount()
1980{
1981 return mTexStorage ? mTexStorage->levelCount() : 0;
1982}
1983
1984void Texture3D::createTexture()
1985{
1986 GLsizei width = mImageArray[0]->getWidth();
1987 GLsizei height = mImageArray[0]->getHeight();
1988 GLsizei depth = mImageArray[0]->getDepth();
1989
1990 if (!(width > 0 && height > 0 && depth > 0))
1991 return; // do not attempt to create native textures for nonexistant data
1992
1993 GLint levels = creationLevels(width, height, depth);
1994 GLenum internalformat = mImageArray[0]->getInternalFormat();
1995
1996 delete mTexStorage;
1997 mTexStorage = new rx::TextureStorageInterface3D(mRenderer, levels, internalformat, mUsage, width, height, depth);
1998
1999 if (mTexStorage->isManaged())
2000 {
2001 int levels = levelCount();
2002
2003 for (int level = 0; level < levels; level++)
2004 {
2005 mImageArray[level]->setManagedSurface(mTexStorage, level);
2006 }
2007 }
2008
2009 mDirtyImages = true;
2010}
2011
2012void Texture3D::updateTexture()
2013{
Jamie Madilleb3665c2013-07-19 16:36:57 -04002014 int levels = (isMipmapComplete() ? levelCount() : 1);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002015
2016 for (int level = 0; level < levels; level++)
2017 {
Jamie Madill07edd442013-07-19 16:36:58 -04002018 updateTextureLevel(level);
2019 }
2020}
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002021
Jamie Madill07edd442013-07-19 16:36:58 -04002022void Texture3D::updateTextureLevel(int level)
2023{
2024 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
2025
2026 rx::Image *image = mImageArray[level];
2027
2028 if (image->isDirty())
2029 {
2030 commitRect(level, 0, 0, 0, mImageArray[level]->getWidth(), mImageArray[level]->getHeight(), mImageArray[level]->getDepth());
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002031 }
2032}
2033
2034void Texture3D::convertToRenderTarget()
2035{
2036 rx::TextureStorageInterface3D *newTexStorage = NULL;
2037
2038 if (mImageArray[0]->getWidth() != 0 && mImageArray[0]->getHeight() != 0 && mImageArray[0]->getDepth() != 0)
2039 {
2040 GLsizei width = mImageArray[0]->getWidth();
2041 GLsizei height = mImageArray[0]->getHeight();
2042 GLsizei depth = mImageArray[0]->getDepth();
2043 GLint levels = mTexStorage != NULL ? mTexStorage->levelCount() : creationLevels(width, height, depth);
2044 GLenum internalformat = mImageArray[0]->getInternalFormat();
2045
2046 newTexStorage = new rx::TextureStorageInterface3D(mRenderer, levels, internalformat, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, width, height, depth);
2047
2048 if (mTexStorage != NULL)
2049 {
2050 if (!mRenderer->copyToRenderTarget(newTexStorage, mTexStorage))
2051 {
2052 delete newTexStorage;
2053 return gl::error(GL_OUT_OF_MEMORY);
2054 }
2055 }
2056 }
2057
2058 delete mTexStorage;
2059 mTexStorage = newTexStorage;
2060
2061 mDirtyImages = true;
2062}
2063
2064rx::RenderTarget *Texture3D::getRenderTarget(GLenum target)
2065{
2066 UNIMPLEMENTED();
2067 return NULL;
2068}
2069
2070rx::TextureStorageInterface *Texture3D::getStorage(bool renderTarget)
2071{
2072 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
2073 {
2074 if (renderTarget)
2075 {
2076 convertToRenderTarget();
2077 }
2078 else
2079 {
2080 createTexture();
2081 }
2082 }
2083
2084 return mTexStorage;
2085}
2086
2087void Texture3D::redefineImage(GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth)
2088{
2089 // If there currently is a corresponding storage texture image, it has these parameters
2090 const int storageWidth = std::max(1, mImageArray[0]->getWidth() >> level);
2091 const int storageHeight = std::max(1, mImageArray[0]->getHeight() >> level);
2092 const int storageDepth = std::max(1, mImageArray[0]->getDepth() >> level);
2093 const int storageFormat = mImageArray[0]->getInternalFormat();
2094
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00002095 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, false);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002096
2097 if (mTexStorage)
2098 {
2099 const int storageLevels = mTexStorage->levelCount();
2100
2101 if ((level >= storageLevels && storageLevels != 0) ||
2102 width != storageWidth ||
2103 height != storageHeight ||
2104 depth != storageDepth ||
2105 internalformat != storageFormat) // Discard mismatched storage
2106 {
2107 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
2108 {
2109 mImageArray[i]->markDirty();
2110 }
2111
2112 delete mTexStorage;
2113 mTexStorage = NULL;
2114 mDirtyImages = true;
2115 }
2116 }
2117}
2118
2119void Texture3D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth)
2120{
2121 if (level < levelCount())
2122 {
2123 rx::Image *image = mImageArray[level];
2124 if (image->updateSurface(mTexStorage, level, xoffset, yoffset, zoffset, width, height, depth))
2125 {
2126 image->markClean();
2127 }
2128 }
2129}
2130
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002131Texture2DArray::Texture2DArray(rx::Renderer *renderer, GLuint id) : Texture(renderer, id)
2132{
2133 mTexStorage = NULL;
2134 mColorbufferProxy = NULL;
2135 mProxyRefs = 0;
2136
2137 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2138 {
2139 mLayerCounts[level] = 0;
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002140 mImageArray[level] = NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002141 }
2142}
2143
2144Texture2DArray::~Texture2DArray()
2145{
2146 mColorbufferProxy = NULL;
2147
2148 delete mTexStorage;
2149 mTexStorage = NULL;
2150 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2151 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002152 for (int layer = 0; layer < mLayerCounts[level]; ++layer)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002153 {
2154 delete mImageArray[level][layer];
2155 }
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002156 delete[] mImageArray[level];
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002157 }
2158}
2159
2160void Texture2DArray::addProxyRef(const Renderbuffer *proxy)
2161{
2162 mProxyRefs++;
2163}
2164
2165void Texture2DArray::releaseProxy(const Renderbuffer *proxy)
2166{
2167 if (mProxyRefs > 0)
2168 mProxyRefs--;
2169
2170 if (mProxyRefs == 0)
2171 mColorbufferProxy = NULL;
2172}
2173
2174GLenum Texture2DArray::getTarget() const
2175{
2176 return GL_TEXTURE_2D_ARRAY;
2177}
2178
2179GLsizei Texture2DArray::getWidth(GLint level) const
2180{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002181 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 +00002182}
2183
2184GLsizei Texture2DArray::getHeight(GLint level) const
2185{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002186 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 +00002187}
2188
2189GLsizei Texture2DArray::getDepth(GLint level) const
2190{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002191 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mLayerCounts[level] : 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002192}
2193
2194GLenum Texture2DArray::getInternalFormat(GLint level) const
2195{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002196 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 +00002197}
2198
2199GLenum Texture2DArray::getActualFormat(GLint level) const
2200{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002201 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getActualFormat() : D3DFMT_UNKNOWN;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002202}
2203
2204bool Texture2DArray::isCompressed(GLint level) const
2205{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00002206 return IsFormatCompressed(getInternalFormat(level), mRenderer->getCurrentClientVersion());
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002207}
2208
2209bool Texture2DArray::isDepth(GLint level) const
2210{
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00002211 return GetDepthBits(getInternalFormat(level), mRenderer->getCurrentClientVersion()) > 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002212}
2213
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00002214void Texture2DArray::setImage(GLint level, GLsizei width, GLsizei height, GLsizei depth, GLint internalFormat, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002215{
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00002216 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2217 GLint sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
2218 : GetSizedInternalFormat(format, type, clientVersion);
2219 redefineImage(level, sizedInternalFormat, width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002220
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002221 GLsizei inputDepthPitch = gl::GetDepthPitch(sizedInternalFormat, type, clientVersion, width, height, unpackAlignment);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002222
2223 for (int i = 0; i < depth; i++)
2224 {
2225 const void *layerPixels = reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i);
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002226 Texture::setImage(unpackAlignment, type, layerPixels, mImageArray[level][i]);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002227 }
2228}
2229
2230void Texture2DArray::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
2231{
2232 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
2233 redefineImage(level, format, width, height, depth);
2234
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002235 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2236 GLsizei inputDepthPitch = gl::GetDepthPitch(format, GL_UNSIGNED_BYTE, clientVersion, width, height, 1);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002237
2238 for (int i = 0; i < depth; i++)
2239 {
2240 const void *layerPixels = reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i);
2241 Texture::setCompressedImage(imageSize, layerPixels, mImageArray[level][i]);
2242 }
2243}
2244
2245void Texture2DArray::subImage(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
2246{
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002247 GLint internalformat = getInternalFormat(level);
2248 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2249 GLsizei inputDepthPitch = gl::GetDepthPitch(internalformat, type, width, height, clientVersion, unpackAlignment);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002250
2251 for (int i = 0; i < depth; i++)
2252 {
2253 int layer = zoffset + i;
2254 const void *layerPixels = reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i);
2255
2256 if (Texture::subImage(xoffset, yoffset, zoffset, width, height, 1, format, type, unpackAlignment, layerPixels, mImageArray[level][layer]))
2257 {
2258 commitRect(level, xoffset, yoffset, layer, width, height);
2259 }
2260 }
2261}
2262
2263void Texture2DArray::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
2264{
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002265 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2266 GLsizei inputDepthPitch = gl::GetDepthPitch(format, GL_UNSIGNED_BYTE, clientVersion, width, height, 1);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002267
2268 for (int i = 0; i < depth; i++)
2269 {
2270 int layer = zoffset + i;
2271 const void *layerPixels = reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i);
2272
2273 if (Texture::subImageCompressed(xoffset, yoffset, zoffset, width, height, 1, format, imageSize, layerPixels, mImageArray[level][layer]))
2274 {
2275 commitRect(level, xoffset, yoffset, layer, width, height);
2276 }
2277 }
2278}
2279
2280void Texture2DArray::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2281{
2282 delete mTexStorage;
2283 mTexStorage = new rx::TextureStorageInterface2DArray(mRenderer, levels, internalformat, mUsage, width, height, depth);
2284 mImmutable = true;
2285
2286 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2287 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002288 GLsizei levelWidth = std::max(width >> level, 1);
2289 GLsizei levelHeight = std::max(width >> level, 1);
2290
2291 // Clear this level
2292 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002293 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002294 delete mImageArray[level][layer];
2295 }
2296 delete[] mImageArray[level];
2297 mImageArray[level] = NULL;
2298 mLayerCounts[level] = 0;
2299
2300 if (level < levels)
2301 {
2302 // Create new images for this level
2303 mImageArray[level] = new rx::Image*[depth]();
2304 mLayerCounts[level] = depth;
2305
2306 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002307 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002308 mImageArray[level][layer] = mRenderer->createImage();
2309 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, levelWidth,
2310 levelHeight, 1, true);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002311 }
2312 }
2313 }
2314
2315 if (mTexStorage->isManaged())
2316 {
2317 int levels = levelCount();
2318
2319 for (int level = 0; level < levels; level++)
2320 {
2321 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2322 {
2323 mImageArray[level][layer]->setManagedSurface(mTexStorage, layer, level);
2324 }
2325 }
2326 }
2327}
2328
2329void Texture2DArray::generateMipmaps()
2330{
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00002331 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
2332 int q = log2(std::max(getWidth(0), getHeight(0)));
2333 for (int i = 1; i <= q; i++)
2334 {
2335 redefineImage(i, getInternalFormat(0), std::max(getWidth(0) >> i, 1), std::max(getHeight(0) >> i, 1), getDepth(0));
2336 }
2337
2338 if (mTexStorage && mTexStorage->isRenderTarget())
2339 {
2340 for (int level = 1; level <= q; level++)
2341 {
2342 mTexStorage->generateMipmap(level);
2343
2344 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2345 {
2346 mImageArray[level][layer]->markClean();
2347 }
2348 }
2349 }
2350 else
2351 {
2352 for (int level = 1; level <= q; level++)
2353 {
2354 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2355 {
2356 mRenderer->generateMipmap(mImageArray[level][layer], mImageArray[level - 1][layer]);
2357 }
2358 }
2359 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002360}
2361
2362void Texture2DArray::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
2363{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002364 if (xoffset + width > getWidth(level) || yoffset + height > getHeight(level) || zoffset >= getDepth(level) || getDepth(level) == 0)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002365 {
2366 return gl::error(GL_INVALID_VALUE);
2367 }
2368
Jamie Madill07edd442013-07-19 16:36:58 -04002369 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
2370 // the current level we're copying to is defined (with appropriate format, width & height)
2371 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
2372
2373 if (!mImageArray[level][0]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002374 {
2375 mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, x, y, width, height, source);
2376 mDirtyImages = true;
2377 }
2378 else
2379 {
2380 if (!mTexStorage || !mTexStorage->isRenderTarget())
2381 {
2382 convertToRenderTarget();
2383 }
2384
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002385 if (level < levelCount())
2386 {
Jamie Madill07edd442013-07-19 16:36:58 -04002387 updateTextureLevel(level);
2388
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002389 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2390
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002391 gl::Rectangle sourceRect;
2392 sourceRect.x = x;
2393 sourceRect.width = width;
2394 sourceRect.y = y;
2395 sourceRect.height = height;
2396
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +00002397 mRenderer->copyImage(source, sourceRect, gl::GetFormat(getInternalFormat(0), clientVersion),
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002398 xoffset, yoffset, zoffset, mTexStorage, level);
2399 }
2400 }
2401}
2402
2403bool Texture2DArray::isSamplerComplete() const
2404{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002405 GLsizei width = getWidth(0);
2406 GLsizei height = getHeight(0);
2407 GLsizei depth = getDepth(0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002408
2409 if (width <= 0 || height <= 0 || depth <= 0)
2410 {
2411 return false;
2412 }
2413
2414 bool mipmapping = isMipmapFiltered();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002415
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +00002416 if (!IsTextureFilteringSupported(getInternalFormat(0), mRenderer))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002417 {
2418 if (mSamplerState.magFilter != GL_NEAREST ||
2419 (mSamplerState.minFilter != GL_NEAREST && mSamplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
2420 {
2421 return false;
2422 }
2423 }
2424
2425 if (mipmapping && !isMipmapComplete())
2426 {
2427 return false;
2428 }
2429
2430 return true;
2431}
2432
2433bool Texture2DArray::isMipmapComplete() const
2434{
Jamie Madill07edd442013-07-19 16:36:58 -04002435 GLsizei width = getWidth(0);
2436 GLsizei height = getHeight(0);
2437
2438 int q = log2(std::max(width, height));
2439
2440 for (int level = 1; level <= q; level++)
2441 {
2442 if (!isLevelComplete(level))
2443 {
2444 return false;
2445 }
2446 }
2447
2448 return true;
2449}
2450
2451bool Texture2DArray::isLevelComplete(int level) const
2452{
2453 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
2454
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002455 if (isImmutable())
2456 {
2457 return true;
2458 }
2459
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002460 GLsizei width = getWidth(0);
2461 GLsizei height = getHeight(0);
2462 GLsizei depth = getDepth(0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002463
2464 if (width <= 0 || height <= 0 || depth <= 0)
2465 {
2466 return false;
2467 }
2468
Jamie Madill07edd442013-07-19 16:36:58 -04002469 if (level == 0)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002470 {
Jamie Madill07edd442013-07-19 16:36:58 -04002471 return true;
2472 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002473
Jamie Madill07edd442013-07-19 16:36:58 -04002474 if (getInternalFormat(level) != getInternalFormat(0))
2475 {
2476 return false;
2477 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002478
Jamie Madill07edd442013-07-19 16:36:58 -04002479 if (getWidth(level) != std::max(1, width >> level))
2480 {
2481 return false;
2482 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002483
Jamie Madill07edd442013-07-19 16:36:58 -04002484 if (getHeight(level) != std::max(1, height >> level))
2485 {
2486 return false;
2487 }
2488
2489 if (getDepth(level) != depth)
2490 {
2491 return false;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002492 }
2493
2494 return true;
2495}
2496
2497Renderbuffer *Texture2DArray::getRenderbuffer(GLenum target)
2498{
2499 UNIMPLEMENTED();
2500 return NULL;
2501}
2502
2503int Texture2DArray::levelCount()
2504{
2505 return mTexStorage ? mTexStorage->levelCount() : 0;
2506}
2507
2508void Texture2DArray::createTexture()
2509{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002510 GLsizei width = getWidth(0);
2511 GLsizei height = getHeight(0);
2512 GLsizei depth = getDepth(0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002513
2514 if (width <= 0 || height <= 0 || depth <= 0)
2515 {
2516 return; // do not attempt to create native textures for nonexistant data
2517 }
2518
2519 GLint levels = creationLevels(width, height);
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002520 GLenum internalformat = getInternalFormat(0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002521
2522 delete mTexStorage;
2523 mTexStorage = new rx::TextureStorageInterface2DArray(mRenderer, levels, internalformat, mUsage, width, height, depth);
2524
2525 if (mTexStorage->isManaged())
2526 {
2527 int levels = levelCount();
2528 for (int level = 0; level < levels; level++)
2529 {
2530 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2531 {
2532 mImageArray[level][layer]->setManagedSurface(mTexStorage, layer, level);
2533 }
2534 }
2535 }
2536
2537 mDirtyImages = true;
2538}
2539
2540void Texture2DArray::updateTexture()
2541{
Jamie Madilleb3665c2013-07-19 16:36:57 -04002542 int levels = (isMipmapComplete() ? levelCount() : 1);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002543 for (int level = 0; level < levels; level++)
2544 {
Jamie Madill07edd442013-07-19 16:36:58 -04002545 updateTextureLevel(level);
2546 }
2547}
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002548
Jamie Madill07edd442013-07-19 16:36:58 -04002549void Texture2DArray::updateTextureLevel(int level)
2550{
2551 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2552 {
2553 rx::Image *image = mImageArray[level][layer];
2554
2555 if (image->isDirty())
2556 {
2557 commitRect(level, 0, 0, layer, image->getWidth(), image->getHeight());
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002558 }
2559 }
2560}
2561
2562void Texture2DArray::convertToRenderTarget()
2563{
2564 rx::TextureStorageInterface2DArray *newTexStorage = NULL;
2565
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002566 GLsizei width = getWidth(0);
2567 GLsizei height = getHeight(0);
2568 GLsizei depth = getDepth(0);
2569
2570 if (width != 0 && height != 0 && depth != 0)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002571 {
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002572 GLint levels = mTexStorage != NULL ? mTexStorage->levelCount() : creationLevels(width, height);
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002573 GLenum internalformat = getInternalFormat(0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002574
2575 newTexStorage = new rx::TextureStorageInterface2DArray(mRenderer, levels, internalformat, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, width, height, depth);
2576
2577 if (mTexStorage != NULL)
2578 {
2579 if (!mRenderer->copyToRenderTarget(newTexStorage, mTexStorage))
2580 {
2581 delete newTexStorage;
2582 return gl::error(GL_OUT_OF_MEMORY);
2583 }
2584 }
2585 }
2586
2587 delete mTexStorage;
2588 mTexStorage = newTexStorage;
2589
2590 mDirtyImages = true;
2591}
2592
2593rx::RenderTarget *Texture2DArray::getRenderTarget(GLenum target)
2594{
2595 UNIMPLEMENTED();
2596 return NULL;
2597}
2598
2599rx::TextureStorageInterface *Texture2DArray::getStorage(bool renderTarget)
2600{
2601 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
2602 {
2603 if (renderTarget)
2604 {
2605 convertToRenderTarget();
2606 }
2607 else
2608 {
2609 createTexture();
2610 }
2611 }
2612
2613 return mTexStorage;
2614}
2615
2616void Texture2DArray::redefineImage(GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth)
2617{
2618 // If there currently is a corresponding storage texture image, it has these parameters
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002619 const int storageWidth = std::max(1, getWidth(0) >> level);
2620 const int storageHeight = std::max(1, getHeight(0) >> level);
2621 const int storageDepth = getDepth(0);
2622 const int storageFormat = getInternalFormat(0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002623
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002624 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002625 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002626 delete mImageArray[level][layer];
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002627 }
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002628 delete[] mImageArray[level];
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002629
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002630 mImageArray[level] = new rx::Image*[depth]();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002631 mLayerCounts[level] = depth;
2632
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002633 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2634 {
2635 mImageArray[level][layer] = mRenderer->createImage();
2636 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, width, height, 1, false);
2637 }
2638
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002639 if (mTexStorage)
2640 {
2641 const int storageLevels = mTexStorage->levelCount();
2642
2643 if ((level >= storageLevels && storageLevels != 0) ||
2644 width != storageWidth ||
2645 height != storageHeight ||
2646 depth != storageDepth ||
2647 internalformat != storageFormat) // Discard mismatched storage
2648 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002649 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002650 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002651 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002652 {
2653 mImageArray[level][layer]->markDirty();
2654 }
2655 }
2656
2657 delete mTexStorage;
2658 mTexStorage = NULL;
2659 mDirtyImages = true;
2660 }
2661 }
2662}
2663
2664void Texture2DArray::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint layerTarget, GLsizei width, GLsizei height)
2665{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002666 if (level < levelCount() && layerTarget < getDepth(level))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002667 {
2668 rx::Image *image = mImageArray[level][layerTarget];
2669 if (image->updateSurface(mTexStorage, level, xoffset, yoffset, layerTarget, width, height))
2670 {
2671 image->markClean();
2672 }
2673 }
2674}
2675
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00002676}