blob: 29a32d77372172c24c6610a16103a13b4bfaab38 [file] [log] [blame]
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +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>
jbauman@chromium.orgf1f28c82011-05-12 20:53:34 +000016#include <intrin.h>
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +000017
18#include "common/debug.h"
19
jbauman@chromium.orgae345802011-03-30 22:04:25 +000020#include "libEGL/Display.h"
21
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +000022#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{
daniel@transgaming.coma9eb5da2011-03-21 16:39:16 +000030unsigned int Texture::mCurrentSerial = 1;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +000031
daniel@transgaming.comde631782011-11-09 17:45:04 +000032Image::Image()
daniel@transgaming.comdff362f2011-11-09 17:45:08 +000033 : mWidth(0), mHeight(0), mDirty(false), mSurface(NULL), mFormat(GL_NONE), mType(GL_UNSIGNED_BYTE)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +000034{
35}
36
daniel@transgaming.comde631782011-11-09 17:45:04 +000037Image::~Image()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +000038{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +000039 if (mSurface)
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +000040 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +000041 mSurface->Release();
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +000042 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +000043}
44
daniel@transgaming.comdff362f2011-11-09 17:45:08 +000045void Image::redefine(GLenum format, GLsizei width, GLsizei height, GLenum type)
46{
daniel@transgaming.com4c0a7712011-11-09 17:45:19 +000047 if (mWidth != width ||
48 mHeight != height ||
49 mFormat != format ||
50 mType != type)
51 {
52 if (mSurface)
53 {
54 mSurface->Release();
55 mSurface = NULL;
56 }
57 }
58
daniel@transgaming.comdff362f2011-11-09 17:45:08 +000059 mWidth = width;
60 mHeight = height;
61 mFormat = format;
62 mType = type;
daniel@transgaming.comdff362f2011-11-09 17:45:08 +000063}
64
65void Image::createSurface()
66{
67 if(mSurface)
68 {
69 return;
70 }
71
72 IDirect3DTexture9 *newTexture = NULL;
73 IDirect3DSurface9 *newSurface = NULL;
74
75 if (mWidth != 0 && mHeight != 0)
76 {
77 int levelToFetch = 0;
78 GLsizei requestWidth = mWidth;
79 GLsizei requestHeight = mHeight;
80 if (IsCompressed(mFormat) && (mWidth % 4 != 0 || mHeight % 4 != 0))
81 {
82 bool isMult4 = false;
83 int upsampleCount = 0;
84 while (!isMult4)
85 {
86 requestWidth <<= 1;
87 requestHeight <<= 1;
88 upsampleCount++;
89 if (requestWidth % 4 == 0 && requestHeight % 4 == 0)
90 {
91 isMult4 = true;
92 }
93 }
94 levelToFetch = upsampleCount;
95 }
96
97 HRESULT result = getDevice()->CreateTexture(requestWidth, requestHeight, levelToFetch + 1, NULL, getD3DFormat(),
98 D3DPOOL_SYSTEMMEM, &newTexture, NULL);
99
100 if (FAILED(result))
101 {
102 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com73de05a2011-11-09 17:45:24 +0000103 ERR("Creating image surface failed.");
daniel@transgaming.comdff362f2011-11-09 17:45:08 +0000104 return error(GL_OUT_OF_MEMORY);
105 }
106
107 newTexture->GetSurfaceLevel(levelToFetch, &newSurface);
108 newTexture->Release();
109 }
110
111 mSurface = newSurface;
112}
113
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +0000114HRESULT Image::lock(D3DLOCKED_RECT *lockedRect, const RECT *rect)
115{
116 createSurface();
117
118 HRESULT result = D3DERR_INVALIDCALL;
119
120 if (mSurface)
121 {
122 result = mSurface->LockRect(lockedRect, rect, 0);
123 ASSERT(SUCCEEDED(result));
124
125 mDirty = true;
126 }
127
128 return result;
129}
130
131void Image::unlock()
132{
133 if (mSurface)
134 {
135 HRESULT result = mSurface->UnlockRect();
136 ASSERT(SUCCEEDED(result));
137 }
138}
139
daniel@transgaming.comde631782011-11-09 17:45:04 +0000140bool Image::isRenderable() const
daniel@transgaming.com549bdef2011-03-29 00:57:01 +0000141{
142 switch(getD3DFormat())
143 {
144 case D3DFMT_L8:
145 case D3DFMT_A8L8:
146 case D3DFMT_DXT1:
gman@chromium.org50c526d2011-08-10 05:19:44 +0000147 case D3DFMT_DXT3:
148 case D3DFMT_DXT5:
daniel@transgaming.com549bdef2011-03-29 00:57:01 +0000149 return false;
150 case D3DFMT_A8R8G8B8:
151 case D3DFMT_X8R8G8B8:
152 case D3DFMT_A16B16G16R16F:
153 case D3DFMT_A32B32G32R32F:
154 return true;
155 default:
156 UNREACHABLE();
157 }
158
159 return false;
160}
161
daniel@transgaming.comde631782011-11-09 17:45:04 +0000162D3DFORMAT Image::getD3DFormat() const
daniel@transgaming.com549bdef2011-03-29 00:57:01 +0000163{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +0000164 if (mFormat == GL_COMPRESSED_RGB_S3TC_DXT1_EXT ||
165 mFormat == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT)
daniel@transgaming.com549bdef2011-03-29 00:57:01 +0000166 {
167 return D3DFMT_DXT1;
168 }
daniel@transgaming.comdff362f2011-11-09 17:45:08 +0000169 else if (mFormat == GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE)
gman@chromium.org50c526d2011-08-10 05:19:44 +0000170 {
171 return D3DFMT_DXT3;
172 }
daniel@transgaming.comdff362f2011-11-09 17:45:08 +0000173 else if (mFormat == GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE)
gman@chromium.org50c526d2011-08-10 05:19:44 +0000174 {
175 return D3DFMT_DXT5;
176 }
daniel@transgaming.comdff362f2011-11-09 17:45:08 +0000177 else if (mType == GL_FLOAT)
daniel@transgaming.com549bdef2011-03-29 00:57:01 +0000178 {
179 return D3DFMT_A32B32G32R32F;
180 }
daniel@transgaming.comdff362f2011-11-09 17:45:08 +0000181 else if (mType == GL_HALF_FLOAT_OES)
daniel@transgaming.com549bdef2011-03-29 00:57:01 +0000182 {
183 return D3DFMT_A16B16G16R16F;
184 }
daniel@transgaming.comdff362f2011-11-09 17:45:08 +0000185 else if (mType == GL_UNSIGNED_BYTE)
daniel@transgaming.com549bdef2011-03-29 00:57:01 +0000186 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +0000187 if (mFormat == GL_LUMINANCE && getContext()->supportsLuminanceTextures())
daniel@transgaming.com549bdef2011-03-29 00:57:01 +0000188 {
189 return D3DFMT_L8;
190 }
daniel@transgaming.comdff362f2011-11-09 17:45:08 +0000191 else if (mFormat == GL_LUMINANCE_ALPHA && getContext()->supportsLuminanceAlphaTextures())
daniel@transgaming.com549bdef2011-03-29 00:57:01 +0000192 {
193 return D3DFMT_A8L8;
194 }
daniel@transgaming.comdff362f2011-11-09 17:45:08 +0000195 else if (mFormat == GL_RGB)
daniel@transgaming.com549bdef2011-03-29 00:57:01 +0000196 {
197 return D3DFMT_X8R8G8B8;
198 }
199
200 return D3DFMT_A8R8G8B8;
201 }
202
203 return D3DFMT_A8R8G8B8;
204}
205
daniel@transgaming.com73de05a2011-11-09 17:45:24 +0000206IDirect3DSurface9 *Image::getSurface()
207{
208 createSurface();
209
210 return mSurface;
211}
212
daniel@transgaming.coma9eb5da2011-03-21 16:39:16 +0000213Texture::Texture(GLuint id) : RefCountObject(id), mSerial(issueSerial())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000214{
215 mMinFilter = GL_NEAREST_MIPMAP_LINEAR;
216 mMagFilter = GL_LINEAR;
217 mWrapS = GL_REPEAT;
218 mWrapT = GL_REPEAT;
daniel@transgaming.com0da803b2011-11-09 17:44:58 +0000219 mDirtyParameters = true;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +0000220
daniel@transgaming.com0da803b2011-11-09 17:44:58 +0000221 mDirtyImages = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +0000222
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000223 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000224}
225
226Texture::~Texture()
227{
228}
229
230Blit *Texture::getBlitter()
231{
232 Context *context = getContext();
233 return context->getBlitter();
234}
235
236// Returns true on successful filter state update (valid enum parameter)
237bool Texture::setMinFilter(GLenum filter)
238{
239 switch (filter)
240 {
241 case GL_NEAREST:
242 case GL_LINEAR:
243 case GL_NEAREST_MIPMAP_NEAREST:
244 case GL_LINEAR_MIPMAP_NEAREST:
245 case GL_NEAREST_MIPMAP_LINEAR:
246 case GL_LINEAR_MIPMAP_LINEAR:
247 {
248 if (mMinFilter != filter)
249 {
250 mMinFilter = filter;
daniel@transgaming.com0da803b2011-11-09 17:44:58 +0000251 mDirtyParameters = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000252 }
253 return true;
254 }
255 default:
256 return false;
257 }
258}
259
260// Returns true on successful filter state update (valid enum parameter)
261bool Texture::setMagFilter(GLenum filter)
262{
263 switch (filter)
264 {
265 case GL_NEAREST:
266 case GL_LINEAR:
267 {
268 if (mMagFilter != filter)
269 {
270 mMagFilter = filter;
daniel@transgaming.com0da803b2011-11-09 17:44:58 +0000271 mDirtyParameters = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000272 }
273 return true;
274 }
275 default:
276 return false;
277 }
278}
279
280// Returns true on successful wrap state update (valid enum parameter)
281bool Texture::setWrapS(GLenum wrap)
282{
283 switch (wrap)
284 {
285 case GL_REPEAT:
286 case GL_CLAMP_TO_EDGE:
287 case GL_MIRRORED_REPEAT:
288 {
289 if (mWrapS != wrap)
290 {
291 mWrapS = wrap;
daniel@transgaming.com0da803b2011-11-09 17:44:58 +0000292 mDirtyParameters = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000293 }
294 return true;
295 }
296 default:
297 return false;
298 }
299}
300
301// Returns true on successful wrap state update (valid enum parameter)
302bool Texture::setWrapT(GLenum wrap)
303{
304 switch (wrap)
305 {
306 case GL_REPEAT:
307 case GL_CLAMP_TO_EDGE:
308 case GL_MIRRORED_REPEAT:
309 {
310 if (mWrapT != wrap)
311 {
312 mWrapT = wrap;
daniel@transgaming.com0da803b2011-11-09 17:44:58 +0000313 mDirtyParameters = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000314 }
315 return true;
316 }
317 default:
318 return false;
319 }
320}
321
322GLenum Texture::getMinFilter() const
323{
324 return mMinFilter;
325}
326
327GLenum Texture::getMagFilter() const
328{
329 return mMagFilter;
330}
331
332GLenum Texture::getWrapS() const
333{
334 return mWrapS;
335}
336
337GLenum Texture::getWrapT() const
338{
339 return mWrapT;
340}
341
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000342// Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input
343// into the target pixel rectangle at output with outputPitch bytes in between each line.
344void Texture::loadImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type,
345 GLint unpackAlignment, const void *input, size_t outputPitch, void *output, D3DSURFACE_DESC *description) const
346{
347 GLsizei inputPitch = -ComputePitch(width, format, type, unpackAlignment);
348 input = ((char*)input) - inputPitch * (height - 1);
349
350 switch (type)
351 {
352 case GL_UNSIGNED_BYTE:
353 switch (format)
354 {
355 case GL_ALPHA:
356 loadAlphaImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
357 break;
358 case GL_LUMINANCE:
359 loadLuminanceImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output, description->Format == D3DFMT_L8);
360 break;
361 case GL_LUMINANCE_ALPHA:
362 loadLuminanceAlphaImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output, description->Format == D3DFMT_A8L8);
363 break;
364 case GL_RGB:
365 loadRGBUByteImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
366 break;
367 case GL_RGBA:
jbauman@chromium.orgf1f28c82011-05-12 20:53:34 +0000368 if (supportsSSE2())
369 {
370 loadRGBAUByteImageDataSSE2(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
371 }
372 else
373 {
374 loadRGBAUByteImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
375 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000376 break;
377 case GL_BGRA_EXT:
378 loadBGRAImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
379 break;
380 default: UNREACHABLE();
381 }
382 break;
383 case GL_UNSIGNED_SHORT_5_6_5:
384 switch (format)
385 {
386 case GL_RGB:
387 loadRGB565ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
388 break;
389 default: UNREACHABLE();
390 }
391 break;
392 case GL_UNSIGNED_SHORT_4_4_4_4:
393 switch (format)
394 {
395 case GL_RGBA:
396 loadRGBA4444ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
397 break;
398 default: UNREACHABLE();
399 }
400 break;
401 case GL_UNSIGNED_SHORT_5_5_5_1:
402 switch (format)
403 {
404 case GL_RGBA:
405 loadRGBA5551ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
406 break;
407 default: UNREACHABLE();
408 }
409 break;
410 case GL_FLOAT:
411 switch (format)
412 {
413 // float textures are converted to RGBA, not BGRA, as they're stored that way in D3D
414 case GL_ALPHA:
415 loadAlphaFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
416 break;
417 case GL_LUMINANCE:
418 loadLuminanceFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
419 break;
420 case GL_LUMINANCE_ALPHA:
421 loadLuminanceAlphaFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
422 break;
423 case GL_RGB:
424 loadRGBFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
425 break;
426 case GL_RGBA:
427 loadRGBAFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
428 break;
429 default: UNREACHABLE();
430 }
431 break;
432 case GL_HALF_FLOAT_OES:
433 switch (format)
434 {
435 // float textures are converted to RGBA, not BGRA, as they're stored that way in D3D
436 case GL_ALPHA:
437 loadAlphaHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
438 break;
439 case GL_LUMINANCE:
440 loadLuminanceHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
441 break;
442 case GL_LUMINANCE_ALPHA:
443 loadLuminanceAlphaHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
444 break;
445 case GL_RGB:
446 loadRGBHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
447 break;
448 case GL_RGBA:
449 loadRGBAHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
450 break;
451 default: UNREACHABLE();
452 }
453 break;
454 default: UNREACHABLE();
455 }
456}
457
458void Texture::loadAlphaImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
459 int inputPitch, const void *input, size_t outputPitch, void *output) const
460{
461 const unsigned char *source = NULL;
462 unsigned char *dest = NULL;
463
464 for (int y = 0; y < height; y++)
465 {
466 source = static_cast<const unsigned char*>(input) + y * inputPitch;
467 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
468 for (int x = 0; x < width; x++)
469 {
470 dest[4 * x + 0] = 0;
471 dest[4 * x + 1] = 0;
472 dest[4 * x + 2] = 0;
473 dest[4 * x + 3] = source[x];
474 }
475 }
476}
477
478void Texture::loadAlphaFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
479 int inputPitch, const void *input, size_t outputPitch, void *output) const
480{
481 const float *source = NULL;
482 float *dest = NULL;
483
484 for (int y = 0; y < height; y++)
485 {
486 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
487 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
488 for (int x = 0; x < width; x++)
489 {
490 dest[4 * x + 0] = 0;
491 dest[4 * x + 1] = 0;
492 dest[4 * x + 2] = 0;
493 dest[4 * x + 3] = source[x];
494 }
495 }
496}
497
498void Texture::loadAlphaHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
499 int inputPitch, const void *input, size_t outputPitch, void *output) const
500{
501 const unsigned short *source = NULL;
502 unsigned short *dest = NULL;
503
504 for (int y = 0; y < height; y++)
505 {
506 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
507 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
508 for (int x = 0; x < width; x++)
509 {
510 dest[4 * x + 0] = 0;
511 dest[4 * x + 1] = 0;
512 dest[4 * x + 2] = 0;
513 dest[4 * x + 3] = source[x];
514 }
515 }
516}
517
518void Texture::loadLuminanceImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
519 int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const
520{
521 const int destBytesPerPixel = native? 1: 4;
522 const unsigned char *source = NULL;
523 unsigned char *dest = NULL;
524
525 for (int y = 0; y < height; y++)
526 {
527 source = static_cast<const unsigned char*>(input) + y * inputPitch;
528 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * destBytesPerPixel;
529
530 if (!native) // BGRA8 destination format
531 {
532 for (int x = 0; x < width; x++)
533 {
534 dest[4 * x + 0] = source[x];
535 dest[4 * x + 1] = source[x];
536 dest[4 * x + 2] = source[x];
537 dest[4 * x + 3] = 0xFF;
538 }
539 }
540 else // L8 destination format
541 {
542 memcpy(dest, source, width);
543 }
544 }
545}
546
547void Texture::loadLuminanceFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
548 int inputPitch, const void *input, size_t outputPitch, void *output) const
549{
550 const float *source = NULL;
551 float *dest = NULL;
552
553 for (int y = 0; y < height; y++)
554 {
555 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
556 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
557 for (int x = 0; x < width; x++)
558 {
559 dest[4 * x + 0] = source[x];
560 dest[4 * x + 1] = source[x];
561 dest[4 * x + 2] = source[x];
562 dest[4 * x + 3] = 1.0f;
563 }
564 }
565}
566
567void Texture::loadLuminanceHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
568 int inputPitch, const void *input, size_t outputPitch, void *output) const
569{
570 const unsigned short *source = NULL;
571 unsigned short *dest = NULL;
572
573 for (int y = 0; y < height; y++)
574 {
575 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
576 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
577 for (int x = 0; x < width; x++)
578 {
579 dest[4 * x + 0] = source[x];
580 dest[4 * x + 1] = source[x];
581 dest[4 * x + 2] = source[x];
582 dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1
583 }
584 }
585}
586
587void Texture::loadLuminanceAlphaImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
588 int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const
589{
590 const int destBytesPerPixel = native? 2: 4;
591 const unsigned char *source = NULL;
592 unsigned char *dest = NULL;
593
594 for (int y = 0; y < height; y++)
595 {
596 source = static_cast<const unsigned char*>(input) + y * inputPitch;
597 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * destBytesPerPixel;
598
599 if (!native) // BGRA8 destination format
600 {
601 for (int x = 0; x < width; x++)
602 {
603 dest[4 * x + 0] = source[2*x+0];
604 dest[4 * x + 1] = source[2*x+0];
605 dest[4 * x + 2] = source[2*x+0];
606 dest[4 * x + 3] = source[2*x+1];
607 }
608 }
609 else
610 {
611 memcpy(dest, source, width * 2);
612 }
613 }
614}
615
616void Texture::loadLuminanceAlphaFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
617 int inputPitch, const void *input, size_t outputPitch, void *output) const
618{
619 const float *source = NULL;
620 float *dest = NULL;
621
622 for (int y = 0; y < height; y++)
623 {
624 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
625 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
626 for (int x = 0; x < width; x++)
627 {
628 dest[4 * x + 0] = source[2*x+0];
629 dest[4 * x + 1] = source[2*x+0];
630 dest[4 * x + 2] = source[2*x+0];
631 dest[4 * x + 3] = source[2*x+1];
632 }
633 }
634}
635
636void Texture::loadLuminanceAlphaHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
637 int inputPitch, const void *input, size_t outputPitch, void *output) const
638{
639 const unsigned short *source = NULL;
640 unsigned short *dest = NULL;
641
642 for (int y = 0; y < height; y++)
643 {
644 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
645 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
646 for (int x = 0; x < width; x++)
647 {
648 dest[4 * x + 0] = source[2*x+0];
649 dest[4 * x + 1] = source[2*x+0];
650 dest[4 * x + 2] = source[2*x+0];
651 dest[4 * x + 3] = source[2*x+1];
652 }
653 }
654}
655
656void Texture::loadRGBUByteImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
657 int inputPitch, const void *input, size_t outputPitch, void *output) const
658{
659 const unsigned char *source = NULL;
660 unsigned char *dest = NULL;
661
662 for (int y = 0; y < height; y++)
663 {
664 source = static_cast<const unsigned char*>(input) + y * inputPitch;
665 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
666 for (int x = 0; x < width; x++)
667 {
668 dest[4 * x + 0] = source[x * 3 + 2];
669 dest[4 * x + 1] = source[x * 3 + 1];
670 dest[4 * x + 2] = source[x * 3 + 0];
671 dest[4 * x + 3] = 0xFF;
672 }
673 }
674}
675
676void Texture::loadRGB565ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
677 int inputPitch, const void *input, size_t outputPitch, void *output) const
678{
679 const unsigned short *source = NULL;
680 unsigned char *dest = NULL;
681
682 for (int y = 0; y < height; y++)
683 {
684 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
685 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
686 for (int x = 0; x < width; x++)
687 {
688 unsigned short rgba = source[x];
689 dest[4 * x + 0] = ((rgba & 0x001F) << 3) | ((rgba & 0x001F) >> 2);
690 dest[4 * x + 1] = ((rgba & 0x07E0) >> 3) | ((rgba & 0x07E0) >> 9);
691 dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
692 dest[4 * x + 3] = 0xFF;
693 }
694 }
695}
696
697void Texture::loadRGBFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
698 int inputPitch, const void *input, size_t outputPitch, void *output) const
699{
700 const float *source = NULL;
701 float *dest = NULL;
702
703 for (int y = 0; y < height; y++)
704 {
705 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
706 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
707 for (int x = 0; x < width; x++)
708 {
709 dest[4 * x + 0] = source[x * 3 + 0];
710 dest[4 * x + 1] = source[x * 3 + 1];
711 dest[4 * x + 2] = source[x * 3 + 2];
712 dest[4 * x + 3] = 1.0f;
713 }
714 }
715}
716
717void Texture::loadRGBHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
718 int inputPitch, const void *input, size_t outputPitch, void *output) const
719{
720 const unsigned short *source = NULL;
721 unsigned short *dest = NULL;
722
723 for (int y = 0; y < height; y++)
724 {
725 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
726 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
727 for (int x = 0; x < width; x++)
728 {
729 dest[4 * x + 0] = source[x * 3 + 0];
730 dest[4 * x + 1] = source[x * 3 + 1];
731 dest[4 * x + 2] = source[x * 3 + 2];
732 dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1
733 }
734 }
735}
736
jbauman@chromium.orgf1f28c82011-05-12 20:53:34 +0000737void Texture::loadRGBAUByteImageDataSSE2(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
738 int inputPitch, const void *input, size_t outputPitch, void *output) const
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000739{
jbauman@chromium.orgf1f28c82011-05-12 20:53:34 +0000740 const unsigned int *source = NULL;
741 unsigned int *dest = NULL;
742 __m128i brMask = _mm_set1_epi32(0x00ff00ff);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000743
744 for (int y = 0; y < height; y++)
745 {
jbauman@chromium.orgf1f28c82011-05-12 20:53:34 +0000746 source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);
747 dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4);
748 int x = 0;
749
750 // Make output writes aligned
751 for (x = 0; ((reinterpret_cast<intptr_t>(&dest[x]) & 15) != 0) && x < width; x++)
752 {
753 unsigned int rgba = source[x];
754 dest[x] = (_rotl(rgba, 16) & 0x00ff00ff) | (rgba & 0xff00ff00);
755 }
756
757 for (; x + 3 < width; x += 4)
758 {
759 __m128i sourceData = _mm_loadu_si128(reinterpret_cast<const __m128i*>(&source[x]));
760 // Mask out g and a, which don't change
761 __m128i gaComponents = _mm_andnot_si128(brMask, sourceData);
762 // Mask out b and r
763 __m128i brComponents = _mm_and_si128(sourceData, brMask);
764 // Swap b and r
765 __m128i brSwapped = _mm_shufflehi_epi16(_mm_shufflelo_epi16(brComponents, _MM_SHUFFLE(2, 3, 0, 1)), _MM_SHUFFLE(2, 3, 0, 1));
766 __m128i result = _mm_or_si128(gaComponents, brSwapped);
767 _mm_store_si128(reinterpret_cast<__m128i*>(&dest[x]), result);
768 }
769
770 // Perform leftover writes
771 for (; x < width; x++)
772 {
773 unsigned int rgba = source[x];
774 dest[x] = (_rotl(rgba, 16) & 0x00ff00ff) | (rgba & 0xff00ff00);
775 }
776 }
777}
778
779void Texture::loadRGBAUByteImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
780 int inputPitch, const void *input, size_t outputPitch, void *output) const
781{
782 const unsigned int *source = NULL;
783 unsigned int *dest = NULL;
784 for (int y = 0; y < height; y++)
785 {
786 source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);
787 dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4);
788
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000789 for (int x = 0; x < width; x++)
790 {
jbauman@chromium.orgf1f28c82011-05-12 20:53:34 +0000791 unsigned int rgba = source[x];
792 dest[x] = (_rotl(rgba, 16) & 0x00ff00ff) | (rgba & 0xff00ff00);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000793 }
794 }
795}
796
797void Texture::loadRGBA4444ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
798 int inputPitch, const void *input, size_t outputPitch, void *output) const
799{
800 const unsigned short *source = NULL;
801 unsigned char *dest = NULL;
802
803 for (int y = 0; y < height; y++)
804 {
805 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
806 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
807 for (int x = 0; x < width; x++)
808 {
809 unsigned short rgba = source[x];
810 dest[4 * x + 0] = ((rgba & 0x00F0) << 0) | ((rgba & 0x00F0) >> 4);
811 dest[4 * x + 1] = ((rgba & 0x0F00) >> 4) | ((rgba & 0x0F00) >> 8);
812 dest[4 * x + 2] = ((rgba & 0xF000) >> 8) | ((rgba & 0xF000) >> 12);
813 dest[4 * x + 3] = ((rgba & 0x000F) << 4) | ((rgba & 0x000F) >> 0);
814 }
815 }
816}
817
818void Texture::loadRGBA5551ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
819 int inputPitch, const void *input, size_t outputPitch, void *output) const
820{
821 const unsigned short *source = NULL;
822 unsigned char *dest = NULL;
823
824 for (int y = 0; y < height; y++)
825 {
826 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
827 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
828 for (int x = 0; x < width; x++)
829 {
830 unsigned short rgba = source[x];
831 dest[4 * x + 0] = ((rgba & 0x003E) << 2) | ((rgba & 0x003E) >> 3);
832 dest[4 * x + 1] = ((rgba & 0x07C0) >> 3) | ((rgba & 0x07C0) >> 8);
833 dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
834 dest[4 * x + 3] = (rgba & 0x0001) ? 0xFF : 0;
835 }
836 }
837}
838
839void Texture::loadRGBAFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
840 int inputPitch, const void *input, size_t outputPitch, void *output) const
841{
842 const float *source = NULL;
843 float *dest = NULL;
844
845 for (int y = 0; y < height; y++)
846 {
847 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
848 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
849 memcpy(dest, source, width * 16);
850 }
851}
852
853void Texture::loadRGBAHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
854 int inputPitch, const void *input, size_t outputPitch, void *output) const
855{
856 const unsigned char *source = NULL;
857 unsigned char *dest = NULL;
858
859 for (int y = 0; y < height; y++)
860 {
861 source = static_cast<const unsigned char*>(input) + y * inputPitch;
862 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8;
863 memcpy(dest, source, width * 8);
864 }
865}
866
867void Texture::loadBGRAImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
868 int inputPitch, const void *input, size_t outputPitch, void *output) const
869{
870 const unsigned char *source = NULL;
871 unsigned char *dest = NULL;
872
873 for (int y = 0; y < height; y++)
874 {
875 source = static_cast<const unsigned char*>(input) + y * inputPitch;
876 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
877 memcpy(dest, source, width*4);
878 }
879}
880
881void Texture::loadCompressedImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
gman@chromium.org50c526d2011-08-10 05:19:44 +0000882 int inputPitch, const void *input, size_t outputPitch, void *output) const {
883 switch (getD3DFormat())
884 {
885 case D3DFMT_DXT1:
886 loadDXT1ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
887 break;
888 case D3DFMT_DXT3:
889 loadDXT3ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
890 break;
891 case D3DFMT_DXT5:
892 loadDXT5ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
893 break;
894 }
895}
896
897static void FlipCopyDXT1BlockFull(const unsigned int* source, unsigned int* dest) {
898 // A DXT1 block layout is:
899 // [0-1] color0.
900 // [2-3] color1.
901 // [4-7] color bitmap, 2 bits per pixel.
902 // So each of the 4-7 bytes represents one line, flipping a block is just
903 // flipping those bytes.
904
905 // First 32-bits is two RGB565 colors shared by tile and does not need to be modified.
906 dest[0] = source[0];
907
908 // Second 32-bits contains 4 rows of 4 2-bit interpolants between the colors. All rows should be flipped.
909 dest[1] = (source[1] >> 24) |
910 ((source[1] << 8) & 0x00FF0000) |
911 ((source[1] >> 8) & 0x0000FF00) |
912 (source[1] << 24);
913}
914
915// Flips the first 2 lines of a DXT1 block in the y direction.
916static void FlipCopyDXT1BlockHalf(const unsigned int* source, unsigned int* dest) {
917 // See layout above.
918 dest[0] = source[0];
919 dest[1] = ((source[1] << 8) & 0x0000FF00) |
920 ((source[1] >> 8) & 0x000000FF);
921}
922
923// Flips a full DXT3 block in the y direction.
924static void FlipCopyDXT3BlockFull(const unsigned int* source, unsigned int* dest) {
925 // A DXT3 block layout is:
926 // [0-7] alpha bitmap, 4 bits per pixel.
927 // [8-15] a DXT1 block.
928
929 // First and Second 32 bits are 4bit per pixel alpha and need to be flipped.
930 dest[0] = (source[1] >> 16) | (source[1] << 16);
931 dest[1] = (source[0] >> 16) | (source[0] << 16);
932
933 // And flip the DXT1 block using the above function.
934 FlipCopyDXT1BlockFull(source + 2, dest + 2);
935}
936
937// Flips the first 2 lines of a DXT3 block in the y direction.
938static void FlipCopyDXT3BlockHalf(const unsigned int* source, unsigned int* dest) {
939 // See layout above.
940 dest[0] = (source[1] >> 16) | (source[1] << 16);
941 FlipCopyDXT1BlockHalf(source + 2, dest + 2);
942}
943
944// Flips a full DXT5 block in the y direction.
945static void FlipCopyDXT5BlockFull(const unsigned int* source, unsigned int* dest) {
946 // A DXT5 block layout is:
947 // [0] alpha0.
948 // [1] alpha1.
949 // [2-7] alpha bitmap, 3 bits per pixel.
950 // [8-15] a DXT1 block.
951
952 // The alpha bitmap doesn't easily map lines to bytes, so we have to
953 // interpret it correctly. Extracted from
954 // http://www.opengl.org/registry/specs/EXT/texture_compression_s3tc.txt :
955 //
956 // The 6 "bits" bytes of the block are decoded into one 48-bit integer:
957 //
958 // bits = bits_0 + 256 * (bits_1 + 256 * (bits_2 + 256 * (bits_3 +
959 // 256 * (bits_4 + 256 * bits_5))))
960 //
961 // bits is a 48-bit unsigned integer, from which a three-bit control code
962 // is extracted for a texel at location (x,y) in the block using:
963 //
964 // code(x,y) = bits[3*(4*y+x)+1..3*(4*y+x)+0]
965 //
966 // where bit 47 is the most significant and bit 0 is the least
967 // significant bit.
968 const unsigned char* sourceBytes = static_cast<const unsigned char*>(static_cast<const void*>(source));
969 unsigned char* destBytes = static_cast<unsigned char*>(static_cast<void*>(dest));
970 unsigned int line_0_1 = sourceBytes[2] + 256 * (sourceBytes[3] + 256 * sourceBytes[4]);
971 unsigned int line_2_3 = sourceBytes[5] + 256 * (sourceBytes[6] + 256 * sourceBytes[7]);
972 // swap lines 0 and 1 in line_0_1.
973 unsigned int line_1_0 = ((line_0_1 & 0x000fff) << 12) |
974 ((line_0_1 & 0xfff000) >> 12);
975 // swap lines 2 and 3 in line_2_3.
976 unsigned int line_3_2 = ((line_2_3 & 0x000fff) << 12) |
977 ((line_2_3 & 0xfff000) >> 12);
978 destBytes[0] = sourceBytes[0];
979 destBytes[1] = sourceBytes[1];
980 destBytes[2] = line_3_2 & 0xff;
981 destBytes[3] = (line_3_2 & 0xff00) >> 8;
gman@chromium.org2ac3e732011-08-10 07:59:47 +0000982 destBytes[4] = (line_3_2 & 0xff0000) >> 16;
gman@chromium.org50c526d2011-08-10 05:19:44 +0000983 destBytes[5] = line_1_0 & 0xff;
984 destBytes[6] = (line_1_0 & 0xff00) >> 8;
gman@chromium.org2ac3e732011-08-10 07:59:47 +0000985 destBytes[7] = (line_1_0 & 0xff0000) >> 16;
gman@chromium.org50c526d2011-08-10 05:19:44 +0000986
987 // And flip the DXT1 block using the above function.
988 FlipCopyDXT1BlockFull(source + 2, dest + 2);
989}
990
991// Flips the first 2 lines of a DXT5 block in the y direction.
992static void FlipCopyDXT5BlockHalf(const unsigned int* source, unsigned int* dest) {
993 // See layout above.
994 const unsigned char* sourceBytes = static_cast<const unsigned char*>(static_cast<const void*>(source));
995 unsigned char* destBytes = static_cast<unsigned char*>(static_cast<void*>(dest));
996 unsigned int line_0_1 = sourceBytes[2] + 256 * (sourceBytes[3] + 256 * sourceBytes[4]);
997 unsigned int line_1_0 = ((line_0_1 & 0x000fff) << 12) |
998 ((line_0_1 & 0xfff000) >> 12);
999 destBytes[0] = sourceBytes[0];
1000 destBytes[1] = sourceBytes[1];
1001 destBytes[2] = line_1_0 & 0xff;
1002 destBytes[3] = (line_1_0 & 0xff00) >> 8;
gman@chromium.org25c5cf62011-08-10 08:07:54 +00001003 destBytes[4] = (line_1_0 & 0xff0000) >> 16;
gman@chromium.org50c526d2011-08-10 05:19:44 +00001004 FlipCopyDXT1BlockHalf(source + 2, dest + 2);
1005}
1006
1007void Texture::loadDXT1ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001008 int inputPitch, const void *input, size_t outputPitch, void *output) const
1009{
1010 ASSERT(xoffset % 4 == 0);
1011 ASSERT(yoffset % 4 == 0);
1012 ASSERT(width % 4 == 0 || width == 2 || width == 1);
1013 ASSERT(inputPitch % 8 == 0);
1014 ASSERT(outputPitch % 8 == 0);
1015
1016 const unsigned int *source = reinterpret_cast<const unsigned int*>(input);
1017 unsigned int *dest = reinterpret_cast<unsigned int*>(output);
1018
gman@chromium.org50c526d2011-08-10 05:19:44 +00001019 // Round width up in case it is less than 4.
1020 int blocksAcross = (width + 3) / 4;
1021 int intsAcross = blocksAcross * 2;
1022
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001023 switch (height)
1024 {
1025 case 1:
gman@chromium.org50c526d2011-08-10 05:19:44 +00001026 for (int x = 0; x < intsAcross; x += 2)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001027 {
gman@chromium.org50c526d2011-08-10 05:19:44 +00001028 // just copy the block
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001029 dest[x] = source[x];
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001030 dest[x + 1] = source[x + 1];
1031 }
1032 break;
1033 case 2:
gman@chromium.org50c526d2011-08-10 05:19:44 +00001034 for (int x = 0; x < intsAcross; x += 2)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001035 {
gman@chromium.org50c526d2011-08-10 05:19:44 +00001036 FlipCopyDXT1BlockHalf(source + x, dest + x);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001037 }
1038 break;
1039 default:
1040 ASSERT(height % 4 == 0);
1041 for (int y = 0; y < height / 4; ++y)
1042 {
1043 const unsigned int *source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);
1044 unsigned int *dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
1045
gman@chromium.org50c526d2011-08-10 05:19:44 +00001046 for (int x = 0; x < intsAcross; x += 2)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001047 {
gman@chromium.org50c526d2011-08-10 05:19:44 +00001048 FlipCopyDXT1BlockFull(source + x, dest + x);
1049 }
1050 }
1051 break;
1052 }
1053}
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001054
gman@chromium.org50c526d2011-08-10 05:19:44 +00001055void Texture::loadDXT3ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
1056 int inputPitch, const void *input, size_t outputPitch, void *output) const
1057{
1058 ASSERT(xoffset % 4 == 0);
1059 ASSERT(yoffset % 4 == 0);
1060 ASSERT(width % 4 == 0 || width == 2 || width == 1);
1061 ASSERT(inputPitch % 16 == 0);
1062 ASSERT(outputPitch % 16 == 0);
1063
1064 const unsigned int *source = reinterpret_cast<const unsigned int*>(input);
1065 unsigned int *dest = reinterpret_cast<unsigned int*>(output);
1066
1067 // Round width up in case it is less than 4.
1068 int blocksAcross = (width + 3) / 4;
1069 int intsAcross = blocksAcross * 4;
1070
1071 switch (height)
1072 {
1073 case 1:
1074 for (int x = 0; x < intsAcross; x += 4)
1075 {
1076 // just copy the block
1077 dest[x] = source[x];
1078 dest[x + 1] = source[x + 1];
1079 dest[x + 2] = source[x + 2];
1080 dest[x + 3] = source[x + 3];
1081 }
1082 break;
1083 case 2:
1084 for (int x = 0; x < intsAcross; x += 4)
1085 {
1086 FlipCopyDXT3BlockHalf(source + x, dest + x);
1087 }
1088 break;
1089 default:
1090 ASSERT(height % 4 == 0);
1091 for (int y = 0; y < height / 4; ++y)
1092 {
1093 const unsigned int *source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);
1094 unsigned int *dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
1095
1096 for (int x = 0; x < intsAcross; x += 4)
1097 {
1098 FlipCopyDXT3BlockFull(source + x, dest + x);
1099 }
1100 }
1101 break;
1102 }
1103}
1104
1105void Texture::loadDXT5ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
1106 int inputPitch, const void *input, size_t outputPitch, void *output) const
1107{
1108 ASSERT(xoffset % 4 == 0);
1109 ASSERT(yoffset % 4 == 0);
1110 ASSERT(width % 4 == 0 || width == 2 || width == 1);
1111 ASSERT(inputPitch % 16 == 0);
1112 ASSERT(outputPitch % 16 == 0);
1113
1114 const unsigned int *source = reinterpret_cast<const unsigned int*>(input);
1115 unsigned int *dest = reinterpret_cast<unsigned int*>(output);
1116
1117 // Round width up in case it is less than 4.
1118 int blocksAcross = (width + 3) / 4;
1119 int intsAcross = blocksAcross * 4;
1120
1121 switch (height)
1122 {
1123 case 1:
1124 for (int x = 0; x < intsAcross; x += 4)
1125 {
1126 // just copy the block
1127 dest[x] = source[x];
1128 dest[x + 1] = source[x + 1];
1129 dest[x + 2] = source[x + 2];
1130 dest[x + 3] = source[x + 3];
1131 }
1132 break;
1133 case 2:
1134 for (int x = 0; x < intsAcross; x += 4)
1135 {
1136 FlipCopyDXT5BlockHalf(source + x, dest + x);
1137 }
1138 break;
1139 default:
1140 ASSERT(height % 4 == 0);
gman@chromium.org2ac3e732011-08-10 07:59:47 +00001141 for (int y = 0; y < height / 4; ++y)
gman@chromium.org50c526d2011-08-10 05:19:44 +00001142 {
1143 const unsigned int *source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);
1144 unsigned int *dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
1145
1146 for (int x = 0; x < intsAcross; x += 4)
1147 {
1148 FlipCopyDXT5BlockFull(source + x, dest + x);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001149 }
1150 }
1151 break;
1152 }
1153}
1154
daniel@transgaming.com61208202011-03-21 16:38:50 +00001155void Texture::setImage(GLint unpackAlignment, const void *pixels, Image *image)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001156{
daniel@transgaming.com73de05a2011-11-09 17:45:24 +00001157 if (pixels != NULL)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001158 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001159 D3DLOCKED_RECT locked;
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +00001160 HRESULT result = image->lock(&locked, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001161
1162 if (SUCCEEDED(result))
1163 {
daniel@transgaming.com73de05a2011-11-09 17:45:24 +00001164 D3DSURFACE_DESC description;
1165 image->getSurface()->GetDesc(&description);
1166
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001167 loadImageData(0, 0, image->getWidth(), image->getHeight(), image->getFormat(), image->getType(), unpackAlignment, pixels, locked.Pitch, locked.pBits, &description);
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +00001168 image->unlock();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001169 }
1170
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001171 image->markDirty();
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001172 mDirtyImages = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001173 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001174}
1175
daniel@transgaming.com61208202011-03-21 16:38:50 +00001176void Texture::setCompressedImage(GLsizei imageSize, const void *pixels, Image *image)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001177{
daniel@transgaming.com73de05a2011-11-09 17:45:24 +00001178 if (pixels != NULL)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001179 {
1180 D3DLOCKED_RECT locked;
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +00001181 HRESULT result = image->lock(&locked, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001182
1183 if (SUCCEEDED(result))
1184 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001185 int inputPitch = ComputeCompressedPitch(image->getWidth(), image->getFormat());
1186 int inputSize = ComputeCompressedSize(image->getWidth(), image->getHeight(), image->getFormat());
1187 loadCompressedImageData(0, 0, image->getWidth(), image->getHeight(), -inputPitch, static_cast<const char*>(pixels) + inputSize - inputPitch, locked.Pitch, locked.pBits);
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +00001188 image->unlock();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001189 }
1190
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001191 image->markDirty();
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001192 mDirtyImages = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001193 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001194}
1195
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001196bool Texture::subImage(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, Image *image)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001197{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001198 if (width + xoffset > image->getWidth() || height + yoffset > image->getHeight())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001199 {
1200 error(GL_INVALID_VALUE);
1201 return false;
1202 }
1203
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001204 if (IsCompressed(image->getFormat()))
jbauman@chromium.orge2f954c2011-05-03 20:45:27 +00001205 {
1206 error(GL_INVALID_OPERATION);
1207 return false;
1208 }
1209
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001210 if (format != image->getFormat())
jbauman@chromium.orge2f954c2011-05-03 20:45:27 +00001211 {
1212 error(GL_INVALID_OPERATION);
1213 return false;
1214 }
1215
daniel@transgaming.com73de05a2011-11-09 17:45:24 +00001216 if (pixels != NULL)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001217 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001218 D3DLOCKED_RECT locked;
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +00001219 HRESULT result = image->lock(&locked, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001220
1221 if (SUCCEEDED(result))
1222 {
daniel@transgaming.com73de05a2011-11-09 17:45:24 +00001223 D3DSURFACE_DESC description;
1224 image->getSurface()->GetDesc(&description);
1225
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001226 loadImageData(xoffset, transformPixelYOffset(yoffset, height, image->getHeight()), width, height, format, type, unpackAlignment, pixels, locked.Pitch, locked.pBits, &description);
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +00001227 image->unlock();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001228 }
1229
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001230 image->markDirty();
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001231 mDirtyImages = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001232 }
1233
1234 return true;
1235}
1236
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001237bool Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, Image *image)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001238{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001239 if (width + xoffset > image->getWidth() || height + yoffset > image->getHeight())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001240 {
1241 error(GL_INVALID_VALUE);
1242 return false;
1243 }
1244
1245 if (format != getInternalFormat())
1246 {
1247 error(GL_INVALID_OPERATION);
1248 return false;
1249 }
1250
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +00001251 if (pixels != NULL)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001252 {
1253 RECT updateRegion;
1254 updateRegion.left = xoffset;
1255 updateRegion.right = xoffset + width;
1256 updateRegion.bottom = yoffset + height;
1257 updateRegion.top = yoffset;
1258
1259 D3DLOCKED_RECT locked;
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +00001260 HRESULT result = image->lock(&locked, &updateRegion);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001261
1262 if (SUCCEEDED(result))
1263 {
1264 int inputPitch = ComputeCompressedPitch(width, format);
1265 int inputSize = ComputeCompressedSize(width, height, format);
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001266 loadCompressedImageData(xoffset, transformPixelYOffset(yoffset, height, image->getHeight()), width, height, -inputPitch, static_cast<const char*>(pixels) + inputSize - inputPitch, locked.Pitch, locked.pBits);
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +00001267 image->unlock();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001268 }
1269
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001270 image->markDirty();
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001271 mDirtyImages = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001272 }
1273
1274 return true;
1275}
1276
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001277// This implements glCopyTex[Sub]Image2D for non-renderable internal texture formats and incomplete textures
1278void Texture::copyToImage(Image *image, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, IDirect3DSurface9 *renderTarget)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001279{
1280 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001281 IDirect3DSurface9 *renderTargetData = NULL;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001282 D3DSURFACE_DESC description;
1283 renderTarget->GetDesc(&description);
1284
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001285 HRESULT result = device->CreateOffscreenPlainSurface(description.Width, description.Height, description.Format, D3DPOOL_SYSTEMMEM, &renderTargetData, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001286
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001287 if (FAILED(result))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001288 {
1289 ERR("Could not create matching destination surface.");
1290 return error(GL_OUT_OF_MEMORY);
1291 }
1292
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001293 result = device->GetRenderTargetData(renderTarget, renderTargetData);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001294
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001295 if (FAILED(result))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001296 {
1297 ERR("GetRenderTargetData unexpectedly failed.");
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001298 renderTargetData->Release();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001299 return error(GL_OUT_OF_MEMORY);
1300 }
1301
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001302 RECT sourceRect = transformPixelRect(x, y, width, height, description.Height);
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001303 int destYOffset = transformPixelYOffset(yoffset, height, image->getHeight());
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001304 RECT destRect = {xoffset, destYOffset, xoffset + width, destYOffset + height};
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001305
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001306 if (image->isRenderable())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001307 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001308 result = D3DXLoadSurfaceFromSurface(image->getSurface(), NULL, &destRect, renderTargetData, NULL, &sourceRect, D3DX_FILTER_BOX, 0);
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001309
1310 if (FAILED(result))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001311 {
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001312 ERR("Copying surfaces unexpectedly failed.");
1313 renderTargetData->Release();
1314 return error(GL_OUT_OF_MEMORY);
1315 }
1316 }
1317 else
1318 {
1319 D3DLOCKED_RECT sourceLock = {0};
1320 result = renderTargetData->LockRect(&sourceLock, &sourceRect, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001321
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001322 if (FAILED(result))
1323 {
1324 ERR("Failed to lock the source surface (rectangle might be invalid).");
1325 renderTargetData->Release();
1326 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001327 }
1328
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001329 D3DLOCKED_RECT destLock = {0};
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +00001330 result = image->lock(&destLock, &destRect);
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001331
1332 if (FAILED(result))
1333 {
1334 ERR("Failed to lock the destination surface (rectangle might be invalid).");
1335 renderTargetData->UnlockRect();
1336 renderTargetData->Release();
1337 return error(GL_OUT_OF_MEMORY);
1338 }
1339
1340 if (destLock.pBits && sourceLock.pBits)
1341 {
1342 unsigned char *source = (unsigned char*)sourceLock.pBits;
1343 unsigned char *dest = (unsigned char*)destLock.pBits;
1344
1345 switch (description.Format)
1346 {
1347 case D3DFMT_X8R8G8B8:
1348 case D3DFMT_A8R8G8B8:
1349 switch(image->getD3DFormat())
1350 {
1351 case D3DFMT_L8:
1352 for(int y = 0; y < height; y++)
1353 {
1354 for(int x = 0; x < width; x++)
1355 {
1356 dest[x] = source[x * 4 + 2];
1357 }
1358
1359 source += sourceLock.Pitch;
1360 dest += destLock.Pitch;
1361 }
1362 break;
1363 case D3DFMT_A8L8:
1364 for(int y = 0; y < height; y++)
1365 {
1366 for(int x = 0; x < width; x++)
1367 {
1368 dest[x * 2 + 0] = source[x * 4 + 2];
1369 dest[x * 2 + 1] = source[x * 4 + 3];
1370 }
1371
1372 source += sourceLock.Pitch;
1373 dest += destLock.Pitch;
1374 }
1375 break;
1376 default:
1377 UNREACHABLE();
1378 }
1379 break;
1380 case D3DFMT_R5G6B5:
1381 switch(image->getD3DFormat())
1382 {
1383 case D3DFMT_L8:
1384 for(int y = 0; y < height; y++)
1385 {
1386 for(int x = 0; x < width; x++)
1387 {
1388 unsigned char red = source[x * 2 + 1] & 0xF8;
1389 dest[x] = red | (red >> 5);
1390 }
1391
1392 source += sourceLock.Pitch;
1393 dest += destLock.Pitch;
1394 }
1395 break;
1396 default:
1397 UNREACHABLE();
1398 }
1399 break;
1400 case D3DFMT_A1R5G5B5:
1401 switch(image->getD3DFormat())
1402 {
1403 case D3DFMT_L8:
1404 for(int y = 0; y < height; y++)
1405 {
1406 for(int x = 0; x < width; x++)
1407 {
1408 unsigned char red = source[x * 2 + 1] & 0x7C;
1409 dest[x] = (red << 1) | (red >> 4);
1410 }
1411
1412 source += sourceLock.Pitch;
1413 dest += destLock.Pitch;
1414 }
1415 break;
1416 case D3DFMT_A8L8:
1417 for(int y = 0; y < height; y++)
1418 {
1419 for(int x = 0; x < width; x++)
1420 {
1421 unsigned char red = source[x * 2 + 1] & 0x7C;
1422 dest[x * 2 + 0] = (red << 1) | (red >> 4);
1423 dest[x * 2 + 1] = (signed char)source[x * 2 + 1] >> 7;
1424 }
1425
1426 source += sourceLock.Pitch;
1427 dest += destLock.Pitch;
1428 }
1429 break;
1430 default:
1431 UNREACHABLE();
1432 }
1433 break;
1434 default:
1435 UNREACHABLE();
1436 }
1437 }
1438
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +00001439 image->unlock();
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001440 renderTargetData->UnlockRect();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001441 }
1442
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001443 renderTargetData->Release();
1444
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001445 image->markDirty();
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001446 mDirtyImages = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001447}
1448
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001449IDirect3DBaseTexture9 *Texture::getTexture()
1450{
1451 if (!isComplete())
1452 {
1453 return NULL;
1454 }
1455
daniel@transgaming.comaed18322011-03-21 16:38:13 +00001456 if (!getBaseTexture())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001457 {
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001458 createTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001459 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001460
daniel@transgaming.comc50edcb2011-03-21 16:38:40 +00001461 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001462
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001463 return getBaseTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001464}
1465
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001466bool Texture::hasDirtyParameters() const
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001467{
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001468 return mDirtyParameters;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00001469}
1470
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001471bool Texture::hasDirtyImages() const
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00001472{
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001473 return mDirtyImages;
daniel@transgaming.com38e76e52011-03-21 16:39:10 +00001474}
1475
1476void Texture::resetDirty()
1477{
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001478 mDirtyParameters = false;
1479 mDirtyImages = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001480}
1481
daniel@transgaming.coma9eb5da2011-03-21 16:39:16 +00001482unsigned int Texture::getSerial() const
1483{
1484 return mSerial;
1485}
1486
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001487GLint Texture::creationLevels(GLsizei width, GLsizei height, GLint maxlevel) const
1488{
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00001489 if ((isPow2(width) && isPow2(height)) || getContext()->supportsNonPower2Texture())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001490 {
1491 return maxlevel;
1492 }
1493 else
1494 {
1495 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
1496 return 1;
1497 }
1498}
1499
1500GLint Texture::creationLevels(GLsizei size, GLint maxlevel) const
1501{
1502 return creationLevels(size, size, maxlevel);
1503}
1504
1505int Texture::levelCount() const
1506{
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001507 return getBaseTexture() ? getBaseTexture()->GetLevelCount() : 0;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001508}
1509
daniel@transgaming.coma9eb5da2011-03-21 16:39:16 +00001510unsigned int Texture::issueSerial()
1511{
1512 return mCurrentSerial++;
1513}
1514
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001515Texture2D::Texture2D(GLuint id) : Texture(id)
1516{
1517 mTexture = NULL;
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001518 mSurface = NULL;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001519}
1520
1521Texture2D::~Texture2D()
1522{
1523 mColorbufferProxy.set(NULL);
1524
1525 if (mTexture)
1526 {
1527 mTexture->Release();
1528 mTexture = NULL;
1529 }
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001530
1531 if (mSurface)
1532 {
1533 mSurface->setBoundTexture(NULL);
1534 mSurface = NULL;
1535 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001536}
1537
1538GLenum Texture2D::getTarget() const
1539{
1540 return GL_TEXTURE_2D;
1541}
1542
daniel@transgaming.com61208202011-03-21 16:38:50 +00001543GLsizei Texture2D::getWidth() const
1544{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001545 return mImageArray[0].getWidth();
daniel@transgaming.com61208202011-03-21 16:38:50 +00001546}
1547
1548GLsizei Texture2D::getHeight() const
1549{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001550 return mImageArray[0].getHeight();
daniel@transgaming.com61208202011-03-21 16:38:50 +00001551}
1552
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001553GLenum Texture2D::getInternalFormat() const
1554{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001555 return mImageArray[0].getFormat();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001556}
1557
daniel@transgaming.com61208202011-03-21 16:38:50 +00001558GLenum Texture2D::getType() const
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001559{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001560 return mImageArray[0].getType();
daniel@transgaming.com61208202011-03-21 16:38:50 +00001561}
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001562
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001563D3DFORMAT Texture2D::getD3DFormat() const
1564{
1565 return mImageArray[0].getD3DFormat();
1566}
1567
daniel@transgaming.com68ae2992011-11-09 17:44:49 +00001568void Texture2D::redefineImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLenum type, bool forceRedefine)
daniel@transgaming.com61208202011-03-21 16:38:50 +00001569{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001570 GLsizei textureWidth = mImageArray[0].getWidth();
1571 GLsizei textureHeight = mImageArray[0].getHeight();
1572 GLenum textureFormat = mImageArray[0].getFormat();
1573 GLenum textureType = mImageArray[0].getType();
daniel@transgaming.com94a4f032011-03-21 16:38:55 +00001574
daniel@transgaming.com68ae2992011-11-09 17:44:49 +00001575 mImageArray[level].redefine(format, width, height, type);
daniel@transgaming.comc9ba4ad2011-11-09 17:44:35 +00001576
daniel@transgaming.com61208202011-03-21 16:38:50 +00001577 if (!mTexture)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001578 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001579 return;
1580 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001581
daniel@transgaming.com94a4f032011-03-21 16:38:55 +00001582 bool widthOkay = (textureWidth >> level == width) || (textureWidth >> level == 0 && width == 1);
1583 bool heightOkay = (textureHeight >> level == height) || (textureHeight >> level == 0 && height == 1);
1584 bool textureOkay = (widthOkay && heightOkay && textureFormat == format && textureType == type);
daniel@transgaming.com61208202011-03-21 16:38:50 +00001585
daniel@transgaming.comc9ba4ad2011-11-09 17:44:35 +00001586 if (!textureOkay || forceRedefine || mSurface)
daniel@transgaming.com61208202011-03-21 16:38:50 +00001587 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001588 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1589 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001590 mImageArray[i].markDirty();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001591 }
1592
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001593 mTexture->Release();
1594 mTexture = NULL;
1595 mDirtyImages = true;
1596 mIsRenderable = false;
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001597
1598 if (mSurface)
1599 {
1600 mSurface->setBoundTexture(NULL);
1601 mSurface = NULL;
1602 }
apatrick@chromium.org57a2cd62011-06-08 00:04:07 +00001603
1604 mColorbufferProxy.set(NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001605 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001606}
1607
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001608void Texture2D::setImage(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001609{
daniel@transgaming.com68ae2992011-11-09 17:44:49 +00001610 redefineImage(level, format, width, height, type, false);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001611
daniel@transgaming.com61208202011-03-21 16:38:50 +00001612 Texture::setImage(unpackAlignment, pixels, &mImageArray[level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001613}
1614
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001615void Texture2D::bindTexImage(egl::Surface *surface)
1616{
1617 GLenum format;
1618
1619 switch(surface->getFormat())
1620 {
1621 case D3DFMT_A8R8G8B8:
1622 format = GL_RGBA;
1623 break;
1624 case D3DFMT_X8R8G8B8:
1625 format = GL_RGB;
1626 break;
1627 default:
1628 UNIMPLEMENTED();
1629 return;
1630 }
1631
daniel@transgaming.com68ae2992011-11-09 17:44:49 +00001632 redefineImage(0, format, surface->getWidth(), surface->getHeight(), GL_UNSIGNED_BYTE, true);
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001633
1634 IDirect3DTexture9 *texture = surface->getOffscreenTexture();
1635
1636 mTexture = texture;
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001637 mDirtyImages = true;
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001638 mIsRenderable = true;
1639 mSurface = surface;
1640 mSurface->setBoundTexture(this);
1641}
1642
1643void Texture2D::releaseTexImage()
1644{
daniel@transgaming.com68ae2992011-11-09 17:44:49 +00001645 redefineImage(0, GL_RGB, 0, 0, GL_UNSIGNED_BYTE, true);
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001646}
1647
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001648void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001649{
daniel@transgaming.com68ae2992011-11-09 17:44:49 +00001650 redefineImage(level, format, width, height, GL_UNSIGNED_BYTE, false);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001651
daniel@transgaming.com61208202011-03-21 16:38:50 +00001652 Texture::setCompressedImage(imageSize, pixels, &mImageArray[level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001653}
1654
1655void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1656{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001657 ASSERT(mImageArray[level].getSurface() != NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001658
1659 if (level < levelCount())
1660 {
1661 IDirect3DSurface9 *destLevel = NULL;
1662 HRESULT result = mTexture->GetSurfaceLevel(level, &destLevel);
1663
1664 ASSERT(SUCCEEDED(result));
1665
1666 if (SUCCEEDED(result))
1667 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001668 Image *image = &mImageArray[level];
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001669
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001670 RECT sourceRect = transformPixelRect(xoffset, yoffset, width, height, image->getHeight());;
daniel@transgaming.comb612f882011-11-09 17:44:31 +00001671 POINT destPoint = {sourceRect.left, sourceRect.top};
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001672
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001673 result = getDevice()->UpdateSurface(image->getSurface(), &sourceRect, destLevel, &destPoint);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001674 ASSERT(SUCCEEDED(result));
1675
1676 destLevel->Release();
1677
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001678 image->markClean();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001679 }
1680 }
1681}
1682
1683void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1684{
1685 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[level]))
1686 {
1687 commitRect(level, xoffset, yoffset, width, height);
1688 }
1689}
1690
1691void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1692{
1693 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[level]))
1694 {
1695 commitRect(level, xoffset, yoffset, width, height);
1696 }
1697}
1698
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001699void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001700{
1701 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
1702
1703 if (!renderTarget)
1704 {
1705 ERR("Failed to retrieve the render target.");
1706 return error(GL_OUT_OF_MEMORY);
1707 }
1708
daniel@transgaming.com68ae2992011-11-09 17:44:49 +00001709 redefineImage(level, format, width, height, GL_UNSIGNED_BYTE, false);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001710
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001711 if (!mImageArray[level].isRenderable())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001712 {
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001713 copyToImage(&mImageArray[level], 0, 0, x, y, width, height, renderTarget);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001714 }
1715 else
1716 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001717 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001718 {
1719 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001720 }
daniel@transgaming.com3b3c1d42011-06-08 20:38:09 +00001721
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001722 mImageArray[level].markClean();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001723
1724 if (width != 0 && height != 0 && level < levelCount())
1725 {
1726 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
1727 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
1728 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
1729 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
1730 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
daniel@transgaming.comeef864a2011-04-22 11:33:27 +00001731
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001732 GLint destYOffset = transformPixelYOffset(0, height, mImageArray[level].getHeight());
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001733
1734 IDirect3DSurface9 *dest;
1735 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
1736
daniel@transgaming.comeef864a2011-04-22 11:33:27 +00001737 getBlitter()->copy(source->getRenderTarget(), sourceRect, format, 0, destYOffset, dest);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001738 dest->Release();
1739 }
1740 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001741}
1742
1743void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1744{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001745 if (xoffset + width > mImageArray[level].getWidth() || yoffset + height > mImageArray[level].getHeight())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001746 {
1747 return error(GL_INVALID_VALUE);
1748 }
1749
1750 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
1751
1752 if (!renderTarget)
1753 {
1754 ERR("Failed to retrieve the render target.");
1755 return error(GL_OUT_OF_MEMORY);
1756 }
1757
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001758 if (!mImageArray[level].isRenderable() || (!mTexture && !isComplete()))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001759 {
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001760 copyToImage(&mImageArray[level], xoffset, yoffset, x, y, width, height, renderTarget);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001761 }
1762 else
1763 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001764 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001765 {
1766 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001767 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00001768
1769 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001770
1771 if (level < levelCount())
1772 {
1773 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
1774 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
1775 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
1776 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
1777 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
1778
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001779 GLint destYOffset = transformPixelYOffset(yoffset, height, mImageArray[level].getHeight());
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001780
1781 IDirect3DSurface9 *dest;
1782 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
1783
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001784 getBlitter()->copy(source->getRenderTarget(), sourceRect, mImageArray[0].getFormat(), xoffset, destYOffset, dest);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001785 dest->Release();
1786 }
1787 }
1788}
1789
1790// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1791bool Texture2D::isComplete() const
1792{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001793 GLsizei width = mImageArray[0].getWidth();
1794 GLsizei height = mImageArray[0].getHeight();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001795
1796 if (width <= 0 || height <= 0)
1797 {
1798 return false;
1799 }
1800
1801 bool mipmapping = false;
1802
1803 switch (mMinFilter)
1804 {
1805 case GL_NEAREST:
1806 case GL_LINEAR:
1807 mipmapping = false;
1808 break;
1809 case GL_NEAREST_MIPMAP_NEAREST:
1810 case GL_LINEAR_MIPMAP_NEAREST:
1811 case GL_NEAREST_MIPMAP_LINEAR:
1812 case GL_LINEAR_MIPMAP_LINEAR:
1813 mipmapping = true;
1814 break;
1815 default: UNREACHABLE();
1816 }
1817
1818 if ((getInternalFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) ||
1819 (getInternalFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter()))
1820 {
1821 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
1822 {
1823 return false;
1824 }
1825 }
1826
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00001827 bool npot = getContext()->supportsNonPower2Texture();
1828
1829 if (!npot)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001830 {
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00001831 if ((getWrapS() != GL_CLAMP_TO_EDGE && !isPow2(width)) ||
1832 (getWrapT() != GL_CLAMP_TO_EDGE && !isPow2(height)))
1833 {
1834 return false;
1835 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001836 }
1837
1838 if (mipmapping)
1839 {
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00001840 if (!npot)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001841 {
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00001842 if (!isPow2(width) || !isPow2(height))
1843 {
1844 return false;
1845 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001846 }
1847
1848 int q = log2(std::max(width, height));
1849
1850 for (int level = 1; level <= q; level++)
1851 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001852 if (mImageArray[level].getFormat() != mImageArray[0].getFormat())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001853 {
1854 return false;
1855 }
1856
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001857 if (mImageArray[level].getType() != mImageArray[0].getType())
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00001858 {
1859 return false;
1860 }
1861
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001862 if (mImageArray[level].getWidth() != std::max(1, width >> level))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001863 {
1864 return false;
1865 }
1866
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001867 if (mImageArray[level].getHeight() != std::max(1, height >> level))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001868 {
1869 return false;
1870 }
1871 }
1872 }
1873
1874 return true;
1875}
1876
1877bool Texture2D::isCompressed() const
1878{
1879 return IsCompressed(getInternalFormat());
1880}
1881
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001882IDirect3DBaseTexture9 *Texture2D::getBaseTexture() const
1883{
1884 return mTexture;
1885}
1886
1887// Constructs a Direct3D 9 texture resource from the texture images
1888void Texture2D::createTexture()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001889{
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001890 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001891 D3DFORMAT format = mImageArray[0].getD3DFormat();
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001892 GLint levels = creationLevels(mImageArray[0].getWidth(), mImageArray[0].getHeight(), 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001893
daniel@transgaming.com61208202011-03-21 16:38:50 +00001894 IDirect3DTexture9 *texture = NULL;
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001895 HRESULT result = device->CreateTexture(mImageArray[0].getWidth(), mImageArray[0].getHeight(), levels, 0, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001896
1897 if (FAILED(result))
1898 {
1899 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001900 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001901 }
1902
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001903 if (mTexture)
1904 {
1905 mTexture->Release();
1906 }
1907
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001908 mTexture = texture;
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001909 mDirtyImages = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00001910 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001911}
1912
1913void Texture2D::updateTexture()
1914{
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001915 int levels = levelCount();
1916
1917 for (int level = 0; level < levels; level++)
1918 {
daniel@transgaming.comb612f882011-11-09 17:44:31 +00001919 Image *image = &mImageArray[level];
1920
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +00001921 if (image->isDirty())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001922 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001923 commitRect(level, 0, 0, mImageArray[level].getWidth(), mImageArray[level].getHeight());
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001924 }
1925 }
1926}
1927
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001928void Texture2D::convertToRenderTarget()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001929{
1930 IDirect3DTexture9 *texture = NULL;
1931
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001932 if (mImageArray[0].getWidth() != 0 && mImageArray[0].getHeight() != 0)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001933 {
1934 egl::Display *display = getDisplay();
1935 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001936 D3DFORMAT format = mImageArray[0].getD3DFormat();
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001937 GLint levels = creationLevels(mImageArray[0].getWidth(), mImageArray[0].getHeight(), 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001938
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001939 HRESULT result = device->CreateTexture(mImageArray[0].getWidth(), mImageArray[0].getHeight(), levels, D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001940
1941 if (FAILED(result))
1942 {
1943 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001944 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001945 }
1946
1947 if (mTexture != NULL)
1948 {
1949 int levels = levelCount();
1950 for (int i = 0; i < levels; i++)
1951 {
1952 IDirect3DSurface9 *source;
1953 result = mTexture->GetSurfaceLevel(i, &source);
1954
1955 if (FAILED(result))
1956 {
1957 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1958
1959 texture->Release();
1960
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001961 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001962 }
1963
1964 IDirect3DSurface9 *dest;
1965 result = texture->GetSurfaceLevel(i, &dest);
1966
1967 if (FAILED(result))
1968 {
1969 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1970
1971 texture->Release();
1972 source->Release();
1973
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001974 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001975 }
1976
1977 display->endScene();
1978 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
1979
1980 if (FAILED(result))
1981 {
1982 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1983
1984 texture->Release();
1985 source->Release();
1986 dest->Release();
1987
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001988 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001989 }
1990
1991 source->Release();
1992 dest->Release();
1993 }
1994 }
1995 }
1996
1997 if (mTexture != NULL)
1998 {
1999 mTexture->Release();
2000 }
2001
2002 mTexture = texture;
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00002003 mDirtyImages = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00002004 mIsRenderable = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002005}
2006
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002007void Texture2D::generateMipmaps()
2008{
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00002009 if (!getContext()->supportsNonPower2Texture())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002010 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002011 if (!isPow2(mImageArray[0].getWidth()) || !isPow2(mImageArray[0].getHeight()))
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00002012 {
2013 return error(GL_INVALID_OPERATION);
2014 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002015 }
2016
2017 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002018 unsigned int q = log2(std::max(mImageArray[0].getWidth(), mImageArray[0].getHeight()));
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002019 for (unsigned int i = 1; i <= q; i++)
2020 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002021 mImageArray[i].redefine(mImageArray[0].getFormat(),
2022 std::max(mImageArray[0].getWidth() >> i, 1),
2023 std::max(mImageArray[0].getHeight() >> i, 1),
2024 mImageArray[0].getType());
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002025 }
2026
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002027 if (mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002028 {
2029 if (mTexture == NULL)
2030 {
2031 ERR(" failed because mTexture was null.");
2032 return;
2033 }
2034
2035 for (unsigned int i = 1; i <= q; i++)
2036 {
2037 IDirect3DSurface9 *upper = NULL;
2038 IDirect3DSurface9 *lower = NULL;
2039
2040 mTexture->GetSurfaceLevel(i-1, &upper);
2041 mTexture->GetSurfaceLevel(i, &lower);
2042
2043 if (upper != NULL && lower != NULL)
2044 {
2045 getBlitter()->boxFilter(upper, lower);
2046 }
2047
2048 if (upper != NULL) upper->Release();
2049 if (lower != NULL) lower->Release();
daniel@transgaming.com61208202011-03-21 16:38:50 +00002050
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002051 mImageArray[i].markClean();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002052 }
2053 }
2054 else
2055 {
2056 for (unsigned int i = 1; i <= q; i++)
2057 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002058 if (mImageArray[i].getSurface() == NULL)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002059 {
2060 return error(GL_OUT_OF_MEMORY);
2061 }
2062
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002063 if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[i].getSurface(), NULL, NULL, mImageArray[i - 1].getSurface(), NULL, NULL, D3DX_FILTER_BOX, 0)))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002064 {
2065 ERR(" failed to load filter %d to %d.", i - 1, i);
2066 }
2067
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002068 mImageArray[i].markDirty();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002069 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002070 }
2071}
2072
2073Renderbuffer *Texture2D::getRenderbuffer(GLenum target)
2074{
2075 if (target != GL_TEXTURE_2D)
2076 {
2077 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
2078 }
2079
2080 if (mColorbufferProxy.get() == NULL)
2081 {
2082 mColorbufferProxy.set(new Renderbuffer(id(), new Colorbuffer(this, target)));
2083 }
2084
2085 return mColorbufferProxy.get();
2086}
2087
2088IDirect3DSurface9 *Texture2D::getRenderTarget(GLenum target)
2089{
2090 ASSERT(target == GL_TEXTURE_2D);
2091
daniel@transgaming.com61208202011-03-21 16:38:50 +00002092 if (!mIsRenderable)
2093 {
2094 convertToRenderTarget();
2095 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002096
2097 if (mTexture == NULL)
2098 {
2099 return NULL;
2100 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00002101
2102 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002103
2104 IDirect3DSurface9 *renderTarget = NULL;
2105 mTexture->GetSurfaceLevel(0, &renderTarget);
2106
2107 return renderTarget;
2108}
2109
2110TextureCubeMap::TextureCubeMap(GLuint id) : Texture(id)
2111{
2112 mTexture = NULL;
2113}
2114
2115TextureCubeMap::~TextureCubeMap()
2116{
2117 for (int i = 0; i < 6; i++)
2118 {
2119 mFaceProxies[i].set(NULL);
2120 }
2121
2122 if (mTexture)
2123 {
2124 mTexture->Release();
2125 mTexture = NULL;
2126 }
2127}
2128
2129GLenum TextureCubeMap::getTarget() const
2130{
2131 return GL_TEXTURE_CUBE_MAP;
2132}
2133
daniel@transgaming.com61208202011-03-21 16:38:50 +00002134GLsizei TextureCubeMap::getWidth() const
2135{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002136 return mImageArray[0][0].getWidth();
daniel@transgaming.com61208202011-03-21 16:38:50 +00002137}
2138
2139GLsizei TextureCubeMap::getHeight() const
2140{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002141 return mImageArray[0][0].getHeight();
daniel@transgaming.com61208202011-03-21 16:38:50 +00002142}
2143
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002144GLenum TextureCubeMap::getInternalFormat() const
2145{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002146 return mImageArray[0][0].getFormat();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002147}
2148
daniel@transgaming.com61208202011-03-21 16:38:50 +00002149GLenum TextureCubeMap::getType() const
2150{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002151 return mImageArray[0][0].getType();
daniel@transgaming.com61208202011-03-21 16:38:50 +00002152}
2153
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002154D3DFORMAT TextureCubeMap::getD3DFormat() const
2155{
2156 return mImageArray[0][0].getD3DFormat();
2157}
2158
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002159void TextureCubeMap::setImagePosX(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002160{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002161 setImage(0, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002162}
2163
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002164void TextureCubeMap::setImageNegX(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002165{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002166 setImage(1, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002167}
2168
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002169void TextureCubeMap::setImagePosY(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002170{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002171 setImage(2, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002172}
2173
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002174void TextureCubeMap::setImageNegY(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002175{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002176 setImage(3, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002177}
2178
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002179void TextureCubeMap::setImagePosZ(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002180{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002181 setImage(4, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002182}
2183
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002184void TextureCubeMap::setImageNegZ(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002185{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002186 setImage(5, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002187}
2188
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002189void TextureCubeMap::setCompressedImage(GLenum face, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002190{
daniel@transgaming.com68ae2992011-11-09 17:44:49 +00002191 redefineImage(faceIndex(face), level, format, width, height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002192
daniel@transgaming.com61208202011-03-21 16:38:50 +00002193 Texture::setCompressedImage(imageSize, pixels, &mImageArray[faceIndex(face)][level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002194}
2195
daniel@transgaming.comb612f882011-11-09 17:44:31 +00002196void TextureCubeMap::commitRect(int face, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002197{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002198 ASSERT(mImageArray[face][level].getSurface() != NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002199
2200 if (level < levelCount())
2201 {
daniel@transgaming.comb612f882011-11-09 17:44:31 +00002202 IDirect3DSurface9 *destLevel = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002203 ASSERT(destLevel != NULL);
2204
2205 if (destLevel != NULL)
2206 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00002207 Image *image = &mImageArray[face][level];
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002208
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002209 RECT sourceRect = transformPixelRect(xoffset, yoffset, width, height, image->getHeight());;
daniel@transgaming.comb612f882011-11-09 17:44:31 +00002210 POINT destPoint = {sourceRect.left, sourceRect.top};
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002211
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002212 HRESULT result = getDevice()->UpdateSurface(image->getSurface(), &sourceRect, destLevel, &destPoint);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002213 ASSERT(SUCCEEDED(result));
2214
2215 destLevel->Release();
2216
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002217 image->markClean();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002218 }
2219 }
2220}
2221
2222void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
2223{
2224 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[faceIndex(target)][level]))
2225 {
daniel@transgaming.comb612f882011-11-09 17:44:31 +00002226 commitRect(faceIndex(target), level, xoffset, yoffset, width, height);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002227 }
2228}
2229
2230void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
2231{
2232 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[faceIndex(target)][level]))
2233 {
daniel@transgaming.comb612f882011-11-09 17:44:31 +00002234 commitRect(faceIndex(target), level, xoffset, yoffset, width, height);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002235 }
2236}
2237
2238// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
2239bool TextureCubeMap::isComplete() const
2240{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002241 int size = mImageArray[0][0].getWidth();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002242
2243 if (size <= 0)
2244 {
2245 return false;
2246 }
2247
2248 bool mipmapping;
2249
2250 switch (mMinFilter)
2251 {
2252 case GL_NEAREST:
2253 case GL_LINEAR:
2254 mipmapping = false;
2255 break;
2256 case GL_NEAREST_MIPMAP_NEAREST:
2257 case GL_LINEAR_MIPMAP_NEAREST:
2258 case GL_NEAREST_MIPMAP_LINEAR:
2259 case GL_LINEAR_MIPMAP_LINEAR:
2260 mipmapping = true;
2261 break;
2262 default: UNREACHABLE();
2263 }
2264
2265 for (int face = 0; face < 6; face++)
2266 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002267 if (mImageArray[face][0].getWidth() != size || mImageArray[face][0].getHeight() != size)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002268 {
2269 return false;
2270 }
2271 }
2272
2273 if ((getInternalFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) ||
2274 (getInternalFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter()))
2275 {
2276 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
2277 {
2278 return false;
2279 }
2280 }
2281
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00002282 bool npot = getContext()->supportsNonPower2Texture();
2283
2284 if (!npot)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002285 {
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00002286 if ((getWrapS() != GL_CLAMP_TO_EDGE || getWrapT() != GL_CLAMP_TO_EDGE) && !isPow2(size))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002287 {
2288 return false;
2289 }
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00002290 }
2291
2292 if (mipmapping)
2293 {
2294 if (!npot)
2295 {
2296 if (!isPow2(size))
2297 {
2298 return false;
2299 }
2300 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002301
2302 int q = log2(size);
2303
2304 for (int face = 0; face < 6; face++)
2305 {
2306 for (int level = 1; level <= q; level++)
2307 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002308 if (mImageArray[face][level].getFormat() != mImageArray[0][0].getFormat())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002309 {
2310 return false;
2311 }
2312
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002313 if (mImageArray[face][level].getType() != mImageArray[0][0].getType())
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00002314 {
2315 return false;
2316 }
2317
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002318 if (mImageArray[face][level].getWidth() != std::max(1, size >> level))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002319 {
2320 return false;
2321 }
2322
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002323 ASSERT(mImageArray[face][level].getHeight() == mImageArray[face][level].getWidth());
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002324 }
2325 }
2326 }
2327
2328 return true;
2329}
2330
2331bool TextureCubeMap::isCompressed() const
2332{
2333 return IsCompressed(getInternalFormat());
2334}
2335
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002336IDirect3DBaseTexture9 *TextureCubeMap::getBaseTexture() const
2337{
2338 return mTexture;
2339}
2340
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002341// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002342void TextureCubeMap::createTexture()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002343{
2344 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002345 D3DFORMAT format = mImageArray[0][0].getD3DFormat();
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002346 GLint levels = creationLevels(mImageArray[0][0].getWidth(), 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002347
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00002348 IDirect3DCubeTexture9 *texture = NULL;
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002349 HRESULT result = device->CreateCubeTexture(mImageArray[0][0].getWidth(), levels, 0, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002350
2351 if (FAILED(result))
2352 {
2353 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002354 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002355 }
2356
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002357 if (mTexture)
2358 {
2359 mTexture->Release();
2360 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002361
2362 mTexture = texture;
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00002363 mDirtyImages = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00002364 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002365}
2366
2367void TextureCubeMap::updateTexture()
2368{
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002369 for (int face = 0; face < 6; face++)
2370 {
2371 int levels = levelCount();
2372 for (int level = 0; level < levels; level++)
2373 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00002374 Image *image = &mImageArray[face][level];
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002375
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +00002376 if (image->isDirty())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002377 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002378 commitRect(face, level, 0, 0, image->getWidth(), image->getHeight());
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002379 }
2380 }
2381 }
2382}
2383
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002384void TextureCubeMap::convertToRenderTarget()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002385{
2386 IDirect3DCubeTexture9 *texture = NULL;
2387
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002388 if (mImageArray[0][0].getWidth() != 0)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002389 {
2390 egl::Display *display = getDisplay();
2391 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002392 D3DFORMAT format = mImageArray[0][0].getD3DFormat();
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002393 GLint levels = creationLevels(mImageArray[0][0].getWidth(), 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002394
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002395 HRESULT result = device->CreateCubeTexture(mImageArray[0][0].getWidth(), levels, D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002396
2397 if (FAILED(result))
2398 {
2399 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002400 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002401 }
2402
2403 if (mTexture != NULL)
2404 {
2405 int levels = levelCount();
2406 for (int f = 0; f < 6; f++)
2407 {
2408 for (int i = 0; i < levels; i++)
2409 {
2410 IDirect3DSurface9 *source;
2411 result = mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &source);
2412
2413 if (FAILED(result))
2414 {
2415 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2416
2417 texture->Release();
2418
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002419 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002420 }
2421
2422 IDirect3DSurface9 *dest;
2423 result = texture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &dest);
2424
2425 if (FAILED(result))
2426 {
2427 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2428
2429 texture->Release();
2430 source->Release();
2431
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002432 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002433 }
2434
2435 display->endScene();
2436 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
2437
2438 if (FAILED(result))
2439 {
2440 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2441
2442 texture->Release();
2443 source->Release();
2444 dest->Release();
2445
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002446 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002447 }
daniel@transgaming.coma1a86202011-08-09 13:41:08 +00002448
2449 source->Release();
2450 dest->Release();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002451 }
2452 }
2453 }
2454 }
2455
2456 if (mTexture != NULL)
2457 {
2458 mTexture->Release();
2459 }
2460
2461 mTexture = texture;
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00002462 mDirtyImages = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00002463 mIsRenderable = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002464}
2465
daniel@transgaming.com61208202011-03-21 16:38:50 +00002466void TextureCubeMap::setImage(int faceIndex, GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002467{
daniel@transgaming.com68ae2992011-11-09 17:44:49 +00002468 redefineImage(faceIndex, level, format, width, height, type);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002469
daniel@transgaming.com61208202011-03-21 16:38:50 +00002470 Texture::setImage(unpackAlignment, pixels, &mImageArray[faceIndex][level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002471}
2472
2473unsigned int TextureCubeMap::faceIndex(GLenum face)
2474{
2475 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
2476 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
2477 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
2478 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
2479 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
2480
2481 return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
2482}
2483
daniel@transgaming.com68ae2992011-11-09 17:44:49 +00002484void TextureCubeMap::redefineImage(int face, GLint level, GLenum format, GLsizei width, GLsizei height, GLenum type)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002485{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002486 GLsizei textureWidth = mImageArray[0][0].getWidth();
2487 GLsizei textureHeight = mImageArray[0][0].getHeight();
2488 GLenum textureFormat = mImageArray[0][0].getFormat();
2489 GLenum textureType = mImageArray[0][0].getType();
daniel@transgaming.com94a4f032011-03-21 16:38:55 +00002490
daniel@transgaming.com68ae2992011-11-09 17:44:49 +00002491 mImageArray[face][level].redefine(format, width, height, type);
daniel@transgaming.comc9ba4ad2011-11-09 17:44:35 +00002492
daniel@transgaming.com61208202011-03-21 16:38:50 +00002493 if (!mTexture)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002494 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00002495 return;
2496 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002497
daniel@transgaming.com94a4f032011-03-21 16:38:55 +00002498 bool sizeOkay = (textureWidth >> level == width);
2499 bool textureOkay = (sizeOkay && textureFormat == format && textureType == type);
daniel@transgaming.com61208202011-03-21 16:38:50 +00002500
daniel@transgaming.comc9ba4ad2011-11-09 17:44:35 +00002501 if (!textureOkay)
daniel@transgaming.com61208202011-03-21 16:38:50 +00002502 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002503 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
2504 {
2505 for (int f = 0; f < 6; f++)
2506 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002507 mImageArray[f][i].markDirty();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002508 }
2509 }
2510
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00002511 mTexture->Release();
2512 mTexture = NULL;
2513 mDirtyImages = true;
2514 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002515 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002516}
2517
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002518void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002519{
2520 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
2521
2522 if (!renderTarget)
2523 {
2524 ERR("Failed to retrieve the render target.");
2525 return error(GL_OUT_OF_MEMORY);
2526 }
2527
2528 unsigned int faceindex = faceIndex(target);
daniel@transgaming.com68ae2992011-11-09 17:44:49 +00002529 redefineImage(faceindex, level, format, width, height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002530
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002531 if (!mImageArray[faceindex][level].isRenderable())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002532 {
daniel@transgaming.comb6276992011-03-29 00:58:18 +00002533 copyToImage(&mImageArray[faceindex][level], 0, 0, x, y, width, height, renderTarget);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002534 }
2535 else
2536 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00002537 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002538 {
2539 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002540 }
daniel@transgaming.com3b3c1d42011-06-08 20:38:09 +00002541
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002542 mImageArray[faceindex][level].markClean();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002543
2544 ASSERT(width == height);
2545
2546 if (width > 0 && level < levelCount())
2547 {
2548 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
2549 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
2550 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
2551 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
2552 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
2553
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002554 GLint destYOffset = transformPixelYOffset(0, height, mImageArray[faceindex][level].getWidth());
daniel@transgaming.comeef864a2011-04-22 11:33:27 +00002555
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002556 IDirect3DSurface9 *dest = getCubeMapSurface(target, level);
2557
daniel@transgaming.comeef864a2011-04-22 11:33:27 +00002558 getBlitter()->copy(source->getRenderTarget(), sourceRect, format, 0, destYOffset, dest);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002559 dest->Release();
2560 }
2561 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002562}
2563
daniel@transgaming.comb612f882011-11-09 17:44:31 +00002564IDirect3DSurface9 *TextureCubeMap::getCubeMapSurface(GLenum target, unsigned int level)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002565{
2566 if (mTexture == NULL)
2567 {
2568 UNREACHABLE();
2569 return NULL;
2570 }
2571
2572 IDirect3DSurface9 *surface = NULL;
2573
daniel@transgaming.comb612f882011-11-09 17:44:31 +00002574 HRESULT hr = mTexture->GetCubeMapSurface(es2dx::ConvertCubeFace(target), level, &surface);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002575
2576 return (SUCCEEDED(hr)) ? surface : NULL;
2577}
2578
2579void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
2580{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002581 GLsizei size = mImageArray[faceIndex(target)][level].getWidth();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002582
2583 if (xoffset + width > size || yoffset + height > size)
2584 {
2585 return error(GL_INVALID_VALUE);
2586 }
2587
2588 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
2589
2590 if (!renderTarget)
2591 {
2592 ERR("Failed to retrieve the render target.");
2593 return error(GL_OUT_OF_MEMORY);
2594 }
2595
2596 unsigned int faceindex = faceIndex(target);
daniel@transgaming.com01dae852011-11-09 17:44:53 +00002597
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002598 if (!mImageArray[faceindex][level].isRenderable() || (!mTexture && !isComplete()))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002599 {
daniel@transgaming.comb6276992011-03-29 00:58:18 +00002600 copyToImage(&mImageArray[faceindex][level], 0, 0, x, y, width, height, renderTarget);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002601 }
2602 else
2603 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00002604 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002605 {
2606 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002607 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00002608
2609 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002610
2611 if (level < levelCount())
2612 {
2613 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
2614 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
2615 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
2616 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
2617 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
2618
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002619 GLint destYOffset = transformPixelYOffset(yoffset, height, mImageArray[faceindex][level].getWidth());
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002620
2621 IDirect3DSurface9 *dest = getCubeMapSurface(target, level);
2622
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002623 getBlitter()->copy(source->getRenderTarget(), sourceRect, mImageArray[0][0].getFormat(), xoffset, destYOffset, dest);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002624 dest->Release();
2625 }
2626 }
2627}
2628
2629bool TextureCubeMap::isCubeComplete() const
2630{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002631 if (mImageArray[0][0].getWidth() == 0)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002632 {
2633 return false;
2634 }
2635
2636 for (unsigned int f = 1; f < 6; f++)
2637 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002638 if (mImageArray[f][0].getWidth() != mImageArray[0][0].getWidth()
2639 || mImageArray[f][0].getFormat() != mImageArray[0][0].getFormat())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002640 {
2641 return false;
2642 }
2643 }
2644
2645 return true;
2646}
2647
2648void TextureCubeMap::generateMipmaps()
2649{
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00002650 if (!isCubeComplete())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002651 {
2652 return error(GL_INVALID_OPERATION);
2653 }
2654
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00002655 if (!getContext()->supportsNonPower2Texture())
2656 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002657 if (!isPow2(mImageArray[0][0].getWidth()))
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00002658 {
2659 return error(GL_INVALID_OPERATION);
2660 }
2661 }
2662
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002663 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002664 unsigned int q = log2(mImageArray[0][0].getWidth());
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002665 for (unsigned int f = 0; f < 6; f++)
2666 {
2667 for (unsigned int i = 1; i <= q; i++)
2668 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002669 mImageArray[f][i].redefine(mImageArray[f][0].getFormat(),
2670 std::max(mImageArray[f][0].getWidth() >> i, 1),
2671 std::max(mImageArray[f][0].getWidth() >> i, 1),
2672 mImageArray[f][0].getType());
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002673 }
2674 }
2675
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002676 if (mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002677 {
2678 if (mTexture == NULL)
2679 {
2680 return;
2681 }
2682
2683 for (unsigned int f = 0; f < 6; f++)
2684 {
2685 for (unsigned int i = 1; i <= q; i++)
2686 {
2687 IDirect3DSurface9 *upper = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i-1);
2688 IDirect3DSurface9 *lower = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i);
2689
2690 if (upper != NULL && lower != NULL)
2691 {
2692 getBlitter()->boxFilter(upper, lower);
2693 }
2694
2695 if (upper != NULL) upper->Release();
2696 if (lower != NULL) lower->Release();
daniel@transgaming.com61208202011-03-21 16:38:50 +00002697
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002698 mImageArray[f][i].markClean();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002699 }
2700 }
2701 }
2702 else
2703 {
2704 for (unsigned int f = 0; f < 6; f++)
2705 {
2706 for (unsigned int i = 1; i <= q; i++)
2707 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002708 if (mImageArray[f][i].getSurface() == NULL)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002709 {
2710 return error(GL_OUT_OF_MEMORY);
2711 }
2712
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002713 if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[f][i].getSurface(), NULL, NULL, mImageArray[f][i - 1].getSurface(), NULL, NULL, D3DX_FILTER_BOX, 0)))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002714 {
2715 ERR(" failed to load filter %d to %d.", i - 1, i);
2716 }
2717
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002718 mImageArray[f][i].markDirty();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002719 }
2720 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002721 }
2722}
2723
2724Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target)
2725{
2726 if (!IsCubemapTextureTarget(target))
2727 {
2728 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
2729 }
2730
2731 unsigned int face = faceIndex(target);
2732
2733 if (mFaceProxies[face].get() == NULL)
2734 {
2735 mFaceProxies[face].set(new Renderbuffer(id(), new Colorbuffer(this, target)));
2736 }
2737
2738 return mFaceProxies[face].get();
2739}
2740
2741IDirect3DSurface9 *TextureCubeMap::getRenderTarget(GLenum target)
2742{
2743 ASSERT(IsCubemapTextureTarget(target));
2744
daniel@transgaming.com61208202011-03-21 16:38:50 +00002745 if (!mIsRenderable)
2746 {
2747 convertToRenderTarget();
2748 }
2749
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002750 if (mTexture == NULL)
2751 {
2752 return NULL;
2753 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00002754
2755 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002756
2757 IDirect3DSurface9 *renderTarget = NULL;
2758 mTexture->GetCubeMapSurface(es2dx::ConvertCubeFace(target), 0, &renderTarget);
2759
2760 return renderTarget;
2761}
2762
daniel@transgaming.comb612f882011-11-09 17:44:31 +00002763}