blob: a23fcdc6e2cde38384057ee0648d7c11a86bda86 [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"
22#include "libGLESv2/Blit.h"
23#include "libGLESv2/Framebuffer.h"
24
25namespace gl
26{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000027
daniel@transgaming.com2e38b802012-10-17 18:30:06 +000028namespace
29{
30struct L8
31{
32 unsigned char L;
33
34 static void average(L8 *dst, const L8 *src1, const L8 *src2)
35 {
36 dst->L = ((src1->L ^ src2->L) >> 1) + (src1->L & src2->L);
37 }
38};
39
40struct A8L8
41{
42 unsigned char L;
43 unsigned char A;
44
45 static void average(A8L8 *dst, const A8L8 *src1, const A8L8 *src2)
46 {
47 *(unsigned short*)dst = (((*(unsigned short*)src1 ^ *(unsigned short*)src2) & 0xFEFE) >> 1) + (*(unsigned short*)src1 & *(unsigned short*)src2);
48 }
49};
50
51struct A8R8G8B8
52{
53 unsigned char B;
54 unsigned char G;
55 unsigned char R;
56 unsigned char A;
57
58 static void average(A8R8G8B8 *dst, const A8R8G8B8 *src1, const A8R8G8B8 *src2)
59 {
60 *(unsigned int*)dst = (((*(unsigned int*)src1 ^ *(unsigned int*)src2) & 0xFEFEFEFE) >> 1) + (*(unsigned int*)src1 & *(unsigned int*)src2);
61 }
62};
63
64struct A16B16G16R16F
65{
66 unsigned short R;
67 unsigned short G;
68 unsigned short B;
69 unsigned short A;
70
71 static void average(A16B16G16R16F *dst, const A16B16G16R16F *src1, const A16B16G16R16F *src2)
72 {
73 dst->R = float32ToFloat16((float16ToFloat32(src1->R) + float16ToFloat32(src2->R)) * 0.5f);
74 dst->G = float32ToFloat16((float16ToFloat32(src1->G) + float16ToFloat32(src2->G)) * 0.5f);
75 dst->B = float32ToFloat16((float16ToFloat32(src1->B) + float16ToFloat32(src2->B)) * 0.5f);
76 dst->A = float32ToFloat16((float16ToFloat32(src1->A) + float16ToFloat32(src2->A)) * 0.5f);
77 }
78};
79
80struct A32B32G32R32F
81{
82 float R;
83 float G;
84 float B;
85 float A;
86
87 static void average(A32B32G32R32F *dst, const A32B32G32R32F *src1, const A32B32G32R32F *src2)
88 {
89 dst->R = (src1->R + src2->R) * 0.5f;
90 dst->G = (src1->G + src2->G) * 0.5f;
91 dst->B = (src1->B + src2->B) * 0.5f;
92 dst->A = (src1->A + src2->A) * 0.5f;
93 }
94};
95
96template <typename T>
97void GenerateMip(unsigned int sourceWidth, unsigned int sourceHeight,
98 const unsigned char *sourceData, int sourcePitch,
99 unsigned char *destData, int destPitch)
100{
101 unsigned int mipWidth = std::max(1U, sourceWidth >> 1);
102 unsigned int mipHeight = std::max(1U, sourceHeight >> 1);
103
104 if (sourceHeight == 1)
105 {
106 ASSERT(sourceWidth != 1);
107
108 const T *src = (const T*)sourceData;
109 T *dst = (T*)destData;
110
111 for (unsigned int x = 0; x < mipWidth; x++)
112 {
113 T::average(&dst[x], &src[x * 2], &src[x * 2 + 1]);
114 }
115 }
116 else if (sourceWidth == 1)
117 {
118 ASSERT(sourceHeight != 1);
119
120 for (unsigned int y = 0; y < mipHeight; y++)
121 {
122 const T *src0 = (const T*)(sourceData + y * 2 * sourcePitch);
123 const T *src1 = (const T*)(sourceData + y * 2 * sourcePitch + sourcePitch);
124 T *dst = (T*)(destData + y * destPitch);
125
126 T::average(dst, src0, src1);
127 }
128 }
129 else
130 {
131 for (unsigned int y = 0; y < mipHeight; y++)
132 {
133 const T *src0 = (const T*)(sourceData + y * 2 * sourcePitch);
134 const T *src1 = (const T*)(sourceData + y * 2 * sourcePitch + sourcePitch);
135 T *dst = (T*)(destData + y * destPitch);
136
137 for (unsigned int x = 0; x < mipWidth; x++)
138 {
139 T tmp0;
140 T tmp1;
141
142 T::average(&tmp0, &src0[x * 2], &src0[x * 2 + 1]);
143 T::average(&tmp1, &src1[x * 2], &src1[x * 2 + 1]);
144 T::average(&dst[x], &tmp0, &tmp1);
145 }
146 }
147 }
148}
149
150void GenerateMip(IDirect3DSurface9 *destSurface, IDirect3DSurface9 *sourceSurface)
151{
152 D3DSURFACE_DESC destDesc;
153 HRESULT result = destSurface->GetDesc(&destDesc);
154 ASSERT(SUCCEEDED(result));
155
156 D3DSURFACE_DESC sourceDesc;
157 result = sourceSurface->GetDesc(&sourceDesc);
158 ASSERT(SUCCEEDED(result));
159
160 ASSERT(sourceDesc.Format == destDesc.Format);
daniel@transgaming.com2e38b802012-10-17 18:30:06 +0000161 ASSERT(sourceDesc.Width == 1 || sourceDesc.Width / 2 == destDesc.Width);
162 ASSERT(sourceDesc.Height == 1 || sourceDesc.Height / 2 == destDesc.Height);
163
164 D3DLOCKED_RECT sourceLocked = {0};
165 result = sourceSurface->LockRect(&sourceLocked, NULL, D3DLOCK_READONLY);
166 ASSERT(SUCCEEDED(result));
167
168 D3DLOCKED_RECT destLocked = {0};
169 result = destSurface->LockRect(&destLocked, NULL, 0);
170 ASSERT(SUCCEEDED(result));
171
172 const unsigned char *sourceData = reinterpret_cast<const unsigned char*>(sourceLocked.pBits);
173 unsigned char *destData = reinterpret_cast<unsigned char*>(destLocked.pBits);
174
175 if (sourceData && destData)
176 {
177 switch (sourceDesc.Format)
178 {
179 case D3DFMT_L8:
180 GenerateMip<L8>(sourceDesc.Width, sourceDesc.Height, sourceData, sourceLocked.Pitch, destData, destLocked.Pitch);
181 break;
182 case D3DFMT_A8L8:
183 GenerateMip<A8L8>(sourceDesc.Width, sourceDesc.Height, sourceData, sourceLocked.Pitch, destData, destLocked.Pitch);
184 break;
185 case D3DFMT_A8R8G8B8:
186 case D3DFMT_X8R8G8B8:
187 GenerateMip<A8R8G8B8>(sourceDesc.Width, sourceDesc.Height, sourceData, sourceLocked.Pitch, destData, destLocked.Pitch);
188 break;
189 case D3DFMT_A16B16G16R16F:
190 GenerateMip<A16B16G16R16F>(sourceDesc.Width, sourceDesc.Height, sourceData, sourceLocked.Pitch, destData, destLocked.Pitch);
191 break;
192 case D3DFMT_A32B32G32R32F:
193 GenerateMip<A32B32G32R32F>(sourceDesc.Width, sourceDesc.Height, sourceData, sourceLocked.Pitch, destData, destLocked.Pitch);
194 break;
195 default:
196 UNREACHABLE();
197 break;
198 }
199
200 destSurface->UnlockRect();
201 sourceSurface->UnlockRect();
202 }
203}
204}
205
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000206Texture::Texture(GLuint id) : RefCountObject(id)
207{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000208 mSamplerState.minFilter = GL_NEAREST_MIPMAP_LINEAR;
209 mSamplerState.magFilter = GL_LINEAR;
210 mSamplerState.wrapS = GL_REPEAT;
211 mSamplerState.wrapT = GL_REPEAT;
212 mSamplerState.maxAnisotropy = 1.0f;
213 mSamplerState.lodOffset = 0;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000214 mDirtyParameters = true;
215 mUsage = GL_NONE;
216
217 mDirtyImages = true;
218
219 mImmutable = false;
220}
221
222Texture::~Texture()
223{
224}
225
226// Returns true on successful filter state update (valid enum parameter)
227bool Texture::setMinFilter(GLenum filter)
228{
229 switch (filter)
230 {
231 case GL_NEAREST:
232 case GL_LINEAR:
233 case GL_NEAREST_MIPMAP_NEAREST:
234 case GL_LINEAR_MIPMAP_NEAREST:
235 case GL_NEAREST_MIPMAP_LINEAR:
236 case GL_LINEAR_MIPMAP_LINEAR:
237 {
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000238 if (mSamplerState.minFilter != filter)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000239 {
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000240 mSamplerState.minFilter = filter;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000241 mDirtyParameters = true;
242 }
243 return true;
244 }
245 default:
246 return false;
247 }
248}
249
250// Returns true on successful filter state update (valid enum parameter)
251bool Texture::setMagFilter(GLenum filter)
252{
253 switch (filter)
254 {
255 case GL_NEAREST:
256 case GL_LINEAR:
257 {
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000258 if (mSamplerState.magFilter != filter)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000259 {
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000260 mSamplerState.magFilter = filter;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000261 mDirtyParameters = true;
262 }
263 return true;
264 }
265 default:
266 return false;
267 }
268}
269
270// Returns true on successful wrap state update (valid enum parameter)
271bool Texture::setWrapS(GLenum wrap)
272{
273 switch (wrap)
274 {
275 case GL_REPEAT:
276 case GL_CLAMP_TO_EDGE:
277 case GL_MIRRORED_REPEAT:
278 {
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000279 if (mSamplerState.wrapS != wrap)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000280 {
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000281 mSamplerState.wrapS = wrap;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000282 mDirtyParameters = true;
283 }
284 return true;
285 }
286 default:
287 return false;
288 }
289}
290
291// Returns true on successful wrap state update (valid enum parameter)
292bool Texture::setWrapT(GLenum wrap)
293{
294 switch (wrap)
295 {
296 case GL_REPEAT:
297 case GL_CLAMP_TO_EDGE:
298 case GL_MIRRORED_REPEAT:
299 {
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000300 if (mSamplerState.wrapT != wrap)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000301 {
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000302 mSamplerState.wrapT = wrap;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000303 mDirtyParameters = true;
304 }
305 return true;
306 }
307 default:
308 return false;
309 }
310}
311
daniel@transgaming.com07ab8412012-07-12 15:17:09 +0000312// Returns true on successful max anisotropy update (valid anisotropy value)
313bool Texture::setMaxAnisotropy(float textureMaxAnisotropy, float contextMaxAnisotropy)
314{
315 textureMaxAnisotropy = std::min(textureMaxAnisotropy, contextMaxAnisotropy);
316 if (textureMaxAnisotropy < 1.0f)
317 {
318 return false;
319 }
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000320 if (mSamplerState.maxAnisotropy != textureMaxAnisotropy)
daniel@transgaming.com07ab8412012-07-12 15:17:09 +0000321 {
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000322 mSamplerState.maxAnisotropy = textureMaxAnisotropy;
daniel@transgaming.com07ab8412012-07-12 15:17:09 +0000323 mDirtyParameters = true;
324 }
325 return true;
326}
327
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000328// Returns true on successful usage state update (valid enum parameter)
329bool Texture::setUsage(GLenum usage)
330{
331 switch (usage)
332 {
333 case GL_NONE:
334 case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
335 mUsage = usage;
336 return true;
337 default:
338 return false;
339 }
340}
341
342GLenum Texture::getMinFilter() const
343{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000344 return mSamplerState.minFilter;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000345}
346
347GLenum Texture::getMagFilter() const
348{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000349 return mSamplerState.magFilter;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000350}
351
352GLenum Texture::getWrapS() const
353{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000354 return mSamplerState.wrapS;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000355}
356
357GLenum Texture::getWrapT() const
358{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000359 return mSamplerState.wrapT;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000360}
361
daniel@transgaming.com07ab8412012-07-12 15:17:09 +0000362float Texture::getMaxAnisotropy() const
363{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000364 return mSamplerState.maxAnisotropy;
365}
366
367int Texture::getLodOffset()
368{
369 TextureStorage *texture = getStorage(false);
370 return texture ? texture->getLodOffset() : 0;
371}
372
373void Texture::getSamplerState(SamplerState *sampler)
374{
375 *sampler = mSamplerState;
376 sampler->lodOffset = getLodOffset();
daniel@transgaming.com07ab8412012-07-12 15:17:09 +0000377}
378
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000379GLenum Texture::getUsage() const
380{
381 return mUsage;
382}
383
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +0000384bool Texture::isMipmapFiltered() const
385{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000386 switch (mSamplerState.minFilter)
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +0000387 {
388 case GL_NEAREST:
389 case GL_LINEAR:
390 return false;
391 case GL_NEAREST_MIPMAP_NEAREST:
392 case GL_LINEAR_MIPMAP_NEAREST:
393 case GL_NEAREST_MIPMAP_LINEAR:
394 case GL_LINEAR_MIPMAP_LINEAR:
395 return true;
396 default: UNREACHABLE();
397 return false;
398 }
399}
400
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000401void Texture::setImage(GLint unpackAlignment, const void *pixels, Image *image)
402{
403 if (pixels != NULL)
404 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000405 image->loadData(0, 0, image->getWidth(), image->getHeight(), unpackAlignment, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000406 mDirtyImages = true;
407 }
408}
409
410void Texture::setCompressedImage(GLsizei imageSize, const void *pixels, Image *image)
411{
412 if (pixels != NULL)
413 {
414 image->loadCompressedData(0, 0, image->getWidth(), image->getHeight(), pixels);
415 mDirtyImages = true;
416 }
417}
418
419bool Texture::subImage(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, Image *image)
420{
421 if (pixels != NULL)
422 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000423 image->loadData(xoffset, yoffset, width, height, unpackAlignment, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000424 mDirtyImages = true;
425 }
426
427 return true;
428}
429
430bool Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, Image *image)
431{
432 if (pixels != NULL)
433 {
434 image->loadCompressedData(xoffset, yoffset, width, height, pixels);
435 mDirtyImages = true;
436 }
437
438 return true;
439}
440
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000441TextureStorage *Texture::getNativeTexture()
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000442{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000443 // ensure the underlying texture is created
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000444
445 TextureStorage *storage = getStorage(false);
446 if (storage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000447 {
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000448 updateTexture();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000449 }
450
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000451 return storage;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000452}
453
454bool Texture::hasDirtyParameters() const
455{
456 return mDirtyParameters;
457}
458
459bool Texture::hasDirtyImages() const
460{
461 return mDirtyImages;
462}
463
464void Texture::resetDirty()
465{
466 mDirtyParameters = false;
467 mDirtyImages = false;
468}
469
470unsigned int Texture::getTextureSerial()
471{
472 TextureStorage *texture = getStorage(false);
473 return texture ? texture->getTextureSerial() : 0;
474}
475
476unsigned int Texture::getRenderTargetSerial(GLenum target)
477{
478 TextureStorage *texture = getStorage(true);
479 return texture ? texture->getRenderTargetSerial(target) : 0;
480}
481
482bool Texture::isImmutable() const
483{
484 return mImmutable;
485}
486
487GLint Texture::creationLevels(GLsizei width, GLsizei height) const
488{
489 if ((isPow2(width) && isPow2(height)) || getContext()->supportsNonPower2Texture())
490 {
491 return 0; // Maximum number of levels
492 }
493 else
494 {
495 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
496 return 1;
497 }
498}
499
500GLint Texture::creationLevels(GLsizei size) const
501{
502 return creationLevels(size, size);
503}
504
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000505Blit *Texture::getBlitter()
506{
507 Context *context = getContext();
508 return context->getBlitter();
509}
510
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000511Texture2D::Texture2D(GLuint id) : Texture(id)
512{
513 mTexStorage = NULL;
514 mSurface = NULL;
515 mColorbufferProxy = NULL;
516 mProxyRefs = 0;
517}
518
519Texture2D::~Texture2D()
520{
521 mColorbufferProxy = NULL;
522
523 delete mTexStorage;
524 mTexStorage = NULL;
525
526 if (mSurface)
527 {
528 mSurface->setBoundTexture(NULL);
529 mSurface = NULL;
530 }
531}
532
533// We need to maintain a count of references to renderbuffers acting as
534// proxies for this texture, so that we do not attempt to use a pointer
535// to a renderbuffer proxy which has been deleted.
536void Texture2D::addProxyRef(const Renderbuffer *proxy)
537{
538 mProxyRefs++;
539}
540
541void Texture2D::releaseProxy(const Renderbuffer *proxy)
542{
543 if (mProxyRefs > 0)
544 mProxyRefs--;
545
546 if (mProxyRefs == 0)
547 mColorbufferProxy = NULL;
548}
549
550GLenum Texture2D::getTarget() const
551{
552 return GL_TEXTURE_2D;
553}
554
555GLsizei Texture2D::getWidth(GLint level) const
556{
557 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
558 return mImageArray[level].getWidth();
559 else
560 return 0;
561}
562
563GLsizei Texture2D::getHeight(GLint level) const
564{
565 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
566 return mImageArray[level].getHeight();
567 else
568 return 0;
569}
570
571GLenum Texture2D::getInternalFormat(GLint level) const
572{
573 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000574 return mImageArray[level].getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000575 else
576 return GL_NONE;
577}
578
daniel@transgaming.com20d36662012-10-31 19:51:43 +0000579GLenum Texture2D::getActualFormat(GLint level) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000580{
581 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.com20d36662012-10-31 19:51:43 +0000582 return mImageArray[level].getActualFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000583 else
584 return D3DFMT_UNKNOWN;
585}
586
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000587void Texture2D::redefineImage(GLint level, GLint internalformat, GLsizei width, GLsizei height)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000588{
589 releaseTexImage();
590
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000591 bool redefined = mImageArray[level].redefine(internalformat, width, height, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000592
593 if (mTexStorage && redefined)
594 {
595 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
596 {
597 mImageArray[i].markDirty();
598 }
599
600 delete mTexStorage;
601 mTexStorage = NULL;
602 mDirtyImages = true;
603 }
604}
605
606void Texture2D::setImage(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
607{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000608 GLint internalformat = ConvertSizedInternalFormat(format, type);
609 redefineImage(level, internalformat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000610
611 Texture::setImage(unpackAlignment, pixels, &mImageArray[level]);
612}
613
614void Texture2D::bindTexImage(egl::Surface *surface)
615{
616 releaseTexImage();
617
daniel@transgaming.com106e1f72012-10-31 18:38:36 +0000618 GLint internalformat = surface->getFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000619
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000620 mImageArray[0].redefine(internalformat, surface->getWidth(), surface->getHeight(), true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000621
622 delete mTexStorage;
daniel@transgaming.com3c720782012-10-31 18:42:34 +0000623 renderer::SwapChain *swapchain = surface->getSwapChain(); // D3D9_REPLACE
daniel@transgaming.com25ee7442012-10-31 19:51:56 +0000624 mTexStorage = new TextureStorage2D(swapchain);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000625
626 mDirtyImages = true;
627 mSurface = surface;
628 mSurface->setBoundTexture(this);
629}
630
631void Texture2D::releaseTexImage()
632{
633 if (mSurface)
634 {
635 mSurface->setBoundTexture(NULL);
636 mSurface = NULL;
637
638 if (mTexStorage)
639 {
640 delete mTexStorage;
641 mTexStorage = NULL;
642 }
643
644 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
645 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000646 mImageArray[i].redefine(GL_RGBA8_OES, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000647 }
648 }
649}
650
651void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
652{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000653 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
654 redefineImage(level, format, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000655
656 Texture::setCompressedImage(imageSize, pixels, &mImageArray[level]);
657}
658
659void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
660{
661 ASSERT(mImageArray[level].getSurface() != NULL);
662
663 if (level < levelCount())
664 {
daniel@transgaming.com0f195ad2012-10-31 19:51:59 +0000665 Image *image = &mImageArray[level];
666 if (image->updateSurface(mTexStorage, level, xoffset, yoffset, width, height))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000667 {
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000668 image->markClean();
669 }
670 }
671}
672
673void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
674{
675 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[level]))
676 {
677 commitRect(level, xoffset, yoffset, width, height);
678 }
679}
680
681void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
682{
683 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[level]))
684 {
685 commitRect(level, xoffset, yoffset, width, height);
686 }
687}
688
689void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
690{
691 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
692
693 if (!renderTarget)
694 {
695 ERR("Failed to retrieve the render target.");
696 return error(GL_OUT_OF_MEMORY);
697 }
698
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000699 GLint internalformat = ConvertSizedInternalFormat(format, GL_UNSIGNED_BYTE);
700 redefineImage(level, internalformat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000701
702 if (!mImageArray[level].isRenderableFormat())
703 {
704 mImageArray[level].copy(0, 0, x, y, width, height, renderTarget);
705 mDirtyImages = true;
706 }
707 else
708 {
709 if (!mTexStorage || !mTexStorage->isRenderTarget())
710 {
711 convertToRenderTarget();
712 }
713
714 mImageArray[level].markClean();
715
716 if (width != 0 && height != 0 && level < levelCount())
717 {
718 RECT sourceRect;
719 sourceRect.left = x;
720 sourceRect.right = x + width;
721 sourceRect.top = y;
722 sourceRect.bottom = y + height;
723
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +0000724 IDirect3DSurface9 *dest = mTexStorage->getSurfaceLevel(level, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000725
726 if (dest)
727 {
728 getBlitter()->copy(renderTarget, sourceRect, format, 0, 0, dest);
729 dest->Release();
730 }
731 }
732 }
733
734 renderTarget->Release();
735}
736
737void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
738{
739 if (xoffset + width > mImageArray[level].getWidth() || yoffset + height > mImageArray[level].getHeight())
740 {
741 return error(GL_INVALID_VALUE);
742 }
743
744 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
745
746 if (!renderTarget)
747 {
748 ERR("Failed to retrieve the render target.");
749 return error(GL_OUT_OF_MEMORY);
750 }
751
752 if (!mImageArray[level].isRenderableFormat() || (!mTexStorage && !isSamplerComplete()))
753 {
754 mImageArray[level].copy(xoffset, yoffset, x, y, width, height, renderTarget);
755 mDirtyImages = true;
756 }
757 else
758 {
759 if (!mTexStorage || !mTexStorage->isRenderTarget())
760 {
761 convertToRenderTarget();
762 }
763
764 updateTexture();
765
766 if (level < levelCount())
767 {
768 RECT sourceRect;
769 sourceRect.left = x;
770 sourceRect.right = x + width;
771 sourceRect.top = y;
772 sourceRect.bottom = y + height;
773
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +0000774 IDirect3DSurface9 *dest = mTexStorage->getSurfaceLevel(level, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000775
776 if (dest)
777 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000778 getBlitter()->copy(renderTarget, sourceRect,
779 gl::ExtractFormat(mImageArray[0].getInternalFormat()),
780 xoffset, yoffset, dest);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000781 dest->Release();
782 }
783 }
784 }
785
786 renderTarget->Release();
787}
788
789void Texture2D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height)
790{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000791 delete mTexStorage;
daniel@transgaming.comf032cb82012-10-31 19:51:52 +0000792 mTexStorage = new TextureStorage2D(levels, internalformat, mUsage, false, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000793 mImmutable = true;
794
795 for (int level = 0; level < levels; level++)
796 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000797 mImageArray[level].redefine(internalformat, width, height, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000798 width = std::max(1, width >> 1);
799 height = std::max(1, height >> 1);
800 }
801
802 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
803 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000804 mImageArray[level].redefine(GL_NONE, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000805 }
806
807 if (mTexStorage->isManaged())
808 {
809 int levels = levelCount();
810
811 for (int level = 0; level < levels; level++)
812 {
daniel@transgaming.com0f195ad2012-10-31 19:51:59 +0000813 mImageArray[level].setManagedSurface(mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000814 }
815 }
816}
817
818// Tests for 2D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85.
819bool Texture2D::isSamplerComplete() const
820{
821 GLsizei width = mImageArray[0].getWidth();
822 GLsizei height = mImageArray[0].getHeight();
823
824 if (width <= 0 || height <= 0)
825 {
826 return false;
827 }
828
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +0000829 bool mipmapping = isMipmapFiltered();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000830
daniel@transgaming.com6b1a0a02012-10-17 18:22:47 +0000831 if ((IsFloat32Format(getInternalFormat(0)) && !getContext()->supportsFloat32LinearFilter()) ||
832 (IsFloat16Format(getInternalFormat(0)) && !getContext()->supportsFloat16LinearFilter()))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000833 {
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000834 if (mSamplerState.magFilter != GL_NEAREST ||
835 (mSamplerState.minFilter != GL_NEAREST && mSamplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000836 {
837 return false;
838 }
839 }
840
841 bool npotSupport = getContext()->supportsNonPower2Texture();
842
843 if (!npotSupport)
844 {
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000845 if ((mSamplerState.wrapS != GL_CLAMP_TO_EDGE && !isPow2(width)) ||
846 (mSamplerState.wrapT != GL_CLAMP_TO_EDGE && !isPow2(height)))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000847 {
848 return false;
849 }
850 }
851
852 if (mipmapping)
853 {
854 if (!npotSupport)
855 {
856 if (!isPow2(width) || !isPow2(height))
857 {
858 return false;
859 }
860 }
861
862 if (!isMipmapComplete())
863 {
864 return false;
865 }
866 }
867
868 return true;
869}
870
871// Tests for 2D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
872bool Texture2D::isMipmapComplete() const
873{
874 if (isImmutable())
875 {
876 return true;
877 }
878
879 GLsizei width = mImageArray[0].getWidth();
880 GLsizei height = mImageArray[0].getHeight();
881
882 if (width <= 0 || height <= 0)
883 {
884 return false;
885 }
886
887 int q = log2(std::max(width, height));
888
889 for (int level = 1; level <= q; level++)
890 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000891 if (mImageArray[level].getInternalFormat() != mImageArray[0].getInternalFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000892 {
893 return false;
894 }
895
896 if (mImageArray[level].getWidth() != std::max(1, width >> level))
897 {
898 return false;
899 }
900
901 if (mImageArray[level].getHeight() != std::max(1, height >> level))
902 {
903 return false;
904 }
905 }
906
907 return true;
908}
909
910bool Texture2D::isCompressed(GLint level) const
911{
912 return IsCompressed(getInternalFormat(level));
913}
914
915bool Texture2D::isDepth(GLint level) const
916{
917 return IsDepthTexture(getInternalFormat(level));
918}
919
daniel@transgaming.comf032cb82012-10-31 19:51:52 +0000920// Constructs a native texture resource from the texture images
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000921void Texture2D::createTexture()
922{
923 GLsizei width = mImageArray[0].getWidth();
924 GLsizei height = mImageArray[0].getHeight();
daniel@transgaming.come6a09842012-09-17 21:28:55 +0000925
926 if (!(width > 0 && height > 0))
daniel@transgaming.comf032cb82012-10-31 19:51:52 +0000927 return; // do not attempt to create native textures for nonexistant data
daniel@transgaming.come6a09842012-09-17 21:28:55 +0000928
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000929 GLint levels = creationLevels(width, height);
daniel@transgaming.comf032cb82012-10-31 19:51:52 +0000930 GLenum internalformat = mImageArray[0].getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000931
932 delete mTexStorage;
daniel@transgaming.comf032cb82012-10-31 19:51:52 +0000933 mTexStorage = new TextureStorage2D(levels, internalformat, mUsage, false, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000934
935 if (mTexStorage->isManaged())
936 {
937 int levels = levelCount();
938
939 for (int level = 0; level < levels; level++)
940 {
daniel@transgaming.com0f195ad2012-10-31 19:51:59 +0000941 mImageArray[level].setManagedSurface(mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000942 }
943 }
944
945 mDirtyImages = true;
946}
947
948void Texture2D::updateTexture()
949{
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +0000950 bool mipmapping = (isMipmapFiltered() && isMipmapComplete());
951
952 int levels = (mipmapping ? levelCount() : 1);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000953
954 for (int level = 0; level < levels; level++)
955 {
956 Image *image = &mImageArray[level];
957
958 if (image->isDirty())
959 {
960 commitRect(level, 0, 0, mImageArray[level].getWidth(), mImageArray[level].getHeight());
961 }
962 }
963}
964
965void Texture2D::convertToRenderTarget()
966{
967 TextureStorage2D *newTexStorage = NULL;
968
969 if (mImageArray[0].getWidth() != 0 && mImageArray[0].getHeight() != 0)
970 {
971 GLsizei width = mImageArray[0].getWidth();
972 GLsizei height = mImageArray[0].getHeight();
973 GLint levels = creationLevels(width, height);
daniel@transgaming.comf032cb82012-10-31 19:51:52 +0000974 GLenum internalformat = mImageArray[0].getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000975
daniel@transgaming.comf032cb82012-10-31 19:51:52 +0000976 newTexStorage = new TextureStorage2D(levels, internalformat, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, true, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000977
978 if (mTexStorage != NULL)
979 {
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +0000980 if (!TextureStorage2D::copyToRenderTarget(newTexStorage, mTexStorage))
981 {
982 delete newTexStorage;
983 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000984 }
985 }
986 }
987
988 delete mTexStorage;
989 mTexStorage = newTexStorage;
990
991 mDirtyImages = true;
992}
993
994void Texture2D::generateMipmaps()
995{
996 if (!getContext()->supportsNonPower2Texture())
997 {
998 if (!isPow2(mImageArray[0].getWidth()) || !isPow2(mImageArray[0].getHeight()))
999 {
1000 return error(GL_INVALID_OPERATION);
1001 }
1002 }
1003
1004 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1005 unsigned int q = log2(std::max(mImageArray[0].getWidth(), mImageArray[0].getHeight()));
1006 for (unsigned int i = 1; i <= q; i++)
1007 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001008 redefineImage(i, mImageArray[0].getInternalFormat(),
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001009 std::max(mImageArray[0].getWidth() >> i, 1),
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001010 std::max(mImageArray[0].getHeight() >> i, 1));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001011 }
1012
1013 if (mTexStorage && mTexStorage->isRenderTarget())
1014 {
1015 for (unsigned int i = 1; i <= q; i++)
1016 {
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00001017 IDirect3DSurface9 *upper = mTexStorage->getSurfaceLevel(i - 1, false);
1018 IDirect3DSurface9 *lower = mTexStorage->getSurfaceLevel(i, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001019
1020 if (upper != NULL && lower != NULL)
1021 {
1022 getBlitter()->boxFilter(upper, lower);
1023 }
1024
1025 if (upper != NULL) upper->Release();
1026 if (lower != NULL) lower->Release();
1027
1028 mImageArray[i].markClean();
1029 }
1030 }
1031 else
1032 {
1033 for (unsigned int i = 1; i <= q; i++)
1034 {
1035 if (mImageArray[i].getSurface() == NULL)
1036 {
1037 return error(GL_OUT_OF_MEMORY);
1038 }
1039
daniel@transgaming.com2e38b802012-10-17 18:30:06 +00001040 GenerateMip(mImageArray[i].getSurface(), mImageArray[i - 1].getSurface());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001041
1042 mImageArray[i].markDirty();
1043 }
1044 }
1045}
1046
1047Renderbuffer *Texture2D::getRenderbuffer(GLenum target)
1048{
1049 if (target != GL_TEXTURE_2D)
1050 {
1051 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
1052 }
1053
1054 if (mColorbufferProxy == NULL)
1055 {
1056 mColorbufferProxy = new Renderbuffer(id(), new RenderbufferTexture2D(this, target));
1057 }
1058
1059 return mColorbufferProxy;
1060}
1061
1062// Increments refcount on surface.
1063// caller must Release() the returned surface
1064IDirect3DSurface9 *Texture2D::getRenderTarget(GLenum target)
1065{
1066 ASSERT(target == GL_TEXTURE_2D);
1067
1068 // ensure the underlying texture is created
1069 if (getStorage(true) == NULL)
1070 {
1071 return NULL;
1072 }
1073
1074 updateTexture();
1075
1076 // ensure this is NOT a depth texture
1077 if (isDepth(0))
1078 {
1079 return NULL;
1080 }
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00001081 return mTexStorage->getSurfaceLevel(0, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001082}
1083
1084// Increments refcount on surface.
1085// caller must Release() the returned surface
1086IDirect3DSurface9 *Texture2D::getDepthStencil(GLenum target)
1087{
1088 ASSERT(target == GL_TEXTURE_2D);
1089
1090 // ensure the underlying texture is created
1091 if (getStorage(true) == NULL)
1092 {
1093 return NULL;
1094 }
1095
1096 updateTexture();
1097
1098 // ensure this is actually a depth texture
1099 if (!isDepth(0))
1100 {
1101 return NULL;
1102 }
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00001103 return mTexStorage->getSurfaceLevel(0, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001104}
1105
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +00001106int Texture2D::levelCount()
1107{
1108 return mTexStorage ? mTexStorage->levelCount() - getLodOffset() : 0;
1109}
1110
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001111TextureStorage *Texture2D::getStorage(bool renderTarget)
1112{
1113 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
1114 {
1115 if (renderTarget)
1116 {
1117 convertToRenderTarget();
1118 }
1119 else
1120 {
1121 createTexture();
1122 }
1123 }
1124
1125 return mTexStorage;
1126}
1127
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001128TextureCubeMap::TextureCubeMap(GLuint id) : Texture(id)
1129{
1130 mTexStorage = NULL;
1131 for (int i = 0; i < 6; i++)
1132 {
1133 mFaceProxies[i] = NULL;
1134 mFaceProxyRefs[i] = 0;
1135 }
1136}
1137
1138TextureCubeMap::~TextureCubeMap()
1139{
1140 for (int i = 0; i < 6; i++)
1141 {
1142 mFaceProxies[i] = NULL;
1143 }
1144
1145 delete mTexStorage;
1146 mTexStorage = NULL;
1147}
1148
1149// We need to maintain a count of references to renderbuffers acting as
1150// proxies for this texture, so that the texture is not deleted while
1151// proxy references still exist. If the reference count drops to zero,
1152// we set our proxy pointer NULL, so that a new attempt at referencing
1153// will cause recreation.
1154void TextureCubeMap::addProxyRef(const Renderbuffer *proxy)
1155{
1156 for (int i = 0; i < 6; i++)
1157 {
1158 if (mFaceProxies[i] == proxy)
1159 mFaceProxyRefs[i]++;
1160 }
1161}
1162
1163void TextureCubeMap::releaseProxy(const Renderbuffer *proxy)
1164{
1165 for (int i = 0; i < 6; i++)
1166 {
1167 if (mFaceProxies[i] == proxy)
1168 {
1169 if (mFaceProxyRefs[i] > 0)
1170 mFaceProxyRefs[i]--;
1171
1172 if (mFaceProxyRefs[i] == 0)
1173 mFaceProxies[i] = NULL;
1174 }
1175 }
1176}
1177
1178GLenum TextureCubeMap::getTarget() const
1179{
1180 return GL_TEXTURE_CUBE_MAP;
1181}
1182
1183GLsizei TextureCubeMap::getWidth(GLenum target, GLint level) const
1184{
1185 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1186 return mImageArray[faceIndex(target)][level].getWidth();
1187 else
1188 return 0;
1189}
1190
1191GLsizei TextureCubeMap::getHeight(GLenum target, GLint level) const
1192{
1193 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1194 return mImageArray[faceIndex(target)][level].getHeight();
1195 else
1196 return 0;
1197}
1198
1199GLenum TextureCubeMap::getInternalFormat(GLenum target, GLint level) const
1200{
1201 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001202 return mImageArray[faceIndex(target)][level].getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001203 else
1204 return GL_NONE;
1205}
1206
daniel@transgaming.com20d36662012-10-31 19:51:43 +00001207GLenum TextureCubeMap::getActualFormat(GLenum target, GLint level) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001208{
1209 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.com20d36662012-10-31 19:51:43 +00001210 return mImageArray[faceIndex(target)][level].getActualFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001211 else
1212 return D3DFMT_UNKNOWN;
1213}
1214
1215void TextureCubeMap::setImagePosX(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1216{
1217 setImage(0, level, width, height, format, type, unpackAlignment, pixels);
1218}
1219
1220void TextureCubeMap::setImageNegX(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1221{
1222 setImage(1, level, width, height, format, type, unpackAlignment, pixels);
1223}
1224
1225void TextureCubeMap::setImagePosY(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1226{
1227 setImage(2, level, width, height, format, type, unpackAlignment, pixels);
1228}
1229
1230void TextureCubeMap::setImageNegY(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1231{
1232 setImage(3, level, width, height, format, type, unpackAlignment, pixels);
1233}
1234
1235void TextureCubeMap::setImagePosZ(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1236{
1237 setImage(4, level, width, height, format, type, unpackAlignment, pixels);
1238}
1239
1240void TextureCubeMap::setImageNegZ(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1241{
1242 setImage(5, level, width, height, format, type, unpackAlignment, pixels);
1243}
1244
1245void TextureCubeMap::setCompressedImage(GLenum face, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
1246{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001247 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1248 redefineImage(faceIndex(face), level, format, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001249
1250 Texture::setCompressedImage(imageSize, pixels, &mImageArray[faceIndex(face)][level]);
1251}
1252
1253void TextureCubeMap::commitRect(int face, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1254{
1255 ASSERT(mImageArray[face][level].getSurface() != NULL);
1256
1257 if (level < levelCount())
1258 {
daniel@transgaming.com0f195ad2012-10-31 19:51:59 +00001259 Image *image = &mImageArray[face][level];
1260 if (image->updateSurface(mTexStorage, face, level, xoffset, yoffset, width, height))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001261 image->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001262 }
1263}
1264
1265void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1266{
1267 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[faceIndex(target)][level]))
1268 {
1269 commitRect(faceIndex(target), level, xoffset, yoffset, width, height);
1270 }
1271}
1272
1273void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1274{
1275 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[faceIndex(target)][level]))
1276 {
1277 commitRect(faceIndex(target), level, xoffset, yoffset, width, height);
1278 }
1279}
1280
1281// Tests for cube map sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 86.
1282bool TextureCubeMap::isSamplerComplete() const
1283{
1284 int size = mImageArray[0][0].getWidth();
1285
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +00001286 bool mipmapping = isMipmapFiltered();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001287
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001288 if ((gl::ExtractType(getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0)) == GL_FLOAT && !getContext()->supportsFloat32LinearFilter()) ||
1289 (gl::ExtractType(getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0) == GL_HALF_FLOAT_OES) && !getContext()->supportsFloat16LinearFilter()))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001290 {
daniel@transgaming.comebf139f2012-10-31 18:07:32 +00001291 if (mSamplerState.magFilter != GL_NEAREST ||
1292 (mSamplerState.minFilter != GL_NEAREST && mSamplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001293 {
1294 return false;
1295 }
1296 }
1297
1298 if (!isPow2(size) && !getContext()->supportsNonPower2Texture())
1299 {
daniel@transgaming.comebf139f2012-10-31 18:07:32 +00001300 if (mSamplerState.wrapS != GL_CLAMP_TO_EDGE || mSamplerState.wrapT != GL_CLAMP_TO_EDGE || mipmapping)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001301 {
1302 return false;
1303 }
1304 }
1305
1306 if (!mipmapping)
1307 {
1308 if (!isCubeComplete())
1309 {
1310 return false;
1311 }
1312 }
1313 else
1314 {
1315 if (!isMipmapCubeComplete()) // Also tests for isCubeComplete()
1316 {
1317 return false;
1318 }
1319 }
1320
1321 return true;
1322}
1323
1324// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1325bool TextureCubeMap::isCubeComplete() const
1326{
1327 if (mImageArray[0][0].getWidth() <= 0 || mImageArray[0][0].getHeight() != mImageArray[0][0].getWidth())
1328 {
1329 return false;
1330 }
1331
1332 for (unsigned int face = 1; face < 6; face++)
1333 {
1334 if (mImageArray[face][0].getWidth() != mImageArray[0][0].getWidth() ||
1335 mImageArray[face][0].getWidth() != mImageArray[0][0].getHeight() ||
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001336 mImageArray[face][0].getInternalFormat() != mImageArray[0][0].getInternalFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001337 {
1338 return false;
1339 }
1340 }
1341
1342 return true;
1343}
1344
1345bool TextureCubeMap::isMipmapCubeComplete() const
1346{
1347 if (isImmutable())
1348 {
1349 return true;
1350 }
1351
1352 if (!isCubeComplete())
1353 {
1354 return false;
1355 }
1356
1357 GLsizei size = mImageArray[0][0].getWidth();
1358
1359 int q = log2(size);
1360
1361 for (int face = 0; face < 6; face++)
1362 {
1363 for (int level = 1; level <= q; level++)
1364 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001365 if (mImageArray[face][level].getInternalFormat() != mImageArray[0][0].getInternalFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001366 {
1367 return false;
1368 }
1369
1370 if (mImageArray[face][level].getWidth() != std::max(1, size >> level))
1371 {
1372 return false;
1373 }
1374 }
1375 }
1376
1377 return true;
1378}
1379
1380bool TextureCubeMap::isCompressed(GLenum target, GLint level) const
1381{
1382 return IsCompressed(getInternalFormat(target, level));
1383}
1384
daniel@transgaming.comf032cb82012-10-31 19:51:52 +00001385// Constructs a native texture resource from the texture images, or returns an existing one
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001386void TextureCubeMap::createTexture()
1387{
1388 GLsizei size = mImageArray[0][0].getWidth();
daniel@transgaming.come6a09842012-09-17 21:28:55 +00001389
1390 if (!(size > 0))
daniel@transgaming.comf032cb82012-10-31 19:51:52 +00001391 return; // do not attempt to create native textures for nonexistant data
daniel@transgaming.come6a09842012-09-17 21:28:55 +00001392
sminns@adobe.comce1189b2012-09-18 20:06:35 +00001393 GLint levels = creationLevels(size);
daniel@transgaming.comf032cb82012-10-31 19:51:52 +00001394 GLenum internalformat = mImageArray[0][0].getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001395
1396 delete mTexStorage;
daniel@transgaming.comf032cb82012-10-31 19:51:52 +00001397 mTexStorage = new TextureStorageCubeMap(levels, internalformat, mUsage, false, size);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001398
1399 if (mTexStorage->isManaged())
1400 {
1401 int levels = levelCount();
1402
1403 for (int face = 0; face < 6; face++)
1404 {
1405 for (int level = 0; level < levels; level++)
1406 {
daniel@transgaming.com0f195ad2012-10-31 19:51:59 +00001407 mImageArray[face][level].setManagedSurface(mTexStorage, face, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001408 }
1409 }
1410 }
1411
1412 mDirtyImages = true;
1413}
1414
1415void TextureCubeMap::updateTexture()
1416{
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +00001417 bool mipmapping = isMipmapFiltered() && isMipmapCubeComplete();
1418
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001419 for (int face = 0; face < 6; face++)
1420 {
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +00001421 int levels = (mipmapping ? levelCount() : 1);
1422
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001423 for (int level = 0; level < levels; level++)
1424 {
1425 Image *image = &mImageArray[face][level];
1426
1427 if (image->isDirty())
1428 {
1429 commitRect(face, level, 0, 0, image->getWidth(), image->getHeight());
1430 }
1431 }
1432 }
1433}
1434
1435void TextureCubeMap::convertToRenderTarget()
1436{
1437 TextureStorageCubeMap *newTexStorage = NULL;
1438
1439 if (mImageArray[0][0].getWidth() != 0)
1440 {
1441 GLsizei size = mImageArray[0][0].getWidth();
sminns@adobe.comce1189b2012-09-18 20:06:35 +00001442 GLint levels = creationLevels(size);
daniel@transgaming.comf032cb82012-10-31 19:51:52 +00001443 GLenum internalformat = mImageArray[0][0].getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001444
daniel@transgaming.comf032cb82012-10-31 19:51:52 +00001445 newTexStorage = new TextureStorageCubeMap(levels, internalformat, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, true, size);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001446
1447 if (mTexStorage != NULL)
1448 {
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +00001449 if (!TextureStorageCubeMap::copyToRenderTarget(newTexStorage, mTexStorage))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001450 {
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +00001451 delete newTexStorage;
1452 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001453 }
1454 }
1455 }
1456
1457 delete mTexStorage;
1458 mTexStorage = newTexStorage;
1459
1460 mDirtyImages = true;
1461}
1462
1463void TextureCubeMap::setImage(int faceIndex, GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1464{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001465 GLint internalformat = ConvertSizedInternalFormat(format, type);
1466 redefineImage(faceIndex, level, internalformat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001467
1468 Texture::setImage(unpackAlignment, pixels, &mImageArray[faceIndex][level]);
1469}
1470
1471unsigned int TextureCubeMap::faceIndex(GLenum face)
1472{
1473 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
1474 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
1475 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
1476 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
1477 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
1478
1479 return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
1480}
1481
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001482void TextureCubeMap::redefineImage(int face, GLint level, GLint internalformat, GLsizei width, GLsizei height)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001483{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001484 bool redefined = mImageArray[face][level].redefine(internalformat, width, height, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001485
1486 if (mTexStorage && redefined)
1487 {
1488 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1489 {
1490 for (int f = 0; f < 6; f++)
1491 {
1492 mImageArray[f][i].markDirty();
1493 }
1494 }
1495
1496 delete mTexStorage;
1497 mTexStorage = NULL;
1498
1499 mDirtyImages = true;
1500 }
1501}
1502
1503void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1504{
1505 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
1506
1507 if (!renderTarget)
1508 {
1509 ERR("Failed to retrieve the render target.");
1510 return error(GL_OUT_OF_MEMORY);
1511 }
1512
1513 unsigned int faceindex = faceIndex(target);
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001514 GLint internalformat = gl::ConvertSizedInternalFormat(format, GL_UNSIGNED_BYTE);
1515 redefineImage(faceindex, level, internalformat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001516
1517 if (!mImageArray[faceindex][level].isRenderableFormat())
1518 {
1519 mImageArray[faceindex][level].copy(0, 0, x, y, width, height, renderTarget);
1520 mDirtyImages = true;
1521 }
1522 else
1523 {
1524 if (!mTexStorage || !mTexStorage->isRenderTarget())
1525 {
1526 convertToRenderTarget();
1527 }
1528
1529 mImageArray[faceindex][level].markClean();
1530
1531 ASSERT(width == height);
1532
1533 if (width > 0 && level < levelCount())
1534 {
1535 RECT sourceRect;
1536 sourceRect.left = x;
1537 sourceRect.right = x + width;
1538 sourceRect.top = y;
1539 sourceRect.bottom = y + height;
1540
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00001541 IDirect3DSurface9 *dest = mTexStorage->getCubeMapSurface(target, level, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001542
1543 if (dest)
1544 {
1545 getBlitter()->copy(renderTarget, sourceRect, format, 0, 0, dest);
1546 dest->Release();
1547 }
1548 }
1549 }
1550
1551 renderTarget->Release();
1552}
1553
1554void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1555{
1556 GLsizei size = mImageArray[faceIndex(target)][level].getWidth();
1557
1558 if (xoffset + width > size || yoffset + height > size)
1559 {
1560 return error(GL_INVALID_VALUE);
1561 }
1562
1563 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
1564
1565 if (!renderTarget)
1566 {
1567 ERR("Failed to retrieve the render target.");
1568 return error(GL_OUT_OF_MEMORY);
1569 }
1570
1571 unsigned int faceindex = faceIndex(target);
1572
1573 if (!mImageArray[faceindex][level].isRenderableFormat() || (!mTexStorage && !isSamplerComplete()))
1574 {
1575 mImageArray[faceindex][level].copy(0, 0, x, y, width, height, renderTarget);
1576 mDirtyImages = true;
1577 }
1578 else
1579 {
1580 if (!mTexStorage || !mTexStorage->isRenderTarget())
1581 {
1582 convertToRenderTarget();
1583 }
1584
1585 updateTexture();
1586
1587 if (level < levelCount())
1588 {
1589 RECT sourceRect;
1590 sourceRect.left = x;
1591 sourceRect.right = x + width;
1592 sourceRect.top = y;
1593 sourceRect.bottom = y + height;
1594
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00001595 IDirect3DSurface9 *dest = mTexStorage->getCubeMapSurface(target, level, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001596
1597 if (dest)
1598 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001599 getBlitter()->copy(renderTarget, sourceRect, gl::ExtractFormat(mImageArray[0][0].getInternalFormat()), xoffset, yoffset, dest);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001600 dest->Release();
1601 }
1602 }
1603 }
1604
1605 renderTarget->Release();
1606}
1607
1608void TextureCubeMap::storage(GLsizei levels, GLenum internalformat, GLsizei size)
1609{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001610 delete mTexStorage;
daniel@transgaming.comf032cb82012-10-31 19:51:52 +00001611 mTexStorage = new TextureStorageCubeMap(levels, internalformat, mUsage, false, size);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001612 mImmutable = true;
1613
1614 for (int level = 0; level < levels; level++)
1615 {
1616 for (int face = 0; face < 6; face++)
1617 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001618 mImageArray[face][level].redefine(internalformat, size, size, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001619 size = std::max(1, size >> 1);
1620 }
1621 }
1622
1623 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1624 {
1625 for (int face = 0; face < 6; face++)
1626 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001627 mImageArray[face][level].redefine(GL_NONE, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001628 }
1629 }
1630
1631 if (mTexStorage->isManaged())
1632 {
1633 int levels = levelCount();
1634
1635 for (int face = 0; face < 6; face++)
1636 {
1637 for (int level = 0; level < levels; level++)
1638 {
daniel@transgaming.com0f195ad2012-10-31 19:51:59 +00001639 mImageArray[face][level].setManagedSurface(mTexStorage, face, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001640 }
1641 }
1642 }
1643}
1644
1645void TextureCubeMap::generateMipmaps()
1646{
1647 if (!isCubeComplete())
1648 {
1649 return error(GL_INVALID_OPERATION);
1650 }
1651
1652 if (!getContext()->supportsNonPower2Texture())
1653 {
1654 if (!isPow2(mImageArray[0][0].getWidth()))
1655 {
1656 return error(GL_INVALID_OPERATION);
1657 }
1658 }
1659
1660 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1661 unsigned int q = log2(mImageArray[0][0].getWidth());
1662 for (unsigned int f = 0; f < 6; f++)
1663 {
1664 for (unsigned int i = 1; i <= q; i++)
1665 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001666 redefineImage(f, i, mImageArray[f][0].getInternalFormat(),
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001667 std::max(mImageArray[f][0].getWidth() >> i, 1),
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001668 std::max(mImageArray[f][0].getWidth() >> i, 1));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001669 }
1670 }
1671
1672 if (mTexStorage && mTexStorage->isRenderTarget())
1673 {
1674 for (unsigned int f = 0; f < 6; f++)
1675 {
1676 for (unsigned int i = 1; i <= q; i++)
1677 {
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00001678 IDirect3DSurface9 *upper = mTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i - 1, false);
1679 IDirect3DSurface9 *lower = mTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001680
1681 if (upper != NULL && lower != NULL)
1682 {
1683 getBlitter()->boxFilter(upper, lower);
1684 }
1685
1686 if (upper != NULL) upper->Release();
1687 if (lower != NULL) lower->Release();
1688
1689 mImageArray[f][i].markClean();
1690 }
1691 }
1692 }
1693 else
1694 {
1695 for (unsigned int f = 0; f < 6; f++)
1696 {
1697 for (unsigned int i = 1; i <= q; i++)
1698 {
1699 if (mImageArray[f][i].getSurface() == NULL)
1700 {
1701 return error(GL_OUT_OF_MEMORY);
1702 }
1703
daniel@transgaming.com2e38b802012-10-17 18:30:06 +00001704 GenerateMip(mImageArray[f][i].getSurface(), mImageArray[f][i - 1].getSurface());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001705
1706 mImageArray[f][i].markDirty();
1707 }
1708 }
1709 }
1710}
1711
1712Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target)
1713{
1714 if (!IsCubemapTextureTarget(target))
1715 {
1716 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
1717 }
1718
1719 unsigned int face = faceIndex(target);
1720
1721 if (mFaceProxies[face] == NULL)
1722 {
1723 mFaceProxies[face] = new Renderbuffer(id(), new RenderbufferTextureCubeMap(this, target));
1724 }
1725
1726 return mFaceProxies[face];
1727}
1728
1729// Increments refcount on surface.
1730// caller must Release() the returned surface
1731IDirect3DSurface9 *TextureCubeMap::getRenderTarget(GLenum target)
1732{
1733 ASSERT(IsCubemapTextureTarget(target));
1734
1735 // ensure the underlying texture is created
1736 if (getStorage(true) == NULL)
1737 {
1738 return NULL;
1739 }
1740
1741 updateTexture();
1742
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00001743 return mTexStorage->getCubeMapSurface(target, 0, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001744}
1745
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +00001746int TextureCubeMap::levelCount()
1747{
1748 return mTexStorage ? mTexStorage->levelCount() - getLodOffset() : 0;
1749}
1750
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001751TextureStorage *TextureCubeMap::getStorage(bool renderTarget)
1752{
1753 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
1754 {
1755 if (renderTarget)
1756 {
1757 convertToRenderTarget();
1758 }
1759 else
1760 {
1761 createTexture();
1762 }
1763 }
1764
1765 return mTexStorage;
1766}
1767
1768}