blob: 73ffa56cf3205858ecc9551dbbfc0346b5f6e96a [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.comdf14c762012-10-31 19:51:48 +0000841 D3DFORMAT d3dfmt = TextureStorage::ConvertTextureInternalFormat(internalformat);
842 DWORD d3dusage = TextureStorage::GetTextureUsage(d3dfmt, mUsage, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000843
844 delete mTexStorage;
845 mTexStorage = new TextureStorage2D(levels, d3dfmt, d3dusage, width, height);
846 mImmutable = true;
847
848 for (int level = 0; level < levels; level++)
849 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000850 mImageArray[level].redefine(internalformat, width, height, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000851 width = std::max(1, width >> 1);
852 height = std::max(1, height >> 1);
853 }
854
855 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
856 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000857 mImageArray[level].redefine(GL_NONE, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000858 }
859
860 if (mTexStorage->isManaged())
861 {
862 int levels = levelCount();
863
864 for (int level = 0; level < levels; level++)
865 {
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +0000866 IDirect3DSurface9 *surface = mTexStorage->getSurfaceLevel(level, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000867 mImageArray[level].setManagedSurface(surface);
868 }
869 }
870}
871
872// Tests for 2D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85.
873bool Texture2D::isSamplerComplete() const
874{
875 GLsizei width = mImageArray[0].getWidth();
876 GLsizei height = mImageArray[0].getHeight();
877
878 if (width <= 0 || height <= 0)
879 {
880 return false;
881 }
882
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +0000883 bool mipmapping = isMipmapFiltered();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000884
daniel@transgaming.com6b1a0a02012-10-17 18:22:47 +0000885 if ((IsFloat32Format(getInternalFormat(0)) && !getContext()->supportsFloat32LinearFilter()) ||
886 (IsFloat16Format(getInternalFormat(0)) && !getContext()->supportsFloat16LinearFilter()))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000887 {
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000888 if (mSamplerState.magFilter != GL_NEAREST ||
889 (mSamplerState.minFilter != GL_NEAREST && mSamplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000890 {
891 return false;
892 }
893 }
894
895 bool npotSupport = getContext()->supportsNonPower2Texture();
896
897 if (!npotSupport)
898 {
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000899 if ((mSamplerState.wrapS != GL_CLAMP_TO_EDGE && !isPow2(width)) ||
900 (mSamplerState.wrapT != GL_CLAMP_TO_EDGE && !isPow2(height)))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000901 {
902 return false;
903 }
904 }
905
906 if (mipmapping)
907 {
908 if (!npotSupport)
909 {
910 if (!isPow2(width) || !isPow2(height))
911 {
912 return false;
913 }
914 }
915
916 if (!isMipmapComplete())
917 {
918 return false;
919 }
920 }
921
922 return true;
923}
924
925// Tests for 2D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
926bool Texture2D::isMipmapComplete() const
927{
928 if (isImmutable())
929 {
930 return true;
931 }
932
933 GLsizei width = mImageArray[0].getWidth();
934 GLsizei height = mImageArray[0].getHeight();
935
936 if (width <= 0 || height <= 0)
937 {
938 return false;
939 }
940
941 int q = log2(std::max(width, height));
942
943 for (int level = 1; level <= q; level++)
944 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000945 if (mImageArray[level].getInternalFormat() != mImageArray[0].getInternalFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000946 {
947 return false;
948 }
949
950 if (mImageArray[level].getWidth() != std::max(1, width >> level))
951 {
952 return false;
953 }
954
955 if (mImageArray[level].getHeight() != std::max(1, height >> level))
956 {
957 return false;
958 }
959 }
960
961 return true;
962}
963
964bool Texture2D::isCompressed(GLint level) const
965{
966 return IsCompressed(getInternalFormat(level));
967}
968
969bool Texture2D::isDepth(GLint level) const
970{
971 return IsDepthTexture(getInternalFormat(level));
972}
973
974IDirect3DBaseTexture9 *Texture2D::getBaseTexture() const
975{
976 return mTexStorage ? mTexStorage->getBaseTexture() : NULL;
977}
978
979// Constructs a Direct3D 9 texture resource from the texture images
980void Texture2D::createTexture()
981{
982 GLsizei width = mImageArray[0].getWidth();
983 GLsizei height = mImageArray[0].getHeight();
daniel@transgaming.come6a09842012-09-17 21:28:55 +0000984
985 if (!(width > 0 && height > 0))
986 return; // do not attempt to create d3d textures for nonexistant data
987
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000988 GLint levels = creationLevels(width, height);
989 D3DFORMAT d3dfmt = mImageArray[0].getD3DFormat();
daniel@transgaming.comdf14c762012-10-31 19:51:48 +0000990 DWORD d3dusage = TextureStorage::GetTextureUsage(d3dfmt, mUsage, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000991
992 delete mTexStorage;
993 mTexStorage = new TextureStorage2D(levels, d3dfmt, d3dusage, width, height);
994
995 if (mTexStorage->isManaged())
996 {
997 int levels = levelCount();
998
999 for (int level = 0; level < levels; level++)
1000 {
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00001001 IDirect3DSurface9 *surface = mTexStorage->getSurfaceLevel(level, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001002 mImageArray[level].setManagedSurface(surface);
1003 }
1004 }
1005
1006 mDirtyImages = true;
1007}
1008
1009void Texture2D::updateTexture()
1010{
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +00001011 bool mipmapping = (isMipmapFiltered() && isMipmapComplete());
1012
1013 int levels = (mipmapping ? levelCount() : 1);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001014
1015 for (int level = 0; level < levels; level++)
1016 {
1017 Image *image = &mImageArray[level];
1018
1019 if (image->isDirty())
1020 {
1021 commitRect(level, 0, 0, mImageArray[level].getWidth(), mImageArray[level].getHeight());
1022 }
1023 }
1024}
1025
1026void Texture2D::convertToRenderTarget()
1027{
1028 TextureStorage2D *newTexStorage = NULL;
1029
1030 if (mImageArray[0].getWidth() != 0 && mImageArray[0].getHeight() != 0)
1031 {
1032 GLsizei width = mImageArray[0].getWidth();
1033 GLsizei height = mImageArray[0].getHeight();
1034 GLint levels = creationLevels(width, height);
1035 D3DFORMAT d3dfmt = mImageArray[0].getD3DFormat();
daniel@transgaming.comdf14c762012-10-31 19:51:48 +00001036 DWORD d3dusage = TextureStorage::GetTextureUsage(d3dfmt, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001037
1038 newTexStorage = new TextureStorage2D(levels, d3dfmt, d3dusage, width, height);
1039
1040 if (mTexStorage != NULL)
1041 {
1042 int levels = levelCount();
1043 for (int i = 0; i < levels; i++)
1044 {
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00001045 IDirect3DSurface9 *source = mTexStorage->getSurfaceLevel(i, false);
1046 IDirect3DSurface9 *dest = newTexStorage->getSurfaceLevel(i, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001047
1048 if (!copyToRenderTarget(dest, source, mTexStorage->isManaged()))
1049 {
1050 delete newTexStorage;
1051 if (source) source->Release();
1052 if (dest) dest->Release();
1053 return error(GL_OUT_OF_MEMORY);
1054 }
1055
1056 if (source) source->Release();
1057 if (dest) dest->Release();
1058 }
1059 }
1060 }
1061
1062 delete mTexStorage;
1063 mTexStorage = newTexStorage;
1064
1065 mDirtyImages = true;
1066}
1067
1068void Texture2D::generateMipmaps()
1069{
1070 if (!getContext()->supportsNonPower2Texture())
1071 {
1072 if (!isPow2(mImageArray[0].getWidth()) || !isPow2(mImageArray[0].getHeight()))
1073 {
1074 return error(GL_INVALID_OPERATION);
1075 }
1076 }
1077
1078 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1079 unsigned int q = log2(std::max(mImageArray[0].getWidth(), mImageArray[0].getHeight()));
1080 for (unsigned int i = 1; i <= q; i++)
1081 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001082 redefineImage(i, mImageArray[0].getInternalFormat(),
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001083 std::max(mImageArray[0].getWidth() >> i, 1),
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001084 std::max(mImageArray[0].getHeight() >> i, 1));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001085 }
1086
1087 if (mTexStorage && mTexStorage->isRenderTarget())
1088 {
1089 for (unsigned int i = 1; i <= q; i++)
1090 {
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00001091 IDirect3DSurface9 *upper = mTexStorage->getSurfaceLevel(i - 1, false);
1092 IDirect3DSurface9 *lower = mTexStorage->getSurfaceLevel(i, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001093
1094 if (upper != NULL && lower != NULL)
1095 {
1096 getBlitter()->boxFilter(upper, lower);
1097 }
1098
1099 if (upper != NULL) upper->Release();
1100 if (lower != NULL) lower->Release();
1101
1102 mImageArray[i].markClean();
1103 }
1104 }
1105 else
1106 {
1107 for (unsigned int i = 1; i <= q; i++)
1108 {
1109 if (mImageArray[i].getSurface() == NULL)
1110 {
1111 return error(GL_OUT_OF_MEMORY);
1112 }
1113
daniel@transgaming.com2e38b802012-10-17 18:30:06 +00001114 GenerateMip(mImageArray[i].getSurface(), mImageArray[i - 1].getSurface());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001115
1116 mImageArray[i].markDirty();
1117 }
1118 }
1119}
1120
1121Renderbuffer *Texture2D::getRenderbuffer(GLenum target)
1122{
1123 if (target != GL_TEXTURE_2D)
1124 {
1125 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
1126 }
1127
1128 if (mColorbufferProxy == NULL)
1129 {
1130 mColorbufferProxy = new Renderbuffer(id(), new RenderbufferTexture2D(this, target));
1131 }
1132
1133 return mColorbufferProxy;
1134}
1135
1136// Increments refcount on surface.
1137// caller must Release() the returned surface
1138IDirect3DSurface9 *Texture2D::getRenderTarget(GLenum target)
1139{
1140 ASSERT(target == GL_TEXTURE_2D);
1141
1142 // ensure the underlying texture is created
1143 if (getStorage(true) == NULL)
1144 {
1145 return NULL;
1146 }
1147
1148 updateTexture();
1149
1150 // ensure this is NOT a depth texture
1151 if (isDepth(0))
1152 {
1153 return NULL;
1154 }
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00001155 return mTexStorage->getSurfaceLevel(0, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001156}
1157
1158// Increments refcount on surface.
1159// caller must Release() the returned surface
1160IDirect3DSurface9 *Texture2D::getDepthStencil(GLenum target)
1161{
1162 ASSERT(target == GL_TEXTURE_2D);
1163
1164 // ensure the underlying texture is created
1165 if (getStorage(true) == NULL)
1166 {
1167 return NULL;
1168 }
1169
1170 updateTexture();
1171
1172 // ensure this is actually a depth texture
1173 if (!isDepth(0))
1174 {
1175 return NULL;
1176 }
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00001177 return mTexStorage->getSurfaceLevel(0, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001178}
1179
1180TextureStorage *Texture2D::getStorage(bool renderTarget)
1181{
1182 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
1183 {
1184 if (renderTarget)
1185 {
1186 convertToRenderTarget();
1187 }
1188 else
1189 {
1190 createTexture();
1191 }
1192 }
1193
1194 return mTexStorage;
1195}
1196
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001197TextureCubeMap::TextureCubeMap(GLuint id) : Texture(id)
1198{
1199 mTexStorage = NULL;
1200 for (int i = 0; i < 6; i++)
1201 {
1202 mFaceProxies[i] = NULL;
1203 mFaceProxyRefs[i] = 0;
1204 }
1205}
1206
1207TextureCubeMap::~TextureCubeMap()
1208{
1209 for (int i = 0; i < 6; i++)
1210 {
1211 mFaceProxies[i] = NULL;
1212 }
1213
1214 delete mTexStorage;
1215 mTexStorage = NULL;
1216}
1217
1218// We need to maintain a count of references to renderbuffers acting as
1219// proxies for this texture, so that the texture is not deleted while
1220// proxy references still exist. If the reference count drops to zero,
1221// we set our proxy pointer NULL, so that a new attempt at referencing
1222// will cause recreation.
1223void TextureCubeMap::addProxyRef(const Renderbuffer *proxy)
1224{
1225 for (int i = 0; i < 6; i++)
1226 {
1227 if (mFaceProxies[i] == proxy)
1228 mFaceProxyRefs[i]++;
1229 }
1230}
1231
1232void TextureCubeMap::releaseProxy(const Renderbuffer *proxy)
1233{
1234 for (int i = 0; i < 6; i++)
1235 {
1236 if (mFaceProxies[i] == proxy)
1237 {
1238 if (mFaceProxyRefs[i] > 0)
1239 mFaceProxyRefs[i]--;
1240
1241 if (mFaceProxyRefs[i] == 0)
1242 mFaceProxies[i] = NULL;
1243 }
1244 }
1245}
1246
1247GLenum TextureCubeMap::getTarget() const
1248{
1249 return GL_TEXTURE_CUBE_MAP;
1250}
1251
1252GLsizei TextureCubeMap::getWidth(GLenum target, GLint level) const
1253{
1254 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1255 return mImageArray[faceIndex(target)][level].getWidth();
1256 else
1257 return 0;
1258}
1259
1260GLsizei TextureCubeMap::getHeight(GLenum target, GLint level) const
1261{
1262 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1263 return mImageArray[faceIndex(target)][level].getHeight();
1264 else
1265 return 0;
1266}
1267
1268GLenum TextureCubeMap::getInternalFormat(GLenum target, GLint level) const
1269{
1270 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001271 return mImageArray[faceIndex(target)][level].getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001272 else
1273 return GL_NONE;
1274}
1275
daniel@transgaming.com20d36662012-10-31 19:51:43 +00001276GLenum TextureCubeMap::getActualFormat(GLenum target, GLint level) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001277{
1278 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.com20d36662012-10-31 19:51:43 +00001279 return mImageArray[faceIndex(target)][level].getActualFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001280 else
1281 return D3DFMT_UNKNOWN;
1282}
1283
1284void TextureCubeMap::setImagePosX(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1285{
1286 setImage(0, level, width, height, format, type, unpackAlignment, pixels);
1287}
1288
1289void TextureCubeMap::setImageNegX(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1290{
1291 setImage(1, level, width, height, format, type, unpackAlignment, pixels);
1292}
1293
1294void TextureCubeMap::setImagePosY(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1295{
1296 setImage(2, level, width, height, format, type, unpackAlignment, pixels);
1297}
1298
1299void TextureCubeMap::setImageNegY(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1300{
1301 setImage(3, level, width, height, format, type, unpackAlignment, pixels);
1302}
1303
1304void TextureCubeMap::setImagePosZ(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1305{
1306 setImage(4, level, width, height, format, type, unpackAlignment, pixels);
1307}
1308
1309void TextureCubeMap::setImageNegZ(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1310{
1311 setImage(5, level, width, height, format, type, unpackAlignment, pixels);
1312}
1313
1314void TextureCubeMap::setCompressedImage(GLenum face, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
1315{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001316 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1317 redefineImage(faceIndex(face), level, format, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001318
1319 Texture::setCompressedImage(imageSize, pixels, &mImageArray[faceIndex(face)][level]);
1320}
1321
1322void TextureCubeMap::commitRect(int face, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1323{
1324 ASSERT(mImageArray[face][level].getSurface() != NULL);
1325
1326 if (level < levelCount())
1327 {
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00001328 IDirect3DSurface9 *destLevel = mTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001329 ASSERT(destLevel != NULL);
1330
1331 if (destLevel != NULL)
1332 {
1333 Image *image = &mImageArray[face][level];
1334 image->updateSurface(destLevel, xoffset, yoffset, width, height);
1335
1336 destLevel->Release();
1337 image->markClean();
1338 }
1339 }
1340}
1341
1342void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1343{
1344 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[faceIndex(target)][level]))
1345 {
1346 commitRect(faceIndex(target), level, xoffset, yoffset, width, height);
1347 }
1348}
1349
1350void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1351{
1352 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[faceIndex(target)][level]))
1353 {
1354 commitRect(faceIndex(target), level, xoffset, yoffset, width, height);
1355 }
1356}
1357
1358// Tests for cube map sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 86.
1359bool TextureCubeMap::isSamplerComplete() const
1360{
1361 int size = mImageArray[0][0].getWidth();
1362
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +00001363 bool mipmapping = isMipmapFiltered();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001364
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001365 if ((gl::ExtractType(getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0)) == GL_FLOAT && !getContext()->supportsFloat32LinearFilter()) ||
1366 (gl::ExtractType(getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0) == GL_HALF_FLOAT_OES) && !getContext()->supportsFloat16LinearFilter()))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001367 {
daniel@transgaming.comebf139f2012-10-31 18:07:32 +00001368 if (mSamplerState.magFilter != GL_NEAREST ||
1369 (mSamplerState.minFilter != GL_NEAREST && mSamplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001370 {
1371 return false;
1372 }
1373 }
1374
1375 if (!isPow2(size) && !getContext()->supportsNonPower2Texture())
1376 {
daniel@transgaming.comebf139f2012-10-31 18:07:32 +00001377 if (mSamplerState.wrapS != GL_CLAMP_TO_EDGE || mSamplerState.wrapT != GL_CLAMP_TO_EDGE || mipmapping)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001378 {
1379 return false;
1380 }
1381 }
1382
1383 if (!mipmapping)
1384 {
1385 if (!isCubeComplete())
1386 {
1387 return false;
1388 }
1389 }
1390 else
1391 {
1392 if (!isMipmapCubeComplete()) // Also tests for isCubeComplete()
1393 {
1394 return false;
1395 }
1396 }
1397
1398 return true;
1399}
1400
1401// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1402bool TextureCubeMap::isCubeComplete() const
1403{
1404 if (mImageArray[0][0].getWidth() <= 0 || mImageArray[0][0].getHeight() != mImageArray[0][0].getWidth())
1405 {
1406 return false;
1407 }
1408
1409 for (unsigned int face = 1; face < 6; face++)
1410 {
1411 if (mImageArray[face][0].getWidth() != mImageArray[0][0].getWidth() ||
1412 mImageArray[face][0].getWidth() != mImageArray[0][0].getHeight() ||
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001413 mImageArray[face][0].getInternalFormat() != mImageArray[0][0].getInternalFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001414 {
1415 return false;
1416 }
1417 }
1418
1419 return true;
1420}
1421
1422bool TextureCubeMap::isMipmapCubeComplete() const
1423{
1424 if (isImmutable())
1425 {
1426 return true;
1427 }
1428
1429 if (!isCubeComplete())
1430 {
1431 return false;
1432 }
1433
1434 GLsizei size = mImageArray[0][0].getWidth();
1435
1436 int q = log2(size);
1437
1438 for (int face = 0; face < 6; face++)
1439 {
1440 for (int level = 1; level <= q; level++)
1441 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001442 if (mImageArray[face][level].getInternalFormat() != mImageArray[0][0].getInternalFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001443 {
1444 return false;
1445 }
1446
1447 if (mImageArray[face][level].getWidth() != std::max(1, size >> level))
1448 {
1449 return false;
1450 }
1451 }
1452 }
1453
1454 return true;
1455}
1456
1457bool TextureCubeMap::isCompressed(GLenum target, GLint level) const
1458{
1459 return IsCompressed(getInternalFormat(target, level));
1460}
1461
1462IDirect3DBaseTexture9 *TextureCubeMap::getBaseTexture() const
1463{
1464 return mTexStorage ? mTexStorage->getBaseTexture() : NULL;
1465}
1466
1467// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
1468void TextureCubeMap::createTexture()
1469{
1470 GLsizei size = mImageArray[0][0].getWidth();
daniel@transgaming.come6a09842012-09-17 21:28:55 +00001471
1472 if (!(size > 0))
1473 return; // do not attempt to create d3d textures for nonexistant data
1474
sminns@adobe.comce1189b2012-09-18 20:06:35 +00001475 GLint levels = creationLevels(size);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001476 D3DFORMAT d3dfmt = mImageArray[0][0].getD3DFormat();
daniel@transgaming.comdf14c762012-10-31 19:51:48 +00001477 DWORD d3dusage = TextureStorage::GetTextureUsage(d3dfmt, mUsage, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001478
1479 delete mTexStorage;
1480 mTexStorage = new TextureStorageCubeMap(levels, d3dfmt, d3dusage, size);
1481
1482 if (mTexStorage->isManaged())
1483 {
1484 int levels = levelCount();
1485
1486 for (int face = 0; face < 6; face++)
1487 {
1488 for (int level = 0; level < levels; level++)
1489 {
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00001490 IDirect3DSurface9 *surface = mTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001491 mImageArray[face][level].setManagedSurface(surface);
1492 }
1493 }
1494 }
1495
1496 mDirtyImages = true;
1497}
1498
1499void TextureCubeMap::updateTexture()
1500{
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +00001501 bool mipmapping = isMipmapFiltered() && isMipmapCubeComplete();
1502
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001503 for (int face = 0; face < 6; face++)
1504 {
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +00001505 int levels = (mipmapping ? levelCount() : 1);
1506
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001507 for (int level = 0; level < levels; level++)
1508 {
1509 Image *image = &mImageArray[face][level];
1510
1511 if (image->isDirty())
1512 {
1513 commitRect(face, level, 0, 0, image->getWidth(), image->getHeight());
1514 }
1515 }
1516 }
1517}
1518
1519void TextureCubeMap::convertToRenderTarget()
1520{
1521 TextureStorageCubeMap *newTexStorage = NULL;
1522
1523 if (mImageArray[0][0].getWidth() != 0)
1524 {
1525 GLsizei size = mImageArray[0][0].getWidth();
sminns@adobe.comce1189b2012-09-18 20:06:35 +00001526 GLint levels = creationLevels(size);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001527 D3DFORMAT d3dfmt = mImageArray[0][0].getD3DFormat();
daniel@transgaming.comdf14c762012-10-31 19:51:48 +00001528 DWORD d3dusage = TextureStorage::GetTextureUsage(d3dfmt, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001529
1530 newTexStorage = new TextureStorageCubeMap(levels, d3dfmt, d3dusage, size);
1531
1532 if (mTexStorage != NULL)
1533 {
1534 int levels = levelCount();
1535 for (int f = 0; f < 6; f++)
1536 {
1537 for (int i = 0; i < levels; i++)
1538 {
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00001539 IDirect3DSurface9 *source = mTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i, false);
1540 IDirect3DSurface9 *dest = newTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001541
1542 if (!copyToRenderTarget(dest, source, mTexStorage->isManaged()))
1543 {
1544 delete newTexStorage;
1545 if (source) source->Release();
1546 if (dest) dest->Release();
1547 return error(GL_OUT_OF_MEMORY);
1548 }
1549
1550 if (source) source->Release();
1551 if (dest) dest->Release();
1552 }
1553 }
1554 }
1555 }
1556
1557 delete mTexStorage;
1558 mTexStorage = newTexStorage;
1559
1560 mDirtyImages = true;
1561}
1562
1563void TextureCubeMap::setImage(int faceIndex, GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1564{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001565 GLint internalformat = ConvertSizedInternalFormat(format, type);
1566 redefineImage(faceIndex, level, internalformat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001567
1568 Texture::setImage(unpackAlignment, pixels, &mImageArray[faceIndex][level]);
1569}
1570
1571unsigned int TextureCubeMap::faceIndex(GLenum face)
1572{
1573 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
1574 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
1575 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
1576 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
1577 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
1578
1579 return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
1580}
1581
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001582void TextureCubeMap::redefineImage(int face, GLint level, GLint internalformat, GLsizei width, GLsizei height)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001583{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001584 bool redefined = mImageArray[face][level].redefine(internalformat, width, height, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001585
1586 if (mTexStorage && redefined)
1587 {
1588 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1589 {
1590 for (int f = 0; f < 6; f++)
1591 {
1592 mImageArray[f][i].markDirty();
1593 }
1594 }
1595
1596 delete mTexStorage;
1597 mTexStorage = NULL;
1598
1599 mDirtyImages = true;
1600 }
1601}
1602
1603void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1604{
1605 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
1606
1607 if (!renderTarget)
1608 {
1609 ERR("Failed to retrieve the render target.");
1610 return error(GL_OUT_OF_MEMORY);
1611 }
1612
1613 unsigned int faceindex = faceIndex(target);
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001614 GLint internalformat = gl::ConvertSizedInternalFormat(format, GL_UNSIGNED_BYTE);
1615 redefineImage(faceindex, level, internalformat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001616
1617 if (!mImageArray[faceindex][level].isRenderableFormat())
1618 {
1619 mImageArray[faceindex][level].copy(0, 0, x, y, width, height, renderTarget);
1620 mDirtyImages = true;
1621 }
1622 else
1623 {
1624 if (!mTexStorage || !mTexStorage->isRenderTarget())
1625 {
1626 convertToRenderTarget();
1627 }
1628
1629 mImageArray[faceindex][level].markClean();
1630
1631 ASSERT(width == height);
1632
1633 if (width > 0 && level < levelCount())
1634 {
1635 RECT sourceRect;
1636 sourceRect.left = x;
1637 sourceRect.right = x + width;
1638 sourceRect.top = y;
1639 sourceRect.bottom = y + height;
1640
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00001641 IDirect3DSurface9 *dest = mTexStorage->getCubeMapSurface(target, level, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001642
1643 if (dest)
1644 {
1645 getBlitter()->copy(renderTarget, sourceRect, format, 0, 0, dest);
1646 dest->Release();
1647 }
1648 }
1649 }
1650
1651 renderTarget->Release();
1652}
1653
1654void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1655{
1656 GLsizei size = mImageArray[faceIndex(target)][level].getWidth();
1657
1658 if (xoffset + width > size || yoffset + height > size)
1659 {
1660 return error(GL_INVALID_VALUE);
1661 }
1662
1663 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
1664
1665 if (!renderTarget)
1666 {
1667 ERR("Failed to retrieve the render target.");
1668 return error(GL_OUT_OF_MEMORY);
1669 }
1670
1671 unsigned int faceindex = faceIndex(target);
1672
1673 if (!mImageArray[faceindex][level].isRenderableFormat() || (!mTexStorage && !isSamplerComplete()))
1674 {
1675 mImageArray[faceindex][level].copy(0, 0, x, y, width, height, renderTarget);
1676 mDirtyImages = true;
1677 }
1678 else
1679 {
1680 if (!mTexStorage || !mTexStorage->isRenderTarget())
1681 {
1682 convertToRenderTarget();
1683 }
1684
1685 updateTexture();
1686
1687 if (level < levelCount())
1688 {
1689 RECT sourceRect;
1690 sourceRect.left = x;
1691 sourceRect.right = x + width;
1692 sourceRect.top = y;
1693 sourceRect.bottom = y + height;
1694
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00001695 IDirect3DSurface9 *dest = mTexStorage->getCubeMapSurface(target, level, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001696
1697 if (dest)
1698 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001699 getBlitter()->copy(renderTarget, sourceRect, gl::ExtractFormat(mImageArray[0][0].getInternalFormat()), xoffset, yoffset, dest);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001700 dest->Release();
1701 }
1702 }
1703 }
1704
1705 renderTarget->Release();
1706}
1707
1708void TextureCubeMap::storage(GLsizei levels, GLenum internalformat, GLsizei size)
1709{
daniel@transgaming.comdf14c762012-10-31 19:51:48 +00001710 D3DFORMAT d3dfmt = TextureStorage::ConvertTextureInternalFormat(internalformat);
1711 DWORD d3dusage = TextureStorage::GetTextureUsage(d3dfmt, mUsage, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001712
1713 delete mTexStorage;
1714 mTexStorage = new TextureStorageCubeMap(levels, d3dfmt, d3dusage, size);
1715 mImmutable = true;
1716
1717 for (int level = 0; level < levels; level++)
1718 {
1719 for (int face = 0; face < 6; face++)
1720 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001721 mImageArray[face][level].redefine(internalformat, size, size, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001722 size = std::max(1, size >> 1);
1723 }
1724 }
1725
1726 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1727 {
1728 for (int face = 0; face < 6; face++)
1729 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001730 mImageArray[face][level].redefine(GL_NONE, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001731 }
1732 }
1733
1734 if (mTexStorage->isManaged())
1735 {
1736 int levels = levelCount();
1737
1738 for (int face = 0; face < 6; face++)
1739 {
1740 for (int level = 0; level < levels; level++)
1741 {
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00001742 IDirect3DSurface9 *surface = mTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001743 mImageArray[face][level].setManagedSurface(surface);
1744 }
1745 }
1746 }
1747}
1748
1749void TextureCubeMap::generateMipmaps()
1750{
1751 if (!isCubeComplete())
1752 {
1753 return error(GL_INVALID_OPERATION);
1754 }
1755
1756 if (!getContext()->supportsNonPower2Texture())
1757 {
1758 if (!isPow2(mImageArray[0][0].getWidth()))
1759 {
1760 return error(GL_INVALID_OPERATION);
1761 }
1762 }
1763
1764 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1765 unsigned int q = log2(mImageArray[0][0].getWidth());
1766 for (unsigned int f = 0; f < 6; f++)
1767 {
1768 for (unsigned int i = 1; i <= q; i++)
1769 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001770 redefineImage(f, i, mImageArray[f][0].getInternalFormat(),
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001771 std::max(mImageArray[f][0].getWidth() >> i, 1),
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001772 std::max(mImageArray[f][0].getWidth() >> i, 1));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001773 }
1774 }
1775
1776 if (mTexStorage && mTexStorage->isRenderTarget())
1777 {
1778 for (unsigned int f = 0; f < 6; f++)
1779 {
1780 for (unsigned int i = 1; i <= q; i++)
1781 {
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00001782 IDirect3DSurface9 *upper = mTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i - 1, false);
1783 IDirect3DSurface9 *lower = mTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001784
1785 if (upper != NULL && lower != NULL)
1786 {
1787 getBlitter()->boxFilter(upper, lower);
1788 }
1789
1790 if (upper != NULL) upper->Release();
1791 if (lower != NULL) lower->Release();
1792
1793 mImageArray[f][i].markClean();
1794 }
1795 }
1796 }
1797 else
1798 {
1799 for (unsigned int f = 0; f < 6; f++)
1800 {
1801 for (unsigned int i = 1; i <= q; i++)
1802 {
1803 if (mImageArray[f][i].getSurface() == NULL)
1804 {
1805 return error(GL_OUT_OF_MEMORY);
1806 }
1807
daniel@transgaming.com2e38b802012-10-17 18:30:06 +00001808 GenerateMip(mImageArray[f][i].getSurface(), mImageArray[f][i - 1].getSurface());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001809
1810 mImageArray[f][i].markDirty();
1811 }
1812 }
1813 }
1814}
1815
1816Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target)
1817{
1818 if (!IsCubemapTextureTarget(target))
1819 {
1820 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
1821 }
1822
1823 unsigned int face = faceIndex(target);
1824
1825 if (mFaceProxies[face] == NULL)
1826 {
1827 mFaceProxies[face] = new Renderbuffer(id(), new RenderbufferTextureCubeMap(this, target));
1828 }
1829
1830 return mFaceProxies[face];
1831}
1832
1833// Increments refcount on surface.
1834// caller must Release() the returned surface
1835IDirect3DSurface9 *TextureCubeMap::getRenderTarget(GLenum target)
1836{
1837 ASSERT(IsCubemapTextureTarget(target));
1838
1839 // ensure the underlying texture is created
1840 if (getStorage(true) == NULL)
1841 {
1842 return NULL;
1843 }
1844
1845 updateTexture();
1846
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00001847 return mTexStorage->getCubeMapSurface(target, 0, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001848}
1849
1850TextureStorage *TextureCubeMap::getStorage(bool renderTarget)
1851{
1852 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
1853 {
1854 if (renderTarget)
1855 {
1856 convertToRenderTarget();
1857 }
1858 else
1859 {
1860 createTexture();
1861 }
1862 }
1863
1864 return mTexStorage;
1865}
1866
1867}