blob: 0be3beea704e2ffff4ad3c02a80ad0f539f060eb [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
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000887 if (!image->surface)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000888 {
daniel@transgaming.com61208202011-03-21 16:38:50 +0000889 createSurface(image);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000890 }
891
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000892 if (pixels != NULL && image->surface != NULL)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000893 {
894 D3DSURFACE_DESC description;
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000895 image->surface->GetDesc(&description);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000896
897 D3DLOCKED_RECT locked;
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000898 HRESULT result = image->surface->LockRect(&locked, NULL, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000899
900 ASSERT(SUCCEEDED(result));
901
902 if (SUCCEEDED(result))
903 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000904 loadImageData(xoffset, transformPixelYOffset(yoffset, height, image->height), width, height, format, type, unpackAlignment, pixels, locked.Pitch, locked.pBits, &description);
905 image->surface->UnlockRect();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000906 }
907
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000908 image->dirty = true;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +0000909 mDirtyImage = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000910 }
911
912 return true;
913}
914
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000915bool 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 +0000916{
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000917 if (width + xoffset > image->width || height + yoffset > image->height)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000918 {
919 error(GL_INVALID_VALUE);
920 return false;
921 }
922
923 if (format != getInternalFormat())
924 {
925 error(GL_INVALID_OPERATION);
926 return false;
927 }
928
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000929 if (!image->surface)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000930 {
daniel@transgaming.com61208202011-03-21 16:38:50 +0000931 createSurface(image);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000932 }
933
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000934 if (pixels != NULL && image->surface != NULL)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000935 {
936 RECT updateRegion;
937 updateRegion.left = xoffset;
938 updateRegion.right = xoffset + width;
939 updateRegion.bottom = yoffset + height;
940 updateRegion.top = yoffset;
941
942 D3DLOCKED_RECT locked;
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000943 HRESULT result = image->surface->LockRect(&locked, &updateRegion, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000944
945 ASSERT(SUCCEEDED(result));
946
947 if (SUCCEEDED(result))
948 {
949 int inputPitch = ComputeCompressedPitch(width, format);
950 int inputSize = ComputeCompressedSize(width, height, format);
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000951 loadCompressedImageData(xoffset, transformPixelYOffset(yoffset, height, image->height), width, height, -inputPitch, static_cast<const char*>(pixels) + inputSize - inputPitch, locked.Pitch, locked.pBits);
952 image->surface->UnlockRect();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000953 }
954
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000955 image->dirty = true;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +0000956 mDirtyImage = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000957 }
958
959 return true;
960}
961
daniel@transgaming.comb6276992011-03-29 00:58:18 +0000962// This implements glCopyTex[Sub]Image2D for non-renderable internal texture formats and incomplete textures
963void 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 +0000964{
daniel@transgaming.comb6276992011-03-29 00:58:18 +0000965 if (!image->surface)
966 {
967 createSurface(image);
968
969 if (!image->surface)
970 {
971 ERR("Failed to create an image surface.");
972 return error(GL_OUT_OF_MEMORY);
973 }
974 }
975
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000976 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.comb6276992011-03-29 00:58:18 +0000977 IDirect3DSurface9 *renderTargetData = NULL;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000978 D3DSURFACE_DESC description;
979 renderTarget->GetDesc(&description);
980
daniel@transgaming.comb6276992011-03-29 00:58:18 +0000981 HRESULT result = device->CreateOffscreenPlainSurface(description.Width, description.Height, description.Format, D3DPOOL_SYSTEMMEM, &renderTargetData, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000982
daniel@transgaming.comb6276992011-03-29 00:58:18 +0000983 if (FAILED(result))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000984 {
985 ERR("Could not create matching destination surface.");
986 return error(GL_OUT_OF_MEMORY);
987 }
988
daniel@transgaming.comb6276992011-03-29 00:58:18 +0000989 result = device->GetRenderTargetData(renderTarget, renderTargetData);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000990
daniel@transgaming.comb6276992011-03-29 00:58:18 +0000991 if (FAILED(result))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000992 {
993 ERR("GetRenderTargetData unexpectedly failed.");
daniel@transgaming.comb6276992011-03-29 00:58:18 +0000994 renderTargetData->Release();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000995 return error(GL_OUT_OF_MEMORY);
996 }
997
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000998 RECT sourceRect = transformPixelRect(x, y, width, height, description.Height);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000999 int destYOffset = transformPixelYOffset(yoffset, height, image->height);
1000 RECT destRect = {xoffset, destYOffset, xoffset + width, destYOffset + height};
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001001
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001002 if (image->isRenderable())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001003 {
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001004 result = D3DXLoadSurfaceFromSurface(image->surface, NULL, &destRect, renderTargetData, NULL, &sourceRect, D3DX_FILTER_BOX, 0);
1005
1006 if (FAILED(result))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001007 {
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001008 ERR("Copying surfaces unexpectedly failed.");
1009 renderTargetData->Release();
1010 return error(GL_OUT_OF_MEMORY);
1011 }
1012 }
1013 else
1014 {
1015 D3DLOCKED_RECT sourceLock = {0};
1016 result = renderTargetData->LockRect(&sourceLock, &sourceRect, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001017
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001018 if (FAILED(result))
1019 {
1020 ERR("Failed to lock the source surface (rectangle might be invalid).");
1021 renderTargetData->Release();
1022 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001023 }
1024
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001025 D3DLOCKED_RECT destLock = {0};
1026 result = image->surface->LockRect(&destLock, &destRect, 0);
1027
1028 if (FAILED(result))
1029 {
1030 ERR("Failed to lock the destination surface (rectangle might be invalid).");
1031 renderTargetData->UnlockRect();
1032 renderTargetData->Release();
1033 return error(GL_OUT_OF_MEMORY);
1034 }
1035
1036 if (destLock.pBits && sourceLock.pBits)
1037 {
1038 unsigned char *source = (unsigned char*)sourceLock.pBits;
1039 unsigned char *dest = (unsigned char*)destLock.pBits;
1040
1041 switch (description.Format)
1042 {
1043 case D3DFMT_X8R8G8B8:
1044 case D3DFMT_A8R8G8B8:
1045 switch(image->getD3DFormat())
1046 {
1047 case D3DFMT_L8:
1048 for(int y = 0; y < height; y++)
1049 {
1050 for(int x = 0; x < width; x++)
1051 {
1052 dest[x] = source[x * 4 + 2];
1053 }
1054
1055 source += sourceLock.Pitch;
1056 dest += destLock.Pitch;
1057 }
1058 break;
1059 case D3DFMT_A8L8:
1060 for(int y = 0; y < height; y++)
1061 {
1062 for(int x = 0; x < width; x++)
1063 {
1064 dest[x * 2 + 0] = source[x * 4 + 2];
1065 dest[x * 2 + 1] = source[x * 4 + 3];
1066 }
1067
1068 source += sourceLock.Pitch;
1069 dest += destLock.Pitch;
1070 }
1071 break;
1072 default:
1073 UNREACHABLE();
1074 }
1075 break;
1076 case D3DFMT_R5G6B5:
1077 switch(image->getD3DFormat())
1078 {
1079 case D3DFMT_L8:
1080 for(int y = 0; y < height; y++)
1081 {
1082 for(int x = 0; x < width; x++)
1083 {
1084 unsigned char red = source[x * 2 + 1] & 0xF8;
1085 dest[x] = red | (red >> 5);
1086 }
1087
1088 source += sourceLock.Pitch;
1089 dest += destLock.Pitch;
1090 }
1091 break;
1092 default:
1093 UNREACHABLE();
1094 }
1095 break;
1096 case D3DFMT_A1R5G5B5:
1097 switch(image->getD3DFormat())
1098 {
1099 case D3DFMT_L8:
1100 for(int y = 0; y < height; y++)
1101 {
1102 for(int x = 0; x < width; x++)
1103 {
1104 unsigned char red = source[x * 2 + 1] & 0x7C;
1105 dest[x] = (red << 1) | (red >> 4);
1106 }
1107
1108 source += sourceLock.Pitch;
1109 dest += destLock.Pitch;
1110 }
1111 break;
1112 case D3DFMT_A8L8:
1113 for(int y = 0; y < height; y++)
1114 {
1115 for(int x = 0; x < width; x++)
1116 {
1117 unsigned char red = source[x * 2 + 1] & 0x7C;
1118 dest[x * 2 + 0] = (red << 1) | (red >> 4);
1119 dest[x * 2 + 1] = (signed char)source[x * 2 + 1] >> 7;
1120 }
1121
1122 source += sourceLock.Pitch;
1123 dest += destLock.Pitch;
1124 }
1125 break;
1126 default:
1127 UNREACHABLE();
1128 }
1129 break;
1130 default:
1131 UNREACHABLE();
1132 }
1133 }
1134
1135 image->surface->UnlockRect();
1136 renderTargetData->UnlockRect();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001137 }
1138
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001139 renderTargetData->Release();
1140
1141 image->dirty = true;
1142 mDirtyImage = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001143}
1144
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001145IDirect3DBaseTexture9 *Texture::getTexture()
1146{
1147 if (!isComplete())
1148 {
1149 return NULL;
1150 }
1151
daniel@transgaming.comaed18322011-03-21 16:38:13 +00001152 if (!getBaseTexture())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001153 {
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001154 createTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001155 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001156
daniel@transgaming.comc50edcb2011-03-21 16:38:40 +00001157 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001158
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001159 return getBaseTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001160}
1161
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00001162bool Texture::isDirtyParameter() const
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001163{
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00001164 return mDirtyParameter;
1165}
1166
1167bool Texture::isDirtyImage() const
1168{
1169 return mDirtyImage;
daniel@transgaming.com38e76e52011-03-21 16:39:10 +00001170}
1171
1172void Texture::resetDirty()
1173{
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00001174 mDirtyParameter = false;
1175 mDirtyImage = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001176}
1177
daniel@transgaming.coma9eb5da2011-03-21 16:39:16 +00001178unsigned int Texture::getSerial() const
1179{
1180 return mSerial;
1181}
1182
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001183GLint Texture::creationLevels(GLsizei width, GLsizei height, GLint maxlevel) const
1184{
1185 if (isPow2(width) && isPow2(height))
1186 {
1187 return maxlevel;
1188 }
1189 else
1190 {
1191 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
1192 return 1;
1193 }
1194}
1195
1196GLint Texture::creationLevels(GLsizei size, GLint maxlevel) const
1197{
1198 return creationLevels(size, size, maxlevel);
1199}
1200
1201int Texture::levelCount() const
1202{
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001203 return getBaseTexture() ? getBaseTexture()->GetLevelCount() : 0;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001204}
1205
daniel@transgaming.coma9eb5da2011-03-21 16:39:16 +00001206unsigned int Texture::issueSerial()
1207{
1208 return mCurrentSerial++;
1209}
1210
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001211Texture2D::Texture2D(GLuint id) : Texture(id)
1212{
1213 mTexture = NULL;
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001214 mSurface = NULL;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001215}
1216
1217Texture2D::~Texture2D()
1218{
1219 mColorbufferProxy.set(NULL);
1220
1221 if (mTexture)
1222 {
1223 mTexture->Release();
1224 mTexture = NULL;
1225 }
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001226
1227 if (mSurface)
1228 {
1229 mSurface->setBoundTexture(NULL);
1230 mSurface = NULL;
1231 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001232}
1233
1234GLenum Texture2D::getTarget() const
1235{
1236 return GL_TEXTURE_2D;
1237}
1238
daniel@transgaming.com61208202011-03-21 16:38:50 +00001239GLsizei Texture2D::getWidth() const
1240{
1241 return mImageArray[0].width;
1242}
1243
1244GLsizei Texture2D::getHeight() const
1245{
1246 return mImageArray[0].height;
1247}
1248
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001249GLenum Texture2D::getInternalFormat() const
1250{
1251 return mImageArray[0].format;
1252}
1253
daniel@transgaming.com61208202011-03-21 16:38:50 +00001254GLenum Texture2D::getType() const
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001255{
daniel@transgaming.com61208202011-03-21 16:38:50 +00001256 return mImageArray[0].type;
1257}
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001258
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001259D3DFORMAT Texture2D::getD3DFormat() const
1260{
1261 return mImageArray[0].getD3DFormat();
1262}
1263
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001264void Texture2D::redefineTexture(GLint level, GLenum format, GLsizei width, GLsizei height, GLenum type, bool forceRedefine)
daniel@transgaming.com61208202011-03-21 16:38:50 +00001265{
daniel@transgaming.com94a4f032011-03-21 16:38:55 +00001266 GLsizei textureWidth = mImageArray[0].width;
1267 GLsizei textureHeight = mImageArray[0].height;
1268 GLenum textureFormat = mImageArray[0].format;
1269 GLenum textureType = mImageArray[0].type;
1270
daniel@transgaming.com61208202011-03-21 16:38:50 +00001271 mImageArray[level].width = width;
1272 mImageArray[level].height = height;
1273 mImageArray[level].format = format;
1274 mImageArray[level].type = type;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001275
daniel@transgaming.com61208202011-03-21 16:38:50 +00001276 if (!mTexture)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001277 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001278 return;
1279 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001280
daniel@transgaming.com94a4f032011-03-21 16:38:55 +00001281 bool widthOkay = (textureWidth >> level == width) || (textureWidth >> level == 0 && width == 1);
1282 bool heightOkay = (textureHeight >> level == height) || (textureHeight >> level == 0 && height == 1);
1283 bool textureOkay = (widthOkay && heightOkay && textureFormat == format && textureType == type);
daniel@transgaming.com61208202011-03-21 16:38:50 +00001284
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001285 if (!textureOkay || forceRedefine || mSurface) // Purge all the levels and the texture.
daniel@transgaming.com61208202011-03-21 16:38:50 +00001286 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001287 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1288 {
1289 if (mImageArray[i].surface != NULL)
1290 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001291 mImageArray[i].surface->Release();
1292 mImageArray[i].surface = NULL;
daniel@transgaming.com61208202011-03-21 16:38:50 +00001293 mImageArray[i].dirty = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001294 }
1295 }
1296
1297 if (mTexture != NULL)
1298 {
1299 mTexture->Release();
1300 mTexture = NULL;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00001301 mDirtyImage = true;
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001302 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001303 }
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001304
1305 if (mSurface)
1306 {
1307 mSurface->setBoundTexture(NULL);
1308 mSurface = NULL;
1309 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001310 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001311}
1312
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001313void 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 +00001314{
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001315 redefineTexture(level, format, width, height, type, false);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001316
daniel@transgaming.com61208202011-03-21 16:38:50 +00001317 Texture::setImage(unpackAlignment, pixels, &mImageArray[level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001318}
1319
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001320void Texture2D::bindTexImage(egl::Surface *surface)
1321{
1322 GLenum format;
1323
1324 switch(surface->getFormat())
1325 {
1326 case D3DFMT_A8R8G8B8:
1327 format = GL_RGBA;
1328 break;
1329 case D3DFMT_X8R8G8B8:
1330 format = GL_RGB;
1331 break;
1332 default:
1333 UNIMPLEMENTED();
1334 return;
1335 }
1336
1337 redefineTexture(0, format, surface->getWidth(), surface->getHeight(), GL_UNSIGNED_BYTE, true);
1338
1339 IDirect3DTexture9 *texture = surface->getOffscreenTexture();
1340
1341 mTexture = texture;
1342 mDirtyImage = true;
1343 mIsRenderable = true;
1344 mSurface = surface;
1345 mSurface->setBoundTexture(this);
1346}
1347
1348void Texture2D::releaseTexImage()
1349{
1350 redefineTexture(0, GL_RGB, 0, 0, GL_UNSIGNED_BYTE, true);
1351}
1352
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001353void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001354{
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001355 redefineTexture(level, format, width, height, GL_UNSIGNED_BYTE, false);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001356
daniel@transgaming.com61208202011-03-21 16:38:50 +00001357 Texture::setCompressedImage(imageSize, pixels, &mImageArray[level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001358}
1359
1360void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1361{
1362 ASSERT(mImageArray[level].surface != NULL);
1363
1364 if (level < levelCount())
1365 {
1366 IDirect3DSurface9 *destLevel = NULL;
1367 HRESULT result = mTexture->GetSurfaceLevel(level, &destLevel);
1368
1369 ASSERT(SUCCEEDED(result));
1370
1371 if (SUCCEEDED(result))
1372 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001373 Image *image = &mImageArray[level];
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001374
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001375 RECT sourceRect = transformPixelRect(xoffset, yoffset, width, height, image->height);;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001376
1377 POINT destPoint;
1378 destPoint.x = sourceRect.left;
1379 destPoint.y = sourceRect.top;
1380
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001381 result = getDevice()->UpdateSurface(image->surface, &sourceRect, destLevel, &destPoint);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001382 ASSERT(SUCCEEDED(result));
1383
1384 destLevel->Release();
1385
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001386 image->dirty = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001387 }
1388 }
1389}
1390
1391void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1392{
1393 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[level]))
1394 {
1395 commitRect(level, xoffset, yoffset, width, height);
1396 }
1397}
1398
1399void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1400{
1401 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[level]))
1402 {
1403 commitRect(level, xoffset, yoffset, width, height);
1404 }
1405}
1406
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001407void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001408{
1409 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
1410
1411 if (!renderTarget)
1412 {
1413 ERR("Failed to retrieve the render target.");
1414 return error(GL_OUT_OF_MEMORY);
1415 }
1416
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001417 redefineTexture(level, format, width, height, GL_UNSIGNED_BYTE, false);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001418
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001419 if (!mImageArray[level].isRenderable())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001420 {
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001421 copyToImage(&mImageArray[level], 0, 0, x, y, width, height, renderTarget);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001422 }
1423 else
1424 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001425 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001426 {
1427 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001428 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00001429
1430 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001431
1432 if (width != 0 && height != 0 && level < levelCount())
1433 {
1434 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
1435 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
1436 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
1437 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
1438 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
1439
1440 IDirect3DSurface9 *dest;
1441 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
1442
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001443 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, format, 0, 0, dest);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001444 dest->Release();
1445 }
1446 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001447}
1448
1449void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1450{
1451 if (xoffset + width > mImageArray[level].width || yoffset + height > mImageArray[level].height)
1452 {
1453 return error(GL_INVALID_VALUE);
1454 }
1455
1456 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
1457
1458 if (!renderTarget)
1459 {
1460 ERR("Failed to retrieve the render target.");
1461 return error(GL_OUT_OF_MEMORY);
1462 }
1463
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001464 redefineTexture(level, mImageArray[level].format, mImageArray[level].width, mImageArray[level].height, GL_UNSIGNED_BYTE, false);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001465
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001466 if (!mImageArray[level].isRenderable() || (!mTexture && !isComplete()))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001467 {
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001468 copyToImage(&mImageArray[level], xoffset, yoffset, x, y, width, height, renderTarget);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001469 }
1470 else
1471 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001472 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001473 {
1474 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001475 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00001476
1477 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001478
1479 if (level < levelCount())
1480 {
1481 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
1482 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
1483 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
1484 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
1485 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
1486
1487 GLint destYOffset = transformPixelYOffset(yoffset, height, mImageArray[level].height);
1488
1489 IDirect3DSurface9 *dest;
1490 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
1491
1492 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0].format, xoffset, destYOffset, dest);
1493 dest->Release();
1494 }
1495 }
1496}
1497
1498// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1499bool Texture2D::isComplete() const
1500{
1501 GLsizei width = mImageArray[0].width;
1502 GLsizei height = mImageArray[0].height;
1503
1504 if (width <= 0 || height <= 0)
1505 {
1506 return false;
1507 }
1508
1509 bool mipmapping = false;
1510
1511 switch (mMinFilter)
1512 {
1513 case GL_NEAREST:
1514 case GL_LINEAR:
1515 mipmapping = false;
1516 break;
1517 case GL_NEAREST_MIPMAP_NEAREST:
1518 case GL_LINEAR_MIPMAP_NEAREST:
1519 case GL_NEAREST_MIPMAP_LINEAR:
1520 case GL_LINEAR_MIPMAP_LINEAR:
1521 mipmapping = true;
1522 break;
1523 default: UNREACHABLE();
1524 }
1525
1526 if ((getInternalFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) ||
1527 (getInternalFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter()))
1528 {
1529 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
1530 {
1531 return false;
1532 }
1533 }
1534
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001535 if ((getWrapS() != GL_CLAMP_TO_EDGE && !isPow2(width))
1536 || (getWrapT() != GL_CLAMP_TO_EDGE && !isPow2(height)))
1537 {
1538 return false;
1539 }
1540
1541 if (mipmapping)
1542 {
1543 if (!isPow2(width) || !isPow2(height))
1544 {
1545 return false;
1546 }
1547
1548 int q = log2(std::max(width, height));
1549
1550 for (int level = 1; level <= q; level++)
1551 {
1552 if (mImageArray[level].format != mImageArray[0].format)
1553 {
1554 return false;
1555 }
1556
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00001557 if (mImageArray[level].type != mImageArray[0].type)
1558 {
1559 return false;
1560 }
1561
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001562 if (mImageArray[level].width != std::max(1, width >> level))
1563 {
1564 return false;
1565 }
1566
1567 if (mImageArray[level].height != std::max(1, height >> level))
1568 {
1569 return false;
1570 }
1571 }
1572 }
1573
1574 return true;
1575}
1576
1577bool Texture2D::isCompressed() const
1578{
1579 return IsCompressed(getInternalFormat());
1580}
1581
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001582IDirect3DBaseTexture9 *Texture2D::getBaseTexture() const
1583{
1584 return mTexture;
1585}
1586
1587// Constructs a Direct3D 9 texture resource from the texture images
1588void Texture2D::createTexture()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001589{
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001590 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001591 D3DFORMAT format = mImageArray[0].getD3DFormat();
daniel@transgaming.com61208202011-03-21 16:38:50 +00001592 GLint levels = creationLevels(mImageArray[0].width, mImageArray[0].height, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001593
daniel@transgaming.com61208202011-03-21 16:38:50 +00001594 IDirect3DTexture9 *texture = NULL;
1595 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 +00001596
1597 if (FAILED(result))
1598 {
1599 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001600 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001601 }
1602
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001603 if (mTexture)
1604 {
1605 mTexture->Release();
1606 }
1607
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001608 mTexture = texture;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00001609 mDirtyImage = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00001610 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001611}
1612
1613void Texture2D::updateTexture()
1614{
1615 IDirect3DDevice9 *device = getDevice();
1616
1617 int levels = levelCount();
1618
1619 for (int level = 0; level < levels; level++)
1620 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001621 if (mImageArray[level].surface && mImageArray[level].dirty)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001622 {
1623 IDirect3DSurface9 *levelSurface = NULL;
1624 HRESULT result = mTexture->GetSurfaceLevel(level, &levelSurface);
1625
1626 ASSERT(SUCCEEDED(result));
1627
1628 if (SUCCEEDED(result))
1629 {
1630 result = device->UpdateSurface(mImageArray[level].surface, NULL, levelSurface, NULL);
1631 ASSERT(SUCCEEDED(result));
1632
1633 levelSurface->Release();
1634
1635 mImageArray[level].dirty = false;
1636 }
1637 }
1638 }
1639}
1640
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001641void Texture2D::convertToRenderTarget()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001642{
1643 IDirect3DTexture9 *texture = NULL;
1644
daniel@transgaming.com61208202011-03-21 16:38:50 +00001645 if (mImageArray[0].width != 0 && mImageArray[0].height != 0)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001646 {
1647 egl::Display *display = getDisplay();
1648 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001649 D3DFORMAT format = mImageArray[0].getD3DFormat();
daniel@transgaming.com61208202011-03-21 16:38:50 +00001650 GLint levels = creationLevels(mImageArray[0].width, mImageArray[0].height, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001651
daniel@transgaming.com61208202011-03-21 16:38:50 +00001652 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 +00001653
1654 if (FAILED(result))
1655 {
1656 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001657 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001658 }
1659
1660 if (mTexture != NULL)
1661 {
1662 int levels = levelCount();
1663 for (int i = 0; i < levels; i++)
1664 {
1665 IDirect3DSurface9 *source;
1666 result = mTexture->GetSurfaceLevel(i, &source);
1667
1668 if (FAILED(result))
1669 {
1670 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1671
1672 texture->Release();
1673
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001674 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001675 }
1676
1677 IDirect3DSurface9 *dest;
1678 result = texture->GetSurfaceLevel(i, &dest);
1679
1680 if (FAILED(result))
1681 {
1682 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1683
1684 texture->Release();
1685 source->Release();
1686
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001687 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001688 }
1689
1690 display->endScene();
1691 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
1692
1693 if (FAILED(result))
1694 {
1695 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1696
1697 texture->Release();
1698 source->Release();
1699 dest->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 source->Release();
1705 dest->Release();
1706 }
1707 }
1708 }
1709
1710 if (mTexture != NULL)
1711 {
1712 mTexture->Release();
1713 }
1714
1715 mTexture = texture;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00001716 mDirtyImage = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00001717 mIsRenderable = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001718}
1719
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001720void Texture2D::generateMipmaps()
1721{
1722 if (!isPow2(mImageArray[0].width) || !isPow2(mImageArray[0].height))
1723 {
1724 return error(GL_INVALID_OPERATION);
1725 }
1726
1727 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
daniel@transgaming.com61208202011-03-21 16:38:50 +00001728 unsigned int q = log2(std::max(mImageArray[0].width, mImageArray[0].height));
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001729 for (unsigned int i = 1; i <= q; i++)
1730 {
1731 if (mImageArray[i].surface != NULL)
1732 {
1733 mImageArray[i].surface->Release();
1734 mImageArray[i].surface = NULL;
1735 }
1736
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001737 mImageArray[i].width = std::max(mImageArray[0].width >> i, 1);
1738 mImageArray[i].height = std::max(mImageArray[0].height >> i, 1);
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00001739 mImageArray[i].format = mImageArray[0].format;
1740 mImageArray[i].type = mImageArray[0].type;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001741 }
1742
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001743 if (mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001744 {
1745 if (mTexture == NULL)
1746 {
1747 ERR(" failed because mTexture was null.");
1748 return;
1749 }
1750
1751 for (unsigned int i = 1; i <= q; i++)
1752 {
1753 IDirect3DSurface9 *upper = NULL;
1754 IDirect3DSurface9 *lower = NULL;
1755
1756 mTexture->GetSurfaceLevel(i-1, &upper);
1757 mTexture->GetSurfaceLevel(i, &lower);
1758
1759 if (upper != NULL && lower != NULL)
1760 {
1761 getBlitter()->boxFilter(upper, lower);
1762 }
1763
1764 if (upper != NULL) upper->Release();
1765 if (lower != NULL) lower->Release();
daniel@transgaming.com61208202011-03-21 16:38:50 +00001766
1767 mImageArray[i].dirty = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001768 }
1769 }
1770 else
1771 {
1772 for (unsigned int i = 1; i <= q; i++)
1773 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001774 createSurface(&mImageArray[i]);
1775
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001776 if (mImageArray[i].surface == NULL)
1777 {
1778 return error(GL_OUT_OF_MEMORY);
1779 }
1780
1781 if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[i].surface, NULL, NULL, mImageArray[i - 1].surface, NULL, NULL, D3DX_FILTER_BOX, 0)))
1782 {
1783 ERR(" failed to load filter %d to %d.", i - 1, i);
1784 }
1785
1786 mImageArray[i].dirty = true;
1787 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001788 }
1789}
1790
1791Renderbuffer *Texture2D::getRenderbuffer(GLenum target)
1792{
1793 if (target != GL_TEXTURE_2D)
1794 {
1795 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
1796 }
1797
1798 if (mColorbufferProxy.get() == NULL)
1799 {
1800 mColorbufferProxy.set(new Renderbuffer(id(), new Colorbuffer(this, target)));
1801 }
1802
1803 return mColorbufferProxy.get();
1804}
1805
1806IDirect3DSurface9 *Texture2D::getRenderTarget(GLenum target)
1807{
1808 ASSERT(target == GL_TEXTURE_2D);
1809
daniel@transgaming.com61208202011-03-21 16:38:50 +00001810 if (!mIsRenderable)
1811 {
1812 convertToRenderTarget();
1813 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001814
1815 if (mTexture == NULL)
1816 {
1817 return NULL;
1818 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00001819
1820 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001821
1822 IDirect3DSurface9 *renderTarget = NULL;
1823 mTexture->GetSurfaceLevel(0, &renderTarget);
1824
1825 return renderTarget;
1826}
1827
1828TextureCubeMap::TextureCubeMap(GLuint id) : Texture(id)
1829{
1830 mTexture = NULL;
1831}
1832
1833TextureCubeMap::~TextureCubeMap()
1834{
1835 for (int i = 0; i < 6; i++)
1836 {
1837 mFaceProxies[i].set(NULL);
1838 }
1839
1840 if (mTexture)
1841 {
1842 mTexture->Release();
1843 mTexture = NULL;
1844 }
1845}
1846
1847GLenum TextureCubeMap::getTarget() const
1848{
1849 return GL_TEXTURE_CUBE_MAP;
1850}
1851
daniel@transgaming.com61208202011-03-21 16:38:50 +00001852GLsizei TextureCubeMap::getWidth() const
1853{
1854 return mImageArray[0][0].width;
1855}
1856
1857GLsizei TextureCubeMap::getHeight() const
1858{
1859 return mImageArray[0][0].height;
1860}
1861
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001862GLenum TextureCubeMap::getInternalFormat() const
1863{
1864 return mImageArray[0][0].format;
1865}
1866
daniel@transgaming.com61208202011-03-21 16:38:50 +00001867GLenum TextureCubeMap::getType() const
1868{
1869 return mImageArray[0][0].type;
1870}
1871
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001872D3DFORMAT TextureCubeMap::getD3DFormat() const
1873{
1874 return mImageArray[0][0].getD3DFormat();
1875}
1876
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001877void 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 +00001878{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001879 setImage(0, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001880}
1881
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001882void 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 +00001883{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001884 setImage(1, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001885}
1886
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001887void 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 +00001888{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001889 setImage(2, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001890}
1891
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001892void 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 +00001893{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001894 setImage(3, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001895}
1896
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001897void 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 +00001898{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001899 setImage(4, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001900}
1901
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001902void 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 +00001903{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001904 setImage(5, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001905}
1906
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001907void 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 +00001908{
daniel@transgaming.com61208202011-03-21 16:38:50 +00001909 redefineTexture(faceIndex(face), level, format, width, height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001910
daniel@transgaming.com61208202011-03-21 16:38:50 +00001911 Texture::setCompressedImage(imageSize, pixels, &mImageArray[faceIndex(face)][level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001912}
1913
1914void TextureCubeMap::commitRect(GLenum faceTarget, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1915{
1916 int face = faceIndex(faceTarget);
1917 ASSERT(mImageArray[face][level].surface != NULL);
1918
1919 if (level < levelCount())
1920 {
1921 IDirect3DSurface9 *destLevel = getCubeMapSurface(faceTarget, level);
1922 ASSERT(destLevel != NULL);
1923
1924 if (destLevel != NULL)
1925 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001926 Image *image = &mImageArray[face][level];
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001927
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001928 RECT sourceRect = transformPixelRect(xoffset, yoffset, width, height, image->height);;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001929
1930 POINT destPoint;
1931 destPoint.x = sourceRect.left;
1932 destPoint.y = sourceRect.top;
1933
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001934 HRESULT result = getDevice()->UpdateSurface(image->surface, &sourceRect, destLevel, &destPoint);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001935 ASSERT(SUCCEEDED(result));
1936
1937 destLevel->Release();
1938
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001939 image->dirty = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001940 }
1941 }
1942}
1943
1944void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1945{
1946 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[faceIndex(target)][level]))
1947 {
1948 commitRect(target, level, xoffset, yoffset, width, height);
1949 }
1950}
1951
1952void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1953{
1954 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[faceIndex(target)][level]))
1955 {
1956 commitRect(target, level, xoffset, yoffset, width, height);
1957 }
1958}
1959
1960// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1961bool TextureCubeMap::isComplete() const
1962{
1963 int size = mImageArray[0][0].width;
1964
1965 if (size <= 0)
1966 {
1967 return false;
1968 }
1969
1970 bool mipmapping;
1971
1972 switch (mMinFilter)
1973 {
1974 case GL_NEAREST:
1975 case GL_LINEAR:
1976 mipmapping = false;
1977 break;
1978 case GL_NEAREST_MIPMAP_NEAREST:
1979 case GL_LINEAR_MIPMAP_NEAREST:
1980 case GL_NEAREST_MIPMAP_LINEAR:
1981 case GL_LINEAR_MIPMAP_LINEAR:
1982 mipmapping = true;
1983 break;
1984 default: UNREACHABLE();
1985 }
1986
1987 for (int face = 0; face < 6; face++)
1988 {
1989 if (mImageArray[face][0].width != size || mImageArray[face][0].height != size)
1990 {
1991 return false;
1992 }
1993 }
1994
1995 if ((getInternalFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) ||
1996 (getInternalFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter()))
1997 {
1998 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
1999 {
2000 return false;
2001 }
2002 }
2003
2004 if (mipmapping)
2005 {
2006 if (!isPow2(size) && (getWrapS() != GL_CLAMP_TO_EDGE || getWrapT() != GL_CLAMP_TO_EDGE))
2007 {
2008 return false;
2009 }
2010
2011 int q = log2(size);
2012
2013 for (int face = 0; face < 6; face++)
2014 {
2015 for (int level = 1; level <= q; level++)
2016 {
2017 if (mImageArray[face][level].format != mImageArray[0][0].format)
2018 {
2019 return false;
2020 }
2021
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00002022 if (mImageArray[face][level].type != mImageArray[0][0].type)
2023 {
2024 return false;
2025 }
2026
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002027 if (mImageArray[face][level].width != std::max(1, size >> level))
2028 {
2029 return false;
2030 }
2031
2032 ASSERT(mImageArray[face][level].height == mImageArray[face][level].width);
2033 }
2034 }
2035 }
2036
2037 return true;
2038}
2039
2040bool TextureCubeMap::isCompressed() const
2041{
2042 return IsCompressed(getInternalFormat());
2043}
2044
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002045IDirect3DBaseTexture9 *TextureCubeMap::getBaseTexture() const
2046{
2047 return mTexture;
2048}
2049
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002050// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002051void TextureCubeMap::createTexture()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002052{
2053 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002054 D3DFORMAT format = mImageArray[0][0].getD3DFormat();
daniel@transgaming.com61208202011-03-21 16:38:50 +00002055 GLint levels = creationLevels(mImageArray[0][0].width, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002056
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00002057 IDirect3DCubeTexture9 *texture = NULL;
daniel@transgaming.com61208202011-03-21 16:38:50 +00002058 HRESULT result = device->CreateCubeTexture(mImageArray[0][0].width, levels, 0, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002059
2060 if (FAILED(result))
2061 {
2062 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002063 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002064 }
2065
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002066 if (mTexture)
2067 {
2068 mTexture->Release();
2069 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002070
2071 mTexture = texture;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00002072 mDirtyImage = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00002073 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002074}
2075
2076void TextureCubeMap::updateTexture()
2077{
2078 IDirect3DDevice9 *device = getDevice();
2079
2080 for (int face = 0; face < 6; face++)
2081 {
2082 int levels = levelCount();
2083 for (int level = 0; level < levels; level++)
2084 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00002085 Image *image = &mImageArray[face][level];
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002086
daniel@transgaming.com61208202011-03-21 16:38:50 +00002087 if (image->surface && image->dirty)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002088 {
2089 IDirect3DSurface9 *levelSurface = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level);
2090 ASSERT(levelSurface != NULL);
2091
2092 if (levelSurface != NULL)
2093 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00002094 HRESULT result = device->UpdateSurface(image->surface, NULL, levelSurface, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002095 ASSERT(SUCCEEDED(result));
2096
2097 levelSurface->Release();
2098
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00002099 image->dirty = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002100 }
2101 }
2102 }
2103 }
2104}
2105
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002106void TextureCubeMap::convertToRenderTarget()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002107{
2108 IDirect3DCubeTexture9 *texture = NULL;
2109
daniel@transgaming.com61208202011-03-21 16:38:50 +00002110 if (mImageArray[0][0].width != 0)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002111 {
2112 egl::Display *display = getDisplay();
2113 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002114 D3DFORMAT format = mImageArray[0][0].getD3DFormat();
daniel@transgaming.com61208202011-03-21 16:38:50 +00002115 GLint levels = creationLevels(mImageArray[0][0].width, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002116
daniel@transgaming.com61208202011-03-21 16:38:50 +00002117 HRESULT result = device->CreateCubeTexture(mImageArray[0][0].width, levels, D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002118
2119 if (FAILED(result))
2120 {
2121 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002122 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002123 }
2124
2125 if (mTexture != NULL)
2126 {
2127 int levels = levelCount();
2128 for (int f = 0; f < 6; f++)
2129 {
2130 for (int i = 0; i < levels; i++)
2131 {
2132 IDirect3DSurface9 *source;
2133 result = mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &source);
2134
2135 if (FAILED(result))
2136 {
2137 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2138
2139 texture->Release();
2140
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002141 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002142 }
2143
2144 IDirect3DSurface9 *dest;
2145 result = texture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &dest);
2146
2147 if (FAILED(result))
2148 {
2149 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2150
2151 texture->Release();
2152 source->Release();
2153
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002154 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002155 }
2156
2157 display->endScene();
2158 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
2159
2160 if (FAILED(result))
2161 {
2162 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2163
2164 texture->Release();
2165 source->Release();
2166 dest->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 }
2172 }
2173 }
2174
2175 if (mTexture != NULL)
2176 {
2177 mTexture->Release();
2178 }
2179
2180 mTexture = texture;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00002181 mDirtyImage = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00002182 mIsRenderable = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002183}
2184
daniel@transgaming.com61208202011-03-21 16:38:50 +00002185void 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 +00002186{
daniel@transgaming.com61208202011-03-21 16:38:50 +00002187 redefineTexture(faceIndex, level, format, width, height, type);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002188
daniel@transgaming.com61208202011-03-21 16:38:50 +00002189 Texture::setImage(unpackAlignment, pixels, &mImageArray[faceIndex][level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002190}
2191
2192unsigned int TextureCubeMap::faceIndex(GLenum face)
2193{
2194 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
2195 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
2196 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
2197 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
2198 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
2199
2200 return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
2201}
2202
daniel@transgaming.com61208202011-03-21 16:38:50 +00002203void TextureCubeMap::redefineTexture(int face, GLint level, GLenum format, GLsizei width, GLsizei height, GLenum type)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002204{
daniel@transgaming.com94a4f032011-03-21 16:38:55 +00002205 GLsizei textureWidth = mImageArray[0][0].width;
2206 GLsizei textureHeight = mImageArray[0][0].height;
2207 GLenum textureFormat = mImageArray[0][0].format;
2208 GLenum textureType = mImageArray[0][0].type;
2209
daniel@transgaming.com61208202011-03-21 16:38:50 +00002210 mImageArray[face][level].width = width;
2211 mImageArray[face][level].height = height;
2212 mImageArray[face][level].format = format;
2213 mImageArray[face][level].type = type;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002214
daniel@transgaming.com61208202011-03-21 16:38:50 +00002215 if (!mTexture)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002216 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00002217 return;
2218 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002219
daniel@transgaming.com94a4f032011-03-21 16:38:55 +00002220 bool sizeOkay = (textureWidth >> level == width);
2221 bool textureOkay = (sizeOkay && textureFormat == format && textureType == type);
daniel@transgaming.com61208202011-03-21 16:38:50 +00002222
2223 if (!textureOkay) // Purge all the levels and the texture.
2224 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002225 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
2226 {
2227 for (int f = 0; f < 6; f++)
2228 {
2229 if (mImageArray[f][i].surface != NULL)
2230 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002231 mImageArray[f][i].surface->Release();
2232 mImageArray[f][i].surface = NULL;
daniel@transgaming.com61208202011-03-21 16:38:50 +00002233 mImageArray[f][i].dirty = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002234 }
2235 }
2236 }
2237
2238 if (mTexture != NULL)
2239 {
2240 mTexture->Release();
2241 mTexture = NULL;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00002242 mDirtyImage = true;
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002243 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002244 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002245 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002246}
2247
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002248void 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 +00002249{
2250 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
2251
2252 if (!renderTarget)
2253 {
2254 ERR("Failed to retrieve the render target.");
2255 return error(GL_OUT_OF_MEMORY);
2256 }
2257
2258 unsigned int faceindex = faceIndex(target);
daniel@transgaming.com61208202011-03-21 16:38:50 +00002259 redefineTexture(faceindex, level, format, width, height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002260
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002261 if (!mImageArray[faceindex][level].isRenderable())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002262 {
daniel@transgaming.comb6276992011-03-29 00:58:18 +00002263 copyToImage(&mImageArray[faceindex][level], 0, 0, x, y, width, height, renderTarget);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002264 }
2265 else
2266 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00002267 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002268 {
2269 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002270 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00002271
2272 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002273
2274 ASSERT(width == height);
2275
2276 if (width > 0 && level < levelCount())
2277 {
2278 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
2279 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
2280 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
2281 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
2282 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
2283
2284 IDirect3DSurface9 *dest = getCubeMapSurface(target, level);
2285
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002286 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, format, 0, 0, dest);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002287 dest->Release();
2288 }
2289 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002290}
2291
2292IDirect3DSurface9 *TextureCubeMap::getCubeMapSurface(GLenum face, unsigned int level)
2293{
2294 if (mTexture == NULL)
2295 {
2296 UNREACHABLE();
2297 return NULL;
2298 }
2299
2300 IDirect3DSurface9 *surface = NULL;
2301
2302 HRESULT hr = mTexture->GetCubeMapSurface(es2dx::ConvertCubeFace(face), level, &surface);
2303
2304 return (SUCCEEDED(hr)) ? surface : NULL;
2305}
2306
2307void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
2308{
2309 GLsizei size = mImageArray[faceIndex(target)][level].width;
2310
2311 if (xoffset + width > size || yoffset + height > size)
2312 {
2313 return error(GL_INVALID_VALUE);
2314 }
2315
2316 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
2317
2318 if (!renderTarget)
2319 {
2320 ERR("Failed to retrieve the render target.");
2321 return error(GL_OUT_OF_MEMORY);
2322 }
2323
2324 unsigned int faceindex = faceIndex(target);
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002325 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 +00002326
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002327 if (!mImageArray[faceindex][level].isRenderable() || (!mTexture && !isComplete()))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002328 {
daniel@transgaming.comb6276992011-03-29 00:58:18 +00002329 copyToImage(&mImageArray[faceindex][level], 0, 0, x, y, width, height, renderTarget);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002330 }
2331 else
2332 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00002333 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002334 {
2335 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002336 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00002337
2338 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002339
2340 if (level < levelCount())
2341 {
2342 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
2343 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
2344 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
2345 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
2346 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
2347
2348 GLint destYOffset = transformPixelYOffset(yoffset, height, mImageArray[faceindex][level].width);
2349
2350 IDirect3DSurface9 *dest = getCubeMapSurface(target, level);
2351
2352 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0][0].format, xoffset, destYOffset, dest);
2353 dest->Release();
2354 }
2355 }
2356}
2357
2358bool TextureCubeMap::isCubeComplete() const
2359{
2360 if (mImageArray[0][0].width == 0)
2361 {
2362 return false;
2363 }
2364
2365 for (unsigned int f = 1; f < 6; f++)
2366 {
2367 if (mImageArray[f][0].width != mImageArray[0][0].width
2368 || mImageArray[f][0].format != mImageArray[0][0].format)
2369 {
2370 return false;
2371 }
2372 }
2373
2374 return true;
2375}
2376
2377void TextureCubeMap::generateMipmaps()
2378{
2379 if (!isPow2(mImageArray[0][0].width) || !isCubeComplete())
2380 {
2381 return error(GL_INVALID_OPERATION);
2382 }
2383
2384 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
2385 unsigned int q = log2(mImageArray[0][0].width);
2386 for (unsigned int f = 0; f < 6; f++)
2387 {
2388 for (unsigned int i = 1; i <= q; i++)
2389 {
2390 if (mImageArray[f][i].surface != NULL)
2391 {
2392 mImageArray[f][i].surface->Release();
2393 mImageArray[f][i].surface = NULL;
2394 }
2395
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002396 mImageArray[f][i].width = std::max(mImageArray[f][0].width >> i, 1);
2397 mImageArray[f][i].height = mImageArray[f][i].width;
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00002398 mImageArray[f][i].format = mImageArray[f][0].format;
2399 mImageArray[f][i].type = mImageArray[f][0].type;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002400 }
2401 }
2402
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002403 if (mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002404 {
2405 if (mTexture == NULL)
2406 {
2407 return;
2408 }
2409
2410 for (unsigned int f = 0; f < 6; f++)
2411 {
2412 for (unsigned int i = 1; i <= q; i++)
2413 {
2414 IDirect3DSurface9 *upper = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i-1);
2415 IDirect3DSurface9 *lower = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i);
2416
2417 if (upper != NULL && lower != NULL)
2418 {
2419 getBlitter()->boxFilter(upper, lower);
2420 }
2421
2422 if (upper != NULL) upper->Release();
2423 if (lower != NULL) lower->Release();
daniel@transgaming.com61208202011-03-21 16:38:50 +00002424
2425 mImageArray[f][i].dirty = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002426 }
2427 }
2428 }
2429 else
2430 {
2431 for (unsigned int f = 0; f < 6; f++)
2432 {
2433 for (unsigned int i = 1; i <= q; i++)
2434 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00002435 createSurface(&mImageArray[f][i]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002436 if (mImageArray[f][i].surface == NULL)
2437 {
2438 return error(GL_OUT_OF_MEMORY);
2439 }
2440
2441 if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[f][i].surface, NULL, NULL, mImageArray[f][i - 1].surface, NULL, NULL, D3DX_FILTER_BOX, 0)))
2442 {
2443 ERR(" failed to load filter %d to %d.", i - 1, i);
2444 }
2445
2446 mImageArray[f][i].dirty = true;
2447 }
2448 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002449 }
2450}
2451
2452Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target)
2453{
2454 if (!IsCubemapTextureTarget(target))
2455 {
2456 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
2457 }
2458
2459 unsigned int face = faceIndex(target);
2460
2461 if (mFaceProxies[face].get() == NULL)
2462 {
2463 mFaceProxies[face].set(new Renderbuffer(id(), new Colorbuffer(this, target)));
2464 }
2465
2466 return mFaceProxies[face].get();
2467}
2468
2469IDirect3DSurface9 *TextureCubeMap::getRenderTarget(GLenum target)
2470{
2471 ASSERT(IsCubemapTextureTarget(target));
2472
daniel@transgaming.com61208202011-03-21 16:38:50 +00002473 if (!mIsRenderable)
2474 {
2475 convertToRenderTarget();
2476 }
2477
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002478 if (mTexture == NULL)
2479 {
2480 return NULL;
2481 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00002482
2483 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002484
2485 IDirect3DSurface9 *renderTarget = NULL;
2486 mTexture->GetCubeMapSurface(es2dx::ConvertCubeFace(target), 0, &renderTarget);
2487
2488 return renderTarget;
2489}
2490
2491}