blob: dbb48219987308081c5d66bbe7e353fa57370625 [file] [log] [blame]
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001//
2// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7// Texture.cpp: Implements the gl::Texture class and its derived classes
8// Texture2D and TextureCubeMap. Implements GL texture objects and related
9// functionality. [OpenGL ES 2.0.24] section 3.7 page 63.
10
11#include "libGLESv2/Texture.h"
12
13#include <d3dx9tex.h>
14
15#include <algorithm>
jbauman@chromium.orgf1f28c82011-05-12 20:53:34 +000016#include <intrin.h>
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +000017
18#include "common/debug.h"
19
jbauman@chromium.orgae345802011-03-30 22:04:25 +000020#include "libEGL/Display.h"
21
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +000022#include "libGLESv2/main.h"
23#include "libGLESv2/mathutil.h"
24#include "libGLESv2/utilities.h"
25#include "libGLESv2/Blit.h"
26#include "libGLESv2/Framebuffer.h"
27
28namespace gl
29{
daniel@transgaming.coma9eb5da2011-03-21 16:39:16 +000030unsigned int Texture::mCurrentSerial = 1;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +000031
32Texture::Image::Image()
daniel@transgaming.comc50edcb2011-03-21 16:38:40 +000033 : width(0), height(0), dirty(false), surface(NULL), format(GL_NONE), type(GL_UNSIGNED_BYTE)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +000034{
35}
36
37Texture::Image::~Image()
38{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +000039 if (surface)
40 {
41 surface->Release();
42 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +000043}
44
daniel@transgaming.com549bdef2011-03-29 00:57:01 +000045bool Texture::Image::isRenderable() const
46{
47 switch(getD3DFormat())
48 {
49 case D3DFMT_L8:
50 case D3DFMT_A8L8:
51 case D3DFMT_DXT1:
52 return false;
53 case D3DFMT_A8R8G8B8:
54 case D3DFMT_X8R8G8B8:
55 case D3DFMT_A16B16G16R16F:
56 case D3DFMT_A32B32G32R32F:
57 return true;
58 default:
59 UNREACHABLE();
60 }
61
62 return false;
63}
64
65D3DFORMAT Texture::Image::getD3DFormat() const
66{
67 if (format == GL_COMPRESSED_RGB_S3TC_DXT1_EXT ||
68 format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT)
69 {
70 return D3DFMT_DXT1;
71 }
72 else if (type == GL_FLOAT)
73 {
74 return D3DFMT_A32B32G32R32F;
75 }
76 else if (type == GL_HALF_FLOAT_OES)
77 {
78 return D3DFMT_A16B16G16R16F;
79 }
80 else if (type == GL_UNSIGNED_BYTE)
81 {
82 if (format == GL_LUMINANCE && getContext()->supportsLuminanceTextures())
83 {
84 return D3DFMT_L8;
85 }
86 else if (format == GL_LUMINANCE_ALPHA && getContext()->supportsLuminanceAlphaTextures())
87 {
88 return D3DFMT_A8L8;
89 }
90 else if (format == GL_RGB)
91 {
92 return D3DFMT_X8R8G8B8;
93 }
94
95 return D3DFMT_A8R8G8B8;
96 }
97
98 return D3DFMT_A8R8G8B8;
99}
100
daniel@transgaming.coma9eb5da2011-03-21 16:39:16 +0000101Texture::Texture(GLuint id) : RefCountObject(id), mSerial(issueSerial())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000102{
103 mMinFilter = GL_NEAREST_MIPMAP_LINEAR;
104 mMagFilter = GL_LINEAR;
105 mWrapS = GL_REPEAT;
106 mWrapT = GL_REPEAT;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +0000107 mDirtyParameter = true;
108
109 mDirtyImage = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +0000110
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000111 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000112}
113
114Texture::~Texture()
115{
116}
117
118Blit *Texture::getBlitter()
119{
120 Context *context = getContext();
121 return context->getBlitter();
122}
123
124// Returns true on successful filter state update (valid enum parameter)
125bool Texture::setMinFilter(GLenum filter)
126{
127 switch (filter)
128 {
129 case GL_NEAREST:
130 case GL_LINEAR:
131 case GL_NEAREST_MIPMAP_NEAREST:
132 case GL_LINEAR_MIPMAP_NEAREST:
133 case GL_NEAREST_MIPMAP_LINEAR:
134 case GL_LINEAR_MIPMAP_LINEAR:
135 {
136 if (mMinFilter != filter)
137 {
138 mMinFilter = filter;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +0000139 mDirtyParameter = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000140 }
141 return true;
142 }
143 default:
144 return false;
145 }
146}
147
148// Returns true on successful filter state update (valid enum parameter)
149bool Texture::setMagFilter(GLenum filter)
150{
151 switch (filter)
152 {
153 case GL_NEAREST:
154 case GL_LINEAR:
155 {
156 if (mMagFilter != filter)
157 {
158 mMagFilter = filter;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +0000159 mDirtyParameter = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000160 }
161 return true;
162 }
163 default:
164 return false;
165 }
166}
167
168// Returns true on successful wrap state update (valid enum parameter)
169bool Texture::setWrapS(GLenum wrap)
170{
171 switch (wrap)
172 {
173 case GL_REPEAT:
174 case GL_CLAMP_TO_EDGE:
175 case GL_MIRRORED_REPEAT:
176 {
177 if (mWrapS != wrap)
178 {
179 mWrapS = wrap;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +0000180 mDirtyParameter = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000181 }
182 return true;
183 }
184 default:
185 return false;
186 }
187}
188
189// Returns true on successful wrap state update (valid enum parameter)
190bool Texture::setWrapT(GLenum wrap)
191{
192 switch (wrap)
193 {
194 case GL_REPEAT:
195 case GL_CLAMP_TO_EDGE:
196 case GL_MIRRORED_REPEAT:
197 {
198 if (mWrapT != wrap)
199 {
200 mWrapT = wrap;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +0000201 mDirtyParameter = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000202 }
203 return true;
204 }
205 default:
206 return false;
207 }
208}
209
210GLenum Texture::getMinFilter() const
211{
212 return mMinFilter;
213}
214
215GLenum Texture::getMagFilter() const
216{
217 return mMagFilter;
218}
219
220GLenum Texture::getWrapS() const
221{
222 return mWrapS;
223}
224
225GLenum Texture::getWrapT() const
226{
227 return mWrapT;
228}
229
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000230// Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input
231// into the target pixel rectangle at output with outputPitch bytes in between each line.
232void Texture::loadImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type,
233 GLint unpackAlignment, const void *input, size_t outputPitch, void *output, D3DSURFACE_DESC *description) const
234{
235 GLsizei inputPitch = -ComputePitch(width, format, type, unpackAlignment);
236 input = ((char*)input) - inputPitch * (height - 1);
237
238 switch (type)
239 {
240 case GL_UNSIGNED_BYTE:
241 switch (format)
242 {
243 case GL_ALPHA:
244 loadAlphaImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
245 break;
246 case GL_LUMINANCE:
247 loadLuminanceImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output, description->Format == D3DFMT_L8);
248 break;
249 case GL_LUMINANCE_ALPHA:
250 loadLuminanceAlphaImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output, description->Format == D3DFMT_A8L8);
251 break;
252 case GL_RGB:
253 loadRGBUByteImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
254 break;
255 case GL_RGBA:
jbauman@chromium.orgf1f28c82011-05-12 20:53:34 +0000256 if (supportsSSE2())
257 {
258 loadRGBAUByteImageDataSSE2(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
259 }
260 else
261 {
262 loadRGBAUByteImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
263 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000264 break;
265 case GL_BGRA_EXT:
266 loadBGRAImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
267 break;
268 default: UNREACHABLE();
269 }
270 break;
271 case GL_UNSIGNED_SHORT_5_6_5:
272 switch (format)
273 {
274 case GL_RGB:
275 loadRGB565ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
276 break;
277 default: UNREACHABLE();
278 }
279 break;
280 case GL_UNSIGNED_SHORT_4_4_4_4:
281 switch (format)
282 {
283 case GL_RGBA:
284 loadRGBA4444ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
285 break;
286 default: UNREACHABLE();
287 }
288 break;
289 case GL_UNSIGNED_SHORT_5_5_5_1:
290 switch (format)
291 {
292 case GL_RGBA:
293 loadRGBA5551ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
294 break;
295 default: UNREACHABLE();
296 }
297 break;
298 case GL_FLOAT:
299 switch (format)
300 {
301 // float textures are converted to RGBA, not BGRA, as they're stored that way in D3D
302 case GL_ALPHA:
303 loadAlphaFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
304 break;
305 case GL_LUMINANCE:
306 loadLuminanceFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
307 break;
308 case GL_LUMINANCE_ALPHA:
309 loadLuminanceAlphaFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
310 break;
311 case GL_RGB:
312 loadRGBFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
313 break;
314 case GL_RGBA:
315 loadRGBAFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
316 break;
317 default: UNREACHABLE();
318 }
319 break;
320 case GL_HALF_FLOAT_OES:
321 switch (format)
322 {
323 // float textures are converted to RGBA, not BGRA, as they're stored that way in D3D
324 case GL_ALPHA:
325 loadAlphaHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
326 break;
327 case GL_LUMINANCE:
328 loadLuminanceHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
329 break;
330 case GL_LUMINANCE_ALPHA:
331 loadLuminanceAlphaHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
332 break;
333 case GL_RGB:
334 loadRGBHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
335 break;
336 case GL_RGBA:
337 loadRGBAHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
338 break;
339 default: UNREACHABLE();
340 }
341 break;
342 default: UNREACHABLE();
343 }
344}
345
346void Texture::loadAlphaImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
347 int inputPitch, const void *input, size_t outputPitch, void *output) const
348{
349 const unsigned char *source = NULL;
350 unsigned char *dest = NULL;
351
352 for (int y = 0; y < height; y++)
353 {
354 source = static_cast<const unsigned char*>(input) + y * inputPitch;
355 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
356 for (int x = 0; x < width; x++)
357 {
358 dest[4 * x + 0] = 0;
359 dest[4 * x + 1] = 0;
360 dest[4 * x + 2] = 0;
361 dest[4 * x + 3] = source[x];
362 }
363 }
364}
365
366void Texture::loadAlphaFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
367 int inputPitch, const void *input, size_t outputPitch, void *output) const
368{
369 const float *source = NULL;
370 float *dest = NULL;
371
372 for (int y = 0; y < height; y++)
373 {
374 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
375 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
376 for (int x = 0; x < width; x++)
377 {
378 dest[4 * x + 0] = 0;
379 dest[4 * x + 1] = 0;
380 dest[4 * x + 2] = 0;
381 dest[4 * x + 3] = source[x];
382 }
383 }
384}
385
386void Texture::loadAlphaHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
387 int inputPitch, const void *input, size_t outputPitch, void *output) const
388{
389 const unsigned short *source = NULL;
390 unsigned short *dest = NULL;
391
392 for (int y = 0; y < height; y++)
393 {
394 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
395 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
396 for (int x = 0; x < width; x++)
397 {
398 dest[4 * x + 0] = 0;
399 dest[4 * x + 1] = 0;
400 dest[4 * x + 2] = 0;
401 dest[4 * x + 3] = source[x];
402 }
403 }
404}
405
406void Texture::loadLuminanceImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
407 int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const
408{
409 const int destBytesPerPixel = native? 1: 4;
410 const unsigned char *source = NULL;
411 unsigned char *dest = NULL;
412
413 for (int y = 0; y < height; y++)
414 {
415 source = static_cast<const unsigned char*>(input) + y * inputPitch;
416 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * destBytesPerPixel;
417
418 if (!native) // BGRA8 destination format
419 {
420 for (int x = 0; x < width; x++)
421 {
422 dest[4 * x + 0] = source[x];
423 dest[4 * x + 1] = source[x];
424 dest[4 * x + 2] = source[x];
425 dest[4 * x + 3] = 0xFF;
426 }
427 }
428 else // L8 destination format
429 {
430 memcpy(dest, source, width);
431 }
432 }
433}
434
435void Texture::loadLuminanceFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
436 int inputPitch, const void *input, size_t outputPitch, void *output) const
437{
438 const float *source = NULL;
439 float *dest = NULL;
440
441 for (int y = 0; y < height; y++)
442 {
443 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
444 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
445 for (int x = 0; x < width; x++)
446 {
447 dest[4 * x + 0] = source[x];
448 dest[4 * x + 1] = source[x];
449 dest[4 * x + 2] = source[x];
450 dest[4 * x + 3] = 1.0f;
451 }
452 }
453}
454
455void Texture::loadLuminanceHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
456 int inputPitch, const void *input, size_t outputPitch, void *output) const
457{
458 const unsigned short *source = NULL;
459 unsigned short *dest = NULL;
460
461 for (int y = 0; y < height; y++)
462 {
463 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
464 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
465 for (int x = 0; x < width; x++)
466 {
467 dest[4 * x + 0] = source[x];
468 dest[4 * x + 1] = source[x];
469 dest[4 * x + 2] = source[x];
470 dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1
471 }
472 }
473}
474
475void Texture::loadLuminanceAlphaImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
476 int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const
477{
478 const int destBytesPerPixel = native? 2: 4;
479 const unsigned char *source = NULL;
480 unsigned char *dest = NULL;
481
482 for (int y = 0; y < height; y++)
483 {
484 source = static_cast<const unsigned char*>(input) + y * inputPitch;
485 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * destBytesPerPixel;
486
487 if (!native) // BGRA8 destination format
488 {
489 for (int x = 0; x < width; x++)
490 {
491 dest[4 * x + 0] = source[2*x+0];
492 dest[4 * x + 1] = source[2*x+0];
493 dest[4 * x + 2] = source[2*x+0];
494 dest[4 * x + 3] = source[2*x+1];
495 }
496 }
497 else
498 {
499 memcpy(dest, source, width * 2);
500 }
501 }
502}
503
504void Texture::loadLuminanceAlphaFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
505 int inputPitch, const void *input, size_t outputPitch, void *output) const
506{
507 const float *source = NULL;
508 float *dest = NULL;
509
510 for (int y = 0; y < height; y++)
511 {
512 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
513 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
514 for (int x = 0; x < width; x++)
515 {
516 dest[4 * x + 0] = source[2*x+0];
517 dest[4 * x + 1] = source[2*x+0];
518 dest[4 * x + 2] = source[2*x+0];
519 dest[4 * x + 3] = source[2*x+1];
520 }
521 }
522}
523
524void Texture::loadLuminanceAlphaHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
525 int inputPitch, const void *input, size_t outputPitch, void *output) const
526{
527 const unsigned short *source = NULL;
528 unsigned short *dest = NULL;
529
530 for (int y = 0; y < height; y++)
531 {
532 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
533 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
534 for (int x = 0; x < width; x++)
535 {
536 dest[4 * x + 0] = source[2*x+0];
537 dest[4 * x + 1] = source[2*x+0];
538 dest[4 * x + 2] = source[2*x+0];
539 dest[4 * x + 3] = source[2*x+1];
540 }
541 }
542}
543
544void Texture::loadRGBUByteImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
545 int inputPitch, const void *input, size_t outputPitch, void *output) const
546{
547 const unsigned char *source = NULL;
548 unsigned char *dest = NULL;
549
550 for (int y = 0; y < height; y++)
551 {
552 source = static_cast<const unsigned char*>(input) + y * inputPitch;
553 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
554 for (int x = 0; x < width; x++)
555 {
556 dest[4 * x + 0] = source[x * 3 + 2];
557 dest[4 * x + 1] = source[x * 3 + 1];
558 dest[4 * x + 2] = source[x * 3 + 0];
559 dest[4 * x + 3] = 0xFF;
560 }
561 }
562}
563
564void Texture::loadRGB565ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
565 int inputPitch, const void *input, size_t outputPitch, void *output) const
566{
567 const unsigned short *source = NULL;
568 unsigned char *dest = NULL;
569
570 for (int y = 0; y < height; y++)
571 {
572 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
573 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
574 for (int x = 0; x < width; x++)
575 {
576 unsigned short rgba = source[x];
577 dest[4 * x + 0] = ((rgba & 0x001F) << 3) | ((rgba & 0x001F) >> 2);
578 dest[4 * x + 1] = ((rgba & 0x07E0) >> 3) | ((rgba & 0x07E0) >> 9);
579 dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
580 dest[4 * x + 3] = 0xFF;
581 }
582 }
583}
584
585void Texture::loadRGBFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
586 int inputPitch, const void *input, size_t outputPitch, void *output) const
587{
588 const float *source = NULL;
589 float *dest = NULL;
590
591 for (int y = 0; y < height; y++)
592 {
593 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
594 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
595 for (int x = 0; x < width; x++)
596 {
597 dest[4 * x + 0] = source[x * 3 + 0];
598 dest[4 * x + 1] = source[x * 3 + 1];
599 dest[4 * x + 2] = source[x * 3 + 2];
600 dest[4 * x + 3] = 1.0f;
601 }
602 }
603}
604
605void Texture::loadRGBHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
606 int inputPitch, const void *input, size_t outputPitch, void *output) const
607{
608 const unsigned short *source = NULL;
609 unsigned short *dest = NULL;
610
611 for (int y = 0; y < height; y++)
612 {
613 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
614 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
615 for (int x = 0; x < width; x++)
616 {
617 dest[4 * x + 0] = source[x * 3 + 0];
618 dest[4 * x + 1] = source[x * 3 + 1];
619 dest[4 * x + 2] = source[x * 3 + 2];
620 dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1
621 }
622 }
623}
624
jbauman@chromium.orgf1f28c82011-05-12 20:53:34 +0000625void Texture::loadRGBAUByteImageDataSSE2(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
626 int inputPitch, const void *input, size_t outputPitch, void *output) const
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000627{
jbauman@chromium.orgf1f28c82011-05-12 20:53:34 +0000628 const unsigned int *source = NULL;
629 unsigned int *dest = NULL;
630 __m128i brMask = _mm_set1_epi32(0x00ff00ff);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000631
632 for (int y = 0; y < height; y++)
633 {
jbauman@chromium.orgf1f28c82011-05-12 20:53:34 +0000634 source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);
635 dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4);
636 int x = 0;
637
638 // Make output writes aligned
639 for (x = 0; ((reinterpret_cast<intptr_t>(&dest[x]) & 15) != 0) && x < width; x++)
640 {
641 unsigned int rgba = source[x];
642 dest[x] = (_rotl(rgba, 16) & 0x00ff00ff) | (rgba & 0xff00ff00);
643 }
644
645 for (; x + 3 < width; x += 4)
646 {
647 __m128i sourceData = _mm_loadu_si128(reinterpret_cast<const __m128i*>(&source[x]));
648 // Mask out g and a, which don't change
649 __m128i gaComponents = _mm_andnot_si128(brMask, sourceData);
650 // Mask out b and r
651 __m128i brComponents = _mm_and_si128(sourceData, brMask);
652 // Swap b and r
653 __m128i brSwapped = _mm_shufflehi_epi16(_mm_shufflelo_epi16(brComponents, _MM_SHUFFLE(2, 3, 0, 1)), _MM_SHUFFLE(2, 3, 0, 1));
654 __m128i result = _mm_or_si128(gaComponents, brSwapped);
655 _mm_store_si128(reinterpret_cast<__m128i*>(&dest[x]), result);
656 }
657
658 // Perform leftover writes
659 for (; x < width; x++)
660 {
661 unsigned int rgba = source[x];
662 dest[x] = (_rotl(rgba, 16) & 0x00ff00ff) | (rgba & 0xff00ff00);
663 }
664 }
665}
666
667void Texture::loadRGBAUByteImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
668 int inputPitch, const void *input, size_t outputPitch, void *output) const
669{
670 const unsigned int *source = NULL;
671 unsigned int *dest = NULL;
672 for (int y = 0; y < height; y++)
673 {
674 source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);
675 dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4);
676
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000677 for (int x = 0; x < width; x++)
678 {
jbauman@chromium.orgf1f28c82011-05-12 20:53:34 +0000679 unsigned int rgba = source[x];
680 dest[x] = (_rotl(rgba, 16) & 0x00ff00ff) | (rgba & 0xff00ff00);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000681 }
682 }
683}
684
685void Texture::loadRGBA4444ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
686 int inputPitch, const void *input, size_t outputPitch, void *output) const
687{
688 const unsigned short *source = NULL;
689 unsigned char *dest = NULL;
690
691 for (int y = 0; y < height; y++)
692 {
693 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
694 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
695 for (int x = 0; x < width; x++)
696 {
697 unsigned short rgba = source[x];
698 dest[4 * x + 0] = ((rgba & 0x00F0) << 0) | ((rgba & 0x00F0) >> 4);
699 dest[4 * x + 1] = ((rgba & 0x0F00) >> 4) | ((rgba & 0x0F00) >> 8);
700 dest[4 * x + 2] = ((rgba & 0xF000) >> 8) | ((rgba & 0xF000) >> 12);
701 dest[4 * x + 3] = ((rgba & 0x000F) << 4) | ((rgba & 0x000F) >> 0);
702 }
703 }
704}
705
706void Texture::loadRGBA5551ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
707 int inputPitch, const void *input, size_t outputPitch, void *output) const
708{
709 const unsigned short *source = NULL;
710 unsigned char *dest = NULL;
711
712 for (int y = 0; y < height; y++)
713 {
714 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
715 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
716 for (int x = 0; x < width; x++)
717 {
718 unsigned short rgba = source[x];
719 dest[4 * x + 0] = ((rgba & 0x003E) << 2) | ((rgba & 0x003E) >> 3);
720 dest[4 * x + 1] = ((rgba & 0x07C0) >> 3) | ((rgba & 0x07C0) >> 8);
721 dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
722 dest[4 * x + 3] = (rgba & 0x0001) ? 0xFF : 0;
723 }
724 }
725}
726
727void Texture::loadRGBAFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
728 int inputPitch, const void *input, size_t outputPitch, void *output) const
729{
730 const float *source = NULL;
731 float *dest = NULL;
732
733 for (int y = 0; y < height; y++)
734 {
735 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
736 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
737 memcpy(dest, source, width * 16);
738 }
739}
740
741void Texture::loadRGBAHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
742 int inputPitch, const void *input, size_t outputPitch, void *output) const
743{
744 const unsigned char *source = NULL;
745 unsigned char *dest = NULL;
746
747 for (int y = 0; y < height; y++)
748 {
749 source = static_cast<const unsigned char*>(input) + y * inputPitch;
750 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8;
751 memcpy(dest, source, width * 8);
752 }
753}
754
755void Texture::loadBGRAImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
756 int inputPitch, const void *input, size_t outputPitch, void *output) const
757{
758 const unsigned char *source = NULL;
759 unsigned char *dest = NULL;
760
761 for (int y = 0; y < height; y++)
762 {
763 source = static_cast<const unsigned char*>(input) + y * inputPitch;
764 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
765 memcpy(dest, source, width*4);
766 }
767}
768
769void Texture::loadCompressedImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
770 int inputPitch, const void *input, size_t outputPitch, void *output) const
771{
772 ASSERT(xoffset % 4 == 0);
773 ASSERT(yoffset % 4 == 0);
774 ASSERT(width % 4 == 0 || width == 2 || width == 1);
775 ASSERT(inputPitch % 8 == 0);
776 ASSERT(outputPitch % 8 == 0);
777
778 const unsigned int *source = reinterpret_cast<const unsigned int*>(input);
779 unsigned int *dest = reinterpret_cast<unsigned int*>(output);
780
781 switch (height)
782 {
783 case 1:
784 // Round width up in case it is 1.
785 for (int x = 0; x < (width + 1) / 2; x += 2)
786 {
787 // First 32-bits is two RGB565 colors shared by tile and does not need to be modified.
788 dest[x] = source[x];
789
790 // Second 32-bits contains 4 rows of 4 2-bit interpolants between the colors, the last 3 rows being unused. No flipping should occur.
791 dest[x + 1] = source[x + 1];
792 }
793 break;
794 case 2:
795 // Round width up in case it is 1.
796 for (int x = 0; x < (width + 1) / 2; x += 2)
797 {
798 // First 32-bits is two RGB565 colors shared by tile and does not need to be modified.
799 dest[x] = source[x];
800
801 // 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.
802 dest[x + 1] = ((source[x + 1] << 8) & 0x0000FF00) |
803 ((source[x + 1] >> 8) & 0x000000FF);
804 }
805 break;
806 default:
807 ASSERT(height % 4 == 0);
808 for (int y = 0; y < height / 4; ++y)
809 {
810 const unsigned int *source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);
811 unsigned int *dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
812
813 // Round width up in case it is 1.
814 for (int x = 0; x < (width + 1) / 2; x += 2)
815 {
816 // First 32-bits is two RGB565 colors shared by tile and does not need to be modified.
817 dest[x] = source[x];
818
819 // Second 32-bits contains 4 rows of 4 2-bit interpolants between the colors. All rows should be flipped.
820 dest[x + 1] = (source[x + 1] >> 24) |
821 ((source[x + 1] << 8) & 0x00FF0000) |
822 ((source[x + 1] >> 8) & 0x0000FF00) |
823 (source[x + 1] << 24);
824 }
825 }
826 break;
827 }
828}
829
daniel@transgaming.com61208202011-03-21 16:38:50 +0000830void Texture::createSurface(Image *image)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000831{
832 IDirect3DTexture9 *newTexture = NULL;
833 IDirect3DSurface9 *newSurface = NULL;
834
daniel@transgaming.com61208202011-03-21 16:38:50 +0000835 if (image->width != 0 && image->height != 0)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000836 {
837 int levelToFetch = 0;
daniel@transgaming.com61208202011-03-21 16:38:50 +0000838 GLsizei requestWidth = image->width;
839 GLsizei requestHeight = image->height;
840 if (IsCompressed(image->format) && (image->width % 4 != 0 || image->height % 4 != 0))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000841 {
842 bool isMult4 = false;
843 int upsampleCount = 0;
844 while (!isMult4)
845 {
846 requestWidth <<= 1;
847 requestHeight <<= 1;
848 upsampleCount++;
849 if (requestWidth % 4 == 0 && requestHeight % 4 == 0)
850 {
851 isMult4 = true;
852 }
853 }
854 levelToFetch = upsampleCount;
855 }
856
daniel@transgaming.com549bdef2011-03-29 00:57:01 +0000857 HRESULT result = getDevice()->CreateTexture(requestWidth, requestHeight, levelToFetch + 1, NULL, image->getD3DFormat(),
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000858 D3DPOOL_SYSTEMMEM, &newTexture, NULL);
859
860 if (FAILED(result))
861 {
862 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
863 return error(GL_OUT_OF_MEMORY);
864 }
865
866 newTexture->GetSurfaceLevel(levelToFetch, &newSurface);
867 newTexture->Release();
868 }
869
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +0000870 if (image->surface)
871 {
872 image->surface->Release();
873 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000874
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +0000875 image->surface = newSurface;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000876}
877
daniel@transgaming.com61208202011-03-21 16:38:50 +0000878void Texture::setImage(GLint unpackAlignment, const void *pixels, Image *image)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000879{
daniel@transgaming.com61208202011-03-21 16:38:50 +0000880 createSurface(image);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000881
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000882 if (pixels != NULL && image->surface != NULL)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000883 {
884 D3DSURFACE_DESC description;
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000885 image->surface->GetDesc(&description);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000886
887 D3DLOCKED_RECT locked;
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000888 HRESULT result = image->surface->LockRect(&locked, NULL, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000889
890 ASSERT(SUCCEEDED(result));
891
892 if (SUCCEEDED(result))
893 {
daniel@transgaming.com61208202011-03-21 16:38:50 +0000894 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 +0000895 image->surface->UnlockRect();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000896 }
897
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000898 image->dirty = true;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +0000899 mDirtyImage = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000900 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000901}
902
daniel@transgaming.com61208202011-03-21 16:38:50 +0000903void Texture::setCompressedImage(GLsizei imageSize, const void *pixels, Image *image)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000904{
daniel@transgaming.com61208202011-03-21 16:38:50 +0000905 createSurface(image);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000906
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000907 if (pixels != NULL && image->surface != NULL)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000908 {
909 D3DLOCKED_RECT locked;
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000910 HRESULT result = image->surface->LockRect(&locked, NULL, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000911
912 ASSERT(SUCCEEDED(result));
913
914 if (SUCCEEDED(result))
915 {
daniel@transgaming.com61208202011-03-21 16:38:50 +0000916 int inputPitch = ComputeCompressedPitch(image->width, image->format);
917 int inputSize = ComputeCompressedSize(image->width, image->height, image->format);
918 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 +0000919 image->surface->UnlockRect();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000920 }
921
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000922 image->dirty = true;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +0000923 mDirtyImage = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000924 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000925}
926
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000927bool 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 +0000928{
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000929 if (width + xoffset > image->width || height + yoffset > image->height)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000930 {
931 error(GL_INVALID_VALUE);
932 return false;
933 }
934
jbauman@chromium.orge2f954c2011-05-03 20:45:27 +0000935 if (IsCompressed(image->format))
936 {
937 error(GL_INVALID_OPERATION);
938 return false;
939 }
940
941 if (format != image->format)
942 {
943 error(GL_INVALID_OPERATION);
944 return false;
945 }
946
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000947 if (!image->surface)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000948 {
daniel@transgaming.com61208202011-03-21 16:38:50 +0000949 createSurface(image);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000950 }
951
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000952 if (pixels != NULL && image->surface != NULL)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000953 {
954 D3DSURFACE_DESC description;
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000955 image->surface->GetDesc(&description);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000956
957 D3DLOCKED_RECT locked;
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000958 HRESULT result = image->surface->LockRect(&locked, NULL, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000959
960 ASSERT(SUCCEEDED(result));
961
962 if (SUCCEEDED(result))
963 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000964 loadImageData(xoffset, transformPixelYOffset(yoffset, height, image->height), width, height, format, type, unpackAlignment, pixels, locked.Pitch, locked.pBits, &description);
965 image->surface->UnlockRect();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000966 }
967
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000968 image->dirty = true;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +0000969 mDirtyImage = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000970 }
971
972 return true;
973}
974
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000975bool 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 +0000976{
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000977 if (width + xoffset > image->width || height + yoffset > image->height)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000978 {
979 error(GL_INVALID_VALUE);
980 return false;
981 }
982
983 if (format != getInternalFormat())
984 {
985 error(GL_INVALID_OPERATION);
986 return false;
987 }
988
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000989 if (!image->surface)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000990 {
daniel@transgaming.com61208202011-03-21 16:38:50 +0000991 createSurface(image);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000992 }
993
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000994 if (pixels != NULL && image->surface != NULL)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000995 {
996 RECT updateRegion;
997 updateRegion.left = xoffset;
998 updateRegion.right = xoffset + width;
999 updateRegion.bottom = yoffset + height;
1000 updateRegion.top = yoffset;
1001
1002 D3DLOCKED_RECT locked;
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001003 HRESULT result = image->surface->LockRect(&locked, &updateRegion, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001004
1005 ASSERT(SUCCEEDED(result));
1006
1007 if (SUCCEEDED(result))
1008 {
1009 int inputPitch = ComputeCompressedPitch(width, format);
1010 int inputSize = ComputeCompressedSize(width, height, format);
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001011 loadCompressedImageData(xoffset, transformPixelYOffset(yoffset, height, image->height), width, height, -inputPitch, static_cast<const char*>(pixels) + inputSize - inputPitch, locked.Pitch, locked.pBits);
1012 image->surface->UnlockRect();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001013 }
1014
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001015 image->dirty = true;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00001016 mDirtyImage = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001017 }
1018
1019 return true;
1020}
1021
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001022// This implements glCopyTex[Sub]Image2D for non-renderable internal texture formats and incomplete textures
1023void 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 +00001024{
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001025 if (!image->surface)
1026 {
1027 createSurface(image);
1028
1029 if (!image->surface)
1030 {
1031 ERR("Failed to create an image surface.");
1032 return error(GL_OUT_OF_MEMORY);
1033 }
1034 }
1035
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001036 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001037 IDirect3DSurface9 *renderTargetData = NULL;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001038 D3DSURFACE_DESC description;
1039 renderTarget->GetDesc(&description);
1040
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001041 HRESULT result = device->CreateOffscreenPlainSurface(description.Width, description.Height, description.Format, D3DPOOL_SYSTEMMEM, &renderTargetData, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001042
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001043 if (FAILED(result))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001044 {
1045 ERR("Could not create matching destination surface.");
1046 return error(GL_OUT_OF_MEMORY);
1047 }
1048
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001049 result = device->GetRenderTargetData(renderTarget, renderTargetData);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001050
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001051 if (FAILED(result))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001052 {
1053 ERR("GetRenderTargetData unexpectedly failed.");
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001054 renderTargetData->Release();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001055 return error(GL_OUT_OF_MEMORY);
1056 }
1057
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001058 RECT sourceRect = transformPixelRect(x, y, width, height, description.Height);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001059 int destYOffset = transformPixelYOffset(yoffset, height, image->height);
1060 RECT destRect = {xoffset, destYOffset, xoffset + width, destYOffset + height};
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001061
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001062 if (image->isRenderable())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001063 {
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001064 result = D3DXLoadSurfaceFromSurface(image->surface, NULL, &destRect, renderTargetData, NULL, &sourceRect, D3DX_FILTER_BOX, 0);
1065
1066 if (FAILED(result))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001067 {
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001068 ERR("Copying surfaces unexpectedly failed.");
1069 renderTargetData->Release();
1070 return error(GL_OUT_OF_MEMORY);
1071 }
1072 }
1073 else
1074 {
1075 D3DLOCKED_RECT sourceLock = {0};
1076 result = renderTargetData->LockRect(&sourceLock, &sourceRect, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001077
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001078 if (FAILED(result))
1079 {
1080 ERR("Failed to lock the source surface (rectangle might be invalid).");
1081 renderTargetData->Release();
1082 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001083 }
1084
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001085 D3DLOCKED_RECT destLock = {0};
1086 result = image->surface->LockRect(&destLock, &destRect, 0);
1087
1088 if (FAILED(result))
1089 {
1090 ERR("Failed to lock the destination surface (rectangle might be invalid).");
1091 renderTargetData->UnlockRect();
1092 renderTargetData->Release();
1093 return error(GL_OUT_OF_MEMORY);
1094 }
1095
1096 if (destLock.pBits && sourceLock.pBits)
1097 {
1098 unsigned char *source = (unsigned char*)sourceLock.pBits;
1099 unsigned char *dest = (unsigned char*)destLock.pBits;
1100
1101 switch (description.Format)
1102 {
1103 case D3DFMT_X8R8G8B8:
1104 case D3DFMT_A8R8G8B8:
1105 switch(image->getD3DFormat())
1106 {
1107 case D3DFMT_L8:
1108 for(int y = 0; y < height; y++)
1109 {
1110 for(int x = 0; x < width; x++)
1111 {
1112 dest[x] = source[x * 4 + 2];
1113 }
1114
1115 source += sourceLock.Pitch;
1116 dest += destLock.Pitch;
1117 }
1118 break;
1119 case D3DFMT_A8L8:
1120 for(int y = 0; y < height; y++)
1121 {
1122 for(int x = 0; x < width; x++)
1123 {
1124 dest[x * 2 + 0] = source[x * 4 + 2];
1125 dest[x * 2 + 1] = source[x * 4 + 3];
1126 }
1127
1128 source += sourceLock.Pitch;
1129 dest += destLock.Pitch;
1130 }
1131 break;
1132 default:
1133 UNREACHABLE();
1134 }
1135 break;
1136 case D3DFMT_R5G6B5:
1137 switch(image->getD3DFormat())
1138 {
1139 case D3DFMT_L8:
1140 for(int y = 0; y < height; y++)
1141 {
1142 for(int x = 0; x < width; x++)
1143 {
1144 unsigned char red = source[x * 2 + 1] & 0xF8;
1145 dest[x] = red | (red >> 5);
1146 }
1147
1148 source += sourceLock.Pitch;
1149 dest += destLock.Pitch;
1150 }
1151 break;
1152 default:
1153 UNREACHABLE();
1154 }
1155 break;
1156 case D3DFMT_A1R5G5B5:
1157 switch(image->getD3DFormat())
1158 {
1159 case D3DFMT_L8:
1160 for(int y = 0; y < height; y++)
1161 {
1162 for(int x = 0; x < width; x++)
1163 {
1164 unsigned char red = source[x * 2 + 1] & 0x7C;
1165 dest[x] = (red << 1) | (red >> 4);
1166 }
1167
1168 source += sourceLock.Pitch;
1169 dest += destLock.Pitch;
1170 }
1171 break;
1172 case D3DFMT_A8L8:
1173 for(int y = 0; y < height; y++)
1174 {
1175 for(int x = 0; x < width; x++)
1176 {
1177 unsigned char red = source[x * 2 + 1] & 0x7C;
1178 dest[x * 2 + 0] = (red << 1) | (red >> 4);
1179 dest[x * 2 + 1] = (signed char)source[x * 2 + 1] >> 7;
1180 }
1181
1182 source += sourceLock.Pitch;
1183 dest += destLock.Pitch;
1184 }
1185 break;
1186 default:
1187 UNREACHABLE();
1188 }
1189 break;
1190 default:
1191 UNREACHABLE();
1192 }
1193 }
1194
1195 image->surface->UnlockRect();
1196 renderTargetData->UnlockRect();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001197 }
1198
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001199 renderTargetData->Release();
1200
1201 image->dirty = true;
1202 mDirtyImage = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001203}
1204
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001205IDirect3DBaseTexture9 *Texture::getTexture()
1206{
1207 if (!isComplete())
1208 {
1209 return NULL;
1210 }
1211
daniel@transgaming.comaed18322011-03-21 16:38:13 +00001212 if (!getBaseTexture())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001213 {
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001214 createTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001215 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001216
daniel@transgaming.comc50edcb2011-03-21 16:38:40 +00001217 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001218
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001219 return getBaseTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001220}
1221
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00001222bool Texture::isDirtyParameter() const
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001223{
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00001224 return mDirtyParameter;
1225}
1226
1227bool Texture::isDirtyImage() const
1228{
1229 return mDirtyImage;
daniel@transgaming.com38e76e52011-03-21 16:39:10 +00001230}
1231
1232void Texture::resetDirty()
1233{
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00001234 mDirtyParameter = false;
1235 mDirtyImage = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001236}
1237
daniel@transgaming.coma9eb5da2011-03-21 16:39:16 +00001238unsigned int Texture::getSerial() const
1239{
1240 return mSerial;
1241}
1242
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001243GLint Texture::creationLevels(GLsizei width, GLsizei height, GLint maxlevel) const
1244{
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00001245 if ((isPow2(width) && isPow2(height)) || getContext()->supportsNonPower2Texture())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001246 {
1247 return maxlevel;
1248 }
1249 else
1250 {
1251 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
1252 return 1;
1253 }
1254}
1255
1256GLint Texture::creationLevels(GLsizei size, GLint maxlevel) const
1257{
1258 return creationLevels(size, size, maxlevel);
1259}
1260
1261int Texture::levelCount() const
1262{
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001263 return getBaseTexture() ? getBaseTexture()->GetLevelCount() : 0;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001264}
1265
daniel@transgaming.coma9eb5da2011-03-21 16:39:16 +00001266unsigned int Texture::issueSerial()
1267{
1268 return mCurrentSerial++;
1269}
1270
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001271Texture2D::Texture2D(GLuint id) : Texture(id)
1272{
1273 mTexture = NULL;
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001274 mSurface = NULL;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001275}
1276
1277Texture2D::~Texture2D()
1278{
1279 mColorbufferProxy.set(NULL);
1280
1281 if (mTexture)
1282 {
1283 mTexture->Release();
1284 mTexture = NULL;
1285 }
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001286
1287 if (mSurface)
1288 {
1289 mSurface->setBoundTexture(NULL);
1290 mSurface = NULL;
1291 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001292}
1293
1294GLenum Texture2D::getTarget() const
1295{
1296 return GL_TEXTURE_2D;
1297}
1298
daniel@transgaming.com61208202011-03-21 16:38:50 +00001299GLsizei Texture2D::getWidth() const
1300{
1301 return mImageArray[0].width;
1302}
1303
1304GLsizei Texture2D::getHeight() const
1305{
1306 return mImageArray[0].height;
1307}
1308
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001309GLenum Texture2D::getInternalFormat() const
1310{
1311 return mImageArray[0].format;
1312}
1313
daniel@transgaming.com61208202011-03-21 16:38:50 +00001314GLenum Texture2D::getType() const
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001315{
daniel@transgaming.com61208202011-03-21 16:38:50 +00001316 return mImageArray[0].type;
1317}
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001318
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001319D3DFORMAT Texture2D::getD3DFormat() const
1320{
1321 return mImageArray[0].getD3DFormat();
1322}
1323
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001324void Texture2D::redefineTexture(GLint level, GLenum format, GLsizei width, GLsizei height, GLenum type, bool forceRedefine)
daniel@transgaming.com61208202011-03-21 16:38:50 +00001325{
daniel@transgaming.com94a4f032011-03-21 16:38:55 +00001326 GLsizei textureWidth = mImageArray[0].width;
1327 GLsizei textureHeight = mImageArray[0].height;
1328 GLenum textureFormat = mImageArray[0].format;
1329 GLenum textureType = mImageArray[0].type;
1330
daniel@transgaming.com61208202011-03-21 16:38:50 +00001331 mImageArray[level].width = width;
1332 mImageArray[level].height = height;
1333 mImageArray[level].format = format;
1334 mImageArray[level].type = type;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001335
daniel@transgaming.com61208202011-03-21 16:38:50 +00001336 if (!mTexture)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001337 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001338 return;
1339 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001340
daniel@transgaming.com94a4f032011-03-21 16:38:55 +00001341 bool widthOkay = (textureWidth >> level == width) || (textureWidth >> level == 0 && width == 1);
1342 bool heightOkay = (textureHeight >> level == height) || (textureHeight >> level == 0 && height == 1);
1343 bool textureOkay = (widthOkay && heightOkay && textureFormat == format && textureType == type);
daniel@transgaming.com61208202011-03-21 16:38:50 +00001344
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001345 if (!textureOkay || forceRedefine || mSurface) // Purge all the levels and the texture.
daniel@transgaming.com61208202011-03-21 16:38:50 +00001346 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001347 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1348 {
1349 if (mImageArray[i].surface != NULL)
1350 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001351 mImageArray[i].surface->Release();
1352 mImageArray[i].surface = NULL;
daniel@transgaming.com61208202011-03-21 16:38:50 +00001353 mImageArray[i].dirty = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001354 }
1355 }
1356
1357 if (mTexture != NULL)
1358 {
1359 mTexture->Release();
1360 mTexture = NULL;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00001361 mDirtyImage = true;
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001362 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001363 }
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001364
1365 if (mSurface)
1366 {
1367 mSurface->setBoundTexture(NULL);
1368 mSurface = NULL;
1369 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001370 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001371}
1372
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001373void 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 +00001374{
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001375 redefineTexture(level, format, width, height, type, false);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001376
daniel@transgaming.com61208202011-03-21 16:38:50 +00001377 Texture::setImage(unpackAlignment, pixels, &mImageArray[level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001378}
1379
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001380void Texture2D::bindTexImage(egl::Surface *surface)
1381{
1382 GLenum format;
1383
1384 switch(surface->getFormat())
1385 {
1386 case D3DFMT_A8R8G8B8:
1387 format = GL_RGBA;
1388 break;
1389 case D3DFMT_X8R8G8B8:
1390 format = GL_RGB;
1391 break;
1392 default:
1393 UNIMPLEMENTED();
1394 return;
1395 }
1396
1397 redefineTexture(0, format, surface->getWidth(), surface->getHeight(), GL_UNSIGNED_BYTE, true);
1398
1399 IDirect3DTexture9 *texture = surface->getOffscreenTexture();
1400
1401 mTexture = texture;
1402 mDirtyImage = true;
1403 mIsRenderable = true;
1404 mSurface = surface;
1405 mSurface->setBoundTexture(this);
1406}
1407
1408void Texture2D::releaseTexImage()
1409{
1410 redefineTexture(0, GL_RGB, 0, 0, GL_UNSIGNED_BYTE, true);
1411}
1412
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001413void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001414{
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001415 redefineTexture(level, format, width, height, GL_UNSIGNED_BYTE, false);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001416
daniel@transgaming.com61208202011-03-21 16:38:50 +00001417 Texture::setCompressedImage(imageSize, pixels, &mImageArray[level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001418}
1419
1420void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1421{
1422 ASSERT(mImageArray[level].surface != NULL);
1423
1424 if (level < levelCount())
1425 {
1426 IDirect3DSurface9 *destLevel = NULL;
1427 HRESULT result = mTexture->GetSurfaceLevel(level, &destLevel);
1428
1429 ASSERT(SUCCEEDED(result));
1430
1431 if (SUCCEEDED(result))
1432 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001433 Image *image = &mImageArray[level];
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001434
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001435 RECT sourceRect = transformPixelRect(xoffset, yoffset, width, height, image->height);;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001436
1437 POINT destPoint;
1438 destPoint.x = sourceRect.left;
1439 destPoint.y = sourceRect.top;
1440
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001441 result = getDevice()->UpdateSurface(image->surface, &sourceRect, destLevel, &destPoint);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001442 ASSERT(SUCCEEDED(result));
1443
1444 destLevel->Release();
1445
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001446 image->dirty = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001447 }
1448 }
1449}
1450
1451void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1452{
1453 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[level]))
1454 {
1455 commitRect(level, xoffset, yoffset, width, height);
1456 }
1457}
1458
1459void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1460{
1461 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[level]))
1462 {
1463 commitRect(level, xoffset, yoffset, width, height);
1464 }
1465}
1466
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001467void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001468{
1469 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
1470
1471 if (!renderTarget)
1472 {
1473 ERR("Failed to retrieve the render target.");
1474 return error(GL_OUT_OF_MEMORY);
1475 }
1476
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001477 redefineTexture(level, format, width, height, GL_UNSIGNED_BYTE, false);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001478
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001479 if (!mImageArray[level].isRenderable())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001480 {
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001481 copyToImage(&mImageArray[level], 0, 0, x, y, width, height, renderTarget);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001482 }
1483 else
1484 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001485 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001486 {
1487 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001488 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00001489
1490 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001491
1492 if (width != 0 && height != 0 && level < levelCount())
1493 {
1494 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
1495 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
1496 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
1497 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
1498 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
daniel@transgaming.comeef864a2011-04-22 11:33:27 +00001499
1500 GLint destYOffset = transformPixelYOffset(0, height, mImageArray[level].height);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001501
1502 IDirect3DSurface9 *dest;
1503 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
1504
daniel@transgaming.comeef864a2011-04-22 11:33:27 +00001505 getBlitter()->copy(source->getRenderTarget(), sourceRect, format, 0, destYOffset, dest);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001506 dest->Release();
1507 }
1508 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001509}
1510
1511void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1512{
1513 if (xoffset + width > mImageArray[level].width || yoffset + height > mImageArray[level].height)
1514 {
1515 return error(GL_INVALID_VALUE);
1516 }
1517
1518 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
1519
1520 if (!renderTarget)
1521 {
1522 ERR("Failed to retrieve the render target.");
1523 return error(GL_OUT_OF_MEMORY);
1524 }
1525
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001526 redefineTexture(level, mImageArray[level].format, mImageArray[level].width, mImageArray[level].height, GL_UNSIGNED_BYTE, false);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001527
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001528 if (!mImageArray[level].isRenderable() || (!mTexture && !isComplete()))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001529 {
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001530 copyToImage(&mImageArray[level], xoffset, yoffset, x, y, width, height, renderTarget);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001531 }
1532 else
1533 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001534 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001535 {
1536 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001537 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00001538
1539 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001540
1541 if (level < levelCount())
1542 {
1543 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
1544 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
1545 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
1546 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
1547 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
1548
1549 GLint destYOffset = transformPixelYOffset(yoffset, height, mImageArray[level].height);
1550
1551 IDirect3DSurface9 *dest;
1552 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
1553
daniel@transgaming.comeef864a2011-04-22 11:33:27 +00001554 getBlitter()->copy(source->getRenderTarget(), sourceRect, mImageArray[0].format, xoffset, destYOffset, dest);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001555 dest->Release();
1556 }
1557 }
1558}
1559
1560// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1561bool Texture2D::isComplete() const
1562{
1563 GLsizei width = mImageArray[0].width;
1564 GLsizei height = mImageArray[0].height;
1565
1566 if (width <= 0 || height <= 0)
1567 {
1568 return false;
1569 }
1570
1571 bool mipmapping = false;
1572
1573 switch (mMinFilter)
1574 {
1575 case GL_NEAREST:
1576 case GL_LINEAR:
1577 mipmapping = false;
1578 break;
1579 case GL_NEAREST_MIPMAP_NEAREST:
1580 case GL_LINEAR_MIPMAP_NEAREST:
1581 case GL_NEAREST_MIPMAP_LINEAR:
1582 case GL_LINEAR_MIPMAP_LINEAR:
1583 mipmapping = true;
1584 break;
1585 default: UNREACHABLE();
1586 }
1587
1588 if ((getInternalFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) ||
1589 (getInternalFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter()))
1590 {
1591 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
1592 {
1593 return false;
1594 }
1595 }
1596
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00001597 bool npot = getContext()->supportsNonPower2Texture();
1598
1599 if (!npot)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001600 {
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00001601 if ((getWrapS() != GL_CLAMP_TO_EDGE && !isPow2(width)) ||
1602 (getWrapT() != GL_CLAMP_TO_EDGE && !isPow2(height)))
1603 {
1604 return false;
1605 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001606 }
1607
1608 if (mipmapping)
1609 {
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00001610 if (!npot)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001611 {
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00001612 if (!isPow2(width) || !isPow2(height))
1613 {
1614 return false;
1615 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001616 }
1617
1618 int q = log2(std::max(width, height));
1619
1620 for (int level = 1; level <= q; level++)
1621 {
1622 if (mImageArray[level].format != mImageArray[0].format)
1623 {
1624 return false;
1625 }
1626
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00001627 if (mImageArray[level].type != mImageArray[0].type)
1628 {
1629 return false;
1630 }
1631
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001632 if (mImageArray[level].width != std::max(1, width >> level))
1633 {
1634 return false;
1635 }
1636
1637 if (mImageArray[level].height != std::max(1, height >> level))
1638 {
1639 return false;
1640 }
1641 }
1642 }
1643
1644 return true;
1645}
1646
1647bool Texture2D::isCompressed() const
1648{
1649 return IsCompressed(getInternalFormat());
1650}
1651
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001652IDirect3DBaseTexture9 *Texture2D::getBaseTexture() const
1653{
1654 return mTexture;
1655}
1656
1657// Constructs a Direct3D 9 texture resource from the texture images
1658void Texture2D::createTexture()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001659{
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001660 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001661 D3DFORMAT format = mImageArray[0].getD3DFormat();
daniel@transgaming.com61208202011-03-21 16:38:50 +00001662 GLint levels = creationLevels(mImageArray[0].width, mImageArray[0].height, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001663
daniel@transgaming.com61208202011-03-21 16:38:50 +00001664 IDirect3DTexture9 *texture = NULL;
1665 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 +00001666
1667 if (FAILED(result))
1668 {
1669 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001670 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001671 }
1672
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001673 if (mTexture)
1674 {
1675 mTexture->Release();
1676 }
1677
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001678 mTexture = texture;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00001679 mDirtyImage = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00001680 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001681}
1682
1683void Texture2D::updateTexture()
1684{
1685 IDirect3DDevice9 *device = getDevice();
1686
1687 int levels = levelCount();
1688
1689 for (int level = 0; level < levels; level++)
1690 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001691 if (mImageArray[level].surface && mImageArray[level].dirty)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001692 {
1693 IDirect3DSurface9 *levelSurface = NULL;
1694 HRESULT result = mTexture->GetSurfaceLevel(level, &levelSurface);
1695
1696 ASSERT(SUCCEEDED(result));
1697
1698 if (SUCCEEDED(result))
1699 {
1700 result = device->UpdateSurface(mImageArray[level].surface, NULL, levelSurface, NULL);
1701 ASSERT(SUCCEEDED(result));
1702
1703 levelSurface->Release();
1704
1705 mImageArray[level].dirty = false;
1706 }
1707 }
1708 }
1709}
1710
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001711void Texture2D::convertToRenderTarget()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001712{
1713 IDirect3DTexture9 *texture = NULL;
1714
daniel@transgaming.com61208202011-03-21 16:38:50 +00001715 if (mImageArray[0].width != 0 && mImageArray[0].height != 0)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001716 {
1717 egl::Display *display = getDisplay();
1718 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001719 D3DFORMAT format = mImageArray[0].getD3DFormat();
daniel@transgaming.com61208202011-03-21 16:38:50 +00001720 GLint levels = creationLevels(mImageArray[0].width, mImageArray[0].height, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001721
daniel@transgaming.com61208202011-03-21 16:38:50 +00001722 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 +00001723
1724 if (FAILED(result))
1725 {
1726 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001727 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001728 }
1729
1730 if (mTexture != NULL)
1731 {
1732 int levels = levelCount();
1733 for (int i = 0; i < levels; i++)
1734 {
1735 IDirect3DSurface9 *source;
1736 result = mTexture->GetSurfaceLevel(i, &source);
1737
1738 if (FAILED(result))
1739 {
1740 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1741
1742 texture->Release();
1743
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001744 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001745 }
1746
1747 IDirect3DSurface9 *dest;
1748 result = texture->GetSurfaceLevel(i, &dest);
1749
1750 if (FAILED(result))
1751 {
1752 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1753
1754 texture->Release();
1755 source->Release();
1756
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001757 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001758 }
1759
1760 display->endScene();
1761 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
1762
1763 if (FAILED(result))
1764 {
1765 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1766
1767 texture->Release();
1768 source->Release();
1769 dest->Release();
1770
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001771 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001772 }
1773
1774 source->Release();
1775 dest->Release();
1776 }
1777 }
1778 }
1779
1780 if (mTexture != NULL)
1781 {
1782 mTexture->Release();
1783 }
1784
1785 mTexture = texture;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00001786 mDirtyImage = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00001787 mIsRenderable = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001788}
1789
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001790void Texture2D::generateMipmaps()
1791{
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00001792 if (!getContext()->supportsNonPower2Texture())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001793 {
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00001794 if (!isPow2(mImageArray[0].width) || !isPow2(mImageArray[0].height))
1795 {
1796 return error(GL_INVALID_OPERATION);
1797 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001798 }
1799
1800 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
daniel@transgaming.com61208202011-03-21 16:38:50 +00001801 unsigned int q = log2(std::max(mImageArray[0].width, mImageArray[0].height));
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001802 for (unsigned int i = 1; i <= q; i++)
1803 {
1804 if (mImageArray[i].surface != NULL)
1805 {
1806 mImageArray[i].surface->Release();
1807 mImageArray[i].surface = NULL;
1808 }
1809
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001810 mImageArray[i].width = std::max(mImageArray[0].width >> i, 1);
1811 mImageArray[i].height = std::max(mImageArray[0].height >> i, 1);
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00001812 mImageArray[i].format = mImageArray[0].format;
1813 mImageArray[i].type = mImageArray[0].type;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001814 }
1815
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001816 if (mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001817 {
1818 if (mTexture == NULL)
1819 {
1820 ERR(" failed because mTexture was null.");
1821 return;
1822 }
1823
1824 for (unsigned int i = 1; i <= q; i++)
1825 {
1826 IDirect3DSurface9 *upper = NULL;
1827 IDirect3DSurface9 *lower = NULL;
1828
1829 mTexture->GetSurfaceLevel(i-1, &upper);
1830 mTexture->GetSurfaceLevel(i, &lower);
1831
1832 if (upper != NULL && lower != NULL)
1833 {
1834 getBlitter()->boxFilter(upper, lower);
1835 }
1836
1837 if (upper != NULL) upper->Release();
1838 if (lower != NULL) lower->Release();
daniel@transgaming.com61208202011-03-21 16:38:50 +00001839
1840 mImageArray[i].dirty = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001841 }
1842 }
1843 else
1844 {
1845 for (unsigned int i = 1; i <= q; i++)
1846 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001847 createSurface(&mImageArray[i]);
1848
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001849 if (mImageArray[i].surface == NULL)
1850 {
1851 return error(GL_OUT_OF_MEMORY);
1852 }
1853
1854 if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[i].surface, NULL, NULL, mImageArray[i - 1].surface, NULL, NULL, D3DX_FILTER_BOX, 0)))
1855 {
1856 ERR(" failed to load filter %d to %d.", i - 1, i);
1857 }
1858
1859 mImageArray[i].dirty = true;
1860 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001861 }
1862}
1863
1864Renderbuffer *Texture2D::getRenderbuffer(GLenum target)
1865{
1866 if (target != GL_TEXTURE_2D)
1867 {
1868 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
1869 }
1870
1871 if (mColorbufferProxy.get() == NULL)
1872 {
1873 mColorbufferProxy.set(new Renderbuffer(id(), new Colorbuffer(this, target)));
1874 }
1875
1876 return mColorbufferProxy.get();
1877}
1878
1879IDirect3DSurface9 *Texture2D::getRenderTarget(GLenum target)
1880{
1881 ASSERT(target == GL_TEXTURE_2D);
1882
daniel@transgaming.com61208202011-03-21 16:38:50 +00001883 if (!mIsRenderable)
1884 {
1885 convertToRenderTarget();
1886 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001887
1888 if (mTexture == NULL)
1889 {
1890 return NULL;
1891 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00001892
1893 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001894
1895 IDirect3DSurface9 *renderTarget = NULL;
1896 mTexture->GetSurfaceLevel(0, &renderTarget);
1897
1898 return renderTarget;
1899}
1900
1901TextureCubeMap::TextureCubeMap(GLuint id) : Texture(id)
1902{
1903 mTexture = NULL;
1904}
1905
1906TextureCubeMap::~TextureCubeMap()
1907{
1908 for (int i = 0; i < 6; i++)
1909 {
1910 mFaceProxies[i].set(NULL);
1911 }
1912
1913 if (mTexture)
1914 {
1915 mTexture->Release();
1916 mTexture = NULL;
1917 }
1918}
1919
1920GLenum TextureCubeMap::getTarget() const
1921{
1922 return GL_TEXTURE_CUBE_MAP;
1923}
1924
daniel@transgaming.com61208202011-03-21 16:38:50 +00001925GLsizei TextureCubeMap::getWidth() const
1926{
1927 return mImageArray[0][0].width;
1928}
1929
1930GLsizei TextureCubeMap::getHeight() const
1931{
1932 return mImageArray[0][0].height;
1933}
1934
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001935GLenum TextureCubeMap::getInternalFormat() const
1936{
1937 return mImageArray[0][0].format;
1938}
1939
daniel@transgaming.com61208202011-03-21 16:38:50 +00001940GLenum TextureCubeMap::getType() const
1941{
1942 return mImageArray[0][0].type;
1943}
1944
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001945D3DFORMAT TextureCubeMap::getD3DFormat() const
1946{
1947 return mImageArray[0][0].getD3DFormat();
1948}
1949
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001950void 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 +00001951{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001952 setImage(0, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001953}
1954
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001955void 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 +00001956{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001957 setImage(1, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001958}
1959
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001960void 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 +00001961{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001962 setImage(2, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001963}
1964
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001965void 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 +00001966{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001967 setImage(3, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001968}
1969
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001970void 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 +00001971{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001972 setImage(4, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001973}
1974
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001975void 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 +00001976{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001977 setImage(5, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001978}
1979
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001980void 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 +00001981{
daniel@transgaming.com61208202011-03-21 16:38:50 +00001982 redefineTexture(faceIndex(face), level, format, width, height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001983
daniel@transgaming.com61208202011-03-21 16:38:50 +00001984 Texture::setCompressedImage(imageSize, pixels, &mImageArray[faceIndex(face)][level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001985}
1986
1987void TextureCubeMap::commitRect(GLenum faceTarget, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1988{
1989 int face = faceIndex(faceTarget);
1990 ASSERT(mImageArray[face][level].surface != NULL);
1991
1992 if (level < levelCount())
1993 {
1994 IDirect3DSurface9 *destLevel = getCubeMapSurface(faceTarget, level);
1995 ASSERT(destLevel != NULL);
1996
1997 if (destLevel != NULL)
1998 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001999 Image *image = &mImageArray[face][level];
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002000
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00002001 RECT sourceRect = transformPixelRect(xoffset, yoffset, width, height, image->height);;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002002
2003 POINT destPoint;
2004 destPoint.x = sourceRect.left;
2005 destPoint.y = sourceRect.top;
2006
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00002007 HRESULT result = getDevice()->UpdateSurface(image->surface, &sourceRect, destLevel, &destPoint);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002008 ASSERT(SUCCEEDED(result));
2009
2010 destLevel->Release();
2011
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00002012 image->dirty = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002013 }
2014 }
2015}
2016
2017void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
2018{
2019 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[faceIndex(target)][level]))
2020 {
2021 commitRect(target, level, xoffset, yoffset, width, height);
2022 }
2023}
2024
2025void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
2026{
2027 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[faceIndex(target)][level]))
2028 {
2029 commitRect(target, level, xoffset, yoffset, width, height);
2030 }
2031}
2032
2033// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
2034bool TextureCubeMap::isComplete() const
2035{
2036 int size = mImageArray[0][0].width;
2037
2038 if (size <= 0)
2039 {
2040 return false;
2041 }
2042
2043 bool mipmapping;
2044
2045 switch (mMinFilter)
2046 {
2047 case GL_NEAREST:
2048 case GL_LINEAR:
2049 mipmapping = false;
2050 break;
2051 case GL_NEAREST_MIPMAP_NEAREST:
2052 case GL_LINEAR_MIPMAP_NEAREST:
2053 case GL_NEAREST_MIPMAP_LINEAR:
2054 case GL_LINEAR_MIPMAP_LINEAR:
2055 mipmapping = true;
2056 break;
2057 default: UNREACHABLE();
2058 }
2059
2060 for (int face = 0; face < 6; face++)
2061 {
2062 if (mImageArray[face][0].width != size || mImageArray[face][0].height != size)
2063 {
2064 return false;
2065 }
2066 }
2067
2068 if ((getInternalFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) ||
2069 (getInternalFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter()))
2070 {
2071 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
2072 {
2073 return false;
2074 }
2075 }
2076
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00002077 bool npot = getContext()->supportsNonPower2Texture();
2078
2079 if (!npot)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002080 {
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00002081 if ((getWrapS() != GL_CLAMP_TO_EDGE || getWrapT() != GL_CLAMP_TO_EDGE) && !isPow2(size))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002082 {
2083 return false;
2084 }
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00002085 }
2086
2087 if (mipmapping)
2088 {
2089 if (!npot)
2090 {
2091 if (!isPow2(size))
2092 {
2093 return false;
2094 }
2095 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002096
2097 int q = log2(size);
2098
2099 for (int face = 0; face < 6; face++)
2100 {
2101 for (int level = 1; level <= q; level++)
2102 {
2103 if (mImageArray[face][level].format != mImageArray[0][0].format)
2104 {
2105 return false;
2106 }
2107
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00002108 if (mImageArray[face][level].type != mImageArray[0][0].type)
2109 {
2110 return false;
2111 }
2112
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002113 if (mImageArray[face][level].width != std::max(1, size >> level))
2114 {
2115 return false;
2116 }
2117
2118 ASSERT(mImageArray[face][level].height == mImageArray[face][level].width);
2119 }
2120 }
2121 }
2122
2123 return true;
2124}
2125
2126bool TextureCubeMap::isCompressed() const
2127{
2128 return IsCompressed(getInternalFormat());
2129}
2130
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002131IDirect3DBaseTexture9 *TextureCubeMap::getBaseTexture() const
2132{
2133 return mTexture;
2134}
2135
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002136// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002137void TextureCubeMap::createTexture()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002138{
2139 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002140 D3DFORMAT format = mImageArray[0][0].getD3DFormat();
daniel@transgaming.com61208202011-03-21 16:38:50 +00002141 GLint levels = creationLevels(mImageArray[0][0].width, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002142
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00002143 IDirect3DCubeTexture9 *texture = NULL;
daniel@transgaming.com61208202011-03-21 16:38:50 +00002144 HRESULT result = device->CreateCubeTexture(mImageArray[0][0].width, levels, 0, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002145
2146 if (FAILED(result))
2147 {
2148 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002149 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002150 }
2151
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002152 if (mTexture)
2153 {
2154 mTexture->Release();
2155 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002156
2157 mTexture = texture;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00002158 mDirtyImage = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00002159 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002160}
2161
2162void TextureCubeMap::updateTexture()
2163{
2164 IDirect3DDevice9 *device = getDevice();
2165
2166 for (int face = 0; face < 6; face++)
2167 {
2168 int levels = levelCount();
2169 for (int level = 0; level < levels; level++)
2170 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00002171 Image *image = &mImageArray[face][level];
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002172
daniel@transgaming.com61208202011-03-21 16:38:50 +00002173 if (image->surface && image->dirty)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002174 {
2175 IDirect3DSurface9 *levelSurface = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level);
2176 ASSERT(levelSurface != NULL);
2177
2178 if (levelSurface != NULL)
2179 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00002180 HRESULT result = device->UpdateSurface(image->surface, NULL, levelSurface, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002181 ASSERT(SUCCEEDED(result));
2182
2183 levelSurface->Release();
2184
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00002185 image->dirty = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002186 }
2187 }
2188 }
2189 }
2190}
2191
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002192void TextureCubeMap::convertToRenderTarget()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002193{
2194 IDirect3DCubeTexture9 *texture = NULL;
2195
daniel@transgaming.com61208202011-03-21 16:38:50 +00002196 if (mImageArray[0][0].width != 0)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002197 {
2198 egl::Display *display = getDisplay();
2199 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002200 D3DFORMAT format = mImageArray[0][0].getD3DFormat();
daniel@transgaming.com61208202011-03-21 16:38:50 +00002201 GLint levels = creationLevels(mImageArray[0][0].width, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002202
daniel@transgaming.com61208202011-03-21 16:38:50 +00002203 HRESULT result = device->CreateCubeTexture(mImageArray[0][0].width, levels, D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002204
2205 if (FAILED(result))
2206 {
2207 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002208 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002209 }
2210
2211 if (mTexture != NULL)
2212 {
2213 int levels = levelCount();
2214 for (int f = 0; f < 6; f++)
2215 {
2216 for (int i = 0; i < levels; i++)
2217 {
2218 IDirect3DSurface9 *source;
2219 result = mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &source);
2220
2221 if (FAILED(result))
2222 {
2223 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2224
2225 texture->Release();
2226
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002227 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002228 }
2229
2230 IDirect3DSurface9 *dest;
2231 result = texture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &dest);
2232
2233 if (FAILED(result))
2234 {
2235 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2236
2237 texture->Release();
2238 source->Release();
2239
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002240 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002241 }
2242
2243 display->endScene();
2244 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
2245
2246 if (FAILED(result))
2247 {
2248 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2249
2250 texture->Release();
2251 source->Release();
2252 dest->Release();
2253
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002254 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002255 }
2256 }
2257 }
2258 }
2259 }
2260
2261 if (mTexture != NULL)
2262 {
2263 mTexture->Release();
2264 }
2265
2266 mTexture = texture;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00002267 mDirtyImage = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00002268 mIsRenderable = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002269}
2270
daniel@transgaming.com61208202011-03-21 16:38:50 +00002271void 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 +00002272{
daniel@transgaming.com61208202011-03-21 16:38:50 +00002273 redefineTexture(faceIndex, level, format, width, height, type);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002274
daniel@transgaming.com61208202011-03-21 16:38:50 +00002275 Texture::setImage(unpackAlignment, pixels, &mImageArray[faceIndex][level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002276}
2277
2278unsigned int TextureCubeMap::faceIndex(GLenum face)
2279{
2280 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
2281 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
2282 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
2283 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
2284 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
2285
2286 return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
2287}
2288
daniel@transgaming.com61208202011-03-21 16:38:50 +00002289void TextureCubeMap::redefineTexture(int face, GLint level, GLenum format, GLsizei width, GLsizei height, GLenum type)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002290{
daniel@transgaming.com94a4f032011-03-21 16:38:55 +00002291 GLsizei textureWidth = mImageArray[0][0].width;
2292 GLsizei textureHeight = mImageArray[0][0].height;
2293 GLenum textureFormat = mImageArray[0][0].format;
2294 GLenum textureType = mImageArray[0][0].type;
2295
daniel@transgaming.com61208202011-03-21 16:38:50 +00002296 mImageArray[face][level].width = width;
2297 mImageArray[face][level].height = height;
2298 mImageArray[face][level].format = format;
2299 mImageArray[face][level].type = type;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002300
daniel@transgaming.com61208202011-03-21 16:38:50 +00002301 if (!mTexture)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002302 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00002303 return;
2304 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002305
daniel@transgaming.com94a4f032011-03-21 16:38:55 +00002306 bool sizeOkay = (textureWidth >> level == width);
2307 bool textureOkay = (sizeOkay && textureFormat == format && textureType == type);
daniel@transgaming.com61208202011-03-21 16:38:50 +00002308
2309 if (!textureOkay) // Purge all the levels and the texture.
2310 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002311 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
2312 {
2313 for (int f = 0; f < 6; f++)
2314 {
2315 if (mImageArray[f][i].surface != NULL)
2316 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002317 mImageArray[f][i].surface->Release();
2318 mImageArray[f][i].surface = NULL;
daniel@transgaming.com61208202011-03-21 16:38:50 +00002319 mImageArray[f][i].dirty = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002320 }
2321 }
2322 }
2323
2324 if (mTexture != NULL)
2325 {
2326 mTexture->Release();
2327 mTexture = NULL;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00002328 mDirtyImage = true;
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002329 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002330 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002331 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002332}
2333
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002334void 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 +00002335{
2336 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
2337
2338 if (!renderTarget)
2339 {
2340 ERR("Failed to retrieve the render target.");
2341 return error(GL_OUT_OF_MEMORY);
2342 }
2343
2344 unsigned int faceindex = faceIndex(target);
daniel@transgaming.com61208202011-03-21 16:38:50 +00002345 redefineTexture(faceindex, level, format, width, height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002346
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002347 if (!mImageArray[faceindex][level].isRenderable())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002348 {
daniel@transgaming.comb6276992011-03-29 00:58:18 +00002349 copyToImage(&mImageArray[faceindex][level], 0, 0, x, y, width, height, renderTarget);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002350 }
2351 else
2352 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00002353 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002354 {
2355 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002356 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00002357
2358 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002359
2360 ASSERT(width == height);
2361
2362 if (width > 0 && level < levelCount())
2363 {
2364 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
2365 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
2366 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
2367 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
2368 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
2369
daniel@transgaming.comeef864a2011-04-22 11:33:27 +00002370 GLint destYOffset = transformPixelYOffset(0, height, mImageArray[faceindex][level].width);
2371
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002372 IDirect3DSurface9 *dest = getCubeMapSurface(target, level);
2373
daniel@transgaming.comeef864a2011-04-22 11:33:27 +00002374 getBlitter()->copy(source->getRenderTarget(), sourceRect, format, 0, destYOffset, dest);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002375 dest->Release();
2376 }
2377 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002378}
2379
2380IDirect3DSurface9 *TextureCubeMap::getCubeMapSurface(GLenum face, unsigned int level)
2381{
2382 if (mTexture == NULL)
2383 {
2384 UNREACHABLE();
2385 return NULL;
2386 }
2387
2388 IDirect3DSurface9 *surface = NULL;
2389
2390 HRESULT hr = mTexture->GetCubeMapSurface(es2dx::ConvertCubeFace(face), level, &surface);
2391
2392 return (SUCCEEDED(hr)) ? surface : NULL;
2393}
2394
2395void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
2396{
2397 GLsizei size = mImageArray[faceIndex(target)][level].width;
2398
2399 if (xoffset + width > size || yoffset + height > size)
2400 {
2401 return error(GL_INVALID_VALUE);
2402 }
2403
2404 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
2405
2406 if (!renderTarget)
2407 {
2408 ERR("Failed to retrieve the render target.");
2409 return error(GL_OUT_OF_MEMORY);
2410 }
2411
2412 unsigned int faceindex = faceIndex(target);
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002413 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 +00002414
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002415 if (!mImageArray[faceindex][level].isRenderable() || (!mTexture && !isComplete()))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002416 {
daniel@transgaming.comb6276992011-03-29 00:58:18 +00002417 copyToImage(&mImageArray[faceindex][level], 0, 0, x, y, width, height, renderTarget);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002418 }
2419 else
2420 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00002421 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002422 {
2423 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002424 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00002425
2426 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002427
2428 if (level < levelCount())
2429 {
2430 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
2431 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
2432 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
2433 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
2434 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
2435
2436 GLint destYOffset = transformPixelYOffset(yoffset, height, mImageArray[faceindex][level].width);
2437
2438 IDirect3DSurface9 *dest = getCubeMapSurface(target, level);
2439
daniel@transgaming.comeef864a2011-04-22 11:33:27 +00002440 getBlitter()->copy(source->getRenderTarget(), sourceRect, mImageArray[0][0].format, xoffset, destYOffset, dest);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002441 dest->Release();
2442 }
2443 }
2444}
2445
2446bool TextureCubeMap::isCubeComplete() const
2447{
2448 if (mImageArray[0][0].width == 0)
2449 {
2450 return false;
2451 }
2452
2453 for (unsigned int f = 1; f < 6; f++)
2454 {
2455 if (mImageArray[f][0].width != mImageArray[0][0].width
2456 || mImageArray[f][0].format != mImageArray[0][0].format)
2457 {
2458 return false;
2459 }
2460 }
2461
2462 return true;
2463}
2464
2465void TextureCubeMap::generateMipmaps()
2466{
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00002467 if (!isCubeComplete())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002468 {
2469 return error(GL_INVALID_OPERATION);
2470 }
2471
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00002472 if (!getContext()->supportsNonPower2Texture())
2473 {
2474 if (!isPow2(mImageArray[0][0].width))
2475 {
2476 return error(GL_INVALID_OPERATION);
2477 }
2478 }
2479
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002480 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
2481 unsigned int q = log2(mImageArray[0][0].width);
2482 for (unsigned int f = 0; f < 6; f++)
2483 {
2484 for (unsigned int i = 1; i <= q; i++)
2485 {
2486 if (mImageArray[f][i].surface != NULL)
2487 {
2488 mImageArray[f][i].surface->Release();
2489 mImageArray[f][i].surface = NULL;
2490 }
2491
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002492 mImageArray[f][i].width = std::max(mImageArray[f][0].width >> i, 1);
2493 mImageArray[f][i].height = mImageArray[f][i].width;
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00002494 mImageArray[f][i].format = mImageArray[f][0].format;
2495 mImageArray[f][i].type = mImageArray[f][0].type;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002496 }
2497 }
2498
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002499 if (mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002500 {
2501 if (mTexture == NULL)
2502 {
2503 return;
2504 }
2505
2506 for (unsigned int f = 0; f < 6; f++)
2507 {
2508 for (unsigned int i = 1; i <= q; i++)
2509 {
2510 IDirect3DSurface9 *upper = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i-1);
2511 IDirect3DSurface9 *lower = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i);
2512
2513 if (upper != NULL && lower != NULL)
2514 {
2515 getBlitter()->boxFilter(upper, lower);
2516 }
2517
2518 if (upper != NULL) upper->Release();
2519 if (lower != NULL) lower->Release();
daniel@transgaming.com61208202011-03-21 16:38:50 +00002520
2521 mImageArray[f][i].dirty = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002522 }
2523 }
2524 }
2525 else
2526 {
2527 for (unsigned int f = 0; f < 6; f++)
2528 {
2529 for (unsigned int i = 1; i <= q; i++)
2530 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00002531 createSurface(&mImageArray[f][i]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002532 if (mImageArray[f][i].surface == NULL)
2533 {
2534 return error(GL_OUT_OF_MEMORY);
2535 }
2536
2537 if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[f][i].surface, NULL, NULL, mImageArray[f][i - 1].surface, NULL, NULL, D3DX_FILTER_BOX, 0)))
2538 {
2539 ERR(" failed to load filter %d to %d.", i - 1, i);
2540 }
2541
2542 mImageArray[f][i].dirty = true;
2543 }
2544 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002545 }
2546}
2547
2548Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target)
2549{
2550 if (!IsCubemapTextureTarget(target))
2551 {
2552 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
2553 }
2554
2555 unsigned int face = faceIndex(target);
2556
2557 if (mFaceProxies[face].get() == NULL)
2558 {
2559 mFaceProxies[face].set(new Renderbuffer(id(), new Colorbuffer(this, target)));
2560 }
2561
2562 return mFaceProxies[face].get();
2563}
2564
2565IDirect3DSurface9 *TextureCubeMap::getRenderTarget(GLenum target)
2566{
2567 ASSERT(IsCubemapTextureTarget(target));
2568
daniel@transgaming.com61208202011-03-21 16:38:50 +00002569 if (!mIsRenderable)
2570 {
2571 convertToRenderTarget();
2572 }
2573
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002574 if (mTexture == NULL)
2575 {
2576 return NULL;
2577 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00002578
2579 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002580
2581 IDirect3DSurface9 *renderTarget = NULL;
2582 mTexture->GetCubeMapSurface(es2dx::ConvertCubeFace(target), 0, &renderTarget);
2583
2584 return renderTarget;
2585}
2586
2587}