blob: e0712af58b79108399fe0e98ef7efc8f6a172bbc [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.coma734f272012-10-31 18:07:48 +0000441// D3D9_REPLACE
442IDirect3DBaseTexture9 *Texture::getD3DTexture()
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000443{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000444 // ensure the underlying texture is created
445 if (getStorage(false) == NULL)
446 {
447 return NULL;
448 }
449
450 updateTexture();
451
452 return getBaseTexture();
453}
454
455bool Texture::hasDirtyParameters() const
456{
457 return mDirtyParameters;
458}
459
460bool Texture::hasDirtyImages() const
461{
462 return mDirtyImages;
463}
464
465void Texture::resetDirty()
466{
467 mDirtyParameters = false;
468 mDirtyImages = false;
469}
470
471unsigned int Texture::getTextureSerial()
472{
473 TextureStorage *texture = getStorage(false);
474 return texture ? texture->getTextureSerial() : 0;
475}
476
477unsigned int Texture::getRenderTargetSerial(GLenum target)
478{
479 TextureStorage *texture = getStorage(true);
480 return texture ? texture->getRenderTargetSerial(target) : 0;
481}
482
483bool Texture::isImmutable() const
484{
485 return mImmutable;
486}
487
488GLint Texture::creationLevels(GLsizei width, GLsizei height) const
489{
490 if ((isPow2(width) && isPow2(height)) || getContext()->supportsNonPower2Texture())
491 {
492 return 0; // Maximum number of levels
493 }
494 else
495 {
496 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
497 return 1;
498 }
499}
500
501GLint Texture::creationLevels(GLsizei size) const
502{
503 return creationLevels(size, size);
504}
505
jbauman@chromium.org6bc4a142012-09-06 21:28:30 +0000506int Texture::levelCount()
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000507{
jbauman@chromium.org6bc4a142012-09-06 21:28:30 +0000508 return getBaseTexture() ? getBaseTexture()->GetLevelCount() - getLodOffset() : 0;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000509}
510
511Blit *Texture::getBlitter()
512{
513 Context *context = getContext();
514 return context->getBlitter();
515}
516
517bool Texture::copyToRenderTarget(IDirect3DSurface9 *dest, IDirect3DSurface9 *source, bool fromManaged)
518{
519 if (source && dest)
520 {
daniel@transgaming.comdabf0022012-10-17 18:29:59 +0000521 HRESULT result = D3DERR_OUTOFVIDEOMEMORY;
daniel@transgaming.com2507f412012-10-31 18:46:48 +0000522 renderer::Renderer9 *renderer = getDisplay()->getRenderer();
daniel@transgaming.com64e62902012-10-31 18:27:46 +0000523 IDirect3DDevice9 *device = renderer->getDevice(); // D3D9_REPLACE
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000524
525 if (fromManaged)
526 {
daniel@transgaming.comdabf0022012-10-17 18:29:59 +0000527 D3DSURFACE_DESC desc;
528 source->GetDesc(&desc);
529
530 IDirect3DSurface9 *surf = 0;
daniel@transgaming.com64e62902012-10-31 18:27:46 +0000531 result = device->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &surf, NULL);
daniel@transgaming.comdabf0022012-10-17 18:29:59 +0000532
533 if (SUCCEEDED(result))
534 {
daniel@transgaming.comb9d7e6f2012-10-31 19:08:32 +0000535 Image::CopyLockableSurfaces(surf, source);
daniel@transgaming.com64e62902012-10-31 18:27:46 +0000536 result = device->UpdateSurface(surf, NULL, dest, NULL);
daniel@transgaming.comdabf0022012-10-17 18:29:59 +0000537 surf->Release();
538 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000539 }
540 else
541 {
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000542 renderer->endScene();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000543 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
544 }
545
546 if (FAILED(result))
547 {
548 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
549 return false;
550 }
551 }
552
553 return true;
554}
555
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000556Texture2D::Texture2D(GLuint id) : Texture(id)
557{
558 mTexStorage = NULL;
559 mSurface = NULL;
560 mColorbufferProxy = NULL;
561 mProxyRefs = 0;
562}
563
564Texture2D::~Texture2D()
565{
566 mColorbufferProxy = NULL;
567
568 delete mTexStorage;
569 mTexStorage = NULL;
570
571 if (mSurface)
572 {
573 mSurface->setBoundTexture(NULL);
574 mSurface = NULL;
575 }
576}
577
578// We need to maintain a count of references to renderbuffers acting as
579// proxies for this texture, so that we do not attempt to use a pointer
580// to a renderbuffer proxy which has been deleted.
581void Texture2D::addProxyRef(const Renderbuffer *proxy)
582{
583 mProxyRefs++;
584}
585
586void Texture2D::releaseProxy(const Renderbuffer *proxy)
587{
588 if (mProxyRefs > 0)
589 mProxyRefs--;
590
591 if (mProxyRefs == 0)
592 mColorbufferProxy = NULL;
593}
594
595GLenum Texture2D::getTarget() const
596{
597 return GL_TEXTURE_2D;
598}
599
600GLsizei Texture2D::getWidth(GLint level) const
601{
602 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
603 return mImageArray[level].getWidth();
604 else
605 return 0;
606}
607
608GLsizei Texture2D::getHeight(GLint level) const
609{
610 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
611 return mImageArray[level].getHeight();
612 else
613 return 0;
614}
615
616GLenum Texture2D::getInternalFormat(GLint level) const
617{
618 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000619 return mImageArray[level].getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000620 else
621 return GL_NONE;
622}
623
daniel@transgaming.com20d36662012-10-31 19:51:43 +0000624GLenum Texture2D::getActualFormat(GLint level) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000625{
626 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.com20d36662012-10-31 19:51:43 +0000627 return mImageArray[level].getActualFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000628 else
629 return D3DFMT_UNKNOWN;
630}
631
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000632void Texture2D::redefineImage(GLint level, GLint internalformat, GLsizei width, GLsizei height)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000633{
634 releaseTexImage();
635
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000636 bool redefined = mImageArray[level].redefine(internalformat, width, height, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000637
638 if (mTexStorage && redefined)
639 {
640 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
641 {
642 mImageArray[i].markDirty();
643 }
644
645 delete mTexStorage;
646 mTexStorage = NULL;
647 mDirtyImages = true;
648 }
649}
650
651void Texture2D::setImage(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
652{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000653 GLint internalformat = ConvertSizedInternalFormat(format, type);
654 redefineImage(level, internalformat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000655
656 Texture::setImage(unpackAlignment, pixels, &mImageArray[level]);
657}
658
659void Texture2D::bindTexImage(egl::Surface *surface)
660{
661 releaseTexImage();
662
daniel@transgaming.com106e1f72012-10-31 18:38:36 +0000663 GLint internalformat = surface->getFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000664
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000665 mImageArray[0].redefine(internalformat, surface->getWidth(), surface->getHeight(), true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000666
667 delete mTexStorage;
daniel@transgaming.com3c720782012-10-31 18:42:34 +0000668 renderer::SwapChain *swapchain = surface->getSwapChain(); // D3D9_REPLACE
daniel@transgaming.com25ee7442012-10-31 19:51:56 +0000669 mTexStorage = new TextureStorage2D(swapchain);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000670
671 mDirtyImages = true;
672 mSurface = surface;
673 mSurface->setBoundTexture(this);
674}
675
676void Texture2D::releaseTexImage()
677{
678 if (mSurface)
679 {
680 mSurface->setBoundTexture(NULL);
681 mSurface = NULL;
682
683 if (mTexStorage)
684 {
685 delete mTexStorage;
686 mTexStorage = NULL;
687 }
688
689 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
690 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000691 mImageArray[i].redefine(GL_RGBA8_OES, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000692 }
693 }
694}
695
696void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
697{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000698 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
699 redefineImage(level, format, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000700
701 Texture::setCompressedImage(imageSize, pixels, &mImageArray[level]);
702}
703
704void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
705{
706 ASSERT(mImageArray[level].getSurface() != NULL);
707
708 if (level < levelCount())
709 {
daniel@transgaming.com0f195ad2012-10-31 19:51:59 +0000710 Image *image = &mImageArray[level];
711 if (image->updateSurface(mTexStorage, level, xoffset, yoffset, width, height))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000712 {
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000713 image->markClean();
714 }
715 }
716}
717
718void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
719{
720 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[level]))
721 {
722 commitRect(level, xoffset, yoffset, width, height);
723 }
724}
725
726void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
727{
728 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[level]))
729 {
730 commitRect(level, xoffset, yoffset, width, height);
731 }
732}
733
734void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
735{
736 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
737
738 if (!renderTarget)
739 {
740 ERR("Failed to retrieve the render target.");
741 return error(GL_OUT_OF_MEMORY);
742 }
743
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000744 GLint internalformat = ConvertSizedInternalFormat(format, GL_UNSIGNED_BYTE);
745 redefineImage(level, internalformat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000746
747 if (!mImageArray[level].isRenderableFormat())
748 {
749 mImageArray[level].copy(0, 0, x, y, width, height, renderTarget);
750 mDirtyImages = true;
751 }
752 else
753 {
754 if (!mTexStorage || !mTexStorage->isRenderTarget())
755 {
756 convertToRenderTarget();
757 }
758
759 mImageArray[level].markClean();
760
761 if (width != 0 && height != 0 && level < levelCount())
762 {
763 RECT sourceRect;
764 sourceRect.left = x;
765 sourceRect.right = x + width;
766 sourceRect.top = y;
767 sourceRect.bottom = y + height;
768
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +0000769 IDirect3DSurface9 *dest = mTexStorage->getSurfaceLevel(level, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000770
771 if (dest)
772 {
773 getBlitter()->copy(renderTarget, sourceRect, format, 0, 0, dest);
774 dest->Release();
775 }
776 }
777 }
778
779 renderTarget->Release();
780}
781
782void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
783{
784 if (xoffset + width > mImageArray[level].getWidth() || yoffset + height > mImageArray[level].getHeight())
785 {
786 return error(GL_INVALID_VALUE);
787 }
788
789 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
790
791 if (!renderTarget)
792 {
793 ERR("Failed to retrieve the render target.");
794 return error(GL_OUT_OF_MEMORY);
795 }
796
797 if (!mImageArray[level].isRenderableFormat() || (!mTexStorage && !isSamplerComplete()))
798 {
799 mImageArray[level].copy(xoffset, yoffset, x, y, width, height, renderTarget);
800 mDirtyImages = true;
801 }
802 else
803 {
804 if (!mTexStorage || !mTexStorage->isRenderTarget())
805 {
806 convertToRenderTarget();
807 }
808
809 updateTexture();
810
811 if (level < levelCount())
812 {
813 RECT sourceRect;
814 sourceRect.left = x;
815 sourceRect.right = x + width;
816 sourceRect.top = y;
817 sourceRect.bottom = y + height;
818
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +0000819 IDirect3DSurface9 *dest = mTexStorage->getSurfaceLevel(level, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000820
821 if (dest)
822 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000823 getBlitter()->copy(renderTarget, sourceRect,
824 gl::ExtractFormat(mImageArray[0].getInternalFormat()),
825 xoffset, yoffset, dest);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000826 dest->Release();
827 }
828 }
829 }
830
831 renderTarget->Release();
832}
833
834void Texture2D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height)
835{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000836 delete mTexStorage;
daniel@transgaming.comf032cb82012-10-31 19:51:52 +0000837 mTexStorage = new TextureStorage2D(levels, internalformat, mUsage, false, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000838 mImmutable = true;
839
840 for (int level = 0; level < levels; level++)
841 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000842 mImageArray[level].redefine(internalformat, width, height, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000843 width = std::max(1, width >> 1);
844 height = std::max(1, height >> 1);
845 }
846
847 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
848 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000849 mImageArray[level].redefine(GL_NONE, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000850 }
851
852 if (mTexStorage->isManaged())
853 {
854 int levels = levelCount();
855
856 for (int level = 0; level < levels; level++)
857 {
daniel@transgaming.com0f195ad2012-10-31 19:51:59 +0000858 mImageArray[level].setManagedSurface(mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000859 }
860 }
861}
862
863// Tests for 2D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85.
864bool Texture2D::isSamplerComplete() const
865{
866 GLsizei width = mImageArray[0].getWidth();
867 GLsizei height = mImageArray[0].getHeight();
868
869 if (width <= 0 || height <= 0)
870 {
871 return false;
872 }
873
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +0000874 bool mipmapping = isMipmapFiltered();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000875
daniel@transgaming.com6b1a0a02012-10-17 18:22:47 +0000876 if ((IsFloat32Format(getInternalFormat(0)) && !getContext()->supportsFloat32LinearFilter()) ||
877 (IsFloat16Format(getInternalFormat(0)) && !getContext()->supportsFloat16LinearFilter()))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000878 {
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000879 if (mSamplerState.magFilter != GL_NEAREST ||
880 (mSamplerState.minFilter != GL_NEAREST && mSamplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000881 {
882 return false;
883 }
884 }
885
886 bool npotSupport = getContext()->supportsNonPower2Texture();
887
888 if (!npotSupport)
889 {
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000890 if ((mSamplerState.wrapS != GL_CLAMP_TO_EDGE && !isPow2(width)) ||
891 (mSamplerState.wrapT != GL_CLAMP_TO_EDGE && !isPow2(height)))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000892 {
893 return false;
894 }
895 }
896
897 if (mipmapping)
898 {
899 if (!npotSupport)
900 {
901 if (!isPow2(width) || !isPow2(height))
902 {
903 return false;
904 }
905 }
906
907 if (!isMipmapComplete())
908 {
909 return false;
910 }
911 }
912
913 return true;
914}
915
916// Tests for 2D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
917bool Texture2D::isMipmapComplete() const
918{
919 if (isImmutable())
920 {
921 return true;
922 }
923
924 GLsizei width = mImageArray[0].getWidth();
925 GLsizei height = mImageArray[0].getHeight();
926
927 if (width <= 0 || height <= 0)
928 {
929 return false;
930 }
931
932 int q = log2(std::max(width, height));
933
934 for (int level = 1; level <= q; level++)
935 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000936 if (mImageArray[level].getInternalFormat() != mImageArray[0].getInternalFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000937 {
938 return false;
939 }
940
941 if (mImageArray[level].getWidth() != std::max(1, width >> level))
942 {
943 return false;
944 }
945
946 if (mImageArray[level].getHeight() != std::max(1, height >> level))
947 {
948 return false;
949 }
950 }
951
952 return true;
953}
954
955bool Texture2D::isCompressed(GLint level) const
956{
957 return IsCompressed(getInternalFormat(level));
958}
959
960bool Texture2D::isDepth(GLint level) const
961{
962 return IsDepthTexture(getInternalFormat(level));
963}
964
965IDirect3DBaseTexture9 *Texture2D::getBaseTexture() const
966{
967 return mTexStorage ? mTexStorage->getBaseTexture() : NULL;
968}
969
daniel@transgaming.comf032cb82012-10-31 19:51:52 +0000970// Constructs a native texture resource from the texture images
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000971void Texture2D::createTexture()
972{
973 GLsizei width = mImageArray[0].getWidth();
974 GLsizei height = mImageArray[0].getHeight();
daniel@transgaming.come6a09842012-09-17 21:28:55 +0000975
976 if (!(width > 0 && height > 0))
daniel@transgaming.comf032cb82012-10-31 19:51:52 +0000977 return; // do not attempt to create native textures for nonexistant data
daniel@transgaming.come6a09842012-09-17 21:28:55 +0000978
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000979 GLint levels = creationLevels(width, height);
daniel@transgaming.comf032cb82012-10-31 19:51:52 +0000980 GLenum internalformat = mImageArray[0].getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000981
982 delete mTexStorage;
daniel@transgaming.comf032cb82012-10-31 19:51:52 +0000983 mTexStorage = new TextureStorage2D(levels, internalformat, mUsage, false, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000984
985 if (mTexStorage->isManaged())
986 {
987 int levels = levelCount();
988
989 for (int level = 0; level < levels; level++)
990 {
daniel@transgaming.com0f195ad2012-10-31 19:51:59 +0000991 mImageArray[level].setManagedSurface(mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000992 }
993 }
994
995 mDirtyImages = true;
996}
997
998void Texture2D::updateTexture()
999{
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +00001000 bool mipmapping = (isMipmapFiltered() && isMipmapComplete());
1001
1002 int levels = (mipmapping ? levelCount() : 1);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001003
1004 for (int level = 0; level < levels; level++)
1005 {
1006 Image *image = &mImageArray[level];
1007
1008 if (image->isDirty())
1009 {
1010 commitRect(level, 0, 0, mImageArray[level].getWidth(), mImageArray[level].getHeight());
1011 }
1012 }
1013}
1014
1015void Texture2D::convertToRenderTarget()
1016{
1017 TextureStorage2D *newTexStorage = NULL;
1018
1019 if (mImageArray[0].getWidth() != 0 && mImageArray[0].getHeight() != 0)
1020 {
1021 GLsizei width = mImageArray[0].getWidth();
1022 GLsizei height = mImageArray[0].getHeight();
1023 GLint levels = creationLevels(width, height);
daniel@transgaming.comf032cb82012-10-31 19:51:52 +00001024 GLenum internalformat = mImageArray[0].getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001025
daniel@transgaming.comf032cb82012-10-31 19:51:52 +00001026 newTexStorage = new TextureStorage2D(levels, internalformat, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, true, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001027
1028 if (mTexStorage != NULL)
1029 {
1030 int levels = levelCount();
1031 for (int i = 0; i < levels; i++)
1032 {
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00001033 IDirect3DSurface9 *source = mTexStorage->getSurfaceLevel(i, false);
1034 IDirect3DSurface9 *dest = newTexStorage->getSurfaceLevel(i, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001035
1036 if (!copyToRenderTarget(dest, source, mTexStorage->isManaged()))
1037 {
1038 delete newTexStorage;
1039 if (source) source->Release();
1040 if (dest) dest->Release();
1041 return error(GL_OUT_OF_MEMORY);
1042 }
1043
1044 if (source) source->Release();
1045 if (dest) dest->Release();
1046 }
1047 }
1048 }
1049
1050 delete mTexStorage;
1051 mTexStorage = newTexStorage;
1052
1053 mDirtyImages = true;
1054}
1055
1056void Texture2D::generateMipmaps()
1057{
1058 if (!getContext()->supportsNonPower2Texture())
1059 {
1060 if (!isPow2(mImageArray[0].getWidth()) || !isPow2(mImageArray[0].getHeight()))
1061 {
1062 return error(GL_INVALID_OPERATION);
1063 }
1064 }
1065
1066 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1067 unsigned int q = log2(std::max(mImageArray[0].getWidth(), mImageArray[0].getHeight()));
1068 for (unsigned int i = 1; i <= q; i++)
1069 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001070 redefineImage(i, mImageArray[0].getInternalFormat(),
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001071 std::max(mImageArray[0].getWidth() >> i, 1),
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001072 std::max(mImageArray[0].getHeight() >> i, 1));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001073 }
1074
1075 if (mTexStorage && mTexStorage->isRenderTarget())
1076 {
1077 for (unsigned int i = 1; i <= q; i++)
1078 {
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00001079 IDirect3DSurface9 *upper = mTexStorage->getSurfaceLevel(i - 1, false);
1080 IDirect3DSurface9 *lower = mTexStorage->getSurfaceLevel(i, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001081
1082 if (upper != NULL && lower != NULL)
1083 {
1084 getBlitter()->boxFilter(upper, lower);
1085 }
1086
1087 if (upper != NULL) upper->Release();
1088 if (lower != NULL) lower->Release();
1089
1090 mImageArray[i].markClean();
1091 }
1092 }
1093 else
1094 {
1095 for (unsigned int i = 1; i <= q; i++)
1096 {
1097 if (mImageArray[i].getSurface() == NULL)
1098 {
1099 return error(GL_OUT_OF_MEMORY);
1100 }
1101
daniel@transgaming.com2e38b802012-10-17 18:30:06 +00001102 GenerateMip(mImageArray[i].getSurface(), mImageArray[i - 1].getSurface());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001103
1104 mImageArray[i].markDirty();
1105 }
1106 }
1107}
1108
1109Renderbuffer *Texture2D::getRenderbuffer(GLenum target)
1110{
1111 if (target != GL_TEXTURE_2D)
1112 {
1113 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
1114 }
1115
1116 if (mColorbufferProxy == NULL)
1117 {
1118 mColorbufferProxy = new Renderbuffer(id(), new RenderbufferTexture2D(this, target));
1119 }
1120
1121 return mColorbufferProxy;
1122}
1123
1124// Increments refcount on surface.
1125// caller must Release() the returned surface
1126IDirect3DSurface9 *Texture2D::getRenderTarget(GLenum target)
1127{
1128 ASSERT(target == GL_TEXTURE_2D);
1129
1130 // ensure the underlying texture is created
1131 if (getStorage(true) == NULL)
1132 {
1133 return NULL;
1134 }
1135
1136 updateTexture();
1137
1138 // ensure this is NOT a depth texture
1139 if (isDepth(0))
1140 {
1141 return NULL;
1142 }
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00001143 return mTexStorage->getSurfaceLevel(0, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001144}
1145
1146// Increments refcount on surface.
1147// caller must Release() the returned surface
1148IDirect3DSurface9 *Texture2D::getDepthStencil(GLenum target)
1149{
1150 ASSERT(target == GL_TEXTURE_2D);
1151
1152 // ensure the underlying texture is created
1153 if (getStorage(true) == NULL)
1154 {
1155 return NULL;
1156 }
1157
1158 updateTexture();
1159
1160 // ensure this is actually a depth texture
1161 if (!isDepth(0))
1162 {
1163 return NULL;
1164 }
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00001165 return mTexStorage->getSurfaceLevel(0, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001166}
1167
1168TextureStorage *Texture2D::getStorage(bool renderTarget)
1169{
1170 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
1171 {
1172 if (renderTarget)
1173 {
1174 convertToRenderTarget();
1175 }
1176 else
1177 {
1178 createTexture();
1179 }
1180 }
1181
1182 return mTexStorage;
1183}
1184
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001185TextureCubeMap::TextureCubeMap(GLuint id) : Texture(id)
1186{
1187 mTexStorage = NULL;
1188 for (int i = 0; i < 6; i++)
1189 {
1190 mFaceProxies[i] = NULL;
1191 mFaceProxyRefs[i] = 0;
1192 }
1193}
1194
1195TextureCubeMap::~TextureCubeMap()
1196{
1197 for (int i = 0; i < 6; i++)
1198 {
1199 mFaceProxies[i] = NULL;
1200 }
1201
1202 delete mTexStorage;
1203 mTexStorage = NULL;
1204}
1205
1206// We need to maintain a count of references to renderbuffers acting as
1207// proxies for this texture, so that the texture is not deleted while
1208// proxy references still exist. If the reference count drops to zero,
1209// we set our proxy pointer NULL, so that a new attempt at referencing
1210// will cause recreation.
1211void TextureCubeMap::addProxyRef(const Renderbuffer *proxy)
1212{
1213 for (int i = 0; i < 6; i++)
1214 {
1215 if (mFaceProxies[i] == proxy)
1216 mFaceProxyRefs[i]++;
1217 }
1218}
1219
1220void TextureCubeMap::releaseProxy(const Renderbuffer *proxy)
1221{
1222 for (int i = 0; i < 6; i++)
1223 {
1224 if (mFaceProxies[i] == proxy)
1225 {
1226 if (mFaceProxyRefs[i] > 0)
1227 mFaceProxyRefs[i]--;
1228
1229 if (mFaceProxyRefs[i] == 0)
1230 mFaceProxies[i] = NULL;
1231 }
1232 }
1233}
1234
1235GLenum TextureCubeMap::getTarget() const
1236{
1237 return GL_TEXTURE_CUBE_MAP;
1238}
1239
1240GLsizei TextureCubeMap::getWidth(GLenum target, GLint level) const
1241{
1242 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1243 return mImageArray[faceIndex(target)][level].getWidth();
1244 else
1245 return 0;
1246}
1247
1248GLsizei TextureCubeMap::getHeight(GLenum target, GLint level) const
1249{
1250 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1251 return mImageArray[faceIndex(target)][level].getHeight();
1252 else
1253 return 0;
1254}
1255
1256GLenum TextureCubeMap::getInternalFormat(GLenum target, GLint level) const
1257{
1258 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001259 return mImageArray[faceIndex(target)][level].getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001260 else
1261 return GL_NONE;
1262}
1263
daniel@transgaming.com20d36662012-10-31 19:51:43 +00001264GLenum TextureCubeMap::getActualFormat(GLenum target, GLint level) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001265{
1266 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.com20d36662012-10-31 19:51:43 +00001267 return mImageArray[faceIndex(target)][level].getActualFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001268 else
1269 return D3DFMT_UNKNOWN;
1270}
1271
1272void TextureCubeMap::setImagePosX(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1273{
1274 setImage(0, level, width, height, format, type, unpackAlignment, pixels);
1275}
1276
1277void TextureCubeMap::setImageNegX(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1278{
1279 setImage(1, level, width, height, format, type, unpackAlignment, pixels);
1280}
1281
1282void TextureCubeMap::setImagePosY(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1283{
1284 setImage(2, level, width, height, format, type, unpackAlignment, pixels);
1285}
1286
1287void TextureCubeMap::setImageNegY(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1288{
1289 setImage(3, level, width, height, format, type, unpackAlignment, pixels);
1290}
1291
1292void TextureCubeMap::setImagePosZ(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1293{
1294 setImage(4, level, width, height, format, type, unpackAlignment, pixels);
1295}
1296
1297void TextureCubeMap::setImageNegZ(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1298{
1299 setImage(5, level, width, height, format, type, unpackAlignment, pixels);
1300}
1301
1302void TextureCubeMap::setCompressedImage(GLenum face, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
1303{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001304 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1305 redefineImage(faceIndex(face), level, format, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001306
1307 Texture::setCompressedImage(imageSize, pixels, &mImageArray[faceIndex(face)][level]);
1308}
1309
1310void TextureCubeMap::commitRect(int face, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1311{
1312 ASSERT(mImageArray[face][level].getSurface() != NULL);
1313
1314 if (level < levelCount())
1315 {
daniel@transgaming.com0f195ad2012-10-31 19:51:59 +00001316 Image *image = &mImageArray[face][level];
1317 if (image->updateSurface(mTexStorage, face, level, xoffset, yoffset, width, height))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001318 image->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001319 }
1320}
1321
1322void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1323{
1324 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[faceIndex(target)][level]))
1325 {
1326 commitRect(faceIndex(target), level, xoffset, yoffset, width, height);
1327 }
1328}
1329
1330void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1331{
1332 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[faceIndex(target)][level]))
1333 {
1334 commitRect(faceIndex(target), level, xoffset, yoffset, width, height);
1335 }
1336}
1337
1338// Tests for cube map sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 86.
1339bool TextureCubeMap::isSamplerComplete() const
1340{
1341 int size = mImageArray[0][0].getWidth();
1342
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +00001343 bool mipmapping = isMipmapFiltered();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001344
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001345 if ((gl::ExtractType(getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0)) == GL_FLOAT && !getContext()->supportsFloat32LinearFilter()) ||
1346 (gl::ExtractType(getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0) == GL_HALF_FLOAT_OES) && !getContext()->supportsFloat16LinearFilter()))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001347 {
daniel@transgaming.comebf139f2012-10-31 18:07:32 +00001348 if (mSamplerState.magFilter != GL_NEAREST ||
1349 (mSamplerState.minFilter != GL_NEAREST && mSamplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001350 {
1351 return false;
1352 }
1353 }
1354
1355 if (!isPow2(size) && !getContext()->supportsNonPower2Texture())
1356 {
daniel@transgaming.comebf139f2012-10-31 18:07:32 +00001357 if (mSamplerState.wrapS != GL_CLAMP_TO_EDGE || mSamplerState.wrapT != GL_CLAMP_TO_EDGE || mipmapping)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001358 {
1359 return false;
1360 }
1361 }
1362
1363 if (!mipmapping)
1364 {
1365 if (!isCubeComplete())
1366 {
1367 return false;
1368 }
1369 }
1370 else
1371 {
1372 if (!isMipmapCubeComplete()) // Also tests for isCubeComplete()
1373 {
1374 return false;
1375 }
1376 }
1377
1378 return true;
1379}
1380
1381// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1382bool TextureCubeMap::isCubeComplete() const
1383{
1384 if (mImageArray[0][0].getWidth() <= 0 || mImageArray[0][0].getHeight() != mImageArray[0][0].getWidth())
1385 {
1386 return false;
1387 }
1388
1389 for (unsigned int face = 1; face < 6; face++)
1390 {
1391 if (mImageArray[face][0].getWidth() != mImageArray[0][0].getWidth() ||
1392 mImageArray[face][0].getWidth() != mImageArray[0][0].getHeight() ||
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001393 mImageArray[face][0].getInternalFormat() != mImageArray[0][0].getInternalFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001394 {
1395 return false;
1396 }
1397 }
1398
1399 return true;
1400}
1401
1402bool TextureCubeMap::isMipmapCubeComplete() const
1403{
1404 if (isImmutable())
1405 {
1406 return true;
1407 }
1408
1409 if (!isCubeComplete())
1410 {
1411 return false;
1412 }
1413
1414 GLsizei size = mImageArray[0][0].getWidth();
1415
1416 int q = log2(size);
1417
1418 for (int face = 0; face < 6; face++)
1419 {
1420 for (int level = 1; level <= q; level++)
1421 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001422 if (mImageArray[face][level].getInternalFormat() != mImageArray[0][0].getInternalFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001423 {
1424 return false;
1425 }
1426
1427 if (mImageArray[face][level].getWidth() != std::max(1, size >> level))
1428 {
1429 return false;
1430 }
1431 }
1432 }
1433
1434 return true;
1435}
1436
1437bool TextureCubeMap::isCompressed(GLenum target, GLint level) const
1438{
1439 return IsCompressed(getInternalFormat(target, level));
1440}
1441
1442IDirect3DBaseTexture9 *TextureCubeMap::getBaseTexture() const
1443{
1444 return mTexStorage ? mTexStorage->getBaseTexture() : NULL;
1445}
1446
daniel@transgaming.comf032cb82012-10-31 19:51:52 +00001447// Constructs a native texture resource from the texture images, or returns an existing one
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001448void TextureCubeMap::createTexture()
1449{
1450 GLsizei size = mImageArray[0][0].getWidth();
daniel@transgaming.come6a09842012-09-17 21:28:55 +00001451
1452 if (!(size > 0))
daniel@transgaming.comf032cb82012-10-31 19:51:52 +00001453 return; // do not attempt to create native textures for nonexistant data
daniel@transgaming.come6a09842012-09-17 21:28:55 +00001454
sminns@adobe.comce1189b2012-09-18 20:06:35 +00001455 GLint levels = creationLevels(size);
daniel@transgaming.comf032cb82012-10-31 19:51:52 +00001456 GLenum internalformat = mImageArray[0][0].getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001457
1458 delete mTexStorage;
daniel@transgaming.comf032cb82012-10-31 19:51:52 +00001459 mTexStorage = new TextureStorageCubeMap(levels, internalformat, mUsage, false, size);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001460
1461 if (mTexStorage->isManaged())
1462 {
1463 int levels = levelCount();
1464
1465 for (int face = 0; face < 6; face++)
1466 {
1467 for (int level = 0; level < levels; level++)
1468 {
daniel@transgaming.com0f195ad2012-10-31 19:51:59 +00001469 mImageArray[face][level].setManagedSurface(mTexStorage, face, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001470 }
1471 }
1472 }
1473
1474 mDirtyImages = true;
1475}
1476
1477void TextureCubeMap::updateTexture()
1478{
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +00001479 bool mipmapping = isMipmapFiltered() && isMipmapCubeComplete();
1480
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001481 for (int face = 0; face < 6; face++)
1482 {
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +00001483 int levels = (mipmapping ? levelCount() : 1);
1484
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001485 for (int level = 0; level < levels; level++)
1486 {
1487 Image *image = &mImageArray[face][level];
1488
1489 if (image->isDirty())
1490 {
1491 commitRect(face, level, 0, 0, image->getWidth(), image->getHeight());
1492 }
1493 }
1494 }
1495}
1496
1497void TextureCubeMap::convertToRenderTarget()
1498{
1499 TextureStorageCubeMap *newTexStorage = NULL;
1500
1501 if (mImageArray[0][0].getWidth() != 0)
1502 {
1503 GLsizei size = mImageArray[0][0].getWidth();
sminns@adobe.comce1189b2012-09-18 20:06:35 +00001504 GLint levels = creationLevels(size);
daniel@transgaming.comf032cb82012-10-31 19:51:52 +00001505 GLenum internalformat = mImageArray[0][0].getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001506
daniel@transgaming.comf032cb82012-10-31 19:51:52 +00001507 newTexStorage = new TextureStorageCubeMap(levels, internalformat, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, true, size);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001508
1509 if (mTexStorage != NULL)
1510 {
1511 int levels = levelCount();
1512 for (int f = 0; f < 6; f++)
1513 {
1514 for (int i = 0; i < levels; i++)
1515 {
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00001516 IDirect3DSurface9 *source = mTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i, false);
1517 IDirect3DSurface9 *dest = newTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001518
1519 if (!copyToRenderTarget(dest, source, mTexStorage->isManaged()))
1520 {
1521 delete newTexStorage;
1522 if (source) source->Release();
1523 if (dest) dest->Release();
1524 return error(GL_OUT_OF_MEMORY);
1525 }
1526
1527 if (source) source->Release();
1528 if (dest) dest->Release();
1529 }
1530 }
1531 }
1532 }
1533
1534 delete mTexStorage;
1535 mTexStorage = newTexStorage;
1536
1537 mDirtyImages = true;
1538}
1539
1540void TextureCubeMap::setImage(int faceIndex, GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1541{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001542 GLint internalformat = ConvertSizedInternalFormat(format, type);
1543 redefineImage(faceIndex, level, internalformat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001544
1545 Texture::setImage(unpackAlignment, pixels, &mImageArray[faceIndex][level]);
1546}
1547
1548unsigned int TextureCubeMap::faceIndex(GLenum face)
1549{
1550 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
1551 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
1552 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
1553 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
1554 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
1555
1556 return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
1557}
1558
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001559void TextureCubeMap::redefineImage(int face, GLint level, GLint internalformat, GLsizei width, GLsizei height)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001560{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001561 bool redefined = mImageArray[face][level].redefine(internalformat, width, height, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001562
1563 if (mTexStorage && redefined)
1564 {
1565 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1566 {
1567 for (int f = 0; f < 6; f++)
1568 {
1569 mImageArray[f][i].markDirty();
1570 }
1571 }
1572
1573 delete mTexStorage;
1574 mTexStorage = NULL;
1575
1576 mDirtyImages = true;
1577 }
1578}
1579
1580void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1581{
1582 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
1583
1584 if (!renderTarget)
1585 {
1586 ERR("Failed to retrieve the render target.");
1587 return error(GL_OUT_OF_MEMORY);
1588 }
1589
1590 unsigned int faceindex = faceIndex(target);
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001591 GLint internalformat = gl::ConvertSizedInternalFormat(format, GL_UNSIGNED_BYTE);
1592 redefineImage(faceindex, level, internalformat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001593
1594 if (!mImageArray[faceindex][level].isRenderableFormat())
1595 {
1596 mImageArray[faceindex][level].copy(0, 0, x, y, width, height, renderTarget);
1597 mDirtyImages = true;
1598 }
1599 else
1600 {
1601 if (!mTexStorage || !mTexStorage->isRenderTarget())
1602 {
1603 convertToRenderTarget();
1604 }
1605
1606 mImageArray[faceindex][level].markClean();
1607
1608 ASSERT(width == height);
1609
1610 if (width > 0 && level < levelCount())
1611 {
1612 RECT sourceRect;
1613 sourceRect.left = x;
1614 sourceRect.right = x + width;
1615 sourceRect.top = y;
1616 sourceRect.bottom = y + height;
1617
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00001618 IDirect3DSurface9 *dest = mTexStorage->getCubeMapSurface(target, level, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001619
1620 if (dest)
1621 {
1622 getBlitter()->copy(renderTarget, sourceRect, format, 0, 0, dest);
1623 dest->Release();
1624 }
1625 }
1626 }
1627
1628 renderTarget->Release();
1629}
1630
1631void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1632{
1633 GLsizei size = mImageArray[faceIndex(target)][level].getWidth();
1634
1635 if (xoffset + width > size || yoffset + height > size)
1636 {
1637 return error(GL_INVALID_VALUE);
1638 }
1639
1640 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
1641
1642 if (!renderTarget)
1643 {
1644 ERR("Failed to retrieve the render target.");
1645 return error(GL_OUT_OF_MEMORY);
1646 }
1647
1648 unsigned int faceindex = faceIndex(target);
1649
1650 if (!mImageArray[faceindex][level].isRenderableFormat() || (!mTexStorage && !isSamplerComplete()))
1651 {
1652 mImageArray[faceindex][level].copy(0, 0, x, y, width, height, renderTarget);
1653 mDirtyImages = true;
1654 }
1655 else
1656 {
1657 if (!mTexStorage || !mTexStorage->isRenderTarget())
1658 {
1659 convertToRenderTarget();
1660 }
1661
1662 updateTexture();
1663
1664 if (level < levelCount())
1665 {
1666 RECT sourceRect;
1667 sourceRect.left = x;
1668 sourceRect.right = x + width;
1669 sourceRect.top = y;
1670 sourceRect.bottom = y + height;
1671
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00001672 IDirect3DSurface9 *dest = mTexStorage->getCubeMapSurface(target, level, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001673
1674 if (dest)
1675 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001676 getBlitter()->copy(renderTarget, sourceRect, gl::ExtractFormat(mImageArray[0][0].getInternalFormat()), xoffset, yoffset, dest);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001677 dest->Release();
1678 }
1679 }
1680 }
1681
1682 renderTarget->Release();
1683}
1684
1685void TextureCubeMap::storage(GLsizei levels, GLenum internalformat, GLsizei size)
1686{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001687 delete mTexStorage;
daniel@transgaming.comf032cb82012-10-31 19:51:52 +00001688 mTexStorage = new TextureStorageCubeMap(levels, internalformat, mUsage, false, size);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001689 mImmutable = true;
1690
1691 for (int level = 0; level < levels; level++)
1692 {
1693 for (int face = 0; face < 6; face++)
1694 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001695 mImageArray[face][level].redefine(internalformat, size, size, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001696 size = std::max(1, size >> 1);
1697 }
1698 }
1699
1700 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1701 {
1702 for (int face = 0; face < 6; face++)
1703 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001704 mImageArray[face][level].redefine(GL_NONE, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001705 }
1706 }
1707
1708 if (mTexStorage->isManaged())
1709 {
1710 int levels = levelCount();
1711
1712 for (int face = 0; face < 6; face++)
1713 {
1714 for (int level = 0; level < levels; level++)
1715 {
daniel@transgaming.com0f195ad2012-10-31 19:51:59 +00001716 mImageArray[face][level].setManagedSurface(mTexStorage, face, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001717 }
1718 }
1719 }
1720}
1721
1722void TextureCubeMap::generateMipmaps()
1723{
1724 if (!isCubeComplete())
1725 {
1726 return error(GL_INVALID_OPERATION);
1727 }
1728
1729 if (!getContext()->supportsNonPower2Texture())
1730 {
1731 if (!isPow2(mImageArray[0][0].getWidth()))
1732 {
1733 return error(GL_INVALID_OPERATION);
1734 }
1735 }
1736
1737 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1738 unsigned int q = log2(mImageArray[0][0].getWidth());
1739 for (unsigned int f = 0; f < 6; f++)
1740 {
1741 for (unsigned int i = 1; i <= q; i++)
1742 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001743 redefineImage(f, i, mImageArray[f][0].getInternalFormat(),
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001744 std::max(mImageArray[f][0].getWidth() >> i, 1),
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001745 std::max(mImageArray[f][0].getWidth() >> i, 1));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001746 }
1747 }
1748
1749 if (mTexStorage && mTexStorage->isRenderTarget())
1750 {
1751 for (unsigned int f = 0; f < 6; f++)
1752 {
1753 for (unsigned int i = 1; i <= q; i++)
1754 {
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00001755 IDirect3DSurface9 *upper = mTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i - 1, false);
1756 IDirect3DSurface9 *lower = mTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001757
1758 if (upper != NULL && lower != NULL)
1759 {
1760 getBlitter()->boxFilter(upper, lower);
1761 }
1762
1763 if (upper != NULL) upper->Release();
1764 if (lower != NULL) lower->Release();
1765
1766 mImageArray[f][i].markClean();
1767 }
1768 }
1769 }
1770 else
1771 {
1772 for (unsigned int f = 0; f < 6; f++)
1773 {
1774 for (unsigned int i = 1; i <= q; i++)
1775 {
1776 if (mImageArray[f][i].getSurface() == NULL)
1777 {
1778 return error(GL_OUT_OF_MEMORY);
1779 }
1780
daniel@transgaming.com2e38b802012-10-17 18:30:06 +00001781 GenerateMip(mImageArray[f][i].getSurface(), mImageArray[f][i - 1].getSurface());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001782
1783 mImageArray[f][i].markDirty();
1784 }
1785 }
1786 }
1787}
1788
1789Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target)
1790{
1791 if (!IsCubemapTextureTarget(target))
1792 {
1793 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
1794 }
1795
1796 unsigned int face = faceIndex(target);
1797
1798 if (mFaceProxies[face] == NULL)
1799 {
1800 mFaceProxies[face] = new Renderbuffer(id(), new RenderbufferTextureCubeMap(this, target));
1801 }
1802
1803 return mFaceProxies[face];
1804}
1805
1806// Increments refcount on surface.
1807// caller must Release() the returned surface
1808IDirect3DSurface9 *TextureCubeMap::getRenderTarget(GLenum target)
1809{
1810 ASSERT(IsCubemapTextureTarget(target));
1811
1812 // ensure the underlying texture is created
1813 if (getStorage(true) == NULL)
1814 {
1815 return NULL;
1816 }
1817
1818 updateTexture();
1819
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00001820 return mTexStorage->getCubeMapSurface(target, 0, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001821}
1822
1823TextureStorage *TextureCubeMap::getStorage(bool renderTarget)
1824{
1825 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
1826 {
1827 if (renderTarget)
1828 {
1829 convertToRenderTarget();
1830 }
1831 else
1832 {
1833 createTexture();
1834 }
1835 }
1836
1837 return mTexStorage;
1838}
1839
1840}