blob: cd4d63711b1467c30df0997f0288bf1eb7e1ff9a [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;
daniel@transgaming.com07ab8412012-07-12 15:17:09 +00001160 mMaxAnisotropy = 1.0f;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001161
1162 mDirtyImages = true;
1163
1164 mImmutable = false;
1165}
1166
1167Texture::~Texture()
1168{
1169}
1170
1171// Returns true on successful filter state update (valid enum parameter)
1172bool Texture::setMinFilter(GLenum filter)
1173{
1174 switch (filter)
1175 {
1176 case GL_NEAREST:
1177 case GL_LINEAR:
1178 case GL_NEAREST_MIPMAP_NEAREST:
1179 case GL_LINEAR_MIPMAP_NEAREST:
1180 case GL_NEAREST_MIPMAP_LINEAR:
1181 case GL_LINEAR_MIPMAP_LINEAR:
1182 {
1183 if (mMinFilter != filter)
1184 {
1185 mMinFilter = filter;
1186 mDirtyParameters = true;
1187 }
1188 return true;
1189 }
1190 default:
1191 return false;
1192 }
1193}
1194
1195// Returns true on successful filter state update (valid enum parameter)
1196bool Texture::setMagFilter(GLenum filter)
1197{
1198 switch (filter)
1199 {
1200 case GL_NEAREST:
1201 case GL_LINEAR:
1202 {
1203 if (mMagFilter != filter)
1204 {
1205 mMagFilter = filter;
1206 mDirtyParameters = true;
1207 }
1208 return true;
1209 }
1210 default:
1211 return false;
1212 }
1213}
1214
1215// Returns true on successful wrap state update (valid enum parameter)
1216bool Texture::setWrapS(GLenum wrap)
1217{
1218 switch (wrap)
1219 {
1220 case GL_REPEAT:
1221 case GL_CLAMP_TO_EDGE:
1222 case GL_MIRRORED_REPEAT:
1223 {
1224 if (mWrapS != wrap)
1225 {
1226 mWrapS = wrap;
1227 mDirtyParameters = true;
1228 }
1229 return true;
1230 }
1231 default:
1232 return false;
1233 }
1234}
1235
1236// Returns true on successful wrap state update (valid enum parameter)
1237bool Texture::setWrapT(GLenum wrap)
1238{
1239 switch (wrap)
1240 {
1241 case GL_REPEAT:
1242 case GL_CLAMP_TO_EDGE:
1243 case GL_MIRRORED_REPEAT:
1244 {
1245 if (mWrapT != wrap)
1246 {
1247 mWrapT = wrap;
1248 mDirtyParameters = true;
1249 }
1250 return true;
1251 }
1252 default:
1253 return false;
1254 }
1255}
1256
daniel@transgaming.com07ab8412012-07-12 15:17:09 +00001257// Returns true on successful max anisotropy update (valid anisotropy value)
1258bool Texture::setMaxAnisotropy(float textureMaxAnisotropy, float contextMaxAnisotropy)
1259{
1260 textureMaxAnisotropy = std::min(textureMaxAnisotropy, contextMaxAnisotropy);
1261 if (textureMaxAnisotropy < 1.0f)
1262 {
1263 return false;
1264 }
1265 if (mMaxAnisotropy != textureMaxAnisotropy)
1266 {
1267 mMaxAnisotropy = textureMaxAnisotropy;
1268 mDirtyParameters = true;
1269 }
1270 return true;
1271}
1272
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001273// Returns true on successful usage state update (valid enum parameter)
1274bool Texture::setUsage(GLenum usage)
1275{
1276 switch (usage)
1277 {
1278 case GL_NONE:
1279 case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
1280 mUsage = usage;
1281 return true;
1282 default:
1283 return false;
1284 }
1285}
1286
1287GLenum Texture::getMinFilter() const
1288{
1289 return mMinFilter;
1290}
1291
1292GLenum Texture::getMagFilter() const
1293{
1294 return mMagFilter;
1295}
1296
1297GLenum Texture::getWrapS() const
1298{
1299 return mWrapS;
1300}
1301
1302GLenum Texture::getWrapT() const
1303{
1304 return mWrapT;
1305}
1306
daniel@transgaming.com07ab8412012-07-12 15:17:09 +00001307float Texture::getMaxAnisotropy() const
1308{
1309 return mMaxAnisotropy;
1310}
1311
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001312GLenum Texture::getUsage() const
1313{
1314 return mUsage;
1315}
1316
1317void Texture::setImage(GLint unpackAlignment, const void *pixels, Image *image)
1318{
1319 if (pixels != NULL)
1320 {
1321 image->loadData(0, 0, image->getWidth(), image->getHeight(), image->getType(), unpackAlignment, pixels);
1322 mDirtyImages = true;
1323 }
1324}
1325
1326void Texture::setCompressedImage(GLsizei imageSize, const void *pixels, Image *image)
1327{
1328 if (pixels != NULL)
1329 {
1330 image->loadCompressedData(0, 0, image->getWidth(), image->getHeight(), pixels);
1331 mDirtyImages = true;
1332 }
1333}
1334
1335bool Texture::subImage(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, Image *image)
1336{
1337 if (pixels != NULL)
1338 {
1339 image->loadData(xoffset, yoffset, width, height, type, unpackAlignment, pixels);
1340 mDirtyImages = true;
1341 }
1342
1343 return true;
1344}
1345
1346bool Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, Image *image)
1347{
1348 if (pixels != NULL)
1349 {
1350 image->loadCompressedData(xoffset, yoffset, width, height, pixels);
1351 mDirtyImages = true;
1352 }
1353
1354 return true;
1355}
1356
1357IDirect3DBaseTexture9 *Texture::getTexture()
1358{
1359 if (!isSamplerComplete())
1360 {
1361 return NULL;
1362 }
1363
1364 // ensure the underlying texture is created
1365 if (getStorage(false) == NULL)
1366 {
1367 return NULL;
1368 }
1369
1370 updateTexture();
1371
1372 return getBaseTexture();
1373}
1374
1375bool Texture::hasDirtyParameters() const
1376{
1377 return mDirtyParameters;
1378}
1379
1380bool Texture::hasDirtyImages() const
1381{
1382 return mDirtyImages;
1383}
1384
1385void Texture::resetDirty()
1386{
1387 mDirtyParameters = false;
1388 mDirtyImages = false;
1389}
1390
1391unsigned int Texture::getTextureSerial()
1392{
1393 TextureStorage *texture = getStorage(false);
1394 return texture ? texture->getTextureSerial() : 0;
1395}
1396
1397unsigned int Texture::getRenderTargetSerial(GLenum target)
1398{
1399 TextureStorage *texture = getStorage(true);
1400 return texture ? texture->getRenderTargetSerial(target) : 0;
1401}
1402
1403bool Texture::isImmutable() const
1404{
1405 return mImmutable;
1406}
1407
1408GLint Texture::creationLevels(GLsizei width, GLsizei height) const
1409{
1410 if ((isPow2(width) && isPow2(height)) || getContext()->supportsNonPower2Texture())
1411 {
1412 return 0; // Maximum number of levels
1413 }
1414 else
1415 {
1416 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
1417 return 1;
1418 }
1419}
1420
1421GLint Texture::creationLevels(GLsizei size) const
1422{
1423 return creationLevels(size, size);
1424}
1425
1426int Texture::levelCount() const
1427{
1428 return getBaseTexture() ? getBaseTexture()->GetLevelCount() : 0;
1429}
1430
1431Blit *Texture::getBlitter()
1432{
1433 Context *context = getContext();
1434 return context->getBlitter();
1435}
1436
1437bool Texture::copyToRenderTarget(IDirect3DSurface9 *dest, IDirect3DSurface9 *source, bool fromManaged)
1438{
1439 if (source && dest)
1440 {
1441 HRESULT result;
1442
1443 if (fromManaged)
1444 {
1445 result = D3DXLoadSurfaceFromSurface(dest, NULL, NULL, source, NULL, NULL, D3DX_FILTER_BOX, 0);
1446 }
1447 else
1448 {
1449 egl::Display *display = getDisplay();
1450 IDirect3DDevice9 *device = display->getDevice();
1451
1452 display->endScene();
1453 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
1454 }
1455
1456 if (FAILED(result))
1457 {
1458 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1459 return false;
1460 }
1461 }
1462
1463 return true;
1464}
1465
1466TextureStorage2D::TextureStorage2D(IDirect3DTexture9 *surfaceTexture) : TextureStorage(D3DUSAGE_RENDERTARGET), mRenderTargetSerial(RenderbufferStorage::issueSerial())
1467{
1468 mTexture = surfaceTexture;
1469}
1470
1471TextureStorage2D::TextureStorage2D(int levels, D3DFORMAT format, DWORD usage, int width, int height)
1472 : TextureStorage(usage), mRenderTargetSerial(RenderbufferStorage::issueSerial())
1473{
1474 mTexture = NULL;
1475 // if the width or height is not positive this should be treated as an incomplete texture
1476 // we handle that here by skipping the d3d texture creation
1477 if (width > 0 && height > 0)
1478 {
1479 IDirect3DDevice9 *device = getDevice();
1480 HRESULT result = device->CreateTexture(width, height, levels, getUsage(), format, getPool(), &mTexture, NULL);
1481
1482 if (FAILED(result))
1483 {
1484 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1485 error(GL_OUT_OF_MEMORY);
1486 }
1487 }
1488}
1489
1490TextureStorage2D::~TextureStorage2D()
1491{
1492 if (mTexture)
1493 {
1494 mTexture->Release();
1495 }
1496}
1497
1498// Increments refcount on surface.
1499// caller must Release() the returned surface
1500IDirect3DSurface9 *TextureStorage2D::getSurfaceLevel(int level)
1501{
1502 IDirect3DSurface9 *surface = NULL;
1503
1504 if (mTexture)
1505 {
1506 HRESULT result = mTexture->GetSurfaceLevel(level, &surface);
1507 ASSERT(SUCCEEDED(result));
1508 }
1509
1510 return surface;
1511}
1512
1513IDirect3DBaseTexture9 *TextureStorage2D::getBaseTexture() const
1514{
1515 return mTexture;
1516}
1517
1518unsigned int TextureStorage2D::getRenderTargetSerial(GLenum target) const
1519{
1520 return mRenderTargetSerial;
1521}
1522
1523Texture2D::Texture2D(GLuint id) : Texture(id)
1524{
1525 mTexStorage = NULL;
1526 mSurface = NULL;
1527 mColorbufferProxy = NULL;
1528 mProxyRefs = 0;
1529}
1530
1531Texture2D::~Texture2D()
1532{
1533 mColorbufferProxy = NULL;
1534
1535 delete mTexStorage;
1536 mTexStorage = NULL;
1537
1538 if (mSurface)
1539 {
1540 mSurface->setBoundTexture(NULL);
1541 mSurface = NULL;
1542 }
1543}
1544
1545// We need to maintain a count of references to renderbuffers acting as
1546// proxies for this texture, so that we do not attempt to use a pointer
1547// to a renderbuffer proxy which has been deleted.
1548void Texture2D::addProxyRef(const Renderbuffer *proxy)
1549{
1550 mProxyRefs++;
1551}
1552
1553void Texture2D::releaseProxy(const Renderbuffer *proxy)
1554{
1555 if (mProxyRefs > 0)
1556 mProxyRefs--;
1557
1558 if (mProxyRefs == 0)
1559 mColorbufferProxy = NULL;
1560}
1561
1562GLenum Texture2D::getTarget() const
1563{
1564 return GL_TEXTURE_2D;
1565}
1566
1567GLsizei Texture2D::getWidth(GLint level) const
1568{
1569 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1570 return mImageArray[level].getWidth();
1571 else
1572 return 0;
1573}
1574
1575GLsizei Texture2D::getHeight(GLint level) const
1576{
1577 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1578 return mImageArray[level].getHeight();
1579 else
1580 return 0;
1581}
1582
1583GLenum Texture2D::getInternalFormat(GLint level) const
1584{
1585 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1586 return mImageArray[level].getFormat();
1587 else
1588 return GL_NONE;
1589}
1590
1591D3DFORMAT Texture2D::getD3DFormat(GLint level) const
1592{
1593 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1594 return mImageArray[level].getD3DFormat();
1595 else
1596 return D3DFMT_UNKNOWN;
1597}
1598
1599void Texture2D::redefineImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLenum type)
1600{
1601 releaseTexImage();
1602
1603 bool redefined = mImageArray[level].redefine(format, width, height, type, false);
1604
1605 if (mTexStorage && redefined)
1606 {
1607 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1608 {
1609 mImageArray[i].markDirty();
1610 }
1611
1612 delete mTexStorage;
1613 mTexStorage = NULL;
1614 mDirtyImages = true;
1615 }
1616}
1617
1618void Texture2D::setImage(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1619{
1620 redefineImage(level, format, width, height, type);
1621
1622 Texture::setImage(unpackAlignment, pixels, &mImageArray[level]);
1623}
1624
1625void Texture2D::bindTexImage(egl::Surface *surface)
1626{
1627 releaseTexImage();
1628
1629 GLenum format;
1630
1631 switch(surface->getFormat())
1632 {
1633 case D3DFMT_A8R8G8B8:
1634 format = GL_RGBA;
1635 break;
1636 case D3DFMT_X8R8G8B8:
1637 format = GL_RGB;
1638 break;
1639 default:
1640 UNIMPLEMENTED();
1641 return;
1642 }
1643
1644 mImageArray[0].redefine(format, surface->getWidth(), surface->getHeight(), GL_UNSIGNED_BYTE, true);
1645
1646 delete mTexStorage;
1647 mTexStorage = new TextureStorage2D(surface->getOffscreenTexture());
1648
1649 mDirtyImages = true;
1650 mSurface = surface;
1651 mSurface->setBoundTexture(this);
1652}
1653
1654void Texture2D::releaseTexImage()
1655{
1656 if (mSurface)
1657 {
1658 mSurface->setBoundTexture(NULL);
1659 mSurface = NULL;
1660
1661 if (mTexStorage)
1662 {
1663 delete mTexStorage;
1664 mTexStorage = NULL;
1665 }
1666
1667 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1668 {
1669 mImageArray[i].redefine(GL_RGBA, 0, 0, GL_UNSIGNED_BYTE, true);
1670 }
1671 }
1672}
1673
1674void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
1675{
1676 redefineImage(level, format, width, height, GL_UNSIGNED_BYTE);
1677
1678 Texture::setCompressedImage(imageSize, pixels, &mImageArray[level]);
1679}
1680
1681void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1682{
1683 ASSERT(mImageArray[level].getSurface() != NULL);
1684
1685 if (level < levelCount())
1686 {
1687 IDirect3DSurface9 *destLevel = mTexStorage->getSurfaceLevel(level);
1688
1689 if (destLevel)
1690 {
1691 Image *image = &mImageArray[level];
1692 image->updateSurface(destLevel, xoffset, yoffset, width, height);
1693
1694 destLevel->Release();
1695 image->markClean();
1696 }
1697 }
1698}
1699
1700void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1701{
1702 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[level]))
1703 {
1704 commitRect(level, xoffset, yoffset, width, height);
1705 }
1706}
1707
1708void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1709{
1710 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[level]))
1711 {
1712 commitRect(level, xoffset, yoffset, width, height);
1713 }
1714}
1715
1716void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1717{
1718 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
1719
1720 if (!renderTarget)
1721 {
1722 ERR("Failed to retrieve the render target.");
1723 return error(GL_OUT_OF_MEMORY);
1724 }
1725
1726 redefineImage(level, format, width, height, GL_UNSIGNED_BYTE);
1727
1728 if (!mImageArray[level].isRenderableFormat())
1729 {
1730 mImageArray[level].copy(0, 0, x, y, width, height, renderTarget);
1731 mDirtyImages = true;
1732 }
1733 else
1734 {
1735 if (!mTexStorage || !mTexStorage->isRenderTarget())
1736 {
1737 convertToRenderTarget();
1738 }
1739
1740 mImageArray[level].markClean();
1741
1742 if (width != 0 && height != 0 && level < levelCount())
1743 {
1744 RECT sourceRect;
1745 sourceRect.left = x;
1746 sourceRect.right = x + width;
1747 sourceRect.top = y;
1748 sourceRect.bottom = y + height;
1749
1750 IDirect3DSurface9 *dest = mTexStorage->getSurfaceLevel(level);
1751
1752 if (dest)
1753 {
1754 getBlitter()->copy(renderTarget, sourceRect, format, 0, 0, dest);
1755 dest->Release();
1756 }
1757 }
1758 }
1759
1760 renderTarget->Release();
1761}
1762
1763void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1764{
1765 if (xoffset + width > mImageArray[level].getWidth() || yoffset + height > mImageArray[level].getHeight())
1766 {
1767 return error(GL_INVALID_VALUE);
1768 }
1769
1770 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
1771
1772 if (!renderTarget)
1773 {
1774 ERR("Failed to retrieve the render target.");
1775 return error(GL_OUT_OF_MEMORY);
1776 }
1777
1778 if (!mImageArray[level].isRenderableFormat() || (!mTexStorage && !isSamplerComplete()))
1779 {
1780 mImageArray[level].copy(xoffset, yoffset, x, y, width, height, renderTarget);
1781 mDirtyImages = true;
1782 }
1783 else
1784 {
1785 if (!mTexStorage || !mTexStorage->isRenderTarget())
1786 {
1787 convertToRenderTarget();
1788 }
1789
1790 updateTexture();
1791
1792 if (level < levelCount())
1793 {
1794 RECT sourceRect;
1795 sourceRect.left = x;
1796 sourceRect.right = x + width;
1797 sourceRect.top = y;
1798 sourceRect.bottom = y + height;
1799
1800
1801 IDirect3DSurface9 *dest = mTexStorage->getSurfaceLevel(level);
1802
1803 if (dest)
1804 {
1805 getBlitter()->copy(renderTarget, sourceRect, mImageArray[0].getFormat(), xoffset, yoffset, dest);
1806 dest->Release();
1807 }
1808 }
1809 }
1810
1811 renderTarget->Release();
1812}
1813
1814void Texture2D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height)
1815{
1816 GLenum format = gl::ExtractFormat(internalformat);
1817 GLenum type = gl::ExtractType(internalformat);
1818 D3DFORMAT d3dfmt = ConvertTextureFormatType(format, type);
1819 DWORD d3dusage = GetTextureUsage(d3dfmt, mUsage, false);
1820
1821 delete mTexStorage;
1822 mTexStorage = new TextureStorage2D(levels, d3dfmt, d3dusage, width, height);
1823 mImmutable = true;
1824
1825 for (int level = 0; level < levels; level++)
1826 {
1827 mImageArray[level].redefine(format, width, height, type, true);
1828 width = std::max(1, width >> 1);
1829 height = std::max(1, height >> 1);
1830 }
1831
1832 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1833 {
1834 mImageArray[level].redefine(GL_NONE, 0, 0, GL_UNSIGNED_BYTE, true);
1835 }
1836
1837 if (mTexStorage->isManaged())
1838 {
1839 int levels = levelCount();
1840
1841 for (int level = 0; level < levels; level++)
1842 {
1843 IDirect3DSurface9 *surface = mTexStorage->getSurfaceLevel(level);
1844 mImageArray[level].setManagedSurface(surface);
1845 }
1846 }
1847}
1848
1849// Tests for 2D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85.
1850bool Texture2D::isSamplerComplete() const
1851{
1852 GLsizei width = mImageArray[0].getWidth();
1853 GLsizei height = mImageArray[0].getHeight();
1854
1855 if (width <= 0 || height <= 0)
1856 {
1857 return false;
1858 }
1859
1860 bool mipmapping = false;
1861
1862 switch (mMinFilter)
1863 {
1864 case GL_NEAREST:
1865 case GL_LINEAR:
1866 mipmapping = false;
1867 break;
1868 case GL_NEAREST_MIPMAP_NEAREST:
1869 case GL_LINEAR_MIPMAP_NEAREST:
1870 case GL_NEAREST_MIPMAP_LINEAR:
1871 case GL_LINEAR_MIPMAP_LINEAR:
1872 mipmapping = true;
1873 break;
1874 default: UNREACHABLE();
1875 }
1876
1877 if ((getInternalFormat(0) == GL_FLOAT && !getContext()->supportsFloat32LinearFilter()) ||
1878 (getInternalFormat(0) == GL_HALF_FLOAT_OES && !getContext()->supportsFloat16LinearFilter()))
1879 {
1880 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
1881 {
1882 return false;
1883 }
1884 }
1885
1886 bool npotSupport = getContext()->supportsNonPower2Texture();
1887
1888 if (!npotSupport)
1889 {
1890 if ((getWrapS() != GL_CLAMP_TO_EDGE && !isPow2(width)) ||
1891 (getWrapT() != GL_CLAMP_TO_EDGE && !isPow2(height)))
1892 {
1893 return false;
1894 }
1895 }
1896
1897 if (mipmapping)
1898 {
1899 if (!npotSupport)
1900 {
1901 if (!isPow2(width) || !isPow2(height))
1902 {
1903 return false;
1904 }
1905 }
1906
1907 if (!isMipmapComplete())
1908 {
1909 return false;
1910 }
1911 }
1912
1913 return true;
1914}
1915
1916// Tests for 2D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1917bool Texture2D::isMipmapComplete() const
1918{
1919 if (isImmutable())
1920 {
1921 return true;
1922 }
1923
1924 GLsizei width = mImageArray[0].getWidth();
1925 GLsizei height = mImageArray[0].getHeight();
1926
1927 if (width <= 0 || height <= 0)
1928 {
1929 return false;
1930 }
1931
1932 int q = log2(std::max(width, height));
1933
1934 for (int level = 1; level <= q; level++)
1935 {
1936 if (mImageArray[level].getFormat() != mImageArray[0].getFormat())
1937 {
1938 return false;
1939 }
1940
1941 if (mImageArray[level].getType() != mImageArray[0].getType())
1942 {
1943 return false;
1944 }
1945
1946 if (mImageArray[level].getWidth() != std::max(1, width >> level))
1947 {
1948 return false;
1949 }
1950
1951 if (mImageArray[level].getHeight() != std::max(1, height >> level))
1952 {
1953 return false;
1954 }
1955 }
1956
1957 return true;
1958}
1959
1960bool Texture2D::isCompressed(GLint level) const
1961{
1962 return IsCompressed(getInternalFormat(level));
1963}
1964
1965bool Texture2D::isDepth(GLint level) const
1966{
1967 return IsDepthTexture(getInternalFormat(level));
1968}
1969
1970IDirect3DBaseTexture9 *Texture2D::getBaseTexture() const
1971{
1972 return mTexStorage ? mTexStorage->getBaseTexture() : NULL;
1973}
1974
1975// Constructs a Direct3D 9 texture resource from the texture images
1976void Texture2D::createTexture()
1977{
1978 GLsizei width = mImageArray[0].getWidth();
1979 GLsizei height = mImageArray[0].getHeight();
1980 GLint levels = creationLevels(width, height);
1981 D3DFORMAT d3dfmt = mImageArray[0].getD3DFormat();
1982 DWORD d3dusage = GetTextureUsage(d3dfmt, mUsage, false);
1983
1984 delete mTexStorage;
1985 mTexStorage = new TextureStorage2D(levels, d3dfmt, d3dusage, width, height);
1986
1987 if (mTexStorage->isManaged())
1988 {
1989 int levels = levelCount();
1990
1991 for (int level = 0; level < levels; level++)
1992 {
1993 IDirect3DSurface9 *surface = mTexStorage->getSurfaceLevel(level);
1994 mImageArray[level].setManagedSurface(surface);
1995 }
1996 }
1997
1998 mDirtyImages = true;
1999}
2000
2001void Texture2D::updateTexture()
2002{
2003 int levels = levelCount();
2004
2005 for (int level = 0; level < levels; level++)
2006 {
2007 Image *image = &mImageArray[level];
2008
2009 if (image->isDirty())
2010 {
2011 commitRect(level, 0, 0, mImageArray[level].getWidth(), mImageArray[level].getHeight());
2012 }
2013 }
2014}
2015
2016void Texture2D::convertToRenderTarget()
2017{
2018 TextureStorage2D *newTexStorage = NULL;
2019
2020 if (mImageArray[0].getWidth() != 0 && mImageArray[0].getHeight() != 0)
2021 {
2022 GLsizei width = mImageArray[0].getWidth();
2023 GLsizei height = mImageArray[0].getHeight();
2024 GLint levels = creationLevels(width, height);
2025 D3DFORMAT d3dfmt = mImageArray[0].getD3DFormat();
2026 DWORD d3dusage = GetTextureUsage(d3dfmt, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, true);
2027
2028 newTexStorage = new TextureStorage2D(levels, d3dfmt, d3dusage, width, height);
2029
2030 if (mTexStorage != NULL)
2031 {
2032 int levels = levelCount();
2033 for (int i = 0; i < levels; i++)
2034 {
2035 IDirect3DSurface9 *source = mTexStorage->getSurfaceLevel(i);
2036 IDirect3DSurface9 *dest = newTexStorage->getSurfaceLevel(i);
2037
2038 if (!copyToRenderTarget(dest, source, mTexStorage->isManaged()))
2039 {
2040 delete newTexStorage;
2041 if (source) source->Release();
2042 if (dest) dest->Release();
2043 return error(GL_OUT_OF_MEMORY);
2044 }
2045
2046 if (source) source->Release();
2047 if (dest) dest->Release();
2048 }
2049 }
2050 }
2051
2052 delete mTexStorage;
2053 mTexStorage = newTexStorage;
2054
2055 mDirtyImages = true;
2056}
2057
2058void Texture2D::generateMipmaps()
2059{
2060 if (!getContext()->supportsNonPower2Texture())
2061 {
2062 if (!isPow2(mImageArray[0].getWidth()) || !isPow2(mImageArray[0].getHeight()))
2063 {
2064 return error(GL_INVALID_OPERATION);
2065 }
2066 }
2067
2068 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
2069 unsigned int q = log2(std::max(mImageArray[0].getWidth(), mImageArray[0].getHeight()));
2070 for (unsigned int i = 1; i <= q; i++)
2071 {
2072 redefineImage(i, mImageArray[0].getFormat(),
2073 std::max(mImageArray[0].getWidth() >> i, 1),
2074 std::max(mImageArray[0].getHeight() >> i, 1),
2075 mImageArray[0].getType());
2076 }
2077
2078 if (mTexStorage && mTexStorage->isRenderTarget())
2079 {
2080 for (unsigned int i = 1; i <= q; i++)
2081 {
2082 IDirect3DSurface9 *upper = mTexStorage->getSurfaceLevel(i - 1);
2083 IDirect3DSurface9 *lower = mTexStorage->getSurfaceLevel(i);
2084
2085 if (upper != NULL && lower != NULL)
2086 {
2087 getBlitter()->boxFilter(upper, lower);
2088 }
2089
2090 if (upper != NULL) upper->Release();
2091 if (lower != NULL) lower->Release();
2092
2093 mImageArray[i].markClean();
2094 }
2095 }
2096 else
2097 {
2098 for (unsigned int i = 1; i <= q; i++)
2099 {
2100 if (mImageArray[i].getSurface() == NULL)
2101 {
2102 return error(GL_OUT_OF_MEMORY);
2103 }
2104
2105 if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[i].getSurface(), NULL, NULL, mImageArray[i - 1].getSurface(), NULL, NULL, D3DX_FILTER_BOX, 0)))
2106 {
2107 ERR(" failed to load filter %d to %d.", i - 1, i);
2108 }
2109
2110 mImageArray[i].markDirty();
2111 }
2112 }
2113}
2114
2115Renderbuffer *Texture2D::getRenderbuffer(GLenum target)
2116{
2117 if (target != GL_TEXTURE_2D)
2118 {
2119 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
2120 }
2121
2122 if (mColorbufferProxy == NULL)
2123 {
2124 mColorbufferProxy = new Renderbuffer(id(), new RenderbufferTexture2D(this, target));
2125 }
2126
2127 return mColorbufferProxy;
2128}
2129
2130// Increments refcount on surface.
2131// caller must Release() the returned surface
2132IDirect3DSurface9 *Texture2D::getRenderTarget(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 NOT a depth texture
2145 if (isDepth(0))
2146 {
2147 return NULL;
2148 }
2149 return mTexStorage->getSurfaceLevel(0);
2150}
2151
2152// Increments refcount on surface.
2153// caller must Release() the returned surface
2154IDirect3DSurface9 *Texture2D::getDepthStencil(GLenum target)
2155{
2156 ASSERT(target == GL_TEXTURE_2D);
2157
2158 // ensure the underlying texture is created
2159 if (getStorage(true) == NULL)
2160 {
2161 return NULL;
2162 }
2163
2164 updateTexture();
2165
2166 // ensure this is actually a depth texture
2167 if (!isDepth(0))
2168 {
2169 return NULL;
2170 }
2171 return mTexStorage->getSurfaceLevel(0);
2172}
2173
2174TextureStorage *Texture2D::getStorage(bool renderTarget)
2175{
2176 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
2177 {
2178 if (renderTarget)
2179 {
2180 convertToRenderTarget();
2181 }
2182 else
2183 {
2184 createTexture();
2185 }
2186 }
2187
2188 return mTexStorage;
2189}
2190
2191TextureStorageCubeMap::TextureStorageCubeMap(int levels, D3DFORMAT format, DWORD usage, int size)
2192 : TextureStorage(usage), mFirstRenderTargetSerial(RenderbufferStorage::issueCubeSerials())
2193{
2194 mTexture = NULL;
2195 // if the size is not positive this should be treated as an incomplete texture
2196 // we handle that here by skipping the d3d texture creation
2197 if (size > 0)
2198 {
2199 IDirect3DDevice9 *device = getDevice();
2200 HRESULT result = device->CreateCubeTexture(size, levels, getUsage(), format, getPool(), &mTexture, NULL);
2201
2202 if (FAILED(result))
2203 {
2204 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2205 error(GL_OUT_OF_MEMORY);
2206 }
2207 }
2208}
2209
2210TextureStorageCubeMap::~TextureStorageCubeMap()
2211{
2212 if (mTexture)
2213 {
2214 mTexture->Release();
2215 }
2216}
2217
2218// Increments refcount on surface.
2219// caller must Release() the returned surface
2220IDirect3DSurface9 *TextureStorageCubeMap::getCubeMapSurface(GLenum faceTarget, int level)
2221{
2222 IDirect3DSurface9 *surface = NULL;
2223
2224 if (mTexture)
2225 {
2226 HRESULT result = mTexture->GetCubeMapSurface(es2dx::ConvertCubeFace(faceTarget), level, &surface);
2227 ASSERT(SUCCEEDED(result));
2228 }
2229
2230 return surface;
2231}
2232
2233IDirect3DBaseTexture9 *TextureStorageCubeMap::getBaseTexture() const
2234{
2235 return mTexture;
2236}
2237
2238unsigned int TextureStorageCubeMap::getRenderTargetSerial(GLenum target) const
2239{
2240 return mFirstRenderTargetSerial + TextureCubeMap::faceIndex(target);
2241}
2242
2243TextureCubeMap::TextureCubeMap(GLuint id) : Texture(id)
2244{
2245 mTexStorage = NULL;
2246 for (int i = 0; i < 6; i++)
2247 {
2248 mFaceProxies[i] = NULL;
2249 mFaceProxyRefs[i] = 0;
2250 }
2251}
2252
2253TextureCubeMap::~TextureCubeMap()
2254{
2255 for (int i = 0; i < 6; i++)
2256 {
2257 mFaceProxies[i] = NULL;
2258 }
2259
2260 delete mTexStorage;
2261 mTexStorage = NULL;
2262}
2263
2264// We need to maintain a count of references to renderbuffers acting as
2265// proxies for this texture, so that the texture is not deleted while
2266// proxy references still exist. If the reference count drops to zero,
2267// we set our proxy pointer NULL, so that a new attempt at referencing
2268// will cause recreation.
2269void TextureCubeMap::addProxyRef(const Renderbuffer *proxy)
2270{
2271 for (int i = 0; i < 6; i++)
2272 {
2273 if (mFaceProxies[i] == proxy)
2274 mFaceProxyRefs[i]++;
2275 }
2276}
2277
2278void TextureCubeMap::releaseProxy(const Renderbuffer *proxy)
2279{
2280 for (int i = 0; i < 6; i++)
2281 {
2282 if (mFaceProxies[i] == proxy)
2283 {
2284 if (mFaceProxyRefs[i] > 0)
2285 mFaceProxyRefs[i]--;
2286
2287 if (mFaceProxyRefs[i] == 0)
2288 mFaceProxies[i] = NULL;
2289 }
2290 }
2291}
2292
2293GLenum TextureCubeMap::getTarget() const
2294{
2295 return GL_TEXTURE_CUBE_MAP;
2296}
2297
2298GLsizei TextureCubeMap::getWidth(GLenum target, GLint level) const
2299{
2300 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
2301 return mImageArray[faceIndex(target)][level].getWidth();
2302 else
2303 return 0;
2304}
2305
2306GLsizei TextureCubeMap::getHeight(GLenum target, GLint level) const
2307{
2308 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
2309 return mImageArray[faceIndex(target)][level].getHeight();
2310 else
2311 return 0;
2312}
2313
2314GLenum TextureCubeMap::getInternalFormat(GLenum target, GLint level) const
2315{
2316 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
2317 return mImageArray[faceIndex(target)][level].getFormat();
2318 else
2319 return GL_NONE;
2320}
2321
2322D3DFORMAT TextureCubeMap::getD3DFormat(GLenum target, GLint level) const
2323{
2324 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
2325 return mImageArray[faceIndex(target)][level].getD3DFormat();
2326 else
2327 return D3DFMT_UNKNOWN;
2328}
2329
2330void TextureCubeMap::setImagePosX(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
2331{
2332 setImage(0, level, width, height, format, type, unpackAlignment, pixels);
2333}
2334
2335void TextureCubeMap::setImageNegX(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
2336{
2337 setImage(1, level, width, height, format, type, unpackAlignment, pixels);
2338}
2339
2340void TextureCubeMap::setImagePosY(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
2341{
2342 setImage(2, level, width, height, format, type, unpackAlignment, pixels);
2343}
2344
2345void TextureCubeMap::setImageNegY(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
2346{
2347 setImage(3, level, width, height, format, type, unpackAlignment, pixels);
2348}
2349
2350void TextureCubeMap::setImagePosZ(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
2351{
2352 setImage(4, level, width, height, format, type, unpackAlignment, pixels);
2353}
2354
2355void TextureCubeMap::setImageNegZ(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
2356{
2357 setImage(5, level, width, height, format, type, unpackAlignment, pixels);
2358}
2359
2360void TextureCubeMap::setCompressedImage(GLenum face, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
2361{
2362 redefineImage(faceIndex(face), level, format, width, height, GL_UNSIGNED_BYTE);
2363
2364 Texture::setCompressedImage(imageSize, pixels, &mImageArray[faceIndex(face)][level]);
2365}
2366
2367void TextureCubeMap::commitRect(int face, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
2368{
2369 ASSERT(mImageArray[face][level].getSurface() != NULL);
2370
2371 if (level < levelCount())
2372 {
2373 IDirect3DSurface9 *destLevel = mTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level);
2374 ASSERT(destLevel != NULL);
2375
2376 if (destLevel != NULL)
2377 {
2378 Image *image = &mImageArray[face][level];
2379 image->updateSurface(destLevel, xoffset, yoffset, width, height);
2380
2381 destLevel->Release();
2382 image->markClean();
2383 }
2384 }
2385}
2386
2387void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
2388{
2389 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[faceIndex(target)][level]))
2390 {
2391 commitRect(faceIndex(target), level, xoffset, yoffset, width, height);
2392 }
2393}
2394
2395void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
2396{
2397 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[faceIndex(target)][level]))
2398 {
2399 commitRect(faceIndex(target), level, xoffset, yoffset, width, height);
2400 }
2401}
2402
2403// Tests for cube map sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 86.
2404bool TextureCubeMap::isSamplerComplete() const
2405{
2406 int size = mImageArray[0][0].getWidth();
2407
2408 bool mipmapping;
2409
2410 switch (mMinFilter)
2411 {
2412 case GL_NEAREST:
2413 case GL_LINEAR:
2414 mipmapping = false;
2415 break;
2416 case GL_NEAREST_MIPMAP_NEAREST:
2417 case GL_LINEAR_MIPMAP_NEAREST:
2418 case GL_NEAREST_MIPMAP_LINEAR:
2419 case GL_LINEAR_MIPMAP_LINEAR:
2420 mipmapping = true;
2421 break;
2422 default:
2423 UNREACHABLE();
2424 return false;
2425 }
2426
2427 if ((getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0) == GL_FLOAT && !getContext()->supportsFloat32LinearFilter()) ||
2428 (getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0) == GL_HALF_FLOAT_OES && !getContext()->supportsFloat16LinearFilter()))
2429 {
2430 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
2431 {
2432 return false;
2433 }
2434 }
2435
2436 if (!isPow2(size) && !getContext()->supportsNonPower2Texture())
2437 {
2438 if (getWrapS() != GL_CLAMP_TO_EDGE || getWrapT() != GL_CLAMP_TO_EDGE || mipmapping)
2439 {
2440 return false;
2441 }
2442 }
2443
2444 if (!mipmapping)
2445 {
2446 if (!isCubeComplete())
2447 {
2448 return false;
2449 }
2450 }
2451 else
2452 {
2453 if (!isMipmapCubeComplete()) // Also tests for isCubeComplete()
2454 {
2455 return false;
2456 }
2457 }
2458
2459 return true;
2460}
2461
2462// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
2463bool TextureCubeMap::isCubeComplete() const
2464{
2465 if (mImageArray[0][0].getWidth() <= 0 || mImageArray[0][0].getHeight() != mImageArray[0][0].getWidth())
2466 {
2467 return false;
2468 }
2469
2470 for (unsigned int face = 1; face < 6; face++)
2471 {
2472 if (mImageArray[face][0].getWidth() != mImageArray[0][0].getWidth() ||
2473 mImageArray[face][0].getWidth() != mImageArray[0][0].getHeight() ||
2474 mImageArray[face][0].getFormat() != mImageArray[0][0].getFormat() ||
2475 mImageArray[face][0].getType() != mImageArray[0][0].getType())
2476 {
2477 return false;
2478 }
2479 }
2480
2481 return true;
2482}
2483
2484bool TextureCubeMap::isMipmapCubeComplete() const
2485{
2486 if (isImmutable())
2487 {
2488 return true;
2489 }
2490
2491 if (!isCubeComplete())
2492 {
2493 return false;
2494 }
2495
2496 GLsizei size = mImageArray[0][0].getWidth();
2497
2498 int q = log2(size);
2499
2500 for (int face = 0; face < 6; face++)
2501 {
2502 for (int level = 1; level <= q; level++)
2503 {
2504 if (mImageArray[face][level].getFormat() != mImageArray[0][0].getFormat())
2505 {
2506 return false;
2507 }
2508
2509 if (mImageArray[face][level].getType() != mImageArray[0][0].getType())
2510 {
2511 return false;
2512 }
2513
2514 if (mImageArray[face][level].getWidth() != std::max(1, size >> level))
2515 {
2516 return false;
2517 }
2518 }
2519 }
2520
2521 return true;
2522}
2523
2524bool TextureCubeMap::isCompressed(GLenum target, GLint level) const
2525{
2526 return IsCompressed(getInternalFormat(target, level));
2527}
2528
2529IDirect3DBaseTexture9 *TextureCubeMap::getBaseTexture() const
2530{
2531 return mTexStorage ? mTexStorage->getBaseTexture() : NULL;
2532}
2533
2534// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
2535void TextureCubeMap::createTexture()
2536{
2537 GLsizei size = mImageArray[0][0].getWidth();
2538 GLint levels = creationLevels(size, 0);
2539 D3DFORMAT d3dfmt = mImageArray[0][0].getD3DFormat();
2540 DWORD d3dusage = GetTextureUsage(d3dfmt, mUsage, false);
2541
2542 delete mTexStorage;
2543 mTexStorage = new TextureStorageCubeMap(levels, d3dfmt, d3dusage, size);
2544
2545 if (mTexStorage->isManaged())
2546 {
2547 int levels = levelCount();
2548
2549 for (int face = 0; face < 6; face++)
2550 {
2551 for (int level = 0; level < levels; level++)
2552 {
2553 IDirect3DSurface9 *surface = mTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level);
2554 mImageArray[face][level].setManagedSurface(surface);
2555 }
2556 }
2557 }
2558
2559 mDirtyImages = true;
2560}
2561
2562void TextureCubeMap::updateTexture()
2563{
2564 for (int face = 0; face < 6; face++)
2565 {
2566 int levels = levelCount();
2567 for (int level = 0; level < levels; level++)
2568 {
2569 Image *image = &mImageArray[face][level];
2570
2571 if (image->isDirty())
2572 {
2573 commitRect(face, level, 0, 0, image->getWidth(), image->getHeight());
2574 }
2575 }
2576 }
2577}
2578
2579void TextureCubeMap::convertToRenderTarget()
2580{
2581 TextureStorageCubeMap *newTexStorage = NULL;
2582
2583 if (mImageArray[0][0].getWidth() != 0)
2584 {
2585 GLsizei size = mImageArray[0][0].getWidth();
2586 GLint levels = creationLevels(size, 0);
2587 D3DFORMAT d3dfmt = mImageArray[0][0].getD3DFormat();
2588 DWORD d3dusage = GetTextureUsage(d3dfmt, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, true);
2589
2590 newTexStorage = new TextureStorageCubeMap(levels, d3dfmt, d3dusage, size);
2591
2592 if (mTexStorage != NULL)
2593 {
2594 int levels = levelCount();
2595 for (int f = 0; f < 6; f++)
2596 {
2597 for (int i = 0; i < levels; i++)
2598 {
2599 IDirect3DSurface9 *source = mTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i);
2600 IDirect3DSurface9 *dest = newTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i);
2601
2602 if (!copyToRenderTarget(dest, source, mTexStorage->isManaged()))
2603 {
2604 delete newTexStorage;
2605 if (source) source->Release();
2606 if (dest) dest->Release();
2607 return error(GL_OUT_OF_MEMORY);
2608 }
2609
2610 if (source) source->Release();
2611 if (dest) dest->Release();
2612 }
2613 }
2614 }
2615 }
2616
2617 delete mTexStorage;
2618 mTexStorage = newTexStorage;
2619
2620 mDirtyImages = true;
2621}
2622
2623void TextureCubeMap::setImage(int faceIndex, GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
2624{
2625 redefineImage(faceIndex, level, format, width, height, type);
2626
2627 Texture::setImage(unpackAlignment, pixels, &mImageArray[faceIndex][level]);
2628}
2629
2630unsigned int TextureCubeMap::faceIndex(GLenum face)
2631{
2632 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
2633 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
2634 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
2635 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
2636 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
2637
2638 return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
2639}
2640
2641void TextureCubeMap::redefineImage(int face, GLint level, GLenum format, GLsizei width, GLsizei height, GLenum type)
2642{
2643 bool redefined = mImageArray[face][level].redefine(format, width, height, type, false);
2644
2645 if (mTexStorage && redefined)
2646 {
2647 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
2648 {
2649 for (int f = 0; f < 6; f++)
2650 {
2651 mImageArray[f][i].markDirty();
2652 }
2653 }
2654
2655 delete mTexStorage;
2656 mTexStorage = NULL;
2657
2658 mDirtyImages = true;
2659 }
2660}
2661
2662void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
2663{
2664 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
2665
2666 if (!renderTarget)
2667 {
2668 ERR("Failed to retrieve the render target.");
2669 return error(GL_OUT_OF_MEMORY);
2670 }
2671
2672 unsigned int faceindex = faceIndex(target);
2673 redefineImage(faceindex, level, format, width, height, GL_UNSIGNED_BYTE);
2674
2675 if (!mImageArray[faceindex][level].isRenderableFormat())
2676 {
2677 mImageArray[faceindex][level].copy(0, 0, x, y, width, height, renderTarget);
2678 mDirtyImages = true;
2679 }
2680 else
2681 {
2682 if (!mTexStorage || !mTexStorage->isRenderTarget())
2683 {
2684 convertToRenderTarget();
2685 }
2686
2687 mImageArray[faceindex][level].markClean();
2688
2689 ASSERT(width == height);
2690
2691 if (width > 0 && level < levelCount())
2692 {
2693 RECT sourceRect;
2694 sourceRect.left = x;
2695 sourceRect.right = x + width;
2696 sourceRect.top = y;
2697 sourceRect.bottom = y + height;
2698
2699 IDirect3DSurface9 *dest = mTexStorage->getCubeMapSurface(target, level);
2700
2701 if (dest)
2702 {
2703 getBlitter()->copy(renderTarget, sourceRect, format, 0, 0, dest);
2704 dest->Release();
2705 }
2706 }
2707 }
2708
2709 renderTarget->Release();
2710}
2711
2712void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
2713{
2714 GLsizei size = mImageArray[faceIndex(target)][level].getWidth();
2715
2716 if (xoffset + width > size || yoffset + height > size)
2717 {
2718 return error(GL_INVALID_VALUE);
2719 }
2720
2721 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
2722
2723 if (!renderTarget)
2724 {
2725 ERR("Failed to retrieve the render target.");
2726 return error(GL_OUT_OF_MEMORY);
2727 }
2728
2729 unsigned int faceindex = faceIndex(target);
2730
2731 if (!mImageArray[faceindex][level].isRenderableFormat() || (!mTexStorage && !isSamplerComplete()))
2732 {
2733 mImageArray[faceindex][level].copy(0, 0, x, y, width, height, renderTarget);
2734 mDirtyImages = true;
2735 }
2736 else
2737 {
2738 if (!mTexStorage || !mTexStorage->isRenderTarget())
2739 {
2740 convertToRenderTarget();
2741 }
2742
2743 updateTexture();
2744
2745 if (level < levelCount())
2746 {
2747 RECT sourceRect;
2748 sourceRect.left = x;
2749 sourceRect.right = x + width;
2750 sourceRect.top = y;
2751 sourceRect.bottom = y + height;
2752
2753 IDirect3DSurface9 *dest = mTexStorage->getCubeMapSurface(target, level);
2754
2755 if (dest)
2756 {
2757 getBlitter()->copy(renderTarget, sourceRect, mImageArray[0][0].getFormat(), xoffset, yoffset, dest);
2758 dest->Release();
2759 }
2760 }
2761 }
2762
2763 renderTarget->Release();
2764}
2765
2766void TextureCubeMap::storage(GLsizei levels, GLenum internalformat, GLsizei size)
2767{
2768 GLenum format = gl::ExtractFormat(internalformat);
2769 GLenum type = gl::ExtractType(internalformat);
2770 D3DFORMAT d3dfmt = ConvertTextureFormatType(format, type);
2771 DWORD d3dusage = GetTextureUsage(d3dfmt, mUsage, false);
2772
2773 delete mTexStorage;
2774 mTexStorage = new TextureStorageCubeMap(levels, d3dfmt, d3dusage, size);
2775 mImmutable = true;
2776
2777 for (int level = 0; level < levels; level++)
2778 {
2779 for (int face = 0; face < 6; face++)
2780 {
2781 mImageArray[face][level].redefine(format, size, size, type, true);
2782 size = std::max(1, size >> 1);
2783 }
2784 }
2785
2786 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2787 {
2788 for (int face = 0; face < 6; face++)
2789 {
2790 mImageArray[face][level].redefine(GL_NONE, 0, 0, GL_UNSIGNED_BYTE, true);
2791 }
2792 }
2793
2794 if (mTexStorage->isManaged())
2795 {
2796 int levels = levelCount();
2797
2798 for (int face = 0; face < 6; face++)
2799 {
2800 for (int level = 0; level < levels; level++)
2801 {
2802 IDirect3DSurface9 *surface = mTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level);
2803 mImageArray[face][level].setManagedSurface(surface);
2804 }
2805 }
2806 }
2807}
2808
2809void TextureCubeMap::generateMipmaps()
2810{
2811 if (!isCubeComplete())
2812 {
2813 return error(GL_INVALID_OPERATION);
2814 }
2815
2816 if (!getContext()->supportsNonPower2Texture())
2817 {
2818 if (!isPow2(mImageArray[0][0].getWidth()))
2819 {
2820 return error(GL_INVALID_OPERATION);
2821 }
2822 }
2823
2824 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
2825 unsigned int q = log2(mImageArray[0][0].getWidth());
2826 for (unsigned int f = 0; f < 6; f++)
2827 {
2828 for (unsigned int i = 1; i <= q; i++)
2829 {
2830 redefineImage(f, i, mImageArray[f][0].getFormat(),
2831 std::max(mImageArray[f][0].getWidth() >> i, 1),
2832 std::max(mImageArray[f][0].getWidth() >> i, 1),
2833 mImageArray[f][0].getType());
2834 }
2835 }
2836
2837 if (mTexStorage && mTexStorage->isRenderTarget())
2838 {
2839 for (unsigned int f = 0; f < 6; f++)
2840 {
2841 for (unsigned int i = 1; i <= q; i++)
2842 {
2843 IDirect3DSurface9 *upper = mTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i-1);
2844 IDirect3DSurface9 *lower = mTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i);
2845
2846 if (upper != NULL && lower != NULL)
2847 {
2848 getBlitter()->boxFilter(upper, lower);
2849 }
2850
2851 if (upper != NULL) upper->Release();
2852 if (lower != NULL) lower->Release();
2853
2854 mImageArray[f][i].markClean();
2855 }
2856 }
2857 }
2858 else
2859 {
2860 for (unsigned int f = 0; f < 6; f++)
2861 {
2862 for (unsigned int i = 1; i <= q; i++)
2863 {
2864 if (mImageArray[f][i].getSurface() == NULL)
2865 {
2866 return error(GL_OUT_OF_MEMORY);
2867 }
2868
2869 if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[f][i].getSurface(), NULL, NULL, mImageArray[f][i - 1].getSurface(), NULL, NULL, D3DX_FILTER_BOX, 0)))
2870 {
2871 ERR(" failed to load filter %d to %d.", i - 1, i);
2872 }
2873
2874 mImageArray[f][i].markDirty();
2875 }
2876 }
2877 }
2878}
2879
2880Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target)
2881{
2882 if (!IsCubemapTextureTarget(target))
2883 {
2884 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
2885 }
2886
2887 unsigned int face = faceIndex(target);
2888
2889 if (mFaceProxies[face] == NULL)
2890 {
2891 mFaceProxies[face] = new Renderbuffer(id(), new RenderbufferTextureCubeMap(this, target));
2892 }
2893
2894 return mFaceProxies[face];
2895}
2896
2897// Increments refcount on surface.
2898// caller must Release() the returned surface
2899IDirect3DSurface9 *TextureCubeMap::getRenderTarget(GLenum target)
2900{
2901 ASSERT(IsCubemapTextureTarget(target));
2902
2903 // ensure the underlying texture is created
2904 if (getStorage(true) == NULL)
2905 {
2906 return NULL;
2907 }
2908
2909 updateTexture();
2910
2911 return mTexStorage->getCubeMapSurface(target, 0);
2912}
2913
2914TextureStorage *TextureCubeMap::getStorage(bool renderTarget)
2915{
2916 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
2917 {
2918 if (renderTarget)
2919 {
2920 convertToRenderTarget();
2921 }
2922 else
2923 {
2924 createTexture();
2925 }
2926 }
2927
2928 return mTexStorage;
2929}
2930
2931}