blob: 2261fdd8fcfffa768f5629b67437bcaea47911f8 [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{
1245 if (isPow2(width) && isPow2(height))
1246 {
1247 return maxlevel;
1248 }
1249 else
1250 {
1251 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
1252 return 1;
1253 }
1254}
1255
1256GLint Texture::creationLevels(GLsizei size, GLint maxlevel) const
1257{
1258 return creationLevels(size, size, maxlevel);
1259}
1260
1261int Texture::levelCount() const
1262{
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001263 return getBaseTexture() ? getBaseTexture()->GetLevelCount() : 0;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001264}
1265
daniel@transgaming.coma9eb5da2011-03-21 16:39:16 +00001266unsigned int Texture::issueSerial()
1267{
1268 return mCurrentSerial++;
1269}
1270
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001271Texture2D::Texture2D(GLuint id) : Texture(id)
1272{
1273 mTexture = NULL;
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001274 mSurface = NULL;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001275}
1276
1277Texture2D::~Texture2D()
1278{
1279 mColorbufferProxy.set(NULL);
1280
1281 if (mTexture)
1282 {
1283 mTexture->Release();
1284 mTexture = NULL;
1285 }
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001286
1287 if (mSurface)
1288 {
1289 mSurface->setBoundTexture(NULL);
1290 mSurface = NULL;
1291 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001292}
1293
1294GLenum Texture2D::getTarget() const
1295{
1296 return GL_TEXTURE_2D;
1297}
1298
daniel@transgaming.com61208202011-03-21 16:38:50 +00001299GLsizei Texture2D::getWidth() const
1300{
1301 return mImageArray[0].width;
1302}
1303
1304GLsizei Texture2D::getHeight() const
1305{
1306 return mImageArray[0].height;
1307}
1308
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001309GLenum Texture2D::getInternalFormat() const
1310{
1311 return mImageArray[0].format;
1312}
1313
daniel@transgaming.com61208202011-03-21 16:38:50 +00001314GLenum Texture2D::getType() const
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001315{
daniel@transgaming.com61208202011-03-21 16:38:50 +00001316 return mImageArray[0].type;
1317}
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001318
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001319D3DFORMAT Texture2D::getD3DFormat() const
1320{
1321 return mImageArray[0].getD3DFormat();
1322}
1323
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001324void Texture2D::redefineTexture(GLint level, GLenum format, GLsizei width, GLsizei height, GLenum type, bool forceRedefine)
daniel@transgaming.com61208202011-03-21 16:38:50 +00001325{
daniel@transgaming.com94a4f032011-03-21 16:38:55 +00001326 GLsizei textureWidth = mImageArray[0].width;
1327 GLsizei textureHeight = mImageArray[0].height;
1328 GLenum textureFormat = mImageArray[0].format;
1329 GLenum textureType = mImageArray[0].type;
1330
daniel@transgaming.com61208202011-03-21 16:38:50 +00001331 mImageArray[level].width = width;
1332 mImageArray[level].height = height;
1333 mImageArray[level].format = format;
1334 mImageArray[level].type = type;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001335
daniel@transgaming.com61208202011-03-21 16:38:50 +00001336 if (!mTexture)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001337 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001338 return;
1339 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001340
daniel@transgaming.com94a4f032011-03-21 16:38:55 +00001341 bool widthOkay = (textureWidth >> level == width) || (textureWidth >> level == 0 && width == 1);
1342 bool heightOkay = (textureHeight >> level == height) || (textureHeight >> level == 0 && height == 1);
1343 bool textureOkay = (widthOkay && heightOkay && textureFormat == format && textureType == type);
daniel@transgaming.com61208202011-03-21 16:38:50 +00001344
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001345 if (!textureOkay || forceRedefine || mSurface) // Purge all the levels and the texture.
daniel@transgaming.com61208202011-03-21 16:38:50 +00001346 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001347 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1348 {
1349 if (mImageArray[i].surface != NULL)
1350 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001351 mImageArray[i].surface->Release();
1352 mImageArray[i].surface = NULL;
daniel@transgaming.com61208202011-03-21 16:38:50 +00001353 mImageArray[i].dirty = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001354 }
1355 }
1356
1357 if (mTexture != NULL)
1358 {
1359 mTexture->Release();
1360 mTexture = NULL;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00001361 mDirtyImage = true;
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001362 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001363 }
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001364
1365 if (mSurface)
1366 {
1367 mSurface->setBoundTexture(NULL);
1368 mSurface = NULL;
1369 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001370 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001371}
1372
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001373void Texture2D::setImage(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001374{
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001375 redefineTexture(level, format, width, height, type, false);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001376
daniel@transgaming.com61208202011-03-21 16:38:50 +00001377 Texture::setImage(unpackAlignment, pixels, &mImageArray[level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001378}
1379
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001380void Texture2D::bindTexImage(egl::Surface *surface)
1381{
1382 GLenum format;
1383
1384 switch(surface->getFormat())
1385 {
1386 case D3DFMT_A8R8G8B8:
1387 format = GL_RGBA;
1388 break;
1389 case D3DFMT_X8R8G8B8:
1390 format = GL_RGB;
1391 break;
1392 default:
1393 UNIMPLEMENTED();
1394 return;
1395 }
1396
1397 redefineTexture(0, format, surface->getWidth(), surface->getHeight(), GL_UNSIGNED_BYTE, true);
1398
1399 IDirect3DTexture9 *texture = surface->getOffscreenTexture();
1400
1401 mTexture = texture;
1402 mDirtyImage = true;
1403 mIsRenderable = true;
1404 mSurface = surface;
1405 mSurface->setBoundTexture(this);
1406}
1407
1408void Texture2D::releaseTexImage()
1409{
1410 redefineTexture(0, GL_RGB, 0, 0, GL_UNSIGNED_BYTE, true);
1411}
1412
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001413void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001414{
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001415 redefineTexture(level, format, width, height, GL_UNSIGNED_BYTE, false);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001416
daniel@transgaming.com61208202011-03-21 16:38:50 +00001417 Texture::setCompressedImage(imageSize, pixels, &mImageArray[level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001418}
1419
1420void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1421{
1422 ASSERT(mImageArray[level].surface != NULL);
1423
1424 if (level < levelCount())
1425 {
1426 IDirect3DSurface9 *destLevel = NULL;
1427 HRESULT result = mTexture->GetSurfaceLevel(level, &destLevel);
1428
1429 ASSERT(SUCCEEDED(result));
1430
1431 if (SUCCEEDED(result))
1432 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001433 Image *image = &mImageArray[level];
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001434
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001435 RECT sourceRect = transformPixelRect(xoffset, yoffset, width, height, image->height);;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001436
1437 POINT destPoint;
1438 destPoint.x = sourceRect.left;
1439 destPoint.y = sourceRect.top;
1440
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001441 result = getDevice()->UpdateSurface(image->surface, &sourceRect, destLevel, &destPoint);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001442 ASSERT(SUCCEEDED(result));
1443
1444 destLevel->Release();
1445
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001446 image->dirty = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001447 }
1448 }
1449}
1450
1451void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1452{
1453 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[level]))
1454 {
1455 commitRect(level, xoffset, yoffset, width, height);
1456 }
1457}
1458
1459void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1460{
1461 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[level]))
1462 {
1463 commitRect(level, xoffset, yoffset, width, height);
1464 }
1465}
1466
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001467void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001468{
1469 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
1470
1471 if (!renderTarget)
1472 {
1473 ERR("Failed to retrieve the render target.");
1474 return error(GL_OUT_OF_MEMORY);
1475 }
1476
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001477 redefineTexture(level, format, width, height, GL_UNSIGNED_BYTE, false);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001478
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001479 if (!mImageArray[level].isRenderable())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001480 {
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001481 copyToImage(&mImageArray[level], 0, 0, x, y, width, height, renderTarget);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001482 }
1483 else
1484 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001485 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001486 {
1487 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001488 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00001489
1490 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001491
1492 if (width != 0 && height != 0 && level < levelCount())
1493 {
1494 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
1495 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
1496 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
1497 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
1498 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
daniel@transgaming.comeef864a2011-04-22 11:33:27 +00001499
1500 GLint destYOffset = transformPixelYOffset(0, height, mImageArray[level].height);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001501
1502 IDirect3DSurface9 *dest;
1503 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
1504
daniel@transgaming.comeef864a2011-04-22 11:33:27 +00001505 getBlitter()->copy(source->getRenderTarget(), sourceRect, format, 0, destYOffset, dest);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001506 dest->Release();
1507 }
1508 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001509}
1510
1511void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1512{
1513 if (xoffset + width > mImageArray[level].width || yoffset + height > mImageArray[level].height)
1514 {
1515 return error(GL_INVALID_VALUE);
1516 }
1517
1518 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
1519
1520 if (!renderTarget)
1521 {
1522 ERR("Failed to retrieve the render target.");
1523 return error(GL_OUT_OF_MEMORY);
1524 }
1525
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001526 redefineTexture(level, mImageArray[level].format, mImageArray[level].width, mImageArray[level].height, GL_UNSIGNED_BYTE, false);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001527
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001528 if (!mImageArray[level].isRenderable() || (!mTexture && !isComplete()))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001529 {
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001530 copyToImage(&mImageArray[level], xoffset, yoffset, x, y, width, height, renderTarget);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001531 }
1532 else
1533 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001534 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001535 {
1536 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001537 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00001538
1539 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001540
1541 if (level < levelCount())
1542 {
1543 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
1544 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
1545 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
1546 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
1547 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
1548
1549 GLint destYOffset = transformPixelYOffset(yoffset, height, mImageArray[level].height);
1550
1551 IDirect3DSurface9 *dest;
1552 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
1553
daniel@transgaming.comeef864a2011-04-22 11:33:27 +00001554 getBlitter()->copy(source->getRenderTarget(), sourceRect, mImageArray[0].format, xoffset, destYOffset, dest);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001555 dest->Release();
1556 }
1557 }
1558}
1559
1560// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1561bool Texture2D::isComplete() const
1562{
1563 GLsizei width = mImageArray[0].width;
1564 GLsizei height = mImageArray[0].height;
1565
1566 if (width <= 0 || height <= 0)
1567 {
1568 return false;
1569 }
1570
1571 bool mipmapping = false;
1572
1573 switch (mMinFilter)
1574 {
1575 case GL_NEAREST:
1576 case GL_LINEAR:
1577 mipmapping = false;
1578 break;
1579 case GL_NEAREST_MIPMAP_NEAREST:
1580 case GL_LINEAR_MIPMAP_NEAREST:
1581 case GL_NEAREST_MIPMAP_LINEAR:
1582 case GL_LINEAR_MIPMAP_LINEAR:
1583 mipmapping = true;
1584 break;
1585 default: UNREACHABLE();
1586 }
1587
1588 if ((getInternalFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) ||
1589 (getInternalFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter()))
1590 {
1591 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
1592 {
1593 return false;
1594 }
1595 }
1596
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001597 if ((getWrapS() != GL_CLAMP_TO_EDGE && !isPow2(width))
1598 || (getWrapT() != GL_CLAMP_TO_EDGE && !isPow2(height)))
1599 {
1600 return false;
1601 }
1602
1603 if (mipmapping)
1604 {
1605 if (!isPow2(width) || !isPow2(height))
1606 {
1607 return false;
1608 }
1609
1610 int q = log2(std::max(width, height));
1611
1612 for (int level = 1; level <= q; level++)
1613 {
1614 if (mImageArray[level].format != mImageArray[0].format)
1615 {
1616 return false;
1617 }
1618
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00001619 if (mImageArray[level].type != mImageArray[0].type)
1620 {
1621 return false;
1622 }
1623
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001624 if (mImageArray[level].width != std::max(1, width >> level))
1625 {
1626 return false;
1627 }
1628
1629 if (mImageArray[level].height != std::max(1, height >> level))
1630 {
1631 return false;
1632 }
1633 }
1634 }
1635
1636 return true;
1637}
1638
1639bool Texture2D::isCompressed() const
1640{
1641 return IsCompressed(getInternalFormat());
1642}
1643
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001644IDirect3DBaseTexture9 *Texture2D::getBaseTexture() const
1645{
1646 return mTexture;
1647}
1648
1649// Constructs a Direct3D 9 texture resource from the texture images
1650void Texture2D::createTexture()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001651{
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001652 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001653 D3DFORMAT format = mImageArray[0].getD3DFormat();
daniel@transgaming.com61208202011-03-21 16:38:50 +00001654 GLint levels = creationLevels(mImageArray[0].width, mImageArray[0].height, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001655
daniel@transgaming.com61208202011-03-21 16:38:50 +00001656 IDirect3DTexture9 *texture = NULL;
1657 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 +00001658
1659 if (FAILED(result))
1660 {
1661 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001662 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001663 }
1664
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001665 if (mTexture)
1666 {
1667 mTexture->Release();
1668 }
1669
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001670 mTexture = texture;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00001671 mDirtyImage = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00001672 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001673}
1674
1675void Texture2D::updateTexture()
1676{
1677 IDirect3DDevice9 *device = getDevice();
1678
1679 int levels = levelCount();
1680
1681 for (int level = 0; level < levels; level++)
1682 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001683 if (mImageArray[level].surface && mImageArray[level].dirty)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001684 {
1685 IDirect3DSurface9 *levelSurface = NULL;
1686 HRESULT result = mTexture->GetSurfaceLevel(level, &levelSurface);
1687
1688 ASSERT(SUCCEEDED(result));
1689
1690 if (SUCCEEDED(result))
1691 {
1692 result = device->UpdateSurface(mImageArray[level].surface, NULL, levelSurface, NULL);
1693 ASSERT(SUCCEEDED(result));
1694
1695 levelSurface->Release();
1696
1697 mImageArray[level].dirty = false;
1698 }
1699 }
1700 }
1701}
1702
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001703void Texture2D::convertToRenderTarget()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001704{
1705 IDirect3DTexture9 *texture = NULL;
1706
daniel@transgaming.com61208202011-03-21 16:38:50 +00001707 if (mImageArray[0].width != 0 && mImageArray[0].height != 0)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001708 {
1709 egl::Display *display = getDisplay();
1710 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001711 D3DFORMAT format = mImageArray[0].getD3DFormat();
daniel@transgaming.com61208202011-03-21 16:38:50 +00001712 GLint levels = creationLevels(mImageArray[0].width, mImageArray[0].height, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001713
daniel@transgaming.com61208202011-03-21 16:38:50 +00001714 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 +00001715
1716 if (FAILED(result))
1717 {
1718 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001719 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001720 }
1721
1722 if (mTexture != NULL)
1723 {
1724 int levels = levelCount();
1725 for (int i = 0; i < levels; i++)
1726 {
1727 IDirect3DSurface9 *source;
1728 result = mTexture->GetSurfaceLevel(i, &source);
1729
1730 if (FAILED(result))
1731 {
1732 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1733
1734 texture->Release();
1735
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001736 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001737 }
1738
1739 IDirect3DSurface9 *dest;
1740 result = texture->GetSurfaceLevel(i, &dest);
1741
1742 if (FAILED(result))
1743 {
1744 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1745
1746 texture->Release();
1747 source->Release();
1748
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001749 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001750 }
1751
1752 display->endScene();
1753 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
1754
1755 if (FAILED(result))
1756 {
1757 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1758
1759 texture->Release();
1760 source->Release();
1761 dest->Release();
1762
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001763 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001764 }
1765
1766 source->Release();
1767 dest->Release();
1768 }
1769 }
1770 }
1771
1772 if (mTexture != NULL)
1773 {
1774 mTexture->Release();
1775 }
1776
1777 mTexture = texture;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00001778 mDirtyImage = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00001779 mIsRenderable = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001780}
1781
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001782void Texture2D::generateMipmaps()
1783{
1784 if (!isPow2(mImageArray[0].width) || !isPow2(mImageArray[0].height))
1785 {
1786 return error(GL_INVALID_OPERATION);
1787 }
1788
1789 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
daniel@transgaming.com61208202011-03-21 16:38:50 +00001790 unsigned int q = log2(std::max(mImageArray[0].width, mImageArray[0].height));
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001791 for (unsigned int i = 1; i <= q; i++)
1792 {
1793 if (mImageArray[i].surface != NULL)
1794 {
1795 mImageArray[i].surface->Release();
1796 mImageArray[i].surface = NULL;
1797 }
1798
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001799 mImageArray[i].width = std::max(mImageArray[0].width >> i, 1);
1800 mImageArray[i].height = std::max(mImageArray[0].height >> i, 1);
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00001801 mImageArray[i].format = mImageArray[0].format;
1802 mImageArray[i].type = mImageArray[0].type;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001803 }
1804
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001805 if (mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001806 {
1807 if (mTexture == NULL)
1808 {
1809 ERR(" failed because mTexture was null.");
1810 return;
1811 }
1812
1813 for (unsigned int i = 1; i <= q; i++)
1814 {
1815 IDirect3DSurface9 *upper = NULL;
1816 IDirect3DSurface9 *lower = NULL;
1817
1818 mTexture->GetSurfaceLevel(i-1, &upper);
1819 mTexture->GetSurfaceLevel(i, &lower);
1820
1821 if (upper != NULL && lower != NULL)
1822 {
1823 getBlitter()->boxFilter(upper, lower);
1824 }
1825
1826 if (upper != NULL) upper->Release();
1827 if (lower != NULL) lower->Release();
daniel@transgaming.com61208202011-03-21 16:38:50 +00001828
1829 mImageArray[i].dirty = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001830 }
1831 }
1832 else
1833 {
1834 for (unsigned int i = 1; i <= q; i++)
1835 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001836 createSurface(&mImageArray[i]);
1837
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001838 if (mImageArray[i].surface == NULL)
1839 {
1840 return error(GL_OUT_OF_MEMORY);
1841 }
1842
1843 if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[i].surface, NULL, NULL, mImageArray[i - 1].surface, NULL, NULL, D3DX_FILTER_BOX, 0)))
1844 {
1845 ERR(" failed to load filter %d to %d.", i - 1, i);
1846 }
1847
1848 mImageArray[i].dirty = true;
1849 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001850 }
1851}
1852
1853Renderbuffer *Texture2D::getRenderbuffer(GLenum target)
1854{
1855 if (target != GL_TEXTURE_2D)
1856 {
1857 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
1858 }
1859
1860 if (mColorbufferProxy.get() == NULL)
1861 {
1862 mColorbufferProxy.set(new Renderbuffer(id(), new Colorbuffer(this, target)));
1863 }
1864
1865 return mColorbufferProxy.get();
1866}
1867
1868IDirect3DSurface9 *Texture2D::getRenderTarget(GLenum target)
1869{
1870 ASSERT(target == GL_TEXTURE_2D);
1871
daniel@transgaming.com61208202011-03-21 16:38:50 +00001872 if (!mIsRenderable)
1873 {
1874 convertToRenderTarget();
1875 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001876
1877 if (mTexture == NULL)
1878 {
1879 return NULL;
1880 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00001881
1882 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001883
1884 IDirect3DSurface9 *renderTarget = NULL;
1885 mTexture->GetSurfaceLevel(0, &renderTarget);
1886
1887 return renderTarget;
1888}
1889
1890TextureCubeMap::TextureCubeMap(GLuint id) : Texture(id)
1891{
1892 mTexture = NULL;
1893}
1894
1895TextureCubeMap::~TextureCubeMap()
1896{
1897 for (int i = 0; i < 6; i++)
1898 {
1899 mFaceProxies[i].set(NULL);
1900 }
1901
1902 if (mTexture)
1903 {
1904 mTexture->Release();
1905 mTexture = NULL;
1906 }
1907}
1908
1909GLenum TextureCubeMap::getTarget() const
1910{
1911 return GL_TEXTURE_CUBE_MAP;
1912}
1913
daniel@transgaming.com61208202011-03-21 16:38:50 +00001914GLsizei TextureCubeMap::getWidth() const
1915{
1916 return mImageArray[0][0].width;
1917}
1918
1919GLsizei TextureCubeMap::getHeight() const
1920{
1921 return mImageArray[0][0].height;
1922}
1923
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001924GLenum TextureCubeMap::getInternalFormat() const
1925{
1926 return mImageArray[0][0].format;
1927}
1928
daniel@transgaming.com61208202011-03-21 16:38:50 +00001929GLenum TextureCubeMap::getType() const
1930{
1931 return mImageArray[0][0].type;
1932}
1933
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001934D3DFORMAT TextureCubeMap::getD3DFormat() const
1935{
1936 return mImageArray[0][0].getD3DFormat();
1937}
1938
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001939void 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 +00001940{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001941 setImage(0, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001942}
1943
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001944void 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 +00001945{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001946 setImage(1, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001947}
1948
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001949void 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 +00001950{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001951 setImage(2, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001952}
1953
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001954void 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 +00001955{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001956 setImage(3, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001957}
1958
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001959void 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 +00001960{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001961 setImage(4, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001962}
1963
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001964void 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 +00001965{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001966 setImage(5, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001967}
1968
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001969void 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 +00001970{
daniel@transgaming.com61208202011-03-21 16:38:50 +00001971 redefineTexture(faceIndex(face), level, format, width, height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001972
daniel@transgaming.com61208202011-03-21 16:38:50 +00001973 Texture::setCompressedImage(imageSize, pixels, &mImageArray[faceIndex(face)][level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001974}
1975
1976void TextureCubeMap::commitRect(GLenum faceTarget, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1977{
1978 int face = faceIndex(faceTarget);
1979 ASSERT(mImageArray[face][level].surface != NULL);
1980
1981 if (level < levelCount())
1982 {
1983 IDirect3DSurface9 *destLevel = getCubeMapSurface(faceTarget, level);
1984 ASSERT(destLevel != NULL);
1985
1986 if (destLevel != NULL)
1987 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001988 Image *image = &mImageArray[face][level];
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001989
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001990 RECT sourceRect = transformPixelRect(xoffset, yoffset, width, height, image->height);;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001991
1992 POINT destPoint;
1993 destPoint.x = sourceRect.left;
1994 destPoint.y = sourceRect.top;
1995
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001996 HRESULT result = getDevice()->UpdateSurface(image->surface, &sourceRect, destLevel, &destPoint);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001997 ASSERT(SUCCEEDED(result));
1998
1999 destLevel->Release();
2000
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00002001 image->dirty = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002002 }
2003 }
2004}
2005
2006void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
2007{
2008 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[faceIndex(target)][level]))
2009 {
2010 commitRect(target, level, xoffset, yoffset, width, height);
2011 }
2012}
2013
2014void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
2015{
2016 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[faceIndex(target)][level]))
2017 {
2018 commitRect(target, level, xoffset, yoffset, width, height);
2019 }
2020}
2021
2022// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
2023bool TextureCubeMap::isComplete() const
2024{
2025 int size = mImageArray[0][0].width;
2026
2027 if (size <= 0)
2028 {
2029 return false;
2030 }
2031
2032 bool mipmapping;
2033
2034 switch (mMinFilter)
2035 {
2036 case GL_NEAREST:
2037 case GL_LINEAR:
2038 mipmapping = false;
2039 break;
2040 case GL_NEAREST_MIPMAP_NEAREST:
2041 case GL_LINEAR_MIPMAP_NEAREST:
2042 case GL_NEAREST_MIPMAP_LINEAR:
2043 case GL_LINEAR_MIPMAP_LINEAR:
2044 mipmapping = true;
2045 break;
2046 default: UNREACHABLE();
2047 }
2048
2049 for (int face = 0; face < 6; face++)
2050 {
2051 if (mImageArray[face][0].width != size || mImageArray[face][0].height != size)
2052 {
2053 return false;
2054 }
2055 }
2056
2057 if ((getInternalFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) ||
2058 (getInternalFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter()))
2059 {
2060 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
2061 {
2062 return false;
2063 }
2064 }
2065
2066 if (mipmapping)
2067 {
2068 if (!isPow2(size) && (getWrapS() != GL_CLAMP_TO_EDGE || getWrapT() != GL_CLAMP_TO_EDGE))
2069 {
2070 return false;
2071 }
2072
2073 int q = log2(size);
2074
2075 for (int face = 0; face < 6; face++)
2076 {
2077 for (int level = 1; level <= q; level++)
2078 {
2079 if (mImageArray[face][level].format != mImageArray[0][0].format)
2080 {
2081 return false;
2082 }
2083
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00002084 if (mImageArray[face][level].type != mImageArray[0][0].type)
2085 {
2086 return false;
2087 }
2088
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002089 if (mImageArray[face][level].width != std::max(1, size >> level))
2090 {
2091 return false;
2092 }
2093
2094 ASSERT(mImageArray[face][level].height == mImageArray[face][level].width);
2095 }
2096 }
2097 }
2098
2099 return true;
2100}
2101
2102bool TextureCubeMap::isCompressed() const
2103{
2104 return IsCompressed(getInternalFormat());
2105}
2106
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002107IDirect3DBaseTexture9 *TextureCubeMap::getBaseTexture() const
2108{
2109 return mTexture;
2110}
2111
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002112// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002113void TextureCubeMap::createTexture()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002114{
2115 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002116 D3DFORMAT format = mImageArray[0][0].getD3DFormat();
daniel@transgaming.com61208202011-03-21 16:38:50 +00002117 GLint levels = creationLevels(mImageArray[0][0].width, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002118
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00002119 IDirect3DCubeTexture9 *texture = NULL;
daniel@transgaming.com61208202011-03-21 16:38:50 +00002120 HRESULT result = device->CreateCubeTexture(mImageArray[0][0].width, levels, 0, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002121
2122 if (FAILED(result))
2123 {
2124 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002125 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002126 }
2127
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002128 if (mTexture)
2129 {
2130 mTexture->Release();
2131 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002132
2133 mTexture = texture;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00002134 mDirtyImage = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00002135 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002136}
2137
2138void TextureCubeMap::updateTexture()
2139{
2140 IDirect3DDevice9 *device = getDevice();
2141
2142 for (int face = 0; face < 6; face++)
2143 {
2144 int levels = levelCount();
2145 for (int level = 0; level < levels; level++)
2146 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00002147 Image *image = &mImageArray[face][level];
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002148
daniel@transgaming.com61208202011-03-21 16:38:50 +00002149 if (image->surface && image->dirty)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002150 {
2151 IDirect3DSurface9 *levelSurface = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level);
2152 ASSERT(levelSurface != NULL);
2153
2154 if (levelSurface != NULL)
2155 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00002156 HRESULT result = device->UpdateSurface(image->surface, NULL, levelSurface, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002157 ASSERT(SUCCEEDED(result));
2158
2159 levelSurface->Release();
2160
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00002161 image->dirty = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002162 }
2163 }
2164 }
2165 }
2166}
2167
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002168void TextureCubeMap::convertToRenderTarget()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002169{
2170 IDirect3DCubeTexture9 *texture = NULL;
2171
daniel@transgaming.com61208202011-03-21 16:38:50 +00002172 if (mImageArray[0][0].width != 0)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002173 {
2174 egl::Display *display = getDisplay();
2175 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002176 D3DFORMAT format = mImageArray[0][0].getD3DFormat();
daniel@transgaming.com61208202011-03-21 16:38:50 +00002177 GLint levels = creationLevels(mImageArray[0][0].width, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002178
daniel@transgaming.com61208202011-03-21 16:38:50 +00002179 HRESULT result = device->CreateCubeTexture(mImageArray[0][0].width, levels, D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002180
2181 if (FAILED(result))
2182 {
2183 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002184 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002185 }
2186
2187 if (mTexture != NULL)
2188 {
2189 int levels = levelCount();
2190 for (int f = 0; f < 6; f++)
2191 {
2192 for (int i = 0; i < levels; i++)
2193 {
2194 IDirect3DSurface9 *source;
2195 result = mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &source);
2196
2197 if (FAILED(result))
2198 {
2199 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2200
2201 texture->Release();
2202
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002203 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002204 }
2205
2206 IDirect3DSurface9 *dest;
2207 result = texture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &dest);
2208
2209 if (FAILED(result))
2210 {
2211 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2212
2213 texture->Release();
2214 source->Release();
2215
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002216 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002217 }
2218
2219 display->endScene();
2220 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
2221
2222 if (FAILED(result))
2223 {
2224 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2225
2226 texture->Release();
2227 source->Release();
2228 dest->Release();
2229
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002230 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002231 }
2232 }
2233 }
2234 }
2235 }
2236
2237 if (mTexture != NULL)
2238 {
2239 mTexture->Release();
2240 }
2241
2242 mTexture = texture;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00002243 mDirtyImage = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00002244 mIsRenderable = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002245}
2246
daniel@transgaming.com61208202011-03-21 16:38:50 +00002247void 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 +00002248{
daniel@transgaming.com61208202011-03-21 16:38:50 +00002249 redefineTexture(faceIndex, level, format, width, height, type);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002250
daniel@transgaming.com61208202011-03-21 16:38:50 +00002251 Texture::setImage(unpackAlignment, pixels, &mImageArray[faceIndex][level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002252}
2253
2254unsigned int TextureCubeMap::faceIndex(GLenum face)
2255{
2256 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
2257 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
2258 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
2259 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
2260 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
2261
2262 return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
2263}
2264
daniel@transgaming.com61208202011-03-21 16:38:50 +00002265void TextureCubeMap::redefineTexture(int face, GLint level, GLenum format, GLsizei width, GLsizei height, GLenum type)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002266{
daniel@transgaming.com94a4f032011-03-21 16:38:55 +00002267 GLsizei textureWidth = mImageArray[0][0].width;
2268 GLsizei textureHeight = mImageArray[0][0].height;
2269 GLenum textureFormat = mImageArray[0][0].format;
2270 GLenum textureType = mImageArray[0][0].type;
2271
daniel@transgaming.com61208202011-03-21 16:38:50 +00002272 mImageArray[face][level].width = width;
2273 mImageArray[face][level].height = height;
2274 mImageArray[face][level].format = format;
2275 mImageArray[face][level].type = type;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002276
daniel@transgaming.com61208202011-03-21 16:38:50 +00002277 if (!mTexture)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002278 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00002279 return;
2280 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002281
daniel@transgaming.com94a4f032011-03-21 16:38:55 +00002282 bool sizeOkay = (textureWidth >> level == width);
2283 bool textureOkay = (sizeOkay && textureFormat == format && textureType == type);
daniel@transgaming.com61208202011-03-21 16:38:50 +00002284
2285 if (!textureOkay) // Purge all the levels and the texture.
2286 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002287 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
2288 {
2289 for (int f = 0; f < 6; f++)
2290 {
2291 if (mImageArray[f][i].surface != NULL)
2292 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002293 mImageArray[f][i].surface->Release();
2294 mImageArray[f][i].surface = NULL;
daniel@transgaming.com61208202011-03-21 16:38:50 +00002295 mImageArray[f][i].dirty = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002296 }
2297 }
2298 }
2299
2300 if (mTexture != NULL)
2301 {
2302 mTexture->Release();
2303 mTexture = NULL;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00002304 mDirtyImage = true;
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002305 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002306 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002307 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002308}
2309
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002310void 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 +00002311{
2312 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
2313
2314 if (!renderTarget)
2315 {
2316 ERR("Failed to retrieve the render target.");
2317 return error(GL_OUT_OF_MEMORY);
2318 }
2319
2320 unsigned int faceindex = faceIndex(target);
daniel@transgaming.com61208202011-03-21 16:38:50 +00002321 redefineTexture(faceindex, level, format, width, height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002322
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002323 if (!mImageArray[faceindex][level].isRenderable())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002324 {
daniel@transgaming.comb6276992011-03-29 00:58:18 +00002325 copyToImage(&mImageArray[faceindex][level], 0, 0, x, y, width, height, renderTarget);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002326 }
2327 else
2328 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00002329 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002330 {
2331 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002332 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00002333
2334 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002335
2336 ASSERT(width == height);
2337
2338 if (width > 0 && level < levelCount())
2339 {
2340 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
2341 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
2342 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
2343 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
2344 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
2345
daniel@transgaming.comeef864a2011-04-22 11:33:27 +00002346 GLint destYOffset = transformPixelYOffset(0, height, mImageArray[faceindex][level].width);
2347
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002348 IDirect3DSurface9 *dest = getCubeMapSurface(target, level);
2349
daniel@transgaming.comeef864a2011-04-22 11:33:27 +00002350 getBlitter()->copy(source->getRenderTarget(), sourceRect, format, 0, destYOffset, dest);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002351 dest->Release();
2352 }
2353 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002354}
2355
2356IDirect3DSurface9 *TextureCubeMap::getCubeMapSurface(GLenum face, unsigned int level)
2357{
2358 if (mTexture == NULL)
2359 {
2360 UNREACHABLE();
2361 return NULL;
2362 }
2363
2364 IDirect3DSurface9 *surface = NULL;
2365
2366 HRESULT hr = mTexture->GetCubeMapSurface(es2dx::ConvertCubeFace(face), level, &surface);
2367
2368 return (SUCCEEDED(hr)) ? surface : NULL;
2369}
2370
2371void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
2372{
2373 GLsizei size = mImageArray[faceIndex(target)][level].width;
2374
2375 if (xoffset + width > size || yoffset + height > size)
2376 {
2377 return error(GL_INVALID_VALUE);
2378 }
2379
2380 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
2381
2382 if (!renderTarget)
2383 {
2384 ERR("Failed to retrieve the render target.");
2385 return error(GL_OUT_OF_MEMORY);
2386 }
2387
2388 unsigned int faceindex = faceIndex(target);
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002389 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 +00002390
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002391 if (!mImageArray[faceindex][level].isRenderable() || (!mTexture && !isComplete()))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002392 {
daniel@transgaming.comb6276992011-03-29 00:58:18 +00002393 copyToImage(&mImageArray[faceindex][level], 0, 0, x, y, width, height, renderTarget);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002394 }
2395 else
2396 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00002397 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002398 {
2399 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002400 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00002401
2402 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002403
2404 if (level < levelCount())
2405 {
2406 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
2407 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
2408 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
2409 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
2410 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
2411
2412 GLint destYOffset = transformPixelYOffset(yoffset, height, mImageArray[faceindex][level].width);
2413
2414 IDirect3DSurface9 *dest = getCubeMapSurface(target, level);
2415
daniel@transgaming.comeef864a2011-04-22 11:33:27 +00002416 getBlitter()->copy(source->getRenderTarget(), sourceRect, mImageArray[0][0].format, xoffset, destYOffset, dest);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002417 dest->Release();
2418 }
2419 }
2420}
2421
2422bool TextureCubeMap::isCubeComplete() const
2423{
2424 if (mImageArray[0][0].width == 0)
2425 {
2426 return false;
2427 }
2428
2429 for (unsigned int f = 1; f < 6; f++)
2430 {
2431 if (mImageArray[f][0].width != mImageArray[0][0].width
2432 || mImageArray[f][0].format != mImageArray[0][0].format)
2433 {
2434 return false;
2435 }
2436 }
2437
2438 return true;
2439}
2440
2441void TextureCubeMap::generateMipmaps()
2442{
2443 if (!isPow2(mImageArray[0][0].width) || !isCubeComplete())
2444 {
2445 return error(GL_INVALID_OPERATION);
2446 }
2447
2448 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
2449 unsigned int q = log2(mImageArray[0][0].width);
2450 for (unsigned int f = 0; f < 6; f++)
2451 {
2452 for (unsigned int i = 1; i <= q; i++)
2453 {
2454 if (mImageArray[f][i].surface != NULL)
2455 {
2456 mImageArray[f][i].surface->Release();
2457 mImageArray[f][i].surface = NULL;
2458 }
2459
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002460 mImageArray[f][i].width = std::max(mImageArray[f][0].width >> i, 1);
2461 mImageArray[f][i].height = mImageArray[f][i].width;
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00002462 mImageArray[f][i].format = mImageArray[f][0].format;
2463 mImageArray[f][i].type = mImageArray[f][0].type;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002464 }
2465 }
2466
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002467 if (mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002468 {
2469 if (mTexture == NULL)
2470 {
2471 return;
2472 }
2473
2474 for (unsigned int f = 0; f < 6; f++)
2475 {
2476 for (unsigned int i = 1; i <= q; i++)
2477 {
2478 IDirect3DSurface9 *upper = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i-1);
2479 IDirect3DSurface9 *lower = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i);
2480
2481 if (upper != NULL && lower != NULL)
2482 {
2483 getBlitter()->boxFilter(upper, lower);
2484 }
2485
2486 if (upper != NULL) upper->Release();
2487 if (lower != NULL) lower->Release();
daniel@transgaming.com61208202011-03-21 16:38:50 +00002488
2489 mImageArray[f][i].dirty = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002490 }
2491 }
2492 }
2493 else
2494 {
2495 for (unsigned int f = 0; f < 6; f++)
2496 {
2497 for (unsigned int i = 1; i <= q; i++)
2498 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00002499 createSurface(&mImageArray[f][i]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002500 if (mImageArray[f][i].surface == NULL)
2501 {
2502 return error(GL_OUT_OF_MEMORY);
2503 }
2504
2505 if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[f][i].surface, NULL, NULL, mImageArray[f][i - 1].surface, NULL, NULL, D3DX_FILTER_BOX, 0)))
2506 {
2507 ERR(" failed to load filter %d to %d.", i - 1, i);
2508 }
2509
2510 mImageArray[f][i].dirty = true;
2511 }
2512 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002513 }
2514}
2515
2516Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target)
2517{
2518 if (!IsCubemapTextureTarget(target))
2519 {
2520 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
2521 }
2522
2523 unsigned int face = faceIndex(target);
2524
2525 if (mFaceProxies[face].get() == NULL)
2526 {
2527 mFaceProxies[face].set(new Renderbuffer(id(), new Colorbuffer(this, target)));
2528 }
2529
2530 return mFaceProxies[face].get();
2531}
2532
2533IDirect3DSurface9 *TextureCubeMap::getRenderTarget(GLenum target)
2534{
2535 ASSERT(IsCubemapTextureTarget(target));
2536
daniel@transgaming.com61208202011-03-21 16:38:50 +00002537 if (!mIsRenderable)
2538 {
2539 convertToRenderTarget();
2540 }
2541
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002542 if (mTexture == NULL)
2543 {
2544 return NULL;
2545 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00002546
2547 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002548
2549 IDirect3DSurface9 *renderTarget = NULL;
2550 mTexture->GetCubeMapSurface(es2dx::ConvertCubeFace(target), 0, &renderTarget);
2551
2552 return renderTarget;
2553}
2554
2555}