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