blob: bb4c4b8f5c7399e1ee8a15caf86817df748e355a [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 }
apatrick@chromium.org57a2cd62011-06-08 00:04:07 +00001370
1371 mColorbufferProxy.set(NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001372 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001373}
1374
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001375void 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 +00001376{
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001377 redefineTexture(level, format, width, height, type, false);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001378
daniel@transgaming.com61208202011-03-21 16:38:50 +00001379 Texture::setImage(unpackAlignment, pixels, &mImageArray[level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001380}
1381
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001382void Texture2D::bindTexImage(egl::Surface *surface)
1383{
1384 GLenum format;
1385
1386 switch(surface->getFormat())
1387 {
1388 case D3DFMT_A8R8G8B8:
1389 format = GL_RGBA;
1390 break;
1391 case D3DFMT_X8R8G8B8:
1392 format = GL_RGB;
1393 break;
1394 default:
1395 UNIMPLEMENTED();
1396 return;
1397 }
1398
1399 redefineTexture(0, format, surface->getWidth(), surface->getHeight(), GL_UNSIGNED_BYTE, true);
1400
1401 IDirect3DTexture9 *texture = surface->getOffscreenTexture();
1402
1403 mTexture = texture;
1404 mDirtyImage = true;
1405 mIsRenderable = true;
1406 mSurface = surface;
1407 mSurface->setBoundTexture(this);
1408}
1409
1410void Texture2D::releaseTexImage()
1411{
1412 redefineTexture(0, GL_RGB, 0, 0, GL_UNSIGNED_BYTE, true);
1413}
1414
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001415void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001416{
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001417 redefineTexture(level, format, width, height, GL_UNSIGNED_BYTE, false);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001418
daniel@transgaming.com61208202011-03-21 16:38:50 +00001419 Texture::setCompressedImage(imageSize, pixels, &mImageArray[level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001420}
1421
1422void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1423{
1424 ASSERT(mImageArray[level].surface != NULL);
1425
1426 if (level < levelCount())
1427 {
1428 IDirect3DSurface9 *destLevel = NULL;
1429 HRESULT result = mTexture->GetSurfaceLevel(level, &destLevel);
1430
1431 ASSERT(SUCCEEDED(result));
1432
1433 if (SUCCEEDED(result))
1434 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001435 Image *image = &mImageArray[level];
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001436
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001437 RECT sourceRect = transformPixelRect(xoffset, yoffset, width, height, image->height);;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001438
1439 POINT destPoint;
1440 destPoint.x = sourceRect.left;
1441 destPoint.y = sourceRect.top;
1442
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001443 result = getDevice()->UpdateSurface(image->surface, &sourceRect, destLevel, &destPoint);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001444 ASSERT(SUCCEEDED(result));
1445
1446 destLevel->Release();
1447
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001448 image->dirty = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001449 }
1450 }
1451}
1452
1453void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1454{
1455 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[level]))
1456 {
1457 commitRect(level, xoffset, yoffset, width, height);
1458 }
1459}
1460
1461void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1462{
1463 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[level]))
1464 {
1465 commitRect(level, xoffset, yoffset, width, height);
1466 }
1467}
1468
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001469void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001470{
1471 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
1472
1473 if (!renderTarget)
1474 {
1475 ERR("Failed to retrieve the render target.");
1476 return error(GL_OUT_OF_MEMORY);
1477 }
1478
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001479 redefineTexture(level, format, width, height, GL_UNSIGNED_BYTE, false);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001480
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001481 if (!mImageArray[level].isRenderable())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001482 {
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001483 copyToImage(&mImageArray[level], 0, 0, x, y, width, height, renderTarget);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001484 }
1485 else
1486 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001487 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001488 {
1489 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001490 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00001491
1492 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001493
1494 if (width != 0 && height != 0 && level < levelCount())
1495 {
1496 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
1497 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
1498 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
1499 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
1500 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
daniel@transgaming.comeef864a2011-04-22 11:33:27 +00001501
1502 GLint destYOffset = transformPixelYOffset(0, height, mImageArray[level].height);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001503
1504 IDirect3DSurface9 *dest;
1505 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
1506
daniel@transgaming.comeef864a2011-04-22 11:33:27 +00001507 getBlitter()->copy(source->getRenderTarget(), sourceRect, format, 0, destYOffset, dest);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001508 dest->Release();
1509 }
1510 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001511}
1512
1513void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1514{
1515 if (xoffset + width > mImageArray[level].width || yoffset + height > mImageArray[level].height)
1516 {
1517 return error(GL_INVALID_VALUE);
1518 }
1519
1520 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
1521
1522 if (!renderTarget)
1523 {
1524 ERR("Failed to retrieve the render target.");
1525 return error(GL_OUT_OF_MEMORY);
1526 }
1527
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001528 redefineTexture(level, mImageArray[level].format, mImageArray[level].width, mImageArray[level].height, GL_UNSIGNED_BYTE, false);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001529
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001530 if (!mImageArray[level].isRenderable() || (!mTexture && !isComplete()))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001531 {
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001532 copyToImage(&mImageArray[level], xoffset, yoffset, x, y, width, height, renderTarget);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001533 }
1534 else
1535 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001536 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001537 {
1538 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001539 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00001540
1541 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001542
1543 if (level < levelCount())
1544 {
1545 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
1546 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
1547 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
1548 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
1549 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
1550
1551 GLint destYOffset = transformPixelYOffset(yoffset, height, mImageArray[level].height);
1552
1553 IDirect3DSurface9 *dest;
1554 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
1555
daniel@transgaming.comeef864a2011-04-22 11:33:27 +00001556 getBlitter()->copy(source->getRenderTarget(), sourceRect, mImageArray[0].format, xoffset, destYOffset, dest);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001557 dest->Release();
1558 }
1559 }
1560}
1561
1562// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1563bool Texture2D::isComplete() const
1564{
1565 GLsizei width = mImageArray[0].width;
1566 GLsizei height = mImageArray[0].height;
1567
1568 if (width <= 0 || height <= 0)
1569 {
1570 return false;
1571 }
1572
1573 bool mipmapping = false;
1574
1575 switch (mMinFilter)
1576 {
1577 case GL_NEAREST:
1578 case GL_LINEAR:
1579 mipmapping = false;
1580 break;
1581 case GL_NEAREST_MIPMAP_NEAREST:
1582 case GL_LINEAR_MIPMAP_NEAREST:
1583 case GL_NEAREST_MIPMAP_LINEAR:
1584 case GL_LINEAR_MIPMAP_LINEAR:
1585 mipmapping = true;
1586 break;
1587 default: UNREACHABLE();
1588 }
1589
1590 if ((getInternalFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) ||
1591 (getInternalFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter()))
1592 {
1593 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
1594 {
1595 return false;
1596 }
1597 }
1598
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00001599 bool npot = getContext()->supportsNonPower2Texture();
1600
1601 if (!npot)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001602 {
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00001603 if ((getWrapS() != GL_CLAMP_TO_EDGE && !isPow2(width)) ||
1604 (getWrapT() != GL_CLAMP_TO_EDGE && !isPow2(height)))
1605 {
1606 return false;
1607 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001608 }
1609
1610 if (mipmapping)
1611 {
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00001612 if (!npot)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001613 {
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00001614 if (!isPow2(width) || !isPow2(height))
1615 {
1616 return false;
1617 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001618 }
1619
1620 int q = log2(std::max(width, height));
1621
1622 for (int level = 1; level <= q; level++)
1623 {
1624 if (mImageArray[level].format != mImageArray[0].format)
1625 {
1626 return false;
1627 }
1628
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00001629 if (mImageArray[level].type != mImageArray[0].type)
1630 {
1631 return false;
1632 }
1633
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001634 if (mImageArray[level].width != std::max(1, width >> level))
1635 {
1636 return false;
1637 }
1638
1639 if (mImageArray[level].height != std::max(1, height >> level))
1640 {
1641 return false;
1642 }
1643 }
1644 }
1645
1646 return true;
1647}
1648
1649bool Texture2D::isCompressed() const
1650{
1651 return IsCompressed(getInternalFormat());
1652}
1653
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001654IDirect3DBaseTexture9 *Texture2D::getBaseTexture() const
1655{
1656 return mTexture;
1657}
1658
1659// Constructs a Direct3D 9 texture resource from the texture images
1660void Texture2D::createTexture()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001661{
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001662 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001663 D3DFORMAT format = mImageArray[0].getD3DFormat();
daniel@transgaming.com61208202011-03-21 16:38:50 +00001664 GLint levels = creationLevels(mImageArray[0].width, mImageArray[0].height, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001665
daniel@transgaming.com61208202011-03-21 16:38:50 +00001666 IDirect3DTexture9 *texture = NULL;
1667 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 +00001668
1669 if (FAILED(result))
1670 {
1671 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001672 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001673 }
1674
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001675 if (mTexture)
1676 {
1677 mTexture->Release();
1678 }
1679
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001680 mTexture = texture;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00001681 mDirtyImage = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00001682 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001683}
1684
1685void Texture2D::updateTexture()
1686{
1687 IDirect3DDevice9 *device = getDevice();
1688
1689 int levels = levelCount();
1690
1691 for (int level = 0; level < levels; level++)
1692 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001693 if (mImageArray[level].surface && mImageArray[level].dirty)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001694 {
1695 IDirect3DSurface9 *levelSurface = NULL;
1696 HRESULT result = mTexture->GetSurfaceLevel(level, &levelSurface);
1697
1698 ASSERT(SUCCEEDED(result));
1699
1700 if (SUCCEEDED(result))
1701 {
1702 result = device->UpdateSurface(mImageArray[level].surface, NULL, levelSurface, NULL);
1703 ASSERT(SUCCEEDED(result));
1704
1705 levelSurface->Release();
1706
1707 mImageArray[level].dirty = false;
1708 }
1709 }
1710 }
1711}
1712
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001713void Texture2D::convertToRenderTarget()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001714{
1715 IDirect3DTexture9 *texture = NULL;
1716
daniel@transgaming.com61208202011-03-21 16:38:50 +00001717 if (mImageArray[0].width != 0 && mImageArray[0].height != 0)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001718 {
1719 egl::Display *display = getDisplay();
1720 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001721 D3DFORMAT format = mImageArray[0].getD3DFormat();
daniel@transgaming.com61208202011-03-21 16:38:50 +00001722 GLint levels = creationLevels(mImageArray[0].width, mImageArray[0].height, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001723
daniel@transgaming.com61208202011-03-21 16:38:50 +00001724 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 +00001725
1726 if (FAILED(result))
1727 {
1728 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001729 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001730 }
1731
1732 if (mTexture != NULL)
1733 {
1734 int levels = levelCount();
1735 for (int i = 0; i < levels; i++)
1736 {
1737 IDirect3DSurface9 *source;
1738 result = mTexture->GetSurfaceLevel(i, &source);
1739
1740 if (FAILED(result))
1741 {
1742 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1743
1744 texture->Release();
1745
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001746 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001747 }
1748
1749 IDirect3DSurface9 *dest;
1750 result = texture->GetSurfaceLevel(i, &dest);
1751
1752 if (FAILED(result))
1753 {
1754 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1755
1756 texture->Release();
1757 source->Release();
1758
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001759 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001760 }
1761
1762 display->endScene();
1763 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
1764
1765 if (FAILED(result))
1766 {
1767 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1768
1769 texture->Release();
1770 source->Release();
1771 dest->Release();
1772
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001773 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001774 }
1775
1776 source->Release();
1777 dest->Release();
1778 }
1779 }
1780 }
1781
1782 if (mTexture != NULL)
1783 {
1784 mTexture->Release();
1785 }
1786
1787 mTexture = texture;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00001788 mDirtyImage = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00001789 mIsRenderable = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001790}
1791
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001792void Texture2D::generateMipmaps()
1793{
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00001794 if (!getContext()->supportsNonPower2Texture())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001795 {
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00001796 if (!isPow2(mImageArray[0].width) || !isPow2(mImageArray[0].height))
1797 {
1798 return error(GL_INVALID_OPERATION);
1799 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001800 }
1801
1802 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
daniel@transgaming.com61208202011-03-21 16:38:50 +00001803 unsigned int q = log2(std::max(mImageArray[0].width, mImageArray[0].height));
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001804 for (unsigned int i = 1; i <= q; i++)
1805 {
1806 if (mImageArray[i].surface != NULL)
1807 {
1808 mImageArray[i].surface->Release();
1809 mImageArray[i].surface = NULL;
1810 }
1811
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001812 mImageArray[i].width = std::max(mImageArray[0].width >> i, 1);
1813 mImageArray[i].height = std::max(mImageArray[0].height >> i, 1);
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00001814 mImageArray[i].format = mImageArray[0].format;
1815 mImageArray[i].type = mImageArray[0].type;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001816 }
1817
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001818 if (mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001819 {
1820 if (mTexture == NULL)
1821 {
1822 ERR(" failed because mTexture was null.");
1823 return;
1824 }
1825
1826 for (unsigned int i = 1; i <= q; i++)
1827 {
1828 IDirect3DSurface9 *upper = NULL;
1829 IDirect3DSurface9 *lower = NULL;
1830
1831 mTexture->GetSurfaceLevel(i-1, &upper);
1832 mTexture->GetSurfaceLevel(i, &lower);
1833
1834 if (upper != NULL && lower != NULL)
1835 {
1836 getBlitter()->boxFilter(upper, lower);
1837 }
1838
1839 if (upper != NULL) upper->Release();
1840 if (lower != NULL) lower->Release();
daniel@transgaming.com61208202011-03-21 16:38:50 +00001841
1842 mImageArray[i].dirty = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001843 }
1844 }
1845 else
1846 {
1847 for (unsigned int i = 1; i <= q; i++)
1848 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001849 createSurface(&mImageArray[i]);
1850
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001851 if (mImageArray[i].surface == NULL)
1852 {
1853 return error(GL_OUT_OF_MEMORY);
1854 }
1855
1856 if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[i].surface, NULL, NULL, mImageArray[i - 1].surface, NULL, NULL, D3DX_FILTER_BOX, 0)))
1857 {
1858 ERR(" failed to load filter %d to %d.", i - 1, i);
1859 }
1860
1861 mImageArray[i].dirty = true;
1862 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001863 }
1864}
1865
1866Renderbuffer *Texture2D::getRenderbuffer(GLenum target)
1867{
1868 if (target != GL_TEXTURE_2D)
1869 {
1870 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
1871 }
1872
1873 if (mColorbufferProxy.get() == NULL)
1874 {
1875 mColorbufferProxy.set(new Renderbuffer(id(), new Colorbuffer(this, target)));
1876 }
1877
1878 return mColorbufferProxy.get();
1879}
1880
1881IDirect3DSurface9 *Texture2D::getRenderTarget(GLenum target)
1882{
1883 ASSERT(target == GL_TEXTURE_2D);
1884
daniel@transgaming.com61208202011-03-21 16:38:50 +00001885 if (!mIsRenderable)
1886 {
1887 convertToRenderTarget();
1888 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001889
1890 if (mTexture == NULL)
1891 {
1892 return NULL;
1893 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00001894
1895 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001896
1897 IDirect3DSurface9 *renderTarget = NULL;
1898 mTexture->GetSurfaceLevel(0, &renderTarget);
1899
1900 return renderTarget;
1901}
1902
1903TextureCubeMap::TextureCubeMap(GLuint id) : Texture(id)
1904{
1905 mTexture = NULL;
1906}
1907
1908TextureCubeMap::~TextureCubeMap()
1909{
1910 for (int i = 0; i < 6; i++)
1911 {
1912 mFaceProxies[i].set(NULL);
1913 }
1914
1915 if (mTexture)
1916 {
1917 mTexture->Release();
1918 mTexture = NULL;
1919 }
1920}
1921
1922GLenum TextureCubeMap::getTarget() const
1923{
1924 return GL_TEXTURE_CUBE_MAP;
1925}
1926
daniel@transgaming.com61208202011-03-21 16:38:50 +00001927GLsizei TextureCubeMap::getWidth() const
1928{
1929 return mImageArray[0][0].width;
1930}
1931
1932GLsizei TextureCubeMap::getHeight() const
1933{
1934 return mImageArray[0][0].height;
1935}
1936
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001937GLenum TextureCubeMap::getInternalFormat() const
1938{
1939 return mImageArray[0][0].format;
1940}
1941
daniel@transgaming.com61208202011-03-21 16:38:50 +00001942GLenum TextureCubeMap::getType() const
1943{
1944 return mImageArray[0][0].type;
1945}
1946
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001947D3DFORMAT TextureCubeMap::getD3DFormat() const
1948{
1949 return mImageArray[0][0].getD3DFormat();
1950}
1951
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001952void 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 +00001953{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001954 setImage(0, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001955}
1956
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001957void 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 +00001958{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001959 setImage(1, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001960}
1961
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001962void 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 +00001963{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001964 setImage(2, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001965}
1966
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001967void 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 +00001968{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001969 setImage(3, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001970}
1971
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001972void 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 +00001973{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001974 setImage(4, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001975}
1976
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001977void 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 +00001978{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001979 setImage(5, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001980}
1981
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001982void 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 +00001983{
daniel@transgaming.com61208202011-03-21 16:38:50 +00001984 redefineTexture(faceIndex(face), level, format, width, height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001985
daniel@transgaming.com61208202011-03-21 16:38:50 +00001986 Texture::setCompressedImage(imageSize, pixels, &mImageArray[faceIndex(face)][level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001987}
1988
1989void TextureCubeMap::commitRect(GLenum faceTarget, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1990{
1991 int face = faceIndex(faceTarget);
1992 ASSERT(mImageArray[face][level].surface != NULL);
1993
1994 if (level < levelCount())
1995 {
1996 IDirect3DSurface9 *destLevel = getCubeMapSurface(faceTarget, level);
1997 ASSERT(destLevel != NULL);
1998
1999 if (destLevel != NULL)
2000 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00002001 Image *image = &mImageArray[face][level];
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002002
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00002003 RECT sourceRect = transformPixelRect(xoffset, yoffset, width, height, image->height);;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002004
2005 POINT destPoint;
2006 destPoint.x = sourceRect.left;
2007 destPoint.y = sourceRect.top;
2008
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00002009 HRESULT result = getDevice()->UpdateSurface(image->surface, &sourceRect, destLevel, &destPoint);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002010 ASSERT(SUCCEEDED(result));
2011
2012 destLevel->Release();
2013
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00002014 image->dirty = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002015 }
2016 }
2017}
2018
2019void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
2020{
2021 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[faceIndex(target)][level]))
2022 {
2023 commitRect(target, level, xoffset, yoffset, width, height);
2024 }
2025}
2026
2027void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
2028{
2029 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[faceIndex(target)][level]))
2030 {
2031 commitRect(target, level, xoffset, yoffset, width, height);
2032 }
2033}
2034
2035// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
2036bool TextureCubeMap::isComplete() const
2037{
2038 int size = mImageArray[0][0].width;
2039
2040 if (size <= 0)
2041 {
2042 return false;
2043 }
2044
2045 bool mipmapping;
2046
2047 switch (mMinFilter)
2048 {
2049 case GL_NEAREST:
2050 case GL_LINEAR:
2051 mipmapping = false;
2052 break;
2053 case GL_NEAREST_MIPMAP_NEAREST:
2054 case GL_LINEAR_MIPMAP_NEAREST:
2055 case GL_NEAREST_MIPMAP_LINEAR:
2056 case GL_LINEAR_MIPMAP_LINEAR:
2057 mipmapping = true;
2058 break;
2059 default: UNREACHABLE();
2060 }
2061
2062 for (int face = 0; face < 6; face++)
2063 {
2064 if (mImageArray[face][0].width != size || mImageArray[face][0].height != size)
2065 {
2066 return false;
2067 }
2068 }
2069
2070 if ((getInternalFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) ||
2071 (getInternalFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter()))
2072 {
2073 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
2074 {
2075 return false;
2076 }
2077 }
2078
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00002079 bool npot = getContext()->supportsNonPower2Texture();
2080
2081 if (!npot)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002082 {
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00002083 if ((getWrapS() != GL_CLAMP_TO_EDGE || getWrapT() != GL_CLAMP_TO_EDGE) && !isPow2(size))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002084 {
2085 return false;
2086 }
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00002087 }
2088
2089 if (mipmapping)
2090 {
2091 if (!npot)
2092 {
2093 if (!isPow2(size))
2094 {
2095 return false;
2096 }
2097 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002098
2099 int q = log2(size);
2100
2101 for (int face = 0; face < 6; face++)
2102 {
2103 for (int level = 1; level <= q; level++)
2104 {
2105 if (mImageArray[face][level].format != mImageArray[0][0].format)
2106 {
2107 return false;
2108 }
2109
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00002110 if (mImageArray[face][level].type != mImageArray[0][0].type)
2111 {
2112 return false;
2113 }
2114
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002115 if (mImageArray[face][level].width != std::max(1, size >> level))
2116 {
2117 return false;
2118 }
2119
2120 ASSERT(mImageArray[face][level].height == mImageArray[face][level].width);
2121 }
2122 }
2123 }
2124
2125 return true;
2126}
2127
2128bool TextureCubeMap::isCompressed() const
2129{
2130 return IsCompressed(getInternalFormat());
2131}
2132
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002133IDirect3DBaseTexture9 *TextureCubeMap::getBaseTexture() const
2134{
2135 return mTexture;
2136}
2137
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002138// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002139void TextureCubeMap::createTexture()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002140{
2141 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002142 D3DFORMAT format = mImageArray[0][0].getD3DFormat();
daniel@transgaming.com61208202011-03-21 16:38:50 +00002143 GLint levels = creationLevels(mImageArray[0][0].width, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002144
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00002145 IDirect3DCubeTexture9 *texture = NULL;
daniel@transgaming.com61208202011-03-21 16:38:50 +00002146 HRESULT result = device->CreateCubeTexture(mImageArray[0][0].width, levels, 0, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002147
2148 if (FAILED(result))
2149 {
2150 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002151 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002152 }
2153
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002154 if (mTexture)
2155 {
2156 mTexture->Release();
2157 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002158
2159 mTexture = texture;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00002160 mDirtyImage = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00002161 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002162}
2163
2164void TextureCubeMap::updateTexture()
2165{
2166 IDirect3DDevice9 *device = getDevice();
2167
2168 for (int face = 0; face < 6; face++)
2169 {
2170 int levels = levelCount();
2171 for (int level = 0; level < levels; level++)
2172 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00002173 Image *image = &mImageArray[face][level];
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002174
daniel@transgaming.com61208202011-03-21 16:38:50 +00002175 if (image->surface && image->dirty)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002176 {
2177 IDirect3DSurface9 *levelSurface = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level);
2178 ASSERT(levelSurface != NULL);
2179
2180 if (levelSurface != NULL)
2181 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00002182 HRESULT result = device->UpdateSurface(image->surface, NULL, levelSurface, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002183 ASSERT(SUCCEEDED(result));
2184
2185 levelSurface->Release();
2186
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00002187 image->dirty = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002188 }
2189 }
2190 }
2191 }
2192}
2193
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002194void TextureCubeMap::convertToRenderTarget()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002195{
2196 IDirect3DCubeTexture9 *texture = NULL;
2197
daniel@transgaming.com61208202011-03-21 16:38:50 +00002198 if (mImageArray[0][0].width != 0)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002199 {
2200 egl::Display *display = getDisplay();
2201 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002202 D3DFORMAT format = mImageArray[0][0].getD3DFormat();
daniel@transgaming.com61208202011-03-21 16:38:50 +00002203 GLint levels = creationLevels(mImageArray[0][0].width, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002204
daniel@transgaming.com61208202011-03-21 16:38:50 +00002205 HRESULT result = device->CreateCubeTexture(mImageArray[0][0].width, levels, D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002206
2207 if (FAILED(result))
2208 {
2209 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002210 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002211 }
2212
2213 if (mTexture != NULL)
2214 {
2215 int levels = levelCount();
2216 for (int f = 0; f < 6; f++)
2217 {
2218 for (int i = 0; i < levels; i++)
2219 {
2220 IDirect3DSurface9 *source;
2221 result = mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &source);
2222
2223 if (FAILED(result))
2224 {
2225 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2226
2227 texture->Release();
2228
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002229 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002230 }
2231
2232 IDirect3DSurface9 *dest;
2233 result = texture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &dest);
2234
2235 if (FAILED(result))
2236 {
2237 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2238
2239 texture->Release();
2240 source->Release();
2241
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002242 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002243 }
2244
2245 display->endScene();
2246 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
2247
2248 if (FAILED(result))
2249 {
2250 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2251
2252 texture->Release();
2253 source->Release();
2254 dest->Release();
2255
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002256 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002257 }
2258 }
2259 }
2260 }
2261 }
2262
2263 if (mTexture != NULL)
2264 {
2265 mTexture->Release();
2266 }
2267
2268 mTexture = texture;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00002269 mDirtyImage = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00002270 mIsRenderable = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002271}
2272
daniel@transgaming.com61208202011-03-21 16:38:50 +00002273void 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 +00002274{
daniel@transgaming.com61208202011-03-21 16:38:50 +00002275 redefineTexture(faceIndex, level, format, width, height, type);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002276
daniel@transgaming.com61208202011-03-21 16:38:50 +00002277 Texture::setImage(unpackAlignment, pixels, &mImageArray[faceIndex][level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002278}
2279
2280unsigned int TextureCubeMap::faceIndex(GLenum face)
2281{
2282 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
2283 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
2284 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
2285 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
2286 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
2287
2288 return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
2289}
2290
daniel@transgaming.com61208202011-03-21 16:38:50 +00002291void TextureCubeMap::redefineTexture(int face, GLint level, GLenum format, GLsizei width, GLsizei height, GLenum type)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002292{
daniel@transgaming.com94a4f032011-03-21 16:38:55 +00002293 GLsizei textureWidth = mImageArray[0][0].width;
2294 GLsizei textureHeight = mImageArray[0][0].height;
2295 GLenum textureFormat = mImageArray[0][0].format;
2296 GLenum textureType = mImageArray[0][0].type;
2297
daniel@transgaming.com61208202011-03-21 16:38:50 +00002298 mImageArray[face][level].width = width;
2299 mImageArray[face][level].height = height;
2300 mImageArray[face][level].format = format;
2301 mImageArray[face][level].type = type;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002302
daniel@transgaming.com61208202011-03-21 16:38:50 +00002303 if (!mTexture)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002304 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00002305 return;
2306 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002307
daniel@transgaming.com94a4f032011-03-21 16:38:55 +00002308 bool sizeOkay = (textureWidth >> level == width);
2309 bool textureOkay = (sizeOkay && textureFormat == format && textureType == type);
daniel@transgaming.com61208202011-03-21 16:38:50 +00002310
2311 if (!textureOkay) // Purge all the levels and the texture.
2312 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002313 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
2314 {
2315 for (int f = 0; f < 6; f++)
2316 {
2317 if (mImageArray[f][i].surface != NULL)
2318 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002319 mImageArray[f][i].surface->Release();
2320 mImageArray[f][i].surface = NULL;
daniel@transgaming.com61208202011-03-21 16:38:50 +00002321 mImageArray[f][i].dirty = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002322 }
2323 }
2324 }
2325
2326 if (mTexture != NULL)
2327 {
2328 mTexture->Release();
2329 mTexture = NULL;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00002330 mDirtyImage = true;
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002331 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002332 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002333 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002334}
2335
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002336void 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 +00002337{
2338 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
2339
2340 if (!renderTarget)
2341 {
2342 ERR("Failed to retrieve the render target.");
2343 return error(GL_OUT_OF_MEMORY);
2344 }
2345
2346 unsigned int faceindex = faceIndex(target);
daniel@transgaming.com61208202011-03-21 16:38:50 +00002347 redefineTexture(faceindex, level, format, width, height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002348
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002349 if (!mImageArray[faceindex][level].isRenderable())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002350 {
daniel@transgaming.comb6276992011-03-29 00:58:18 +00002351 copyToImage(&mImageArray[faceindex][level], 0, 0, x, y, width, height, renderTarget);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002352 }
2353 else
2354 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00002355 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002356 {
2357 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002358 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00002359
2360 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002361
2362 ASSERT(width == height);
2363
2364 if (width > 0 && level < levelCount())
2365 {
2366 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
2367 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
2368 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
2369 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
2370 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
2371
daniel@transgaming.comeef864a2011-04-22 11:33:27 +00002372 GLint destYOffset = transformPixelYOffset(0, height, mImageArray[faceindex][level].width);
2373
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002374 IDirect3DSurface9 *dest = getCubeMapSurface(target, level);
2375
daniel@transgaming.comeef864a2011-04-22 11:33:27 +00002376 getBlitter()->copy(source->getRenderTarget(), sourceRect, format, 0, destYOffset, dest);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002377 dest->Release();
2378 }
2379 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002380}
2381
2382IDirect3DSurface9 *TextureCubeMap::getCubeMapSurface(GLenum face, unsigned int level)
2383{
2384 if (mTexture == NULL)
2385 {
2386 UNREACHABLE();
2387 return NULL;
2388 }
2389
2390 IDirect3DSurface9 *surface = NULL;
2391
2392 HRESULT hr = mTexture->GetCubeMapSurface(es2dx::ConvertCubeFace(face), level, &surface);
2393
2394 return (SUCCEEDED(hr)) ? surface : NULL;
2395}
2396
2397void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
2398{
2399 GLsizei size = mImageArray[faceIndex(target)][level].width;
2400
2401 if (xoffset + width > size || yoffset + height > size)
2402 {
2403 return error(GL_INVALID_VALUE);
2404 }
2405
2406 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
2407
2408 if (!renderTarget)
2409 {
2410 ERR("Failed to retrieve the render target.");
2411 return error(GL_OUT_OF_MEMORY);
2412 }
2413
2414 unsigned int faceindex = faceIndex(target);
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002415 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 +00002416
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002417 if (!mImageArray[faceindex][level].isRenderable() || (!mTexture && !isComplete()))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002418 {
daniel@transgaming.comb6276992011-03-29 00:58:18 +00002419 copyToImage(&mImageArray[faceindex][level], 0, 0, x, y, width, height, renderTarget);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002420 }
2421 else
2422 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00002423 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002424 {
2425 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002426 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00002427
2428 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002429
2430 if (level < levelCount())
2431 {
2432 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
2433 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
2434 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
2435 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
2436 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
2437
2438 GLint destYOffset = transformPixelYOffset(yoffset, height, mImageArray[faceindex][level].width);
2439
2440 IDirect3DSurface9 *dest = getCubeMapSurface(target, level);
2441
daniel@transgaming.comeef864a2011-04-22 11:33:27 +00002442 getBlitter()->copy(source->getRenderTarget(), sourceRect, mImageArray[0][0].format, xoffset, destYOffset, dest);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002443 dest->Release();
2444 }
2445 }
2446}
2447
2448bool TextureCubeMap::isCubeComplete() const
2449{
2450 if (mImageArray[0][0].width == 0)
2451 {
2452 return false;
2453 }
2454
2455 for (unsigned int f = 1; f < 6; f++)
2456 {
2457 if (mImageArray[f][0].width != mImageArray[0][0].width
2458 || mImageArray[f][0].format != mImageArray[0][0].format)
2459 {
2460 return false;
2461 }
2462 }
2463
2464 return true;
2465}
2466
2467void TextureCubeMap::generateMipmaps()
2468{
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00002469 if (!isCubeComplete())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002470 {
2471 return error(GL_INVALID_OPERATION);
2472 }
2473
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00002474 if (!getContext()->supportsNonPower2Texture())
2475 {
2476 if (!isPow2(mImageArray[0][0].width))
2477 {
2478 return error(GL_INVALID_OPERATION);
2479 }
2480 }
2481
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002482 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
2483 unsigned int q = log2(mImageArray[0][0].width);
2484 for (unsigned int f = 0; f < 6; f++)
2485 {
2486 for (unsigned int i = 1; i <= q; i++)
2487 {
2488 if (mImageArray[f][i].surface != NULL)
2489 {
2490 mImageArray[f][i].surface->Release();
2491 mImageArray[f][i].surface = NULL;
2492 }
2493
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002494 mImageArray[f][i].width = std::max(mImageArray[f][0].width >> i, 1);
2495 mImageArray[f][i].height = mImageArray[f][i].width;
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00002496 mImageArray[f][i].format = mImageArray[f][0].format;
2497 mImageArray[f][i].type = mImageArray[f][0].type;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002498 }
2499 }
2500
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002501 if (mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002502 {
2503 if (mTexture == NULL)
2504 {
2505 return;
2506 }
2507
2508 for (unsigned int f = 0; f < 6; f++)
2509 {
2510 for (unsigned int i = 1; i <= q; i++)
2511 {
2512 IDirect3DSurface9 *upper = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i-1);
2513 IDirect3DSurface9 *lower = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i);
2514
2515 if (upper != NULL && lower != NULL)
2516 {
2517 getBlitter()->boxFilter(upper, lower);
2518 }
2519
2520 if (upper != NULL) upper->Release();
2521 if (lower != NULL) lower->Release();
daniel@transgaming.com61208202011-03-21 16:38:50 +00002522
2523 mImageArray[f][i].dirty = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002524 }
2525 }
2526 }
2527 else
2528 {
2529 for (unsigned int f = 0; f < 6; f++)
2530 {
2531 for (unsigned int i = 1; i <= q; i++)
2532 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00002533 createSurface(&mImageArray[f][i]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002534 if (mImageArray[f][i].surface == NULL)
2535 {
2536 return error(GL_OUT_OF_MEMORY);
2537 }
2538
2539 if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[f][i].surface, NULL, NULL, mImageArray[f][i - 1].surface, NULL, NULL, D3DX_FILTER_BOX, 0)))
2540 {
2541 ERR(" failed to load filter %d to %d.", i - 1, i);
2542 }
2543
2544 mImageArray[f][i].dirty = true;
2545 }
2546 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002547 }
2548}
2549
2550Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target)
2551{
2552 if (!IsCubemapTextureTarget(target))
2553 {
2554 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
2555 }
2556
2557 unsigned int face = faceIndex(target);
2558
2559 if (mFaceProxies[face].get() == NULL)
2560 {
2561 mFaceProxies[face].set(new Renderbuffer(id(), new Colorbuffer(this, target)));
2562 }
2563
2564 return mFaceProxies[face].get();
2565}
2566
2567IDirect3DSurface9 *TextureCubeMap::getRenderTarget(GLenum target)
2568{
2569 ASSERT(IsCubemapTextureTarget(target));
2570
daniel@transgaming.com61208202011-03-21 16:38:50 +00002571 if (!mIsRenderable)
2572 {
2573 convertToRenderTarget();
2574 }
2575
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002576 if (mTexture == NULL)
2577 {
2578 return NULL;
2579 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00002580
2581 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002582
2583 IDirect3DSurface9 *renderTarget = NULL;
2584 mTexture->GetCubeMapSurface(es2dx::ConvertCubeFace(target), 0, &renderTarget);
2585
2586 return renderTarget;
2587}
2588
2589}