blob: f7931f2495556718b4d891ec2483371c43f1bd8f [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>
16
17#include "common/debug.h"
18
jbauman@chromium.orgae345802011-03-30 22:04:25 +000019#include "libEGL/Display.h"
20
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +000021#include "libGLESv2/main.h"
22#include "libGLESv2/mathutil.h"
23#include "libGLESv2/utilities.h"
24#include "libGLESv2/Blit.h"
25#include "libGLESv2/Framebuffer.h"
26
27namespace gl
28{
daniel@transgaming.coma9eb5da2011-03-21 16:39:16 +000029unsigned int Texture::mCurrentSerial = 1;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +000030
31Texture::Image::Image()
daniel@transgaming.comc50edcb2011-03-21 16:38:40 +000032 : width(0), height(0), dirty(false), surface(NULL), format(GL_NONE), type(GL_UNSIGNED_BYTE)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +000033{
34}
35
36Texture::Image::~Image()
37{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +000038 if (surface)
39 {
40 surface->Release();
41 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +000042}
43
daniel@transgaming.com549bdef2011-03-29 00:57:01 +000044bool Texture::Image::isRenderable() const
45{
46 switch(getD3DFormat())
47 {
48 case D3DFMT_L8:
49 case D3DFMT_A8L8:
50 case D3DFMT_DXT1:
51 return false;
52 case D3DFMT_A8R8G8B8:
53 case D3DFMT_X8R8G8B8:
54 case D3DFMT_A16B16G16R16F:
55 case D3DFMT_A32B32G32R32F:
56 return true;
57 default:
58 UNREACHABLE();
59 }
60
61 return false;
62}
63
64D3DFORMAT Texture::Image::getD3DFormat() const
65{
66 if (format == GL_COMPRESSED_RGB_S3TC_DXT1_EXT ||
67 format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT)
68 {
69 return D3DFMT_DXT1;
70 }
71 else if (type == GL_FLOAT)
72 {
73 return D3DFMT_A32B32G32R32F;
74 }
75 else if (type == GL_HALF_FLOAT_OES)
76 {
77 return D3DFMT_A16B16G16R16F;
78 }
79 else if (type == GL_UNSIGNED_BYTE)
80 {
81 if (format == GL_LUMINANCE && getContext()->supportsLuminanceTextures())
82 {
83 return D3DFMT_L8;
84 }
85 else if (format == GL_LUMINANCE_ALPHA && getContext()->supportsLuminanceAlphaTextures())
86 {
87 return D3DFMT_A8L8;
88 }
89 else if (format == GL_RGB)
90 {
91 return D3DFMT_X8R8G8B8;
92 }
93
94 return D3DFMT_A8R8G8B8;
95 }
96
97 return D3DFMT_A8R8G8B8;
98}
99
daniel@transgaming.coma9eb5da2011-03-21 16:39:16 +0000100Texture::Texture(GLuint id) : RefCountObject(id), mSerial(issueSerial())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000101{
102 mMinFilter = GL_NEAREST_MIPMAP_LINEAR;
103 mMagFilter = GL_LINEAR;
104 mWrapS = GL_REPEAT;
105 mWrapT = GL_REPEAT;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +0000106 mDirtyParameter = true;
107
108 mDirtyImage = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +0000109
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000110 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000111}
112
113Texture::~Texture()
114{
115}
116
117Blit *Texture::getBlitter()
118{
119 Context *context = getContext();
120 return context->getBlitter();
121}
122
123// Returns true on successful filter state update (valid enum parameter)
124bool Texture::setMinFilter(GLenum filter)
125{
126 switch (filter)
127 {
128 case GL_NEAREST:
129 case GL_LINEAR:
130 case GL_NEAREST_MIPMAP_NEAREST:
131 case GL_LINEAR_MIPMAP_NEAREST:
132 case GL_NEAREST_MIPMAP_LINEAR:
133 case GL_LINEAR_MIPMAP_LINEAR:
134 {
135 if (mMinFilter != filter)
136 {
137 mMinFilter = filter;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +0000138 mDirtyParameter = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000139 }
140 return true;
141 }
142 default:
143 return false;
144 }
145}
146
147// Returns true on successful filter state update (valid enum parameter)
148bool Texture::setMagFilter(GLenum filter)
149{
150 switch (filter)
151 {
152 case GL_NEAREST:
153 case GL_LINEAR:
154 {
155 if (mMagFilter != filter)
156 {
157 mMagFilter = filter;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +0000158 mDirtyParameter = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000159 }
160 return true;
161 }
162 default:
163 return false;
164 }
165}
166
167// Returns true on successful wrap state update (valid enum parameter)
168bool Texture::setWrapS(GLenum wrap)
169{
170 switch (wrap)
171 {
172 case GL_REPEAT:
173 case GL_CLAMP_TO_EDGE:
174 case GL_MIRRORED_REPEAT:
175 {
176 if (mWrapS != wrap)
177 {
178 mWrapS = wrap;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +0000179 mDirtyParameter = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000180 }
181 return true;
182 }
183 default:
184 return false;
185 }
186}
187
188// Returns true on successful wrap state update (valid enum parameter)
189bool Texture::setWrapT(GLenum wrap)
190{
191 switch (wrap)
192 {
193 case GL_REPEAT:
194 case GL_CLAMP_TO_EDGE:
195 case GL_MIRRORED_REPEAT:
196 {
197 if (mWrapT != wrap)
198 {
199 mWrapT = wrap;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +0000200 mDirtyParameter = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000201 }
202 return true;
203 }
204 default:
205 return false;
206 }
207}
208
209GLenum Texture::getMinFilter() const
210{
211 return mMinFilter;
212}
213
214GLenum Texture::getMagFilter() const
215{
216 return mMagFilter;
217}
218
219GLenum Texture::getWrapS() const
220{
221 return mWrapS;
222}
223
224GLenum Texture::getWrapT() const
225{
226 return mWrapT;
227}
228
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000229// Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input
230// into the target pixel rectangle at output with outputPitch bytes in between each line.
231void Texture::loadImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type,
232 GLint unpackAlignment, const void *input, size_t outputPitch, void *output, D3DSURFACE_DESC *description) const
233{
234 GLsizei inputPitch = -ComputePitch(width, format, type, unpackAlignment);
235 input = ((char*)input) - inputPitch * (height - 1);
236
237 switch (type)
238 {
239 case GL_UNSIGNED_BYTE:
240 switch (format)
241 {
242 case GL_ALPHA:
243 loadAlphaImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
244 break;
245 case GL_LUMINANCE:
246 loadLuminanceImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output, description->Format == D3DFMT_L8);
247 break;
248 case GL_LUMINANCE_ALPHA:
249 loadLuminanceAlphaImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output, description->Format == D3DFMT_A8L8);
250 break;
251 case GL_RGB:
252 loadRGBUByteImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
253 break;
254 case GL_RGBA:
255 loadRGBAUByteImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
256 break;
257 case GL_BGRA_EXT:
258 loadBGRAImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
259 break;
260 default: UNREACHABLE();
261 }
262 break;
263 case GL_UNSIGNED_SHORT_5_6_5:
264 switch (format)
265 {
266 case GL_RGB:
267 loadRGB565ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
268 break;
269 default: UNREACHABLE();
270 }
271 break;
272 case GL_UNSIGNED_SHORT_4_4_4_4:
273 switch (format)
274 {
275 case GL_RGBA:
276 loadRGBA4444ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
277 break;
278 default: UNREACHABLE();
279 }
280 break;
281 case GL_UNSIGNED_SHORT_5_5_5_1:
282 switch (format)
283 {
284 case GL_RGBA:
285 loadRGBA5551ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
286 break;
287 default: UNREACHABLE();
288 }
289 break;
290 case GL_FLOAT:
291 switch (format)
292 {
293 // float textures are converted to RGBA, not BGRA, as they're stored that way in D3D
294 case GL_ALPHA:
295 loadAlphaFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
296 break;
297 case GL_LUMINANCE:
298 loadLuminanceFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
299 break;
300 case GL_LUMINANCE_ALPHA:
301 loadLuminanceAlphaFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
302 break;
303 case GL_RGB:
304 loadRGBFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
305 break;
306 case GL_RGBA:
307 loadRGBAFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
308 break;
309 default: UNREACHABLE();
310 }
311 break;
312 case GL_HALF_FLOAT_OES:
313 switch (format)
314 {
315 // float textures are converted to RGBA, not BGRA, as they're stored that way in D3D
316 case GL_ALPHA:
317 loadAlphaHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
318 break;
319 case GL_LUMINANCE:
320 loadLuminanceHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
321 break;
322 case GL_LUMINANCE_ALPHA:
323 loadLuminanceAlphaHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
324 break;
325 case GL_RGB:
326 loadRGBHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
327 break;
328 case GL_RGBA:
329 loadRGBAHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
330 break;
331 default: UNREACHABLE();
332 }
333 break;
334 default: UNREACHABLE();
335 }
336}
337
338void Texture::loadAlphaImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
339 int inputPitch, const void *input, size_t outputPitch, void *output) const
340{
341 const unsigned char *source = NULL;
342 unsigned char *dest = NULL;
343
344 for (int y = 0; y < height; y++)
345 {
346 source = static_cast<const unsigned char*>(input) + y * inputPitch;
347 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
348 for (int x = 0; x < width; x++)
349 {
350 dest[4 * x + 0] = 0;
351 dest[4 * x + 1] = 0;
352 dest[4 * x + 2] = 0;
353 dest[4 * x + 3] = source[x];
354 }
355 }
356}
357
358void Texture::loadAlphaFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
359 int inputPitch, const void *input, size_t outputPitch, void *output) const
360{
361 const float *source = NULL;
362 float *dest = NULL;
363
364 for (int y = 0; y < height; y++)
365 {
366 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
367 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
368 for (int x = 0; x < width; x++)
369 {
370 dest[4 * x + 0] = 0;
371 dest[4 * x + 1] = 0;
372 dest[4 * x + 2] = 0;
373 dest[4 * x + 3] = source[x];
374 }
375 }
376}
377
378void Texture::loadAlphaHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
379 int inputPitch, const void *input, size_t outputPitch, void *output) const
380{
381 const unsigned short *source = NULL;
382 unsigned short *dest = NULL;
383
384 for (int y = 0; y < height; y++)
385 {
386 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
387 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
388 for (int x = 0; x < width; x++)
389 {
390 dest[4 * x + 0] = 0;
391 dest[4 * x + 1] = 0;
392 dest[4 * x + 2] = 0;
393 dest[4 * x + 3] = source[x];
394 }
395 }
396}
397
398void Texture::loadLuminanceImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
399 int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const
400{
401 const int destBytesPerPixel = native? 1: 4;
402 const unsigned char *source = NULL;
403 unsigned char *dest = NULL;
404
405 for (int y = 0; y < height; y++)
406 {
407 source = static_cast<const unsigned char*>(input) + y * inputPitch;
408 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * destBytesPerPixel;
409
410 if (!native) // BGRA8 destination format
411 {
412 for (int x = 0; x < width; x++)
413 {
414 dest[4 * x + 0] = source[x];
415 dest[4 * x + 1] = source[x];
416 dest[4 * x + 2] = source[x];
417 dest[4 * x + 3] = 0xFF;
418 }
419 }
420 else // L8 destination format
421 {
422 memcpy(dest, source, width);
423 }
424 }
425}
426
427void Texture::loadLuminanceFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
428 int inputPitch, const void *input, size_t outputPitch, void *output) const
429{
430 const float *source = NULL;
431 float *dest = NULL;
432
433 for (int y = 0; y < height; y++)
434 {
435 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
436 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
437 for (int x = 0; x < width; x++)
438 {
439 dest[4 * x + 0] = source[x];
440 dest[4 * x + 1] = source[x];
441 dest[4 * x + 2] = source[x];
442 dest[4 * x + 3] = 1.0f;
443 }
444 }
445}
446
447void Texture::loadLuminanceHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
448 int inputPitch, const void *input, size_t outputPitch, void *output) const
449{
450 const unsigned short *source = NULL;
451 unsigned short *dest = NULL;
452
453 for (int y = 0; y < height; y++)
454 {
455 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
456 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
457 for (int x = 0; x < width; x++)
458 {
459 dest[4 * x + 0] = source[x];
460 dest[4 * x + 1] = source[x];
461 dest[4 * x + 2] = source[x];
462 dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1
463 }
464 }
465}
466
467void Texture::loadLuminanceAlphaImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
468 int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const
469{
470 const int destBytesPerPixel = native? 2: 4;
471 const unsigned char *source = NULL;
472 unsigned char *dest = NULL;
473
474 for (int y = 0; y < height; y++)
475 {
476 source = static_cast<const unsigned char*>(input) + y * inputPitch;
477 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * destBytesPerPixel;
478
479 if (!native) // BGRA8 destination format
480 {
481 for (int x = 0; x < width; x++)
482 {
483 dest[4 * x + 0] = source[2*x+0];
484 dest[4 * x + 1] = source[2*x+0];
485 dest[4 * x + 2] = source[2*x+0];
486 dest[4 * x + 3] = source[2*x+1];
487 }
488 }
489 else
490 {
491 memcpy(dest, source, width * 2);
492 }
493 }
494}
495
496void Texture::loadLuminanceAlphaFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
497 int inputPitch, const void *input, size_t outputPitch, void *output) const
498{
499 const float *source = NULL;
500 float *dest = NULL;
501
502 for (int y = 0; y < height; y++)
503 {
504 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
505 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
506 for (int x = 0; x < width; x++)
507 {
508 dest[4 * x + 0] = source[2*x+0];
509 dest[4 * x + 1] = source[2*x+0];
510 dest[4 * x + 2] = source[2*x+0];
511 dest[4 * x + 3] = source[2*x+1];
512 }
513 }
514}
515
516void Texture::loadLuminanceAlphaHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
517 int inputPitch, const void *input, size_t outputPitch, void *output) const
518{
519 const unsigned short *source = NULL;
520 unsigned short *dest = NULL;
521
522 for (int y = 0; y < height; y++)
523 {
524 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
525 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
526 for (int x = 0; x < width; x++)
527 {
528 dest[4 * x + 0] = source[2*x+0];
529 dest[4 * x + 1] = source[2*x+0];
530 dest[4 * x + 2] = source[2*x+0];
531 dest[4 * x + 3] = source[2*x+1];
532 }
533 }
534}
535
536void Texture::loadRGBUByteImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
537 int inputPitch, const void *input, size_t outputPitch, void *output) const
538{
539 const unsigned char *source = NULL;
540 unsigned char *dest = NULL;
541
542 for (int y = 0; y < height; y++)
543 {
544 source = static_cast<const unsigned char*>(input) + y * inputPitch;
545 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
546 for (int x = 0; x < width; x++)
547 {
548 dest[4 * x + 0] = source[x * 3 + 2];
549 dest[4 * x + 1] = source[x * 3 + 1];
550 dest[4 * x + 2] = source[x * 3 + 0];
551 dest[4 * x + 3] = 0xFF;
552 }
553 }
554}
555
556void Texture::loadRGB565ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
557 int inputPitch, const void *input, size_t outputPitch, void *output) const
558{
559 const unsigned short *source = NULL;
560 unsigned char *dest = NULL;
561
562 for (int y = 0; y < height; y++)
563 {
564 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
565 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
566 for (int x = 0; x < width; x++)
567 {
568 unsigned short rgba = source[x];
569 dest[4 * x + 0] = ((rgba & 0x001F) << 3) | ((rgba & 0x001F) >> 2);
570 dest[4 * x + 1] = ((rgba & 0x07E0) >> 3) | ((rgba & 0x07E0) >> 9);
571 dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
572 dest[4 * x + 3] = 0xFF;
573 }
574 }
575}
576
577void Texture::loadRGBFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
578 int inputPitch, const void *input, size_t outputPitch, void *output) const
579{
580 const float *source = NULL;
581 float *dest = NULL;
582
583 for (int y = 0; y < height; y++)
584 {
585 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
586 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
587 for (int x = 0; x < width; x++)
588 {
589 dest[4 * x + 0] = source[x * 3 + 0];
590 dest[4 * x + 1] = source[x * 3 + 1];
591 dest[4 * x + 2] = source[x * 3 + 2];
592 dest[4 * x + 3] = 1.0f;
593 }
594 }
595}
596
597void Texture::loadRGBHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
598 int inputPitch, const void *input, size_t outputPitch, void *output) const
599{
600 const unsigned short *source = NULL;
601 unsigned short *dest = NULL;
602
603 for (int y = 0; y < height; y++)
604 {
605 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
606 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
607 for (int x = 0; x < width; x++)
608 {
609 dest[4 * x + 0] = source[x * 3 + 0];
610 dest[4 * x + 1] = source[x * 3 + 1];
611 dest[4 * x + 2] = source[x * 3 + 2];
612 dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1
613 }
614 }
615}
616
617void Texture::loadRGBAUByteImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
618 int inputPitch, const void *input, size_t outputPitch, void *output) const
619{
620 const unsigned char *source = NULL;
621 unsigned char *dest = NULL;
622
623 for (int y = 0; y < height; y++)
624 {
625 source = static_cast<const unsigned char*>(input) + y * inputPitch;
626 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
627 for (int x = 0; x < width; x++)
628 {
629 dest[4 * x + 0] = source[x * 4 + 2];
630 dest[4 * x + 1] = source[x * 4 + 1];
631 dest[4 * x + 2] = source[x * 4 + 0];
632 dest[4 * x + 3] = source[x * 4 + 3];
633 }
634 }
635}
636
637void Texture::loadRGBA4444ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
638 int inputPitch, const void *input, size_t outputPitch, void *output) const
639{
640 const unsigned short *source = NULL;
641 unsigned char *dest = NULL;
642
643 for (int y = 0; y < height; y++)
644 {
645 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
646 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
647 for (int x = 0; x < width; x++)
648 {
649 unsigned short rgba = source[x];
650 dest[4 * x + 0] = ((rgba & 0x00F0) << 0) | ((rgba & 0x00F0) >> 4);
651 dest[4 * x + 1] = ((rgba & 0x0F00) >> 4) | ((rgba & 0x0F00) >> 8);
652 dest[4 * x + 2] = ((rgba & 0xF000) >> 8) | ((rgba & 0xF000) >> 12);
653 dest[4 * x + 3] = ((rgba & 0x000F) << 4) | ((rgba & 0x000F) >> 0);
654 }
655 }
656}
657
658void Texture::loadRGBA5551ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
659 int inputPitch, const void *input, size_t outputPitch, void *output) const
660{
661 const unsigned short *source = NULL;
662 unsigned char *dest = NULL;
663
664 for (int y = 0; y < height; y++)
665 {
666 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
667 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
668 for (int x = 0; x < width; x++)
669 {
670 unsigned short rgba = source[x];
671 dest[4 * x + 0] = ((rgba & 0x003E) << 2) | ((rgba & 0x003E) >> 3);
672 dest[4 * x + 1] = ((rgba & 0x07C0) >> 3) | ((rgba & 0x07C0) >> 8);
673 dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
674 dest[4 * x + 3] = (rgba & 0x0001) ? 0xFF : 0;
675 }
676 }
677}
678
679void Texture::loadRGBAFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
680 int inputPitch, const void *input, size_t outputPitch, void *output) const
681{
682 const float *source = NULL;
683 float *dest = NULL;
684
685 for (int y = 0; y < height; y++)
686 {
687 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
688 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
689 memcpy(dest, source, width * 16);
690 }
691}
692
693void Texture::loadRGBAHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
694 int inputPitch, const void *input, size_t outputPitch, void *output) const
695{
696 const unsigned char *source = NULL;
697 unsigned char *dest = NULL;
698
699 for (int y = 0; y < height; y++)
700 {
701 source = static_cast<const unsigned char*>(input) + y * inputPitch;
702 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8;
703 memcpy(dest, source, width * 8);
704 }
705}
706
707void Texture::loadBGRAImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
708 int inputPitch, const void *input, size_t outputPitch, void *output) const
709{
710 const unsigned char *source = NULL;
711 unsigned char *dest = NULL;
712
713 for (int y = 0; y < height; y++)
714 {
715 source = static_cast<const unsigned char*>(input) + y * inputPitch;
716 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
717 memcpy(dest, source, width*4);
718 }
719}
720
721void Texture::loadCompressedImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
722 int inputPitch, const void *input, size_t outputPitch, void *output) const
723{
724 ASSERT(xoffset % 4 == 0);
725 ASSERT(yoffset % 4 == 0);
726 ASSERT(width % 4 == 0 || width == 2 || width == 1);
727 ASSERT(inputPitch % 8 == 0);
728 ASSERT(outputPitch % 8 == 0);
729
730 const unsigned int *source = reinterpret_cast<const unsigned int*>(input);
731 unsigned int *dest = reinterpret_cast<unsigned int*>(output);
732
733 switch (height)
734 {
735 case 1:
736 // Round width up in case it is 1.
737 for (int x = 0; x < (width + 1) / 2; x += 2)
738 {
739 // First 32-bits is two RGB565 colors shared by tile and does not need to be modified.
740 dest[x] = source[x];
741
742 // Second 32-bits contains 4 rows of 4 2-bit interpolants between the colors, the last 3 rows being unused. No flipping should occur.
743 dest[x + 1] = source[x + 1];
744 }
745 break;
746 case 2:
747 // Round width up in case it is 1.
748 for (int x = 0; x < (width + 1) / 2; x += 2)
749 {
750 // First 32-bits is two RGB565 colors shared by tile and does not need to be modified.
751 dest[x] = source[x];
752
753 // Second 32-bits contains 4 rows of 4 2-bit interpolants between the colors, the last 2 rows being unused. Only the top 2 rows should be flipped.
754 dest[x + 1] = ((source[x + 1] << 8) & 0x0000FF00) |
755 ((source[x + 1] >> 8) & 0x000000FF);
756 }
757 break;
758 default:
759 ASSERT(height % 4 == 0);
760 for (int y = 0; y < height / 4; ++y)
761 {
762 const unsigned int *source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);
763 unsigned int *dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
764
765 // Round width up in case it is 1.
766 for (int x = 0; x < (width + 1) / 2; x += 2)
767 {
768 // First 32-bits is two RGB565 colors shared by tile and does not need to be modified.
769 dest[x] = source[x];
770
771 // Second 32-bits contains 4 rows of 4 2-bit interpolants between the colors. All rows should be flipped.
772 dest[x + 1] = (source[x + 1] >> 24) |
773 ((source[x + 1] << 8) & 0x00FF0000) |
774 ((source[x + 1] >> 8) & 0x0000FF00) |
775 (source[x + 1] << 24);
776 }
777 }
778 break;
779 }
780}
781
daniel@transgaming.com61208202011-03-21 16:38:50 +0000782void Texture::createSurface(Image *image)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000783{
784 IDirect3DTexture9 *newTexture = NULL;
785 IDirect3DSurface9 *newSurface = NULL;
786
daniel@transgaming.com61208202011-03-21 16:38:50 +0000787 if (image->width != 0 && image->height != 0)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000788 {
789 int levelToFetch = 0;
daniel@transgaming.com61208202011-03-21 16:38:50 +0000790 GLsizei requestWidth = image->width;
791 GLsizei requestHeight = image->height;
792 if (IsCompressed(image->format) && (image->width % 4 != 0 || image->height % 4 != 0))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000793 {
794 bool isMult4 = false;
795 int upsampleCount = 0;
796 while (!isMult4)
797 {
798 requestWidth <<= 1;
799 requestHeight <<= 1;
800 upsampleCount++;
801 if (requestWidth % 4 == 0 && requestHeight % 4 == 0)
802 {
803 isMult4 = true;
804 }
805 }
806 levelToFetch = upsampleCount;
807 }
808
daniel@transgaming.com549bdef2011-03-29 00:57:01 +0000809 HRESULT result = getDevice()->CreateTexture(requestWidth, requestHeight, levelToFetch + 1, NULL, image->getD3DFormat(),
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000810 D3DPOOL_SYSTEMMEM, &newTexture, NULL);
811
812 if (FAILED(result))
813 {
814 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
815 return error(GL_OUT_OF_MEMORY);
816 }
817
818 newTexture->GetSurfaceLevel(levelToFetch, &newSurface);
819 newTexture->Release();
820 }
821
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +0000822 if (image->surface)
823 {
824 image->surface->Release();
825 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000826
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +0000827 image->surface = newSurface;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000828}
829
daniel@transgaming.com61208202011-03-21 16:38:50 +0000830void Texture::setImage(GLint unpackAlignment, const void *pixels, Image *image)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000831{
daniel@transgaming.com61208202011-03-21 16:38:50 +0000832 createSurface(image);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000833
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000834 if (pixels != NULL && image->surface != NULL)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000835 {
836 D3DSURFACE_DESC description;
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000837 image->surface->GetDesc(&description);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000838
839 D3DLOCKED_RECT locked;
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000840 HRESULT result = image->surface->LockRect(&locked, NULL, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000841
842 ASSERT(SUCCEEDED(result));
843
844 if (SUCCEEDED(result))
845 {
daniel@transgaming.com61208202011-03-21 16:38:50 +0000846 loadImageData(0, 0, image->width, image->height, image->format, image->type, unpackAlignment, pixels, locked.Pitch, locked.pBits, &description);
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000847 image->surface->UnlockRect();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000848 }
849
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000850 image->dirty = true;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +0000851 mDirtyImage = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000852 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000853}
854
daniel@transgaming.com61208202011-03-21 16:38:50 +0000855void Texture::setCompressedImage(GLsizei imageSize, const void *pixels, Image *image)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000856{
daniel@transgaming.com61208202011-03-21 16:38:50 +0000857 createSurface(image);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000858
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000859 if (pixels != NULL && image->surface != NULL)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000860 {
861 D3DLOCKED_RECT locked;
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000862 HRESULT result = image->surface->LockRect(&locked, NULL, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000863
864 ASSERT(SUCCEEDED(result));
865
866 if (SUCCEEDED(result))
867 {
daniel@transgaming.com61208202011-03-21 16:38:50 +0000868 int inputPitch = ComputeCompressedPitch(image->width, image->format);
869 int inputSize = ComputeCompressedSize(image->width, image->height, image->format);
870 loadCompressedImageData(0, 0, image->width, image->height, -inputPitch, static_cast<const char*>(pixels) + inputSize - inputPitch, locked.Pitch, locked.pBits);
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000871 image->surface->UnlockRect();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000872 }
873
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000874 image->dirty = true;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +0000875 mDirtyImage = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000876 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000877}
878
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000879bool 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 +0000880{
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000881 if (width + xoffset > image->width || height + yoffset > image->height)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000882 {
883 error(GL_INVALID_VALUE);
884 return false;
885 }
886
jbauman@chromium.orge2f954c2011-05-03 20:45:27 +0000887 if (IsCompressed(image->format))
888 {
889 error(GL_INVALID_OPERATION);
890 return false;
891 }
892
893 if (format != image->format)
894 {
895 error(GL_INVALID_OPERATION);
896 return false;
897 }
898
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000899 if (!image->surface)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000900 {
daniel@transgaming.com61208202011-03-21 16:38:50 +0000901 createSurface(image);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000902 }
903
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000904 if (pixels != NULL && image->surface != NULL)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000905 {
906 D3DSURFACE_DESC description;
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000907 image->surface->GetDesc(&description);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000908
909 D3DLOCKED_RECT locked;
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000910 HRESULT result = image->surface->LockRect(&locked, NULL, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000911
912 ASSERT(SUCCEEDED(result));
913
914 if (SUCCEEDED(result))
915 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000916 loadImageData(xoffset, transformPixelYOffset(yoffset, height, image->height), width, height, format, type, unpackAlignment, pixels, locked.Pitch, locked.pBits, &description);
917 image->surface->UnlockRect();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000918 }
919
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000920 image->dirty = true;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +0000921 mDirtyImage = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000922 }
923
924 return true;
925}
926
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000927bool 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 +0000928{
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000929 if (width + xoffset > image->width || height + yoffset > image->height)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000930 {
931 error(GL_INVALID_VALUE);
932 return false;
933 }
934
935 if (format != getInternalFormat())
936 {
937 error(GL_INVALID_OPERATION);
938 return false;
939 }
940
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000941 if (!image->surface)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000942 {
daniel@transgaming.com61208202011-03-21 16:38:50 +0000943 createSurface(image);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000944 }
945
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000946 if (pixels != NULL && image->surface != NULL)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000947 {
948 RECT updateRegion;
949 updateRegion.left = xoffset;
950 updateRegion.right = xoffset + width;
951 updateRegion.bottom = yoffset + height;
952 updateRegion.top = yoffset;
953
954 D3DLOCKED_RECT locked;
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000955 HRESULT result = image->surface->LockRect(&locked, &updateRegion, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000956
957 ASSERT(SUCCEEDED(result));
958
959 if (SUCCEEDED(result))
960 {
961 int inputPitch = ComputeCompressedPitch(width, format);
962 int inputSize = ComputeCompressedSize(width, height, format);
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000963 loadCompressedImageData(xoffset, transformPixelYOffset(yoffset, height, image->height), width, height, -inputPitch, static_cast<const char*>(pixels) + inputSize - inputPitch, locked.Pitch, locked.pBits);
964 image->surface->UnlockRect();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000965 }
966
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000967 image->dirty = true;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +0000968 mDirtyImage = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000969 }
970
971 return true;
972}
973
daniel@transgaming.comb6276992011-03-29 00:58:18 +0000974// This implements glCopyTex[Sub]Image2D for non-renderable internal texture formats and incomplete textures
975void 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 +0000976{
daniel@transgaming.comb6276992011-03-29 00:58:18 +0000977 if (!image->surface)
978 {
979 createSurface(image);
980
981 if (!image->surface)
982 {
983 ERR("Failed to create an image surface.");
984 return error(GL_OUT_OF_MEMORY);
985 }
986 }
987
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000988 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.comb6276992011-03-29 00:58:18 +0000989 IDirect3DSurface9 *renderTargetData = NULL;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000990 D3DSURFACE_DESC description;
991 renderTarget->GetDesc(&description);
992
daniel@transgaming.comb6276992011-03-29 00:58:18 +0000993 HRESULT result = device->CreateOffscreenPlainSurface(description.Width, description.Height, description.Format, D3DPOOL_SYSTEMMEM, &renderTargetData, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000994
daniel@transgaming.comb6276992011-03-29 00:58:18 +0000995 if (FAILED(result))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000996 {
997 ERR("Could not create matching destination surface.");
998 return error(GL_OUT_OF_MEMORY);
999 }
1000
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001001 result = device->GetRenderTargetData(renderTarget, renderTargetData);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001002
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001003 if (FAILED(result))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001004 {
1005 ERR("GetRenderTargetData unexpectedly failed.");
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001006 renderTargetData->Release();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001007 return error(GL_OUT_OF_MEMORY);
1008 }
1009
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001010 RECT sourceRect = transformPixelRect(x, y, width, height, description.Height);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001011 int destYOffset = transformPixelYOffset(yoffset, height, image->height);
1012 RECT destRect = {xoffset, destYOffset, xoffset + width, destYOffset + height};
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001013
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001014 if (image->isRenderable())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001015 {
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001016 result = D3DXLoadSurfaceFromSurface(image->surface, NULL, &destRect, renderTargetData, NULL, &sourceRect, D3DX_FILTER_BOX, 0);
1017
1018 if (FAILED(result))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001019 {
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001020 ERR("Copying surfaces unexpectedly failed.");
1021 renderTargetData->Release();
1022 return error(GL_OUT_OF_MEMORY);
1023 }
1024 }
1025 else
1026 {
1027 D3DLOCKED_RECT sourceLock = {0};
1028 result = renderTargetData->LockRect(&sourceLock, &sourceRect, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001029
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001030 if (FAILED(result))
1031 {
1032 ERR("Failed to lock the source surface (rectangle might be invalid).");
1033 renderTargetData->Release();
1034 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001035 }
1036
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001037 D3DLOCKED_RECT destLock = {0};
1038 result = image->surface->LockRect(&destLock, &destRect, 0);
1039
1040 if (FAILED(result))
1041 {
1042 ERR("Failed to lock the destination surface (rectangle might be invalid).");
1043 renderTargetData->UnlockRect();
1044 renderTargetData->Release();
1045 return error(GL_OUT_OF_MEMORY);
1046 }
1047
1048 if (destLock.pBits && sourceLock.pBits)
1049 {
1050 unsigned char *source = (unsigned char*)sourceLock.pBits;
1051 unsigned char *dest = (unsigned char*)destLock.pBits;
1052
1053 switch (description.Format)
1054 {
1055 case D3DFMT_X8R8G8B8:
1056 case D3DFMT_A8R8G8B8:
1057 switch(image->getD3DFormat())
1058 {
1059 case D3DFMT_L8:
1060 for(int y = 0; y < height; y++)
1061 {
1062 for(int x = 0; x < width; x++)
1063 {
1064 dest[x] = source[x * 4 + 2];
1065 }
1066
1067 source += sourceLock.Pitch;
1068 dest += destLock.Pitch;
1069 }
1070 break;
1071 case D3DFMT_A8L8:
1072 for(int y = 0; y < height; y++)
1073 {
1074 for(int x = 0; x < width; x++)
1075 {
1076 dest[x * 2 + 0] = source[x * 4 + 2];
1077 dest[x * 2 + 1] = source[x * 4 + 3];
1078 }
1079
1080 source += sourceLock.Pitch;
1081 dest += destLock.Pitch;
1082 }
1083 break;
1084 default:
1085 UNREACHABLE();
1086 }
1087 break;
1088 case D3DFMT_R5G6B5:
1089 switch(image->getD3DFormat())
1090 {
1091 case D3DFMT_L8:
1092 for(int y = 0; y < height; y++)
1093 {
1094 for(int x = 0; x < width; x++)
1095 {
1096 unsigned char red = source[x * 2 + 1] & 0xF8;
1097 dest[x] = red | (red >> 5);
1098 }
1099
1100 source += sourceLock.Pitch;
1101 dest += destLock.Pitch;
1102 }
1103 break;
1104 default:
1105 UNREACHABLE();
1106 }
1107 break;
1108 case D3DFMT_A1R5G5B5:
1109 switch(image->getD3DFormat())
1110 {
1111 case D3DFMT_L8:
1112 for(int y = 0; y < height; y++)
1113 {
1114 for(int x = 0; x < width; x++)
1115 {
1116 unsigned char red = source[x * 2 + 1] & 0x7C;
1117 dest[x] = (red << 1) | (red >> 4);
1118 }
1119
1120 source += sourceLock.Pitch;
1121 dest += destLock.Pitch;
1122 }
1123 break;
1124 case D3DFMT_A8L8:
1125 for(int y = 0; y < height; y++)
1126 {
1127 for(int x = 0; x < width; x++)
1128 {
1129 unsigned char red = source[x * 2 + 1] & 0x7C;
1130 dest[x * 2 + 0] = (red << 1) | (red >> 4);
1131 dest[x * 2 + 1] = (signed char)source[x * 2 + 1] >> 7;
1132 }
1133
1134 source += sourceLock.Pitch;
1135 dest += destLock.Pitch;
1136 }
1137 break;
1138 default:
1139 UNREACHABLE();
1140 }
1141 break;
1142 default:
1143 UNREACHABLE();
1144 }
1145 }
1146
1147 image->surface->UnlockRect();
1148 renderTargetData->UnlockRect();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001149 }
1150
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001151 renderTargetData->Release();
1152
1153 image->dirty = true;
1154 mDirtyImage = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001155}
1156
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001157IDirect3DBaseTexture9 *Texture::getTexture()
1158{
1159 if (!isComplete())
1160 {
1161 return NULL;
1162 }
1163
daniel@transgaming.comaed18322011-03-21 16:38:13 +00001164 if (!getBaseTexture())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001165 {
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001166 createTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001167 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001168
daniel@transgaming.comc50edcb2011-03-21 16:38:40 +00001169 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001170
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001171 return getBaseTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001172}
1173
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00001174bool Texture::isDirtyParameter() const
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001175{
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00001176 return mDirtyParameter;
1177}
1178
1179bool Texture::isDirtyImage() const
1180{
1181 return mDirtyImage;
daniel@transgaming.com38e76e52011-03-21 16:39:10 +00001182}
1183
1184void Texture::resetDirty()
1185{
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00001186 mDirtyParameter = false;
1187 mDirtyImage = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001188}
1189
daniel@transgaming.coma9eb5da2011-03-21 16:39:16 +00001190unsigned int Texture::getSerial() const
1191{
1192 return mSerial;
1193}
1194
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001195GLint Texture::creationLevels(GLsizei width, GLsizei height, GLint maxlevel) const
1196{
1197 if (isPow2(width) && isPow2(height))
1198 {
1199 return maxlevel;
1200 }
1201 else
1202 {
1203 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
1204 return 1;
1205 }
1206}
1207
1208GLint Texture::creationLevels(GLsizei size, GLint maxlevel) const
1209{
1210 return creationLevels(size, size, maxlevel);
1211}
1212
1213int Texture::levelCount() const
1214{
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001215 return getBaseTexture() ? getBaseTexture()->GetLevelCount() : 0;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001216}
1217
daniel@transgaming.coma9eb5da2011-03-21 16:39:16 +00001218unsigned int Texture::issueSerial()
1219{
1220 return mCurrentSerial++;
1221}
1222
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001223Texture2D::Texture2D(GLuint id) : Texture(id)
1224{
1225 mTexture = NULL;
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001226 mSurface = NULL;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001227}
1228
1229Texture2D::~Texture2D()
1230{
1231 mColorbufferProxy.set(NULL);
1232
1233 if (mTexture)
1234 {
1235 mTexture->Release();
1236 mTexture = NULL;
1237 }
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001238
1239 if (mSurface)
1240 {
1241 mSurface->setBoundTexture(NULL);
1242 mSurface = NULL;
1243 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001244}
1245
1246GLenum Texture2D::getTarget() const
1247{
1248 return GL_TEXTURE_2D;
1249}
1250
daniel@transgaming.com61208202011-03-21 16:38:50 +00001251GLsizei Texture2D::getWidth() const
1252{
1253 return mImageArray[0].width;
1254}
1255
1256GLsizei Texture2D::getHeight() const
1257{
1258 return mImageArray[0].height;
1259}
1260
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001261GLenum Texture2D::getInternalFormat() const
1262{
1263 return mImageArray[0].format;
1264}
1265
daniel@transgaming.com61208202011-03-21 16:38:50 +00001266GLenum Texture2D::getType() const
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001267{
daniel@transgaming.com61208202011-03-21 16:38:50 +00001268 return mImageArray[0].type;
1269}
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001270
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001271D3DFORMAT Texture2D::getD3DFormat() const
1272{
1273 return mImageArray[0].getD3DFormat();
1274}
1275
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001276void Texture2D::redefineTexture(GLint level, GLenum format, GLsizei width, GLsizei height, GLenum type, bool forceRedefine)
daniel@transgaming.com61208202011-03-21 16:38:50 +00001277{
daniel@transgaming.com94a4f032011-03-21 16:38:55 +00001278 GLsizei textureWidth = mImageArray[0].width;
1279 GLsizei textureHeight = mImageArray[0].height;
1280 GLenum textureFormat = mImageArray[0].format;
1281 GLenum textureType = mImageArray[0].type;
1282
daniel@transgaming.com61208202011-03-21 16:38:50 +00001283 mImageArray[level].width = width;
1284 mImageArray[level].height = height;
1285 mImageArray[level].format = format;
1286 mImageArray[level].type = type;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001287
daniel@transgaming.com61208202011-03-21 16:38:50 +00001288 if (!mTexture)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001289 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001290 return;
1291 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001292
daniel@transgaming.com94a4f032011-03-21 16:38:55 +00001293 bool widthOkay = (textureWidth >> level == width) || (textureWidth >> level == 0 && width == 1);
1294 bool heightOkay = (textureHeight >> level == height) || (textureHeight >> level == 0 && height == 1);
1295 bool textureOkay = (widthOkay && heightOkay && textureFormat == format && textureType == type);
daniel@transgaming.com61208202011-03-21 16:38:50 +00001296
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001297 if (!textureOkay || forceRedefine || mSurface) // Purge all the levels and the texture.
daniel@transgaming.com61208202011-03-21 16:38:50 +00001298 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001299 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1300 {
1301 if (mImageArray[i].surface != NULL)
1302 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001303 mImageArray[i].surface->Release();
1304 mImageArray[i].surface = NULL;
daniel@transgaming.com61208202011-03-21 16:38:50 +00001305 mImageArray[i].dirty = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001306 }
1307 }
1308
1309 if (mTexture != NULL)
1310 {
1311 mTexture->Release();
1312 mTexture = NULL;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00001313 mDirtyImage = true;
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001314 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001315 }
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001316
1317 if (mSurface)
1318 {
1319 mSurface->setBoundTexture(NULL);
1320 mSurface = NULL;
1321 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001322 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001323}
1324
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001325void 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 +00001326{
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001327 redefineTexture(level, format, width, height, type, false);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001328
daniel@transgaming.com61208202011-03-21 16:38:50 +00001329 Texture::setImage(unpackAlignment, pixels, &mImageArray[level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001330}
1331
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001332void Texture2D::bindTexImage(egl::Surface *surface)
1333{
1334 GLenum format;
1335
1336 switch(surface->getFormat())
1337 {
1338 case D3DFMT_A8R8G8B8:
1339 format = GL_RGBA;
1340 break;
1341 case D3DFMT_X8R8G8B8:
1342 format = GL_RGB;
1343 break;
1344 default:
1345 UNIMPLEMENTED();
1346 return;
1347 }
1348
1349 redefineTexture(0, format, surface->getWidth(), surface->getHeight(), GL_UNSIGNED_BYTE, true);
1350
1351 IDirect3DTexture9 *texture = surface->getOffscreenTexture();
1352
1353 mTexture = texture;
1354 mDirtyImage = true;
1355 mIsRenderable = true;
1356 mSurface = surface;
1357 mSurface->setBoundTexture(this);
1358}
1359
1360void Texture2D::releaseTexImage()
1361{
1362 redefineTexture(0, GL_RGB, 0, 0, GL_UNSIGNED_BYTE, true);
1363}
1364
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001365void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001366{
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001367 redefineTexture(level, format, width, height, GL_UNSIGNED_BYTE, false);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001368
daniel@transgaming.com61208202011-03-21 16:38:50 +00001369 Texture::setCompressedImage(imageSize, pixels, &mImageArray[level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001370}
1371
1372void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1373{
1374 ASSERT(mImageArray[level].surface != NULL);
1375
1376 if (level < levelCount())
1377 {
1378 IDirect3DSurface9 *destLevel = NULL;
1379 HRESULT result = mTexture->GetSurfaceLevel(level, &destLevel);
1380
1381 ASSERT(SUCCEEDED(result));
1382
1383 if (SUCCEEDED(result))
1384 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001385 Image *image = &mImageArray[level];
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001386
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001387 RECT sourceRect = transformPixelRect(xoffset, yoffset, width, height, image->height);;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001388
1389 POINT destPoint;
1390 destPoint.x = sourceRect.left;
1391 destPoint.y = sourceRect.top;
1392
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001393 result = getDevice()->UpdateSurface(image->surface, &sourceRect, destLevel, &destPoint);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001394 ASSERT(SUCCEEDED(result));
1395
1396 destLevel->Release();
1397
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001398 image->dirty = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001399 }
1400 }
1401}
1402
1403void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1404{
1405 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[level]))
1406 {
1407 commitRect(level, xoffset, yoffset, width, height);
1408 }
1409}
1410
1411void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1412{
1413 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[level]))
1414 {
1415 commitRect(level, xoffset, yoffset, width, height);
1416 }
1417}
1418
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001419void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001420{
1421 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
1422
1423 if (!renderTarget)
1424 {
1425 ERR("Failed to retrieve the render target.");
1426 return error(GL_OUT_OF_MEMORY);
1427 }
1428
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001429 redefineTexture(level, format, width, height, GL_UNSIGNED_BYTE, false);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001430
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001431 if (!mImageArray[level].isRenderable())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001432 {
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001433 copyToImage(&mImageArray[level], 0, 0, x, y, width, height, renderTarget);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001434 }
1435 else
1436 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001437 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001438 {
1439 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001440 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00001441
1442 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001443
1444 if (width != 0 && height != 0 && level < levelCount())
1445 {
1446 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
1447 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
1448 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
1449 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
1450 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
daniel@transgaming.comeef864a2011-04-22 11:33:27 +00001451
1452 GLint destYOffset = transformPixelYOffset(0, height, mImageArray[level].height);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001453
1454 IDirect3DSurface9 *dest;
1455 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
1456
daniel@transgaming.comeef864a2011-04-22 11:33:27 +00001457 getBlitter()->copy(source->getRenderTarget(), sourceRect, format, 0, destYOffset, dest);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001458 dest->Release();
1459 }
1460 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001461}
1462
1463void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1464{
1465 if (xoffset + width > mImageArray[level].width || yoffset + height > mImageArray[level].height)
1466 {
1467 return error(GL_INVALID_VALUE);
1468 }
1469
1470 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
1471
1472 if (!renderTarget)
1473 {
1474 ERR("Failed to retrieve the render target.");
1475 return error(GL_OUT_OF_MEMORY);
1476 }
1477
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001478 redefineTexture(level, mImageArray[level].format, mImageArray[level].width, mImageArray[level].height, GL_UNSIGNED_BYTE, false);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001479
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001480 if (!mImageArray[level].isRenderable() || (!mTexture && !isComplete()))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001481 {
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001482 copyToImage(&mImageArray[level], xoffset, yoffset, x, y, width, height, renderTarget);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001483 }
1484 else
1485 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001486 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001487 {
1488 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001489 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00001490
1491 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001492
1493 if (level < levelCount())
1494 {
1495 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
1496 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
1497 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
1498 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
1499 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
1500
1501 GLint destYOffset = transformPixelYOffset(yoffset, height, mImageArray[level].height);
1502
1503 IDirect3DSurface9 *dest;
1504 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
1505
daniel@transgaming.comeef864a2011-04-22 11:33:27 +00001506 getBlitter()->copy(source->getRenderTarget(), sourceRect, mImageArray[0].format, xoffset, destYOffset, dest);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001507 dest->Release();
1508 }
1509 }
1510}
1511
1512// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1513bool Texture2D::isComplete() const
1514{
1515 GLsizei width = mImageArray[0].width;
1516 GLsizei height = mImageArray[0].height;
1517
1518 if (width <= 0 || height <= 0)
1519 {
1520 return false;
1521 }
1522
1523 bool mipmapping = false;
1524
1525 switch (mMinFilter)
1526 {
1527 case GL_NEAREST:
1528 case GL_LINEAR:
1529 mipmapping = false;
1530 break;
1531 case GL_NEAREST_MIPMAP_NEAREST:
1532 case GL_LINEAR_MIPMAP_NEAREST:
1533 case GL_NEAREST_MIPMAP_LINEAR:
1534 case GL_LINEAR_MIPMAP_LINEAR:
1535 mipmapping = true;
1536 break;
1537 default: UNREACHABLE();
1538 }
1539
1540 if ((getInternalFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) ||
1541 (getInternalFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter()))
1542 {
1543 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
1544 {
1545 return false;
1546 }
1547 }
1548
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001549 if ((getWrapS() != GL_CLAMP_TO_EDGE && !isPow2(width))
1550 || (getWrapT() != GL_CLAMP_TO_EDGE && !isPow2(height)))
1551 {
1552 return false;
1553 }
1554
1555 if (mipmapping)
1556 {
1557 if (!isPow2(width) || !isPow2(height))
1558 {
1559 return false;
1560 }
1561
1562 int q = log2(std::max(width, height));
1563
1564 for (int level = 1; level <= q; level++)
1565 {
1566 if (mImageArray[level].format != mImageArray[0].format)
1567 {
1568 return false;
1569 }
1570
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00001571 if (mImageArray[level].type != mImageArray[0].type)
1572 {
1573 return false;
1574 }
1575
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001576 if (mImageArray[level].width != std::max(1, width >> level))
1577 {
1578 return false;
1579 }
1580
1581 if (mImageArray[level].height != std::max(1, height >> level))
1582 {
1583 return false;
1584 }
1585 }
1586 }
1587
1588 return true;
1589}
1590
1591bool Texture2D::isCompressed() const
1592{
1593 return IsCompressed(getInternalFormat());
1594}
1595
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001596IDirect3DBaseTexture9 *Texture2D::getBaseTexture() const
1597{
1598 return mTexture;
1599}
1600
1601// Constructs a Direct3D 9 texture resource from the texture images
1602void Texture2D::createTexture()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001603{
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001604 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001605 D3DFORMAT format = mImageArray[0].getD3DFormat();
daniel@transgaming.com61208202011-03-21 16:38:50 +00001606 GLint levels = creationLevels(mImageArray[0].width, mImageArray[0].height, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001607
daniel@transgaming.com61208202011-03-21 16:38:50 +00001608 IDirect3DTexture9 *texture = NULL;
1609 HRESULT result = device->CreateTexture(mImageArray[0].width, mImageArray[0].height, levels, 0, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001610
1611 if (FAILED(result))
1612 {
1613 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001614 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001615 }
1616
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001617 if (mTexture)
1618 {
1619 mTexture->Release();
1620 }
1621
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001622 mTexture = texture;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00001623 mDirtyImage = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00001624 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001625}
1626
1627void Texture2D::updateTexture()
1628{
1629 IDirect3DDevice9 *device = getDevice();
1630
1631 int levels = levelCount();
1632
1633 for (int level = 0; level < levels; level++)
1634 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001635 if (mImageArray[level].surface && mImageArray[level].dirty)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001636 {
1637 IDirect3DSurface9 *levelSurface = NULL;
1638 HRESULT result = mTexture->GetSurfaceLevel(level, &levelSurface);
1639
1640 ASSERT(SUCCEEDED(result));
1641
1642 if (SUCCEEDED(result))
1643 {
1644 result = device->UpdateSurface(mImageArray[level].surface, NULL, levelSurface, NULL);
1645 ASSERT(SUCCEEDED(result));
1646
1647 levelSurface->Release();
1648
1649 mImageArray[level].dirty = false;
1650 }
1651 }
1652 }
1653}
1654
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001655void Texture2D::convertToRenderTarget()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001656{
1657 IDirect3DTexture9 *texture = NULL;
1658
daniel@transgaming.com61208202011-03-21 16:38:50 +00001659 if (mImageArray[0].width != 0 && mImageArray[0].height != 0)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001660 {
1661 egl::Display *display = getDisplay();
1662 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001663 D3DFORMAT format = mImageArray[0].getD3DFormat();
daniel@transgaming.com61208202011-03-21 16:38:50 +00001664 GLint levels = creationLevels(mImageArray[0].width, mImageArray[0].height, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001665
daniel@transgaming.com61208202011-03-21 16:38:50 +00001666 HRESULT result = device->CreateTexture(mImageArray[0].width, mImageArray[0].height, levels, D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001667
1668 if (FAILED(result))
1669 {
1670 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001671 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001672 }
1673
1674 if (mTexture != NULL)
1675 {
1676 int levels = levelCount();
1677 for (int i = 0; i < levels; i++)
1678 {
1679 IDirect3DSurface9 *source;
1680 result = mTexture->GetSurfaceLevel(i, &source);
1681
1682 if (FAILED(result))
1683 {
1684 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1685
1686 texture->Release();
1687
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001688 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001689 }
1690
1691 IDirect3DSurface9 *dest;
1692 result = texture->GetSurfaceLevel(i, &dest);
1693
1694 if (FAILED(result))
1695 {
1696 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1697
1698 texture->Release();
1699 source->Release();
1700
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001701 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001702 }
1703
1704 display->endScene();
1705 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
1706
1707 if (FAILED(result))
1708 {
1709 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1710
1711 texture->Release();
1712 source->Release();
1713 dest->Release();
1714
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001715 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001716 }
1717
1718 source->Release();
1719 dest->Release();
1720 }
1721 }
1722 }
1723
1724 if (mTexture != NULL)
1725 {
1726 mTexture->Release();
1727 }
1728
1729 mTexture = texture;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00001730 mDirtyImage = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00001731 mIsRenderable = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001732}
1733
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001734void Texture2D::generateMipmaps()
1735{
1736 if (!isPow2(mImageArray[0].width) || !isPow2(mImageArray[0].height))
1737 {
1738 return error(GL_INVALID_OPERATION);
1739 }
1740
1741 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
daniel@transgaming.com61208202011-03-21 16:38:50 +00001742 unsigned int q = log2(std::max(mImageArray[0].width, mImageArray[0].height));
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001743 for (unsigned int i = 1; i <= q; i++)
1744 {
1745 if (mImageArray[i].surface != NULL)
1746 {
1747 mImageArray[i].surface->Release();
1748 mImageArray[i].surface = NULL;
1749 }
1750
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001751 mImageArray[i].width = std::max(mImageArray[0].width >> i, 1);
1752 mImageArray[i].height = std::max(mImageArray[0].height >> i, 1);
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00001753 mImageArray[i].format = mImageArray[0].format;
1754 mImageArray[i].type = mImageArray[0].type;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001755 }
1756
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001757 if (mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001758 {
1759 if (mTexture == NULL)
1760 {
1761 ERR(" failed because mTexture was null.");
1762 return;
1763 }
1764
1765 for (unsigned int i = 1; i <= q; i++)
1766 {
1767 IDirect3DSurface9 *upper = NULL;
1768 IDirect3DSurface9 *lower = NULL;
1769
1770 mTexture->GetSurfaceLevel(i-1, &upper);
1771 mTexture->GetSurfaceLevel(i, &lower);
1772
1773 if (upper != NULL && lower != NULL)
1774 {
1775 getBlitter()->boxFilter(upper, lower);
1776 }
1777
1778 if (upper != NULL) upper->Release();
1779 if (lower != NULL) lower->Release();
daniel@transgaming.com61208202011-03-21 16:38:50 +00001780
1781 mImageArray[i].dirty = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001782 }
1783 }
1784 else
1785 {
1786 for (unsigned int i = 1; i <= q; i++)
1787 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001788 createSurface(&mImageArray[i]);
1789
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001790 if (mImageArray[i].surface == NULL)
1791 {
1792 return error(GL_OUT_OF_MEMORY);
1793 }
1794
1795 if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[i].surface, NULL, NULL, mImageArray[i - 1].surface, NULL, NULL, D3DX_FILTER_BOX, 0)))
1796 {
1797 ERR(" failed to load filter %d to %d.", i - 1, i);
1798 }
1799
1800 mImageArray[i].dirty = true;
1801 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001802 }
1803}
1804
1805Renderbuffer *Texture2D::getRenderbuffer(GLenum target)
1806{
1807 if (target != GL_TEXTURE_2D)
1808 {
1809 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
1810 }
1811
1812 if (mColorbufferProxy.get() == NULL)
1813 {
1814 mColorbufferProxy.set(new Renderbuffer(id(), new Colorbuffer(this, target)));
1815 }
1816
1817 return mColorbufferProxy.get();
1818}
1819
1820IDirect3DSurface9 *Texture2D::getRenderTarget(GLenum target)
1821{
1822 ASSERT(target == GL_TEXTURE_2D);
1823
daniel@transgaming.com61208202011-03-21 16:38:50 +00001824 if (!mIsRenderable)
1825 {
1826 convertToRenderTarget();
1827 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001828
1829 if (mTexture == NULL)
1830 {
1831 return NULL;
1832 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00001833
1834 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001835
1836 IDirect3DSurface9 *renderTarget = NULL;
1837 mTexture->GetSurfaceLevel(0, &renderTarget);
1838
1839 return renderTarget;
1840}
1841
1842TextureCubeMap::TextureCubeMap(GLuint id) : Texture(id)
1843{
1844 mTexture = NULL;
1845}
1846
1847TextureCubeMap::~TextureCubeMap()
1848{
1849 for (int i = 0; i < 6; i++)
1850 {
1851 mFaceProxies[i].set(NULL);
1852 }
1853
1854 if (mTexture)
1855 {
1856 mTexture->Release();
1857 mTexture = NULL;
1858 }
1859}
1860
1861GLenum TextureCubeMap::getTarget() const
1862{
1863 return GL_TEXTURE_CUBE_MAP;
1864}
1865
daniel@transgaming.com61208202011-03-21 16:38:50 +00001866GLsizei TextureCubeMap::getWidth() const
1867{
1868 return mImageArray[0][0].width;
1869}
1870
1871GLsizei TextureCubeMap::getHeight() const
1872{
1873 return mImageArray[0][0].height;
1874}
1875
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001876GLenum TextureCubeMap::getInternalFormat() const
1877{
1878 return mImageArray[0][0].format;
1879}
1880
daniel@transgaming.com61208202011-03-21 16:38:50 +00001881GLenum TextureCubeMap::getType() const
1882{
1883 return mImageArray[0][0].type;
1884}
1885
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001886D3DFORMAT TextureCubeMap::getD3DFormat() const
1887{
1888 return mImageArray[0][0].getD3DFormat();
1889}
1890
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001891void 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 +00001892{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001893 setImage(0, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001894}
1895
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001896void 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 +00001897{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001898 setImage(1, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001899}
1900
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001901void 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 +00001902{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001903 setImage(2, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001904}
1905
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001906void 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 +00001907{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001908 setImage(3, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001909}
1910
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001911void 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 +00001912{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001913 setImage(4, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001914}
1915
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001916void 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 +00001917{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001918 setImage(5, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001919}
1920
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001921void 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 +00001922{
daniel@transgaming.com61208202011-03-21 16:38:50 +00001923 redefineTexture(faceIndex(face), level, format, width, height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001924
daniel@transgaming.com61208202011-03-21 16:38:50 +00001925 Texture::setCompressedImage(imageSize, pixels, &mImageArray[faceIndex(face)][level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001926}
1927
1928void TextureCubeMap::commitRect(GLenum faceTarget, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1929{
1930 int face = faceIndex(faceTarget);
1931 ASSERT(mImageArray[face][level].surface != NULL);
1932
1933 if (level < levelCount())
1934 {
1935 IDirect3DSurface9 *destLevel = getCubeMapSurface(faceTarget, level);
1936 ASSERT(destLevel != NULL);
1937
1938 if (destLevel != NULL)
1939 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001940 Image *image = &mImageArray[face][level];
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001941
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001942 RECT sourceRect = transformPixelRect(xoffset, yoffset, width, height, image->height);;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001943
1944 POINT destPoint;
1945 destPoint.x = sourceRect.left;
1946 destPoint.y = sourceRect.top;
1947
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001948 HRESULT result = getDevice()->UpdateSurface(image->surface, &sourceRect, destLevel, &destPoint);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001949 ASSERT(SUCCEEDED(result));
1950
1951 destLevel->Release();
1952
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001953 image->dirty = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001954 }
1955 }
1956}
1957
1958void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1959{
1960 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[faceIndex(target)][level]))
1961 {
1962 commitRect(target, level, xoffset, yoffset, width, height);
1963 }
1964}
1965
1966void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1967{
1968 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[faceIndex(target)][level]))
1969 {
1970 commitRect(target, level, xoffset, yoffset, width, height);
1971 }
1972}
1973
1974// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1975bool TextureCubeMap::isComplete() const
1976{
1977 int size = mImageArray[0][0].width;
1978
1979 if (size <= 0)
1980 {
1981 return false;
1982 }
1983
1984 bool mipmapping;
1985
1986 switch (mMinFilter)
1987 {
1988 case GL_NEAREST:
1989 case GL_LINEAR:
1990 mipmapping = false;
1991 break;
1992 case GL_NEAREST_MIPMAP_NEAREST:
1993 case GL_LINEAR_MIPMAP_NEAREST:
1994 case GL_NEAREST_MIPMAP_LINEAR:
1995 case GL_LINEAR_MIPMAP_LINEAR:
1996 mipmapping = true;
1997 break;
1998 default: UNREACHABLE();
1999 }
2000
2001 for (int face = 0; face < 6; face++)
2002 {
2003 if (mImageArray[face][0].width != size || mImageArray[face][0].height != size)
2004 {
2005 return false;
2006 }
2007 }
2008
2009 if ((getInternalFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) ||
2010 (getInternalFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter()))
2011 {
2012 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
2013 {
2014 return false;
2015 }
2016 }
2017
2018 if (mipmapping)
2019 {
2020 if (!isPow2(size) && (getWrapS() != GL_CLAMP_TO_EDGE || getWrapT() != GL_CLAMP_TO_EDGE))
2021 {
2022 return false;
2023 }
2024
2025 int q = log2(size);
2026
2027 for (int face = 0; face < 6; face++)
2028 {
2029 for (int level = 1; level <= q; level++)
2030 {
2031 if (mImageArray[face][level].format != mImageArray[0][0].format)
2032 {
2033 return false;
2034 }
2035
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00002036 if (mImageArray[face][level].type != mImageArray[0][0].type)
2037 {
2038 return false;
2039 }
2040
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002041 if (mImageArray[face][level].width != std::max(1, size >> level))
2042 {
2043 return false;
2044 }
2045
2046 ASSERT(mImageArray[face][level].height == mImageArray[face][level].width);
2047 }
2048 }
2049 }
2050
2051 return true;
2052}
2053
2054bool TextureCubeMap::isCompressed() const
2055{
2056 return IsCompressed(getInternalFormat());
2057}
2058
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002059IDirect3DBaseTexture9 *TextureCubeMap::getBaseTexture() const
2060{
2061 return mTexture;
2062}
2063
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002064// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002065void TextureCubeMap::createTexture()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002066{
2067 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002068 D3DFORMAT format = mImageArray[0][0].getD3DFormat();
daniel@transgaming.com61208202011-03-21 16:38:50 +00002069 GLint levels = creationLevels(mImageArray[0][0].width, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002070
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00002071 IDirect3DCubeTexture9 *texture = NULL;
daniel@transgaming.com61208202011-03-21 16:38:50 +00002072 HRESULT result = device->CreateCubeTexture(mImageArray[0][0].width, levels, 0, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002073
2074 if (FAILED(result))
2075 {
2076 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002077 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002078 }
2079
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002080 if (mTexture)
2081 {
2082 mTexture->Release();
2083 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002084
2085 mTexture = texture;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00002086 mDirtyImage = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00002087 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002088}
2089
2090void TextureCubeMap::updateTexture()
2091{
2092 IDirect3DDevice9 *device = getDevice();
2093
2094 for (int face = 0; face < 6; face++)
2095 {
2096 int levels = levelCount();
2097 for (int level = 0; level < levels; level++)
2098 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00002099 Image *image = &mImageArray[face][level];
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002100
daniel@transgaming.com61208202011-03-21 16:38:50 +00002101 if (image->surface && image->dirty)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002102 {
2103 IDirect3DSurface9 *levelSurface = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level);
2104 ASSERT(levelSurface != NULL);
2105
2106 if (levelSurface != NULL)
2107 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00002108 HRESULT result = device->UpdateSurface(image->surface, NULL, levelSurface, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002109 ASSERT(SUCCEEDED(result));
2110
2111 levelSurface->Release();
2112
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00002113 image->dirty = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002114 }
2115 }
2116 }
2117 }
2118}
2119
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002120void TextureCubeMap::convertToRenderTarget()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002121{
2122 IDirect3DCubeTexture9 *texture = NULL;
2123
daniel@transgaming.com61208202011-03-21 16:38:50 +00002124 if (mImageArray[0][0].width != 0)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002125 {
2126 egl::Display *display = getDisplay();
2127 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002128 D3DFORMAT format = mImageArray[0][0].getD3DFormat();
daniel@transgaming.com61208202011-03-21 16:38:50 +00002129 GLint levels = creationLevels(mImageArray[0][0].width, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002130
daniel@transgaming.com61208202011-03-21 16:38:50 +00002131 HRESULT result = device->CreateCubeTexture(mImageArray[0][0].width, levels, D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002132
2133 if (FAILED(result))
2134 {
2135 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002136 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002137 }
2138
2139 if (mTexture != NULL)
2140 {
2141 int levels = levelCount();
2142 for (int f = 0; f < 6; f++)
2143 {
2144 for (int i = 0; i < levels; i++)
2145 {
2146 IDirect3DSurface9 *source;
2147 result = mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &source);
2148
2149 if (FAILED(result))
2150 {
2151 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2152
2153 texture->Release();
2154
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002155 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002156 }
2157
2158 IDirect3DSurface9 *dest;
2159 result = texture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &dest);
2160
2161 if (FAILED(result))
2162 {
2163 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2164
2165 texture->Release();
2166 source->Release();
2167
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002168 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002169 }
2170
2171 display->endScene();
2172 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
2173
2174 if (FAILED(result))
2175 {
2176 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2177
2178 texture->Release();
2179 source->Release();
2180 dest->Release();
2181
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002182 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002183 }
2184 }
2185 }
2186 }
2187 }
2188
2189 if (mTexture != NULL)
2190 {
2191 mTexture->Release();
2192 }
2193
2194 mTexture = texture;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00002195 mDirtyImage = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00002196 mIsRenderable = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002197}
2198
daniel@transgaming.com61208202011-03-21 16:38:50 +00002199void 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 +00002200{
daniel@transgaming.com61208202011-03-21 16:38:50 +00002201 redefineTexture(faceIndex, level, format, width, height, type);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002202
daniel@transgaming.com61208202011-03-21 16:38:50 +00002203 Texture::setImage(unpackAlignment, pixels, &mImageArray[faceIndex][level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002204}
2205
2206unsigned int TextureCubeMap::faceIndex(GLenum face)
2207{
2208 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
2209 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
2210 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
2211 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
2212 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
2213
2214 return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
2215}
2216
daniel@transgaming.com61208202011-03-21 16:38:50 +00002217void TextureCubeMap::redefineTexture(int face, GLint level, GLenum format, GLsizei width, GLsizei height, GLenum type)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002218{
daniel@transgaming.com94a4f032011-03-21 16:38:55 +00002219 GLsizei textureWidth = mImageArray[0][0].width;
2220 GLsizei textureHeight = mImageArray[0][0].height;
2221 GLenum textureFormat = mImageArray[0][0].format;
2222 GLenum textureType = mImageArray[0][0].type;
2223
daniel@transgaming.com61208202011-03-21 16:38:50 +00002224 mImageArray[face][level].width = width;
2225 mImageArray[face][level].height = height;
2226 mImageArray[face][level].format = format;
2227 mImageArray[face][level].type = type;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002228
daniel@transgaming.com61208202011-03-21 16:38:50 +00002229 if (!mTexture)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002230 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00002231 return;
2232 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002233
daniel@transgaming.com94a4f032011-03-21 16:38:55 +00002234 bool sizeOkay = (textureWidth >> level == width);
2235 bool textureOkay = (sizeOkay && textureFormat == format && textureType == type);
daniel@transgaming.com61208202011-03-21 16:38:50 +00002236
2237 if (!textureOkay) // Purge all the levels and the texture.
2238 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002239 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
2240 {
2241 for (int f = 0; f < 6; f++)
2242 {
2243 if (mImageArray[f][i].surface != NULL)
2244 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002245 mImageArray[f][i].surface->Release();
2246 mImageArray[f][i].surface = NULL;
daniel@transgaming.com61208202011-03-21 16:38:50 +00002247 mImageArray[f][i].dirty = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002248 }
2249 }
2250 }
2251
2252 if (mTexture != NULL)
2253 {
2254 mTexture->Release();
2255 mTexture = NULL;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00002256 mDirtyImage = true;
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002257 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002258 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002259 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002260}
2261
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002262void 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 +00002263{
2264 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
2265
2266 if (!renderTarget)
2267 {
2268 ERR("Failed to retrieve the render target.");
2269 return error(GL_OUT_OF_MEMORY);
2270 }
2271
2272 unsigned int faceindex = faceIndex(target);
daniel@transgaming.com61208202011-03-21 16:38:50 +00002273 redefineTexture(faceindex, level, format, width, height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002274
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002275 if (!mImageArray[faceindex][level].isRenderable())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002276 {
daniel@transgaming.comb6276992011-03-29 00:58:18 +00002277 copyToImage(&mImageArray[faceindex][level], 0, 0, x, y, width, height, renderTarget);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002278 }
2279 else
2280 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00002281 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002282 {
2283 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002284 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00002285
2286 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002287
2288 ASSERT(width == height);
2289
2290 if (width > 0 && level < levelCount())
2291 {
2292 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
2293 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
2294 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
2295 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
2296 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
2297
daniel@transgaming.comeef864a2011-04-22 11:33:27 +00002298 GLint destYOffset = transformPixelYOffset(0, height, mImageArray[faceindex][level].width);
2299
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002300 IDirect3DSurface9 *dest = getCubeMapSurface(target, level);
2301
daniel@transgaming.comeef864a2011-04-22 11:33:27 +00002302 getBlitter()->copy(source->getRenderTarget(), sourceRect, format, 0, destYOffset, dest);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002303 dest->Release();
2304 }
2305 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002306}
2307
2308IDirect3DSurface9 *TextureCubeMap::getCubeMapSurface(GLenum face, unsigned int level)
2309{
2310 if (mTexture == NULL)
2311 {
2312 UNREACHABLE();
2313 return NULL;
2314 }
2315
2316 IDirect3DSurface9 *surface = NULL;
2317
2318 HRESULT hr = mTexture->GetCubeMapSurface(es2dx::ConvertCubeFace(face), level, &surface);
2319
2320 return (SUCCEEDED(hr)) ? surface : NULL;
2321}
2322
2323void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
2324{
2325 GLsizei size = mImageArray[faceIndex(target)][level].width;
2326
2327 if (xoffset + width > size || yoffset + height > size)
2328 {
2329 return error(GL_INVALID_VALUE);
2330 }
2331
2332 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
2333
2334 if (!renderTarget)
2335 {
2336 ERR("Failed to retrieve the render target.");
2337 return error(GL_OUT_OF_MEMORY);
2338 }
2339
2340 unsigned int faceindex = faceIndex(target);
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002341 redefineTexture(faceindex, level, mImageArray[faceindex][level].format, mImageArray[faceindex][level].width, mImageArray[faceindex][level].height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002342
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002343 if (!mImageArray[faceindex][level].isRenderable() || (!mTexture && !isComplete()))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002344 {
daniel@transgaming.comb6276992011-03-29 00:58:18 +00002345 copyToImage(&mImageArray[faceindex][level], 0, 0, x, y, width, height, renderTarget);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002346 }
2347 else
2348 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00002349 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002350 {
2351 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002352 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00002353
2354 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002355
2356 if (level < levelCount())
2357 {
2358 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
2359 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
2360 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
2361 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
2362 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
2363
2364 GLint destYOffset = transformPixelYOffset(yoffset, height, mImageArray[faceindex][level].width);
2365
2366 IDirect3DSurface9 *dest = getCubeMapSurface(target, level);
2367
daniel@transgaming.comeef864a2011-04-22 11:33:27 +00002368 getBlitter()->copy(source->getRenderTarget(), sourceRect, mImageArray[0][0].format, xoffset, destYOffset, dest);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002369 dest->Release();
2370 }
2371 }
2372}
2373
2374bool TextureCubeMap::isCubeComplete() const
2375{
2376 if (mImageArray[0][0].width == 0)
2377 {
2378 return false;
2379 }
2380
2381 for (unsigned int f = 1; f < 6; f++)
2382 {
2383 if (mImageArray[f][0].width != mImageArray[0][0].width
2384 || mImageArray[f][0].format != mImageArray[0][0].format)
2385 {
2386 return false;
2387 }
2388 }
2389
2390 return true;
2391}
2392
2393void TextureCubeMap::generateMipmaps()
2394{
2395 if (!isPow2(mImageArray[0][0].width) || !isCubeComplete())
2396 {
2397 return error(GL_INVALID_OPERATION);
2398 }
2399
2400 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
2401 unsigned int q = log2(mImageArray[0][0].width);
2402 for (unsigned int f = 0; f < 6; f++)
2403 {
2404 for (unsigned int i = 1; i <= q; i++)
2405 {
2406 if (mImageArray[f][i].surface != NULL)
2407 {
2408 mImageArray[f][i].surface->Release();
2409 mImageArray[f][i].surface = NULL;
2410 }
2411
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002412 mImageArray[f][i].width = std::max(mImageArray[f][0].width >> i, 1);
2413 mImageArray[f][i].height = mImageArray[f][i].width;
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00002414 mImageArray[f][i].format = mImageArray[f][0].format;
2415 mImageArray[f][i].type = mImageArray[f][0].type;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002416 }
2417 }
2418
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002419 if (mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002420 {
2421 if (mTexture == NULL)
2422 {
2423 return;
2424 }
2425
2426 for (unsigned int f = 0; f < 6; f++)
2427 {
2428 for (unsigned int i = 1; i <= q; i++)
2429 {
2430 IDirect3DSurface9 *upper = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i-1);
2431 IDirect3DSurface9 *lower = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i);
2432
2433 if (upper != NULL && lower != NULL)
2434 {
2435 getBlitter()->boxFilter(upper, lower);
2436 }
2437
2438 if (upper != NULL) upper->Release();
2439 if (lower != NULL) lower->Release();
daniel@transgaming.com61208202011-03-21 16:38:50 +00002440
2441 mImageArray[f][i].dirty = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002442 }
2443 }
2444 }
2445 else
2446 {
2447 for (unsigned int f = 0; f < 6; f++)
2448 {
2449 for (unsigned int i = 1; i <= q; i++)
2450 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00002451 createSurface(&mImageArray[f][i]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002452 if (mImageArray[f][i].surface == NULL)
2453 {
2454 return error(GL_OUT_OF_MEMORY);
2455 }
2456
2457 if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[f][i].surface, NULL, NULL, mImageArray[f][i - 1].surface, NULL, NULL, D3DX_FILTER_BOX, 0)))
2458 {
2459 ERR(" failed to load filter %d to %d.", i - 1, i);
2460 }
2461
2462 mImageArray[f][i].dirty = true;
2463 }
2464 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002465 }
2466}
2467
2468Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target)
2469{
2470 if (!IsCubemapTextureTarget(target))
2471 {
2472 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
2473 }
2474
2475 unsigned int face = faceIndex(target);
2476
2477 if (mFaceProxies[face].get() == NULL)
2478 {
2479 mFaceProxies[face].set(new Renderbuffer(id(), new Colorbuffer(this, target)));
2480 }
2481
2482 return mFaceProxies[face].get();
2483}
2484
2485IDirect3DSurface9 *TextureCubeMap::getRenderTarget(GLenum target)
2486{
2487 ASSERT(IsCubemapTextureTarget(target));
2488
daniel@transgaming.com61208202011-03-21 16:38:50 +00002489 if (!mIsRenderable)
2490 {
2491 convertToRenderTarget();
2492 }
2493
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002494 if (mTexture == NULL)
2495 {
2496 return NULL;
2497 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00002498
2499 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002500
2501 IDirect3DSurface9 *renderTarget = NULL;
2502 mTexture->GetCubeMapSurface(es2dx::ConvertCubeFace(target), 0, &renderTarget);
2503
2504 return renderTarget;
2505}
2506
2507}