blob: 6ff2453b61fbbf98335359354e717dfc6b849b73 [file] [log] [blame]
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001//
2// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
3// 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
13#include <d3dx9tex.h>
14
15#include <algorithm>
16#include <intrin.h>
17
18#include "common/debug.h"
19
20#include "libEGL/Display.h"
21
22#include "libGLESv2/main.h"
23#include "libGLESv2/mathutil.h"
24#include "libGLESv2/utilities.h"
25#include "libGLESv2/Blit.h"
26#include "libGLESv2/Framebuffer.h"
27
28namespace gl
29{
30unsigned int TextureStorage::mCurrentTextureSerial = 1;
31
32static D3DFORMAT ConvertTextureFormatType(GLenum format, GLenum type)
33{
34 if (IsDepthTexture(format))
35 {
36 return D3DFMT_INTZ;
37 }
38 else if (format == GL_COMPRESSED_RGB_S3TC_DXT1_EXT ||
39 format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT)
40 {
41 return D3DFMT_DXT1;
42 }
43 else if (format == GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE)
44 {
45 return D3DFMT_DXT3;
46 }
47 else if (format == GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE)
48 {
49 return D3DFMT_DXT5;
50 }
51 else if (type == GL_FLOAT)
52 {
53 return D3DFMT_A32B32G32R32F;
54 }
55 else if (type == GL_HALF_FLOAT_OES)
56 {
57 return D3DFMT_A16B16G16R16F;
58 }
59 else if (type == GL_UNSIGNED_BYTE)
60 {
61 if (format == GL_LUMINANCE && getContext()->supportsLuminanceTextures())
62 {
63 return D3DFMT_L8;
64 }
65 else if (format == GL_LUMINANCE_ALPHA && getContext()->supportsLuminanceAlphaTextures())
66 {
67 return D3DFMT_A8L8;
68 }
69 else if (format == GL_RGB)
70 {
71 return D3DFMT_X8R8G8B8;
72 }
73
74 return D3DFMT_A8R8G8B8;
75 }
76
77 return D3DFMT_A8R8G8B8;
78}
79
80static bool IsTextureFormatRenderable(D3DFORMAT format)
81{
82 if (format == D3DFMT_INTZ)
83 {
84 return true;
85 }
86 switch(format)
87 {
88 case D3DFMT_L8:
89 case D3DFMT_A8L8:
90 case D3DFMT_DXT1:
91 case D3DFMT_DXT3:
92 case D3DFMT_DXT5:
93 return false;
94 case D3DFMT_A8R8G8B8:
95 case D3DFMT_X8R8G8B8:
96 case D3DFMT_A16B16G16R16F:
97 case D3DFMT_A32B32G32R32F:
98 return true;
99 default:
100 UNREACHABLE();
101 }
102
103 return false;
104}
105
106static inline DWORD GetTextureUsage(D3DFORMAT d3dfmt, GLenum glusage, bool forceRenderable)
107{
108 DWORD d3dusage = 0;
109
110 if (d3dfmt == D3DFMT_INTZ)
111 {
112 d3dusage |= D3DUSAGE_DEPTHSTENCIL;
113 }
114 else if(forceRenderable || (IsTextureFormatRenderable(d3dfmt) && (glusage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE)))
115 {
116 d3dusage |= D3DUSAGE_RENDERTARGET;
117 }
118 return d3dusage;
119}
120
121Image::Image()
122{
123 mWidth = 0;
124 mHeight = 0;
125 mFormat = GL_NONE;
126 mType = GL_UNSIGNED_BYTE;
127
128 mSurface = NULL;
129
130 mDirty = false;
131
132 mD3DPool = D3DPOOL_SYSTEMMEM;
133 mD3DFormat = D3DFMT_UNKNOWN;
134}
135
136Image::~Image()
137{
138 if (mSurface)
139 {
140 mSurface->Release();
141 }
142}
143
144bool Image::redefine(GLenum format, GLsizei width, GLsizei height, GLenum type, bool forceRelease)
145{
146 if (mWidth != width ||
147 mHeight != height ||
148 mFormat != format ||
149 mType != type ||
150 forceRelease)
151 {
152 mWidth = width;
153 mHeight = height;
154 mFormat = format;
155 mType = type;
156 // compute the d3d format that will be used
157 mD3DFormat = ConvertTextureFormatType(mFormat, mType);
158
159 if (mSurface)
160 {
161 mSurface->Release();
162 mSurface = NULL;
163 }
164
165 return true;
166 }
167
168 return false;
169}
170
171void Image::createSurface()
172{
173 if(mSurface)
174 {
175 return;
176 }
177
178 IDirect3DTexture9 *newTexture = NULL;
179 IDirect3DSurface9 *newSurface = NULL;
180 const D3DPOOL poolToUse = D3DPOOL_SYSTEMMEM;
181 const D3DFORMAT d3dFormat = getD3DFormat();
182 ASSERT(d3dFormat != D3DFMT_INTZ); // We should never get here for depth textures
183
184 if (mWidth != 0 && mHeight != 0)
185 {
186 int levelToFetch = 0;
187 GLsizei requestWidth = mWidth;
188 GLsizei requestHeight = mHeight;
189 if (IsCompressed(mFormat) && (mWidth % 4 != 0 || mHeight % 4 != 0))
190 {
191 bool isMult4 = false;
192 int upsampleCount = 0;
193 while (!isMult4)
194 {
195 requestWidth <<= 1;
196 requestHeight <<= 1;
197 upsampleCount++;
198 if (requestWidth % 4 == 0 && requestHeight % 4 == 0)
199 {
200 isMult4 = true;
201 }
202 }
203 levelToFetch = upsampleCount;
204 }
205
206 HRESULT result = getDevice()->CreateTexture(requestWidth, requestHeight, levelToFetch + 1, NULL, d3dFormat,
207 poolToUse, &newTexture, NULL);
208
209 if (FAILED(result))
210 {
211 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
212 ERR("Creating image surface failed.");
213 return error(GL_OUT_OF_MEMORY);
214 }
215
216 newTexture->GetSurfaceLevel(levelToFetch, &newSurface);
217 newTexture->Release();
218 }
219
220 mSurface = newSurface;
221 mDirty = false;
222 mD3DPool = poolToUse;
223}
224
225HRESULT Image::lock(D3DLOCKED_RECT *lockedRect, const RECT *rect)
226{
227 createSurface();
228
229 HRESULT result = D3DERR_INVALIDCALL;
230
231 if (mSurface)
232 {
233 result = mSurface->LockRect(lockedRect, rect, 0);
234 ASSERT(SUCCEEDED(result));
235
236 mDirty = true;
237 }
238
239 return result;
240}
241
242void Image::unlock()
243{
244 if (mSurface)
245 {
246 HRESULT result = mSurface->UnlockRect();
247 ASSERT(SUCCEEDED(result));
248 }
249}
250
251bool Image::isRenderableFormat() const
252{
253 return IsTextureFormatRenderable(getD3DFormat());
254}
255
256D3DFORMAT Image::getD3DFormat() const
257{
258 // this should only happen if the image hasn't been redefined first
259 // which would be a bug by the caller
260 ASSERT(mD3DFormat != D3DFMT_UNKNOWN);
261
262 return mD3DFormat;
263}
264
265IDirect3DSurface9 *Image::getSurface()
266{
267 createSurface();
268
269 return mSurface;
270}
271
272void Image::setManagedSurface(IDirect3DSurface9 *surface)
273{
274 if (mSurface)
275 {
276 D3DXLoadSurfaceFromSurface(surface, NULL, NULL, mSurface, NULL, NULL, D3DX_FILTER_BOX, 0);
277 mSurface->Release();
278 }
279
280 D3DSURFACE_DESC desc;
281 surface->GetDesc(&desc);
282 ASSERT(desc.Pool == D3DPOOL_MANAGED);
283
284 mSurface = surface;
285 mD3DPool = desc.Pool;
286}
287
288void Image::updateSurface(IDirect3DSurface9 *destSurface, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
289{
290 IDirect3DSurface9 *sourceSurface = getSurface();
291
292 if (sourceSurface && sourceSurface != destSurface)
293 {
294 RECT rect;
295 rect.left = xoffset;
296 rect.top = yoffset;
297 rect.right = xoffset + width;
298 rect.bottom = yoffset + height;
299
300 if (mD3DPool == D3DPOOL_MANAGED)
301 {
302 HRESULT result = D3DXLoadSurfaceFromSurface(destSurface, NULL, &rect, sourceSurface, NULL, &rect, D3DX_FILTER_BOX, 0);
303 ASSERT(SUCCEEDED(result));
304 }
305 else
306 {
307 // UpdateSurface: source must be SYSTEMMEM, dest must be DEFAULT pools
308 POINT point = {rect.left, rect.top};
309 HRESULT result = getDevice()->UpdateSurface(sourceSurface, &rect, destSurface, &point);
310 ASSERT(SUCCEEDED(result));
311 }
312 }
313}
314
315// Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input
316// into the target pixel rectangle.
317void Image::loadData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum type,
318 GLint unpackAlignment, const void *input)
319{
320 RECT lockRect =
321 {
322 xoffset, yoffset,
323 xoffset + width, yoffset + height
324 };
325
326 D3DLOCKED_RECT locked;
327 HRESULT result = lock(&locked, &lockRect);
328 if (FAILED(result))
329 {
330 return;
331 }
332
333 GLsizei inputPitch = ComputePitch(width, mFormat, type, unpackAlignment);
334
335 switch (type)
336 {
337 case GL_UNSIGNED_BYTE:
338 switch (mFormat)
339 {
340 case GL_ALPHA:
341 if (supportsSSE2())
342 {
343 loadAlphaDataSSE2(width, height, inputPitch, input, locked.Pitch, locked.pBits);
344 }
345 else
346 {
347 loadAlphaData(width, height, inputPitch, input, locked.Pitch, locked.pBits);
348 }
349 break;
350 case GL_LUMINANCE:
351 loadLuminanceData(width, height, inputPitch, input, locked.Pitch, locked.pBits, getD3DFormat() == D3DFMT_L8);
352 break;
353 case GL_LUMINANCE_ALPHA:
354 loadLuminanceAlphaData(width, height, inputPitch, input, locked.Pitch, locked.pBits, getD3DFormat() == D3DFMT_A8L8);
355 break;
356 case GL_RGB:
357 loadRGBUByteData(width, height, inputPitch, input, locked.Pitch, locked.pBits);
358 break;
359 case GL_RGBA:
360 if (supportsSSE2())
361 {
362 loadRGBAUByteDataSSE2(width, height, inputPitch, input, locked.Pitch, locked.pBits);
363 }
364 else
365 {
366 loadRGBAUByteData(width, height, inputPitch, input, locked.Pitch, locked.pBits);
367 }
368 break;
369 case GL_BGRA_EXT:
370 loadBGRAData(width, height, inputPitch, input, locked.Pitch, locked.pBits);
371 break;
372 default: UNREACHABLE();
373 }
374 break;
375 case GL_UNSIGNED_SHORT_5_6_5:
376 switch (mFormat)
377 {
378 case GL_RGB:
379 loadRGB565Data(width, height, inputPitch, input, locked.Pitch, locked.pBits);
380 break;
381 default: UNREACHABLE();
382 }
383 break;
384 case GL_UNSIGNED_SHORT_4_4_4_4:
385 switch (mFormat)
386 {
387 case GL_RGBA:
388 loadRGBA4444Data(width, height, inputPitch, input, locked.Pitch, locked.pBits);
389 break;
390 default: UNREACHABLE();
391 }
392 break;
393 case GL_UNSIGNED_SHORT_5_5_5_1:
394 switch (mFormat)
395 {
396 case GL_RGBA:
397 loadRGBA5551Data(width, height, inputPitch, input, locked.Pitch, locked.pBits);
398 break;
399 default: UNREACHABLE();
400 }
401 break;
402 case GL_FLOAT:
403 switch (mFormat)
404 {
405 // float textures are converted to RGBA, not BGRA, as they're stored that way in D3D
406 case GL_ALPHA:
407 loadAlphaFloatData(width, height, inputPitch, input, locked.Pitch, locked.pBits);
408 break;
409 case GL_LUMINANCE:
410 loadLuminanceFloatData(width, height, inputPitch, input, locked.Pitch, locked.pBits);
411 break;
412 case GL_LUMINANCE_ALPHA:
413 loadLuminanceAlphaFloatData(width, height, inputPitch, input, locked.Pitch, locked.pBits);
414 break;
415 case GL_RGB:
416 loadRGBFloatData(width, height, inputPitch, input, locked.Pitch, locked.pBits);
417 break;
418 case GL_RGBA:
419 loadRGBAFloatData(width, height, inputPitch, input, locked.Pitch, locked.pBits);
420 break;
421 default: UNREACHABLE();
422 }
423 break;
424 case GL_HALF_FLOAT_OES:
425 switch (mFormat)
426 {
427 // float textures are converted to RGBA, not BGRA, as they're stored that way in D3D
428 case GL_ALPHA:
429 loadAlphaHalfFloatData(width, height, inputPitch, input, locked.Pitch, locked.pBits);
430 break;
431 case GL_LUMINANCE:
432 loadLuminanceHalfFloatData(width, height, inputPitch, input, locked.Pitch, locked.pBits);
433 break;
434 case GL_LUMINANCE_ALPHA:
435 loadLuminanceAlphaHalfFloatData(width, height, inputPitch, input, locked.Pitch, locked.pBits);
436 break;
437 case GL_RGB:
438 loadRGBHalfFloatData(width, height, inputPitch, input, locked.Pitch, locked.pBits);
439 break;
440 case GL_RGBA:
441 loadRGBAHalfFloatData(width, height, inputPitch, input, locked.Pitch, locked.pBits);
442 break;
443 default: UNREACHABLE();
444 }
445 break;
446 default: UNREACHABLE();
447 }
448
449 unlock();
450}
451
452void Image::loadAlphaData(GLsizei width, GLsizei height,
453 int inputPitch, const void *input, size_t outputPitch, void *output) const
454{
455 const unsigned char *source = NULL;
456 unsigned char *dest = NULL;
457
458 for (int y = 0; y < height; y++)
459 {
460 source = static_cast<const unsigned char*>(input) + y * inputPitch;
461 dest = static_cast<unsigned char*>(output) + y * outputPitch;
462 for (int x = 0; x < width; x++)
463 {
464 dest[4 * x + 0] = 0;
465 dest[4 * x + 1] = 0;
466 dest[4 * x + 2] = 0;
467 dest[4 * x + 3] = source[x];
468 }
469 }
470}
471
472void Image::loadAlphaDataSSE2(GLsizei width, GLsizei height,
473 int inputPitch, const void *input, size_t outputPitch, void *output) const
474{
475 const unsigned char *source = NULL;
476 unsigned int *dest = NULL;
477 __m128i zeroWide = _mm_setzero_si128();
478
479 for (int y = 0; y < height; y++)
480 {
481 source = static_cast<const unsigned char*>(input) + y * inputPitch;
482 dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + y * outputPitch);
483
484 int x;
485 // Make output writes aligned
486 for (x = 0; ((reinterpret_cast<intptr_t>(&dest[x]) & 0xF) != 0 && x < width); x++)
487 {
488 dest[x] = static_cast<unsigned int>(source[x]) << 24;
489 }
490
491 for (; x + 7 < width; x += 8)
492 {
493 __m128i sourceData = _mm_loadl_epi64(reinterpret_cast<const __m128i*>(&source[x]));
494 // Interleave each byte to 16bit, make the lower byte to zero
495 sourceData = _mm_unpacklo_epi8(zeroWide, sourceData);
496 // Interleave each 16bit to 32bit, make the lower 16bit to zero
497 __m128i lo = _mm_unpacklo_epi16(zeroWide, sourceData);
498 __m128i hi = _mm_unpackhi_epi16(zeroWide, sourceData);
499
500 _mm_store_si128(reinterpret_cast<__m128i*>(&dest[x]), lo);
501 _mm_store_si128(reinterpret_cast<__m128i*>(&dest[x + 4]), hi);
502 }
503
504 // Handle the remainder
505 for (; x < width; x++)
506 {
507 dest[x] = static_cast<unsigned int>(source[x]) << 24;
508 }
509 }
510}
511
512void Image::loadAlphaFloatData(GLsizei width, GLsizei height,
513 int inputPitch, const void *input, size_t outputPitch, void *output) const
514{
515 const float *source = NULL;
516 float *dest = NULL;
517
518 for (int y = 0; y < height; y++)
519 {
520 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
521 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + y * outputPitch);
522 for (int x = 0; x < width; x++)
523 {
524 dest[4 * x + 0] = 0;
525 dest[4 * x + 1] = 0;
526 dest[4 * x + 2] = 0;
527 dest[4 * x + 3] = source[x];
528 }
529 }
530}
531
532void Image::loadAlphaHalfFloatData(GLsizei width, GLsizei height,
533 int inputPitch, const void *input, size_t outputPitch, void *output) const
534{
535 const unsigned short *source = NULL;
536 unsigned short *dest = NULL;
537
538 for (int y = 0; y < height; y++)
539 {
540 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
541 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + y * outputPitch);
542 for (int x = 0; x < width; x++)
543 {
544 dest[4 * x + 0] = 0;
545 dest[4 * x + 1] = 0;
546 dest[4 * x + 2] = 0;
547 dest[4 * x + 3] = source[x];
548 }
549 }
550}
551
552void Image::loadLuminanceData(GLsizei width, GLsizei height,
553 int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const
554{
555 const unsigned char *source = NULL;
556 unsigned char *dest = NULL;
557
558 for (int y = 0; y < height; y++)
559 {
560 source = static_cast<const unsigned char*>(input) + y * inputPitch;
561 dest = static_cast<unsigned char*>(output) + y * outputPitch;
562
563 if (!native) // BGRA8 destination format
564 {
565 for (int x = 0; x < width; x++)
566 {
567 dest[4 * x + 0] = source[x];
568 dest[4 * x + 1] = source[x];
569 dest[4 * x + 2] = source[x];
570 dest[4 * x + 3] = 0xFF;
571 }
572 }
573 else // L8 destination format
574 {
575 memcpy(dest, source, width);
576 }
577 }
578}
579
580void Image::loadLuminanceFloatData(GLsizei width, GLsizei height,
581 int inputPitch, const void *input, size_t outputPitch, void *output) const
582{
583 const float *source = NULL;
584 float *dest = NULL;
585
586 for (int y = 0; y < height; y++)
587 {
588 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
589 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + y * outputPitch);
590 for (int x = 0; x < width; x++)
591 {
592 dest[4 * x + 0] = source[x];
593 dest[4 * x + 1] = source[x];
594 dest[4 * x + 2] = source[x];
595 dest[4 * x + 3] = 1.0f;
596 }
597 }
598}
599
600void Image::loadLuminanceHalfFloatData(GLsizei width, GLsizei height,
601 int inputPitch, const void *input, size_t outputPitch, void *output) const
602{
603 const unsigned short *source = NULL;
604 unsigned short *dest = NULL;
605
606 for (int y = 0; y < height; y++)
607 {
608 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
609 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + y * outputPitch);
610 for (int x = 0; x < width; x++)
611 {
612 dest[4 * x + 0] = source[x];
613 dest[4 * x + 1] = source[x];
614 dest[4 * x + 2] = source[x];
615 dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1
616 }
617 }
618}
619
620void Image::loadLuminanceAlphaData(GLsizei width, GLsizei height,
621 int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const
622{
623 const unsigned char *source = NULL;
624 unsigned char *dest = NULL;
625
626 for (int y = 0; y < height; y++)
627 {
628 source = static_cast<const unsigned char*>(input) + y * inputPitch;
629 dest = static_cast<unsigned char*>(output) + y * outputPitch;
630
631 if (!native) // BGRA8 destination format
632 {
633 for (int x = 0; x < width; x++)
634 {
635 dest[4 * x + 0] = source[2*x+0];
636 dest[4 * x + 1] = source[2*x+0];
637 dest[4 * x + 2] = source[2*x+0];
638 dest[4 * x + 3] = source[2*x+1];
639 }
640 }
641 else
642 {
643 memcpy(dest, source, width * 2);
644 }
645 }
646}
647
648void Image::loadLuminanceAlphaFloatData(GLsizei width, GLsizei height,
649 int inputPitch, const void *input, size_t outputPitch, void *output) const
650{
651 const float *source = NULL;
652 float *dest = NULL;
653
654 for (int y = 0; y < height; y++)
655 {
656 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
657 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + y * outputPitch);
658 for (int x = 0; x < width; x++)
659 {
660 dest[4 * x + 0] = source[2*x+0];
661 dest[4 * x + 1] = source[2*x+0];
662 dest[4 * x + 2] = source[2*x+0];
663 dest[4 * x + 3] = source[2*x+1];
664 }
665 }
666}
667
668void Image::loadLuminanceAlphaHalfFloatData(GLsizei width, GLsizei height,
669 int inputPitch, const void *input, size_t outputPitch, void *output) const
670{
671 const unsigned short *source = NULL;
672 unsigned short *dest = NULL;
673
674 for (int y = 0; y < height; y++)
675 {
676 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
677 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + y * outputPitch);
678 for (int x = 0; x < width; x++)
679 {
680 dest[4 * x + 0] = source[2*x+0];
681 dest[4 * x + 1] = source[2*x+0];
682 dest[4 * x + 2] = source[2*x+0];
683 dest[4 * x + 3] = source[2*x+1];
684 }
685 }
686}
687
688void Image::loadRGBUByteData(GLsizei width, GLsizei height,
689 int inputPitch, const void *input, size_t outputPitch, void *output) const
690{
691 const unsigned char *source = NULL;
692 unsigned char *dest = NULL;
693
694 for (int y = 0; y < height; y++)
695 {
696 source = static_cast<const unsigned char*>(input) + y * inputPitch;
697 dest = static_cast<unsigned char*>(output) + y * outputPitch;
698 for (int x = 0; x < width; x++)
699 {
700 dest[4 * x + 0] = source[x * 3 + 2];
701 dest[4 * x + 1] = source[x * 3 + 1];
702 dest[4 * x + 2] = source[x * 3 + 0];
703 dest[4 * x + 3] = 0xFF;
704 }
705 }
706}
707
708void Image::loadRGB565Data(GLsizei width, GLsizei height,
709 int inputPitch, const void *input, size_t outputPitch, void *output) const
710{
711 const unsigned short *source = NULL;
712 unsigned char *dest = NULL;
713
714 for (int y = 0; y < height; y++)
715 {
716 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
717 dest = static_cast<unsigned char*>(output) + y * outputPitch;
718 for (int x = 0; x < width; x++)
719 {
720 unsigned short rgba = source[x];
721 dest[4 * x + 0] = ((rgba & 0x001F) << 3) | ((rgba & 0x001F) >> 2);
722 dest[4 * x + 1] = ((rgba & 0x07E0) >> 3) | ((rgba & 0x07E0) >> 9);
723 dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
724 dest[4 * x + 3] = 0xFF;
725 }
726 }
727}
728
729void Image::loadRGBFloatData(GLsizei width, GLsizei height,
730 int inputPitch, const void *input, size_t outputPitch, void *output) const
731{
732 const float *source = NULL;
733 float *dest = NULL;
734
735 for (int y = 0; y < height; y++)
736 {
737 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
738 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + y * outputPitch);
739 for (int x = 0; x < width; x++)
740 {
741 dest[4 * x + 0] = source[x * 3 + 0];
742 dest[4 * x + 1] = source[x * 3 + 1];
743 dest[4 * x + 2] = source[x * 3 + 2];
744 dest[4 * x + 3] = 1.0f;
745 }
746 }
747}
748
749void Image::loadRGBHalfFloatData(GLsizei width, GLsizei height,
750 int inputPitch, const void *input, size_t outputPitch, void *output) const
751{
752 const unsigned short *source = NULL;
753 unsigned short *dest = NULL;
754
755 for (int y = 0; y < height; y++)
756 {
757 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
758 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + y * outputPitch);
759 for (int x = 0; x < width; x++)
760 {
761 dest[4 * x + 0] = source[x * 3 + 0];
762 dest[4 * x + 1] = source[x * 3 + 1];
763 dest[4 * x + 2] = source[x * 3 + 2];
764 dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1
765 }
766 }
767}
768
769void Image::loadRGBAUByteDataSSE2(GLsizei width, GLsizei height,
770 int inputPitch, const void *input, size_t outputPitch, void *output) const
771{
772 const unsigned int *source = NULL;
773 unsigned int *dest = NULL;
774 __m128i brMask = _mm_set1_epi32(0x00ff00ff);
775
776 for (int y = 0; y < height; y++)
777 {
778 source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);
779 dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + y * outputPitch);
780 int x = 0;
781
782 // Make output writes aligned
783 for (x = 0; ((reinterpret_cast<intptr_t>(&dest[x]) & 15) != 0) && x < width; x++)
784 {
785 unsigned int rgba = source[x];
786 dest[x] = (_rotl(rgba, 16) & 0x00ff00ff) | (rgba & 0xff00ff00);
787 }
788
789 for (; x + 3 < width; x += 4)
790 {
791 __m128i sourceData = _mm_loadu_si128(reinterpret_cast<const __m128i*>(&source[x]));
792 // Mask out g and a, which don't change
793 __m128i gaComponents = _mm_andnot_si128(brMask, sourceData);
794 // Mask out b and r
795 __m128i brComponents = _mm_and_si128(sourceData, brMask);
796 // Swap b and r
797 __m128i brSwapped = _mm_shufflehi_epi16(_mm_shufflelo_epi16(brComponents, _MM_SHUFFLE(2, 3, 0, 1)), _MM_SHUFFLE(2, 3, 0, 1));
798 __m128i result = _mm_or_si128(gaComponents, brSwapped);
799 _mm_store_si128(reinterpret_cast<__m128i*>(&dest[x]), result);
800 }
801
802 // Perform leftover writes
803 for (; x < width; x++)
804 {
805 unsigned int rgba = source[x];
806 dest[x] = (_rotl(rgba, 16) & 0x00ff00ff) | (rgba & 0xff00ff00);
807 }
808 }
809}
810
811void Image::loadRGBAUByteData(GLsizei width, GLsizei height,
812 int inputPitch, const void *input, size_t outputPitch, void *output) const
813{
814 const unsigned int *source = NULL;
815 unsigned int *dest = NULL;
816 for (int y = 0; y < height; y++)
817 {
818 source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);
819 dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + y * outputPitch);
820
821 for (int x = 0; x < width; x++)
822 {
823 unsigned int rgba = source[x];
824 dest[x] = (_rotl(rgba, 16) & 0x00ff00ff) | (rgba & 0xff00ff00);
825 }
826 }
827}
828
829void Image::loadRGBA4444Data(GLsizei width, GLsizei height,
830 int inputPitch, const void *input, size_t outputPitch, void *output) const
831{
832 const unsigned short *source = NULL;
833 unsigned char *dest = NULL;
834
835 for (int y = 0; y < height; y++)
836 {
837 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
838 dest = static_cast<unsigned char*>(output) + y * outputPitch;
839 for (int x = 0; x < width; x++)
840 {
841 unsigned short rgba = source[x];
842 dest[4 * x + 0] = ((rgba & 0x00F0) << 0) | ((rgba & 0x00F0) >> 4);
843 dest[4 * x + 1] = ((rgba & 0x0F00) >> 4) | ((rgba & 0x0F00) >> 8);
844 dest[4 * x + 2] = ((rgba & 0xF000) >> 8) | ((rgba & 0xF000) >> 12);
845 dest[4 * x + 3] = ((rgba & 0x000F) << 4) | ((rgba & 0x000F) >> 0);
846 }
847 }
848}
849
850void Image::loadRGBA5551Data(GLsizei width, GLsizei height,
851 int inputPitch, const void *input, size_t outputPitch, void *output) const
852{
853 const unsigned short *source = NULL;
854 unsigned char *dest = NULL;
855
856 for (int y = 0; y < height; y++)
857 {
858 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
859 dest = static_cast<unsigned char*>(output) + y * outputPitch;
860 for (int x = 0; x < width; x++)
861 {
862 unsigned short rgba = source[x];
863 dest[4 * x + 0] = ((rgba & 0x003E) << 2) | ((rgba & 0x003E) >> 3);
864 dest[4 * x + 1] = ((rgba & 0x07C0) >> 3) | ((rgba & 0x07C0) >> 8);
865 dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
866 dest[4 * x + 3] = (rgba & 0x0001) ? 0xFF : 0;
867 }
868 }
869}
870
871void Image::loadRGBAFloatData(GLsizei width, GLsizei height,
872 int inputPitch, const void *input, size_t outputPitch, void *output) const
873{
874 const float *source = NULL;
875 float *dest = NULL;
876
877 for (int y = 0; y < height; y++)
878 {
879 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
880 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + y * outputPitch);
881 memcpy(dest, source, width * 16);
882 }
883}
884
885void Image::loadRGBAHalfFloatData(GLsizei width, GLsizei height,
886 int inputPitch, const void *input, size_t outputPitch, void *output) const
887{
888 const unsigned char *source = NULL;
889 unsigned char *dest = NULL;
890
891 for (int y = 0; y < height; y++)
892 {
893 source = static_cast<const unsigned char*>(input) + y * inputPitch;
894 dest = static_cast<unsigned char*>(output) + y * outputPitch;
895 memcpy(dest, source, width * 8);
896 }
897}
898
899void Image::loadBGRAData(GLsizei width, GLsizei height,
900 int inputPitch, const void *input, size_t outputPitch, void *output) const
901{
902 const unsigned char *source = NULL;
903 unsigned char *dest = NULL;
904
905 for (int y = 0; y < height; y++)
906 {
907 source = static_cast<const unsigned char*>(input) + y * inputPitch;
908 dest = static_cast<unsigned char*>(output) + y * outputPitch;
909 memcpy(dest, source, width*4);
910 }
911}
912
913void Image::loadCompressedData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
914 const void *input) {
915 ASSERT(xoffset % 4 == 0);
916 ASSERT(yoffset % 4 == 0);
917
918 RECT lockRect = {
919 xoffset, yoffset,
920 xoffset + width, yoffset + height
921 };
922
923 D3DLOCKED_RECT locked;
924 HRESULT result = lock(&locked, &lockRect);
925 if (FAILED(result))
926 {
927 return;
928 }
929
930 GLsizei inputSize = ComputeCompressedSize(width, height, mFormat);
931 GLsizei inputPitch = ComputeCompressedPitch(width, mFormat);
932 int rows = inputSize / inputPitch;
933 for (int i = 0; i < rows; ++i)
934 {
935 memcpy((void*)((BYTE*)locked.pBits + i * locked.Pitch), (void*)((BYTE*)input + i * inputPitch), inputPitch);
936 }
937
938 unlock();
939}
940
941// This implements glCopyTex[Sub]Image2D for non-renderable internal texture formats and incomplete textures
942void Image::copy(GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, IDirect3DSurface9 *renderTarget)
943{
944 IDirect3DDevice9 *device = getDevice();
945 IDirect3DSurface9 *renderTargetData = NULL;
946 D3DSURFACE_DESC description;
947 renderTarget->GetDesc(&description);
948
949 HRESULT result = device->CreateOffscreenPlainSurface(description.Width, description.Height, description.Format, D3DPOOL_SYSTEMMEM, &renderTargetData, NULL);
950
951 if (FAILED(result))
952 {
953 ERR("Could not create matching destination surface.");
954 return error(GL_OUT_OF_MEMORY);
955 }
956
957 result = device->GetRenderTargetData(renderTarget, renderTargetData);
958
959 if (FAILED(result))
960 {
961 ERR("GetRenderTargetData unexpectedly failed.");
962 renderTargetData->Release();
963 return error(GL_OUT_OF_MEMORY);
964 }
965
966 RECT sourceRect = {x, y, x + width, y + height};
967 RECT destRect = {xoffset, yoffset, xoffset + width, yoffset + height};
968
969 if (isRenderableFormat())
970 {
971 result = D3DXLoadSurfaceFromSurface(getSurface(), NULL, &destRect, renderTargetData, NULL, &sourceRect, D3DX_FILTER_BOX, 0);
972
973 if (FAILED(result))
974 {
975 ERR("Copying surfaces unexpectedly failed.");
976 renderTargetData->Release();
977 return error(GL_OUT_OF_MEMORY);
978 }
979 }
980 else
981 {
982 D3DLOCKED_RECT sourceLock = {0};
983 result = renderTargetData->LockRect(&sourceLock, &sourceRect, 0);
984
985 if (FAILED(result))
986 {
987 ERR("Failed to lock the source surface (rectangle might be invalid).");
988 renderTargetData->Release();
989 return error(GL_OUT_OF_MEMORY);
990 }
991
992 D3DLOCKED_RECT destLock = {0};
993 result = lock(&destLock, &destRect);
994
995 if (FAILED(result))
996 {
997 ERR("Failed to lock the destination surface (rectangle might be invalid).");
998 renderTargetData->UnlockRect();
999 renderTargetData->Release();
1000 return error(GL_OUT_OF_MEMORY);
1001 }
1002
1003 if (destLock.pBits && sourceLock.pBits)
1004 {
1005 unsigned char *source = (unsigned char*)sourceLock.pBits;
1006 unsigned char *dest = (unsigned char*)destLock.pBits;
1007
1008 switch (description.Format)
1009 {
1010 case D3DFMT_X8R8G8B8:
1011 case D3DFMT_A8R8G8B8:
1012 switch(getD3DFormat())
1013 {
1014 case D3DFMT_L8:
1015 for(int y = 0; y < height; y++)
1016 {
1017 for(int x = 0; x < width; x++)
1018 {
1019 dest[x] = source[x * 4 + 2];
1020 }
1021
1022 source += sourceLock.Pitch;
1023 dest += destLock.Pitch;
1024 }
1025 break;
1026 case D3DFMT_A8L8:
1027 for(int y = 0; y < height; y++)
1028 {
1029 for(int x = 0; x < width; x++)
1030 {
1031 dest[x * 2 + 0] = source[x * 4 + 2];
1032 dest[x * 2 + 1] = source[x * 4 + 3];
1033 }
1034
1035 source += sourceLock.Pitch;
1036 dest += destLock.Pitch;
1037 }
1038 break;
1039 default:
1040 UNREACHABLE();
1041 }
1042 break;
1043 case D3DFMT_R5G6B5:
1044 switch(getD3DFormat())
1045 {
1046 case D3DFMT_L8:
1047 for(int y = 0; y < height; y++)
1048 {
1049 for(int x = 0; x < width; x++)
1050 {
1051 unsigned char red = source[x * 2 + 1] & 0xF8;
1052 dest[x] = red | (red >> 5);
1053 }
1054
1055 source += sourceLock.Pitch;
1056 dest += destLock.Pitch;
1057 }
1058 break;
1059 default:
1060 UNREACHABLE();
1061 }
1062 break;
1063 case D3DFMT_A1R5G5B5:
1064 switch(getD3DFormat())
1065 {
1066 case D3DFMT_L8:
1067 for(int y = 0; y < height; y++)
1068 {
1069 for(int x = 0; x < width; x++)
1070 {
1071 unsigned char red = source[x * 2 + 1] & 0x7C;
1072 dest[x] = (red << 1) | (red >> 4);
1073 }
1074
1075 source += sourceLock.Pitch;
1076 dest += destLock.Pitch;
1077 }
1078 break;
1079 case D3DFMT_A8L8:
1080 for(int y = 0; y < height; y++)
1081 {
1082 for(int x = 0; x < width; x++)
1083 {
1084 unsigned char red = source[x * 2 + 1] & 0x7C;
1085 dest[x * 2 + 0] = (red << 1) | (red >> 4);
1086 dest[x * 2 + 1] = (signed char)source[x * 2 + 1] >> 7;
1087 }
1088
1089 source += sourceLock.Pitch;
1090 dest += destLock.Pitch;
1091 }
1092 break;
1093 default:
1094 UNREACHABLE();
1095 }
1096 break;
1097 default:
1098 UNREACHABLE();
1099 }
1100 }
1101
1102 unlock();
1103 renderTargetData->UnlockRect();
1104 }
1105
1106 renderTargetData->Release();
1107
1108 mDirty = true;
1109}
1110
1111TextureStorage::TextureStorage(DWORD usage)
1112 : mD3DUsage(usage),
1113 mD3DPool(getDisplay()->getTexturePool(usage)),
1114 mTextureSerial(issueTextureSerial())
1115{
1116}
1117
1118TextureStorage::~TextureStorage()
1119{
1120}
1121
1122bool TextureStorage::isRenderTarget() const
1123{
1124 return (mD3DUsage & (D3DUSAGE_RENDERTARGET | D3DUSAGE_DEPTHSTENCIL)) != 0;
1125}
1126
1127bool TextureStorage::isManaged() const
1128{
1129 return (mD3DPool == D3DPOOL_MANAGED);
1130}
1131
1132D3DPOOL TextureStorage::getPool() const
1133{
1134 return mD3DPool;
1135}
1136
1137DWORD TextureStorage::getUsage() const
1138{
1139 return mD3DUsage;
1140}
1141
1142unsigned int TextureStorage::getTextureSerial() const
1143{
1144 return mTextureSerial;
1145}
1146
1147unsigned int TextureStorage::issueTextureSerial()
1148{
1149 return mCurrentTextureSerial++;
1150}
1151
1152Texture::Texture(GLuint id) : RefCountObject(id)
1153{
1154 mMinFilter = GL_NEAREST_MIPMAP_LINEAR;
1155 mMagFilter = GL_LINEAR;
1156 mWrapS = GL_REPEAT;
1157 mWrapT = GL_REPEAT;
1158 mDirtyParameters = true;
1159 mUsage = GL_NONE;
1160
1161 mDirtyImages = true;
1162
1163 mImmutable = false;
1164}
1165
1166Texture::~Texture()
1167{
1168}
1169
1170// Returns true on successful filter state update (valid enum parameter)
1171bool Texture::setMinFilter(GLenum filter)
1172{
1173 switch (filter)
1174 {
1175 case GL_NEAREST:
1176 case GL_LINEAR:
1177 case GL_NEAREST_MIPMAP_NEAREST:
1178 case GL_LINEAR_MIPMAP_NEAREST:
1179 case GL_NEAREST_MIPMAP_LINEAR:
1180 case GL_LINEAR_MIPMAP_LINEAR:
1181 {
1182 if (mMinFilter != filter)
1183 {
1184 mMinFilter = filter;
1185 mDirtyParameters = true;
1186 }
1187 return true;
1188 }
1189 default:
1190 return false;
1191 }
1192}
1193
1194// Returns true on successful filter state update (valid enum parameter)
1195bool Texture::setMagFilter(GLenum filter)
1196{
1197 switch (filter)
1198 {
1199 case GL_NEAREST:
1200 case GL_LINEAR:
1201 {
1202 if (mMagFilter != filter)
1203 {
1204 mMagFilter = filter;
1205 mDirtyParameters = true;
1206 }
1207 return true;
1208 }
1209 default:
1210 return false;
1211 }
1212}
1213
1214// Returns true on successful wrap state update (valid enum parameter)
1215bool Texture::setWrapS(GLenum wrap)
1216{
1217 switch (wrap)
1218 {
1219 case GL_REPEAT:
1220 case GL_CLAMP_TO_EDGE:
1221 case GL_MIRRORED_REPEAT:
1222 {
1223 if (mWrapS != wrap)
1224 {
1225 mWrapS = wrap;
1226 mDirtyParameters = true;
1227 }
1228 return true;
1229 }
1230 default:
1231 return false;
1232 }
1233}
1234
1235// Returns true on successful wrap state update (valid enum parameter)
1236bool Texture::setWrapT(GLenum wrap)
1237{
1238 switch (wrap)
1239 {
1240 case GL_REPEAT:
1241 case GL_CLAMP_TO_EDGE:
1242 case GL_MIRRORED_REPEAT:
1243 {
1244 if (mWrapT != wrap)
1245 {
1246 mWrapT = wrap;
1247 mDirtyParameters = true;
1248 }
1249 return true;
1250 }
1251 default:
1252 return false;
1253 }
1254}
1255
1256// Returns true on successful usage state update (valid enum parameter)
1257bool Texture::setUsage(GLenum usage)
1258{
1259 switch (usage)
1260 {
1261 case GL_NONE:
1262 case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
1263 mUsage = usage;
1264 return true;
1265 default:
1266 return false;
1267 }
1268}
1269
1270GLenum Texture::getMinFilter() const
1271{
1272 return mMinFilter;
1273}
1274
1275GLenum Texture::getMagFilter() const
1276{
1277 return mMagFilter;
1278}
1279
1280GLenum Texture::getWrapS() const
1281{
1282 return mWrapS;
1283}
1284
1285GLenum Texture::getWrapT() const
1286{
1287 return mWrapT;
1288}
1289
1290GLenum Texture::getUsage() const
1291{
1292 return mUsage;
1293}
1294
1295void Texture::setImage(GLint unpackAlignment, const void *pixels, Image *image)
1296{
1297 if (pixels != NULL)
1298 {
1299 image->loadData(0, 0, image->getWidth(), image->getHeight(), image->getType(), unpackAlignment, pixels);
1300 mDirtyImages = true;
1301 }
1302}
1303
1304void Texture::setCompressedImage(GLsizei imageSize, const void *pixels, Image *image)
1305{
1306 if (pixels != NULL)
1307 {
1308 image->loadCompressedData(0, 0, image->getWidth(), image->getHeight(), pixels);
1309 mDirtyImages = true;
1310 }
1311}
1312
1313bool Texture::subImage(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, Image *image)
1314{
1315 if (pixels != NULL)
1316 {
1317 image->loadData(xoffset, yoffset, width, height, type, unpackAlignment, pixels);
1318 mDirtyImages = true;
1319 }
1320
1321 return true;
1322}
1323
1324bool Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, Image *image)
1325{
1326 if (pixels != NULL)
1327 {
1328 image->loadCompressedData(xoffset, yoffset, width, height, pixels);
1329 mDirtyImages = true;
1330 }
1331
1332 return true;
1333}
1334
1335IDirect3DBaseTexture9 *Texture::getTexture()
1336{
1337 if (!isSamplerComplete())
1338 {
1339 return NULL;
1340 }
1341
1342 // ensure the underlying texture is created
1343 if (getStorage(false) == NULL)
1344 {
1345 return NULL;
1346 }
1347
1348 updateTexture();
1349
1350 return getBaseTexture();
1351}
1352
1353bool Texture::hasDirtyParameters() const
1354{
1355 return mDirtyParameters;
1356}
1357
1358bool Texture::hasDirtyImages() const
1359{
1360 return mDirtyImages;
1361}
1362
1363void Texture::resetDirty()
1364{
1365 mDirtyParameters = false;
1366 mDirtyImages = false;
1367}
1368
1369unsigned int Texture::getTextureSerial()
1370{
1371 TextureStorage *texture = getStorage(false);
1372 return texture ? texture->getTextureSerial() : 0;
1373}
1374
1375unsigned int Texture::getRenderTargetSerial(GLenum target)
1376{
1377 TextureStorage *texture = getStorage(true);
1378 return texture ? texture->getRenderTargetSerial(target) : 0;
1379}
1380
1381bool Texture::isImmutable() const
1382{
1383 return mImmutable;
1384}
1385
1386GLint Texture::creationLevels(GLsizei width, GLsizei height) const
1387{
1388 if ((isPow2(width) && isPow2(height)) || getContext()->supportsNonPower2Texture())
1389 {
1390 return 0; // Maximum number of levels
1391 }
1392 else
1393 {
1394 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
1395 return 1;
1396 }
1397}
1398
1399GLint Texture::creationLevels(GLsizei size) const
1400{
1401 return creationLevels(size, size);
1402}
1403
1404int Texture::levelCount() const
1405{
1406 return getBaseTexture() ? getBaseTexture()->GetLevelCount() : 0;
1407}
1408
1409Blit *Texture::getBlitter()
1410{
1411 Context *context = getContext();
1412 return context->getBlitter();
1413}
1414
1415bool Texture::copyToRenderTarget(IDirect3DSurface9 *dest, IDirect3DSurface9 *source, bool fromManaged)
1416{
1417 if (source && dest)
1418 {
1419 HRESULT result;
1420
1421 if (fromManaged)
1422 {
1423 result = D3DXLoadSurfaceFromSurface(dest, NULL, NULL, source, NULL, NULL, D3DX_FILTER_BOX, 0);
1424 }
1425 else
1426 {
1427 egl::Display *display = getDisplay();
1428 IDirect3DDevice9 *device = display->getDevice();
1429
1430 display->endScene();
1431 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
1432 }
1433
1434 if (FAILED(result))
1435 {
1436 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1437 return false;
1438 }
1439 }
1440
1441 return true;
1442}
1443
1444TextureStorage2D::TextureStorage2D(IDirect3DTexture9 *surfaceTexture) : TextureStorage(D3DUSAGE_RENDERTARGET), mRenderTargetSerial(RenderbufferStorage::issueSerial())
1445{
1446 mTexture = surfaceTexture;
1447}
1448
1449TextureStorage2D::TextureStorage2D(int levels, D3DFORMAT format, DWORD usage, int width, int height)
1450 : TextureStorage(usage), mRenderTargetSerial(RenderbufferStorage::issueSerial())
1451{
1452 mTexture = NULL;
1453 // if the width or height is not positive this should be treated as an incomplete texture
1454 // we handle that here by skipping the d3d texture creation
1455 if (width > 0 && height > 0)
1456 {
1457 IDirect3DDevice9 *device = getDevice();
1458 HRESULT result = device->CreateTexture(width, height, levels, getUsage(), format, getPool(), &mTexture, NULL);
1459
1460 if (FAILED(result))
1461 {
1462 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1463 error(GL_OUT_OF_MEMORY);
1464 }
1465 }
1466}
1467
1468TextureStorage2D::~TextureStorage2D()
1469{
1470 if (mTexture)
1471 {
1472 mTexture->Release();
1473 }
1474}
1475
1476// Increments refcount on surface.
1477// caller must Release() the returned surface
1478IDirect3DSurface9 *TextureStorage2D::getSurfaceLevel(int level)
1479{
1480 IDirect3DSurface9 *surface = NULL;
1481
1482 if (mTexture)
1483 {
1484 HRESULT result = mTexture->GetSurfaceLevel(level, &surface);
1485 ASSERT(SUCCEEDED(result));
1486 }
1487
1488 return surface;
1489}
1490
1491IDirect3DBaseTexture9 *TextureStorage2D::getBaseTexture() const
1492{
1493 return mTexture;
1494}
1495
1496unsigned int TextureStorage2D::getRenderTargetSerial(GLenum target) const
1497{
1498 return mRenderTargetSerial;
1499}
1500
1501Texture2D::Texture2D(GLuint id) : Texture(id)
1502{
1503 mTexStorage = NULL;
1504 mSurface = NULL;
1505 mColorbufferProxy = NULL;
1506 mProxyRefs = 0;
1507}
1508
1509Texture2D::~Texture2D()
1510{
1511 mColorbufferProxy = NULL;
1512
1513 delete mTexStorage;
1514 mTexStorage = NULL;
1515
1516 if (mSurface)
1517 {
1518 mSurface->setBoundTexture(NULL);
1519 mSurface = NULL;
1520 }
1521}
1522
1523// We need to maintain a count of references to renderbuffers acting as
1524// proxies for this texture, so that we do not attempt to use a pointer
1525// to a renderbuffer proxy which has been deleted.
1526void Texture2D::addProxyRef(const Renderbuffer *proxy)
1527{
1528 mProxyRefs++;
1529}
1530
1531void Texture2D::releaseProxy(const Renderbuffer *proxy)
1532{
1533 if (mProxyRefs > 0)
1534 mProxyRefs--;
1535
1536 if (mProxyRefs == 0)
1537 mColorbufferProxy = NULL;
1538}
1539
1540GLenum Texture2D::getTarget() const
1541{
1542 return GL_TEXTURE_2D;
1543}
1544
1545GLsizei Texture2D::getWidth(GLint level) const
1546{
1547 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1548 return mImageArray[level].getWidth();
1549 else
1550 return 0;
1551}
1552
1553GLsizei Texture2D::getHeight(GLint level) const
1554{
1555 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1556 return mImageArray[level].getHeight();
1557 else
1558 return 0;
1559}
1560
1561GLenum Texture2D::getInternalFormat(GLint level) const
1562{
1563 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1564 return mImageArray[level].getFormat();
1565 else
1566 return GL_NONE;
1567}
1568
1569D3DFORMAT Texture2D::getD3DFormat(GLint level) const
1570{
1571 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1572 return mImageArray[level].getD3DFormat();
1573 else
1574 return D3DFMT_UNKNOWN;
1575}
1576
1577void Texture2D::redefineImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLenum type)
1578{
1579 releaseTexImage();
1580
1581 bool redefined = mImageArray[level].redefine(format, width, height, type, false);
1582
1583 if (mTexStorage && redefined)
1584 {
1585 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1586 {
1587 mImageArray[i].markDirty();
1588 }
1589
1590 delete mTexStorage;
1591 mTexStorage = NULL;
1592 mDirtyImages = true;
1593 }
1594}
1595
1596void Texture2D::setImage(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1597{
1598 redefineImage(level, format, width, height, type);
1599
1600 Texture::setImage(unpackAlignment, pixels, &mImageArray[level]);
1601}
1602
1603void Texture2D::bindTexImage(egl::Surface *surface)
1604{
1605 releaseTexImage();
1606
1607 GLenum format;
1608
1609 switch(surface->getFormat())
1610 {
1611 case D3DFMT_A8R8G8B8:
1612 format = GL_RGBA;
1613 break;
1614 case D3DFMT_X8R8G8B8:
1615 format = GL_RGB;
1616 break;
1617 default:
1618 UNIMPLEMENTED();
1619 return;
1620 }
1621
1622 mImageArray[0].redefine(format, surface->getWidth(), surface->getHeight(), GL_UNSIGNED_BYTE, true);
1623
1624 delete mTexStorage;
1625 mTexStorage = new TextureStorage2D(surface->getOffscreenTexture());
1626
1627 mDirtyImages = true;
1628 mSurface = surface;
1629 mSurface->setBoundTexture(this);
1630}
1631
1632void Texture2D::releaseTexImage()
1633{
1634 if (mSurface)
1635 {
1636 mSurface->setBoundTexture(NULL);
1637 mSurface = NULL;
1638
1639 if (mTexStorage)
1640 {
1641 delete mTexStorage;
1642 mTexStorage = NULL;
1643 }
1644
1645 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1646 {
1647 mImageArray[i].redefine(GL_RGBA, 0, 0, GL_UNSIGNED_BYTE, true);
1648 }
1649 }
1650}
1651
1652void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
1653{
1654 redefineImage(level, format, width, height, GL_UNSIGNED_BYTE);
1655
1656 Texture::setCompressedImage(imageSize, pixels, &mImageArray[level]);
1657}
1658
1659void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1660{
1661 ASSERT(mImageArray[level].getSurface() != NULL);
1662
1663 if (level < levelCount())
1664 {
1665 IDirect3DSurface9 *destLevel = mTexStorage->getSurfaceLevel(level);
1666
1667 if (destLevel)
1668 {
1669 Image *image = &mImageArray[level];
1670 image->updateSurface(destLevel, xoffset, yoffset, width, height);
1671
1672 destLevel->Release();
1673 image->markClean();
1674 }
1675 }
1676}
1677
1678void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1679{
1680 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[level]))
1681 {
1682 commitRect(level, xoffset, yoffset, width, height);
1683 }
1684}
1685
1686void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1687{
1688 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[level]))
1689 {
1690 commitRect(level, xoffset, yoffset, width, height);
1691 }
1692}
1693
1694void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1695{
1696 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
1697
1698 if (!renderTarget)
1699 {
1700 ERR("Failed to retrieve the render target.");
1701 return error(GL_OUT_OF_MEMORY);
1702 }
1703
1704 redefineImage(level, format, width, height, GL_UNSIGNED_BYTE);
1705
1706 if (!mImageArray[level].isRenderableFormat())
1707 {
1708 mImageArray[level].copy(0, 0, x, y, width, height, renderTarget);
1709 mDirtyImages = true;
1710 }
1711 else
1712 {
1713 if (!mTexStorage || !mTexStorage->isRenderTarget())
1714 {
1715 convertToRenderTarget();
1716 }
1717
1718 mImageArray[level].markClean();
1719
1720 if (width != 0 && height != 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
1728 IDirect3DSurface9 *dest = mTexStorage->getSurfaceLevel(level);
1729
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 Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1742{
1743 if (xoffset + width > mImageArray[level].getWidth() || yoffset + height > mImageArray[level].getHeight())
1744 {
1745 return error(GL_INVALID_VALUE);
1746 }
1747
1748 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
1749
1750 if (!renderTarget)
1751 {
1752 ERR("Failed to retrieve the render target.");
1753 return error(GL_OUT_OF_MEMORY);
1754 }
1755
1756 if (!mImageArray[level].isRenderableFormat() || (!mTexStorage && !isSamplerComplete()))
1757 {
1758 mImageArray[level].copy(xoffset, yoffset, x, y, width, height, renderTarget);
1759 mDirtyImages = true;
1760 }
1761 else
1762 {
1763 if (!mTexStorage || !mTexStorage->isRenderTarget())
1764 {
1765 convertToRenderTarget();
1766 }
1767
1768 updateTexture();
1769
1770 if (level < levelCount())
1771 {
1772 RECT sourceRect;
1773 sourceRect.left = x;
1774 sourceRect.right = x + width;
1775 sourceRect.top = y;
1776 sourceRect.bottom = y + height;
1777
1778
1779 IDirect3DSurface9 *dest = mTexStorage->getSurfaceLevel(level);
1780
1781 if (dest)
1782 {
1783 getBlitter()->copy(renderTarget, sourceRect, mImageArray[0].getFormat(), xoffset, yoffset, dest);
1784 dest->Release();
1785 }
1786 }
1787 }
1788
1789 renderTarget->Release();
1790}
1791
1792void Texture2D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height)
1793{
1794 GLenum format = gl::ExtractFormat(internalformat);
1795 GLenum type = gl::ExtractType(internalformat);
1796 D3DFORMAT d3dfmt = ConvertTextureFormatType(format, type);
1797 DWORD d3dusage = GetTextureUsage(d3dfmt, mUsage, false);
1798
1799 delete mTexStorage;
1800 mTexStorage = new TextureStorage2D(levels, d3dfmt, d3dusage, width, height);
1801 mImmutable = true;
1802
1803 for (int level = 0; level < levels; level++)
1804 {
1805 mImageArray[level].redefine(format, width, height, type, true);
1806 width = std::max(1, width >> 1);
1807 height = std::max(1, height >> 1);
1808 }
1809
1810 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1811 {
1812 mImageArray[level].redefine(GL_NONE, 0, 0, GL_UNSIGNED_BYTE, true);
1813 }
1814
1815 if (mTexStorage->isManaged())
1816 {
1817 int levels = levelCount();
1818
1819 for (int level = 0; level < levels; level++)
1820 {
1821 IDirect3DSurface9 *surface = mTexStorage->getSurfaceLevel(level);
1822 mImageArray[level].setManagedSurface(surface);
1823 }
1824 }
1825}
1826
1827// Tests for 2D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85.
1828bool Texture2D::isSamplerComplete() const
1829{
1830 GLsizei width = mImageArray[0].getWidth();
1831 GLsizei height = mImageArray[0].getHeight();
1832
1833 if (width <= 0 || height <= 0)
1834 {
1835 return false;
1836 }
1837
1838 bool mipmapping = false;
1839
1840 switch (mMinFilter)
1841 {
1842 case GL_NEAREST:
1843 case GL_LINEAR:
1844 mipmapping = false;
1845 break;
1846 case GL_NEAREST_MIPMAP_NEAREST:
1847 case GL_LINEAR_MIPMAP_NEAREST:
1848 case GL_NEAREST_MIPMAP_LINEAR:
1849 case GL_LINEAR_MIPMAP_LINEAR:
1850 mipmapping = true;
1851 break;
1852 default: UNREACHABLE();
1853 }
1854
1855 if ((getInternalFormat(0) == GL_FLOAT && !getContext()->supportsFloat32LinearFilter()) ||
1856 (getInternalFormat(0) == GL_HALF_FLOAT_OES && !getContext()->supportsFloat16LinearFilter()))
1857 {
1858 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
1859 {
1860 return false;
1861 }
1862 }
1863
1864 bool npotSupport = getContext()->supportsNonPower2Texture();
1865
1866 if (!npotSupport)
1867 {
1868 if ((getWrapS() != GL_CLAMP_TO_EDGE && !isPow2(width)) ||
1869 (getWrapT() != GL_CLAMP_TO_EDGE && !isPow2(height)))
1870 {
1871 return false;
1872 }
1873 }
1874
1875 if (mipmapping)
1876 {
1877 if (!npotSupport)
1878 {
1879 if (!isPow2(width) || !isPow2(height))
1880 {
1881 return false;
1882 }
1883 }
1884
1885 if (!isMipmapComplete())
1886 {
1887 return false;
1888 }
1889 }
1890
1891 return true;
1892}
1893
1894// Tests for 2D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1895bool Texture2D::isMipmapComplete() const
1896{
1897 if (isImmutable())
1898 {
1899 return true;
1900 }
1901
1902 GLsizei width = mImageArray[0].getWidth();
1903 GLsizei height = mImageArray[0].getHeight();
1904
1905 if (width <= 0 || height <= 0)
1906 {
1907 return false;
1908 }
1909
1910 int q = log2(std::max(width, height));
1911
1912 for (int level = 1; level <= q; level++)
1913 {
1914 if (mImageArray[level].getFormat() != mImageArray[0].getFormat())
1915 {
1916 return false;
1917 }
1918
1919 if (mImageArray[level].getType() != mImageArray[0].getType())
1920 {
1921 return false;
1922 }
1923
1924 if (mImageArray[level].getWidth() != std::max(1, width >> level))
1925 {
1926 return false;
1927 }
1928
1929 if (mImageArray[level].getHeight() != std::max(1, height >> level))
1930 {
1931 return false;
1932 }
1933 }
1934
1935 return true;
1936}
1937
1938bool Texture2D::isCompressed(GLint level) const
1939{
1940 return IsCompressed(getInternalFormat(level));
1941}
1942
1943bool Texture2D::isDepth(GLint level) const
1944{
1945 return IsDepthTexture(getInternalFormat(level));
1946}
1947
1948IDirect3DBaseTexture9 *Texture2D::getBaseTexture() const
1949{
1950 return mTexStorage ? mTexStorage->getBaseTexture() : NULL;
1951}
1952
1953// Constructs a Direct3D 9 texture resource from the texture images
1954void Texture2D::createTexture()
1955{
1956 GLsizei width = mImageArray[0].getWidth();
1957 GLsizei height = mImageArray[0].getHeight();
1958 GLint levels = creationLevels(width, height);
1959 D3DFORMAT d3dfmt = mImageArray[0].getD3DFormat();
1960 DWORD d3dusage = GetTextureUsage(d3dfmt, mUsage, false);
1961
1962 delete mTexStorage;
1963 mTexStorage = new TextureStorage2D(levels, d3dfmt, d3dusage, width, height);
1964
1965 if (mTexStorage->isManaged())
1966 {
1967 int levels = levelCount();
1968
1969 for (int level = 0; level < levels; level++)
1970 {
1971 IDirect3DSurface9 *surface = mTexStorage->getSurfaceLevel(level);
1972 mImageArray[level].setManagedSurface(surface);
1973 }
1974 }
1975
1976 mDirtyImages = true;
1977}
1978
1979void Texture2D::updateTexture()
1980{
1981 int levels = levelCount();
1982
1983 for (int level = 0; level < levels; level++)
1984 {
1985 Image *image = &mImageArray[level];
1986
1987 if (image->isDirty())
1988 {
1989 commitRect(level, 0, 0, mImageArray[level].getWidth(), mImageArray[level].getHeight());
1990 }
1991 }
1992}
1993
1994void Texture2D::convertToRenderTarget()
1995{
1996 TextureStorage2D *newTexStorage = NULL;
1997
1998 if (mImageArray[0].getWidth() != 0 && mImageArray[0].getHeight() != 0)
1999 {
2000 GLsizei width = mImageArray[0].getWidth();
2001 GLsizei height = mImageArray[0].getHeight();
2002 GLint levels = creationLevels(width, height);
2003 D3DFORMAT d3dfmt = mImageArray[0].getD3DFormat();
2004 DWORD d3dusage = GetTextureUsage(d3dfmt, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, true);
2005
2006 newTexStorage = new TextureStorage2D(levels, d3dfmt, d3dusage, width, height);
2007
2008 if (mTexStorage != NULL)
2009 {
2010 int levels = levelCount();
2011 for (int i = 0; i < levels; i++)
2012 {
2013 IDirect3DSurface9 *source = mTexStorage->getSurfaceLevel(i);
2014 IDirect3DSurface9 *dest = newTexStorage->getSurfaceLevel(i);
2015
2016 if (!copyToRenderTarget(dest, source, mTexStorage->isManaged()))
2017 {
2018 delete newTexStorage;
2019 if (source) source->Release();
2020 if (dest) dest->Release();
2021 return error(GL_OUT_OF_MEMORY);
2022 }
2023
2024 if (source) source->Release();
2025 if (dest) dest->Release();
2026 }
2027 }
2028 }
2029
2030 delete mTexStorage;
2031 mTexStorage = newTexStorage;
2032
2033 mDirtyImages = true;
2034}
2035
2036void Texture2D::generateMipmaps()
2037{
2038 if (!getContext()->supportsNonPower2Texture())
2039 {
2040 if (!isPow2(mImageArray[0].getWidth()) || !isPow2(mImageArray[0].getHeight()))
2041 {
2042 return error(GL_INVALID_OPERATION);
2043 }
2044 }
2045
2046 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
2047 unsigned int q = log2(std::max(mImageArray[0].getWidth(), mImageArray[0].getHeight()));
2048 for (unsigned int i = 1; i <= q; i++)
2049 {
2050 redefineImage(i, mImageArray[0].getFormat(),
2051 std::max(mImageArray[0].getWidth() >> i, 1),
2052 std::max(mImageArray[0].getHeight() >> i, 1),
2053 mImageArray[0].getType());
2054 }
2055
2056 if (mTexStorage && mTexStorage->isRenderTarget())
2057 {
2058 for (unsigned int i = 1; i <= q; i++)
2059 {
2060 IDirect3DSurface9 *upper = mTexStorage->getSurfaceLevel(i - 1);
2061 IDirect3DSurface9 *lower = mTexStorage->getSurfaceLevel(i);
2062
2063 if (upper != NULL && lower != NULL)
2064 {
2065 getBlitter()->boxFilter(upper, lower);
2066 }
2067
2068 if (upper != NULL) upper->Release();
2069 if (lower != NULL) lower->Release();
2070
2071 mImageArray[i].markClean();
2072 }
2073 }
2074 else
2075 {
2076 for (unsigned int i = 1; i <= q; i++)
2077 {
2078 if (mImageArray[i].getSurface() == NULL)
2079 {
2080 return error(GL_OUT_OF_MEMORY);
2081 }
2082
2083 if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[i].getSurface(), NULL, NULL, mImageArray[i - 1].getSurface(), NULL, NULL, D3DX_FILTER_BOX, 0)))
2084 {
2085 ERR(" failed to load filter %d to %d.", i - 1, i);
2086 }
2087
2088 mImageArray[i].markDirty();
2089 }
2090 }
2091}
2092
2093Renderbuffer *Texture2D::getRenderbuffer(GLenum target)
2094{
2095 if (target != GL_TEXTURE_2D)
2096 {
2097 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
2098 }
2099
2100 if (mColorbufferProxy == NULL)
2101 {
2102 mColorbufferProxy = new Renderbuffer(id(), new RenderbufferTexture2D(this, target));
2103 }
2104
2105 return mColorbufferProxy;
2106}
2107
2108// Increments refcount on surface.
2109// caller must Release() the returned surface
2110IDirect3DSurface9 *Texture2D::getRenderTarget(GLenum target)
2111{
2112 ASSERT(target == GL_TEXTURE_2D);
2113
2114 // ensure the underlying texture is created
2115 if (getStorage(true) == NULL)
2116 {
2117 return NULL;
2118 }
2119
2120 updateTexture();
2121
2122 // ensure this is NOT a depth texture
2123 if (isDepth(0))
2124 {
2125 return NULL;
2126 }
2127 return mTexStorage->getSurfaceLevel(0);
2128}
2129
2130// Increments refcount on surface.
2131// caller must Release() the returned surface
2132IDirect3DSurface9 *Texture2D::getDepthStencil(GLenum target)
2133{
2134 ASSERT(target == GL_TEXTURE_2D);
2135
2136 // ensure the underlying texture is created
2137 if (getStorage(true) == NULL)
2138 {
2139 return NULL;
2140 }
2141
2142 updateTexture();
2143
2144 // ensure this is actually a depth texture
2145 if (!isDepth(0))
2146 {
2147 return NULL;
2148 }
2149 return mTexStorage->getSurfaceLevel(0);
2150}
2151
2152TextureStorage *Texture2D::getStorage(bool renderTarget)
2153{
2154 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
2155 {
2156 if (renderTarget)
2157 {
2158 convertToRenderTarget();
2159 }
2160 else
2161 {
2162 createTexture();
2163 }
2164 }
2165
2166 return mTexStorage;
2167}
2168
2169TextureStorageCubeMap::TextureStorageCubeMap(int levels, D3DFORMAT format, DWORD usage, int size)
2170 : TextureStorage(usage), mFirstRenderTargetSerial(RenderbufferStorage::issueCubeSerials())
2171{
2172 mTexture = NULL;
2173 // if the size is not positive this should be treated as an incomplete texture
2174 // we handle that here by skipping the d3d texture creation
2175 if (size > 0)
2176 {
2177 IDirect3DDevice9 *device = getDevice();
2178 HRESULT result = device->CreateCubeTexture(size, levels, getUsage(), format, getPool(), &mTexture, NULL);
2179
2180 if (FAILED(result))
2181 {
2182 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2183 error(GL_OUT_OF_MEMORY);
2184 }
2185 }
2186}
2187
2188TextureStorageCubeMap::~TextureStorageCubeMap()
2189{
2190 if (mTexture)
2191 {
2192 mTexture->Release();
2193 }
2194}
2195
2196// Increments refcount on surface.
2197// caller must Release() the returned surface
2198IDirect3DSurface9 *TextureStorageCubeMap::getCubeMapSurface(GLenum faceTarget, int level)
2199{
2200 IDirect3DSurface9 *surface = NULL;
2201
2202 if (mTexture)
2203 {
2204 HRESULT result = mTexture->GetCubeMapSurface(es2dx::ConvertCubeFace(faceTarget), level, &surface);
2205 ASSERT(SUCCEEDED(result));
2206 }
2207
2208 return surface;
2209}
2210
2211IDirect3DBaseTexture9 *TextureStorageCubeMap::getBaseTexture() const
2212{
2213 return mTexture;
2214}
2215
2216unsigned int TextureStorageCubeMap::getRenderTargetSerial(GLenum target) const
2217{
2218 return mFirstRenderTargetSerial + TextureCubeMap::faceIndex(target);
2219}
2220
2221TextureCubeMap::TextureCubeMap(GLuint id) : Texture(id)
2222{
2223 mTexStorage = NULL;
2224 for (int i = 0; i < 6; i++)
2225 {
2226 mFaceProxies[i] = NULL;
2227 mFaceProxyRefs[i] = 0;
2228 }
2229}
2230
2231TextureCubeMap::~TextureCubeMap()
2232{
2233 for (int i = 0; i < 6; i++)
2234 {
2235 mFaceProxies[i] = NULL;
2236 }
2237
2238 delete mTexStorage;
2239 mTexStorage = NULL;
2240}
2241
2242// We need to maintain a count of references to renderbuffers acting as
2243// proxies for this texture, so that the texture is not deleted while
2244// proxy references still exist. If the reference count drops to zero,
2245// we set our proxy pointer NULL, so that a new attempt at referencing
2246// will cause recreation.
2247void TextureCubeMap::addProxyRef(const Renderbuffer *proxy)
2248{
2249 for (int i = 0; i < 6; i++)
2250 {
2251 if (mFaceProxies[i] == proxy)
2252 mFaceProxyRefs[i]++;
2253 }
2254}
2255
2256void TextureCubeMap::releaseProxy(const Renderbuffer *proxy)
2257{
2258 for (int i = 0; i < 6; i++)
2259 {
2260 if (mFaceProxies[i] == proxy)
2261 {
2262 if (mFaceProxyRefs[i] > 0)
2263 mFaceProxyRefs[i]--;
2264
2265 if (mFaceProxyRefs[i] == 0)
2266 mFaceProxies[i] = NULL;
2267 }
2268 }
2269}
2270
2271GLenum TextureCubeMap::getTarget() const
2272{
2273 return GL_TEXTURE_CUBE_MAP;
2274}
2275
2276GLsizei TextureCubeMap::getWidth(GLenum target, GLint level) const
2277{
2278 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
2279 return mImageArray[faceIndex(target)][level].getWidth();
2280 else
2281 return 0;
2282}
2283
2284GLsizei TextureCubeMap::getHeight(GLenum target, GLint level) const
2285{
2286 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
2287 return mImageArray[faceIndex(target)][level].getHeight();
2288 else
2289 return 0;
2290}
2291
2292GLenum TextureCubeMap::getInternalFormat(GLenum target, GLint level) const
2293{
2294 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
2295 return mImageArray[faceIndex(target)][level].getFormat();
2296 else
2297 return GL_NONE;
2298}
2299
2300D3DFORMAT TextureCubeMap::getD3DFormat(GLenum target, GLint level) const
2301{
2302 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
2303 return mImageArray[faceIndex(target)][level].getD3DFormat();
2304 else
2305 return D3DFMT_UNKNOWN;
2306}
2307
2308void TextureCubeMap::setImagePosX(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
2309{
2310 setImage(0, level, width, height, format, type, unpackAlignment, pixels);
2311}
2312
2313void TextureCubeMap::setImageNegX(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
2314{
2315 setImage(1, level, width, height, format, type, unpackAlignment, pixels);
2316}
2317
2318void TextureCubeMap::setImagePosY(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
2319{
2320 setImage(2, level, width, height, format, type, unpackAlignment, pixels);
2321}
2322
2323void TextureCubeMap::setImageNegY(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
2324{
2325 setImage(3, level, width, height, format, type, unpackAlignment, pixels);
2326}
2327
2328void TextureCubeMap::setImagePosZ(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
2329{
2330 setImage(4, level, width, height, format, type, unpackAlignment, pixels);
2331}
2332
2333void TextureCubeMap::setImageNegZ(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
2334{
2335 setImage(5, level, width, height, format, type, unpackAlignment, pixels);
2336}
2337
2338void TextureCubeMap::setCompressedImage(GLenum face, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
2339{
2340 redefineImage(faceIndex(face), level, format, width, height, GL_UNSIGNED_BYTE);
2341
2342 Texture::setCompressedImage(imageSize, pixels, &mImageArray[faceIndex(face)][level]);
2343}
2344
2345void TextureCubeMap::commitRect(int face, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
2346{
2347 ASSERT(mImageArray[face][level].getSurface() != NULL);
2348
2349 if (level < levelCount())
2350 {
2351 IDirect3DSurface9 *destLevel = mTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level);
2352 ASSERT(destLevel != NULL);
2353
2354 if (destLevel != NULL)
2355 {
2356 Image *image = &mImageArray[face][level];
2357 image->updateSurface(destLevel, xoffset, yoffset, width, height);
2358
2359 destLevel->Release();
2360 image->markClean();
2361 }
2362 }
2363}
2364
2365void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
2366{
2367 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[faceIndex(target)][level]))
2368 {
2369 commitRect(faceIndex(target), level, xoffset, yoffset, width, height);
2370 }
2371}
2372
2373void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
2374{
2375 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[faceIndex(target)][level]))
2376 {
2377 commitRect(faceIndex(target), level, xoffset, yoffset, width, height);
2378 }
2379}
2380
2381// Tests for cube map sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 86.
2382bool TextureCubeMap::isSamplerComplete() const
2383{
2384 int size = mImageArray[0][0].getWidth();
2385
2386 bool mipmapping;
2387
2388 switch (mMinFilter)
2389 {
2390 case GL_NEAREST:
2391 case GL_LINEAR:
2392 mipmapping = false;
2393 break;
2394 case GL_NEAREST_MIPMAP_NEAREST:
2395 case GL_LINEAR_MIPMAP_NEAREST:
2396 case GL_NEAREST_MIPMAP_LINEAR:
2397 case GL_LINEAR_MIPMAP_LINEAR:
2398 mipmapping = true;
2399 break;
2400 default:
2401 UNREACHABLE();
2402 return false;
2403 }
2404
2405 if ((getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0) == GL_FLOAT && !getContext()->supportsFloat32LinearFilter()) ||
2406 (getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0) == GL_HALF_FLOAT_OES && !getContext()->supportsFloat16LinearFilter()))
2407 {
2408 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
2409 {
2410 return false;
2411 }
2412 }
2413
2414 if (!isPow2(size) && !getContext()->supportsNonPower2Texture())
2415 {
2416 if (getWrapS() != GL_CLAMP_TO_EDGE || getWrapT() != GL_CLAMP_TO_EDGE || mipmapping)
2417 {
2418 return false;
2419 }
2420 }
2421
2422 if (!mipmapping)
2423 {
2424 if (!isCubeComplete())
2425 {
2426 return false;
2427 }
2428 }
2429 else
2430 {
2431 if (!isMipmapCubeComplete()) // Also tests for isCubeComplete()
2432 {
2433 return false;
2434 }
2435 }
2436
2437 return true;
2438}
2439
2440// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
2441bool TextureCubeMap::isCubeComplete() const
2442{
2443 if (mImageArray[0][0].getWidth() <= 0 || mImageArray[0][0].getHeight() != mImageArray[0][0].getWidth())
2444 {
2445 return false;
2446 }
2447
2448 for (unsigned int face = 1; face < 6; face++)
2449 {
2450 if (mImageArray[face][0].getWidth() != mImageArray[0][0].getWidth() ||
2451 mImageArray[face][0].getWidth() != mImageArray[0][0].getHeight() ||
2452 mImageArray[face][0].getFormat() != mImageArray[0][0].getFormat() ||
2453 mImageArray[face][0].getType() != mImageArray[0][0].getType())
2454 {
2455 return false;
2456 }
2457 }
2458
2459 return true;
2460}
2461
2462bool TextureCubeMap::isMipmapCubeComplete() const
2463{
2464 if (isImmutable())
2465 {
2466 return true;
2467 }
2468
2469 if (!isCubeComplete())
2470 {
2471 return false;
2472 }
2473
2474 GLsizei size = mImageArray[0][0].getWidth();
2475
2476 int q = log2(size);
2477
2478 for (int face = 0; face < 6; face++)
2479 {
2480 for (int level = 1; level <= q; level++)
2481 {
2482 if (mImageArray[face][level].getFormat() != mImageArray[0][0].getFormat())
2483 {
2484 return false;
2485 }
2486
2487 if (mImageArray[face][level].getType() != mImageArray[0][0].getType())
2488 {
2489 return false;
2490 }
2491
2492 if (mImageArray[face][level].getWidth() != std::max(1, size >> level))
2493 {
2494 return false;
2495 }
2496 }
2497 }
2498
2499 return true;
2500}
2501
2502bool TextureCubeMap::isCompressed(GLenum target, GLint level) const
2503{
2504 return IsCompressed(getInternalFormat(target, level));
2505}
2506
2507IDirect3DBaseTexture9 *TextureCubeMap::getBaseTexture() const
2508{
2509 return mTexStorage ? mTexStorage->getBaseTexture() : NULL;
2510}
2511
2512// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
2513void TextureCubeMap::createTexture()
2514{
2515 GLsizei size = mImageArray[0][0].getWidth();
2516 GLint levels = creationLevels(size, 0);
2517 D3DFORMAT d3dfmt = mImageArray[0][0].getD3DFormat();
2518 DWORD d3dusage = GetTextureUsage(d3dfmt, mUsage, false);
2519
2520 delete mTexStorage;
2521 mTexStorage = new TextureStorageCubeMap(levels, d3dfmt, d3dusage, size);
2522
2523 if (mTexStorage->isManaged())
2524 {
2525 int levels = levelCount();
2526
2527 for (int face = 0; face < 6; face++)
2528 {
2529 for (int level = 0; level < levels; level++)
2530 {
2531 IDirect3DSurface9 *surface = mTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level);
2532 mImageArray[face][level].setManagedSurface(surface);
2533 }
2534 }
2535 }
2536
2537 mDirtyImages = true;
2538}
2539
2540void TextureCubeMap::updateTexture()
2541{
2542 for (int face = 0; face < 6; face++)
2543 {
2544 int levels = levelCount();
2545 for (int level = 0; level < levels; level++)
2546 {
2547 Image *image = &mImageArray[face][level];
2548
2549 if (image->isDirty())
2550 {
2551 commitRect(face, level, 0, 0, image->getWidth(), image->getHeight());
2552 }
2553 }
2554 }
2555}
2556
2557void TextureCubeMap::convertToRenderTarget()
2558{
2559 TextureStorageCubeMap *newTexStorage = NULL;
2560
2561 if (mImageArray[0][0].getWidth() != 0)
2562 {
2563 GLsizei size = mImageArray[0][0].getWidth();
2564 GLint levels = creationLevels(size, 0);
2565 D3DFORMAT d3dfmt = mImageArray[0][0].getD3DFormat();
2566 DWORD d3dusage = GetTextureUsage(d3dfmt, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, true);
2567
2568 newTexStorage = new TextureStorageCubeMap(levels, d3dfmt, d3dusage, size);
2569
2570 if (mTexStorage != NULL)
2571 {
2572 int levels = levelCount();
2573 for (int f = 0; f < 6; f++)
2574 {
2575 for (int i = 0; i < levels; i++)
2576 {
2577 IDirect3DSurface9 *source = mTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i);
2578 IDirect3DSurface9 *dest = newTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i);
2579
2580 if (!copyToRenderTarget(dest, source, mTexStorage->isManaged()))
2581 {
2582 delete newTexStorage;
2583 if (source) source->Release();
2584 if (dest) dest->Release();
2585 return error(GL_OUT_OF_MEMORY);
2586 }
2587
2588 if (source) source->Release();
2589 if (dest) dest->Release();
2590 }
2591 }
2592 }
2593 }
2594
2595 delete mTexStorage;
2596 mTexStorage = newTexStorage;
2597
2598 mDirtyImages = true;
2599}
2600
2601void TextureCubeMap::setImage(int faceIndex, GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
2602{
2603 redefineImage(faceIndex, level, format, width, height, type);
2604
2605 Texture::setImage(unpackAlignment, pixels, &mImageArray[faceIndex][level]);
2606}
2607
2608unsigned int TextureCubeMap::faceIndex(GLenum face)
2609{
2610 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
2611 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
2612 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
2613 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
2614 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
2615
2616 return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
2617}
2618
2619void TextureCubeMap::redefineImage(int face, GLint level, GLenum format, GLsizei width, GLsizei height, GLenum type)
2620{
2621 bool redefined = mImageArray[face][level].redefine(format, width, height, type, false);
2622
2623 if (mTexStorage && redefined)
2624 {
2625 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
2626 {
2627 for (int f = 0; f < 6; f++)
2628 {
2629 mImageArray[f][i].markDirty();
2630 }
2631 }
2632
2633 delete mTexStorage;
2634 mTexStorage = NULL;
2635
2636 mDirtyImages = true;
2637 }
2638}
2639
2640void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
2641{
2642 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
2643
2644 if (!renderTarget)
2645 {
2646 ERR("Failed to retrieve the render target.");
2647 return error(GL_OUT_OF_MEMORY);
2648 }
2649
2650 unsigned int faceindex = faceIndex(target);
2651 redefineImage(faceindex, level, format, width, height, GL_UNSIGNED_BYTE);
2652
2653 if (!mImageArray[faceindex][level].isRenderableFormat())
2654 {
2655 mImageArray[faceindex][level].copy(0, 0, x, y, width, height, renderTarget);
2656 mDirtyImages = true;
2657 }
2658 else
2659 {
2660 if (!mTexStorage || !mTexStorage->isRenderTarget())
2661 {
2662 convertToRenderTarget();
2663 }
2664
2665 mImageArray[faceindex][level].markClean();
2666
2667 ASSERT(width == height);
2668
2669 if (width > 0 && level < levelCount())
2670 {
2671 RECT sourceRect;
2672 sourceRect.left = x;
2673 sourceRect.right = x + width;
2674 sourceRect.top = y;
2675 sourceRect.bottom = y + height;
2676
2677 IDirect3DSurface9 *dest = mTexStorage->getCubeMapSurface(target, level);
2678
2679 if (dest)
2680 {
2681 getBlitter()->copy(renderTarget, sourceRect, format, 0, 0, dest);
2682 dest->Release();
2683 }
2684 }
2685 }
2686
2687 renderTarget->Release();
2688}
2689
2690void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
2691{
2692 GLsizei size = mImageArray[faceIndex(target)][level].getWidth();
2693
2694 if (xoffset + width > size || yoffset + height > size)
2695 {
2696 return error(GL_INVALID_VALUE);
2697 }
2698
2699 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
2700
2701 if (!renderTarget)
2702 {
2703 ERR("Failed to retrieve the render target.");
2704 return error(GL_OUT_OF_MEMORY);
2705 }
2706
2707 unsigned int faceindex = faceIndex(target);
2708
2709 if (!mImageArray[faceindex][level].isRenderableFormat() || (!mTexStorage && !isSamplerComplete()))
2710 {
2711 mImageArray[faceindex][level].copy(0, 0, x, y, width, height, renderTarget);
2712 mDirtyImages = true;
2713 }
2714 else
2715 {
2716 if (!mTexStorage || !mTexStorage->isRenderTarget())
2717 {
2718 convertToRenderTarget();
2719 }
2720
2721 updateTexture();
2722
2723 if (level < levelCount())
2724 {
2725 RECT sourceRect;
2726 sourceRect.left = x;
2727 sourceRect.right = x + width;
2728 sourceRect.top = y;
2729 sourceRect.bottom = y + height;
2730
2731 IDirect3DSurface9 *dest = mTexStorage->getCubeMapSurface(target, level);
2732
2733 if (dest)
2734 {
2735 getBlitter()->copy(renderTarget, sourceRect, mImageArray[0][0].getFormat(), xoffset, yoffset, dest);
2736 dest->Release();
2737 }
2738 }
2739 }
2740
2741 renderTarget->Release();
2742}
2743
2744void TextureCubeMap::storage(GLsizei levels, GLenum internalformat, GLsizei size)
2745{
2746 GLenum format = gl::ExtractFormat(internalformat);
2747 GLenum type = gl::ExtractType(internalformat);
2748 D3DFORMAT d3dfmt = ConvertTextureFormatType(format, type);
2749 DWORD d3dusage = GetTextureUsage(d3dfmt, mUsage, false);
2750
2751 delete mTexStorage;
2752 mTexStorage = new TextureStorageCubeMap(levels, d3dfmt, d3dusage, size);
2753 mImmutable = true;
2754
2755 for (int level = 0; level < levels; level++)
2756 {
2757 for (int face = 0; face < 6; face++)
2758 {
2759 mImageArray[face][level].redefine(format, size, size, type, true);
2760 size = std::max(1, size >> 1);
2761 }
2762 }
2763
2764 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2765 {
2766 for (int face = 0; face < 6; face++)
2767 {
2768 mImageArray[face][level].redefine(GL_NONE, 0, 0, GL_UNSIGNED_BYTE, true);
2769 }
2770 }
2771
2772 if (mTexStorage->isManaged())
2773 {
2774 int levels = levelCount();
2775
2776 for (int face = 0; face < 6; face++)
2777 {
2778 for (int level = 0; level < levels; level++)
2779 {
2780 IDirect3DSurface9 *surface = mTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level);
2781 mImageArray[face][level].setManagedSurface(surface);
2782 }
2783 }
2784 }
2785}
2786
2787void TextureCubeMap::generateMipmaps()
2788{
2789 if (!isCubeComplete())
2790 {
2791 return error(GL_INVALID_OPERATION);
2792 }
2793
2794 if (!getContext()->supportsNonPower2Texture())
2795 {
2796 if (!isPow2(mImageArray[0][0].getWidth()))
2797 {
2798 return error(GL_INVALID_OPERATION);
2799 }
2800 }
2801
2802 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
2803 unsigned int q = log2(mImageArray[0][0].getWidth());
2804 for (unsigned int f = 0; f < 6; f++)
2805 {
2806 for (unsigned int i = 1; i <= q; i++)
2807 {
2808 redefineImage(f, i, mImageArray[f][0].getFormat(),
2809 std::max(mImageArray[f][0].getWidth() >> i, 1),
2810 std::max(mImageArray[f][0].getWidth() >> i, 1),
2811 mImageArray[f][0].getType());
2812 }
2813 }
2814
2815 if (mTexStorage && mTexStorage->isRenderTarget())
2816 {
2817 for (unsigned int f = 0; f < 6; f++)
2818 {
2819 for (unsigned int i = 1; i <= q; i++)
2820 {
2821 IDirect3DSurface9 *upper = mTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i-1);
2822 IDirect3DSurface9 *lower = mTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i);
2823
2824 if (upper != NULL && lower != NULL)
2825 {
2826 getBlitter()->boxFilter(upper, lower);
2827 }
2828
2829 if (upper != NULL) upper->Release();
2830 if (lower != NULL) lower->Release();
2831
2832 mImageArray[f][i].markClean();
2833 }
2834 }
2835 }
2836 else
2837 {
2838 for (unsigned int f = 0; f < 6; f++)
2839 {
2840 for (unsigned int i = 1; i <= q; i++)
2841 {
2842 if (mImageArray[f][i].getSurface() == NULL)
2843 {
2844 return error(GL_OUT_OF_MEMORY);
2845 }
2846
2847 if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[f][i].getSurface(), NULL, NULL, mImageArray[f][i - 1].getSurface(), NULL, NULL, D3DX_FILTER_BOX, 0)))
2848 {
2849 ERR(" failed to load filter %d to %d.", i - 1, i);
2850 }
2851
2852 mImageArray[f][i].markDirty();
2853 }
2854 }
2855 }
2856}
2857
2858Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target)
2859{
2860 if (!IsCubemapTextureTarget(target))
2861 {
2862 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
2863 }
2864
2865 unsigned int face = faceIndex(target);
2866
2867 if (mFaceProxies[face] == NULL)
2868 {
2869 mFaceProxies[face] = new Renderbuffer(id(), new RenderbufferTextureCubeMap(this, target));
2870 }
2871
2872 return mFaceProxies[face];
2873}
2874
2875// Increments refcount on surface.
2876// caller must Release() the returned surface
2877IDirect3DSurface9 *TextureCubeMap::getRenderTarget(GLenum target)
2878{
2879 ASSERT(IsCubemapTextureTarget(target));
2880
2881 // ensure the underlying texture is created
2882 if (getStorage(true) == NULL)
2883 {
2884 return NULL;
2885 }
2886
2887 updateTexture();
2888
2889 return mTexStorage->getCubeMapSurface(target, 0);
2890}
2891
2892TextureStorage *TextureCubeMap::getStorage(bool renderTarget)
2893{
2894 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
2895 {
2896 if (renderTarget)
2897 {
2898 convertToRenderTarget();
2899 }
2900 else
2901 {
2902 createTexture();
2903 }
2904 }
2905
2906 return mTexStorage;
2907}
2908
2909}