blob: e079cb2d4fa5b725cb2d3773b97928d3b859dbb8 [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
669 mTexStorage = new TextureStorage2D(swapchain->getOffscreenTexture());
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.com2b5af7b2012-09-27 17:46:15 +0000710 IDirect3DSurface9 *destLevel = mTexStorage->getSurfaceLevel(level, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000711
712 if (destLevel)
713 {
714 Image *image = &mImageArray[level];
715 image->updateSurface(destLevel, xoffset, yoffset, width, height);
716
717 destLevel->Release();
718 image->markClean();
719 }
720 }
721}
722
723void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
724{
725 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[level]))
726 {
727 commitRect(level, xoffset, yoffset, width, height);
728 }
729}
730
731void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
732{
733 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[level]))
734 {
735 commitRect(level, xoffset, yoffset, width, height);
736 }
737}
738
739void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
740{
741 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
742
743 if (!renderTarget)
744 {
745 ERR("Failed to retrieve the render target.");
746 return error(GL_OUT_OF_MEMORY);
747 }
748
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000749 GLint internalformat = ConvertSizedInternalFormat(format, GL_UNSIGNED_BYTE);
750 redefineImage(level, internalformat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000751
752 if (!mImageArray[level].isRenderableFormat())
753 {
754 mImageArray[level].copy(0, 0, x, y, width, height, renderTarget);
755 mDirtyImages = true;
756 }
757 else
758 {
759 if (!mTexStorage || !mTexStorage->isRenderTarget())
760 {
761 convertToRenderTarget();
762 }
763
764 mImageArray[level].markClean();
765
766 if (width != 0 && height != 0 && 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 {
778 getBlitter()->copy(renderTarget, sourceRect, format, 0, 0, dest);
779 dest->Release();
780 }
781 }
782 }
783
784 renderTarget->Release();
785}
786
787void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
788{
789 if (xoffset + width > mImageArray[level].getWidth() || yoffset + height > mImageArray[level].getHeight())
790 {
791 return error(GL_INVALID_VALUE);
792 }
793
794 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
795
796 if (!renderTarget)
797 {
798 ERR("Failed to retrieve the render target.");
799 return error(GL_OUT_OF_MEMORY);
800 }
801
802 if (!mImageArray[level].isRenderableFormat() || (!mTexStorage && !isSamplerComplete()))
803 {
804 mImageArray[level].copy(xoffset, yoffset, x, y, width, height, renderTarget);
805 mDirtyImages = true;
806 }
807 else
808 {
809 if (!mTexStorage || !mTexStorage->isRenderTarget())
810 {
811 convertToRenderTarget();
812 }
813
814 updateTexture();
815
816 if (level < levelCount())
817 {
818 RECT sourceRect;
819 sourceRect.left = x;
820 sourceRect.right = x + width;
821 sourceRect.top = y;
822 sourceRect.bottom = y + height;
823
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +0000824 IDirect3DSurface9 *dest = mTexStorage->getSurfaceLevel(level, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000825
826 if (dest)
827 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000828 getBlitter()->copy(renderTarget, sourceRect,
829 gl::ExtractFormat(mImageArray[0].getInternalFormat()),
830 xoffset, yoffset, dest);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000831 dest->Release();
832 }
833 }
834 }
835
836 renderTarget->Release();
837}
838
839void Texture2D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height)
840{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000841 delete mTexStorage;
daniel@transgaming.comf032cb82012-10-31 19:51:52 +0000842 mTexStorage = new TextureStorage2D(levels, internalformat, mUsage, false, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000843 mImmutable = true;
844
845 for (int level = 0; level < levels; level++)
846 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000847 mImageArray[level].redefine(internalformat, width, height, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000848 width = std::max(1, width >> 1);
849 height = std::max(1, height >> 1);
850 }
851
852 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
853 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000854 mImageArray[level].redefine(GL_NONE, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000855 }
856
857 if (mTexStorage->isManaged())
858 {
859 int levels = levelCount();
860
861 for (int level = 0; level < levels; level++)
862 {
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +0000863 IDirect3DSurface9 *surface = mTexStorage->getSurfaceLevel(level, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000864 mImageArray[level].setManagedSurface(surface);
865 }
866 }
867}
868
869// Tests for 2D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85.
870bool Texture2D::isSamplerComplete() const
871{
872 GLsizei width = mImageArray[0].getWidth();
873 GLsizei height = mImageArray[0].getHeight();
874
875 if (width <= 0 || height <= 0)
876 {
877 return false;
878 }
879
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +0000880 bool mipmapping = isMipmapFiltered();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000881
daniel@transgaming.com6b1a0a02012-10-17 18:22:47 +0000882 if ((IsFloat32Format(getInternalFormat(0)) && !getContext()->supportsFloat32LinearFilter()) ||
883 (IsFloat16Format(getInternalFormat(0)) && !getContext()->supportsFloat16LinearFilter()))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000884 {
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000885 if (mSamplerState.magFilter != GL_NEAREST ||
886 (mSamplerState.minFilter != GL_NEAREST && mSamplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000887 {
888 return false;
889 }
890 }
891
892 bool npotSupport = getContext()->supportsNonPower2Texture();
893
894 if (!npotSupport)
895 {
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000896 if ((mSamplerState.wrapS != GL_CLAMP_TO_EDGE && !isPow2(width)) ||
897 (mSamplerState.wrapT != GL_CLAMP_TO_EDGE && !isPow2(height)))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000898 {
899 return false;
900 }
901 }
902
903 if (mipmapping)
904 {
905 if (!npotSupport)
906 {
907 if (!isPow2(width) || !isPow2(height))
908 {
909 return false;
910 }
911 }
912
913 if (!isMipmapComplete())
914 {
915 return false;
916 }
917 }
918
919 return true;
920}
921
922// Tests for 2D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
923bool Texture2D::isMipmapComplete() const
924{
925 if (isImmutable())
926 {
927 return true;
928 }
929
930 GLsizei width = mImageArray[0].getWidth();
931 GLsizei height = mImageArray[0].getHeight();
932
933 if (width <= 0 || height <= 0)
934 {
935 return false;
936 }
937
938 int q = log2(std::max(width, height));
939
940 for (int level = 1; level <= q; level++)
941 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000942 if (mImageArray[level].getInternalFormat() != mImageArray[0].getInternalFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000943 {
944 return false;
945 }
946
947 if (mImageArray[level].getWidth() != std::max(1, width >> level))
948 {
949 return false;
950 }
951
952 if (mImageArray[level].getHeight() != std::max(1, height >> level))
953 {
954 return false;
955 }
956 }
957
958 return true;
959}
960
961bool Texture2D::isCompressed(GLint level) const
962{
963 return IsCompressed(getInternalFormat(level));
964}
965
966bool Texture2D::isDepth(GLint level) const
967{
968 return IsDepthTexture(getInternalFormat(level));
969}
970
971IDirect3DBaseTexture9 *Texture2D::getBaseTexture() const
972{
973 return mTexStorage ? mTexStorage->getBaseTexture() : NULL;
974}
975
daniel@transgaming.comf032cb82012-10-31 19:51:52 +0000976// Constructs a native texture resource from the texture images
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000977void Texture2D::createTexture()
978{
979 GLsizei width = mImageArray[0].getWidth();
980 GLsizei height = mImageArray[0].getHeight();
daniel@transgaming.come6a09842012-09-17 21:28:55 +0000981
982 if (!(width > 0 && height > 0))
daniel@transgaming.comf032cb82012-10-31 19:51:52 +0000983 return; // do not attempt to create native textures for nonexistant data
daniel@transgaming.come6a09842012-09-17 21:28:55 +0000984
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000985 GLint levels = creationLevels(width, height);
daniel@transgaming.comf032cb82012-10-31 19:51:52 +0000986 GLenum internalformat = mImageArray[0].getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000987
988 delete mTexStorage;
daniel@transgaming.comf032cb82012-10-31 19:51:52 +0000989 mTexStorage = new TextureStorage2D(levels, internalformat, mUsage, false, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000990
991 if (mTexStorage->isManaged())
992 {
993 int levels = levelCount();
994
995 for (int level = 0; level < levels; level++)
996 {
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +0000997 IDirect3DSurface9 *surface = mTexStorage->getSurfaceLevel(level, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000998 mImageArray[level].setManagedSurface(surface);
999 }
1000 }
1001
1002 mDirtyImages = true;
1003}
1004
1005void Texture2D::updateTexture()
1006{
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +00001007 bool mipmapping = (isMipmapFiltered() && isMipmapComplete());
1008
1009 int levels = (mipmapping ? levelCount() : 1);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001010
1011 for (int level = 0; level < levels; level++)
1012 {
1013 Image *image = &mImageArray[level];
1014
1015 if (image->isDirty())
1016 {
1017 commitRect(level, 0, 0, mImageArray[level].getWidth(), mImageArray[level].getHeight());
1018 }
1019 }
1020}
1021
1022void Texture2D::convertToRenderTarget()
1023{
1024 TextureStorage2D *newTexStorage = NULL;
1025
1026 if (mImageArray[0].getWidth() != 0 && mImageArray[0].getHeight() != 0)
1027 {
1028 GLsizei width = mImageArray[0].getWidth();
1029 GLsizei height = mImageArray[0].getHeight();
1030 GLint levels = creationLevels(width, height);
daniel@transgaming.comf032cb82012-10-31 19:51:52 +00001031 GLenum internalformat = mImageArray[0].getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001032
daniel@transgaming.comf032cb82012-10-31 19:51:52 +00001033 newTexStorage = new TextureStorage2D(levels, internalformat, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, true, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001034
1035 if (mTexStorage != NULL)
1036 {
1037 int levels = levelCount();
1038 for (int i = 0; i < levels; i++)
1039 {
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00001040 IDirect3DSurface9 *source = mTexStorage->getSurfaceLevel(i, false);
1041 IDirect3DSurface9 *dest = newTexStorage->getSurfaceLevel(i, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001042
1043 if (!copyToRenderTarget(dest, source, mTexStorage->isManaged()))
1044 {
1045 delete newTexStorage;
1046 if (source) source->Release();
1047 if (dest) dest->Release();
1048 return error(GL_OUT_OF_MEMORY);
1049 }
1050
1051 if (source) source->Release();
1052 if (dest) dest->Release();
1053 }
1054 }
1055 }
1056
1057 delete mTexStorage;
1058 mTexStorage = newTexStorage;
1059
1060 mDirtyImages = true;
1061}
1062
1063void Texture2D::generateMipmaps()
1064{
1065 if (!getContext()->supportsNonPower2Texture())
1066 {
1067 if (!isPow2(mImageArray[0].getWidth()) || !isPow2(mImageArray[0].getHeight()))
1068 {
1069 return error(GL_INVALID_OPERATION);
1070 }
1071 }
1072
1073 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1074 unsigned int q = log2(std::max(mImageArray[0].getWidth(), mImageArray[0].getHeight()));
1075 for (unsigned int i = 1; i <= q; i++)
1076 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001077 redefineImage(i, mImageArray[0].getInternalFormat(),
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001078 std::max(mImageArray[0].getWidth() >> i, 1),
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001079 std::max(mImageArray[0].getHeight() >> i, 1));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001080 }
1081
1082 if (mTexStorage && mTexStorage->isRenderTarget())
1083 {
1084 for (unsigned int i = 1; i <= q; i++)
1085 {
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00001086 IDirect3DSurface9 *upper = mTexStorage->getSurfaceLevel(i - 1, false);
1087 IDirect3DSurface9 *lower = mTexStorage->getSurfaceLevel(i, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001088
1089 if (upper != NULL && lower != NULL)
1090 {
1091 getBlitter()->boxFilter(upper, lower);
1092 }
1093
1094 if (upper != NULL) upper->Release();
1095 if (lower != NULL) lower->Release();
1096
1097 mImageArray[i].markClean();
1098 }
1099 }
1100 else
1101 {
1102 for (unsigned int i = 1; i <= q; i++)
1103 {
1104 if (mImageArray[i].getSurface() == NULL)
1105 {
1106 return error(GL_OUT_OF_MEMORY);
1107 }
1108
daniel@transgaming.com2e38b802012-10-17 18:30:06 +00001109 GenerateMip(mImageArray[i].getSurface(), mImageArray[i - 1].getSurface());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001110
1111 mImageArray[i].markDirty();
1112 }
1113 }
1114}
1115
1116Renderbuffer *Texture2D::getRenderbuffer(GLenum target)
1117{
1118 if (target != GL_TEXTURE_2D)
1119 {
1120 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
1121 }
1122
1123 if (mColorbufferProxy == NULL)
1124 {
1125 mColorbufferProxy = new Renderbuffer(id(), new RenderbufferTexture2D(this, target));
1126 }
1127
1128 return mColorbufferProxy;
1129}
1130
1131// Increments refcount on surface.
1132// caller must Release() the returned surface
1133IDirect3DSurface9 *Texture2D::getRenderTarget(GLenum target)
1134{
1135 ASSERT(target == GL_TEXTURE_2D);
1136
1137 // ensure the underlying texture is created
1138 if (getStorage(true) == NULL)
1139 {
1140 return NULL;
1141 }
1142
1143 updateTexture();
1144
1145 // ensure this is NOT a depth texture
1146 if (isDepth(0))
1147 {
1148 return NULL;
1149 }
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00001150 return mTexStorage->getSurfaceLevel(0, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001151}
1152
1153// Increments refcount on surface.
1154// caller must Release() the returned surface
1155IDirect3DSurface9 *Texture2D::getDepthStencil(GLenum target)
1156{
1157 ASSERT(target == GL_TEXTURE_2D);
1158
1159 // ensure the underlying texture is created
1160 if (getStorage(true) == NULL)
1161 {
1162 return NULL;
1163 }
1164
1165 updateTexture();
1166
1167 // ensure this is actually a depth texture
1168 if (!isDepth(0))
1169 {
1170 return NULL;
1171 }
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00001172 return mTexStorage->getSurfaceLevel(0, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001173}
1174
1175TextureStorage *Texture2D::getStorage(bool renderTarget)
1176{
1177 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
1178 {
1179 if (renderTarget)
1180 {
1181 convertToRenderTarget();
1182 }
1183 else
1184 {
1185 createTexture();
1186 }
1187 }
1188
1189 return mTexStorage;
1190}
1191
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001192TextureCubeMap::TextureCubeMap(GLuint id) : Texture(id)
1193{
1194 mTexStorage = NULL;
1195 for (int i = 0; i < 6; i++)
1196 {
1197 mFaceProxies[i] = NULL;
1198 mFaceProxyRefs[i] = 0;
1199 }
1200}
1201
1202TextureCubeMap::~TextureCubeMap()
1203{
1204 for (int i = 0; i < 6; i++)
1205 {
1206 mFaceProxies[i] = NULL;
1207 }
1208
1209 delete mTexStorage;
1210 mTexStorage = NULL;
1211}
1212
1213// We need to maintain a count of references to renderbuffers acting as
1214// proxies for this texture, so that the texture is not deleted while
1215// proxy references still exist. If the reference count drops to zero,
1216// we set our proxy pointer NULL, so that a new attempt at referencing
1217// will cause recreation.
1218void TextureCubeMap::addProxyRef(const Renderbuffer *proxy)
1219{
1220 for (int i = 0; i < 6; i++)
1221 {
1222 if (mFaceProxies[i] == proxy)
1223 mFaceProxyRefs[i]++;
1224 }
1225}
1226
1227void TextureCubeMap::releaseProxy(const Renderbuffer *proxy)
1228{
1229 for (int i = 0; i < 6; i++)
1230 {
1231 if (mFaceProxies[i] == proxy)
1232 {
1233 if (mFaceProxyRefs[i] > 0)
1234 mFaceProxyRefs[i]--;
1235
1236 if (mFaceProxyRefs[i] == 0)
1237 mFaceProxies[i] = NULL;
1238 }
1239 }
1240}
1241
1242GLenum TextureCubeMap::getTarget() const
1243{
1244 return GL_TEXTURE_CUBE_MAP;
1245}
1246
1247GLsizei TextureCubeMap::getWidth(GLenum target, GLint level) const
1248{
1249 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1250 return mImageArray[faceIndex(target)][level].getWidth();
1251 else
1252 return 0;
1253}
1254
1255GLsizei TextureCubeMap::getHeight(GLenum target, GLint level) const
1256{
1257 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1258 return mImageArray[faceIndex(target)][level].getHeight();
1259 else
1260 return 0;
1261}
1262
1263GLenum TextureCubeMap::getInternalFormat(GLenum target, GLint level) const
1264{
1265 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001266 return mImageArray[faceIndex(target)][level].getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001267 else
1268 return GL_NONE;
1269}
1270
daniel@transgaming.com20d36662012-10-31 19:51:43 +00001271GLenum TextureCubeMap::getActualFormat(GLenum target, GLint level) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001272{
1273 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.com20d36662012-10-31 19:51:43 +00001274 return mImageArray[faceIndex(target)][level].getActualFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001275 else
1276 return D3DFMT_UNKNOWN;
1277}
1278
1279void TextureCubeMap::setImagePosX(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1280{
1281 setImage(0, level, width, height, format, type, unpackAlignment, pixels);
1282}
1283
1284void TextureCubeMap::setImageNegX(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1285{
1286 setImage(1, level, width, height, format, type, unpackAlignment, pixels);
1287}
1288
1289void TextureCubeMap::setImagePosY(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1290{
1291 setImage(2, level, width, height, format, type, unpackAlignment, pixels);
1292}
1293
1294void TextureCubeMap::setImageNegY(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1295{
1296 setImage(3, level, width, height, format, type, unpackAlignment, pixels);
1297}
1298
1299void TextureCubeMap::setImagePosZ(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1300{
1301 setImage(4, level, width, height, format, type, unpackAlignment, pixels);
1302}
1303
1304void TextureCubeMap::setImageNegZ(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1305{
1306 setImage(5, level, width, height, format, type, unpackAlignment, pixels);
1307}
1308
1309void TextureCubeMap::setCompressedImage(GLenum face, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
1310{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001311 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1312 redefineImage(faceIndex(face), level, format, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001313
1314 Texture::setCompressedImage(imageSize, pixels, &mImageArray[faceIndex(face)][level]);
1315}
1316
1317void TextureCubeMap::commitRect(int face, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1318{
1319 ASSERT(mImageArray[face][level].getSurface() != NULL);
1320
1321 if (level < levelCount())
1322 {
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00001323 IDirect3DSurface9 *destLevel = mTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001324 ASSERT(destLevel != NULL);
1325
1326 if (destLevel != NULL)
1327 {
1328 Image *image = &mImageArray[face][level];
1329 image->updateSurface(destLevel, xoffset, yoffset, width, height);
1330
1331 destLevel->Release();
1332 image->markClean();
1333 }
1334 }
1335}
1336
1337void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1338{
1339 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[faceIndex(target)][level]))
1340 {
1341 commitRect(faceIndex(target), level, xoffset, yoffset, width, height);
1342 }
1343}
1344
1345void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1346{
1347 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[faceIndex(target)][level]))
1348 {
1349 commitRect(faceIndex(target), level, xoffset, yoffset, width, height);
1350 }
1351}
1352
1353// Tests for cube map sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 86.
1354bool TextureCubeMap::isSamplerComplete() const
1355{
1356 int size = mImageArray[0][0].getWidth();
1357
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +00001358 bool mipmapping = isMipmapFiltered();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001359
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001360 if ((gl::ExtractType(getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0)) == GL_FLOAT && !getContext()->supportsFloat32LinearFilter()) ||
1361 (gl::ExtractType(getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0) == GL_HALF_FLOAT_OES) && !getContext()->supportsFloat16LinearFilter()))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001362 {
daniel@transgaming.comebf139f2012-10-31 18:07:32 +00001363 if (mSamplerState.magFilter != GL_NEAREST ||
1364 (mSamplerState.minFilter != GL_NEAREST && mSamplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001365 {
1366 return false;
1367 }
1368 }
1369
1370 if (!isPow2(size) && !getContext()->supportsNonPower2Texture())
1371 {
daniel@transgaming.comebf139f2012-10-31 18:07:32 +00001372 if (mSamplerState.wrapS != GL_CLAMP_TO_EDGE || mSamplerState.wrapT != GL_CLAMP_TO_EDGE || mipmapping)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001373 {
1374 return false;
1375 }
1376 }
1377
1378 if (!mipmapping)
1379 {
1380 if (!isCubeComplete())
1381 {
1382 return false;
1383 }
1384 }
1385 else
1386 {
1387 if (!isMipmapCubeComplete()) // Also tests for isCubeComplete()
1388 {
1389 return false;
1390 }
1391 }
1392
1393 return true;
1394}
1395
1396// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1397bool TextureCubeMap::isCubeComplete() const
1398{
1399 if (mImageArray[0][0].getWidth() <= 0 || mImageArray[0][0].getHeight() != mImageArray[0][0].getWidth())
1400 {
1401 return false;
1402 }
1403
1404 for (unsigned int face = 1; face < 6; face++)
1405 {
1406 if (mImageArray[face][0].getWidth() != mImageArray[0][0].getWidth() ||
1407 mImageArray[face][0].getWidth() != mImageArray[0][0].getHeight() ||
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001408 mImageArray[face][0].getInternalFormat() != mImageArray[0][0].getInternalFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001409 {
1410 return false;
1411 }
1412 }
1413
1414 return true;
1415}
1416
1417bool TextureCubeMap::isMipmapCubeComplete() const
1418{
1419 if (isImmutable())
1420 {
1421 return true;
1422 }
1423
1424 if (!isCubeComplete())
1425 {
1426 return false;
1427 }
1428
1429 GLsizei size = mImageArray[0][0].getWidth();
1430
1431 int q = log2(size);
1432
1433 for (int face = 0; face < 6; face++)
1434 {
1435 for (int level = 1; level <= q; level++)
1436 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001437 if (mImageArray[face][level].getInternalFormat() != mImageArray[0][0].getInternalFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001438 {
1439 return false;
1440 }
1441
1442 if (mImageArray[face][level].getWidth() != std::max(1, size >> level))
1443 {
1444 return false;
1445 }
1446 }
1447 }
1448
1449 return true;
1450}
1451
1452bool TextureCubeMap::isCompressed(GLenum target, GLint level) const
1453{
1454 return IsCompressed(getInternalFormat(target, level));
1455}
1456
1457IDirect3DBaseTexture9 *TextureCubeMap::getBaseTexture() const
1458{
1459 return mTexStorage ? mTexStorage->getBaseTexture() : NULL;
1460}
1461
daniel@transgaming.comf032cb82012-10-31 19:51:52 +00001462// Constructs a native texture resource from the texture images, or returns an existing one
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001463void TextureCubeMap::createTexture()
1464{
1465 GLsizei size = mImageArray[0][0].getWidth();
daniel@transgaming.come6a09842012-09-17 21:28:55 +00001466
1467 if (!(size > 0))
daniel@transgaming.comf032cb82012-10-31 19:51:52 +00001468 return; // do not attempt to create native textures for nonexistant data
daniel@transgaming.come6a09842012-09-17 21:28:55 +00001469
sminns@adobe.comce1189b2012-09-18 20:06:35 +00001470 GLint levels = creationLevels(size);
daniel@transgaming.comf032cb82012-10-31 19:51:52 +00001471 GLenum internalformat = mImageArray[0][0].getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001472
1473 delete mTexStorage;
daniel@transgaming.comf032cb82012-10-31 19:51:52 +00001474 mTexStorage = new TextureStorageCubeMap(levels, internalformat, mUsage, false, size);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001475
1476 if (mTexStorage->isManaged())
1477 {
1478 int levels = levelCount();
1479
1480 for (int face = 0; face < 6; face++)
1481 {
1482 for (int level = 0; level < levels; level++)
1483 {
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00001484 IDirect3DSurface9 *surface = mTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001485 mImageArray[face][level].setManagedSurface(surface);
1486 }
1487 }
1488 }
1489
1490 mDirtyImages = true;
1491}
1492
1493void TextureCubeMap::updateTexture()
1494{
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +00001495 bool mipmapping = isMipmapFiltered() && isMipmapCubeComplete();
1496
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001497 for (int face = 0; face < 6; face++)
1498 {
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +00001499 int levels = (mipmapping ? levelCount() : 1);
1500
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001501 for (int level = 0; level < levels; level++)
1502 {
1503 Image *image = &mImageArray[face][level];
1504
1505 if (image->isDirty())
1506 {
1507 commitRect(face, level, 0, 0, image->getWidth(), image->getHeight());
1508 }
1509 }
1510 }
1511}
1512
1513void TextureCubeMap::convertToRenderTarget()
1514{
1515 TextureStorageCubeMap *newTexStorage = NULL;
1516
1517 if (mImageArray[0][0].getWidth() != 0)
1518 {
1519 GLsizei size = mImageArray[0][0].getWidth();
sminns@adobe.comce1189b2012-09-18 20:06:35 +00001520 GLint levels = creationLevels(size);
daniel@transgaming.comf032cb82012-10-31 19:51:52 +00001521 GLenum internalformat = mImageArray[0][0].getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001522
daniel@transgaming.comf032cb82012-10-31 19:51:52 +00001523 newTexStorage = new TextureStorageCubeMap(levels, internalformat, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, true, size);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001524
1525 if (mTexStorage != NULL)
1526 {
1527 int levels = levelCount();
1528 for (int f = 0; f < 6; f++)
1529 {
1530 for (int i = 0; i < levels; i++)
1531 {
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00001532 IDirect3DSurface9 *source = mTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i, false);
1533 IDirect3DSurface9 *dest = newTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001534
1535 if (!copyToRenderTarget(dest, source, mTexStorage->isManaged()))
1536 {
1537 delete newTexStorage;
1538 if (source) source->Release();
1539 if (dest) dest->Release();
1540 return error(GL_OUT_OF_MEMORY);
1541 }
1542
1543 if (source) source->Release();
1544 if (dest) dest->Release();
1545 }
1546 }
1547 }
1548 }
1549
1550 delete mTexStorage;
1551 mTexStorage = newTexStorage;
1552
1553 mDirtyImages = true;
1554}
1555
1556void TextureCubeMap::setImage(int faceIndex, GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1557{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001558 GLint internalformat = ConvertSizedInternalFormat(format, type);
1559 redefineImage(faceIndex, level, internalformat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001560
1561 Texture::setImage(unpackAlignment, pixels, &mImageArray[faceIndex][level]);
1562}
1563
1564unsigned int TextureCubeMap::faceIndex(GLenum face)
1565{
1566 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
1567 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
1568 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
1569 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
1570 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
1571
1572 return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
1573}
1574
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001575void TextureCubeMap::redefineImage(int face, GLint level, GLint internalformat, GLsizei width, GLsizei height)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001576{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001577 bool redefined = mImageArray[face][level].redefine(internalformat, width, height, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001578
1579 if (mTexStorage && redefined)
1580 {
1581 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1582 {
1583 for (int f = 0; f < 6; f++)
1584 {
1585 mImageArray[f][i].markDirty();
1586 }
1587 }
1588
1589 delete mTexStorage;
1590 mTexStorage = NULL;
1591
1592 mDirtyImages = true;
1593 }
1594}
1595
1596void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1597{
1598 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
1599
1600 if (!renderTarget)
1601 {
1602 ERR("Failed to retrieve the render target.");
1603 return error(GL_OUT_OF_MEMORY);
1604 }
1605
1606 unsigned int faceindex = faceIndex(target);
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001607 GLint internalformat = gl::ConvertSizedInternalFormat(format, GL_UNSIGNED_BYTE);
1608 redefineImage(faceindex, level, internalformat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001609
1610 if (!mImageArray[faceindex][level].isRenderableFormat())
1611 {
1612 mImageArray[faceindex][level].copy(0, 0, x, y, width, height, renderTarget);
1613 mDirtyImages = true;
1614 }
1615 else
1616 {
1617 if (!mTexStorage || !mTexStorage->isRenderTarget())
1618 {
1619 convertToRenderTarget();
1620 }
1621
1622 mImageArray[faceindex][level].markClean();
1623
1624 ASSERT(width == height);
1625
1626 if (width > 0 && level < levelCount())
1627 {
1628 RECT sourceRect;
1629 sourceRect.left = x;
1630 sourceRect.right = x + width;
1631 sourceRect.top = y;
1632 sourceRect.bottom = y + height;
1633
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00001634 IDirect3DSurface9 *dest = mTexStorage->getCubeMapSurface(target, level, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001635
1636 if (dest)
1637 {
1638 getBlitter()->copy(renderTarget, sourceRect, format, 0, 0, dest);
1639 dest->Release();
1640 }
1641 }
1642 }
1643
1644 renderTarget->Release();
1645}
1646
1647void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1648{
1649 GLsizei size = mImageArray[faceIndex(target)][level].getWidth();
1650
1651 if (xoffset + width > size || yoffset + height > size)
1652 {
1653 return error(GL_INVALID_VALUE);
1654 }
1655
1656 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
1657
1658 if (!renderTarget)
1659 {
1660 ERR("Failed to retrieve the render target.");
1661 return error(GL_OUT_OF_MEMORY);
1662 }
1663
1664 unsigned int faceindex = faceIndex(target);
1665
1666 if (!mImageArray[faceindex][level].isRenderableFormat() || (!mTexStorage && !isSamplerComplete()))
1667 {
1668 mImageArray[faceindex][level].copy(0, 0, x, y, width, height, renderTarget);
1669 mDirtyImages = true;
1670 }
1671 else
1672 {
1673 if (!mTexStorage || !mTexStorage->isRenderTarget())
1674 {
1675 convertToRenderTarget();
1676 }
1677
1678 updateTexture();
1679
1680 if (level < levelCount())
1681 {
1682 RECT sourceRect;
1683 sourceRect.left = x;
1684 sourceRect.right = x + width;
1685 sourceRect.top = y;
1686 sourceRect.bottom = y + height;
1687
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00001688 IDirect3DSurface9 *dest = mTexStorage->getCubeMapSurface(target, level, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001689
1690 if (dest)
1691 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001692 getBlitter()->copy(renderTarget, sourceRect, gl::ExtractFormat(mImageArray[0][0].getInternalFormat()), xoffset, yoffset, dest);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001693 dest->Release();
1694 }
1695 }
1696 }
1697
1698 renderTarget->Release();
1699}
1700
1701void TextureCubeMap::storage(GLsizei levels, GLenum internalformat, GLsizei size)
1702{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001703 delete mTexStorage;
daniel@transgaming.comf032cb82012-10-31 19:51:52 +00001704 mTexStorage = new TextureStorageCubeMap(levels, internalformat, mUsage, false, size);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001705 mImmutable = true;
1706
1707 for (int level = 0; level < levels; level++)
1708 {
1709 for (int face = 0; face < 6; face++)
1710 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001711 mImageArray[face][level].redefine(internalformat, size, size, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001712 size = std::max(1, size >> 1);
1713 }
1714 }
1715
1716 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1717 {
1718 for (int face = 0; face < 6; face++)
1719 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001720 mImageArray[face][level].redefine(GL_NONE, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001721 }
1722 }
1723
1724 if (mTexStorage->isManaged())
1725 {
1726 int levels = levelCount();
1727
1728 for (int face = 0; face < 6; face++)
1729 {
1730 for (int level = 0; level < levels; level++)
1731 {
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00001732 IDirect3DSurface9 *surface = mTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001733 mImageArray[face][level].setManagedSurface(surface);
1734 }
1735 }
1736 }
1737}
1738
1739void TextureCubeMap::generateMipmaps()
1740{
1741 if (!isCubeComplete())
1742 {
1743 return error(GL_INVALID_OPERATION);
1744 }
1745
1746 if (!getContext()->supportsNonPower2Texture())
1747 {
1748 if (!isPow2(mImageArray[0][0].getWidth()))
1749 {
1750 return error(GL_INVALID_OPERATION);
1751 }
1752 }
1753
1754 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1755 unsigned int q = log2(mImageArray[0][0].getWidth());
1756 for (unsigned int f = 0; f < 6; f++)
1757 {
1758 for (unsigned int i = 1; i <= q; i++)
1759 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001760 redefineImage(f, i, mImageArray[f][0].getInternalFormat(),
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001761 std::max(mImageArray[f][0].getWidth() >> i, 1),
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001762 std::max(mImageArray[f][0].getWidth() >> i, 1));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001763 }
1764 }
1765
1766 if (mTexStorage && mTexStorage->isRenderTarget())
1767 {
1768 for (unsigned int f = 0; f < 6; f++)
1769 {
1770 for (unsigned int i = 1; i <= q; i++)
1771 {
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00001772 IDirect3DSurface9 *upper = mTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i - 1, false);
1773 IDirect3DSurface9 *lower = mTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001774
1775 if (upper != NULL && lower != NULL)
1776 {
1777 getBlitter()->boxFilter(upper, lower);
1778 }
1779
1780 if (upper != NULL) upper->Release();
1781 if (lower != NULL) lower->Release();
1782
1783 mImageArray[f][i].markClean();
1784 }
1785 }
1786 }
1787 else
1788 {
1789 for (unsigned int f = 0; f < 6; f++)
1790 {
1791 for (unsigned int i = 1; i <= q; i++)
1792 {
1793 if (mImageArray[f][i].getSurface() == NULL)
1794 {
1795 return error(GL_OUT_OF_MEMORY);
1796 }
1797
daniel@transgaming.com2e38b802012-10-17 18:30:06 +00001798 GenerateMip(mImageArray[f][i].getSurface(), mImageArray[f][i - 1].getSurface());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001799
1800 mImageArray[f][i].markDirty();
1801 }
1802 }
1803 }
1804}
1805
1806Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target)
1807{
1808 if (!IsCubemapTextureTarget(target))
1809 {
1810 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
1811 }
1812
1813 unsigned int face = faceIndex(target);
1814
1815 if (mFaceProxies[face] == NULL)
1816 {
1817 mFaceProxies[face] = new Renderbuffer(id(), new RenderbufferTextureCubeMap(this, target));
1818 }
1819
1820 return mFaceProxies[face];
1821}
1822
1823// Increments refcount on surface.
1824// caller must Release() the returned surface
1825IDirect3DSurface9 *TextureCubeMap::getRenderTarget(GLenum target)
1826{
1827 ASSERT(IsCubemapTextureTarget(target));
1828
1829 // ensure the underlying texture is created
1830 if (getStorage(true) == NULL)
1831 {
1832 return NULL;
1833 }
1834
1835 updateTexture();
1836
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00001837 return mTexStorage->getCubeMapSurface(target, 0, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001838}
1839
1840TextureStorage *TextureCubeMap::getStorage(bool renderTarget)
1841{
1842 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
1843 {
1844 if (renderTarget)
1845 {
1846 convertToRenderTarget();
1847 }
1848 else
1849 {
1850 createTexture();
1851 }
1852 }
1853
1854 return mTexStorage;
1855}
1856
1857}