blob: 3aea280c4f1a49838be53e46c0a2781de76d7cae [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 +000027static inline DWORD GetTextureUsage(D3DFORMAT d3dfmt, GLenum glusage, bool forceRenderable)
28{
29 DWORD d3dusage = 0;
30
31 if (d3dfmt == D3DFMT_INTZ)
32 {
33 d3dusage |= D3DUSAGE_DEPTHSTENCIL;
34 }
daniel@transgaming.comb9d7e6f2012-10-31 19:08:32 +000035 else if(forceRenderable || (Texture::IsTextureFormatRenderable(d3dfmt) && (glusage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE)))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000036 {
37 d3dusage |= D3DUSAGE_RENDERTARGET;
38 }
39 return d3dusage;
40}
41
daniel@transgaming.com2e38b802012-10-17 18:30:06 +000042namespace
43{
44struct L8
45{
46 unsigned char L;
47
48 static void average(L8 *dst, const L8 *src1, const L8 *src2)
49 {
50 dst->L = ((src1->L ^ src2->L) >> 1) + (src1->L & src2->L);
51 }
52};
53
54struct A8L8
55{
56 unsigned char L;
57 unsigned char A;
58
59 static void average(A8L8 *dst, const A8L8 *src1, const A8L8 *src2)
60 {
61 *(unsigned short*)dst = (((*(unsigned short*)src1 ^ *(unsigned short*)src2) & 0xFEFE) >> 1) + (*(unsigned short*)src1 & *(unsigned short*)src2);
62 }
63};
64
65struct A8R8G8B8
66{
67 unsigned char B;
68 unsigned char G;
69 unsigned char R;
70 unsigned char A;
71
72 static void average(A8R8G8B8 *dst, const A8R8G8B8 *src1, const A8R8G8B8 *src2)
73 {
74 *(unsigned int*)dst = (((*(unsigned int*)src1 ^ *(unsigned int*)src2) & 0xFEFEFEFE) >> 1) + (*(unsigned int*)src1 & *(unsigned int*)src2);
75 }
76};
77
78struct A16B16G16R16F
79{
80 unsigned short R;
81 unsigned short G;
82 unsigned short B;
83 unsigned short A;
84
85 static void average(A16B16G16R16F *dst, const A16B16G16R16F *src1, const A16B16G16R16F *src2)
86 {
87 dst->R = float32ToFloat16((float16ToFloat32(src1->R) + float16ToFloat32(src2->R)) * 0.5f);
88 dst->G = float32ToFloat16((float16ToFloat32(src1->G) + float16ToFloat32(src2->G)) * 0.5f);
89 dst->B = float32ToFloat16((float16ToFloat32(src1->B) + float16ToFloat32(src2->B)) * 0.5f);
90 dst->A = float32ToFloat16((float16ToFloat32(src1->A) + float16ToFloat32(src2->A)) * 0.5f);
91 }
92};
93
94struct A32B32G32R32F
95{
96 float R;
97 float G;
98 float B;
99 float A;
100
101 static void average(A32B32G32R32F *dst, const A32B32G32R32F *src1, const A32B32G32R32F *src2)
102 {
103 dst->R = (src1->R + src2->R) * 0.5f;
104 dst->G = (src1->G + src2->G) * 0.5f;
105 dst->B = (src1->B + src2->B) * 0.5f;
106 dst->A = (src1->A + src2->A) * 0.5f;
107 }
108};
109
110template <typename T>
111void GenerateMip(unsigned int sourceWidth, unsigned int sourceHeight,
112 const unsigned char *sourceData, int sourcePitch,
113 unsigned char *destData, int destPitch)
114{
115 unsigned int mipWidth = std::max(1U, sourceWidth >> 1);
116 unsigned int mipHeight = std::max(1U, sourceHeight >> 1);
117
118 if (sourceHeight == 1)
119 {
120 ASSERT(sourceWidth != 1);
121
122 const T *src = (const T*)sourceData;
123 T *dst = (T*)destData;
124
125 for (unsigned int x = 0; x < mipWidth; x++)
126 {
127 T::average(&dst[x], &src[x * 2], &src[x * 2 + 1]);
128 }
129 }
130 else if (sourceWidth == 1)
131 {
132 ASSERT(sourceHeight != 1);
133
134 for (unsigned int y = 0; y < mipHeight; y++)
135 {
136 const T *src0 = (const T*)(sourceData + y * 2 * sourcePitch);
137 const T *src1 = (const T*)(sourceData + y * 2 * sourcePitch + sourcePitch);
138 T *dst = (T*)(destData + y * destPitch);
139
140 T::average(dst, src0, src1);
141 }
142 }
143 else
144 {
145 for (unsigned int y = 0; y < mipHeight; y++)
146 {
147 const T *src0 = (const T*)(sourceData + y * 2 * sourcePitch);
148 const T *src1 = (const T*)(sourceData + y * 2 * sourcePitch + sourcePitch);
149 T *dst = (T*)(destData + y * destPitch);
150
151 for (unsigned int x = 0; x < mipWidth; x++)
152 {
153 T tmp0;
154 T tmp1;
155
156 T::average(&tmp0, &src0[x * 2], &src0[x * 2 + 1]);
157 T::average(&tmp1, &src1[x * 2], &src1[x * 2 + 1]);
158 T::average(&dst[x], &tmp0, &tmp1);
159 }
160 }
161 }
162}
163
164void GenerateMip(IDirect3DSurface9 *destSurface, IDirect3DSurface9 *sourceSurface)
165{
166 D3DSURFACE_DESC destDesc;
167 HRESULT result = destSurface->GetDesc(&destDesc);
168 ASSERT(SUCCEEDED(result));
169
170 D3DSURFACE_DESC sourceDesc;
171 result = sourceSurface->GetDesc(&sourceDesc);
172 ASSERT(SUCCEEDED(result));
173
174 ASSERT(sourceDesc.Format == destDesc.Format);
daniel@transgaming.com2e38b802012-10-17 18:30:06 +0000175 ASSERT(sourceDesc.Width == 1 || sourceDesc.Width / 2 == destDesc.Width);
176 ASSERT(sourceDesc.Height == 1 || sourceDesc.Height / 2 == destDesc.Height);
177
178 D3DLOCKED_RECT sourceLocked = {0};
179 result = sourceSurface->LockRect(&sourceLocked, NULL, D3DLOCK_READONLY);
180 ASSERT(SUCCEEDED(result));
181
182 D3DLOCKED_RECT destLocked = {0};
183 result = destSurface->LockRect(&destLocked, NULL, 0);
184 ASSERT(SUCCEEDED(result));
185
186 const unsigned char *sourceData = reinterpret_cast<const unsigned char*>(sourceLocked.pBits);
187 unsigned char *destData = reinterpret_cast<unsigned char*>(destLocked.pBits);
188
189 if (sourceData && destData)
190 {
191 switch (sourceDesc.Format)
192 {
193 case D3DFMT_L8:
194 GenerateMip<L8>(sourceDesc.Width, sourceDesc.Height, sourceData, sourceLocked.Pitch, destData, destLocked.Pitch);
195 break;
196 case D3DFMT_A8L8:
197 GenerateMip<A8L8>(sourceDesc.Width, sourceDesc.Height, sourceData, sourceLocked.Pitch, destData, destLocked.Pitch);
198 break;
199 case D3DFMT_A8R8G8B8:
200 case D3DFMT_X8R8G8B8:
201 GenerateMip<A8R8G8B8>(sourceDesc.Width, sourceDesc.Height, sourceData, sourceLocked.Pitch, destData, destLocked.Pitch);
202 break;
203 case D3DFMT_A16B16G16R16F:
204 GenerateMip<A16B16G16R16F>(sourceDesc.Width, sourceDesc.Height, sourceData, sourceLocked.Pitch, destData, destLocked.Pitch);
205 break;
206 case D3DFMT_A32B32G32R32F:
207 GenerateMip<A32B32G32R32F>(sourceDesc.Width, sourceDesc.Height, sourceData, sourceLocked.Pitch, destData, destLocked.Pitch);
208 break;
209 default:
210 UNREACHABLE();
211 break;
212 }
213
214 destSurface->UnlockRect();
215 sourceSurface->UnlockRect();
216 }
217}
218}
219
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000220Texture::Texture(GLuint id) : RefCountObject(id)
221{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000222 mSamplerState.minFilter = GL_NEAREST_MIPMAP_LINEAR;
223 mSamplerState.magFilter = GL_LINEAR;
224 mSamplerState.wrapS = GL_REPEAT;
225 mSamplerState.wrapT = GL_REPEAT;
226 mSamplerState.maxAnisotropy = 1.0f;
227 mSamplerState.lodOffset = 0;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000228 mDirtyParameters = true;
229 mUsage = GL_NONE;
230
231 mDirtyImages = true;
232
233 mImmutable = false;
234}
235
236Texture::~Texture()
237{
238}
239
daniel@transgaming.comb9d7e6f2012-10-31 19:08:32 +0000240D3DFORMAT Texture::ConvertTextureInternalFormat(GLint internalformat)
241{
242 switch (internalformat)
243 {
244 case GL_DEPTH_COMPONENT16:
245 case GL_DEPTH_COMPONENT32_OES:
246 case GL_DEPTH24_STENCIL8_OES:
247 return D3DFMT_INTZ;
248 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
249 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
250 return D3DFMT_DXT1;
251 case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
252 return D3DFMT_DXT3;
253 case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
254 return D3DFMT_DXT5;
255 case GL_RGBA32F_EXT:
256 case GL_RGB32F_EXT:
257 case GL_ALPHA32F_EXT:
258 case GL_LUMINANCE32F_EXT:
259 case GL_LUMINANCE_ALPHA32F_EXT:
260 return D3DFMT_A32B32G32R32F;
261 case GL_RGBA16F_EXT:
262 case GL_RGB16F_EXT:
263 case GL_ALPHA16F_EXT:
264 case GL_LUMINANCE16F_EXT:
265 case GL_LUMINANCE_ALPHA16F_EXT:
266 return D3DFMT_A16B16G16R16F;
267 case GL_LUMINANCE8_EXT:
268 if (getContext()->supportsLuminanceTextures())
269 {
270 return D3DFMT_L8;
271 }
272 break;
273 case GL_LUMINANCE8_ALPHA8_EXT:
274 if (getContext()->supportsLuminanceAlphaTextures())
275 {
276 return D3DFMT_A8L8;
277 }
278 break;
279 case GL_RGB8_OES:
280 case GL_RGB565:
281 return D3DFMT_X8R8G8B8;
282 }
283
284 return D3DFMT_A8R8G8B8;
285}
286
287bool Texture::IsTextureFormatRenderable(D3DFORMAT format)
288{
289 if (format == D3DFMT_INTZ)
290 {
291 return true;
292 }
293 switch(format)
294 {
295 case D3DFMT_L8:
296 case D3DFMT_A8L8:
297 case D3DFMT_DXT1:
298 case D3DFMT_DXT3:
299 case D3DFMT_DXT5:
300 return false;
301 case D3DFMT_A8R8G8B8:
302 case D3DFMT_X8R8G8B8:
303 case D3DFMT_A16B16G16R16F:
304 case D3DFMT_A32B32G32R32F:
305 return true;
306 default:
307 UNREACHABLE();
308 }
309
310 return false;
311}
312
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000313// Returns true on successful filter state update (valid enum parameter)
314bool Texture::setMinFilter(GLenum filter)
315{
316 switch (filter)
317 {
318 case GL_NEAREST:
319 case GL_LINEAR:
320 case GL_NEAREST_MIPMAP_NEAREST:
321 case GL_LINEAR_MIPMAP_NEAREST:
322 case GL_NEAREST_MIPMAP_LINEAR:
323 case GL_LINEAR_MIPMAP_LINEAR:
324 {
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000325 if (mSamplerState.minFilter != filter)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000326 {
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000327 mSamplerState.minFilter = filter;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000328 mDirtyParameters = true;
329 }
330 return true;
331 }
332 default:
333 return false;
334 }
335}
336
337// Returns true on successful filter state update (valid enum parameter)
338bool Texture::setMagFilter(GLenum filter)
339{
340 switch (filter)
341 {
342 case GL_NEAREST:
343 case GL_LINEAR:
344 {
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000345 if (mSamplerState.magFilter != filter)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000346 {
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000347 mSamplerState.magFilter = filter;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000348 mDirtyParameters = true;
349 }
350 return true;
351 }
352 default:
353 return false;
354 }
355}
356
357// Returns true on successful wrap state update (valid enum parameter)
358bool Texture::setWrapS(GLenum wrap)
359{
360 switch (wrap)
361 {
362 case GL_REPEAT:
363 case GL_CLAMP_TO_EDGE:
364 case GL_MIRRORED_REPEAT:
365 {
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000366 if (mSamplerState.wrapS != wrap)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000367 {
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000368 mSamplerState.wrapS = wrap;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000369 mDirtyParameters = true;
370 }
371 return true;
372 }
373 default:
374 return false;
375 }
376}
377
378// Returns true on successful wrap state update (valid enum parameter)
379bool Texture::setWrapT(GLenum wrap)
380{
381 switch (wrap)
382 {
383 case GL_REPEAT:
384 case GL_CLAMP_TO_EDGE:
385 case GL_MIRRORED_REPEAT:
386 {
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000387 if (mSamplerState.wrapT != wrap)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000388 {
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000389 mSamplerState.wrapT = wrap;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000390 mDirtyParameters = true;
391 }
392 return true;
393 }
394 default:
395 return false;
396 }
397}
398
daniel@transgaming.com07ab8412012-07-12 15:17:09 +0000399// Returns true on successful max anisotropy update (valid anisotropy value)
400bool Texture::setMaxAnisotropy(float textureMaxAnisotropy, float contextMaxAnisotropy)
401{
402 textureMaxAnisotropy = std::min(textureMaxAnisotropy, contextMaxAnisotropy);
403 if (textureMaxAnisotropy < 1.0f)
404 {
405 return false;
406 }
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000407 if (mSamplerState.maxAnisotropy != textureMaxAnisotropy)
daniel@transgaming.com07ab8412012-07-12 15:17:09 +0000408 {
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000409 mSamplerState.maxAnisotropy = textureMaxAnisotropy;
daniel@transgaming.com07ab8412012-07-12 15:17:09 +0000410 mDirtyParameters = true;
411 }
412 return true;
413}
414
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000415// Returns true on successful usage state update (valid enum parameter)
416bool Texture::setUsage(GLenum usage)
417{
418 switch (usage)
419 {
420 case GL_NONE:
421 case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
422 mUsage = usage;
423 return true;
424 default:
425 return false;
426 }
427}
428
429GLenum Texture::getMinFilter() const
430{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000431 return mSamplerState.minFilter;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000432}
433
434GLenum Texture::getMagFilter() const
435{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000436 return mSamplerState.magFilter;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000437}
438
439GLenum Texture::getWrapS() const
440{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000441 return mSamplerState.wrapS;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000442}
443
444GLenum Texture::getWrapT() const
445{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000446 return mSamplerState.wrapT;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000447}
448
daniel@transgaming.com07ab8412012-07-12 15:17:09 +0000449float Texture::getMaxAnisotropy() const
450{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000451 return mSamplerState.maxAnisotropy;
452}
453
454int Texture::getLodOffset()
455{
456 TextureStorage *texture = getStorage(false);
457 return texture ? texture->getLodOffset() : 0;
458}
459
460void Texture::getSamplerState(SamplerState *sampler)
461{
462 *sampler = mSamplerState;
463 sampler->lodOffset = getLodOffset();
daniel@transgaming.com07ab8412012-07-12 15:17:09 +0000464}
465
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000466GLenum Texture::getUsage() const
467{
468 return mUsage;
469}
470
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +0000471bool Texture::isMipmapFiltered() const
472{
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000473 switch (mSamplerState.minFilter)
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +0000474 {
475 case GL_NEAREST:
476 case GL_LINEAR:
477 return false;
478 case GL_NEAREST_MIPMAP_NEAREST:
479 case GL_LINEAR_MIPMAP_NEAREST:
480 case GL_NEAREST_MIPMAP_LINEAR:
481 case GL_LINEAR_MIPMAP_LINEAR:
482 return true;
483 default: UNREACHABLE();
484 return false;
485 }
486}
487
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000488void Texture::setImage(GLint unpackAlignment, const void *pixels, Image *image)
489{
490 if (pixels != NULL)
491 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000492 image->loadData(0, 0, image->getWidth(), image->getHeight(), unpackAlignment, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000493 mDirtyImages = true;
494 }
495}
496
497void Texture::setCompressedImage(GLsizei imageSize, const void *pixels, Image *image)
498{
499 if (pixels != NULL)
500 {
501 image->loadCompressedData(0, 0, image->getWidth(), image->getHeight(), pixels);
502 mDirtyImages = true;
503 }
504}
505
506bool Texture::subImage(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, Image *image)
507{
508 if (pixels != NULL)
509 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000510 image->loadData(xoffset, yoffset, width, height, unpackAlignment, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000511 mDirtyImages = true;
512 }
513
514 return true;
515}
516
517bool Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, Image *image)
518{
519 if (pixels != NULL)
520 {
521 image->loadCompressedData(xoffset, yoffset, width, height, pixels);
522 mDirtyImages = true;
523 }
524
525 return true;
526}
527
daniel@transgaming.coma734f272012-10-31 18:07:48 +0000528// D3D9_REPLACE
529IDirect3DBaseTexture9 *Texture::getD3DTexture()
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000530{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000531 // ensure the underlying texture is created
532 if (getStorage(false) == NULL)
533 {
534 return NULL;
535 }
536
537 updateTexture();
538
539 return getBaseTexture();
540}
541
542bool Texture::hasDirtyParameters() const
543{
544 return mDirtyParameters;
545}
546
547bool Texture::hasDirtyImages() const
548{
549 return mDirtyImages;
550}
551
552void Texture::resetDirty()
553{
554 mDirtyParameters = false;
555 mDirtyImages = false;
556}
557
558unsigned int Texture::getTextureSerial()
559{
560 TextureStorage *texture = getStorage(false);
561 return texture ? texture->getTextureSerial() : 0;
562}
563
564unsigned int Texture::getRenderTargetSerial(GLenum target)
565{
566 TextureStorage *texture = getStorage(true);
567 return texture ? texture->getRenderTargetSerial(target) : 0;
568}
569
570bool Texture::isImmutable() const
571{
572 return mImmutable;
573}
574
575GLint Texture::creationLevels(GLsizei width, GLsizei height) const
576{
577 if ((isPow2(width) && isPow2(height)) || getContext()->supportsNonPower2Texture())
578 {
579 return 0; // Maximum number of levels
580 }
581 else
582 {
583 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
584 return 1;
585 }
586}
587
588GLint Texture::creationLevels(GLsizei size) const
589{
590 return creationLevels(size, size);
591}
592
jbauman@chromium.org6bc4a142012-09-06 21:28:30 +0000593int Texture::levelCount()
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000594{
jbauman@chromium.org6bc4a142012-09-06 21:28:30 +0000595 return getBaseTexture() ? getBaseTexture()->GetLevelCount() - getLodOffset() : 0;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000596}
597
598Blit *Texture::getBlitter()
599{
600 Context *context = getContext();
601 return context->getBlitter();
602}
603
604bool Texture::copyToRenderTarget(IDirect3DSurface9 *dest, IDirect3DSurface9 *source, bool fromManaged)
605{
606 if (source && dest)
607 {
daniel@transgaming.comdabf0022012-10-17 18:29:59 +0000608 HRESULT result = D3DERR_OUTOFVIDEOMEMORY;
daniel@transgaming.com2507f412012-10-31 18:46:48 +0000609 renderer::Renderer9 *renderer = getDisplay()->getRenderer();
daniel@transgaming.com64e62902012-10-31 18:27:46 +0000610 IDirect3DDevice9 *device = renderer->getDevice(); // D3D9_REPLACE
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000611
612 if (fromManaged)
613 {
daniel@transgaming.comdabf0022012-10-17 18:29:59 +0000614 D3DSURFACE_DESC desc;
615 source->GetDesc(&desc);
616
617 IDirect3DSurface9 *surf = 0;
daniel@transgaming.com64e62902012-10-31 18:27:46 +0000618 result = device->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &surf, NULL);
daniel@transgaming.comdabf0022012-10-17 18:29:59 +0000619
620 if (SUCCEEDED(result))
621 {
daniel@transgaming.comb9d7e6f2012-10-31 19:08:32 +0000622 Image::CopyLockableSurfaces(surf, source);
daniel@transgaming.com64e62902012-10-31 18:27:46 +0000623 result = device->UpdateSurface(surf, NULL, dest, NULL);
daniel@transgaming.comdabf0022012-10-17 18:29:59 +0000624 surf->Release();
625 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000626 }
627 else
628 {
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000629 renderer->endScene();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000630 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
631 }
632
633 if (FAILED(result))
634 {
635 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
636 return false;
637 }
638 }
639
640 return true;
641}
642
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000643Texture2D::Texture2D(GLuint id) : Texture(id)
644{
645 mTexStorage = NULL;
646 mSurface = NULL;
647 mColorbufferProxy = NULL;
648 mProxyRefs = 0;
649}
650
651Texture2D::~Texture2D()
652{
653 mColorbufferProxy = NULL;
654
655 delete mTexStorage;
656 mTexStorage = NULL;
657
658 if (mSurface)
659 {
660 mSurface->setBoundTexture(NULL);
661 mSurface = NULL;
662 }
663}
664
665// We need to maintain a count of references to renderbuffers acting as
666// proxies for this texture, so that we do not attempt to use a pointer
667// to a renderbuffer proxy which has been deleted.
668void Texture2D::addProxyRef(const Renderbuffer *proxy)
669{
670 mProxyRefs++;
671}
672
673void Texture2D::releaseProxy(const Renderbuffer *proxy)
674{
675 if (mProxyRefs > 0)
676 mProxyRefs--;
677
678 if (mProxyRefs == 0)
679 mColorbufferProxy = NULL;
680}
681
682GLenum Texture2D::getTarget() const
683{
684 return GL_TEXTURE_2D;
685}
686
687GLsizei Texture2D::getWidth(GLint level) const
688{
689 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
690 return mImageArray[level].getWidth();
691 else
692 return 0;
693}
694
695GLsizei Texture2D::getHeight(GLint level) const
696{
697 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
698 return mImageArray[level].getHeight();
699 else
700 return 0;
701}
702
703GLenum Texture2D::getInternalFormat(GLint level) const
704{
705 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000706 return mImageArray[level].getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000707 else
708 return GL_NONE;
709}
710
daniel@transgaming.com20d36662012-10-31 19:51:43 +0000711GLenum Texture2D::getActualFormat(GLint level) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000712{
713 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.com20d36662012-10-31 19:51:43 +0000714 return mImageArray[level].getActualFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000715 else
716 return D3DFMT_UNKNOWN;
717}
718
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000719void Texture2D::redefineImage(GLint level, GLint internalformat, GLsizei width, GLsizei height)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000720{
721 releaseTexImage();
722
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000723 bool redefined = mImageArray[level].redefine(internalformat, width, height, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000724
725 if (mTexStorage && redefined)
726 {
727 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
728 {
729 mImageArray[i].markDirty();
730 }
731
732 delete mTexStorage;
733 mTexStorage = NULL;
734 mDirtyImages = true;
735 }
736}
737
738void Texture2D::setImage(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
739{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000740 GLint internalformat = ConvertSizedInternalFormat(format, type);
741 redefineImage(level, internalformat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000742
743 Texture::setImage(unpackAlignment, pixels, &mImageArray[level]);
744}
745
746void Texture2D::bindTexImage(egl::Surface *surface)
747{
748 releaseTexImage();
749
daniel@transgaming.com106e1f72012-10-31 18:38:36 +0000750 GLint internalformat = surface->getFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000751
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000752 mImageArray[0].redefine(internalformat, surface->getWidth(), surface->getHeight(), true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000753
754 delete mTexStorage;
daniel@transgaming.com3c720782012-10-31 18:42:34 +0000755 renderer::SwapChain *swapchain = surface->getSwapChain(); // D3D9_REPLACE
756 mTexStorage = new TextureStorage2D(swapchain->getOffscreenTexture());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000757
758 mDirtyImages = true;
759 mSurface = surface;
760 mSurface->setBoundTexture(this);
761}
762
763void Texture2D::releaseTexImage()
764{
765 if (mSurface)
766 {
767 mSurface->setBoundTexture(NULL);
768 mSurface = NULL;
769
770 if (mTexStorage)
771 {
772 delete mTexStorage;
773 mTexStorage = NULL;
774 }
775
776 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
777 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000778 mImageArray[i].redefine(GL_RGBA8_OES, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000779 }
780 }
781}
782
783void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
784{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000785 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
786 redefineImage(level, format, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000787
788 Texture::setCompressedImage(imageSize, pixels, &mImageArray[level]);
789}
790
791void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
792{
793 ASSERT(mImageArray[level].getSurface() != NULL);
794
795 if (level < levelCount())
796 {
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +0000797 IDirect3DSurface9 *destLevel = mTexStorage->getSurfaceLevel(level, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000798
799 if (destLevel)
800 {
801 Image *image = &mImageArray[level];
802 image->updateSurface(destLevel, xoffset, yoffset, width, height);
803
804 destLevel->Release();
805 image->markClean();
806 }
807 }
808}
809
810void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
811{
812 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[level]))
813 {
814 commitRect(level, xoffset, yoffset, width, height);
815 }
816}
817
818void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
819{
820 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[level]))
821 {
822 commitRect(level, xoffset, yoffset, width, height);
823 }
824}
825
826void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
827{
828 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
829
830 if (!renderTarget)
831 {
832 ERR("Failed to retrieve the render target.");
833 return error(GL_OUT_OF_MEMORY);
834 }
835
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000836 GLint internalformat = ConvertSizedInternalFormat(format, GL_UNSIGNED_BYTE);
837 redefineImage(level, internalformat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000838
839 if (!mImageArray[level].isRenderableFormat())
840 {
841 mImageArray[level].copy(0, 0, x, y, width, height, renderTarget);
842 mDirtyImages = true;
843 }
844 else
845 {
846 if (!mTexStorage || !mTexStorage->isRenderTarget())
847 {
848 convertToRenderTarget();
849 }
850
851 mImageArray[level].markClean();
852
853 if (width != 0 && height != 0 && level < levelCount())
854 {
855 RECT sourceRect;
856 sourceRect.left = x;
857 sourceRect.right = x + width;
858 sourceRect.top = y;
859 sourceRect.bottom = y + height;
860
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +0000861 IDirect3DSurface9 *dest = mTexStorage->getSurfaceLevel(level, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000862
863 if (dest)
864 {
865 getBlitter()->copy(renderTarget, sourceRect, format, 0, 0, dest);
866 dest->Release();
867 }
868 }
869 }
870
871 renderTarget->Release();
872}
873
874void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
875{
876 if (xoffset + width > mImageArray[level].getWidth() || yoffset + height > mImageArray[level].getHeight())
877 {
878 return error(GL_INVALID_VALUE);
879 }
880
881 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
882
883 if (!renderTarget)
884 {
885 ERR("Failed to retrieve the render target.");
886 return error(GL_OUT_OF_MEMORY);
887 }
888
889 if (!mImageArray[level].isRenderableFormat() || (!mTexStorage && !isSamplerComplete()))
890 {
891 mImageArray[level].copy(xoffset, yoffset, x, y, width, height, renderTarget);
892 mDirtyImages = true;
893 }
894 else
895 {
896 if (!mTexStorage || !mTexStorage->isRenderTarget())
897 {
898 convertToRenderTarget();
899 }
900
901 updateTexture();
902
903 if (level < levelCount())
904 {
905 RECT sourceRect;
906 sourceRect.left = x;
907 sourceRect.right = x + width;
908 sourceRect.top = y;
909 sourceRect.bottom = y + height;
910
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +0000911 IDirect3DSurface9 *dest = mTexStorage->getSurfaceLevel(level, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000912
913 if (dest)
914 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000915 getBlitter()->copy(renderTarget, sourceRect,
916 gl::ExtractFormat(mImageArray[0].getInternalFormat()),
917 xoffset, yoffset, dest);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000918 dest->Release();
919 }
920 }
921 }
922
923 renderTarget->Release();
924}
925
926void Texture2D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height)
927{
daniel@transgaming.com6b1a0a02012-10-17 18:22:47 +0000928 D3DFORMAT d3dfmt = ConvertTextureInternalFormat(internalformat);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000929 DWORD d3dusage = GetTextureUsage(d3dfmt, mUsage, false);
930
931 delete mTexStorage;
932 mTexStorage = new TextureStorage2D(levels, d3dfmt, d3dusage, width, height);
933 mImmutable = true;
934
935 for (int level = 0; level < levels; level++)
936 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000937 mImageArray[level].redefine(internalformat, width, height, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000938 width = std::max(1, width >> 1);
939 height = std::max(1, height >> 1);
940 }
941
942 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
943 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000944 mImageArray[level].redefine(GL_NONE, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000945 }
946
947 if (mTexStorage->isManaged())
948 {
949 int levels = levelCount();
950
951 for (int level = 0; level < levels; level++)
952 {
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +0000953 IDirect3DSurface9 *surface = mTexStorage->getSurfaceLevel(level, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000954 mImageArray[level].setManagedSurface(surface);
955 }
956 }
957}
958
959// Tests for 2D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85.
960bool Texture2D::isSamplerComplete() const
961{
962 GLsizei width = mImageArray[0].getWidth();
963 GLsizei height = mImageArray[0].getHeight();
964
965 if (width <= 0 || height <= 0)
966 {
967 return false;
968 }
969
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +0000970 bool mipmapping = isMipmapFiltered();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000971
daniel@transgaming.com6b1a0a02012-10-17 18:22:47 +0000972 if ((IsFloat32Format(getInternalFormat(0)) && !getContext()->supportsFloat32LinearFilter()) ||
973 (IsFloat16Format(getInternalFormat(0)) && !getContext()->supportsFloat16LinearFilter()))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000974 {
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000975 if (mSamplerState.magFilter != GL_NEAREST ||
976 (mSamplerState.minFilter != GL_NEAREST && mSamplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000977 {
978 return false;
979 }
980 }
981
982 bool npotSupport = getContext()->supportsNonPower2Texture();
983
984 if (!npotSupport)
985 {
daniel@transgaming.comebf139f2012-10-31 18:07:32 +0000986 if ((mSamplerState.wrapS != GL_CLAMP_TO_EDGE && !isPow2(width)) ||
987 (mSamplerState.wrapT != GL_CLAMP_TO_EDGE && !isPow2(height)))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000988 {
989 return false;
990 }
991 }
992
993 if (mipmapping)
994 {
995 if (!npotSupport)
996 {
997 if (!isPow2(width) || !isPow2(height))
998 {
999 return false;
1000 }
1001 }
1002
1003 if (!isMipmapComplete())
1004 {
1005 return false;
1006 }
1007 }
1008
1009 return true;
1010}
1011
1012// Tests for 2D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1013bool Texture2D::isMipmapComplete() const
1014{
1015 if (isImmutable())
1016 {
1017 return true;
1018 }
1019
1020 GLsizei width = mImageArray[0].getWidth();
1021 GLsizei height = mImageArray[0].getHeight();
1022
1023 if (width <= 0 || height <= 0)
1024 {
1025 return false;
1026 }
1027
1028 int q = log2(std::max(width, height));
1029
1030 for (int level = 1; level <= q; level++)
1031 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001032 if (mImageArray[level].getInternalFormat() != mImageArray[0].getInternalFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001033 {
1034 return false;
1035 }
1036
1037 if (mImageArray[level].getWidth() != std::max(1, width >> level))
1038 {
1039 return false;
1040 }
1041
1042 if (mImageArray[level].getHeight() != std::max(1, height >> level))
1043 {
1044 return false;
1045 }
1046 }
1047
1048 return true;
1049}
1050
1051bool Texture2D::isCompressed(GLint level) const
1052{
1053 return IsCompressed(getInternalFormat(level));
1054}
1055
1056bool Texture2D::isDepth(GLint level) const
1057{
1058 return IsDepthTexture(getInternalFormat(level));
1059}
1060
1061IDirect3DBaseTexture9 *Texture2D::getBaseTexture() const
1062{
1063 return mTexStorage ? mTexStorage->getBaseTexture() : NULL;
1064}
1065
1066// Constructs a Direct3D 9 texture resource from the texture images
1067void Texture2D::createTexture()
1068{
1069 GLsizei width = mImageArray[0].getWidth();
1070 GLsizei height = mImageArray[0].getHeight();
daniel@transgaming.come6a09842012-09-17 21:28:55 +00001071
1072 if (!(width > 0 && height > 0))
1073 return; // do not attempt to create d3d textures for nonexistant data
1074
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001075 GLint levels = creationLevels(width, height);
1076 D3DFORMAT d3dfmt = mImageArray[0].getD3DFormat();
1077 DWORD d3dusage = GetTextureUsage(d3dfmt, mUsage, false);
1078
1079 delete mTexStorage;
1080 mTexStorage = new TextureStorage2D(levels, d3dfmt, d3dusage, width, height);
1081
1082 if (mTexStorage->isManaged())
1083 {
1084 int levels = levelCount();
1085
1086 for (int level = 0; level < levels; level++)
1087 {
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00001088 IDirect3DSurface9 *surface = mTexStorage->getSurfaceLevel(level, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001089 mImageArray[level].setManagedSurface(surface);
1090 }
1091 }
1092
1093 mDirtyImages = true;
1094}
1095
1096void Texture2D::updateTexture()
1097{
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +00001098 bool mipmapping = (isMipmapFiltered() && isMipmapComplete());
1099
1100 int levels = (mipmapping ? levelCount() : 1);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001101
1102 for (int level = 0; level < levels; level++)
1103 {
1104 Image *image = &mImageArray[level];
1105
1106 if (image->isDirty())
1107 {
1108 commitRect(level, 0, 0, mImageArray[level].getWidth(), mImageArray[level].getHeight());
1109 }
1110 }
1111}
1112
1113void Texture2D::convertToRenderTarget()
1114{
1115 TextureStorage2D *newTexStorage = NULL;
1116
1117 if (mImageArray[0].getWidth() != 0 && mImageArray[0].getHeight() != 0)
1118 {
1119 GLsizei width = mImageArray[0].getWidth();
1120 GLsizei height = mImageArray[0].getHeight();
1121 GLint levels = creationLevels(width, height);
1122 D3DFORMAT d3dfmt = mImageArray[0].getD3DFormat();
1123 DWORD d3dusage = GetTextureUsage(d3dfmt, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, true);
1124
1125 newTexStorage = new TextureStorage2D(levels, d3dfmt, d3dusage, width, height);
1126
1127 if (mTexStorage != NULL)
1128 {
1129 int levels = levelCount();
1130 for (int i = 0; i < levels; i++)
1131 {
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00001132 IDirect3DSurface9 *source = mTexStorage->getSurfaceLevel(i, false);
1133 IDirect3DSurface9 *dest = newTexStorage->getSurfaceLevel(i, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001134
1135 if (!copyToRenderTarget(dest, source, mTexStorage->isManaged()))
1136 {
1137 delete newTexStorage;
1138 if (source) source->Release();
1139 if (dest) dest->Release();
1140 return error(GL_OUT_OF_MEMORY);
1141 }
1142
1143 if (source) source->Release();
1144 if (dest) dest->Release();
1145 }
1146 }
1147 }
1148
1149 delete mTexStorage;
1150 mTexStorage = newTexStorage;
1151
1152 mDirtyImages = true;
1153}
1154
1155void Texture2D::generateMipmaps()
1156{
1157 if (!getContext()->supportsNonPower2Texture())
1158 {
1159 if (!isPow2(mImageArray[0].getWidth()) || !isPow2(mImageArray[0].getHeight()))
1160 {
1161 return error(GL_INVALID_OPERATION);
1162 }
1163 }
1164
1165 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1166 unsigned int q = log2(std::max(mImageArray[0].getWidth(), mImageArray[0].getHeight()));
1167 for (unsigned int i = 1; i <= q; i++)
1168 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001169 redefineImage(i, mImageArray[0].getInternalFormat(),
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001170 std::max(mImageArray[0].getWidth() >> i, 1),
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001171 std::max(mImageArray[0].getHeight() >> i, 1));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001172 }
1173
1174 if (mTexStorage && mTexStorage->isRenderTarget())
1175 {
1176 for (unsigned int i = 1; i <= q; i++)
1177 {
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00001178 IDirect3DSurface9 *upper = mTexStorage->getSurfaceLevel(i - 1, false);
1179 IDirect3DSurface9 *lower = mTexStorage->getSurfaceLevel(i, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001180
1181 if (upper != NULL && lower != NULL)
1182 {
1183 getBlitter()->boxFilter(upper, lower);
1184 }
1185
1186 if (upper != NULL) upper->Release();
1187 if (lower != NULL) lower->Release();
1188
1189 mImageArray[i].markClean();
1190 }
1191 }
1192 else
1193 {
1194 for (unsigned int i = 1; i <= q; i++)
1195 {
1196 if (mImageArray[i].getSurface() == NULL)
1197 {
1198 return error(GL_OUT_OF_MEMORY);
1199 }
1200
daniel@transgaming.com2e38b802012-10-17 18:30:06 +00001201 GenerateMip(mImageArray[i].getSurface(), mImageArray[i - 1].getSurface());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001202
1203 mImageArray[i].markDirty();
1204 }
1205 }
1206}
1207
1208Renderbuffer *Texture2D::getRenderbuffer(GLenum target)
1209{
1210 if (target != GL_TEXTURE_2D)
1211 {
1212 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
1213 }
1214
1215 if (mColorbufferProxy == NULL)
1216 {
1217 mColorbufferProxy = new Renderbuffer(id(), new RenderbufferTexture2D(this, target));
1218 }
1219
1220 return mColorbufferProxy;
1221}
1222
1223// Increments refcount on surface.
1224// caller must Release() the returned surface
1225IDirect3DSurface9 *Texture2D::getRenderTarget(GLenum target)
1226{
1227 ASSERT(target == GL_TEXTURE_2D);
1228
1229 // ensure the underlying texture is created
1230 if (getStorage(true) == NULL)
1231 {
1232 return NULL;
1233 }
1234
1235 updateTexture();
1236
1237 // ensure this is NOT a depth texture
1238 if (isDepth(0))
1239 {
1240 return NULL;
1241 }
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00001242 return mTexStorage->getSurfaceLevel(0, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001243}
1244
1245// Increments refcount on surface.
1246// caller must Release() the returned surface
1247IDirect3DSurface9 *Texture2D::getDepthStencil(GLenum target)
1248{
1249 ASSERT(target == GL_TEXTURE_2D);
1250
1251 // ensure the underlying texture is created
1252 if (getStorage(true) == NULL)
1253 {
1254 return NULL;
1255 }
1256
1257 updateTexture();
1258
1259 // ensure this is actually a depth texture
1260 if (!isDepth(0))
1261 {
1262 return NULL;
1263 }
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00001264 return mTexStorage->getSurfaceLevel(0, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001265}
1266
1267TextureStorage *Texture2D::getStorage(bool renderTarget)
1268{
1269 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
1270 {
1271 if (renderTarget)
1272 {
1273 convertToRenderTarget();
1274 }
1275 else
1276 {
1277 createTexture();
1278 }
1279 }
1280
1281 return mTexStorage;
1282}
1283
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001284TextureCubeMap::TextureCubeMap(GLuint id) : Texture(id)
1285{
1286 mTexStorage = NULL;
1287 for (int i = 0; i < 6; i++)
1288 {
1289 mFaceProxies[i] = NULL;
1290 mFaceProxyRefs[i] = 0;
1291 }
1292}
1293
1294TextureCubeMap::~TextureCubeMap()
1295{
1296 for (int i = 0; i < 6; i++)
1297 {
1298 mFaceProxies[i] = NULL;
1299 }
1300
1301 delete mTexStorage;
1302 mTexStorage = NULL;
1303}
1304
1305// We need to maintain a count of references to renderbuffers acting as
1306// proxies for this texture, so that the texture is not deleted while
1307// proxy references still exist. If the reference count drops to zero,
1308// we set our proxy pointer NULL, so that a new attempt at referencing
1309// will cause recreation.
1310void TextureCubeMap::addProxyRef(const Renderbuffer *proxy)
1311{
1312 for (int i = 0; i < 6; i++)
1313 {
1314 if (mFaceProxies[i] == proxy)
1315 mFaceProxyRefs[i]++;
1316 }
1317}
1318
1319void TextureCubeMap::releaseProxy(const Renderbuffer *proxy)
1320{
1321 for (int i = 0; i < 6; i++)
1322 {
1323 if (mFaceProxies[i] == proxy)
1324 {
1325 if (mFaceProxyRefs[i] > 0)
1326 mFaceProxyRefs[i]--;
1327
1328 if (mFaceProxyRefs[i] == 0)
1329 mFaceProxies[i] = NULL;
1330 }
1331 }
1332}
1333
1334GLenum TextureCubeMap::getTarget() const
1335{
1336 return GL_TEXTURE_CUBE_MAP;
1337}
1338
1339GLsizei TextureCubeMap::getWidth(GLenum target, GLint level) const
1340{
1341 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1342 return mImageArray[faceIndex(target)][level].getWidth();
1343 else
1344 return 0;
1345}
1346
1347GLsizei TextureCubeMap::getHeight(GLenum target, GLint level) const
1348{
1349 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1350 return mImageArray[faceIndex(target)][level].getHeight();
1351 else
1352 return 0;
1353}
1354
1355GLenum TextureCubeMap::getInternalFormat(GLenum target, GLint level) const
1356{
1357 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001358 return mImageArray[faceIndex(target)][level].getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001359 else
1360 return GL_NONE;
1361}
1362
daniel@transgaming.com20d36662012-10-31 19:51:43 +00001363GLenum TextureCubeMap::getActualFormat(GLenum target, GLint level) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001364{
1365 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.com20d36662012-10-31 19:51:43 +00001366 return mImageArray[faceIndex(target)][level].getActualFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001367 else
1368 return D3DFMT_UNKNOWN;
1369}
1370
1371void TextureCubeMap::setImagePosX(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1372{
1373 setImage(0, level, width, height, format, type, unpackAlignment, pixels);
1374}
1375
1376void TextureCubeMap::setImageNegX(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1377{
1378 setImage(1, level, width, height, format, type, unpackAlignment, pixels);
1379}
1380
1381void TextureCubeMap::setImagePosY(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1382{
1383 setImage(2, level, width, height, format, type, unpackAlignment, pixels);
1384}
1385
1386void TextureCubeMap::setImageNegY(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1387{
1388 setImage(3, level, width, height, format, type, unpackAlignment, pixels);
1389}
1390
1391void TextureCubeMap::setImagePosZ(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1392{
1393 setImage(4, level, width, height, format, type, unpackAlignment, pixels);
1394}
1395
1396void TextureCubeMap::setImageNegZ(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1397{
1398 setImage(5, level, width, height, format, type, unpackAlignment, pixels);
1399}
1400
1401void TextureCubeMap::setCompressedImage(GLenum face, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
1402{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001403 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1404 redefineImage(faceIndex(face), level, format, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001405
1406 Texture::setCompressedImage(imageSize, pixels, &mImageArray[faceIndex(face)][level]);
1407}
1408
1409void TextureCubeMap::commitRect(int face, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1410{
1411 ASSERT(mImageArray[face][level].getSurface() != NULL);
1412
1413 if (level < levelCount())
1414 {
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00001415 IDirect3DSurface9 *destLevel = mTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001416 ASSERT(destLevel != NULL);
1417
1418 if (destLevel != NULL)
1419 {
1420 Image *image = &mImageArray[face][level];
1421 image->updateSurface(destLevel, xoffset, yoffset, width, height);
1422
1423 destLevel->Release();
1424 image->markClean();
1425 }
1426 }
1427}
1428
1429void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1430{
1431 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[faceIndex(target)][level]))
1432 {
1433 commitRect(faceIndex(target), level, xoffset, yoffset, width, height);
1434 }
1435}
1436
1437void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1438{
1439 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[faceIndex(target)][level]))
1440 {
1441 commitRect(faceIndex(target), level, xoffset, yoffset, width, height);
1442 }
1443}
1444
1445// Tests for cube map sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 86.
1446bool TextureCubeMap::isSamplerComplete() const
1447{
1448 int size = mImageArray[0][0].getWidth();
1449
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +00001450 bool mipmapping = isMipmapFiltered();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001451
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001452 if ((gl::ExtractType(getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0)) == GL_FLOAT && !getContext()->supportsFloat32LinearFilter()) ||
1453 (gl::ExtractType(getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0) == GL_HALF_FLOAT_OES) && !getContext()->supportsFloat16LinearFilter()))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001454 {
daniel@transgaming.comebf139f2012-10-31 18:07:32 +00001455 if (mSamplerState.magFilter != GL_NEAREST ||
1456 (mSamplerState.minFilter != GL_NEAREST && mSamplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001457 {
1458 return false;
1459 }
1460 }
1461
1462 if (!isPow2(size) && !getContext()->supportsNonPower2Texture())
1463 {
daniel@transgaming.comebf139f2012-10-31 18:07:32 +00001464 if (mSamplerState.wrapS != GL_CLAMP_TO_EDGE || mSamplerState.wrapT != GL_CLAMP_TO_EDGE || mipmapping)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001465 {
1466 return false;
1467 }
1468 }
1469
1470 if (!mipmapping)
1471 {
1472 if (!isCubeComplete())
1473 {
1474 return false;
1475 }
1476 }
1477 else
1478 {
1479 if (!isMipmapCubeComplete()) // Also tests for isCubeComplete()
1480 {
1481 return false;
1482 }
1483 }
1484
1485 return true;
1486}
1487
1488// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1489bool TextureCubeMap::isCubeComplete() const
1490{
1491 if (mImageArray[0][0].getWidth() <= 0 || mImageArray[0][0].getHeight() != mImageArray[0][0].getWidth())
1492 {
1493 return false;
1494 }
1495
1496 for (unsigned int face = 1; face < 6; face++)
1497 {
1498 if (mImageArray[face][0].getWidth() != mImageArray[0][0].getWidth() ||
1499 mImageArray[face][0].getWidth() != mImageArray[0][0].getHeight() ||
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001500 mImageArray[face][0].getInternalFormat() != mImageArray[0][0].getInternalFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001501 {
1502 return false;
1503 }
1504 }
1505
1506 return true;
1507}
1508
1509bool TextureCubeMap::isMipmapCubeComplete() const
1510{
1511 if (isImmutable())
1512 {
1513 return true;
1514 }
1515
1516 if (!isCubeComplete())
1517 {
1518 return false;
1519 }
1520
1521 GLsizei size = mImageArray[0][0].getWidth();
1522
1523 int q = log2(size);
1524
1525 for (int face = 0; face < 6; face++)
1526 {
1527 for (int level = 1; level <= q; level++)
1528 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001529 if (mImageArray[face][level].getInternalFormat() != mImageArray[0][0].getInternalFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001530 {
1531 return false;
1532 }
1533
1534 if (mImageArray[face][level].getWidth() != std::max(1, size >> level))
1535 {
1536 return false;
1537 }
1538 }
1539 }
1540
1541 return true;
1542}
1543
1544bool TextureCubeMap::isCompressed(GLenum target, GLint level) const
1545{
1546 return IsCompressed(getInternalFormat(target, level));
1547}
1548
1549IDirect3DBaseTexture9 *TextureCubeMap::getBaseTexture() const
1550{
1551 return mTexStorage ? mTexStorage->getBaseTexture() : NULL;
1552}
1553
1554// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
1555void TextureCubeMap::createTexture()
1556{
1557 GLsizei size = mImageArray[0][0].getWidth();
daniel@transgaming.come6a09842012-09-17 21:28:55 +00001558
1559 if (!(size > 0))
1560 return; // do not attempt to create d3d textures for nonexistant data
1561
sminns@adobe.comce1189b2012-09-18 20:06:35 +00001562 GLint levels = creationLevels(size);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001563 D3DFORMAT d3dfmt = mImageArray[0][0].getD3DFormat();
1564 DWORD d3dusage = GetTextureUsage(d3dfmt, mUsage, false);
1565
1566 delete mTexStorage;
1567 mTexStorage = new TextureStorageCubeMap(levels, d3dfmt, d3dusage, size);
1568
1569 if (mTexStorage->isManaged())
1570 {
1571 int levels = levelCount();
1572
1573 for (int face = 0; face < 6; face++)
1574 {
1575 for (int level = 0; level < levels; level++)
1576 {
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00001577 IDirect3DSurface9 *surface = mTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001578 mImageArray[face][level].setManagedSurface(surface);
1579 }
1580 }
1581 }
1582
1583 mDirtyImages = true;
1584}
1585
1586void TextureCubeMap::updateTexture()
1587{
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +00001588 bool mipmapping = isMipmapFiltered() && isMipmapCubeComplete();
1589
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001590 for (int face = 0; face < 6; face++)
1591 {
daniel@transgaming.comca9a3c82012-10-26 18:55:07 +00001592 int levels = (mipmapping ? levelCount() : 1);
1593
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001594 for (int level = 0; level < levels; level++)
1595 {
1596 Image *image = &mImageArray[face][level];
1597
1598 if (image->isDirty())
1599 {
1600 commitRect(face, level, 0, 0, image->getWidth(), image->getHeight());
1601 }
1602 }
1603 }
1604}
1605
1606void TextureCubeMap::convertToRenderTarget()
1607{
1608 TextureStorageCubeMap *newTexStorage = NULL;
1609
1610 if (mImageArray[0][0].getWidth() != 0)
1611 {
1612 GLsizei size = mImageArray[0][0].getWidth();
sminns@adobe.comce1189b2012-09-18 20:06:35 +00001613 GLint levels = creationLevels(size);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001614 D3DFORMAT d3dfmt = mImageArray[0][0].getD3DFormat();
1615 DWORD d3dusage = GetTextureUsage(d3dfmt, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, true);
1616
1617 newTexStorage = new TextureStorageCubeMap(levels, d3dfmt, d3dusage, size);
1618
1619 if (mTexStorage != NULL)
1620 {
1621 int levels = levelCount();
1622 for (int f = 0; f < 6; f++)
1623 {
1624 for (int i = 0; i < levels; i++)
1625 {
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00001626 IDirect3DSurface9 *source = mTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i, false);
1627 IDirect3DSurface9 *dest = newTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001628
1629 if (!copyToRenderTarget(dest, source, mTexStorage->isManaged()))
1630 {
1631 delete newTexStorage;
1632 if (source) source->Release();
1633 if (dest) dest->Release();
1634 return error(GL_OUT_OF_MEMORY);
1635 }
1636
1637 if (source) source->Release();
1638 if (dest) dest->Release();
1639 }
1640 }
1641 }
1642 }
1643
1644 delete mTexStorage;
1645 mTexStorage = newTexStorage;
1646
1647 mDirtyImages = true;
1648}
1649
1650void TextureCubeMap::setImage(int faceIndex, GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1651{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001652 GLint internalformat = ConvertSizedInternalFormat(format, type);
1653 redefineImage(faceIndex, level, internalformat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001654
1655 Texture::setImage(unpackAlignment, pixels, &mImageArray[faceIndex][level]);
1656}
1657
1658unsigned int TextureCubeMap::faceIndex(GLenum face)
1659{
1660 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
1661 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
1662 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
1663 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
1664 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
1665
1666 return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
1667}
1668
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001669void TextureCubeMap::redefineImage(int face, GLint level, GLint internalformat, GLsizei width, GLsizei height)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001670{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001671 bool redefined = mImageArray[face][level].redefine(internalformat, width, height, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001672
1673 if (mTexStorage && redefined)
1674 {
1675 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1676 {
1677 for (int f = 0; f < 6; f++)
1678 {
1679 mImageArray[f][i].markDirty();
1680 }
1681 }
1682
1683 delete mTexStorage;
1684 mTexStorage = NULL;
1685
1686 mDirtyImages = true;
1687 }
1688}
1689
1690void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1691{
1692 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
1693
1694 if (!renderTarget)
1695 {
1696 ERR("Failed to retrieve the render target.");
1697 return error(GL_OUT_OF_MEMORY);
1698 }
1699
1700 unsigned int faceindex = faceIndex(target);
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001701 GLint internalformat = gl::ConvertSizedInternalFormat(format, GL_UNSIGNED_BYTE);
1702 redefineImage(faceindex, level, internalformat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001703
1704 if (!mImageArray[faceindex][level].isRenderableFormat())
1705 {
1706 mImageArray[faceindex][level].copy(0, 0, x, y, width, height, renderTarget);
1707 mDirtyImages = true;
1708 }
1709 else
1710 {
1711 if (!mTexStorage || !mTexStorage->isRenderTarget())
1712 {
1713 convertToRenderTarget();
1714 }
1715
1716 mImageArray[faceindex][level].markClean();
1717
1718 ASSERT(width == height);
1719
1720 if (width > 0 && level < levelCount())
1721 {
1722 RECT sourceRect;
1723 sourceRect.left = x;
1724 sourceRect.right = x + width;
1725 sourceRect.top = y;
1726 sourceRect.bottom = y + height;
1727
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00001728 IDirect3DSurface9 *dest = mTexStorage->getCubeMapSurface(target, level, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001729
1730 if (dest)
1731 {
1732 getBlitter()->copy(renderTarget, sourceRect, format, 0, 0, dest);
1733 dest->Release();
1734 }
1735 }
1736 }
1737
1738 renderTarget->Release();
1739}
1740
1741void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1742{
1743 GLsizei size = mImageArray[faceIndex(target)][level].getWidth();
1744
1745 if (xoffset + width > size || yoffset + height > size)
1746 {
1747 return error(GL_INVALID_VALUE);
1748 }
1749
1750 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
1751
1752 if (!renderTarget)
1753 {
1754 ERR("Failed to retrieve the render target.");
1755 return error(GL_OUT_OF_MEMORY);
1756 }
1757
1758 unsigned int faceindex = faceIndex(target);
1759
1760 if (!mImageArray[faceindex][level].isRenderableFormat() || (!mTexStorage && !isSamplerComplete()))
1761 {
1762 mImageArray[faceindex][level].copy(0, 0, x, y, width, height, renderTarget);
1763 mDirtyImages = true;
1764 }
1765 else
1766 {
1767 if (!mTexStorage || !mTexStorage->isRenderTarget())
1768 {
1769 convertToRenderTarget();
1770 }
1771
1772 updateTexture();
1773
1774 if (level < levelCount())
1775 {
1776 RECT sourceRect;
1777 sourceRect.left = x;
1778 sourceRect.right = x + width;
1779 sourceRect.top = y;
1780 sourceRect.bottom = y + height;
1781
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00001782 IDirect3DSurface9 *dest = mTexStorage->getCubeMapSurface(target, level, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001783
1784 if (dest)
1785 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001786 getBlitter()->copy(renderTarget, sourceRect, gl::ExtractFormat(mImageArray[0][0].getInternalFormat()), xoffset, yoffset, dest);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001787 dest->Release();
1788 }
1789 }
1790 }
1791
1792 renderTarget->Release();
1793}
1794
1795void TextureCubeMap::storage(GLsizei levels, GLenum internalformat, GLsizei size)
1796{
daniel@transgaming.com6b1a0a02012-10-17 18:22:47 +00001797 D3DFORMAT d3dfmt = ConvertTextureInternalFormat(internalformat);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001798 DWORD d3dusage = GetTextureUsage(d3dfmt, mUsage, false);
1799
1800 delete mTexStorage;
1801 mTexStorage = new TextureStorageCubeMap(levels, d3dfmt, d3dusage, size);
1802 mImmutable = true;
1803
1804 for (int level = 0; level < levels; level++)
1805 {
1806 for (int face = 0; face < 6; face++)
1807 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001808 mImageArray[face][level].redefine(internalformat, size, size, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001809 size = std::max(1, size >> 1);
1810 }
1811 }
1812
1813 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1814 {
1815 for (int face = 0; face < 6; face++)
1816 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001817 mImageArray[face][level].redefine(GL_NONE, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001818 }
1819 }
1820
1821 if (mTexStorage->isManaged())
1822 {
1823 int levels = levelCount();
1824
1825 for (int face = 0; face < 6; face++)
1826 {
1827 for (int level = 0; level < levels; level++)
1828 {
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00001829 IDirect3DSurface9 *surface = mTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001830 mImageArray[face][level].setManagedSurface(surface);
1831 }
1832 }
1833 }
1834}
1835
1836void TextureCubeMap::generateMipmaps()
1837{
1838 if (!isCubeComplete())
1839 {
1840 return error(GL_INVALID_OPERATION);
1841 }
1842
1843 if (!getContext()->supportsNonPower2Texture())
1844 {
1845 if (!isPow2(mImageArray[0][0].getWidth()))
1846 {
1847 return error(GL_INVALID_OPERATION);
1848 }
1849 }
1850
1851 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1852 unsigned int q = log2(mImageArray[0][0].getWidth());
1853 for (unsigned int f = 0; f < 6; f++)
1854 {
1855 for (unsigned int i = 1; i <= q; i++)
1856 {
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001857 redefineImage(f, i, mImageArray[f][0].getInternalFormat(),
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001858 std::max(mImageArray[f][0].getWidth() >> i, 1),
daniel@transgaming.com6452adf2012-10-17 18:22:35 +00001859 std::max(mImageArray[f][0].getWidth() >> i, 1));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001860 }
1861 }
1862
1863 if (mTexStorage && mTexStorage->isRenderTarget())
1864 {
1865 for (unsigned int f = 0; f < 6; f++)
1866 {
1867 for (unsigned int i = 1; i <= q; i++)
1868 {
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00001869 IDirect3DSurface9 *upper = mTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i - 1, false);
1870 IDirect3DSurface9 *lower = mTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001871
1872 if (upper != NULL && lower != NULL)
1873 {
1874 getBlitter()->boxFilter(upper, lower);
1875 }
1876
1877 if (upper != NULL) upper->Release();
1878 if (lower != NULL) lower->Release();
1879
1880 mImageArray[f][i].markClean();
1881 }
1882 }
1883 }
1884 else
1885 {
1886 for (unsigned int f = 0; f < 6; f++)
1887 {
1888 for (unsigned int i = 1; i <= q; i++)
1889 {
1890 if (mImageArray[f][i].getSurface() == NULL)
1891 {
1892 return error(GL_OUT_OF_MEMORY);
1893 }
1894
daniel@transgaming.com2e38b802012-10-17 18:30:06 +00001895 GenerateMip(mImageArray[f][i].getSurface(), mImageArray[f][i - 1].getSurface());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001896
1897 mImageArray[f][i].markDirty();
1898 }
1899 }
1900 }
1901}
1902
1903Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target)
1904{
1905 if (!IsCubemapTextureTarget(target))
1906 {
1907 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
1908 }
1909
1910 unsigned int face = faceIndex(target);
1911
1912 if (mFaceProxies[face] == NULL)
1913 {
1914 mFaceProxies[face] = new Renderbuffer(id(), new RenderbufferTextureCubeMap(this, target));
1915 }
1916
1917 return mFaceProxies[face];
1918}
1919
1920// Increments refcount on surface.
1921// caller must Release() the returned surface
1922IDirect3DSurface9 *TextureCubeMap::getRenderTarget(GLenum target)
1923{
1924 ASSERT(IsCubemapTextureTarget(target));
1925
1926 // ensure the underlying texture is created
1927 if (getStorage(true) == NULL)
1928 {
1929 return NULL;
1930 }
1931
1932 updateTexture();
1933
daniel@transgaming.com2b5af7b2012-09-27 17:46:15 +00001934 return mTexStorage->getCubeMapSurface(target, 0, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001935}
1936
1937TextureStorage *TextureCubeMap::getStorage(bool renderTarget)
1938{
1939 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
1940 {
1941 if (renderTarget)
1942 {
1943 convertToRenderTarget();
1944 }
1945 else
1946 {
1947 createTexture();
1948 }
1949 }
1950
1951 return mTexStorage;
1952}
1953
1954}