blob: e97949c34501ce26c7a5fd1b43888f9f31b15242 [file] [log] [blame]
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001//
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00002// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved.
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00003// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7// Texture.cpp: Implements the gl::Texture class and its derived classes
8// Texture2D and TextureCubeMap. Implements GL texture objects and related
9// functionality. [OpenGL ES 2.0.24] section 3.7 page 63.
10
11#include "libGLESv2/Texture.h"
12
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000013#include <algorithm>
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000014
15#include "common/debug.h"
16
17#include "libEGL/Display.h"
18
19#include "libGLESv2/main.h"
20#include "libGLESv2/mathutil.h"
21#include "libGLESv2/utilities.h"
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +000022#include "libGLESv2/renderer/Blit.h"
daniel@transgaming.coma27e05b2012-11-28 19:39:42 +000023#include "libGLESv2/renderer/SwapChain9.h"
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000024#include "libGLESv2/Framebuffer.h"
25
26namespace gl
27{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000028
daniel@transgaming.com370482e2012-11-28 19:32:13 +000029Texture::Texture(rx::Renderer *renderer, GLuint id) : RefCountObject(id)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000030{
daniel@transgaming.com370482e2012-11-28 19:32:13 +000031 mRenderer = renderer;
32
daniel@transgaming.comebf139f2012-10-31 18:07:32 +000033 mSamplerState.minFilter = GL_NEAREST_MIPMAP_LINEAR;
34 mSamplerState.magFilter = GL_LINEAR;
35 mSamplerState.wrapS = GL_REPEAT;
36 mSamplerState.wrapT = GL_REPEAT;
37 mSamplerState.maxAnisotropy = 1.0f;
38 mSamplerState.lodOffset = 0;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000039 mDirtyParameters = true;
40 mUsage = GL_NONE;
41
42 mDirtyImages = true;
43
44 mImmutable = false;
45}
46
47Texture::~Texture()
48{
49}
50
51// Returns true on successful filter state update (valid enum parameter)
52bool Texture::setMinFilter(GLenum filter)
53{
54 switch (filter)
55 {
56 case GL_NEAREST:
57 case GL_LINEAR:
58 case GL_NEAREST_MIPMAP_NEAREST:
59 case GL_LINEAR_MIPMAP_NEAREST:
60 case GL_NEAREST_MIPMAP_LINEAR:
61 case GL_LINEAR_MIPMAP_LINEAR:
62 {
daniel@transgaming.comebf139f2012-10-31 18:07:32 +000063 if (mSamplerState.minFilter != filter)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000064 {
daniel@transgaming.comebf139f2012-10-31 18:07:32 +000065 mSamplerState.minFilter = filter;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000066 mDirtyParameters = true;
67 }
68 return true;
69 }
70 default:
71 return false;
72 }
73}
74
75// Returns true on successful filter state update (valid enum parameter)
76bool Texture::setMagFilter(GLenum filter)
77{
78 switch (filter)
79 {
80 case GL_NEAREST:
81 case GL_LINEAR:
82 {
daniel@transgaming.comebf139f2012-10-31 18:07:32 +000083 if (mSamplerState.magFilter != filter)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000084 {
daniel@transgaming.comebf139f2012-10-31 18:07:32 +000085 mSamplerState.magFilter = filter;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000086 mDirtyParameters = true;
87 }
88 return true;
89 }
90 default:
91 return false;
92 }
93}
94
95// Returns true on successful wrap state update (valid enum parameter)
96bool Texture::setWrapS(GLenum wrap)
97{
98 switch (wrap)
99 {
100 case GL_REPEAT:
101 case GL_CLAMP_TO_EDGE:
102 case GL_MIRRORED_REPEAT:
103 {
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000104 if (mSamplerState.wrapS != wrap)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000105 {
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000106 mSamplerState.wrapS = wrap;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000107 mDirtyParameters = true;
108 }
109 return true;
110 }
111 default:
112 return false;
113 }
114}
115
116// Returns true on successful wrap state update (valid enum parameter)
117bool Texture::setWrapT(GLenum wrap)
118{
119 switch (wrap)
120 {
121 case GL_REPEAT:
122 case GL_CLAMP_TO_EDGE:
123 case GL_MIRRORED_REPEAT:
124 {
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000125 if (mSamplerState.wrapT != wrap)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000126 {
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000127 mSamplerState.wrapT = wrap;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000128 mDirtyParameters = true;
129 }
130 return true;
131 }
132 default:
133 return false;
134 }
135}
136
daniel@transgaming.com07ab8412012-07-12 15:17:09 +0000137// Returns true on successful max anisotropy update (valid anisotropy value)
138bool Texture::setMaxAnisotropy(float textureMaxAnisotropy, float contextMaxAnisotropy)
139{
140 textureMaxAnisotropy = std::min(textureMaxAnisotropy, contextMaxAnisotropy);
141 if (textureMaxAnisotropy < 1.0f)
142 {
143 return false;
144 }
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000145 if (mSamplerState.maxAnisotropy != textureMaxAnisotropy)
daniel@transgaming.com07ab8412012-07-12 15:17:09 +0000146 {
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000147 mSamplerState.maxAnisotropy = textureMaxAnisotropy;
daniel@transgaming.com07ab8412012-07-12 15:17:09 +0000148 mDirtyParameters = true;
149 }
150 return true;
151}
152
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000153// Returns true on successful usage state update (valid enum parameter)
154bool Texture::setUsage(GLenum usage)
155{
156 switch (usage)
157 {
158 case GL_NONE:
159 case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
160 mUsage = usage;
161 return true;
162 default:
163 return false;
164 }
165}
166
167GLenum Texture::getMinFilter() const
168{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000169 return mSamplerState.minFilter;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000170}
171
172GLenum Texture::getMagFilter() const
173{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000174 return mSamplerState.magFilter;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000175}
176
177GLenum Texture::getWrapS() const
178{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000179 return mSamplerState.wrapS;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000180}
181
182GLenum Texture::getWrapT() const
183{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000184 return mSamplerState.wrapT;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000185}
186
daniel@transgaming.com07ab8412012-07-12 15:17:09 +0000187float Texture::getMaxAnisotropy() const
188{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000189 return mSamplerState.maxAnisotropy;
190}
191
192int Texture::getLodOffset()
193{
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000194 rx::TextureStorageInterface *texture = getStorage(false);
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000195 return texture ? texture->getLodOffset() : 0;
196}
197
198void Texture::getSamplerState(SamplerState *sampler)
199{
200 *sampler = mSamplerState;
201 sampler->lodOffset = getLodOffset();
daniel@transgaming.com07ab8412012-07-12 15:17:09 +0000202}
203
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000204GLenum Texture::getUsage() const
205{
206 return mUsage;
207}
208
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +0000209bool Texture::isMipmapFiltered() const
210{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000211 switch (mSamplerState.minFilter)
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +0000212 {
213 case GL_NEAREST:
214 case GL_LINEAR:
215 return false;
216 case GL_NEAREST_MIPMAP_NEAREST:
217 case GL_LINEAR_MIPMAP_NEAREST:
218 case GL_NEAREST_MIPMAP_LINEAR:
219 case GL_LINEAR_MIPMAP_LINEAR:
220 return true;
221 default: UNREACHABLE();
222 return false;
223 }
224}
225
daniel@transgaming.com31b13e12012-11-28 19:34:30 +0000226void Texture::setImage(GLint unpackAlignment, const void *pixels, rx::Image *image)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000227{
228 if (pixels != NULL)
229 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000230 image->loadData(0, 0, image->getWidth(), image->getHeight(), unpackAlignment, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000231 mDirtyImages = true;
232 }
233}
234
daniel@transgaming.com31b13e12012-11-28 19:34:30 +0000235void Texture::setCompressedImage(GLsizei imageSize, const void *pixels, rx::Image *image)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000236{
237 if (pixels != NULL)
238 {
239 image->loadCompressedData(0, 0, image->getWidth(), image->getHeight(), pixels);
240 mDirtyImages = true;
241 }
242}
243
daniel@transgaming.com31b13e12012-11-28 19:34:30 +0000244bool Texture::subImage(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, rx::Image *image)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000245{
246 if (pixels != NULL)
247 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000248 image->loadData(xoffset, yoffset, width, height, unpackAlignment, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000249 mDirtyImages = true;
250 }
251
252 return true;
253}
254
daniel@transgaming.com31b13e12012-11-28 19:34:30 +0000255bool Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, rx::Image *image)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000256{
257 if (pixels != NULL)
258 {
259 image->loadCompressedData(xoffset, yoffset, width, height, pixels);
260 mDirtyImages = true;
261 }
262
263 return true;
264}
265
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000266rx::TextureStorageInterface *Texture::getNativeTexture()
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000267{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000268 // ensure the underlying texture is created
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000269
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000270 rx::TextureStorageInterface *storage = getStorage(false);
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000271 if (storage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000272 {
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000273 updateTexture();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000274 }
275
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000276 return storage;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000277}
278
279bool Texture::hasDirtyParameters() const
280{
281 return mDirtyParameters;
282}
283
284bool Texture::hasDirtyImages() const
285{
286 return mDirtyImages;
287}
288
289void Texture::resetDirty()
290{
291 mDirtyParameters = false;
292 mDirtyImages = false;
293}
294
295unsigned int Texture::getTextureSerial()
296{
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000297 rx::TextureStorageInterface *texture = getStorage(false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000298 return texture ? texture->getTextureSerial() : 0;
299}
300
301unsigned int Texture::getRenderTargetSerial(GLenum target)
302{
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000303 rx::TextureStorageInterface *texture = getStorage(true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000304 return texture ? texture->getRenderTargetSerial(target) : 0;
305}
306
307bool Texture::isImmutable() const
308{
309 return mImmutable;
310}
311
312GLint Texture::creationLevels(GLsizei width, GLsizei height) const
313{
daniel@transgaming.comea32d482012-11-28 19:33:18 +0000314 if ((isPow2(width) && isPow2(height)) || mRenderer->getNonPower2TextureSupport())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000315 {
316 return 0; // Maximum number of levels
317 }
318 else
319 {
320 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
321 return 1;
322 }
323}
324
325GLint Texture::creationLevels(GLsizei size) const
326{
327 return creationLevels(size, size);
328}
329
daniel@transgaming.com370482e2012-11-28 19:32:13 +0000330Texture2D::Texture2D(rx::Renderer *renderer, GLuint id) : Texture(renderer, id)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000331{
332 mTexStorage = NULL;
333 mSurface = NULL;
334 mColorbufferProxy = NULL;
335 mProxyRefs = 0;
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000336
337 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
338 {
daniel@transgaming.com244e1832012-12-20 20:52:35 +0000339 mImageArray[i] = renderer->createImage();
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000340 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000341}
342
343Texture2D::~Texture2D()
344{
345 mColorbufferProxy = NULL;
346
347 delete mTexStorage;
348 mTexStorage = NULL;
349
350 if (mSurface)
351 {
352 mSurface->setBoundTexture(NULL);
353 mSurface = NULL;
354 }
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000355
356 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
357 {
358 delete mImageArray[i];
359 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000360}
361
362// We need to maintain a count of references to renderbuffers acting as
363// proxies for this texture, so that we do not attempt to use a pointer
364// to a renderbuffer proxy which has been deleted.
365void Texture2D::addProxyRef(const Renderbuffer *proxy)
366{
367 mProxyRefs++;
368}
369
370void Texture2D::releaseProxy(const Renderbuffer *proxy)
371{
372 if (mProxyRefs > 0)
373 mProxyRefs--;
374
375 if (mProxyRefs == 0)
376 mColorbufferProxy = NULL;
377}
378
379GLenum Texture2D::getTarget() const
380{
381 return GL_TEXTURE_2D;
382}
383
384GLsizei Texture2D::getWidth(GLint level) const
385{
386 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000387 return mImageArray[level]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000388 else
389 return 0;
390}
391
392GLsizei Texture2D::getHeight(GLint level) const
393{
394 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000395 return mImageArray[level]->getHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000396 else
397 return 0;
398}
399
400GLenum Texture2D::getInternalFormat(GLint level) const
401{
402 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000403 return mImageArray[level]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000404 else
405 return GL_NONE;
406}
407
daniel@transgaming.com20d36662012-10-31 19:51:43 +0000408GLenum Texture2D::getActualFormat(GLint level) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000409{
410 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000411 return mImageArray[level]->getActualFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000412 else
413 return D3DFMT_UNKNOWN;
414}
415
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000416void Texture2D::redefineImage(GLint level, GLint internalformat, GLsizei width, GLsizei height)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000417{
418 releaseTexImage();
daniel@transgaming.comc5c806d2012-12-20 20:52:53 +0000419
420 bool redefined = mImageArray[level]->redefine(mRenderer, internalformat, width, height, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000421
422 if (mTexStorage && redefined)
423 {
424 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
425 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000426 mImageArray[i]->markDirty();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000427 }
428
429 delete mTexStorage;
430 mTexStorage = NULL;
431 mDirtyImages = true;
432 }
433}
434
435void Texture2D::setImage(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
436{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000437 GLint internalformat = ConvertSizedInternalFormat(format, type);
438 redefineImage(level, internalformat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000439
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000440 Texture::setImage(unpackAlignment, pixels, mImageArray[level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000441}
442
443void Texture2D::bindTexImage(egl::Surface *surface)
444{
445 releaseTexImage();
446
daniel@transgaming.com106e1f72012-10-31 18:38:36 +0000447 GLint internalformat = surface->getFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000448
daniel@transgaming.comc5c806d2012-12-20 20:52:53 +0000449 mImageArray[0]->redefine(mRenderer, internalformat, surface->getWidth(), surface->getHeight(), true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000450
451 delete mTexStorage;
daniel@transgaming.coma27e05b2012-11-28 19:39:42 +0000452 rx::SwapChain9 *swapchain = static_cast<rx::SwapChain9*>(surface->getSwapChain()); // D3D9_REPLACE
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000453 mTexStorage = new rx::TextureStorageInterface2D(mRenderer, swapchain);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000454
455 mDirtyImages = true;
456 mSurface = surface;
457 mSurface->setBoundTexture(this);
458}
459
460void Texture2D::releaseTexImage()
461{
462 if (mSurface)
463 {
464 mSurface->setBoundTexture(NULL);
465 mSurface = NULL;
466
467 if (mTexStorage)
468 {
469 delete mTexStorage;
470 mTexStorage = NULL;
471 }
472
473 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
474 {
daniel@transgaming.comc5c806d2012-12-20 20:52:53 +0000475 mImageArray[i]->redefine(mRenderer, GL_RGBA8_OES, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000476 }
477 }
478}
479
480void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
481{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000482 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
483 redefineImage(level, format, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000484
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000485 Texture::setCompressedImage(imageSize, pixels, mImageArray[level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000486}
487
488void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
489{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000490 if (level < levelCount())
491 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000492 rx::Image *image = mImageArray[level];
daniel@transgaming.com0f195ad2012-10-31 19:51:59 +0000493 if (image->updateSurface(mTexStorage, level, xoffset, yoffset, width, height))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000494 {
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000495 image->markClean();
496 }
497 }
498}
499
500void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
501{
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000502 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, mImageArray[level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000503 {
504 commitRect(level, xoffset, yoffset, width, height);
505 }
506}
507
508void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
509{
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000510 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, mImageArray[level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000511 {
512 commitRect(level, xoffset, yoffset, width, height);
513 }
514}
515
516void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
517{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000518 GLint internalformat = ConvertSizedInternalFormat(format, GL_UNSIGNED_BYTE);
519 redefineImage(level, internalformat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000520
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000521 if (!mImageArray[level]->isRenderableFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000522 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000523 mImageArray[level]->copy(0, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000524 mDirtyImages = true;
525 }
526 else
527 {
528 if (!mTexStorage || !mTexStorage->isRenderTarget())
529 {
530 convertToRenderTarget();
531 }
532
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000533 mImageArray[level]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000534
535 if (width != 0 && height != 0 && level < levelCount())
536 {
537 RECT sourceRect;
538 sourceRect.left = x;
539 sourceRect.right = x + width;
540 sourceRect.top = y;
541 sourceRect.bottom = y + height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000542
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +0000543 mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, level);
daniel@transgaming.com3cef5392012-10-31 19:52:15 +0000544
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000545 }
546 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000547}
548
549void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
550{
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000551 if (xoffset + width > mImageArray[level]->getWidth() || yoffset + height > mImageArray[level]->getHeight())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000552 {
553 return error(GL_INVALID_VALUE);
554 }
555
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000556 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !isSamplerComplete()))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000557 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000558 mImageArray[level]->copy(xoffset, yoffset, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000559 mDirtyImages = true;
560 }
561 else
562 {
563 if (!mTexStorage || !mTexStorage->isRenderTarget())
564 {
565 convertToRenderTarget();
566 }
567
568 updateTexture();
569
570 if (level < levelCount())
571 {
572 RECT sourceRect;
573 sourceRect.left = x;
574 sourceRect.right = x + width;
575 sourceRect.top = y;
576 sourceRect.bottom = y + height;
577
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +0000578 mRenderer->copyImage(source, sourceRect,
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000579 gl::ExtractFormat(mImageArray[0]->getInternalFormat()),
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +0000580 xoffset, yoffset, mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000581 }
582 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000583}
584
585void Texture2D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height)
586{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000587 delete mTexStorage;
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000588 mTexStorage = new rx::TextureStorageInterface2D(mRenderer, levels, internalformat, mUsage, false, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000589 mImmutable = true;
590
591 for (int level = 0; level < levels; level++)
592 {
daniel@transgaming.comc5c806d2012-12-20 20:52:53 +0000593 mImageArray[level]->redefine(mRenderer, internalformat, width, height, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000594 width = std::max(1, width >> 1);
595 height = std::max(1, height >> 1);
596 }
597
598 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
599 {
daniel@transgaming.comc5c806d2012-12-20 20:52:53 +0000600 mImageArray[level]->redefine(mRenderer, GL_NONE, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000601 }
602
603 if (mTexStorage->isManaged())
604 {
605 int levels = levelCount();
606
607 for (int level = 0; level < levels; level++)
608 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000609 mImageArray[level]->setManagedSurface(mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000610 }
611 }
612}
613
614// Tests for 2D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85.
615bool Texture2D::isSamplerComplete() const
616{
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000617 GLsizei width = mImageArray[0]->getWidth();
618 GLsizei height = mImageArray[0]->getHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000619
620 if (width <= 0 || height <= 0)
621 {
622 return false;
623 }
624
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +0000625 bool mipmapping = isMipmapFiltered();
daniel@transgaming.comea32d482012-11-28 19:33:18 +0000626 bool filtering, renderable;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000627
daniel@transgaming.comea32d482012-11-28 19:33:18 +0000628 if ((IsFloat32Format(getInternalFormat(0)) && !mRenderer->getFloat32TextureSupport(&filtering, &renderable)) ||
629 (IsFloat16Format(getInternalFormat(0)) && !mRenderer->getFloat16TextureSupport(&filtering, &renderable)))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000630 {
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000631 if (mSamplerState.magFilter != GL_NEAREST ||
632 (mSamplerState.minFilter != GL_NEAREST && mSamplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000633 {
634 return false;
635 }
636 }
637
daniel@transgaming.comea32d482012-11-28 19:33:18 +0000638 bool npotSupport = mRenderer->getNonPower2TextureSupport();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000639
640 if (!npotSupport)
641 {
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000642 if ((mSamplerState.wrapS != GL_CLAMP_TO_EDGE && !isPow2(width)) ||
643 (mSamplerState.wrapT != GL_CLAMP_TO_EDGE && !isPow2(height)))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000644 {
645 return false;
646 }
647 }
648
649 if (mipmapping)
650 {
651 if (!npotSupport)
652 {
653 if (!isPow2(width) || !isPow2(height))
654 {
655 return false;
656 }
657 }
658
659 if (!isMipmapComplete())
660 {
661 return false;
662 }
663 }
664
665 return true;
666}
667
668// Tests for 2D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
669bool Texture2D::isMipmapComplete() const
670{
671 if (isImmutable())
672 {
673 return true;
674 }
675
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000676 GLsizei width = mImageArray[0]->getWidth();
677 GLsizei height = mImageArray[0]->getHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000678
679 if (width <= 0 || height <= 0)
680 {
681 return false;
682 }
683
684 int q = log2(std::max(width, height));
685
686 for (int level = 1; level <= q; level++)
687 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000688 if (mImageArray[level]->getInternalFormat() != mImageArray[0]->getInternalFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000689 {
690 return false;
691 }
692
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000693 if (mImageArray[level]->getWidth() != std::max(1, width >> level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000694 {
695 return false;
696 }
697
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000698 if (mImageArray[level]->getHeight() != std::max(1, height >> level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000699 {
700 return false;
701 }
702 }
703
704 return true;
705}
706
707bool Texture2D::isCompressed(GLint level) const
708{
709 return IsCompressed(getInternalFormat(level));
710}
711
712bool Texture2D::isDepth(GLint level) const
713{
714 return IsDepthTexture(getInternalFormat(level));
715}
716
daniel@transgaming.comf032cb82012-10-31 19:51:52 +0000717// Constructs a native texture resource from the texture images
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000718void Texture2D::createTexture()
719{
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000720 GLsizei width = mImageArray[0]->getWidth();
721 GLsizei height = mImageArray[0]->getHeight();
daniel@transgaming.come6a09842012-09-17 21:28:55 +0000722
723 if (!(width > 0 && height > 0))
daniel@transgaming.comf032cb82012-10-31 19:51:52 +0000724 return; // do not attempt to create native textures for nonexistant data
daniel@transgaming.come6a09842012-09-17 21:28:55 +0000725
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000726 GLint levels = creationLevels(width, height);
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000727 GLenum internalformat = mImageArray[0]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000728
729 delete mTexStorage;
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000730 mTexStorage = new rx::TextureStorageInterface2D(mRenderer, levels, internalformat, mUsage, false, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000731
732 if (mTexStorage->isManaged())
733 {
734 int levels = levelCount();
735
736 for (int level = 0; level < levels; level++)
737 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000738 mImageArray[level]->setManagedSurface(mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000739 }
740 }
741
742 mDirtyImages = true;
743}
744
745void Texture2D::updateTexture()
746{
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +0000747 bool mipmapping = (isMipmapFiltered() && isMipmapComplete());
748
749 int levels = (mipmapping ? levelCount() : 1);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000750
751 for (int level = 0; level < levels; level++)
752 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000753 rx::Image *image = mImageArray[level];
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000754
755 if (image->isDirty())
756 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000757 commitRect(level, 0, 0, mImageArray[level]->getWidth(), mImageArray[level]->getHeight());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000758 }
759 }
760}
761
762void Texture2D::convertToRenderTarget()
763{
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000764 rx::TextureStorageInterface2D *newTexStorage = NULL;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000765
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000766 if (mImageArray[0]->getWidth() != 0 && mImageArray[0]->getHeight() != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000767 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000768 GLsizei width = mImageArray[0]->getWidth();
769 GLsizei height = mImageArray[0]->getHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000770 GLint levels = creationLevels(width, height);
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000771 GLenum internalformat = mImageArray[0]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000772
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000773 newTexStorage = new rx::TextureStorageInterface2D(mRenderer, levels, internalformat, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, true, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000774
775 if (mTexStorage != NULL)
776 {
daniel@transgaming.com1d80eee2012-11-28 19:33:31 +0000777 if (!mRenderer->copyToRenderTarget(newTexStorage, mTexStorage))
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +0000778 {
779 delete newTexStorage;
780 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000781 }
782 }
783 }
784
785 delete mTexStorage;
786 mTexStorage = newTexStorage;
787
788 mDirtyImages = true;
789}
790
791void Texture2D::generateMipmaps()
792{
daniel@transgaming.comea32d482012-11-28 19:33:18 +0000793 if (!mRenderer->getNonPower2TextureSupport())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000794 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000795 if (!isPow2(mImageArray[0]->getWidth()) || !isPow2(mImageArray[0]->getHeight()))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000796 {
797 return error(GL_INVALID_OPERATION);
798 }
799 }
800
801 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000802 unsigned int q = log2(std::max(mImageArray[0]->getWidth(), mImageArray[0]->getHeight()));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000803 for (unsigned int i = 1; i <= q; i++)
804 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000805 redefineImage(i, mImageArray[0]->getInternalFormat(),
806 std::max(mImageArray[0]->getWidth() >> i, 1),
807 std::max(mImageArray[0]->getHeight() >> i, 1));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000808 }
809
810 if (mTexStorage && mTexStorage->isRenderTarget())
811 {
812 for (unsigned int i = 1; i <= q; i++)
813 {
daniel@transgaming.com0ad830b2012-10-31 19:52:12 +0000814 mTexStorage->generateMipmap(i);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000815
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000816 mImageArray[i]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000817 }
818 }
819 else
820 {
821 for (unsigned int i = 1; i <= q; i++)
822 {
daniel@transgaming.com4ba24062012-12-20 20:54:24 +0000823 mRenderer->generateMipmap(mImageArray[i], mImageArray[i - 1]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000824 }
825 }
826}
827
828Renderbuffer *Texture2D::getRenderbuffer(GLenum target)
829{
830 if (target != GL_TEXTURE_2D)
831 {
832 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
833 }
834
835 if (mColorbufferProxy == NULL)
836 {
daniel@transgaming.com70062c92012-11-28 19:32:30 +0000837 mColorbufferProxy = new Renderbuffer(mRenderer, id(), new RenderbufferTexture2D(this, target));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000838 }
839
840 return mColorbufferProxy;
841}
842
daniel@transgaming.comd186dc72012-11-28 19:40:16 +0000843rx::RenderTarget *Texture2D::getRenderTarget(GLenum target)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000844{
845 ASSERT(target == GL_TEXTURE_2D);
846
847 // ensure the underlying texture is created
848 if (getStorage(true) == NULL)
849 {
850 return NULL;
851 }
852
853 updateTexture();
854
855 // ensure this is NOT a depth texture
856 if (isDepth(0))
857 {
858 return NULL;
859 }
daniel@transgaming.com34da3972012-12-20 21:10:29 +0000860
daniel@transgaming.comd186dc72012-11-28 19:40:16 +0000861 return mTexStorage->getRenderTarget();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000862}
863
daniel@transgaming.comd186dc72012-11-28 19:40:16 +0000864rx::RenderTarget *Texture2D::getDepthStencil(GLenum target)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000865{
866 ASSERT(target == GL_TEXTURE_2D);
867
868 // ensure the underlying texture is created
869 if (getStorage(true) == NULL)
870 {
871 return NULL;
872 }
873
874 updateTexture();
875
876 // ensure this is actually a depth texture
877 if (!isDepth(0))
878 {
879 return NULL;
880 }
daniel@transgaming.comd186dc72012-11-28 19:40:16 +0000881 return mTexStorage->getRenderTarget();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000882}
883
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +0000884int Texture2D::levelCount()
885{
886 return mTexStorage ? mTexStorage->levelCount() - getLodOffset() : 0;
887}
888
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000889rx::TextureStorageInterface *Texture2D::getStorage(bool renderTarget)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000890{
891 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
892 {
893 if (renderTarget)
894 {
895 convertToRenderTarget();
896 }
897 else
898 {
899 createTexture();
900 }
901 }
902
903 return mTexStorage;
904}
905
daniel@transgaming.com370482e2012-11-28 19:32:13 +0000906TextureCubeMap::TextureCubeMap(rx::Renderer *renderer, GLuint id) : Texture(renderer, id)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000907{
908 mTexStorage = NULL;
909 for (int i = 0; i < 6; i++)
910 {
911 mFaceProxies[i] = NULL;
912 mFaceProxyRefs[i] = 0;
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000913
914 for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
915 {
daniel@transgaming.com244e1832012-12-20 20:52:35 +0000916 mImageArray[i][j] = renderer->createImage();
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000917 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000918 }
919}
920
921TextureCubeMap::~TextureCubeMap()
922{
923 for (int i = 0; i < 6; i++)
924 {
925 mFaceProxies[i] = NULL;
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000926
927 for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
928 {
929 delete mImageArray[i][j];
930 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000931 }
932
933 delete mTexStorage;
934 mTexStorage = NULL;
935}
936
937// We need to maintain a count of references to renderbuffers acting as
938// proxies for this texture, so that the texture is not deleted while
939// proxy references still exist. If the reference count drops to zero,
940// we set our proxy pointer NULL, so that a new attempt at referencing
941// will cause recreation.
942void TextureCubeMap::addProxyRef(const Renderbuffer *proxy)
943{
944 for (int i = 0; i < 6; i++)
945 {
946 if (mFaceProxies[i] == proxy)
947 mFaceProxyRefs[i]++;
948 }
949}
950
951void TextureCubeMap::releaseProxy(const Renderbuffer *proxy)
952{
953 for (int i = 0; i < 6; i++)
954 {
955 if (mFaceProxies[i] == proxy)
956 {
957 if (mFaceProxyRefs[i] > 0)
958 mFaceProxyRefs[i]--;
959
960 if (mFaceProxyRefs[i] == 0)
961 mFaceProxies[i] = NULL;
962 }
963 }
964}
965
966GLenum TextureCubeMap::getTarget() const
967{
968 return GL_TEXTURE_CUBE_MAP;
969}
970
971GLsizei TextureCubeMap::getWidth(GLenum target, GLint level) const
972{
973 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000974 return mImageArray[faceIndex(target)][level]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000975 else
976 return 0;
977}
978
979GLsizei TextureCubeMap::getHeight(GLenum target, GLint level) const
980{
981 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000982 return mImageArray[faceIndex(target)][level]->getHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000983 else
984 return 0;
985}
986
987GLenum TextureCubeMap::getInternalFormat(GLenum target, GLint level) const
988{
989 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000990 return mImageArray[faceIndex(target)][level]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000991 else
992 return GL_NONE;
993}
994
daniel@transgaming.com20d36662012-10-31 19:51:43 +0000995GLenum TextureCubeMap::getActualFormat(GLenum target, GLint level) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000996{
997 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000998 return mImageArray[faceIndex(target)][level]->getActualFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000999 else
1000 return D3DFMT_UNKNOWN;
1001}
1002
1003void TextureCubeMap::setImagePosX(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1004{
1005 setImage(0, level, width, height, format, type, unpackAlignment, pixels);
1006}
1007
1008void TextureCubeMap::setImageNegX(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1009{
1010 setImage(1, level, width, height, format, type, unpackAlignment, pixels);
1011}
1012
1013void TextureCubeMap::setImagePosY(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1014{
1015 setImage(2, level, width, height, format, type, unpackAlignment, pixels);
1016}
1017
1018void TextureCubeMap::setImageNegY(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1019{
1020 setImage(3, level, width, height, format, type, unpackAlignment, pixels);
1021}
1022
1023void TextureCubeMap::setImagePosZ(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1024{
1025 setImage(4, level, width, height, format, type, unpackAlignment, pixels);
1026}
1027
1028void TextureCubeMap::setImageNegZ(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1029{
1030 setImage(5, level, width, height, format, type, unpackAlignment, pixels);
1031}
1032
1033void TextureCubeMap::setCompressedImage(GLenum face, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
1034{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001035 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1036 redefineImage(faceIndex(face), level, format, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001037
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001038 Texture::setCompressedImage(imageSize, pixels, mImageArray[faceIndex(face)][level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001039}
1040
1041void TextureCubeMap::commitRect(int face, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1042{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001043 if (level < levelCount())
1044 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001045 rx::Image *image = mImageArray[face][level];
daniel@transgaming.com0f195ad2012-10-31 19:51:59 +00001046 if (image->updateSurface(mTexStorage, face, level, xoffset, yoffset, width, height))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001047 image->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001048 }
1049}
1050
1051void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1052{
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001053 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, mImageArray[faceIndex(target)][level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001054 {
1055 commitRect(faceIndex(target), level, xoffset, yoffset, width, height);
1056 }
1057}
1058
1059void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1060{
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001061 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, mImageArray[faceIndex(target)][level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001062 {
1063 commitRect(faceIndex(target), level, xoffset, yoffset, width, height);
1064 }
1065}
1066
1067// Tests for cube map sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 86.
1068bool TextureCubeMap::isSamplerComplete() const
1069{
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001070 int size = mImageArray[0][0]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001071
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +00001072 bool mipmapping = isMipmapFiltered();
daniel@transgaming.comea32d482012-11-28 19:33:18 +00001073 bool filtering, renderable;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001074
daniel@transgaming.comea32d482012-11-28 19:33:18 +00001075 if ((gl::ExtractType(getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0)) == GL_FLOAT && !mRenderer->getFloat32TextureSupport(&filtering, &renderable)) ||
1076 (gl::ExtractType(getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0) == GL_HALF_FLOAT_OES) && !mRenderer->getFloat16TextureSupport(&filtering, &renderable)))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001077 {
daniel@transgaming.comebf139f2012-10-31 18:07:32 +00001078 if (mSamplerState.magFilter != GL_NEAREST ||
1079 (mSamplerState.minFilter != GL_NEAREST && mSamplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001080 {
1081 return false;
1082 }
1083 }
1084
daniel@transgaming.comea32d482012-11-28 19:33:18 +00001085 if (!isPow2(size) && !mRenderer->getNonPower2TextureSupport())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001086 {
daniel@transgaming.comebf139f2012-10-31 18:07:32 +00001087 if (mSamplerState.wrapS != GL_CLAMP_TO_EDGE || mSamplerState.wrapT != GL_CLAMP_TO_EDGE || mipmapping)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001088 {
1089 return false;
1090 }
1091 }
1092
1093 if (!mipmapping)
1094 {
1095 if (!isCubeComplete())
1096 {
1097 return false;
1098 }
1099 }
1100 else
1101 {
1102 if (!isMipmapCubeComplete()) // Also tests for isCubeComplete()
1103 {
1104 return false;
1105 }
1106 }
1107
1108 return true;
1109}
1110
1111// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1112bool TextureCubeMap::isCubeComplete() const
1113{
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001114 if (mImageArray[0][0]->getWidth() <= 0 || mImageArray[0][0]->getHeight() != mImageArray[0][0]->getWidth())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001115 {
1116 return false;
1117 }
1118
1119 for (unsigned int face = 1; face < 6; face++)
1120 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001121 if (mImageArray[face][0]->getWidth() != mImageArray[0][0]->getWidth() ||
1122 mImageArray[face][0]->getWidth() != mImageArray[0][0]->getHeight() ||
1123 mImageArray[face][0]->getInternalFormat() != mImageArray[0][0]->getInternalFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001124 {
1125 return false;
1126 }
1127 }
1128
1129 return true;
1130}
1131
1132bool TextureCubeMap::isMipmapCubeComplete() const
1133{
1134 if (isImmutable())
1135 {
1136 return true;
1137 }
1138
1139 if (!isCubeComplete())
1140 {
1141 return false;
1142 }
1143
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001144 GLsizei size = mImageArray[0][0]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001145
1146 int q = log2(size);
1147
1148 for (int face = 0; face < 6; face++)
1149 {
1150 for (int level = 1; level <= q; level++)
1151 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001152 if (mImageArray[face][level]->getInternalFormat() != mImageArray[0][0]->getInternalFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001153 {
1154 return false;
1155 }
1156
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001157 if (mImageArray[face][level]->getWidth() != std::max(1, size >> level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001158 {
1159 return false;
1160 }
1161 }
1162 }
1163
1164 return true;
1165}
1166
1167bool TextureCubeMap::isCompressed(GLenum target, GLint level) const
1168{
1169 return IsCompressed(getInternalFormat(target, level));
1170}
1171
daniel@transgaming.comf032cb82012-10-31 19:51:52 +00001172// Constructs a native texture resource from the texture images, or returns an existing one
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001173void TextureCubeMap::createTexture()
1174{
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001175 GLsizei size = mImageArray[0][0]->getWidth();
daniel@transgaming.come6a09842012-09-17 21:28:55 +00001176
1177 if (!(size > 0))
daniel@transgaming.comf032cb82012-10-31 19:51:52 +00001178 return; // do not attempt to create native textures for nonexistant data
daniel@transgaming.come6a09842012-09-17 21:28:55 +00001179
sminns@adobe.comce1189b2012-09-18 20:06:35 +00001180 GLint levels = creationLevels(size);
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001181 GLenum internalformat = mImageArray[0][0]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001182
1183 delete mTexStorage;
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001184 mTexStorage = new rx::TextureStorageInterfaceCube(mRenderer, levels, internalformat, mUsage, false, size);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001185
1186 if (mTexStorage->isManaged())
1187 {
1188 int levels = levelCount();
1189
1190 for (int face = 0; face < 6; face++)
1191 {
1192 for (int level = 0; level < levels; level++)
1193 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001194 mImageArray[face][level]->setManagedSurface(mTexStorage, face, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001195 }
1196 }
1197 }
1198
1199 mDirtyImages = true;
1200}
1201
1202void TextureCubeMap::updateTexture()
1203{
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +00001204 bool mipmapping = isMipmapFiltered() && isMipmapCubeComplete();
1205
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001206 for (int face = 0; face < 6; face++)
1207 {
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +00001208 int levels = (mipmapping ? levelCount() : 1);
1209
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001210 for (int level = 0; level < levels; level++)
1211 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001212 rx::Image *image = mImageArray[face][level];
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001213
1214 if (image->isDirty())
1215 {
1216 commitRect(face, level, 0, 0, image->getWidth(), image->getHeight());
1217 }
1218 }
1219 }
1220}
1221
1222void TextureCubeMap::convertToRenderTarget()
1223{
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001224 rx::TextureStorageInterfaceCube *newTexStorage = NULL;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001225
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001226 if (mImageArray[0][0]->getWidth() != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001227 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001228 GLsizei size = mImageArray[0][0]->getWidth();
sminns@adobe.comce1189b2012-09-18 20:06:35 +00001229 GLint levels = creationLevels(size);
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001230 GLenum internalformat = mImageArray[0][0]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001231
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001232 newTexStorage = new rx::TextureStorageInterfaceCube(mRenderer, levels, internalformat, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, true, size);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001233
1234 if (mTexStorage != NULL)
1235 {
daniel@transgaming.com1d80eee2012-11-28 19:33:31 +00001236 if (!mRenderer->copyToRenderTarget(newTexStorage, mTexStorage))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001237 {
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +00001238 delete newTexStorage;
1239 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001240 }
1241 }
1242 }
1243
1244 delete mTexStorage;
1245 mTexStorage = newTexStorage;
1246
1247 mDirtyImages = true;
1248}
1249
1250void TextureCubeMap::setImage(int faceIndex, GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1251{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001252 GLint internalformat = ConvertSizedInternalFormat(format, type);
1253 redefineImage(faceIndex, level, internalformat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001254
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001255 Texture::setImage(unpackAlignment, pixels, mImageArray[faceIndex][level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001256}
1257
1258unsigned int TextureCubeMap::faceIndex(GLenum face)
1259{
1260 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
1261 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
1262 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
1263 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
1264 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
1265
1266 return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
1267}
1268
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001269void TextureCubeMap::redefineImage(int face, GLint level, GLint internalformat, GLsizei width, GLsizei height)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001270{
daniel@transgaming.comc5c806d2012-12-20 20:52:53 +00001271 bool redefined = mImageArray[face][level]->redefine(mRenderer, internalformat, width, height, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001272
1273 if (mTexStorage && redefined)
1274 {
1275 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1276 {
1277 for (int f = 0; f < 6; f++)
1278 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001279 mImageArray[f][i]->markDirty();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001280 }
1281 }
1282
1283 delete mTexStorage;
1284 mTexStorage = NULL;
1285
1286 mDirtyImages = true;
1287 }
1288}
1289
1290void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1291{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001292 unsigned int faceindex = faceIndex(target);
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001293 GLint internalformat = gl::ConvertSizedInternalFormat(format, GL_UNSIGNED_BYTE);
1294 redefineImage(faceindex, level, internalformat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001295
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001296 if (!mImageArray[faceindex][level]->isRenderableFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001297 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001298 mImageArray[faceindex][level]->copy(0, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001299 mDirtyImages = true;
1300 }
1301 else
1302 {
1303 if (!mTexStorage || !mTexStorage->isRenderTarget())
1304 {
1305 convertToRenderTarget();
1306 }
1307
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001308 mImageArray[faceindex][level]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001309
1310 ASSERT(width == height);
1311
1312 if (width > 0 && level < levelCount())
1313 {
1314 RECT sourceRect;
1315 sourceRect.left = x;
1316 sourceRect.right = x + width;
1317 sourceRect.top = y;
1318 sourceRect.bottom = y + height;
1319
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +00001320 mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001321
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001322 }
1323 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001324}
1325
1326void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1327{
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001328 GLsizei size = mImageArray[faceIndex(target)][level]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001329
1330 if (xoffset + width > size || yoffset + height > size)
1331 {
1332 return error(GL_INVALID_VALUE);
1333 }
1334
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001335 unsigned int faceindex = faceIndex(target);
1336
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001337 if (!mImageArray[faceindex][level]->isRenderableFormat() || (!mTexStorage && !isSamplerComplete()))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001338 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001339 mImageArray[faceindex][level]->copy(0, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001340 mDirtyImages = true;
1341 }
1342 else
1343 {
1344 if (!mTexStorage || !mTexStorage->isRenderTarget())
1345 {
1346 convertToRenderTarget();
1347 }
1348
1349 updateTexture();
1350
1351 if (level < levelCount())
1352 {
1353 RECT sourceRect;
1354 sourceRect.left = x;
1355 sourceRect.right = x + width;
1356 sourceRect.top = y;
1357 sourceRect.bottom = y + height;
1358
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001359 mRenderer->copyImage(source, sourceRect, gl::ExtractFormat(mImageArray[0][0]->getInternalFormat()),
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +00001360 xoffset, yoffset, mTexStorage, target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001361
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001362 }
1363 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001364}
1365
1366void TextureCubeMap::storage(GLsizei levels, GLenum internalformat, GLsizei size)
1367{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001368 delete mTexStorage;
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001369 mTexStorage = new rx::TextureStorageInterfaceCube(mRenderer, levels, internalformat, mUsage, false, size);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001370 mImmutable = true;
1371
1372 for (int level = 0; level < levels; level++)
1373 {
1374 for (int face = 0; face < 6; face++)
1375 {
daniel@transgaming.comc5c806d2012-12-20 20:52:53 +00001376 mImageArray[face][level]->redefine(mRenderer, internalformat, size, size, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001377 size = std::max(1, size >> 1);
1378 }
1379 }
1380
1381 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1382 {
1383 for (int face = 0; face < 6; face++)
1384 {
daniel@transgaming.comc5c806d2012-12-20 20:52:53 +00001385 mImageArray[face][level]->redefine(mRenderer, GL_NONE, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001386 }
1387 }
1388
1389 if (mTexStorage->isManaged())
1390 {
1391 int levels = levelCount();
1392
1393 for (int face = 0; face < 6; face++)
1394 {
1395 for (int level = 0; level < levels; level++)
1396 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001397 mImageArray[face][level]->setManagedSurface(mTexStorage, face, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001398 }
1399 }
1400 }
1401}
1402
1403void TextureCubeMap::generateMipmaps()
1404{
1405 if (!isCubeComplete())
1406 {
1407 return error(GL_INVALID_OPERATION);
1408 }
1409
daniel@transgaming.comea32d482012-11-28 19:33:18 +00001410 if (!mRenderer->getNonPower2TextureSupport())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001411 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001412 if (!isPow2(mImageArray[0][0]->getWidth()))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001413 {
1414 return error(GL_INVALID_OPERATION);
1415 }
1416 }
1417
1418 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001419 unsigned int q = log2(mImageArray[0][0]->getWidth());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001420 for (unsigned int f = 0; f < 6; f++)
1421 {
1422 for (unsigned int i = 1; i <= q; i++)
1423 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001424 redefineImage(f, i, mImageArray[f][0]->getInternalFormat(),
1425 std::max(mImageArray[f][0]->getWidth() >> i, 1),
1426 std::max(mImageArray[f][0]->getWidth() >> i, 1));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001427 }
1428 }
1429
1430 if (mTexStorage && mTexStorage->isRenderTarget())
1431 {
1432 for (unsigned int f = 0; f < 6; f++)
1433 {
1434 for (unsigned int i = 1; i <= q; i++)
1435 {
daniel@transgaming.com0ad830b2012-10-31 19:52:12 +00001436 mTexStorage->generateMipmap(f, i);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001437
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +00001438 mImageArray[f][i]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001439 }
1440 }
1441 }
1442 else
1443 {
1444 for (unsigned int f = 0; f < 6; f++)
1445 {
1446 for (unsigned int i = 1; i <= q; i++)
1447 {
daniel@transgaming.com4ba24062012-12-20 20:54:24 +00001448 mRenderer->generateMipmap(mImageArray[f][i], mImageArray[f][i - 1]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001449 }
1450 }
1451 }
1452}
1453
1454Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target)
1455{
1456 if (!IsCubemapTextureTarget(target))
1457 {
1458 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
1459 }
1460
1461 unsigned int face = faceIndex(target);
1462
1463 if (mFaceProxies[face] == NULL)
1464 {
daniel@transgaming.com70062c92012-11-28 19:32:30 +00001465 mFaceProxies[face] = new Renderbuffer(mRenderer, id(), new RenderbufferTextureCubeMap(this, target));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001466 }
1467
1468 return mFaceProxies[face];
1469}
1470
daniel@transgaming.comd186dc72012-11-28 19:40:16 +00001471rx::RenderTarget *TextureCubeMap::getRenderTarget(GLenum target)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001472{
1473 ASSERT(IsCubemapTextureTarget(target));
1474
1475 // ensure the underlying texture is created
1476 if (getStorage(true) == NULL)
1477 {
1478 return NULL;
1479 }
1480
1481 updateTexture();
1482
daniel@transgaming.comd186dc72012-11-28 19:40:16 +00001483 return mTexStorage->getRenderTarget(target);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001484}
1485
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +00001486int TextureCubeMap::levelCount()
1487{
1488 return mTexStorage ? mTexStorage->levelCount() - getLodOffset() : 0;
1489}
1490
daniel@transgaming.com87705f82012-12-20 21:10:45 +00001491rx::TextureStorageInterface *TextureCubeMap::getStorage(bool renderTarget)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001492{
1493 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
1494 {
1495 if (renderTarget)
1496 {
1497 convertToRenderTarget();
1498 }
1499 else
1500 {
1501 createTexture();
1502 }
1503 }
1504
1505 return mTexStorage;
1506}
1507
1508}