blob: a0f446e1381f2a72343824ed569a14e86569da9d [file] [log] [blame]
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001//
2// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7// Texture.cpp: Implements the gl::Texture class and its derived classes
8// Texture2D and TextureCubeMap. Implements GL texture objects and related
9// functionality. [OpenGL ES 2.0.24] section 3.7 page 63.
10
11#include "libGLESv2/Texture.h"
12
13#include <d3dx9tex.h>
14
15#include <algorithm>
16
17#include "common/debug.h"
18
19#include "libGLESv2/main.h"
20#include "libGLESv2/mathutil.h"
21#include "libGLESv2/utilities.h"
22#include "libGLESv2/Blit.h"
23#include "libGLESv2/Framebuffer.h"
24
25namespace gl
26{
27
28Texture::Image::Image()
29 : width(0), height(0), dirty(false), surface(NULL), format(GL_NONE)
30{
31}
32
33Texture::Image::~Image()
34{
35 if (surface) surface->Release();
36}
37
38Texture::Texture(GLuint id) : RefCountObject(id)
39{
40 mMinFilter = GL_NEAREST_MIPMAP_LINEAR;
41 mMagFilter = GL_LINEAR;
42 mWrapS = GL_REPEAT;
43 mWrapT = GL_REPEAT;
44
45 mWidth = 0;
46 mHeight = 0;
47
48 mDirtyMetaData = true;
49 mDirty = true;
50 mIsRenderable = false;
51 mType = GL_UNSIGNED_BYTE;
52 mBaseTexture = NULL;
53}
54
55Texture::~Texture()
56{
57}
58
59Blit *Texture::getBlitter()
60{
61 Context *context = getContext();
62 return context->getBlitter();
63}
64
65// Returns true on successful filter state update (valid enum parameter)
66bool Texture::setMinFilter(GLenum filter)
67{
68 switch (filter)
69 {
70 case GL_NEAREST:
71 case GL_LINEAR:
72 case GL_NEAREST_MIPMAP_NEAREST:
73 case GL_LINEAR_MIPMAP_NEAREST:
74 case GL_NEAREST_MIPMAP_LINEAR:
75 case GL_LINEAR_MIPMAP_LINEAR:
76 {
77 if (mMinFilter != filter)
78 {
79 mMinFilter = filter;
80 mDirty = true;
81 }
82 return true;
83 }
84 default:
85 return false;
86 }
87}
88
89// Returns true on successful filter state update (valid enum parameter)
90bool Texture::setMagFilter(GLenum filter)
91{
92 switch (filter)
93 {
94 case GL_NEAREST:
95 case GL_LINEAR:
96 {
97 if (mMagFilter != filter)
98 {
99 mMagFilter = filter;
100 mDirty = true;
101 }
102 return true;
103 }
104 default:
105 return false;
106 }
107}
108
109// Returns true on successful wrap state update (valid enum parameter)
110bool Texture::setWrapS(GLenum wrap)
111{
112 switch (wrap)
113 {
114 case GL_REPEAT:
115 case GL_CLAMP_TO_EDGE:
116 case GL_MIRRORED_REPEAT:
117 {
118 if (mWrapS != wrap)
119 {
120 mWrapS = wrap;
121 mDirty = true;
122 }
123 return true;
124 }
125 default:
126 return false;
127 }
128}
129
130// Returns true on successful wrap state update (valid enum parameter)
131bool Texture::setWrapT(GLenum wrap)
132{
133 switch (wrap)
134 {
135 case GL_REPEAT:
136 case GL_CLAMP_TO_EDGE:
137 case GL_MIRRORED_REPEAT:
138 {
139 if (mWrapT != wrap)
140 {
141 mWrapT = wrap;
142 mDirty = true;
143 }
144 return true;
145 }
146 default:
147 return false;
148 }
149}
150
151GLenum Texture::getMinFilter() const
152{
153 return mMinFilter;
154}
155
156GLenum Texture::getMagFilter() const
157{
158 return mMagFilter;
159}
160
161GLenum Texture::getWrapS() const
162{
163 return mWrapS;
164}
165
166GLenum Texture::getWrapT() const
167{
168 return mWrapT;
169}
170
171GLsizei Texture::getWidth() const
172{
173 return mWidth;
174}
175
176GLsizei Texture::getHeight() const
177{
178 return mHeight;
179}
180
181bool Texture::isFloatingPoint() const
182{
183 return (mType == GL_FLOAT || mType == GL_HALF_FLOAT_OES);
184}
185
186bool Texture::isRenderableFormat() const
187{
188 D3DFORMAT format = getD3DFormat();
189
190 switch(format)
191 {
192 case D3DFMT_L8:
193 case D3DFMT_A8L8:
194 case D3DFMT_DXT1:
195 return false;
196 case D3DFMT_A8R8G8B8:
197 case D3DFMT_X8R8G8B8:
198 case D3DFMT_A16B16G16R16F:
199 case D3DFMT_A32B32G32R32F:
200 return true;
201 default:
202 UNREACHABLE();
203 }
204
205 return false;
206}
207
208// Selects an internal Direct3D 9 format for storing an Image
209D3DFORMAT Texture::selectFormat(GLenum format, GLenum type)
210{
211 if (format == GL_COMPRESSED_RGB_S3TC_DXT1_EXT ||
212 format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT)
213 {
214 return D3DFMT_DXT1;
215 }
216 else if (type == GL_FLOAT)
217 {
218 return D3DFMT_A32B32G32R32F;
219 }
220 else if (type == GL_HALF_FLOAT_OES)
221 {
222 return D3DFMT_A16B16G16R16F;
223 }
224 else if (type == GL_UNSIGNED_BYTE)
225 {
226 if (format == GL_LUMINANCE && getContext()->supportsLuminanceTextures())
227 {
228 return D3DFMT_L8;
229 }
230 else if (format == GL_LUMINANCE_ALPHA && getContext()->supportsLuminanceAlphaTextures())
231 {
232 return D3DFMT_A8L8;
233 }
234 else if (format == GL_RGB)
235 {
236 return D3DFMT_X8R8G8B8;
237 }
238
239 return D3DFMT_A8R8G8B8;
240 }
241
242 return D3DFMT_A8R8G8B8;
243}
244
245// Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input
246// into the target pixel rectangle at output with outputPitch bytes in between each line.
247void Texture::loadImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type,
248 GLint unpackAlignment, const void *input, size_t outputPitch, void *output, D3DSURFACE_DESC *description) const
249{
250 GLsizei inputPitch = -ComputePitch(width, format, type, unpackAlignment);
251 input = ((char*)input) - inputPitch * (height - 1);
252
253 switch (type)
254 {
255 case GL_UNSIGNED_BYTE:
256 switch (format)
257 {
258 case GL_ALPHA:
259 loadAlphaImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
260 break;
261 case GL_LUMINANCE:
262 loadLuminanceImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output, description->Format == D3DFMT_L8);
263 break;
264 case GL_LUMINANCE_ALPHA:
265 loadLuminanceAlphaImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output, description->Format == D3DFMT_A8L8);
266 break;
267 case GL_RGB:
268 loadRGBUByteImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
269 break;
270 case GL_RGBA:
271 loadRGBAUByteImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
272 break;
273 case GL_BGRA_EXT:
274 loadBGRAImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
275 break;
276 default: UNREACHABLE();
277 }
278 break;
279 case GL_UNSIGNED_SHORT_5_6_5:
280 switch (format)
281 {
282 case GL_RGB:
283 loadRGB565ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
284 break;
285 default: UNREACHABLE();
286 }
287 break;
288 case GL_UNSIGNED_SHORT_4_4_4_4:
289 switch (format)
290 {
291 case GL_RGBA:
292 loadRGBA4444ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
293 break;
294 default: UNREACHABLE();
295 }
296 break;
297 case GL_UNSIGNED_SHORT_5_5_5_1:
298 switch (format)
299 {
300 case GL_RGBA:
301 loadRGBA5551ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
302 break;
303 default: UNREACHABLE();
304 }
305 break;
306 case GL_FLOAT:
307 switch (format)
308 {
309 // float textures are converted to RGBA, not BGRA, as they're stored that way in D3D
310 case GL_ALPHA:
311 loadAlphaFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
312 break;
313 case GL_LUMINANCE:
314 loadLuminanceFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
315 break;
316 case GL_LUMINANCE_ALPHA:
317 loadLuminanceAlphaFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
318 break;
319 case GL_RGB:
320 loadRGBFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
321 break;
322 case GL_RGBA:
323 loadRGBAFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
324 break;
325 default: UNREACHABLE();
326 }
327 break;
328 case GL_HALF_FLOAT_OES:
329 switch (format)
330 {
331 // float textures are converted to RGBA, not BGRA, as they're stored that way in D3D
332 case GL_ALPHA:
333 loadAlphaHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
334 break;
335 case GL_LUMINANCE:
336 loadLuminanceHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
337 break;
338 case GL_LUMINANCE_ALPHA:
339 loadLuminanceAlphaHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
340 break;
341 case GL_RGB:
342 loadRGBHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
343 break;
344 case GL_RGBA:
345 loadRGBAHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
346 break;
347 default: UNREACHABLE();
348 }
349 break;
350 default: UNREACHABLE();
351 }
352}
353
354void Texture::loadAlphaImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
355 int inputPitch, const void *input, size_t outputPitch, void *output) const
356{
357 const unsigned char *source = NULL;
358 unsigned char *dest = NULL;
359
360 for (int y = 0; y < height; y++)
361 {
362 source = static_cast<const unsigned char*>(input) + y * inputPitch;
363 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
364 for (int x = 0; x < width; x++)
365 {
366 dest[4 * x + 0] = 0;
367 dest[4 * x + 1] = 0;
368 dest[4 * x + 2] = 0;
369 dest[4 * x + 3] = source[x];
370 }
371 }
372}
373
374void Texture::loadAlphaFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
375 int inputPitch, const void *input, size_t outputPitch, void *output) const
376{
377 const float *source = NULL;
378 float *dest = NULL;
379
380 for (int y = 0; y < height; y++)
381 {
382 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
383 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
384 for (int x = 0; x < width; x++)
385 {
386 dest[4 * x + 0] = 0;
387 dest[4 * x + 1] = 0;
388 dest[4 * x + 2] = 0;
389 dest[4 * x + 3] = source[x];
390 }
391 }
392}
393
394void Texture::loadAlphaHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
395 int inputPitch, const void *input, size_t outputPitch, void *output) const
396{
397 const unsigned short *source = NULL;
398 unsigned short *dest = NULL;
399
400 for (int y = 0; y < height; y++)
401 {
402 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
403 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
404 for (int x = 0; x < width; x++)
405 {
406 dest[4 * x + 0] = 0;
407 dest[4 * x + 1] = 0;
408 dest[4 * x + 2] = 0;
409 dest[4 * x + 3] = source[x];
410 }
411 }
412}
413
414void Texture::loadLuminanceImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
415 int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const
416{
417 const int destBytesPerPixel = native? 1: 4;
418 const unsigned char *source = NULL;
419 unsigned char *dest = NULL;
420
421 for (int y = 0; y < height; y++)
422 {
423 source = static_cast<const unsigned char*>(input) + y * inputPitch;
424 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * destBytesPerPixel;
425
426 if (!native) // BGRA8 destination format
427 {
428 for (int x = 0; x < width; x++)
429 {
430 dest[4 * x + 0] = source[x];
431 dest[4 * x + 1] = source[x];
432 dest[4 * x + 2] = source[x];
433 dest[4 * x + 3] = 0xFF;
434 }
435 }
436 else // L8 destination format
437 {
438 memcpy(dest, source, width);
439 }
440 }
441}
442
443void Texture::loadLuminanceFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
444 int inputPitch, const void *input, size_t outputPitch, void *output) const
445{
446 const float *source = NULL;
447 float *dest = NULL;
448
449 for (int y = 0; y < height; y++)
450 {
451 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
452 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
453 for (int x = 0; x < width; x++)
454 {
455 dest[4 * x + 0] = source[x];
456 dest[4 * x + 1] = source[x];
457 dest[4 * x + 2] = source[x];
458 dest[4 * x + 3] = 1.0f;
459 }
460 }
461}
462
463void Texture::loadLuminanceHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
464 int inputPitch, const void *input, size_t outputPitch, void *output) const
465{
466 const unsigned short *source = NULL;
467 unsigned short *dest = NULL;
468
469 for (int y = 0; y < height; y++)
470 {
471 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
472 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
473 for (int x = 0; x < width; x++)
474 {
475 dest[4 * x + 0] = source[x];
476 dest[4 * x + 1] = source[x];
477 dest[4 * x + 2] = source[x];
478 dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1
479 }
480 }
481}
482
483void Texture::loadLuminanceAlphaImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
484 int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const
485{
486 const int destBytesPerPixel = native? 2: 4;
487 const unsigned char *source = NULL;
488 unsigned char *dest = NULL;
489
490 for (int y = 0; y < height; y++)
491 {
492 source = static_cast<const unsigned char*>(input) + y * inputPitch;
493 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * destBytesPerPixel;
494
495 if (!native) // BGRA8 destination format
496 {
497 for (int x = 0; x < width; x++)
498 {
499 dest[4 * x + 0] = source[2*x+0];
500 dest[4 * x + 1] = source[2*x+0];
501 dest[4 * x + 2] = source[2*x+0];
502 dest[4 * x + 3] = source[2*x+1];
503 }
504 }
505 else
506 {
507 memcpy(dest, source, width * 2);
508 }
509 }
510}
511
512void Texture::loadLuminanceAlphaFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
513 int inputPitch, const void *input, size_t outputPitch, void *output) const
514{
515 const float *source = NULL;
516 float *dest = NULL;
517
518 for (int y = 0; y < height; y++)
519 {
520 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
521 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
522 for (int x = 0; x < width; x++)
523 {
524 dest[4 * x + 0] = source[2*x+0];
525 dest[4 * x + 1] = source[2*x+0];
526 dest[4 * x + 2] = source[2*x+0];
527 dest[4 * x + 3] = source[2*x+1];
528 }
529 }
530}
531
532void Texture::loadLuminanceAlphaHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
533 int inputPitch, const void *input, size_t outputPitch, void *output) const
534{
535 const unsigned short *source = NULL;
536 unsigned short *dest = NULL;
537
538 for (int y = 0; y < height; y++)
539 {
540 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
541 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
542 for (int x = 0; x < width; x++)
543 {
544 dest[4 * x + 0] = source[2*x+0];
545 dest[4 * x + 1] = source[2*x+0];
546 dest[4 * x + 2] = source[2*x+0];
547 dest[4 * x + 3] = source[2*x+1];
548 }
549 }
550}
551
552void Texture::loadRGBUByteImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
553 int inputPitch, const void *input, size_t outputPitch, void *output) const
554{
555 const unsigned char *source = NULL;
556 unsigned char *dest = NULL;
557
558 for (int y = 0; y < height; y++)
559 {
560 source = static_cast<const unsigned char*>(input) + y * inputPitch;
561 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
562 for (int x = 0; x < width; x++)
563 {
564 dest[4 * x + 0] = source[x * 3 + 2];
565 dest[4 * x + 1] = source[x * 3 + 1];
566 dest[4 * x + 2] = source[x * 3 + 0];
567 dest[4 * x + 3] = 0xFF;
568 }
569 }
570}
571
572void Texture::loadRGB565ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
573 int inputPitch, const void *input, size_t outputPitch, void *output) const
574{
575 const unsigned short *source = NULL;
576 unsigned char *dest = NULL;
577
578 for (int y = 0; y < height; y++)
579 {
580 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
581 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
582 for (int x = 0; x < width; x++)
583 {
584 unsigned short rgba = source[x];
585 dest[4 * x + 0] = ((rgba & 0x001F) << 3) | ((rgba & 0x001F) >> 2);
586 dest[4 * x + 1] = ((rgba & 0x07E0) >> 3) | ((rgba & 0x07E0) >> 9);
587 dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
588 dest[4 * x + 3] = 0xFF;
589 }
590 }
591}
592
593void Texture::loadRGBFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
594 int inputPitch, const void *input, size_t outputPitch, void *output) const
595{
596 const float *source = NULL;
597 float *dest = NULL;
598
599 for (int y = 0; y < height; y++)
600 {
601 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
602 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
603 for (int x = 0; x < width; x++)
604 {
605 dest[4 * x + 0] = source[x * 3 + 0];
606 dest[4 * x + 1] = source[x * 3 + 1];
607 dest[4 * x + 2] = source[x * 3 + 2];
608 dest[4 * x + 3] = 1.0f;
609 }
610 }
611}
612
613void Texture::loadRGBHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
614 int inputPitch, const void *input, size_t outputPitch, void *output) const
615{
616 const unsigned short *source = NULL;
617 unsigned short *dest = NULL;
618
619 for (int y = 0; y < height; y++)
620 {
621 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
622 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
623 for (int x = 0; x < width; x++)
624 {
625 dest[4 * x + 0] = source[x * 3 + 0];
626 dest[4 * x + 1] = source[x * 3 + 1];
627 dest[4 * x + 2] = source[x * 3 + 2];
628 dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1
629 }
630 }
631}
632
633void Texture::loadRGBAUByteImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
634 int inputPitch, const void *input, size_t outputPitch, void *output) const
635{
636 const unsigned char *source = NULL;
637 unsigned char *dest = NULL;
638
639 for (int y = 0; y < height; y++)
640 {
641 source = static_cast<const unsigned char*>(input) + y * inputPitch;
642 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
643 for (int x = 0; x < width; x++)
644 {
645 dest[4 * x + 0] = source[x * 4 + 2];
646 dest[4 * x + 1] = source[x * 4 + 1];
647 dest[4 * x + 2] = source[x * 4 + 0];
648 dest[4 * x + 3] = source[x * 4 + 3];
649 }
650 }
651}
652
653void Texture::loadRGBA4444ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
654 int inputPitch, const void *input, size_t outputPitch, void *output) const
655{
656 const unsigned short *source = NULL;
657 unsigned char *dest = NULL;
658
659 for (int y = 0; y < height; y++)
660 {
661 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
662 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
663 for (int x = 0; x < width; x++)
664 {
665 unsigned short rgba = source[x];
666 dest[4 * x + 0] = ((rgba & 0x00F0) << 0) | ((rgba & 0x00F0) >> 4);
667 dest[4 * x + 1] = ((rgba & 0x0F00) >> 4) | ((rgba & 0x0F00) >> 8);
668 dest[4 * x + 2] = ((rgba & 0xF000) >> 8) | ((rgba & 0xF000) >> 12);
669 dest[4 * x + 3] = ((rgba & 0x000F) << 4) | ((rgba & 0x000F) >> 0);
670 }
671 }
672}
673
674void Texture::loadRGBA5551ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
675 int inputPitch, const void *input, size_t outputPitch, void *output) const
676{
677 const unsigned short *source = NULL;
678 unsigned char *dest = NULL;
679
680 for (int y = 0; y < height; y++)
681 {
682 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
683 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
684 for (int x = 0; x < width; x++)
685 {
686 unsigned short rgba = source[x];
687 dest[4 * x + 0] = ((rgba & 0x003E) << 2) | ((rgba & 0x003E) >> 3);
688 dest[4 * x + 1] = ((rgba & 0x07C0) >> 3) | ((rgba & 0x07C0) >> 8);
689 dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
690 dest[4 * x + 3] = (rgba & 0x0001) ? 0xFF : 0;
691 }
692 }
693}
694
695void Texture::loadRGBAFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
696 int inputPitch, const void *input, size_t outputPitch, void *output) const
697{
698 const float *source = NULL;
699 float *dest = NULL;
700
701 for (int y = 0; y < height; y++)
702 {
703 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
704 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
705 memcpy(dest, source, width * 16);
706 }
707}
708
709void Texture::loadRGBAHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
710 int inputPitch, const void *input, size_t outputPitch, void *output) const
711{
712 const unsigned char *source = NULL;
713 unsigned char *dest = NULL;
714
715 for (int y = 0; y < height; y++)
716 {
717 source = static_cast<const unsigned char*>(input) + y * inputPitch;
718 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8;
719 memcpy(dest, source, width * 8);
720 }
721}
722
723void Texture::loadBGRAImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
724 int inputPitch, const void *input, size_t outputPitch, void *output) const
725{
726 const unsigned char *source = NULL;
727 unsigned char *dest = NULL;
728
729 for (int y = 0; y < height; y++)
730 {
731 source = static_cast<const unsigned char*>(input) + y * inputPitch;
732 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
733 memcpy(dest, source, width*4);
734 }
735}
736
737void Texture::loadCompressedImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
738 int inputPitch, const void *input, size_t outputPitch, void *output) const
739{
740 ASSERT(xoffset % 4 == 0);
741 ASSERT(yoffset % 4 == 0);
742 ASSERT(width % 4 == 0 || width == 2 || width == 1);
743 ASSERT(inputPitch % 8 == 0);
744 ASSERT(outputPitch % 8 == 0);
745
746 const unsigned int *source = reinterpret_cast<const unsigned int*>(input);
747 unsigned int *dest = reinterpret_cast<unsigned int*>(output);
748
749 switch (height)
750 {
751 case 1:
752 // Round width up in case it is 1.
753 for (int x = 0; x < (width + 1) / 2; x += 2)
754 {
755 // First 32-bits is two RGB565 colors shared by tile and does not need to be modified.
756 dest[x] = source[x];
757
758 // Second 32-bits contains 4 rows of 4 2-bit interpolants between the colors, the last 3 rows being unused. No flipping should occur.
759 dest[x + 1] = source[x + 1];
760 }
761 break;
762 case 2:
763 // Round width up in case it is 1.
764 for (int x = 0; x < (width + 1) / 2; x += 2)
765 {
766 // First 32-bits is two RGB565 colors shared by tile and does not need to be modified.
767 dest[x] = source[x];
768
769 // 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.
770 dest[x + 1] = ((source[x + 1] << 8) & 0x0000FF00) |
771 ((source[x + 1] >> 8) & 0x000000FF);
772 }
773 break;
774 default:
775 ASSERT(height % 4 == 0);
776 for (int y = 0; y < height / 4; ++y)
777 {
778 const unsigned int *source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);
779 unsigned int *dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
780
781 // Round width up in case it is 1.
782 for (int x = 0; x < (width + 1) / 2; x += 2)
783 {
784 // First 32-bits is two RGB565 colors shared by tile and does not need to be modified.
785 dest[x] = source[x];
786
787 // Second 32-bits contains 4 rows of 4 2-bit interpolants between the colors. All rows should be flipped.
788 dest[x + 1] = (source[x + 1] >> 24) |
789 ((source[x + 1] << 8) & 0x00FF0000) |
790 ((source[x + 1] >> 8) & 0x0000FF00) |
791 (source[x + 1] << 24);
792 }
793 }
794 break;
795 }
796}
797
798void Texture::createSurface(GLsizei width, GLsizei height, GLenum format, GLenum type, Image *img)
799{
800 IDirect3DTexture9 *newTexture = NULL;
801 IDirect3DSurface9 *newSurface = NULL;
802
803 if (width != 0 && height != 0)
804 {
805 int levelToFetch = 0;
806 GLsizei requestWidth = width;
807 GLsizei requestHeight = height;
808 if (IsCompressed(format) && (width % 4 != 0 || height % 4 != 0))
809 {
810 bool isMult4 = false;
811 int upsampleCount = 0;
812 while (!isMult4)
813 {
814 requestWidth <<= 1;
815 requestHeight <<= 1;
816 upsampleCount++;
817 if (requestWidth % 4 == 0 && requestHeight % 4 == 0)
818 {
819 isMult4 = true;
820 }
821 }
822 levelToFetch = upsampleCount;
823 }
824
825 HRESULT result = getDevice()->CreateTexture(requestWidth, requestHeight, levelToFetch + 1, NULL, selectFormat(format, type),
826 D3DPOOL_SYSTEMMEM, &newTexture, NULL);
827
828 if (FAILED(result))
829 {
830 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
831 return error(GL_OUT_OF_MEMORY);
832 }
833
834 newTexture->GetSurfaceLevel(levelToFetch, &newSurface);
835 newTexture->Release();
836 }
837
838 if (img->surface) img->surface->Release();
839 img->surface = newSurface;
840
841 img->width = width;
842 img->height = height;
843 img->format = format;
844}
845
846void Texture::setImage(GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, Image *img)
847{
848 createSurface(width, height, format, type, img);
849
850 if (pixels != NULL && img->surface != NULL)
851 {
852 D3DSURFACE_DESC description;
853 img->surface->GetDesc(&description);
854
855 D3DLOCKED_RECT locked;
856 HRESULT result = img->surface->LockRect(&locked, NULL, 0);
857
858 ASSERT(SUCCEEDED(result));
859
860 if (SUCCEEDED(result))
861 {
862 loadImageData(0, 0, width, height, format, type, unpackAlignment, pixels, locked.Pitch, locked.pBits, &description);
863 img->surface->UnlockRect();
864 }
865
866 img->dirty = true;
867 }
868
869 mDirtyMetaData = true;
870}
871
872void Texture::setCompressedImage(GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, Image *img)
873{
874 createSurface(width, height, format, GL_UNSIGNED_BYTE, img);
875
876 if (pixels != NULL && img->surface != NULL)
877 {
878 D3DLOCKED_RECT locked;
879 HRESULT result = img->surface->LockRect(&locked, NULL, 0);
880
881 ASSERT(SUCCEEDED(result));
882
883 if (SUCCEEDED(result))
884 {
885 int inputPitch = ComputeCompressedPitch(width, format);
886 int inputSize = ComputeCompressedSize(width, height, format);
887 loadCompressedImageData(0, 0, width, height, -inputPitch, static_cast<const char*>(pixels) + inputSize - inputPitch, locked.Pitch, locked.pBits);
888 img->surface->UnlockRect();
889 }
890
891 img->dirty = true;
892 }
893
894 mDirtyMetaData = true;
895}
896
897bool Texture::subImage(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, Image *img)
898{
899 if (width + xoffset > img->width || height + yoffset > img->height)
900 {
901 error(GL_INVALID_VALUE);
902 return false;
903 }
904
905 if (!img->surface)
906 {
907 createSurface(img->width, img->height, format, type, img);
908 }
909
910 if (pixels != NULL && img->surface != NULL)
911 {
912 D3DSURFACE_DESC description;
913 img->surface->GetDesc(&description);
914
915 D3DLOCKED_RECT locked;
916 HRESULT result = img->surface->LockRect(&locked, NULL, 0);
917
918 ASSERT(SUCCEEDED(result));
919
920 if (SUCCEEDED(result))
921 {
922 loadImageData(xoffset, transformPixelYOffset(yoffset, height, img->height), width, height, format, type, unpackAlignment, pixels, locked.Pitch, locked.pBits, &description);
923 img->surface->UnlockRect();
924 }
925
926 img->dirty = true;
927 }
928
929 return true;
930}
931
932bool Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, Image *img)
933{
934 if (width + xoffset > img->width || height + yoffset > img->height)
935 {
936 error(GL_INVALID_VALUE);
937 return false;
938 }
939
940 if (format != getInternalFormat())
941 {
942 error(GL_INVALID_OPERATION);
943 return false;
944 }
945
946 if (!img->surface)
947 {
948 createSurface(img->width, img->height, format, GL_UNSIGNED_BYTE, img);
949 }
950
951 if (pixels != NULL && img->surface != NULL)
952 {
953 RECT updateRegion;
954 updateRegion.left = xoffset;
955 updateRegion.right = xoffset + width;
956 updateRegion.bottom = yoffset + height;
957 updateRegion.top = yoffset;
958
959 D3DLOCKED_RECT locked;
960 HRESULT result = img->surface->LockRect(&locked, &updateRegion, 0);
961
962 ASSERT(SUCCEEDED(result));
963
964 if (SUCCEEDED(result))
965 {
966 int inputPitch = ComputeCompressedPitch(width, format);
967 int inputSize = ComputeCompressedSize(width, height, format);
968 loadCompressedImageData(xoffset, transformPixelYOffset(yoffset, height, img->height), width, height, -inputPitch, static_cast<const char*>(pixels) + inputSize - inputPitch, locked.Pitch, locked.pBits);
969 img->surface->UnlockRect();
970 }
971
972 img->dirty = true;
973 }
974
975 return true;
976}
977
978// This implements glCopyTex[Sub]Image2D for non-renderable internal texture formats
979void Texture::copyNonRenderable(Image *image, GLenum internalFormat, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, IDirect3DSurface9 *renderTarget)
980{
981 IDirect3DDevice9 *device = getDevice();
982 IDirect3DSurface9 *surface = NULL;
983 D3DSURFACE_DESC description;
984 renderTarget->GetDesc(&description);
985
986 HRESULT result = device->CreateOffscreenPlainSurface(description.Width, description.Height, description.Format, D3DPOOL_SYSTEMMEM, &surface, NULL);
987
988 if (!SUCCEEDED(result))
989 {
990 ERR("Could not create matching destination surface.");
991 return error(GL_OUT_OF_MEMORY);
992 }
993
994 result = device->GetRenderTargetData(renderTarget, surface);
995
996 if (!SUCCEEDED(result))
997 {
998 ERR("GetRenderTargetData unexpectedly failed.");
999 surface->Release();
1000 return error(GL_OUT_OF_MEMORY);
1001 }
1002
1003 D3DLOCKED_RECT sourceLock = {0};
1004 RECT sourceRect = transformPixelRect(x, y, width, height, description.Height);
1005 result = surface->LockRect(&sourceLock, &sourceRect, 0);
1006
1007 if (FAILED(result))
1008 {
1009 ERR("Failed to lock the source surface (rectangle might be invalid).");
1010 surface->UnlockRect();
1011 surface->Release();
1012 return error(GL_OUT_OF_MEMORY);
1013 }
1014
1015 if (!image->surface)
1016 {
1017 createSurface(width, height, internalFormat, mType, image);
1018 }
1019
1020 if (image->surface == NULL)
1021 {
1022 ERR("Failed to create an image surface.");
1023 surface->UnlockRect();
1024 surface->Release();
1025 return error(GL_OUT_OF_MEMORY);
1026 }
1027
1028 D3DLOCKED_RECT destLock = {0};
1029 int destYOffset = transformPixelYOffset(yoffset, height, image->height);
1030 RECT destRect = {xoffset, destYOffset, xoffset + width, destYOffset + height};
1031 result = image->surface->LockRect(&destLock, &destRect, 0);
1032
1033 if (FAILED(result))
1034 {
1035 ERR("Failed to lock the destination surface (rectangle might be invalid).");
1036 surface->UnlockRect();
1037 surface->Release();
1038 return error(GL_OUT_OF_MEMORY);
1039 }
1040
1041 if (destLock.pBits && sourceLock.pBits)
1042 {
1043 unsigned char *source = (unsigned char*)sourceLock.pBits;
1044 unsigned char *dest = (unsigned char*)destLock.pBits;
1045
1046 switch (description.Format)
1047 {
1048 case D3DFMT_X8R8G8B8:
1049 case D3DFMT_A8R8G8B8:
1050 switch(getD3DFormat())
1051 {
1052 case D3DFMT_L8:
1053 for(int y = 0; y < height; y++)
1054 {
1055 for(int x = 0; x < width; x++)
1056 {
1057 dest[x] = source[x * 4 + 2];
1058 }
1059
1060 source += sourceLock.Pitch;
1061 dest += destLock.Pitch;
1062 }
1063 break;
1064 case D3DFMT_A8L8:
1065 for(int y = 0; y < height; y++)
1066 {
1067 for(int x = 0; x < width; x++)
1068 {
1069 dest[x * 2 + 0] = source[x * 4 + 2];
1070 dest[x * 2 + 1] = source[x * 4 + 3];
1071 }
1072
1073 source += sourceLock.Pitch;
1074 dest += destLock.Pitch;
1075 }
1076 break;
1077 default:
1078 UNREACHABLE();
1079 }
1080 break;
1081 case D3DFMT_R5G6B5:
1082 switch(getD3DFormat())
1083 {
1084 case D3DFMT_L8:
1085 for(int y = 0; y < height; y++)
1086 {
1087 for(int x = 0; x < width; x++)
1088 {
1089 unsigned char red = source[x * 2 + 1] & 0xF8;
1090 dest[x] = red | (red >> 5);
1091 }
1092
1093 source += sourceLock.Pitch;
1094 dest += destLock.Pitch;
1095 }
1096 break;
1097 default:
1098 UNREACHABLE();
1099 }
1100 break;
1101 case D3DFMT_A1R5G5B5:
1102 switch(getD3DFormat())
1103 {
1104 case D3DFMT_L8:
1105 for(int y = 0; y < height; y++)
1106 {
1107 for(int x = 0; x < width; x++)
1108 {
1109 unsigned char red = source[x * 2 + 1] & 0x7C;
1110 dest[x] = (red << 1) | (red >> 4);
1111 }
1112
1113 source += sourceLock.Pitch;
1114 dest += destLock.Pitch;
1115 }
1116 break;
1117 case D3DFMT_A8L8:
1118 for(int y = 0; y < height; y++)
1119 {
1120 for(int x = 0; x < width; x++)
1121 {
1122 unsigned char red = source[x * 2 + 1] & 0x7C;
1123 dest[x * 2 + 0] = (red << 1) | (red >> 4);
1124 dest[x * 2 + 1] = (signed char)source[x * 2 + 1] >> 7;
1125 }
1126
1127 source += sourceLock.Pitch;
1128 dest += destLock.Pitch;
1129 }
1130 break;
1131 default:
1132 UNREACHABLE();
1133 }
1134 break;
1135 default:
1136 UNREACHABLE();
1137 }
1138
1139 image->dirty = true;
1140 mDirtyMetaData = true;
1141 }
1142
1143 image->surface->UnlockRect();
1144 surface->UnlockRect();
1145 surface->Release();
1146}
1147
1148D3DFORMAT Texture::getD3DFormat() const
1149{
1150 return selectFormat(getInternalFormat(), mType);
1151}
1152
1153IDirect3DBaseTexture9 *Texture::getTexture()
1154{
1155 if (!isComplete())
1156 {
1157 return NULL;
1158 }
1159
1160 if (mDirtyMetaData)
1161 {
1162 mBaseTexture = createTexture();
1163 mIsRenderable = false;
1164 }
1165
1166 if (mDirtyMetaData || dirtyImageData())
1167 {
1168 updateTexture();
1169 }
1170
1171 mDirtyMetaData = false;
1172 ASSERT(!dirtyImageData());
1173
1174 return mBaseTexture;
1175}
1176
1177bool Texture::isDirty() const
1178{
1179 return (mDirty || mDirtyMetaData || dirtyImageData());
1180}
1181
1182// Returns the top-level texture surface as a render target
1183void Texture::needRenderTarget()
1184{
1185 if (!mIsRenderable)
1186 {
1187 mBaseTexture = convertToRenderTarget();
1188 mIsRenderable = true;
1189 }
1190
1191 if (dirtyImageData())
1192 {
1193 updateTexture();
1194 }
1195
1196 mDirtyMetaData = false;
1197}
1198
1199void Texture::dropTexture()
1200{
1201 if (mBaseTexture)
1202 {
1203 mBaseTexture = NULL;
1204 }
1205
1206 mIsRenderable = false;
1207}
1208
1209void Texture::pushTexture(IDirect3DBaseTexture9 *newTexture, bool renderable)
1210{
1211 mBaseTexture = newTexture;
1212 mDirtyMetaData = false;
1213 mIsRenderable = renderable;
1214 mDirty = true;
1215}
1216
1217
1218GLint Texture::creationLevels(GLsizei width, GLsizei height, GLint maxlevel) const
1219{
1220 if (isPow2(width) && isPow2(height))
1221 {
1222 return maxlevel;
1223 }
1224 else
1225 {
1226 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
1227 return 1;
1228 }
1229}
1230
1231GLint Texture::creationLevels(GLsizei size, GLint maxlevel) const
1232{
1233 return creationLevels(size, size, maxlevel);
1234}
1235
1236int Texture::levelCount() const
1237{
1238 return mBaseTexture ? mBaseTexture->GetLevelCount() : 0;
1239}
1240
1241bool Texture::isRenderable() const
1242{
1243 return mIsRenderable;
1244}
1245
1246Texture2D::Texture2D(GLuint id) : Texture(id)
1247{
1248 mTexture = NULL;
1249}
1250
1251Texture2D::~Texture2D()
1252{
1253 mColorbufferProxy.set(NULL);
1254
1255 if (mTexture)
1256 {
1257 mTexture->Release();
1258 mTexture = NULL;
1259 }
1260}
1261
1262GLenum Texture2D::getTarget() const
1263{
1264 return GL_TEXTURE_2D;
1265}
1266
1267GLenum Texture2D::getInternalFormat() const
1268{
1269 return mImageArray[0].format;
1270}
1271
1272// While OpenGL doesn't check texture consistency until draw-time, D3D9 requires a complete texture
1273// for render-to-texture (such as CopyTexImage). We have no way of keeping individual inconsistent levels.
1274// Call this when a particular level of the texture must be defined with a specific format, width and height.
1275//
1276// Returns true if the existing texture was unsuitable and had to be destroyed. If so, it will also set
1277// a new height and width for the texture by working backwards from the given width and height.
1278bool Texture2D::redefineTexture(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum type)
1279{
1280 bool widthOkay = (mWidth >> level == width);
1281 bool heightOkay = (mHeight >> level == height);
1282
1283 bool sizeOkay = ((widthOkay && heightOkay)
1284 || (widthOkay && mHeight >> level == 0 && height == 1)
1285 || (heightOkay && mWidth >> level == 0 && width == 1));
1286
1287 bool typeOkay = (type == mType);
1288
1289 bool textureOkay = (sizeOkay && typeOkay && internalFormat == mImageArray[0].format);
1290
1291 if (!textureOkay)
1292 {
1293 TRACE("Redefining 2D texture (%d, 0x%04X, %d, %d => 0x%04X, %d, %d).", level,
1294 mImageArray[0].format, mWidth, mHeight,
1295 internalFormat, width, height);
1296
1297 // Purge all the levels and the texture.
1298
1299 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1300 {
1301 if (mImageArray[i].surface != NULL)
1302 {
1303 mImageArray[i].dirty = false;
1304
1305 mImageArray[i].surface->Release();
1306 mImageArray[i].surface = NULL;
1307 }
1308 }
1309
1310 if (mTexture != NULL)
1311 {
1312 mTexture->Release();
1313 mTexture = NULL;
1314 dropTexture();
1315 }
1316
1317 mWidth = width << level;
1318 mHeight = height << level;
1319 mImageArray[0].format = internalFormat;
1320 mType = type;
1321 }
1322
1323 return !textureOkay;
1324}
1325
1326void Texture2D::setImage(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1327{
1328 redefineTexture(level, internalFormat, width, height, type);
1329
1330 Texture::setImage(width, height, format, type, unpackAlignment, pixels, &mImageArray[level]);
1331}
1332
1333void Texture2D::setCompressedImage(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
1334{
1335 redefineTexture(level, internalFormat, width, height, GL_UNSIGNED_BYTE);
1336
1337 Texture::setCompressedImage(width, height, internalFormat, imageSize, pixels, &mImageArray[level]);
1338}
1339
1340void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1341{
1342 ASSERT(mImageArray[level].surface != NULL);
1343
1344 if (level < levelCount())
1345 {
1346 IDirect3DSurface9 *destLevel = NULL;
1347 HRESULT result = mTexture->GetSurfaceLevel(level, &destLevel);
1348
1349 ASSERT(SUCCEEDED(result));
1350
1351 if (SUCCEEDED(result))
1352 {
1353 Image *img = &mImageArray[level];
1354
1355 RECT sourceRect = transformPixelRect(xoffset, yoffset, width, height, img->height);;
1356
1357 POINT destPoint;
1358 destPoint.x = sourceRect.left;
1359 destPoint.y = sourceRect.top;
1360
1361 result = getDevice()->UpdateSurface(img->surface, &sourceRect, destLevel, &destPoint);
1362 ASSERT(SUCCEEDED(result));
1363
1364 destLevel->Release();
1365
1366 img->dirty = false;
1367 }
1368 }
1369}
1370
1371void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1372{
1373 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[level]))
1374 {
1375 commitRect(level, xoffset, yoffset, width, height);
1376 }
1377}
1378
1379void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1380{
1381 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[level]))
1382 {
1383 commitRect(level, xoffset, yoffset, width, height);
1384 }
1385}
1386
1387void Texture2D::copyImage(GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1388{
1389 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
1390
1391 if (!renderTarget)
1392 {
1393 ERR("Failed to retrieve the render target.");
1394 return error(GL_OUT_OF_MEMORY);
1395 }
1396
1397 bool redefined = redefineTexture(level, internalFormat, width, height, mType);
1398
1399 if (!isRenderableFormat())
1400 {
1401 copyNonRenderable(&mImageArray[level], internalFormat, 0, 0, x, y, width, height, renderTarget);
1402 }
1403 else
1404 {
1405 if (redefined)
1406 {
1407 convertToRenderTarget();
1408 pushTexture(mTexture, true);
1409 }
1410 else
1411 {
1412 needRenderTarget();
1413 }
1414
1415 if (width != 0 && height != 0 && level < levelCount())
1416 {
1417 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
1418 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
1419 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
1420 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
1421 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
1422
1423 IDirect3DSurface9 *dest;
1424 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
1425
1426 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, internalFormat, 0, 0, dest);
1427 dest->Release();
1428 }
1429 }
1430
1431 mImageArray[level].width = width;
1432 mImageArray[level].height = height;
1433 mImageArray[level].format = internalFormat;
1434}
1435
1436void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1437{
1438 if (xoffset + width > mImageArray[level].width || yoffset + height > mImageArray[level].height)
1439 {
1440 return error(GL_INVALID_VALUE);
1441 }
1442
1443 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
1444
1445 if (!renderTarget)
1446 {
1447 ERR("Failed to retrieve the render target.");
1448 return error(GL_OUT_OF_MEMORY);
1449 }
1450
1451 bool redefined = redefineTexture(0, mImageArray[0].format, mImageArray[0].width, mImageArray[0].height, mType);
1452
1453 if (!isRenderableFormat())
1454 {
1455 copyNonRenderable(&mImageArray[level], getInternalFormat(), xoffset, yoffset, x, y, width, height, renderTarget);
1456 }
1457 else
1458 {
1459 if (redefined)
1460 {
1461 convertToRenderTarget();
1462 pushTexture(mTexture, true);
1463 }
1464 else
1465 {
1466 needRenderTarget();
1467 }
1468
1469 if (level < levelCount())
1470 {
1471 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
1472 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
1473 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
1474 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
1475 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
1476
1477 GLint destYOffset = transformPixelYOffset(yoffset, height, mImageArray[level].height);
1478
1479 IDirect3DSurface9 *dest;
1480 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
1481
1482 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0].format, xoffset, destYOffset, dest);
1483 dest->Release();
1484 }
1485 }
1486}
1487
1488// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1489bool Texture2D::isComplete() const
1490{
1491 GLsizei width = mImageArray[0].width;
1492 GLsizei height = mImageArray[0].height;
1493
1494 if (width <= 0 || height <= 0)
1495 {
1496 return false;
1497 }
1498
1499 bool mipmapping = false;
1500
1501 switch (mMinFilter)
1502 {
1503 case GL_NEAREST:
1504 case GL_LINEAR:
1505 mipmapping = false;
1506 break;
1507 case GL_NEAREST_MIPMAP_NEAREST:
1508 case GL_LINEAR_MIPMAP_NEAREST:
1509 case GL_NEAREST_MIPMAP_LINEAR:
1510 case GL_LINEAR_MIPMAP_LINEAR:
1511 mipmapping = true;
1512 break;
1513 default: UNREACHABLE();
1514 }
1515
1516 if ((getInternalFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) ||
1517 (getInternalFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter()))
1518 {
1519 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
1520 {
1521 return false;
1522 }
1523 }
1524
1525
1526 if ((getWrapS() != GL_CLAMP_TO_EDGE && !isPow2(width))
1527 || (getWrapT() != GL_CLAMP_TO_EDGE && !isPow2(height)))
1528 {
1529 return false;
1530 }
1531
1532 if (mipmapping)
1533 {
1534 if (!isPow2(width) || !isPow2(height))
1535 {
1536 return false;
1537 }
1538
1539 int q = log2(std::max(width, height));
1540
1541 for (int level = 1; level <= q; level++)
1542 {
1543 if (mImageArray[level].format != mImageArray[0].format)
1544 {
1545 return false;
1546 }
1547
1548 if (mImageArray[level].width != std::max(1, width >> level))
1549 {
1550 return false;
1551 }
1552
1553 if (mImageArray[level].height != std::max(1, height >> level))
1554 {
1555 return false;
1556 }
1557 }
1558 }
1559
1560 return true;
1561}
1562
1563bool Texture2D::isCompressed() const
1564{
1565 return IsCompressed(getInternalFormat());
1566}
1567
1568// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
1569IDirect3DBaseTexture9 *Texture2D::createTexture()
1570{
1571 IDirect3DTexture9 *texture;
1572
1573 IDirect3DDevice9 *device = getDevice();
1574 D3DFORMAT format = selectFormat(mImageArray[0].format, mType);
1575
1576 HRESULT result = device->CreateTexture(mWidth, mHeight, creationLevels(mWidth, mHeight, 0), 0, format, D3DPOOL_DEFAULT, &texture, NULL);
1577
1578 if (FAILED(result))
1579 {
1580 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1581 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1582 }
1583
1584 if (mTexture) mTexture->Release();
1585 mTexture = texture;
1586 return texture;
1587}
1588
1589void Texture2D::updateTexture()
1590{
1591 IDirect3DDevice9 *device = getDevice();
1592
1593 int levels = levelCount();
1594
1595 for (int level = 0; level < levels; level++)
1596 {
1597 if (mImageArray[level].dirty)
1598 {
1599 IDirect3DSurface9 *levelSurface = NULL;
1600 HRESULT result = mTexture->GetSurfaceLevel(level, &levelSurface);
1601
1602 ASSERT(SUCCEEDED(result));
1603
1604 if (SUCCEEDED(result))
1605 {
1606 result = device->UpdateSurface(mImageArray[level].surface, NULL, levelSurface, NULL);
1607 ASSERT(SUCCEEDED(result));
1608
1609 levelSurface->Release();
1610
1611 mImageArray[level].dirty = false;
1612 }
1613 }
1614 }
1615}
1616
1617IDirect3DBaseTexture9 *Texture2D::convertToRenderTarget()
1618{
1619 IDirect3DTexture9 *texture = NULL;
1620
1621 if (mWidth != 0 && mHeight != 0)
1622 {
1623 egl::Display *display = getDisplay();
1624 IDirect3DDevice9 *device = getDevice();
1625 D3DFORMAT format = selectFormat(mImageArray[0].format, mType);
1626
1627 HRESULT result = device->CreateTexture(mWidth, mHeight, creationLevels(mWidth, mHeight, 0), D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL);
1628
1629 if (FAILED(result))
1630 {
1631 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1632 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1633 }
1634
1635 if (mTexture != NULL)
1636 {
1637 int levels = levelCount();
1638 for (int i = 0; i < levels; i++)
1639 {
1640 IDirect3DSurface9 *source;
1641 result = mTexture->GetSurfaceLevel(i, &source);
1642
1643 if (FAILED(result))
1644 {
1645 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1646
1647 texture->Release();
1648
1649 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1650 }
1651
1652 IDirect3DSurface9 *dest;
1653 result = texture->GetSurfaceLevel(i, &dest);
1654
1655 if (FAILED(result))
1656 {
1657 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1658
1659 texture->Release();
1660 source->Release();
1661
1662 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1663 }
1664
1665 display->endScene();
1666 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
1667
1668 if (FAILED(result))
1669 {
1670 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1671
1672 texture->Release();
1673 source->Release();
1674 dest->Release();
1675
1676 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1677 }
1678
1679 source->Release();
1680 dest->Release();
1681 }
1682 }
1683 }
1684
1685 if (mTexture != NULL)
1686 {
1687 mTexture->Release();
1688 }
1689
1690 mTexture = texture;
1691 return mTexture;
1692}
1693
1694bool Texture2D::dirtyImageData() const
1695{
1696 int q = log2(std::max(mWidth, mHeight));
1697
1698 for (int i = 0; i <= q; i++)
1699 {
1700 if (mImageArray[i].dirty) return true;
1701 }
1702
1703 return false;
1704}
1705
1706void Texture2D::generateMipmaps()
1707{
1708 if (!isPow2(mImageArray[0].width) || !isPow2(mImageArray[0].height))
1709 {
1710 return error(GL_INVALID_OPERATION);
1711 }
1712
1713 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1714 unsigned int q = log2(std::max(mWidth, mHeight));
1715 for (unsigned int i = 1; i <= q; i++)
1716 {
1717 if (mImageArray[i].surface != NULL)
1718 {
1719 mImageArray[i].surface->Release();
1720 mImageArray[i].surface = NULL;
1721 }
1722
1723 mImageArray[i].dirty = false;
1724
1725 mImageArray[i].format = mImageArray[0].format;
1726 mImageArray[i].width = std::max(mImageArray[0].width >> i, 1);
1727 mImageArray[i].height = std::max(mImageArray[0].height >> i, 1);
1728 }
1729
1730 if (isRenderable())
1731 {
1732 if (mTexture == NULL)
1733 {
1734 ERR(" failed because mTexture was null.");
1735 return;
1736 }
1737
1738 for (unsigned int i = 1; i <= q; i++)
1739 {
1740 IDirect3DSurface9 *upper = NULL;
1741 IDirect3DSurface9 *lower = NULL;
1742
1743 mTexture->GetSurfaceLevel(i-1, &upper);
1744 mTexture->GetSurfaceLevel(i, &lower);
1745
1746 if (upper != NULL && lower != NULL)
1747 {
1748 getBlitter()->boxFilter(upper, lower);
1749 }
1750
1751 if (upper != NULL) upper->Release();
1752 if (lower != NULL) lower->Release();
1753 }
1754 }
1755 else
1756 {
1757 for (unsigned int i = 1; i <= q; i++)
1758 {
1759 createSurface(mImageArray[i].width, mImageArray[i].height, mImageArray[i].format, mType, &mImageArray[i]);
1760 if (mImageArray[i].surface == NULL)
1761 {
1762 return error(GL_OUT_OF_MEMORY);
1763 }
1764
1765 if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[i].surface, NULL, NULL, mImageArray[i - 1].surface, NULL, NULL, D3DX_FILTER_BOX, 0)))
1766 {
1767 ERR(" failed to load filter %d to %d.", i - 1, i);
1768 }
1769
1770 mImageArray[i].dirty = true;
1771 }
1772
1773 mDirtyMetaData = true;
1774 }
1775}
1776
1777Renderbuffer *Texture2D::getRenderbuffer(GLenum target)
1778{
1779 if (target != GL_TEXTURE_2D)
1780 {
1781 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
1782 }
1783
1784 if (mColorbufferProxy.get() == NULL)
1785 {
1786 mColorbufferProxy.set(new Renderbuffer(id(), new Colorbuffer(this, target)));
1787 }
1788
1789 return mColorbufferProxy.get();
1790}
1791
1792IDirect3DSurface9 *Texture2D::getRenderTarget(GLenum target)
1793{
1794 ASSERT(target == GL_TEXTURE_2D);
1795
1796 needRenderTarget();
1797
1798 if (mTexture == NULL)
1799 {
1800 return NULL;
1801 }
1802
1803 IDirect3DSurface9 *renderTarget = NULL;
1804 mTexture->GetSurfaceLevel(0, &renderTarget);
1805
1806 return renderTarget;
1807}
1808
1809TextureCubeMap::TextureCubeMap(GLuint id) : Texture(id)
1810{
1811 mTexture = NULL;
1812}
1813
1814TextureCubeMap::~TextureCubeMap()
1815{
1816 for (int i = 0; i < 6; i++)
1817 {
1818 mFaceProxies[i].set(NULL);
1819 }
1820
1821 if (mTexture)
1822 {
1823 mTexture->Release();
1824 mTexture = NULL;
1825 }
1826}
1827
1828GLenum TextureCubeMap::getTarget() const
1829{
1830 return GL_TEXTURE_CUBE_MAP;
1831}
1832
1833GLenum TextureCubeMap::getInternalFormat() const
1834{
1835 return mImageArray[0][0].format;
1836}
1837
1838void TextureCubeMap::setImagePosX(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1839{
1840 setImage(0, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
1841}
1842
1843void TextureCubeMap::setImageNegX(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1844{
1845 setImage(1, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
1846}
1847
1848void TextureCubeMap::setImagePosY(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1849{
1850 setImage(2, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
1851}
1852
1853void TextureCubeMap::setImageNegY(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1854{
1855 setImage(3, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
1856}
1857
1858void TextureCubeMap::setImagePosZ(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1859{
1860 setImage(4, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
1861}
1862
1863void TextureCubeMap::setImageNegZ(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1864{
1865 setImage(5, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
1866}
1867
1868void TextureCubeMap::setCompressedImage(GLenum face, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
1869{
1870 redefineTexture(level, internalFormat, width);
1871
1872 Texture::setCompressedImage(width, height, internalFormat, imageSize, pixels, &mImageArray[faceIndex(face)][level]);
1873}
1874
1875void TextureCubeMap::commitRect(GLenum faceTarget, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1876{
1877 int face = faceIndex(faceTarget);
1878 ASSERT(mImageArray[face][level].surface != NULL);
1879
1880 if (level < levelCount())
1881 {
1882 IDirect3DSurface9 *destLevel = getCubeMapSurface(faceTarget, level);
1883 ASSERT(destLevel != NULL);
1884
1885 if (destLevel != NULL)
1886 {
1887 Image *img = &mImageArray[face][level];
1888
1889 RECT sourceRect = transformPixelRect(xoffset, yoffset, width, height, img->height);;
1890
1891 POINT destPoint;
1892 destPoint.x = sourceRect.left;
1893 destPoint.y = sourceRect.top;
1894
1895 HRESULT result = getDevice()->UpdateSurface(img->surface, &sourceRect, destLevel, &destPoint);
1896 ASSERT(SUCCEEDED(result));
1897
1898 destLevel->Release();
1899
1900 img->dirty = false;
1901 }
1902 }
1903}
1904
1905void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1906{
1907 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[faceIndex(target)][level]))
1908 {
1909 commitRect(target, level, xoffset, yoffset, width, height);
1910 }
1911}
1912
1913void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1914{
1915 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[faceIndex(target)][level]))
1916 {
1917 commitRect(target, level, xoffset, yoffset, width, height);
1918 }
1919}
1920
1921// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1922bool TextureCubeMap::isComplete() const
1923{
1924 int size = mImageArray[0][0].width;
1925
1926 if (size <= 0)
1927 {
1928 return false;
1929 }
1930
1931 bool mipmapping;
1932
1933 switch (mMinFilter)
1934 {
1935 case GL_NEAREST:
1936 case GL_LINEAR:
1937 mipmapping = false;
1938 break;
1939 case GL_NEAREST_MIPMAP_NEAREST:
1940 case GL_LINEAR_MIPMAP_NEAREST:
1941 case GL_NEAREST_MIPMAP_LINEAR:
1942 case GL_LINEAR_MIPMAP_LINEAR:
1943 mipmapping = true;
1944 break;
1945 default: UNREACHABLE();
1946 }
1947
1948 for (int face = 0; face < 6; face++)
1949 {
1950 if (mImageArray[face][0].width != size || mImageArray[face][0].height != size)
1951 {
1952 return false;
1953 }
1954 }
1955
1956 if ((getInternalFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) ||
1957 (getInternalFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter()))
1958 {
1959 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
1960 {
1961 return false;
1962 }
1963 }
1964
1965 if (mipmapping)
1966 {
1967 if (!isPow2(size) && (getWrapS() != GL_CLAMP_TO_EDGE || getWrapT() != GL_CLAMP_TO_EDGE))
1968 {
1969 return false;
1970 }
1971
1972 int q = log2(size);
1973
1974 for (int face = 0; face < 6; face++)
1975 {
1976 for (int level = 1; level <= q; level++)
1977 {
1978 if (mImageArray[face][level].format != mImageArray[0][0].format)
1979 {
1980 return false;
1981 }
1982
1983 if (mImageArray[face][level].width != std::max(1, size >> level))
1984 {
1985 return false;
1986 }
1987
1988 ASSERT(mImageArray[face][level].height == mImageArray[face][level].width);
1989 }
1990 }
1991 }
1992
1993 return true;
1994}
1995
1996bool TextureCubeMap::isCompressed() const
1997{
1998 return IsCompressed(getInternalFormat());
1999}
2000
2001// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
2002IDirect3DBaseTexture9 *TextureCubeMap::createTexture()
2003{
2004 IDirect3DDevice9 *device = getDevice();
2005 D3DFORMAT format = selectFormat(mImageArray[0][0].format, mType);
2006
2007 IDirect3DCubeTexture9 *texture;
2008
2009 HRESULT result = device->CreateCubeTexture(mWidth, creationLevels(mWidth, 0), 0, format, D3DPOOL_DEFAULT, &texture, NULL);
2010
2011 if (FAILED(result))
2012 {
2013 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2014 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
2015 }
2016
2017 if (mTexture) mTexture->Release();
2018
2019 mTexture = texture;
2020 return mTexture;
2021}
2022
2023void TextureCubeMap::updateTexture()
2024{
2025 IDirect3DDevice9 *device = getDevice();
2026
2027 for (int face = 0; face < 6; face++)
2028 {
2029 int levels = levelCount();
2030 for (int level = 0; level < levels; level++)
2031 {
2032 Image *img = &mImageArray[face][level];
2033
2034 if (img->dirty)
2035 {
2036 IDirect3DSurface9 *levelSurface = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level);
2037 ASSERT(levelSurface != NULL);
2038
2039 if (levelSurface != NULL)
2040 {
2041 HRESULT result = device->UpdateSurface(img->surface, NULL, levelSurface, NULL);
2042 ASSERT(SUCCEEDED(result));
2043
2044 levelSurface->Release();
2045
2046 img->dirty = false;
2047 }
2048 }
2049 }
2050 }
2051}
2052
2053IDirect3DBaseTexture9 *TextureCubeMap::convertToRenderTarget()
2054{
2055 IDirect3DCubeTexture9 *texture = NULL;
2056
2057 if (mWidth != 0)
2058 {
2059 egl::Display *display = getDisplay();
2060 IDirect3DDevice9 *device = getDevice();
2061 D3DFORMAT format = selectFormat(mImageArray[0][0].format, mType);
2062
2063 HRESULT result = device->CreateCubeTexture(mWidth, creationLevels(mWidth, 0), D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL);
2064
2065 if (FAILED(result))
2066 {
2067 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2068 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
2069 }
2070
2071 if (mTexture != NULL)
2072 {
2073 int levels = levelCount();
2074 for (int f = 0; f < 6; f++)
2075 {
2076 for (int i = 0; i < levels; i++)
2077 {
2078 IDirect3DSurface9 *source;
2079 result = mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &source);
2080
2081 if (FAILED(result))
2082 {
2083 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2084
2085 texture->Release();
2086
2087 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
2088 }
2089
2090 IDirect3DSurface9 *dest;
2091 result = texture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &dest);
2092
2093 if (FAILED(result))
2094 {
2095 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2096
2097 texture->Release();
2098 source->Release();
2099
2100 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
2101 }
2102
2103 display->endScene();
2104 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
2105
2106 if (FAILED(result))
2107 {
2108 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2109
2110 texture->Release();
2111 source->Release();
2112 dest->Release();
2113
2114 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
2115 }
2116 }
2117 }
2118 }
2119 }
2120
2121 if (mTexture != NULL)
2122 {
2123 mTexture->Release();
2124 }
2125
2126 mTexture = texture;
2127 return mTexture;
2128}
2129
2130void TextureCubeMap::setImage(int face, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
2131{
2132 redefineTexture(level, internalFormat, width);
2133
2134 Texture::setImage(width, height, format, type, unpackAlignment, pixels, &mImageArray[face][level]);
2135}
2136
2137unsigned int TextureCubeMap::faceIndex(GLenum face)
2138{
2139 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
2140 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
2141 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
2142 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
2143 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
2144
2145 return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
2146}
2147
2148bool TextureCubeMap::dirtyImageData() const
2149{
2150 int q = log2(mWidth);
2151
2152 for (int f = 0; f < 6; f++)
2153 {
2154 for (int i = 0; i <= q; i++)
2155 {
2156 if (mImageArray[f][i].dirty) return true;
2157 }
2158 }
2159
2160 return false;
2161}
2162
2163// While OpenGL doesn't check texture consistency until draw-time, D3D9 requires a complete texture
2164// for render-to-texture (such as CopyTexImage). We have no way of keeping individual inconsistent levels & faces.
2165// Call this when a particular level of the texture must be defined with a specific format, width and height.
2166//
2167// Returns true if the existing texture was unsuitable had to be destroyed. If so, it will also set
2168// a new size for the texture by working backwards from the given size.
2169bool TextureCubeMap::redefineTexture(GLint level, GLenum internalFormat, GLsizei width)
2170{
2171 // Are these settings compatible with level 0?
2172 bool sizeOkay = (mImageArray[0][0].width >> level == width);
2173
2174 bool textureOkay = (sizeOkay && internalFormat == mImageArray[0][0].format);
2175
2176 if (!textureOkay)
2177 {
2178 TRACE("Redefining cube texture (%d, 0x%04X, %d => 0x%04X, %d).", level,
2179 mImageArray[0][0].format, mImageArray[0][0].width,
2180 internalFormat, width);
2181
2182 // Purge all the levels and the texture.
2183 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
2184 {
2185 for (int f = 0; f < 6; f++)
2186 {
2187 if (mImageArray[f][i].surface != NULL)
2188 {
2189 mImageArray[f][i].dirty = false;
2190
2191 mImageArray[f][i].surface->Release();
2192 mImageArray[f][i].surface = NULL;
2193 }
2194 }
2195 }
2196
2197 if (mTexture != NULL)
2198 {
2199 mTexture->Release();
2200 mTexture = NULL;
2201 dropTexture();
2202 }
2203
2204 mWidth = width << level;
2205 mImageArray[0][0].width = width << level;
2206 mHeight = width << level;
2207 mImageArray[0][0].height = width << level;
2208
2209 mImageArray[0][0].format = internalFormat;
2210 }
2211
2212 return !textureOkay;
2213}
2214
2215void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
2216{
2217 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
2218
2219 if (!renderTarget)
2220 {
2221 ERR("Failed to retrieve the render target.");
2222 return error(GL_OUT_OF_MEMORY);
2223 }
2224
2225 unsigned int faceindex = faceIndex(target);
2226 bool redefined = redefineTexture(level, internalFormat, width);
2227
2228 if (!isRenderableFormat())
2229 {
2230 copyNonRenderable(&mImageArray[faceindex][level], internalFormat, 0, 0, x, y, width, height, renderTarget);
2231 }
2232 else
2233 {
2234 if (redefined)
2235 {
2236 convertToRenderTarget();
2237 pushTexture(mTexture, true);
2238 }
2239 else
2240 {
2241 needRenderTarget();
2242 }
2243
2244 ASSERT(width == height);
2245
2246 if (width > 0 && level < levelCount())
2247 {
2248 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
2249 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
2250 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
2251 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
2252 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
2253
2254 IDirect3DSurface9 *dest = getCubeMapSurface(target, level);
2255
2256 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, internalFormat, 0, 0, dest);
2257 dest->Release();
2258 }
2259 }
2260
2261 mImageArray[faceindex][level].width = width;
2262 mImageArray[faceindex][level].height = height;
2263 mImageArray[faceindex][level].format = internalFormat;
2264}
2265
2266IDirect3DSurface9 *TextureCubeMap::getCubeMapSurface(GLenum face, unsigned int level)
2267{
2268 if (mTexture == NULL)
2269 {
2270 UNREACHABLE();
2271 return NULL;
2272 }
2273
2274 IDirect3DSurface9 *surface = NULL;
2275
2276 HRESULT hr = mTexture->GetCubeMapSurface(es2dx::ConvertCubeFace(face), level, &surface);
2277
2278 return (SUCCEEDED(hr)) ? surface : NULL;
2279}
2280
2281void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
2282{
2283 GLsizei size = mImageArray[faceIndex(target)][level].width;
2284
2285 if (xoffset + width > size || yoffset + height > size)
2286 {
2287 return error(GL_INVALID_VALUE);
2288 }
2289
2290 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
2291
2292 if (!renderTarget)
2293 {
2294 ERR("Failed to retrieve the render target.");
2295 return error(GL_OUT_OF_MEMORY);
2296 }
2297
2298 unsigned int faceindex = faceIndex(target);
2299 bool redefined = redefineTexture(0, mImageArray[0][0].format, mImageArray[0][0].width);
2300
2301 if (!isRenderableFormat())
2302 {
2303 copyNonRenderable(&mImageArray[faceindex][level], getInternalFormat(), 0, 0, x, y, width, height, renderTarget);
2304 }
2305 else
2306 {
2307 if (redefined)
2308 {
2309 convertToRenderTarget();
2310 pushTexture(mTexture, true);
2311 }
2312 else
2313 {
2314 needRenderTarget();
2315 }
2316
2317 if (level < levelCount())
2318 {
2319 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
2320 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
2321 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
2322 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
2323 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
2324
2325 GLint destYOffset = transformPixelYOffset(yoffset, height, mImageArray[faceindex][level].width);
2326
2327 IDirect3DSurface9 *dest = getCubeMapSurface(target, level);
2328
2329 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0][0].format, xoffset, destYOffset, dest);
2330 dest->Release();
2331 }
2332 }
2333}
2334
2335bool TextureCubeMap::isCubeComplete() const
2336{
2337 if (mImageArray[0][0].width == 0)
2338 {
2339 return false;
2340 }
2341
2342 for (unsigned int f = 1; f < 6; f++)
2343 {
2344 if (mImageArray[f][0].width != mImageArray[0][0].width
2345 || mImageArray[f][0].format != mImageArray[0][0].format)
2346 {
2347 return false;
2348 }
2349 }
2350
2351 return true;
2352}
2353
2354void TextureCubeMap::generateMipmaps()
2355{
2356 if (!isPow2(mImageArray[0][0].width) || !isCubeComplete())
2357 {
2358 return error(GL_INVALID_OPERATION);
2359 }
2360
2361 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
2362 unsigned int q = log2(mImageArray[0][0].width);
2363 for (unsigned int f = 0; f < 6; f++)
2364 {
2365 for (unsigned int i = 1; i <= q; i++)
2366 {
2367 if (mImageArray[f][i].surface != NULL)
2368 {
2369 mImageArray[f][i].surface->Release();
2370 mImageArray[f][i].surface = NULL;
2371 }
2372
2373 mImageArray[f][i].dirty = false;
2374
2375 mImageArray[f][i].format = mImageArray[f][0].format;
2376 mImageArray[f][i].width = std::max(mImageArray[f][0].width >> i, 1);
2377 mImageArray[f][i].height = mImageArray[f][i].width;
2378 }
2379 }
2380
2381 if (isRenderable())
2382 {
2383 if (mTexture == NULL)
2384 {
2385 return;
2386 }
2387
2388 for (unsigned int f = 0; f < 6; f++)
2389 {
2390 for (unsigned int i = 1; i <= q; i++)
2391 {
2392 IDirect3DSurface9 *upper = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i-1);
2393 IDirect3DSurface9 *lower = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i);
2394
2395 if (upper != NULL && lower != NULL)
2396 {
2397 getBlitter()->boxFilter(upper, lower);
2398 }
2399
2400 if (upper != NULL) upper->Release();
2401 if (lower != NULL) lower->Release();
2402 }
2403 }
2404 }
2405 else
2406 {
2407 for (unsigned int f = 0; f < 6; f++)
2408 {
2409 for (unsigned int i = 1; i <= q; i++)
2410 {
2411 createSurface(mImageArray[f][i].width, mImageArray[f][i].height, mImageArray[f][i].format, mType, &mImageArray[f][i]);
2412 if (mImageArray[f][i].surface == NULL)
2413 {
2414 return error(GL_OUT_OF_MEMORY);
2415 }
2416
2417 if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[f][i].surface, NULL, NULL, mImageArray[f][i - 1].surface, NULL, NULL, D3DX_FILTER_BOX, 0)))
2418 {
2419 ERR(" failed to load filter %d to %d.", i - 1, i);
2420 }
2421
2422 mImageArray[f][i].dirty = true;
2423 }
2424 }
2425
2426 mDirtyMetaData = true;
2427 }
2428}
2429
2430Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target)
2431{
2432 if (!IsCubemapTextureTarget(target))
2433 {
2434 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
2435 }
2436
2437 unsigned int face = faceIndex(target);
2438
2439 if (mFaceProxies[face].get() == NULL)
2440 {
2441 mFaceProxies[face].set(new Renderbuffer(id(), new Colorbuffer(this, target)));
2442 }
2443
2444 return mFaceProxies[face].get();
2445}
2446
2447IDirect3DSurface9 *TextureCubeMap::getRenderTarget(GLenum target)
2448{
2449 ASSERT(IsCubemapTextureTarget(target));
2450
2451 needRenderTarget();
2452
2453 if (mTexture == NULL)
2454 {
2455 return NULL;
2456 }
2457
2458 IDirect3DSurface9 *renderTarget = NULL;
2459 mTexture->GetCubeMapSurface(es2dx::ConvertCubeFace(target), 0, &renderTarget);
2460
2461 return renderTarget;
2462}
2463
2464}