blob: 555590b083c107ce7a45f2e491ab653deb9fb1a6 [file] [log] [blame]
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001//
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00002// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved.
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00003// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7// Texture.cpp: Implements the gl::Texture class and its derived classes
8// Texture2D and TextureCubeMap. Implements GL texture objects and related
9// functionality. [OpenGL ES 2.0.24] section 3.7 page 63.
10
11#include "libGLESv2/Texture.h"
12
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000013#include <algorithm>
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000014
15#include "common/debug.h"
16
17#include "libEGL/Display.h"
18
19#include "libGLESv2/main.h"
20#include "libGLESv2/mathutil.h"
21#include "libGLESv2/utilities.h"
22#include "libGLESv2/Blit.h"
23#include "libGLESv2/Framebuffer.h"
24
25namespace gl
26{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000027
daniel@transgaming.com2e38b802012-10-17 18:30:06 +000028namespace
29{
30struct L8
31{
32 unsigned char L;
33
34 static void average(L8 *dst, const L8 *src1, const L8 *src2)
35 {
36 dst->L = ((src1->L ^ src2->L) >> 1) + (src1->L & src2->L);
37 }
38};
39
40struct A8L8
41{
42 unsigned char L;
43 unsigned char A;
44
45 static void average(A8L8 *dst, const A8L8 *src1, const A8L8 *src2)
46 {
47 *(unsigned short*)dst = (((*(unsigned short*)src1 ^ *(unsigned short*)src2) & 0xFEFE) >> 1) + (*(unsigned short*)src1 & *(unsigned short*)src2);
48 }
49};
50
51struct A8R8G8B8
52{
53 unsigned char B;
54 unsigned char G;
55 unsigned char R;
56 unsigned char A;
57
58 static void average(A8R8G8B8 *dst, const A8R8G8B8 *src1, const A8R8G8B8 *src2)
59 {
60 *(unsigned int*)dst = (((*(unsigned int*)src1 ^ *(unsigned int*)src2) & 0xFEFEFEFE) >> 1) + (*(unsigned int*)src1 & *(unsigned int*)src2);
61 }
62};
63
64struct A16B16G16R16F
65{
66 unsigned short R;
67 unsigned short G;
68 unsigned short B;
69 unsigned short A;
70
71 static void average(A16B16G16R16F *dst, const A16B16G16R16F *src1, const A16B16G16R16F *src2)
72 {
73 dst->R = float32ToFloat16((float16ToFloat32(src1->R) + float16ToFloat32(src2->R)) * 0.5f);
74 dst->G = float32ToFloat16((float16ToFloat32(src1->G) + float16ToFloat32(src2->G)) * 0.5f);
75 dst->B = float32ToFloat16((float16ToFloat32(src1->B) + float16ToFloat32(src2->B)) * 0.5f);
76 dst->A = float32ToFloat16((float16ToFloat32(src1->A) + float16ToFloat32(src2->A)) * 0.5f);
77 }
78};
79
80struct A32B32G32R32F
81{
82 float R;
83 float G;
84 float B;
85 float A;
86
87 static void average(A32B32G32R32F *dst, const A32B32G32R32F *src1, const A32B32G32R32F *src2)
88 {
89 dst->R = (src1->R + src2->R) * 0.5f;
90 dst->G = (src1->G + src2->G) * 0.5f;
91 dst->B = (src1->B + src2->B) * 0.5f;
92 dst->A = (src1->A + src2->A) * 0.5f;
93 }
94};
95
96template <typename T>
97void GenerateMip(unsigned int sourceWidth, unsigned int sourceHeight,
98 const unsigned char *sourceData, int sourcePitch,
99 unsigned char *destData, int destPitch)
100{
101 unsigned int mipWidth = std::max(1U, sourceWidth >> 1);
102 unsigned int mipHeight = std::max(1U, sourceHeight >> 1);
103
104 if (sourceHeight == 1)
105 {
106 ASSERT(sourceWidth != 1);
107
108 const T *src = (const T*)sourceData;
109 T *dst = (T*)destData;
110
111 for (unsigned int x = 0; x < mipWidth; x++)
112 {
113 T::average(&dst[x], &src[x * 2], &src[x * 2 + 1]);
114 }
115 }
116 else if (sourceWidth == 1)
117 {
118 ASSERT(sourceHeight != 1);
119
120 for (unsigned int y = 0; y < mipHeight; y++)
121 {
122 const T *src0 = (const T*)(sourceData + y * 2 * sourcePitch);
123 const T *src1 = (const T*)(sourceData + y * 2 * sourcePitch + sourcePitch);
124 T *dst = (T*)(destData + y * destPitch);
125
126 T::average(dst, src0, src1);
127 }
128 }
129 else
130 {
131 for (unsigned int y = 0; y < mipHeight; y++)
132 {
133 const T *src0 = (const T*)(sourceData + y * 2 * sourcePitch);
134 const T *src1 = (const T*)(sourceData + y * 2 * sourcePitch + sourcePitch);
135 T *dst = (T*)(destData + y * destPitch);
136
137 for (unsigned int x = 0; x < mipWidth; x++)
138 {
139 T tmp0;
140 T tmp1;
141
142 T::average(&tmp0, &src0[x * 2], &src0[x * 2 + 1]);
143 T::average(&tmp1, &src1[x * 2], &src1[x * 2 + 1]);
144 T::average(&dst[x], &tmp0, &tmp1);
145 }
146 }
147 }
148}
149
150void GenerateMip(IDirect3DSurface9 *destSurface, IDirect3DSurface9 *sourceSurface)
151{
152 D3DSURFACE_DESC destDesc;
153 HRESULT result = destSurface->GetDesc(&destDesc);
154 ASSERT(SUCCEEDED(result));
155
156 D3DSURFACE_DESC sourceDesc;
157 result = sourceSurface->GetDesc(&sourceDesc);
158 ASSERT(SUCCEEDED(result));
159
160 ASSERT(sourceDesc.Format == destDesc.Format);
daniel@transgaming.com2e38b802012-10-17 18:30:06 +0000161 ASSERT(sourceDesc.Width == 1 || sourceDesc.Width / 2 == destDesc.Width);
162 ASSERT(sourceDesc.Height == 1 || sourceDesc.Height / 2 == destDesc.Height);
163
164 D3DLOCKED_RECT sourceLocked = {0};
165 result = sourceSurface->LockRect(&sourceLocked, NULL, D3DLOCK_READONLY);
166 ASSERT(SUCCEEDED(result));
167
168 D3DLOCKED_RECT destLocked = {0};
169 result = destSurface->LockRect(&destLocked, NULL, 0);
170 ASSERT(SUCCEEDED(result));
171
172 const unsigned char *sourceData = reinterpret_cast<const unsigned char*>(sourceLocked.pBits);
173 unsigned char *destData = reinterpret_cast<unsigned char*>(destLocked.pBits);
174
175 if (sourceData && destData)
176 {
177 switch (sourceDesc.Format)
178 {
179 case D3DFMT_L8:
180 GenerateMip<L8>(sourceDesc.Width, sourceDesc.Height, sourceData, sourceLocked.Pitch, destData, destLocked.Pitch);
181 break;
182 case D3DFMT_A8L8:
183 GenerateMip<A8L8>(sourceDesc.Width, sourceDesc.Height, sourceData, sourceLocked.Pitch, destData, destLocked.Pitch);
184 break;
185 case D3DFMT_A8R8G8B8:
186 case D3DFMT_X8R8G8B8:
187 GenerateMip<A8R8G8B8>(sourceDesc.Width, sourceDesc.Height, sourceData, sourceLocked.Pitch, destData, destLocked.Pitch);
188 break;
189 case D3DFMT_A16B16G16R16F:
190 GenerateMip<A16B16G16R16F>(sourceDesc.Width, sourceDesc.Height, sourceData, sourceLocked.Pitch, destData, destLocked.Pitch);
191 break;
192 case D3DFMT_A32B32G32R32F:
193 GenerateMip<A32B32G32R32F>(sourceDesc.Width, sourceDesc.Height, sourceData, sourceLocked.Pitch, destData, destLocked.Pitch);
194 break;
195 default:
196 UNREACHABLE();
197 break;
198 }
199
200 destSurface->UnlockRect();
201 sourceSurface->UnlockRect();
202 }
203}
204}
205
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000206Texture::Texture(GLuint id) : RefCountObject(id)
207{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000208 mSamplerState.minFilter = GL_NEAREST_MIPMAP_LINEAR;
209 mSamplerState.magFilter = GL_LINEAR;
210 mSamplerState.wrapS = GL_REPEAT;
211 mSamplerState.wrapT = GL_REPEAT;
212 mSamplerState.maxAnisotropy = 1.0f;
213 mSamplerState.lodOffset = 0;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000214 mDirtyParameters = true;
215 mUsage = GL_NONE;
216
217 mDirtyImages = true;
218
219 mImmutable = false;
220}
221
222Texture::~Texture()
223{
224}
225
226// Returns true on successful filter state update (valid enum parameter)
227bool Texture::setMinFilter(GLenum filter)
228{
229 switch (filter)
230 {
231 case GL_NEAREST:
232 case GL_LINEAR:
233 case GL_NEAREST_MIPMAP_NEAREST:
234 case GL_LINEAR_MIPMAP_NEAREST:
235 case GL_NEAREST_MIPMAP_LINEAR:
236 case GL_LINEAR_MIPMAP_LINEAR:
237 {
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000238 if (mSamplerState.minFilter != filter)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000239 {
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000240 mSamplerState.minFilter = filter;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000241 mDirtyParameters = true;
242 }
243 return true;
244 }
245 default:
246 return false;
247 }
248}
249
250// Returns true on successful filter state update (valid enum parameter)
251bool Texture::setMagFilter(GLenum filter)
252{
253 switch (filter)
254 {
255 case GL_NEAREST:
256 case GL_LINEAR:
257 {
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000258 if (mSamplerState.magFilter != filter)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000259 {
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000260 mSamplerState.magFilter = filter;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000261 mDirtyParameters = true;
262 }
263 return true;
264 }
265 default:
266 return false;
267 }
268}
269
270// Returns true on successful wrap state update (valid enum parameter)
271bool Texture::setWrapS(GLenum wrap)
272{
273 switch (wrap)
274 {
275 case GL_REPEAT:
276 case GL_CLAMP_TO_EDGE:
277 case GL_MIRRORED_REPEAT:
278 {
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000279 if (mSamplerState.wrapS != wrap)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000280 {
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000281 mSamplerState.wrapS = wrap;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000282 mDirtyParameters = true;
283 }
284 return true;
285 }
286 default:
287 return false;
288 }
289}
290
291// Returns true on successful wrap state update (valid enum parameter)
292bool Texture::setWrapT(GLenum wrap)
293{
294 switch (wrap)
295 {
296 case GL_REPEAT:
297 case GL_CLAMP_TO_EDGE:
298 case GL_MIRRORED_REPEAT:
299 {
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000300 if (mSamplerState.wrapT != wrap)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000301 {
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000302 mSamplerState.wrapT = wrap;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000303 mDirtyParameters = true;
304 }
305 return true;
306 }
307 default:
308 return false;
309 }
310}
311
daniel@transgaming.com07ab8412012-07-12 15:17:09 +0000312// Returns true on successful max anisotropy update (valid anisotropy value)
313bool Texture::setMaxAnisotropy(float textureMaxAnisotropy, float contextMaxAnisotropy)
314{
315 textureMaxAnisotropy = std::min(textureMaxAnisotropy, contextMaxAnisotropy);
316 if (textureMaxAnisotropy < 1.0f)
317 {
318 return false;
319 }
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000320 if (mSamplerState.maxAnisotropy != textureMaxAnisotropy)
daniel@transgaming.com07ab8412012-07-12 15:17:09 +0000321 {
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000322 mSamplerState.maxAnisotropy = textureMaxAnisotropy;
daniel@transgaming.com07ab8412012-07-12 15:17:09 +0000323 mDirtyParameters = true;
324 }
325 return true;
326}
327
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000328// Returns true on successful usage state update (valid enum parameter)
329bool Texture::setUsage(GLenum usage)
330{
331 switch (usage)
332 {
333 case GL_NONE:
334 case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
335 mUsage = usage;
336 return true;
337 default:
338 return false;
339 }
340}
341
342GLenum Texture::getMinFilter() const
343{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000344 return mSamplerState.minFilter;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000345}
346
347GLenum Texture::getMagFilter() const
348{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000349 return mSamplerState.magFilter;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000350}
351
352GLenum Texture::getWrapS() const
353{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000354 return mSamplerState.wrapS;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000355}
356
357GLenum Texture::getWrapT() const
358{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000359 return mSamplerState.wrapT;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000360}
361
daniel@transgaming.com07ab8412012-07-12 15:17:09 +0000362float Texture::getMaxAnisotropy() const
363{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000364 return mSamplerState.maxAnisotropy;
365}
366
367int Texture::getLodOffset()
368{
369 TextureStorage *texture = getStorage(false);
370 return texture ? texture->getLodOffset() : 0;
371}
372
373void Texture::getSamplerState(SamplerState *sampler)
374{
375 *sampler = mSamplerState;
376 sampler->lodOffset = getLodOffset();
daniel@transgaming.com07ab8412012-07-12 15:17:09 +0000377}
378
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000379GLenum Texture::getUsage() const
380{
381 return mUsage;
382}
383
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +0000384bool Texture::isMipmapFiltered() const
385{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000386 switch (mSamplerState.minFilter)
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +0000387 {
388 case GL_NEAREST:
389 case GL_LINEAR:
390 return false;
391 case GL_NEAREST_MIPMAP_NEAREST:
392 case GL_LINEAR_MIPMAP_NEAREST:
393 case GL_NEAREST_MIPMAP_LINEAR:
394 case GL_LINEAR_MIPMAP_LINEAR:
395 return true;
396 default: UNREACHABLE();
397 return false;
398 }
399}
400
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000401void Texture::setImage(GLint unpackAlignment, const void *pixels, Image *image)
402{
403 if (pixels != NULL)
404 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000405 image->loadData(0, 0, image->getWidth(), image->getHeight(), unpackAlignment, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000406 mDirtyImages = true;
407 }
408}
409
410void Texture::setCompressedImage(GLsizei imageSize, const void *pixels, Image *image)
411{
412 if (pixels != NULL)
413 {
414 image->loadCompressedData(0, 0, image->getWidth(), image->getHeight(), pixels);
415 mDirtyImages = true;
416 }
417}
418
419bool Texture::subImage(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, Image *image)
420{
421 if (pixels != NULL)
422 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000423 image->loadData(xoffset, yoffset, width, height, unpackAlignment, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000424 mDirtyImages = true;
425 }
426
427 return true;
428}
429
430bool Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, Image *image)
431{
432 if (pixels != NULL)
433 {
434 image->loadCompressedData(xoffset, yoffset, width, height, pixels);
435 mDirtyImages = true;
436 }
437
438 return true;
439}
440
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000441TextureStorage *Texture::getNativeTexture()
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000442{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000443 // ensure the underlying texture is created
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000444
445 TextureStorage *storage = getStorage(false);
446 if (storage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000447 {
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000448 updateTexture();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000449 }
450
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000451 return storage;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000452}
453
454bool Texture::hasDirtyParameters() const
455{
456 return mDirtyParameters;
457}
458
459bool Texture::hasDirtyImages() const
460{
461 return mDirtyImages;
462}
463
464void Texture::resetDirty()
465{
466 mDirtyParameters = false;
467 mDirtyImages = false;
468}
469
470unsigned int Texture::getTextureSerial()
471{
472 TextureStorage *texture = getStorage(false);
473 return texture ? texture->getTextureSerial() : 0;
474}
475
476unsigned int Texture::getRenderTargetSerial(GLenum target)
477{
478 TextureStorage *texture = getStorage(true);
479 return texture ? texture->getRenderTargetSerial(target) : 0;
480}
481
482bool Texture::isImmutable() const
483{
484 return mImmutable;
485}
486
487GLint Texture::creationLevels(GLsizei width, GLsizei height) const
488{
489 if ((isPow2(width) && isPow2(height)) || getContext()->supportsNonPower2Texture())
490 {
491 return 0; // Maximum number of levels
492 }
493 else
494 {
495 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
496 return 1;
497 }
498}
499
500GLint Texture::creationLevels(GLsizei size) const
501{
502 return creationLevels(size, size);
503}
504
jbauman@chromium.org6bc4a142012-09-06 21:28:30 +0000505int Texture::levelCount()
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000506{
jbauman@chromium.org6bc4a142012-09-06 21:28:30 +0000507 return getBaseTexture() ? getBaseTexture()->GetLevelCount() - getLodOffset() : 0;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000508}
509
510Blit *Texture::getBlitter()
511{
512 Context *context = getContext();
513 return context->getBlitter();
514}
515
516bool Texture::copyToRenderTarget(IDirect3DSurface9 *dest, IDirect3DSurface9 *source, bool fromManaged)
517{
518 if (source && dest)
519 {
daniel@transgaming.comdabf0022012-10-17 18:29:59 +0000520 HRESULT result = D3DERR_OUTOFVIDEOMEMORY;
daniel@transgaming.com2507f412012-10-31 18:46:48 +0000521 renderer::Renderer9 *renderer = getDisplay()->getRenderer();
daniel@transgaming.com64e62902012-10-31 18:27:46 +0000522 IDirect3DDevice9 *device = renderer->getDevice(); // D3D9_REPLACE
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000523
524 if (fromManaged)
525 {
daniel@transgaming.comdabf0022012-10-17 18:29:59 +0000526 D3DSURFACE_DESC desc;
527 source->GetDesc(&desc);
528
529 IDirect3DSurface9 *surf = 0;
daniel@transgaming.com64e62902012-10-31 18:27:46 +0000530 result = device->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &surf, NULL);
daniel@transgaming.comdabf0022012-10-17 18:29:59 +0000531
532 if (SUCCEEDED(result))
533 {
daniel@transgaming.comb9d7e6f2012-10-31 19:08:32 +0000534 Image::CopyLockableSurfaces(surf, source);
daniel@transgaming.com64e62902012-10-31 18:27:46 +0000535 result = device->UpdateSurface(surf, NULL, dest, NULL);
daniel@transgaming.comdabf0022012-10-17 18:29:59 +0000536 surf->Release();
537 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000538 }
539 else
540 {
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000541 renderer->endScene();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000542 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
543 }
544
545 if (FAILED(result))
546 {
547 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
548 return false;
549 }
550 }
551
552 return true;
553}
554
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000555Texture2D::Texture2D(GLuint id) : Texture(id)
556{
557 mTexStorage = NULL;
558 mSurface = NULL;
559 mColorbufferProxy = NULL;
560 mProxyRefs = 0;
561}
562
563Texture2D::~Texture2D()
564{
565 mColorbufferProxy = NULL;
566
567 delete mTexStorage;
568 mTexStorage = NULL;
569
570 if (mSurface)
571 {
572 mSurface->setBoundTexture(NULL);
573 mSurface = NULL;
574 }
575}
576
577// We need to maintain a count of references to renderbuffers acting as
578// proxies for this texture, so that we do not attempt to use a pointer
579// to a renderbuffer proxy which has been deleted.
580void Texture2D::addProxyRef(const Renderbuffer *proxy)
581{
582 mProxyRefs++;
583}
584
585void Texture2D::releaseProxy(const Renderbuffer *proxy)
586{
587 if (mProxyRefs > 0)
588 mProxyRefs--;
589
590 if (mProxyRefs == 0)
591 mColorbufferProxy = NULL;
592}
593
594GLenum Texture2D::getTarget() const
595{
596 return GL_TEXTURE_2D;
597}
598
599GLsizei Texture2D::getWidth(GLint level) const
600{
601 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
602 return mImageArray[level].getWidth();
603 else
604 return 0;
605}
606
607GLsizei Texture2D::getHeight(GLint level) const
608{
609 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
610 return mImageArray[level].getHeight();
611 else
612 return 0;
613}
614
615GLenum Texture2D::getInternalFormat(GLint level) const
616{
617 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000618 return mImageArray[level].getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000619 else
620 return GL_NONE;
621}
622
daniel@transgaming.com20d36662012-10-31 19:51:43 +0000623GLenum Texture2D::getActualFormat(GLint level) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000624{
625 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.com20d36662012-10-31 19:51:43 +0000626 return mImageArray[level].getActualFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000627 else
628 return D3DFMT_UNKNOWN;
629}
630
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000631void Texture2D::redefineImage(GLint level, GLint internalformat, GLsizei width, GLsizei height)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000632{
633 releaseTexImage();
634
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000635 bool redefined = mImageArray[level].redefine(internalformat, width, height, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000636
637 if (mTexStorage && redefined)
638 {
639 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
640 {
641 mImageArray[i].markDirty();
642 }
643
644 delete mTexStorage;
645 mTexStorage = NULL;
646 mDirtyImages = true;
647 }
648}
649
650void Texture2D::setImage(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
651{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000652 GLint internalformat = ConvertSizedInternalFormat(format, type);
653 redefineImage(level, internalformat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000654
655 Texture::setImage(unpackAlignment, pixels, &mImageArray[level]);
656}
657
658void Texture2D::bindTexImage(egl::Surface *surface)
659{
660 releaseTexImage();
661
daniel@transgaming.com106e1f72012-10-31 18:38:36 +0000662 GLint internalformat = surface->getFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000663
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000664 mImageArray[0].redefine(internalformat, surface->getWidth(), surface->getHeight(), true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000665
666 delete mTexStorage;
daniel@transgaming.com3c720782012-10-31 18:42:34 +0000667 renderer::SwapChain *swapchain = surface->getSwapChain(); // D3D9_REPLACE
daniel@transgaming.com25ee7442012-10-31 19:51:56 +0000668 mTexStorage = new TextureStorage2D(swapchain);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000669
670 mDirtyImages = true;
671 mSurface = surface;
672 mSurface->setBoundTexture(this);
673}
674
675void Texture2D::releaseTexImage()
676{
677 if (mSurface)
678 {
679 mSurface->setBoundTexture(NULL);
680 mSurface = NULL;
681
682 if (mTexStorage)
683 {
684 delete mTexStorage;
685 mTexStorage = NULL;
686 }
687
688 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
689 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000690 mImageArray[i].redefine(GL_RGBA8_OES, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000691 }
692 }
693}
694
695void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
696{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000697 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
698 redefineImage(level, format, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000699
700 Texture::setCompressedImage(imageSize, pixels, &mImageArray[level]);
701}
702
703void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
704{
705 ASSERT(mImageArray[level].getSurface() != NULL);
706
707 if (level < levelCount())
708 {
daniel@transgaming.com0f195ad2012-10-31 19:51:59 +0000709 Image *image = &mImageArray[level];
710 if (image->updateSurface(mTexStorage, level, xoffset, yoffset, width, height))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000711 {
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000712 image->markClean();
713 }
714 }
715}
716
717void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
718{
719 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[level]))
720 {
721 commitRect(level, xoffset, yoffset, width, height);
722 }
723}
724
725void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
726{
727 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[level]))
728 {
729 commitRect(level, xoffset, yoffset, width, height);
730 }
731}
732
733void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
734{
735 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
736
737 if (!renderTarget)
738 {
739 ERR("Failed to retrieve the render target.");
740 return error(GL_OUT_OF_MEMORY);
741 }
742
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000743 GLint internalformat = ConvertSizedInternalFormat(format, GL_UNSIGNED_BYTE);
744 redefineImage(level, internalformat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000745
746 if (!mImageArray[level].isRenderableFormat())
747 {
748 mImageArray[level].copy(0, 0, x, y, width, height, renderTarget);
749 mDirtyImages = true;
750 }
751 else
752 {
753 if (!mTexStorage || !mTexStorage->isRenderTarget())
754 {
755 convertToRenderTarget();
756 }
757
758 mImageArray[level].markClean();
759
760 if (width != 0 && height != 0 && level < levelCount())
761 {
762 RECT sourceRect;
763 sourceRect.left = x;
764 sourceRect.right = x + width;
765 sourceRect.top = y;
766 sourceRect.bottom = y + height;
767
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +0000768 IDirect3DSurface9 *dest = mTexStorage->getSurfaceLevel(level, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000769
770 if (dest)
771 {
772 getBlitter()->copy(renderTarget, sourceRect, format, 0, 0, dest);
773 dest->Release();
774 }
775 }
776 }
777
778 renderTarget->Release();
779}
780
781void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
782{
783 if (xoffset + width > mImageArray[level].getWidth() || yoffset + height > mImageArray[level].getHeight())
784 {
785 return error(GL_INVALID_VALUE);
786 }
787
788 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
789
790 if (!renderTarget)
791 {
792 ERR("Failed to retrieve the render target.");
793 return error(GL_OUT_OF_MEMORY);
794 }
795
796 if (!mImageArray[level].isRenderableFormat() || (!mTexStorage && !isSamplerComplete()))
797 {
798 mImageArray[level].copy(xoffset, yoffset, x, y, width, height, renderTarget);
799 mDirtyImages = true;
800 }
801 else
802 {
803 if (!mTexStorage || !mTexStorage->isRenderTarget())
804 {
805 convertToRenderTarget();
806 }
807
808 updateTexture();
809
810 if (level < levelCount())
811 {
812 RECT sourceRect;
813 sourceRect.left = x;
814 sourceRect.right = x + width;
815 sourceRect.top = y;
816 sourceRect.bottom = y + height;
817
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +0000818 IDirect3DSurface9 *dest = mTexStorage->getSurfaceLevel(level, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000819
820 if (dest)
821 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000822 getBlitter()->copy(renderTarget, sourceRect,
823 gl::ExtractFormat(mImageArray[0].getInternalFormat()),
824 xoffset, yoffset, dest);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000825 dest->Release();
826 }
827 }
828 }
829
830 renderTarget->Release();
831}
832
833void Texture2D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height)
834{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000835 delete mTexStorage;
daniel@transgaming.comf032cb82012-10-31 19:51:52 +0000836 mTexStorage = new TextureStorage2D(levels, internalformat, mUsage, false, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000837 mImmutable = true;
838
839 for (int level = 0; level < levels; level++)
840 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000841 mImageArray[level].redefine(internalformat, width, height, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000842 width = std::max(1, width >> 1);
843 height = std::max(1, height >> 1);
844 }
845
846 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
847 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000848 mImageArray[level].redefine(GL_NONE, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000849 }
850
851 if (mTexStorage->isManaged())
852 {
853 int levels = levelCount();
854
855 for (int level = 0; level < levels; level++)
856 {
daniel@transgaming.com0f195ad2012-10-31 19:51:59 +0000857 mImageArray[level].setManagedSurface(mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000858 }
859 }
860}
861
862// Tests for 2D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85.
863bool Texture2D::isSamplerComplete() const
864{
865 GLsizei width = mImageArray[0].getWidth();
866 GLsizei height = mImageArray[0].getHeight();
867
868 if (width <= 0 || height <= 0)
869 {
870 return false;
871 }
872
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +0000873 bool mipmapping = isMipmapFiltered();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000874
daniel@transgaming.com6b1a0a02012-10-17 18:22:47 +0000875 if ((IsFloat32Format(getInternalFormat(0)) && !getContext()->supportsFloat32LinearFilter()) ||
876 (IsFloat16Format(getInternalFormat(0)) && !getContext()->supportsFloat16LinearFilter()))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000877 {
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000878 if (mSamplerState.magFilter != GL_NEAREST ||
879 (mSamplerState.minFilter != GL_NEAREST && mSamplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000880 {
881 return false;
882 }
883 }
884
885 bool npotSupport = getContext()->supportsNonPower2Texture();
886
887 if (!npotSupport)
888 {
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000889 if ((mSamplerState.wrapS != GL_CLAMP_TO_EDGE && !isPow2(width)) ||
890 (mSamplerState.wrapT != GL_CLAMP_TO_EDGE && !isPow2(height)))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000891 {
892 return false;
893 }
894 }
895
896 if (mipmapping)
897 {
898 if (!npotSupport)
899 {
900 if (!isPow2(width) || !isPow2(height))
901 {
902 return false;
903 }
904 }
905
906 if (!isMipmapComplete())
907 {
908 return false;
909 }
910 }
911
912 return true;
913}
914
915// Tests for 2D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
916bool Texture2D::isMipmapComplete() const
917{
918 if (isImmutable())
919 {
920 return true;
921 }
922
923 GLsizei width = mImageArray[0].getWidth();
924 GLsizei height = mImageArray[0].getHeight();
925
926 if (width <= 0 || height <= 0)
927 {
928 return false;
929 }
930
931 int q = log2(std::max(width, height));
932
933 for (int level = 1; level <= q; level++)
934 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000935 if (mImageArray[level].getInternalFormat() != mImageArray[0].getInternalFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000936 {
937 return false;
938 }
939
940 if (mImageArray[level].getWidth() != std::max(1, width >> level))
941 {
942 return false;
943 }
944
945 if (mImageArray[level].getHeight() != std::max(1, height >> level))
946 {
947 return false;
948 }
949 }
950
951 return true;
952}
953
954bool Texture2D::isCompressed(GLint level) const
955{
956 return IsCompressed(getInternalFormat(level));
957}
958
959bool Texture2D::isDepth(GLint level) const
960{
961 return IsDepthTexture(getInternalFormat(level));
962}
963
964IDirect3DBaseTexture9 *Texture2D::getBaseTexture() const
965{
966 return mTexStorage ? mTexStorage->getBaseTexture() : NULL;
967}
968
daniel@transgaming.comf032cb82012-10-31 19:51:52 +0000969// Constructs a native texture resource from the texture images
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000970void Texture2D::createTexture()
971{
972 GLsizei width = mImageArray[0].getWidth();
973 GLsizei height = mImageArray[0].getHeight();
daniel@transgaming.come6a09842012-09-17 21:28:55 +0000974
975 if (!(width > 0 && height > 0))
daniel@transgaming.comf032cb82012-10-31 19:51:52 +0000976 return; // do not attempt to create native textures for nonexistant data
daniel@transgaming.come6a09842012-09-17 21:28:55 +0000977
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000978 GLint levels = creationLevels(width, height);
daniel@transgaming.comf032cb82012-10-31 19:51:52 +0000979 GLenum internalformat = mImageArray[0].getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000980
981 delete mTexStorage;
daniel@transgaming.comf032cb82012-10-31 19:51:52 +0000982 mTexStorage = new TextureStorage2D(levels, internalformat, mUsage, false, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000983
984 if (mTexStorage->isManaged())
985 {
986 int levels = levelCount();
987
988 for (int level = 0; level < levels; level++)
989 {
daniel@transgaming.com0f195ad2012-10-31 19:51:59 +0000990 mImageArray[level].setManagedSurface(mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000991 }
992 }
993
994 mDirtyImages = true;
995}
996
997void Texture2D::updateTexture()
998{
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +0000999 bool mipmapping = (isMipmapFiltered() && isMipmapComplete());
1000
1001 int levels = (mipmapping ? levelCount() : 1);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001002
1003 for (int level = 0; level < levels; level++)
1004 {
1005 Image *image = &mImageArray[level];
1006
1007 if (image->isDirty())
1008 {
1009 commitRect(level, 0, 0, mImageArray[level].getWidth(), mImageArray[level].getHeight());
1010 }
1011 }
1012}
1013
1014void Texture2D::convertToRenderTarget()
1015{
1016 TextureStorage2D *newTexStorage = NULL;
1017
1018 if (mImageArray[0].getWidth() != 0 && mImageArray[0].getHeight() != 0)
1019 {
1020 GLsizei width = mImageArray[0].getWidth();
1021 GLsizei height = mImageArray[0].getHeight();
1022 GLint levels = creationLevels(width, height);
daniel@transgaming.comf032cb82012-10-31 19:51:52 +00001023 GLenum internalformat = mImageArray[0].getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001024
daniel@transgaming.comf032cb82012-10-31 19:51:52 +00001025 newTexStorage = new TextureStorage2D(levels, internalformat, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, true, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001026
1027 if (mTexStorage != NULL)
1028 {
1029 int levels = levelCount();
1030 for (int i = 0; i < levels; i++)
1031 {
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00001032 IDirect3DSurface9 *source = mTexStorage->getSurfaceLevel(i, false);
1033 IDirect3DSurface9 *dest = newTexStorage->getSurfaceLevel(i, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001034
1035 if (!copyToRenderTarget(dest, source, mTexStorage->isManaged()))
1036 {
1037 delete newTexStorage;
1038 if (source) source->Release();
1039 if (dest) dest->Release();
1040 return error(GL_OUT_OF_MEMORY);
1041 }
1042
1043 if (source) source->Release();
1044 if (dest) dest->Release();
1045 }
1046 }
1047 }
1048
1049 delete mTexStorage;
1050 mTexStorage = newTexStorage;
1051
1052 mDirtyImages = true;
1053}
1054
1055void Texture2D::generateMipmaps()
1056{
1057 if (!getContext()->supportsNonPower2Texture())
1058 {
1059 if (!isPow2(mImageArray[0].getWidth()) || !isPow2(mImageArray[0].getHeight()))
1060 {
1061 return error(GL_INVALID_OPERATION);
1062 }
1063 }
1064
1065 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1066 unsigned int q = log2(std::max(mImageArray[0].getWidth(), mImageArray[0].getHeight()));
1067 for (unsigned int i = 1; i <= q; i++)
1068 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001069 redefineImage(i, mImageArray[0].getInternalFormat(),
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001070 std::max(mImageArray[0].getWidth() >> i, 1),
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001071 std::max(mImageArray[0].getHeight() >> i, 1));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001072 }
1073
1074 if (mTexStorage && mTexStorage->isRenderTarget())
1075 {
1076 for (unsigned int i = 1; i <= q; i++)
1077 {
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00001078 IDirect3DSurface9 *upper = mTexStorage->getSurfaceLevel(i - 1, false);
1079 IDirect3DSurface9 *lower = mTexStorage->getSurfaceLevel(i, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001080
1081 if (upper != NULL && lower != NULL)
1082 {
1083 getBlitter()->boxFilter(upper, lower);
1084 }
1085
1086 if (upper != NULL) upper->Release();
1087 if (lower != NULL) lower->Release();
1088
1089 mImageArray[i].markClean();
1090 }
1091 }
1092 else
1093 {
1094 for (unsigned int i = 1; i <= q; i++)
1095 {
1096 if (mImageArray[i].getSurface() == NULL)
1097 {
1098 return error(GL_OUT_OF_MEMORY);
1099 }
1100
daniel@transgaming.com2e38b802012-10-17 18:30:06 +00001101 GenerateMip(mImageArray[i].getSurface(), mImageArray[i - 1].getSurface());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001102
1103 mImageArray[i].markDirty();
1104 }
1105 }
1106}
1107
1108Renderbuffer *Texture2D::getRenderbuffer(GLenum target)
1109{
1110 if (target != GL_TEXTURE_2D)
1111 {
1112 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
1113 }
1114
1115 if (mColorbufferProxy == NULL)
1116 {
1117 mColorbufferProxy = new Renderbuffer(id(), new RenderbufferTexture2D(this, target));
1118 }
1119
1120 return mColorbufferProxy;
1121}
1122
1123// Increments refcount on surface.
1124// caller must Release() the returned surface
1125IDirect3DSurface9 *Texture2D::getRenderTarget(GLenum target)
1126{
1127 ASSERT(target == GL_TEXTURE_2D);
1128
1129 // ensure the underlying texture is created
1130 if (getStorage(true) == NULL)
1131 {
1132 return NULL;
1133 }
1134
1135 updateTexture();
1136
1137 // ensure this is NOT a depth texture
1138 if (isDepth(0))
1139 {
1140 return NULL;
1141 }
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00001142 return mTexStorage->getSurfaceLevel(0, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001143}
1144
1145// Increments refcount on surface.
1146// caller must Release() the returned surface
1147IDirect3DSurface9 *Texture2D::getDepthStencil(GLenum target)
1148{
1149 ASSERT(target == GL_TEXTURE_2D);
1150
1151 // ensure the underlying texture is created
1152 if (getStorage(true) == NULL)
1153 {
1154 return NULL;
1155 }
1156
1157 updateTexture();
1158
1159 // ensure this is actually a depth texture
1160 if (!isDepth(0))
1161 {
1162 return NULL;
1163 }
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00001164 return mTexStorage->getSurfaceLevel(0, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001165}
1166
1167TextureStorage *Texture2D::getStorage(bool renderTarget)
1168{
1169 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
1170 {
1171 if (renderTarget)
1172 {
1173 convertToRenderTarget();
1174 }
1175 else
1176 {
1177 createTexture();
1178 }
1179 }
1180
1181 return mTexStorage;
1182}
1183
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001184TextureCubeMap::TextureCubeMap(GLuint id) : Texture(id)
1185{
1186 mTexStorage = NULL;
1187 for (int i = 0; i < 6; i++)
1188 {
1189 mFaceProxies[i] = NULL;
1190 mFaceProxyRefs[i] = 0;
1191 }
1192}
1193
1194TextureCubeMap::~TextureCubeMap()
1195{
1196 for (int i = 0; i < 6; i++)
1197 {
1198 mFaceProxies[i] = NULL;
1199 }
1200
1201 delete mTexStorage;
1202 mTexStorage = NULL;
1203}
1204
1205// We need to maintain a count of references to renderbuffers acting as
1206// proxies for this texture, so that the texture is not deleted while
1207// proxy references still exist. If the reference count drops to zero,
1208// we set our proxy pointer NULL, so that a new attempt at referencing
1209// will cause recreation.
1210void TextureCubeMap::addProxyRef(const Renderbuffer *proxy)
1211{
1212 for (int i = 0; i < 6; i++)
1213 {
1214 if (mFaceProxies[i] == proxy)
1215 mFaceProxyRefs[i]++;
1216 }
1217}
1218
1219void TextureCubeMap::releaseProxy(const Renderbuffer *proxy)
1220{
1221 for (int i = 0; i < 6; i++)
1222 {
1223 if (mFaceProxies[i] == proxy)
1224 {
1225 if (mFaceProxyRefs[i] > 0)
1226 mFaceProxyRefs[i]--;
1227
1228 if (mFaceProxyRefs[i] == 0)
1229 mFaceProxies[i] = NULL;
1230 }
1231 }
1232}
1233
1234GLenum TextureCubeMap::getTarget() const
1235{
1236 return GL_TEXTURE_CUBE_MAP;
1237}
1238
1239GLsizei TextureCubeMap::getWidth(GLenum target, GLint level) const
1240{
1241 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1242 return mImageArray[faceIndex(target)][level].getWidth();
1243 else
1244 return 0;
1245}
1246
1247GLsizei TextureCubeMap::getHeight(GLenum target, GLint level) const
1248{
1249 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1250 return mImageArray[faceIndex(target)][level].getHeight();
1251 else
1252 return 0;
1253}
1254
1255GLenum TextureCubeMap::getInternalFormat(GLenum target, GLint level) const
1256{
1257 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001258 return mImageArray[faceIndex(target)][level].getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001259 else
1260 return GL_NONE;
1261}
1262
daniel@transgaming.com20d36662012-10-31 19:51:43 +00001263GLenum TextureCubeMap::getActualFormat(GLenum target, GLint level) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001264{
1265 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.com20d36662012-10-31 19:51:43 +00001266 return mImageArray[faceIndex(target)][level].getActualFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001267 else
1268 return D3DFMT_UNKNOWN;
1269}
1270
1271void TextureCubeMap::setImagePosX(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1272{
1273 setImage(0, level, width, height, format, type, unpackAlignment, pixels);
1274}
1275
1276void TextureCubeMap::setImageNegX(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1277{
1278 setImage(1, level, width, height, format, type, unpackAlignment, pixels);
1279}
1280
1281void TextureCubeMap::setImagePosY(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1282{
1283 setImage(2, level, width, height, format, type, unpackAlignment, pixels);
1284}
1285
1286void TextureCubeMap::setImageNegY(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1287{
1288 setImage(3, level, width, height, format, type, unpackAlignment, pixels);
1289}
1290
1291void TextureCubeMap::setImagePosZ(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1292{
1293 setImage(4, level, width, height, format, type, unpackAlignment, pixels);
1294}
1295
1296void TextureCubeMap::setImageNegZ(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1297{
1298 setImage(5, level, width, height, format, type, unpackAlignment, pixels);
1299}
1300
1301void TextureCubeMap::setCompressedImage(GLenum face, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
1302{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001303 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1304 redefineImage(faceIndex(face), level, format, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001305
1306 Texture::setCompressedImage(imageSize, pixels, &mImageArray[faceIndex(face)][level]);
1307}
1308
1309void TextureCubeMap::commitRect(int face, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1310{
1311 ASSERT(mImageArray[face][level].getSurface() != NULL);
1312
1313 if (level < levelCount())
1314 {
daniel@transgaming.com0f195ad2012-10-31 19:51:59 +00001315 Image *image = &mImageArray[face][level];
1316 if (image->updateSurface(mTexStorage, face, level, xoffset, yoffset, width, height))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001317 image->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001318 }
1319}
1320
1321void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1322{
1323 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[faceIndex(target)][level]))
1324 {
1325 commitRect(faceIndex(target), level, xoffset, yoffset, width, height);
1326 }
1327}
1328
1329void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1330{
1331 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[faceIndex(target)][level]))
1332 {
1333 commitRect(faceIndex(target), level, xoffset, yoffset, width, height);
1334 }
1335}
1336
1337// Tests for cube map sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 86.
1338bool TextureCubeMap::isSamplerComplete() const
1339{
1340 int size = mImageArray[0][0].getWidth();
1341
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +00001342 bool mipmapping = isMipmapFiltered();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001343
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001344 if ((gl::ExtractType(getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0)) == GL_FLOAT && !getContext()->supportsFloat32LinearFilter()) ||
1345 (gl::ExtractType(getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0) == GL_HALF_FLOAT_OES) && !getContext()->supportsFloat16LinearFilter()))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001346 {
daniel@transgaming.comebf139f2012-10-31 18:07:32 +00001347 if (mSamplerState.magFilter != GL_NEAREST ||
1348 (mSamplerState.minFilter != GL_NEAREST && mSamplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001349 {
1350 return false;
1351 }
1352 }
1353
1354 if (!isPow2(size) && !getContext()->supportsNonPower2Texture())
1355 {
daniel@transgaming.comebf139f2012-10-31 18:07:32 +00001356 if (mSamplerState.wrapS != GL_CLAMP_TO_EDGE || mSamplerState.wrapT != GL_CLAMP_TO_EDGE || mipmapping)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001357 {
1358 return false;
1359 }
1360 }
1361
1362 if (!mipmapping)
1363 {
1364 if (!isCubeComplete())
1365 {
1366 return false;
1367 }
1368 }
1369 else
1370 {
1371 if (!isMipmapCubeComplete()) // Also tests for isCubeComplete()
1372 {
1373 return false;
1374 }
1375 }
1376
1377 return true;
1378}
1379
1380// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1381bool TextureCubeMap::isCubeComplete() const
1382{
1383 if (mImageArray[0][0].getWidth() <= 0 || mImageArray[0][0].getHeight() != mImageArray[0][0].getWidth())
1384 {
1385 return false;
1386 }
1387
1388 for (unsigned int face = 1; face < 6; face++)
1389 {
1390 if (mImageArray[face][0].getWidth() != mImageArray[0][0].getWidth() ||
1391 mImageArray[face][0].getWidth() != mImageArray[0][0].getHeight() ||
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001392 mImageArray[face][0].getInternalFormat() != mImageArray[0][0].getInternalFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001393 {
1394 return false;
1395 }
1396 }
1397
1398 return true;
1399}
1400
1401bool TextureCubeMap::isMipmapCubeComplete() const
1402{
1403 if (isImmutable())
1404 {
1405 return true;
1406 }
1407
1408 if (!isCubeComplete())
1409 {
1410 return false;
1411 }
1412
1413 GLsizei size = mImageArray[0][0].getWidth();
1414
1415 int q = log2(size);
1416
1417 for (int face = 0; face < 6; face++)
1418 {
1419 for (int level = 1; level <= q; level++)
1420 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001421 if (mImageArray[face][level].getInternalFormat() != mImageArray[0][0].getInternalFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001422 {
1423 return false;
1424 }
1425
1426 if (mImageArray[face][level].getWidth() != std::max(1, size >> level))
1427 {
1428 return false;
1429 }
1430 }
1431 }
1432
1433 return true;
1434}
1435
1436bool TextureCubeMap::isCompressed(GLenum target, GLint level) const
1437{
1438 return IsCompressed(getInternalFormat(target, level));
1439}
1440
1441IDirect3DBaseTexture9 *TextureCubeMap::getBaseTexture() const
1442{
1443 return mTexStorage ? mTexStorage->getBaseTexture() : NULL;
1444}
1445
daniel@transgaming.comf032cb82012-10-31 19:51:52 +00001446// Constructs a native texture resource from the texture images, or returns an existing one
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001447void TextureCubeMap::createTexture()
1448{
1449 GLsizei size = mImageArray[0][0].getWidth();
daniel@transgaming.come6a09842012-09-17 21:28:55 +00001450
1451 if (!(size > 0))
daniel@transgaming.comf032cb82012-10-31 19:51:52 +00001452 return; // do not attempt to create native textures for nonexistant data
daniel@transgaming.come6a09842012-09-17 21:28:55 +00001453
sminns@adobe.comce1189b2012-09-18 20:06:35 +00001454 GLint levels = creationLevels(size);
daniel@transgaming.comf032cb82012-10-31 19:51:52 +00001455 GLenum internalformat = mImageArray[0][0].getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001456
1457 delete mTexStorage;
daniel@transgaming.comf032cb82012-10-31 19:51:52 +00001458 mTexStorage = new TextureStorageCubeMap(levels, internalformat, mUsage, false, size);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001459
1460 if (mTexStorage->isManaged())
1461 {
1462 int levels = levelCount();
1463
1464 for (int face = 0; face < 6; face++)
1465 {
1466 for (int level = 0; level < levels; level++)
1467 {
daniel@transgaming.com0f195ad2012-10-31 19:51:59 +00001468 mImageArray[face][level].setManagedSurface(mTexStorage, face, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001469 }
1470 }
1471 }
1472
1473 mDirtyImages = true;
1474}
1475
1476void TextureCubeMap::updateTexture()
1477{
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +00001478 bool mipmapping = isMipmapFiltered() && isMipmapCubeComplete();
1479
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001480 for (int face = 0; face < 6; face++)
1481 {
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +00001482 int levels = (mipmapping ? levelCount() : 1);
1483
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001484 for (int level = 0; level < levels; level++)
1485 {
1486 Image *image = &mImageArray[face][level];
1487
1488 if (image->isDirty())
1489 {
1490 commitRect(face, level, 0, 0, image->getWidth(), image->getHeight());
1491 }
1492 }
1493 }
1494}
1495
1496void TextureCubeMap::convertToRenderTarget()
1497{
1498 TextureStorageCubeMap *newTexStorage = NULL;
1499
1500 if (mImageArray[0][0].getWidth() != 0)
1501 {
1502 GLsizei size = mImageArray[0][0].getWidth();
sminns@adobe.comce1189b2012-09-18 20:06:35 +00001503 GLint levels = creationLevels(size);
daniel@transgaming.comf032cb82012-10-31 19:51:52 +00001504 GLenum internalformat = mImageArray[0][0].getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001505
daniel@transgaming.comf032cb82012-10-31 19:51:52 +00001506 newTexStorage = new TextureStorageCubeMap(levels, internalformat, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, true, size);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001507
1508 if (mTexStorage != NULL)
1509 {
1510 int levels = levelCount();
1511 for (int f = 0; f < 6; f++)
1512 {
1513 for (int i = 0; i < levels; i++)
1514 {
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00001515 IDirect3DSurface9 *source = mTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i, false);
1516 IDirect3DSurface9 *dest = newTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001517
1518 if (!copyToRenderTarget(dest, source, mTexStorage->isManaged()))
1519 {
1520 delete newTexStorage;
1521 if (source) source->Release();
1522 if (dest) dest->Release();
1523 return error(GL_OUT_OF_MEMORY);
1524 }
1525
1526 if (source) source->Release();
1527 if (dest) dest->Release();
1528 }
1529 }
1530 }
1531 }
1532
1533 delete mTexStorage;
1534 mTexStorage = newTexStorage;
1535
1536 mDirtyImages = true;
1537}
1538
1539void TextureCubeMap::setImage(int faceIndex, GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1540{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001541 GLint internalformat = ConvertSizedInternalFormat(format, type);
1542 redefineImage(faceIndex, level, internalformat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001543
1544 Texture::setImage(unpackAlignment, pixels, &mImageArray[faceIndex][level]);
1545}
1546
1547unsigned int TextureCubeMap::faceIndex(GLenum face)
1548{
1549 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
1550 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
1551 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
1552 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
1553 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
1554
1555 return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
1556}
1557
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001558void TextureCubeMap::redefineImage(int face, GLint level, GLint internalformat, GLsizei width, GLsizei height)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001559{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001560 bool redefined = mImageArray[face][level].redefine(internalformat, width, height, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001561
1562 if (mTexStorage && redefined)
1563 {
1564 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1565 {
1566 for (int f = 0; f < 6; f++)
1567 {
1568 mImageArray[f][i].markDirty();
1569 }
1570 }
1571
1572 delete mTexStorage;
1573 mTexStorage = NULL;
1574
1575 mDirtyImages = true;
1576 }
1577}
1578
1579void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1580{
1581 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
1582
1583 if (!renderTarget)
1584 {
1585 ERR("Failed to retrieve the render target.");
1586 return error(GL_OUT_OF_MEMORY);
1587 }
1588
1589 unsigned int faceindex = faceIndex(target);
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001590 GLint internalformat = gl::ConvertSizedInternalFormat(format, GL_UNSIGNED_BYTE);
1591 redefineImage(faceindex, level, internalformat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001592
1593 if (!mImageArray[faceindex][level].isRenderableFormat())
1594 {
1595 mImageArray[faceindex][level].copy(0, 0, x, y, width, height, renderTarget);
1596 mDirtyImages = true;
1597 }
1598 else
1599 {
1600 if (!mTexStorage || !mTexStorage->isRenderTarget())
1601 {
1602 convertToRenderTarget();
1603 }
1604
1605 mImageArray[faceindex][level].markClean();
1606
1607 ASSERT(width == height);
1608
1609 if (width > 0 && level < levelCount())
1610 {
1611 RECT sourceRect;
1612 sourceRect.left = x;
1613 sourceRect.right = x + width;
1614 sourceRect.top = y;
1615 sourceRect.bottom = y + height;
1616
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00001617 IDirect3DSurface9 *dest = mTexStorage->getCubeMapSurface(target, level, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001618
1619 if (dest)
1620 {
1621 getBlitter()->copy(renderTarget, sourceRect, format, 0, 0, dest);
1622 dest->Release();
1623 }
1624 }
1625 }
1626
1627 renderTarget->Release();
1628}
1629
1630void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1631{
1632 GLsizei size = mImageArray[faceIndex(target)][level].getWidth();
1633
1634 if (xoffset + width > size || yoffset + height > size)
1635 {
1636 return error(GL_INVALID_VALUE);
1637 }
1638
1639 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
1640
1641 if (!renderTarget)
1642 {
1643 ERR("Failed to retrieve the render target.");
1644 return error(GL_OUT_OF_MEMORY);
1645 }
1646
1647 unsigned int faceindex = faceIndex(target);
1648
1649 if (!mImageArray[faceindex][level].isRenderableFormat() || (!mTexStorage && !isSamplerComplete()))
1650 {
1651 mImageArray[faceindex][level].copy(0, 0, x, y, width, height, renderTarget);
1652 mDirtyImages = true;
1653 }
1654 else
1655 {
1656 if (!mTexStorage || !mTexStorage->isRenderTarget())
1657 {
1658 convertToRenderTarget();
1659 }
1660
1661 updateTexture();
1662
1663 if (level < levelCount())
1664 {
1665 RECT sourceRect;
1666 sourceRect.left = x;
1667 sourceRect.right = x + width;
1668 sourceRect.top = y;
1669 sourceRect.bottom = y + height;
1670
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00001671 IDirect3DSurface9 *dest = mTexStorage->getCubeMapSurface(target, level, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001672
1673 if (dest)
1674 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001675 getBlitter()->copy(renderTarget, sourceRect, gl::ExtractFormat(mImageArray[0][0].getInternalFormat()), xoffset, yoffset, dest);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001676 dest->Release();
1677 }
1678 }
1679 }
1680
1681 renderTarget->Release();
1682}
1683
1684void TextureCubeMap::storage(GLsizei levels, GLenum internalformat, GLsizei size)
1685{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001686 delete mTexStorage;
daniel@transgaming.comf032cb82012-10-31 19:51:52 +00001687 mTexStorage = new TextureStorageCubeMap(levels, internalformat, mUsage, false, size);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001688 mImmutable = true;
1689
1690 for (int level = 0; level < levels; level++)
1691 {
1692 for (int face = 0; face < 6; face++)
1693 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001694 mImageArray[face][level].redefine(internalformat, size, size, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001695 size = std::max(1, size >> 1);
1696 }
1697 }
1698
1699 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1700 {
1701 for (int face = 0; face < 6; face++)
1702 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001703 mImageArray[face][level].redefine(GL_NONE, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001704 }
1705 }
1706
1707 if (mTexStorage->isManaged())
1708 {
1709 int levels = levelCount();
1710
1711 for (int face = 0; face < 6; face++)
1712 {
1713 for (int level = 0; level < levels; level++)
1714 {
daniel@transgaming.com0f195ad2012-10-31 19:51:59 +00001715 mImageArray[face][level].setManagedSurface(mTexStorage, face, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001716 }
1717 }
1718 }
1719}
1720
1721void TextureCubeMap::generateMipmaps()
1722{
1723 if (!isCubeComplete())
1724 {
1725 return error(GL_INVALID_OPERATION);
1726 }
1727
1728 if (!getContext()->supportsNonPower2Texture())
1729 {
1730 if (!isPow2(mImageArray[0][0].getWidth()))
1731 {
1732 return error(GL_INVALID_OPERATION);
1733 }
1734 }
1735
1736 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1737 unsigned int q = log2(mImageArray[0][0].getWidth());
1738 for (unsigned int f = 0; f < 6; f++)
1739 {
1740 for (unsigned int i = 1; i <= q; i++)
1741 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001742 redefineImage(f, i, mImageArray[f][0].getInternalFormat(),
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001743 std::max(mImageArray[f][0].getWidth() >> i, 1),
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001744 std::max(mImageArray[f][0].getWidth() >> i, 1));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001745 }
1746 }
1747
1748 if (mTexStorage && mTexStorage->isRenderTarget())
1749 {
1750 for (unsigned int f = 0; f < 6; f++)
1751 {
1752 for (unsigned int i = 1; i <= q; i++)
1753 {
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00001754 IDirect3DSurface9 *upper = mTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i - 1, false);
1755 IDirect3DSurface9 *lower = mTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001756
1757 if (upper != NULL && lower != NULL)
1758 {
1759 getBlitter()->boxFilter(upper, lower);
1760 }
1761
1762 if (upper != NULL) upper->Release();
1763 if (lower != NULL) lower->Release();
1764
1765 mImageArray[f][i].markClean();
1766 }
1767 }
1768 }
1769 else
1770 {
1771 for (unsigned int f = 0; f < 6; f++)
1772 {
1773 for (unsigned int i = 1; i <= q; i++)
1774 {
1775 if (mImageArray[f][i].getSurface() == NULL)
1776 {
1777 return error(GL_OUT_OF_MEMORY);
1778 }
1779
daniel@transgaming.com2e38b802012-10-17 18:30:06 +00001780 GenerateMip(mImageArray[f][i].getSurface(), mImageArray[f][i - 1].getSurface());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001781
1782 mImageArray[f][i].markDirty();
1783 }
1784 }
1785 }
1786}
1787
1788Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target)
1789{
1790 if (!IsCubemapTextureTarget(target))
1791 {
1792 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
1793 }
1794
1795 unsigned int face = faceIndex(target);
1796
1797 if (mFaceProxies[face] == NULL)
1798 {
1799 mFaceProxies[face] = new Renderbuffer(id(), new RenderbufferTextureCubeMap(this, target));
1800 }
1801
1802 return mFaceProxies[face];
1803}
1804
1805// Increments refcount on surface.
1806// caller must Release() the returned surface
1807IDirect3DSurface9 *TextureCubeMap::getRenderTarget(GLenum target)
1808{
1809 ASSERT(IsCubemapTextureTarget(target));
1810
1811 // ensure the underlying texture is created
1812 if (getStorage(true) == NULL)
1813 {
1814 return NULL;
1815 }
1816
1817 updateTexture();
1818
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00001819 return mTexStorage->getCubeMapSurface(target, 0, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001820}
1821
1822TextureStorage *TextureCubeMap::getStorage(bool renderTarget)
1823{
1824 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
1825 {
1826 if (renderTarget)
1827 {
1828 convertToRenderTarget();
1829 }
1830 else
1831 {
1832 createTexture();
1833 }
1834 }
1835
1836 return mTexStorage;
1837}
1838
1839}