blob: bf3fb99f24bf4c4d84c98145fab954e2aa41b8b9 [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());
daniel@transgaming.comeef864a2011-04-22 11:33:27 +00001439
1440 GLint destYOffset = transformPixelYOffset(0, height, mImageArray[level].height);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001441
1442 IDirect3DSurface9 *dest;
1443 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
1444
daniel@transgaming.comeef864a2011-04-22 11:33:27 +00001445 getBlitter()->copy(source->getRenderTarget(), sourceRect, format, 0, destYOffset, dest);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001446 dest->Release();
1447 }
1448 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001449}
1450
1451void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1452{
1453 if (xoffset + width > mImageArray[level].width || yoffset + height > mImageArray[level].height)
1454 {
1455 return error(GL_INVALID_VALUE);
1456 }
1457
1458 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
1459
1460 if (!renderTarget)
1461 {
1462 ERR("Failed to retrieve the render target.");
1463 return error(GL_OUT_OF_MEMORY);
1464 }
1465
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001466 redefineTexture(level, mImageArray[level].format, mImageArray[level].width, mImageArray[level].height, GL_UNSIGNED_BYTE, false);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001467
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001468 if (!mImageArray[level].isRenderable() || (!mTexture && !isComplete()))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001469 {
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001470 copyToImage(&mImageArray[level], xoffset, yoffset, x, y, width, height, renderTarget);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001471 }
1472 else
1473 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001474 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001475 {
1476 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001477 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00001478
1479 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001480
1481 if (level < levelCount())
1482 {
1483 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
1484 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
1485 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
1486 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
1487 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
1488
1489 GLint destYOffset = transformPixelYOffset(yoffset, height, mImageArray[level].height);
1490
1491 IDirect3DSurface9 *dest;
1492 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
1493
daniel@transgaming.comeef864a2011-04-22 11:33:27 +00001494 getBlitter()->copy(source->getRenderTarget(), sourceRect, mImageArray[0].format, xoffset, destYOffset, dest);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001495 dest->Release();
1496 }
1497 }
1498}
1499
1500// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1501bool Texture2D::isComplete() const
1502{
1503 GLsizei width = mImageArray[0].width;
1504 GLsizei height = mImageArray[0].height;
1505
1506 if (width <= 0 || height <= 0)
1507 {
1508 return false;
1509 }
1510
1511 bool mipmapping = false;
1512
1513 switch (mMinFilter)
1514 {
1515 case GL_NEAREST:
1516 case GL_LINEAR:
1517 mipmapping = false;
1518 break;
1519 case GL_NEAREST_MIPMAP_NEAREST:
1520 case GL_LINEAR_MIPMAP_NEAREST:
1521 case GL_NEAREST_MIPMAP_LINEAR:
1522 case GL_LINEAR_MIPMAP_LINEAR:
1523 mipmapping = true;
1524 break;
1525 default: UNREACHABLE();
1526 }
1527
1528 if ((getInternalFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) ||
1529 (getInternalFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter()))
1530 {
1531 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
1532 {
1533 return false;
1534 }
1535 }
1536
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001537 if ((getWrapS() != GL_CLAMP_TO_EDGE && !isPow2(width))
1538 || (getWrapT() != GL_CLAMP_TO_EDGE && !isPow2(height)))
1539 {
1540 return false;
1541 }
1542
1543 if (mipmapping)
1544 {
1545 if (!isPow2(width) || !isPow2(height))
1546 {
1547 return false;
1548 }
1549
1550 int q = log2(std::max(width, height));
1551
1552 for (int level = 1; level <= q; level++)
1553 {
1554 if (mImageArray[level].format != mImageArray[0].format)
1555 {
1556 return false;
1557 }
1558
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00001559 if (mImageArray[level].type != mImageArray[0].type)
1560 {
1561 return false;
1562 }
1563
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001564 if (mImageArray[level].width != std::max(1, width >> level))
1565 {
1566 return false;
1567 }
1568
1569 if (mImageArray[level].height != std::max(1, height >> level))
1570 {
1571 return false;
1572 }
1573 }
1574 }
1575
1576 return true;
1577}
1578
1579bool Texture2D::isCompressed() const
1580{
1581 return IsCompressed(getInternalFormat());
1582}
1583
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001584IDirect3DBaseTexture9 *Texture2D::getBaseTexture() const
1585{
1586 return mTexture;
1587}
1588
1589// Constructs a Direct3D 9 texture resource from the texture images
1590void Texture2D::createTexture()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001591{
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001592 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001593 D3DFORMAT format = mImageArray[0].getD3DFormat();
daniel@transgaming.com61208202011-03-21 16:38:50 +00001594 GLint levels = creationLevels(mImageArray[0].width, mImageArray[0].height, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001595
daniel@transgaming.com61208202011-03-21 16:38:50 +00001596 IDirect3DTexture9 *texture = NULL;
1597 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 +00001598
1599 if (FAILED(result))
1600 {
1601 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001602 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001603 }
1604
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001605 if (mTexture)
1606 {
1607 mTexture->Release();
1608 }
1609
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001610 mTexture = texture;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00001611 mDirtyImage = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00001612 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001613}
1614
1615void Texture2D::updateTexture()
1616{
1617 IDirect3DDevice9 *device = getDevice();
1618
1619 int levels = levelCount();
1620
1621 for (int level = 0; level < levels; level++)
1622 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001623 if (mImageArray[level].surface && mImageArray[level].dirty)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001624 {
1625 IDirect3DSurface9 *levelSurface = NULL;
1626 HRESULT result = mTexture->GetSurfaceLevel(level, &levelSurface);
1627
1628 ASSERT(SUCCEEDED(result));
1629
1630 if (SUCCEEDED(result))
1631 {
1632 result = device->UpdateSurface(mImageArray[level].surface, NULL, levelSurface, NULL);
1633 ASSERT(SUCCEEDED(result));
1634
1635 levelSurface->Release();
1636
1637 mImageArray[level].dirty = false;
1638 }
1639 }
1640 }
1641}
1642
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001643void Texture2D::convertToRenderTarget()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001644{
1645 IDirect3DTexture9 *texture = NULL;
1646
daniel@transgaming.com61208202011-03-21 16:38:50 +00001647 if (mImageArray[0].width != 0 && mImageArray[0].height != 0)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001648 {
1649 egl::Display *display = getDisplay();
1650 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001651 D3DFORMAT format = mImageArray[0].getD3DFormat();
daniel@transgaming.com61208202011-03-21 16:38:50 +00001652 GLint levels = creationLevels(mImageArray[0].width, mImageArray[0].height, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001653
daniel@transgaming.com61208202011-03-21 16:38:50 +00001654 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 +00001655
1656 if (FAILED(result))
1657 {
1658 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001659 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001660 }
1661
1662 if (mTexture != NULL)
1663 {
1664 int levels = levelCount();
1665 for (int i = 0; i < levels; i++)
1666 {
1667 IDirect3DSurface9 *source;
1668 result = mTexture->GetSurfaceLevel(i, &source);
1669
1670 if (FAILED(result))
1671 {
1672 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1673
1674 texture->Release();
1675
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001676 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001677 }
1678
1679 IDirect3DSurface9 *dest;
1680 result = texture->GetSurfaceLevel(i, &dest);
1681
1682 if (FAILED(result))
1683 {
1684 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1685
1686 texture->Release();
1687 source->Release();
1688
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001689 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001690 }
1691
1692 display->endScene();
1693 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
1694
1695 if (FAILED(result))
1696 {
1697 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1698
1699 texture->Release();
1700 source->Release();
1701 dest->Release();
1702
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001703 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001704 }
1705
1706 source->Release();
1707 dest->Release();
1708 }
1709 }
1710 }
1711
1712 if (mTexture != NULL)
1713 {
1714 mTexture->Release();
1715 }
1716
1717 mTexture = texture;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00001718 mDirtyImage = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00001719 mIsRenderable = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001720}
1721
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001722void Texture2D::generateMipmaps()
1723{
1724 if (!isPow2(mImageArray[0].width) || !isPow2(mImageArray[0].height))
1725 {
1726 return error(GL_INVALID_OPERATION);
1727 }
1728
1729 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
daniel@transgaming.com61208202011-03-21 16:38:50 +00001730 unsigned int q = log2(std::max(mImageArray[0].width, mImageArray[0].height));
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001731 for (unsigned int i = 1; i <= q; i++)
1732 {
1733 if (mImageArray[i].surface != NULL)
1734 {
1735 mImageArray[i].surface->Release();
1736 mImageArray[i].surface = NULL;
1737 }
1738
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001739 mImageArray[i].width = std::max(mImageArray[0].width >> i, 1);
1740 mImageArray[i].height = std::max(mImageArray[0].height >> i, 1);
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00001741 mImageArray[i].format = mImageArray[0].format;
1742 mImageArray[i].type = mImageArray[0].type;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001743 }
1744
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001745 if (mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001746 {
1747 if (mTexture == NULL)
1748 {
1749 ERR(" failed because mTexture was null.");
1750 return;
1751 }
1752
1753 for (unsigned int i = 1; i <= q; i++)
1754 {
1755 IDirect3DSurface9 *upper = NULL;
1756 IDirect3DSurface9 *lower = NULL;
1757
1758 mTexture->GetSurfaceLevel(i-1, &upper);
1759 mTexture->GetSurfaceLevel(i, &lower);
1760
1761 if (upper != NULL && lower != NULL)
1762 {
1763 getBlitter()->boxFilter(upper, lower);
1764 }
1765
1766 if (upper != NULL) upper->Release();
1767 if (lower != NULL) lower->Release();
daniel@transgaming.com61208202011-03-21 16:38:50 +00001768
1769 mImageArray[i].dirty = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001770 }
1771 }
1772 else
1773 {
1774 for (unsigned int i = 1; i <= q; i++)
1775 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001776 createSurface(&mImageArray[i]);
1777
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001778 if (mImageArray[i].surface == NULL)
1779 {
1780 return error(GL_OUT_OF_MEMORY);
1781 }
1782
1783 if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[i].surface, NULL, NULL, mImageArray[i - 1].surface, NULL, NULL, D3DX_FILTER_BOX, 0)))
1784 {
1785 ERR(" failed to load filter %d to %d.", i - 1, i);
1786 }
1787
1788 mImageArray[i].dirty = true;
1789 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001790 }
1791}
1792
1793Renderbuffer *Texture2D::getRenderbuffer(GLenum target)
1794{
1795 if (target != GL_TEXTURE_2D)
1796 {
1797 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
1798 }
1799
1800 if (mColorbufferProxy.get() == NULL)
1801 {
1802 mColorbufferProxy.set(new Renderbuffer(id(), new Colorbuffer(this, target)));
1803 }
1804
1805 return mColorbufferProxy.get();
1806}
1807
1808IDirect3DSurface9 *Texture2D::getRenderTarget(GLenum target)
1809{
1810 ASSERT(target == GL_TEXTURE_2D);
1811
daniel@transgaming.com61208202011-03-21 16:38:50 +00001812 if (!mIsRenderable)
1813 {
1814 convertToRenderTarget();
1815 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001816
1817 if (mTexture == NULL)
1818 {
1819 return NULL;
1820 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00001821
1822 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001823
1824 IDirect3DSurface9 *renderTarget = NULL;
1825 mTexture->GetSurfaceLevel(0, &renderTarget);
1826
1827 return renderTarget;
1828}
1829
1830TextureCubeMap::TextureCubeMap(GLuint id) : Texture(id)
1831{
1832 mTexture = NULL;
1833}
1834
1835TextureCubeMap::~TextureCubeMap()
1836{
1837 for (int i = 0; i < 6; i++)
1838 {
1839 mFaceProxies[i].set(NULL);
1840 }
1841
1842 if (mTexture)
1843 {
1844 mTexture->Release();
1845 mTexture = NULL;
1846 }
1847}
1848
1849GLenum TextureCubeMap::getTarget() const
1850{
1851 return GL_TEXTURE_CUBE_MAP;
1852}
1853
daniel@transgaming.com61208202011-03-21 16:38:50 +00001854GLsizei TextureCubeMap::getWidth() const
1855{
1856 return mImageArray[0][0].width;
1857}
1858
1859GLsizei TextureCubeMap::getHeight() const
1860{
1861 return mImageArray[0][0].height;
1862}
1863
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001864GLenum TextureCubeMap::getInternalFormat() const
1865{
1866 return mImageArray[0][0].format;
1867}
1868
daniel@transgaming.com61208202011-03-21 16:38:50 +00001869GLenum TextureCubeMap::getType() const
1870{
1871 return mImageArray[0][0].type;
1872}
1873
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001874D3DFORMAT TextureCubeMap::getD3DFormat() const
1875{
1876 return mImageArray[0][0].getD3DFormat();
1877}
1878
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001879void 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 +00001880{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001881 setImage(0, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001882}
1883
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001884void 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 +00001885{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001886 setImage(1, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001887}
1888
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001889void 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 +00001890{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001891 setImage(2, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001892}
1893
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001894void 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 +00001895{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001896 setImage(3, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001897}
1898
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001899void 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 +00001900{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001901 setImage(4, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001902}
1903
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001904void 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 +00001905{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001906 setImage(5, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001907}
1908
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001909void 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 +00001910{
daniel@transgaming.com61208202011-03-21 16:38:50 +00001911 redefineTexture(faceIndex(face), level, format, width, height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001912
daniel@transgaming.com61208202011-03-21 16:38:50 +00001913 Texture::setCompressedImage(imageSize, pixels, &mImageArray[faceIndex(face)][level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001914}
1915
1916void TextureCubeMap::commitRect(GLenum faceTarget, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1917{
1918 int face = faceIndex(faceTarget);
1919 ASSERT(mImageArray[face][level].surface != NULL);
1920
1921 if (level < levelCount())
1922 {
1923 IDirect3DSurface9 *destLevel = getCubeMapSurface(faceTarget, level);
1924 ASSERT(destLevel != NULL);
1925
1926 if (destLevel != NULL)
1927 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001928 Image *image = &mImageArray[face][level];
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001929
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001930 RECT sourceRect = transformPixelRect(xoffset, yoffset, width, height, image->height);;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001931
1932 POINT destPoint;
1933 destPoint.x = sourceRect.left;
1934 destPoint.y = sourceRect.top;
1935
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001936 HRESULT result = getDevice()->UpdateSurface(image->surface, &sourceRect, destLevel, &destPoint);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001937 ASSERT(SUCCEEDED(result));
1938
1939 destLevel->Release();
1940
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001941 image->dirty = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001942 }
1943 }
1944}
1945
1946void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1947{
1948 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[faceIndex(target)][level]))
1949 {
1950 commitRect(target, level, xoffset, yoffset, width, height);
1951 }
1952}
1953
1954void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1955{
1956 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[faceIndex(target)][level]))
1957 {
1958 commitRect(target, level, xoffset, yoffset, width, height);
1959 }
1960}
1961
1962// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1963bool TextureCubeMap::isComplete() const
1964{
1965 int size = mImageArray[0][0].width;
1966
1967 if (size <= 0)
1968 {
1969 return false;
1970 }
1971
1972 bool mipmapping;
1973
1974 switch (mMinFilter)
1975 {
1976 case GL_NEAREST:
1977 case GL_LINEAR:
1978 mipmapping = false;
1979 break;
1980 case GL_NEAREST_MIPMAP_NEAREST:
1981 case GL_LINEAR_MIPMAP_NEAREST:
1982 case GL_NEAREST_MIPMAP_LINEAR:
1983 case GL_LINEAR_MIPMAP_LINEAR:
1984 mipmapping = true;
1985 break;
1986 default: UNREACHABLE();
1987 }
1988
1989 for (int face = 0; face < 6; face++)
1990 {
1991 if (mImageArray[face][0].width != size || mImageArray[face][0].height != size)
1992 {
1993 return false;
1994 }
1995 }
1996
1997 if ((getInternalFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) ||
1998 (getInternalFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter()))
1999 {
2000 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
2001 {
2002 return false;
2003 }
2004 }
2005
2006 if (mipmapping)
2007 {
2008 if (!isPow2(size) && (getWrapS() != GL_CLAMP_TO_EDGE || getWrapT() != GL_CLAMP_TO_EDGE))
2009 {
2010 return false;
2011 }
2012
2013 int q = log2(size);
2014
2015 for (int face = 0; face < 6; face++)
2016 {
2017 for (int level = 1; level <= q; level++)
2018 {
2019 if (mImageArray[face][level].format != mImageArray[0][0].format)
2020 {
2021 return false;
2022 }
2023
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00002024 if (mImageArray[face][level].type != mImageArray[0][0].type)
2025 {
2026 return false;
2027 }
2028
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002029 if (mImageArray[face][level].width != std::max(1, size >> level))
2030 {
2031 return false;
2032 }
2033
2034 ASSERT(mImageArray[face][level].height == mImageArray[face][level].width);
2035 }
2036 }
2037 }
2038
2039 return true;
2040}
2041
2042bool TextureCubeMap::isCompressed() const
2043{
2044 return IsCompressed(getInternalFormat());
2045}
2046
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002047IDirect3DBaseTexture9 *TextureCubeMap::getBaseTexture() const
2048{
2049 return mTexture;
2050}
2051
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002052// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002053void TextureCubeMap::createTexture()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002054{
2055 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002056 D3DFORMAT format = mImageArray[0][0].getD3DFormat();
daniel@transgaming.com61208202011-03-21 16:38:50 +00002057 GLint levels = creationLevels(mImageArray[0][0].width, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002058
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00002059 IDirect3DCubeTexture9 *texture = NULL;
daniel@transgaming.com61208202011-03-21 16:38:50 +00002060 HRESULT result = device->CreateCubeTexture(mImageArray[0][0].width, levels, 0, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002061
2062 if (FAILED(result))
2063 {
2064 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002065 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002066 }
2067
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002068 if (mTexture)
2069 {
2070 mTexture->Release();
2071 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002072
2073 mTexture = texture;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00002074 mDirtyImage = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00002075 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002076}
2077
2078void TextureCubeMap::updateTexture()
2079{
2080 IDirect3DDevice9 *device = getDevice();
2081
2082 for (int face = 0; face < 6; face++)
2083 {
2084 int levels = levelCount();
2085 for (int level = 0; level < levels; level++)
2086 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00002087 Image *image = &mImageArray[face][level];
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002088
daniel@transgaming.com61208202011-03-21 16:38:50 +00002089 if (image->surface && image->dirty)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002090 {
2091 IDirect3DSurface9 *levelSurface = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level);
2092 ASSERT(levelSurface != NULL);
2093
2094 if (levelSurface != NULL)
2095 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00002096 HRESULT result = device->UpdateSurface(image->surface, NULL, levelSurface, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002097 ASSERT(SUCCEEDED(result));
2098
2099 levelSurface->Release();
2100
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00002101 image->dirty = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002102 }
2103 }
2104 }
2105 }
2106}
2107
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002108void TextureCubeMap::convertToRenderTarget()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002109{
2110 IDirect3DCubeTexture9 *texture = NULL;
2111
daniel@transgaming.com61208202011-03-21 16:38:50 +00002112 if (mImageArray[0][0].width != 0)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002113 {
2114 egl::Display *display = getDisplay();
2115 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002116 D3DFORMAT format = mImageArray[0][0].getD3DFormat();
daniel@transgaming.com61208202011-03-21 16:38:50 +00002117 GLint levels = creationLevels(mImageArray[0][0].width, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002118
daniel@transgaming.com61208202011-03-21 16:38:50 +00002119 HRESULT result = device->CreateCubeTexture(mImageArray[0][0].width, levels, D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002120
2121 if (FAILED(result))
2122 {
2123 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002124 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002125 }
2126
2127 if (mTexture != NULL)
2128 {
2129 int levels = levelCount();
2130 for (int f = 0; f < 6; f++)
2131 {
2132 for (int i = 0; i < levels; i++)
2133 {
2134 IDirect3DSurface9 *source;
2135 result = mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &source);
2136
2137 if (FAILED(result))
2138 {
2139 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2140
2141 texture->Release();
2142
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002143 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002144 }
2145
2146 IDirect3DSurface9 *dest;
2147 result = texture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &dest);
2148
2149 if (FAILED(result))
2150 {
2151 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2152
2153 texture->Release();
2154 source->Release();
2155
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002156 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002157 }
2158
2159 display->endScene();
2160 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
2161
2162 if (FAILED(result))
2163 {
2164 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2165
2166 texture->Release();
2167 source->Release();
2168 dest->Release();
2169
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002170 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002171 }
2172 }
2173 }
2174 }
2175 }
2176
2177 if (mTexture != NULL)
2178 {
2179 mTexture->Release();
2180 }
2181
2182 mTexture = texture;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00002183 mDirtyImage = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00002184 mIsRenderable = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002185}
2186
daniel@transgaming.com61208202011-03-21 16:38:50 +00002187void 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 +00002188{
daniel@transgaming.com61208202011-03-21 16:38:50 +00002189 redefineTexture(faceIndex, level, format, width, height, type);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002190
daniel@transgaming.com61208202011-03-21 16:38:50 +00002191 Texture::setImage(unpackAlignment, pixels, &mImageArray[faceIndex][level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002192}
2193
2194unsigned int TextureCubeMap::faceIndex(GLenum face)
2195{
2196 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
2197 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
2198 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
2199 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
2200 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
2201
2202 return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
2203}
2204
daniel@transgaming.com61208202011-03-21 16:38:50 +00002205void TextureCubeMap::redefineTexture(int face, GLint level, GLenum format, GLsizei width, GLsizei height, GLenum type)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002206{
daniel@transgaming.com94a4f032011-03-21 16:38:55 +00002207 GLsizei textureWidth = mImageArray[0][0].width;
2208 GLsizei textureHeight = mImageArray[0][0].height;
2209 GLenum textureFormat = mImageArray[0][0].format;
2210 GLenum textureType = mImageArray[0][0].type;
2211
daniel@transgaming.com61208202011-03-21 16:38:50 +00002212 mImageArray[face][level].width = width;
2213 mImageArray[face][level].height = height;
2214 mImageArray[face][level].format = format;
2215 mImageArray[face][level].type = type;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002216
daniel@transgaming.com61208202011-03-21 16:38:50 +00002217 if (!mTexture)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002218 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00002219 return;
2220 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002221
daniel@transgaming.com94a4f032011-03-21 16:38:55 +00002222 bool sizeOkay = (textureWidth >> level == width);
2223 bool textureOkay = (sizeOkay && textureFormat == format && textureType == type);
daniel@transgaming.com61208202011-03-21 16:38:50 +00002224
2225 if (!textureOkay) // Purge all the levels and the texture.
2226 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002227 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
2228 {
2229 for (int f = 0; f < 6; f++)
2230 {
2231 if (mImageArray[f][i].surface != NULL)
2232 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002233 mImageArray[f][i].surface->Release();
2234 mImageArray[f][i].surface = NULL;
daniel@transgaming.com61208202011-03-21 16:38:50 +00002235 mImageArray[f][i].dirty = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002236 }
2237 }
2238 }
2239
2240 if (mTexture != NULL)
2241 {
2242 mTexture->Release();
2243 mTexture = NULL;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00002244 mDirtyImage = true;
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002245 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002246 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002247 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002248}
2249
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002250void 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 +00002251{
2252 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
2253
2254 if (!renderTarget)
2255 {
2256 ERR("Failed to retrieve the render target.");
2257 return error(GL_OUT_OF_MEMORY);
2258 }
2259
2260 unsigned int faceindex = faceIndex(target);
daniel@transgaming.com61208202011-03-21 16:38:50 +00002261 redefineTexture(faceindex, level, format, width, height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002262
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002263 if (!mImageArray[faceindex][level].isRenderable())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002264 {
daniel@transgaming.comb6276992011-03-29 00:58:18 +00002265 copyToImage(&mImageArray[faceindex][level], 0, 0, x, y, width, height, renderTarget);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002266 }
2267 else
2268 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00002269 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002270 {
2271 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002272 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00002273
2274 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002275
2276 ASSERT(width == height);
2277
2278 if (width > 0 && level < levelCount())
2279 {
2280 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
2281 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
2282 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
2283 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
2284 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
2285
daniel@transgaming.comeef864a2011-04-22 11:33:27 +00002286 GLint destYOffset = transformPixelYOffset(0, height, mImageArray[faceindex][level].width);
2287
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002288 IDirect3DSurface9 *dest = getCubeMapSurface(target, level);
2289
daniel@transgaming.comeef864a2011-04-22 11:33:27 +00002290 getBlitter()->copy(source->getRenderTarget(), sourceRect, format, 0, destYOffset, dest);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002291 dest->Release();
2292 }
2293 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002294}
2295
2296IDirect3DSurface9 *TextureCubeMap::getCubeMapSurface(GLenum face, unsigned int level)
2297{
2298 if (mTexture == NULL)
2299 {
2300 UNREACHABLE();
2301 return NULL;
2302 }
2303
2304 IDirect3DSurface9 *surface = NULL;
2305
2306 HRESULT hr = mTexture->GetCubeMapSurface(es2dx::ConvertCubeFace(face), level, &surface);
2307
2308 return (SUCCEEDED(hr)) ? surface : NULL;
2309}
2310
2311void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
2312{
2313 GLsizei size = mImageArray[faceIndex(target)][level].width;
2314
2315 if (xoffset + width > size || yoffset + height > size)
2316 {
2317 return error(GL_INVALID_VALUE);
2318 }
2319
2320 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
2321
2322 if (!renderTarget)
2323 {
2324 ERR("Failed to retrieve the render target.");
2325 return error(GL_OUT_OF_MEMORY);
2326 }
2327
2328 unsigned int faceindex = faceIndex(target);
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002329 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 +00002330
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002331 if (!mImageArray[faceindex][level].isRenderable() || (!mTexture && !isComplete()))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002332 {
daniel@transgaming.comb6276992011-03-29 00:58:18 +00002333 copyToImage(&mImageArray[faceindex][level], 0, 0, x, y, width, height, renderTarget);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002334 }
2335 else
2336 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00002337 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002338 {
2339 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002340 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00002341
2342 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002343
2344 if (level < levelCount())
2345 {
2346 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
2347 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
2348 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
2349 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
2350 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
2351
2352 GLint destYOffset = transformPixelYOffset(yoffset, height, mImageArray[faceindex][level].width);
2353
2354 IDirect3DSurface9 *dest = getCubeMapSurface(target, level);
2355
daniel@transgaming.comeef864a2011-04-22 11:33:27 +00002356 getBlitter()->copy(source->getRenderTarget(), sourceRect, mImageArray[0][0].format, xoffset, destYOffset, dest);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002357 dest->Release();
2358 }
2359 }
2360}
2361
2362bool TextureCubeMap::isCubeComplete() const
2363{
2364 if (mImageArray[0][0].width == 0)
2365 {
2366 return false;
2367 }
2368
2369 for (unsigned int f = 1; f < 6; f++)
2370 {
2371 if (mImageArray[f][0].width != mImageArray[0][0].width
2372 || mImageArray[f][0].format != mImageArray[0][0].format)
2373 {
2374 return false;
2375 }
2376 }
2377
2378 return true;
2379}
2380
2381void TextureCubeMap::generateMipmaps()
2382{
2383 if (!isPow2(mImageArray[0][0].width) || !isCubeComplete())
2384 {
2385 return error(GL_INVALID_OPERATION);
2386 }
2387
2388 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
2389 unsigned int q = log2(mImageArray[0][0].width);
2390 for (unsigned int f = 0; f < 6; f++)
2391 {
2392 for (unsigned int i = 1; i <= q; i++)
2393 {
2394 if (mImageArray[f][i].surface != NULL)
2395 {
2396 mImageArray[f][i].surface->Release();
2397 mImageArray[f][i].surface = NULL;
2398 }
2399
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002400 mImageArray[f][i].width = std::max(mImageArray[f][0].width >> i, 1);
2401 mImageArray[f][i].height = mImageArray[f][i].width;
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00002402 mImageArray[f][i].format = mImageArray[f][0].format;
2403 mImageArray[f][i].type = mImageArray[f][0].type;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002404 }
2405 }
2406
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002407 if (mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002408 {
2409 if (mTexture == NULL)
2410 {
2411 return;
2412 }
2413
2414 for (unsigned int f = 0; f < 6; f++)
2415 {
2416 for (unsigned int i = 1; i <= q; i++)
2417 {
2418 IDirect3DSurface9 *upper = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i-1);
2419 IDirect3DSurface9 *lower = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i);
2420
2421 if (upper != NULL && lower != NULL)
2422 {
2423 getBlitter()->boxFilter(upper, lower);
2424 }
2425
2426 if (upper != NULL) upper->Release();
2427 if (lower != NULL) lower->Release();
daniel@transgaming.com61208202011-03-21 16:38:50 +00002428
2429 mImageArray[f][i].dirty = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002430 }
2431 }
2432 }
2433 else
2434 {
2435 for (unsigned int f = 0; f < 6; f++)
2436 {
2437 for (unsigned int i = 1; i <= q; i++)
2438 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00002439 createSurface(&mImageArray[f][i]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002440 if (mImageArray[f][i].surface == NULL)
2441 {
2442 return error(GL_OUT_OF_MEMORY);
2443 }
2444
2445 if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[f][i].surface, NULL, NULL, mImageArray[f][i - 1].surface, NULL, NULL, D3DX_FILTER_BOX, 0)))
2446 {
2447 ERR(" failed to load filter %d to %d.", i - 1, i);
2448 }
2449
2450 mImageArray[f][i].dirty = true;
2451 }
2452 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002453 }
2454}
2455
2456Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target)
2457{
2458 if (!IsCubemapTextureTarget(target))
2459 {
2460 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
2461 }
2462
2463 unsigned int face = faceIndex(target);
2464
2465 if (mFaceProxies[face].get() == NULL)
2466 {
2467 mFaceProxies[face].set(new Renderbuffer(id(), new Colorbuffer(this, target)));
2468 }
2469
2470 return mFaceProxies[face].get();
2471}
2472
2473IDirect3DSurface9 *TextureCubeMap::getRenderTarget(GLenum target)
2474{
2475 ASSERT(IsCubemapTextureTarget(target));
2476
daniel@transgaming.com61208202011-03-21 16:38:50 +00002477 if (!mIsRenderable)
2478 {
2479 convertToRenderTarget();
2480 }
2481
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002482 if (mTexture == NULL)
2483 {
2484 return NULL;
2485 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00002486
2487 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002488
2489 IDirect3DSurface9 *renderTarget = NULL;
2490 mTexture->GetCubeMapSurface(es2dx::ConvertCubeFace(target), 0, &renderTarget);
2491
2492 return renderTarget;
2493}
2494
2495}