blob: 38149e17b7baac99a56e11616e9e828122551432 [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{
daniel@transgaming.coma9eb5da2011-03-21 16:39:16 +000027unsigned int Texture::mCurrentSerial = 1;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +000028
29Texture::Image::Image()
daniel@transgaming.comc50edcb2011-03-21 16:38:40 +000030 : width(0), height(0), dirty(false), surface(NULL), format(GL_NONE), type(GL_UNSIGNED_BYTE)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +000031{
32}
33
34Texture::Image::~Image()
35{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +000036 if (surface)
37 {
38 surface->Release();
39 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +000040}
41
daniel@transgaming.coma9eb5da2011-03-21 16:39:16 +000042Texture::Texture(GLuint id) : RefCountObject(id), mSerial(issueSerial())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +000043{
44 mMinFilter = GL_NEAREST_MIPMAP_LINEAR;
45 mMagFilter = GL_LINEAR;
46 mWrapS = GL_REPEAT;
47 mWrapT = GL_REPEAT;
daniel@transgaming.com38e76e52011-03-21 16:39:10 +000048 mDirty = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +000049
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +000050 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +000051}
52
53Texture::~Texture()
54{
55}
56
57Blit *Texture::getBlitter()
58{
59 Context *context = getContext();
60 return context->getBlitter();
61}
62
63// Returns true on successful filter state update (valid enum parameter)
64bool Texture::setMinFilter(GLenum filter)
65{
66 switch (filter)
67 {
68 case GL_NEAREST:
69 case GL_LINEAR:
70 case GL_NEAREST_MIPMAP_NEAREST:
71 case GL_LINEAR_MIPMAP_NEAREST:
72 case GL_NEAREST_MIPMAP_LINEAR:
73 case GL_LINEAR_MIPMAP_LINEAR:
74 {
75 if (mMinFilter != filter)
76 {
77 mMinFilter = filter;
daniel@transgaming.com38e76e52011-03-21 16:39:10 +000078 mDirty = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +000079 }
80 return true;
81 }
82 default:
83 return false;
84 }
85}
86
87// Returns true on successful filter state update (valid enum parameter)
88bool Texture::setMagFilter(GLenum filter)
89{
90 switch (filter)
91 {
92 case GL_NEAREST:
93 case GL_LINEAR:
94 {
95 if (mMagFilter != filter)
96 {
97 mMagFilter = filter;
daniel@transgaming.com38e76e52011-03-21 16:39:10 +000098 mDirty = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +000099 }
100 return true;
101 }
102 default:
103 return false;
104 }
105}
106
107// Returns true on successful wrap state update (valid enum parameter)
108bool Texture::setWrapS(GLenum wrap)
109{
110 switch (wrap)
111 {
112 case GL_REPEAT:
113 case GL_CLAMP_TO_EDGE:
114 case GL_MIRRORED_REPEAT:
115 {
116 if (mWrapS != wrap)
117 {
118 mWrapS = wrap;
daniel@transgaming.com38e76e52011-03-21 16:39:10 +0000119 mDirty = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000120 }
121 return true;
122 }
123 default:
124 return false;
125 }
126}
127
128// Returns true on successful wrap state update (valid enum parameter)
129bool Texture::setWrapT(GLenum wrap)
130{
131 switch (wrap)
132 {
133 case GL_REPEAT:
134 case GL_CLAMP_TO_EDGE:
135 case GL_MIRRORED_REPEAT:
136 {
137 if (mWrapT != wrap)
138 {
139 mWrapT = wrap;
daniel@transgaming.com38e76e52011-03-21 16:39:10 +0000140 mDirty = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000141 }
142 return true;
143 }
144 default:
145 return false;
146 }
147}
148
149GLenum Texture::getMinFilter() const
150{
151 return mMinFilter;
152}
153
154GLenum Texture::getMagFilter() const
155{
156 return mMagFilter;
157}
158
159GLenum Texture::getWrapS() const
160{
161 return mWrapS;
162}
163
164GLenum Texture::getWrapT() const
165{
166 return mWrapT;
167}
168
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000169bool Texture::isRenderableFormat() const
170{
171 D3DFORMAT format = getD3DFormat();
172
173 switch(format)
174 {
175 case D3DFMT_L8:
176 case D3DFMT_A8L8:
177 case D3DFMT_DXT1:
178 return false;
179 case D3DFMT_A8R8G8B8:
180 case D3DFMT_X8R8G8B8:
181 case D3DFMT_A16B16G16R16F:
182 case D3DFMT_A32B32G32R32F:
183 return true;
184 default:
185 UNREACHABLE();
186 }
187
188 return false;
189}
190
191// Selects an internal Direct3D 9 format for storing an Image
192D3DFORMAT Texture::selectFormat(GLenum format, GLenum type)
193{
194 if (format == GL_COMPRESSED_RGB_S3TC_DXT1_EXT ||
195 format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT)
196 {
197 return D3DFMT_DXT1;
198 }
199 else if (type == GL_FLOAT)
200 {
201 return D3DFMT_A32B32G32R32F;
202 }
203 else if (type == GL_HALF_FLOAT_OES)
204 {
205 return D3DFMT_A16B16G16R16F;
206 }
207 else if (type == GL_UNSIGNED_BYTE)
208 {
209 if (format == GL_LUMINANCE && getContext()->supportsLuminanceTextures())
210 {
211 return D3DFMT_L8;
212 }
213 else if (format == GL_LUMINANCE_ALPHA && getContext()->supportsLuminanceAlphaTextures())
214 {
215 return D3DFMT_A8L8;
216 }
217 else if (format == GL_RGB)
218 {
219 return D3DFMT_X8R8G8B8;
220 }
221
222 return D3DFMT_A8R8G8B8;
223 }
224
225 return D3DFMT_A8R8G8B8;
226}
227
228// Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input
229// into the target pixel rectangle at output with outputPitch bytes in between each line.
230void Texture::loadImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type,
231 GLint unpackAlignment, const void *input, size_t outputPitch, void *output, D3DSURFACE_DESC *description) const
232{
233 GLsizei inputPitch = -ComputePitch(width, format, type, unpackAlignment);
234 input = ((char*)input) - inputPitch * (height - 1);
235
236 switch (type)
237 {
238 case GL_UNSIGNED_BYTE:
239 switch (format)
240 {
241 case GL_ALPHA:
242 loadAlphaImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
243 break;
244 case GL_LUMINANCE:
245 loadLuminanceImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output, description->Format == D3DFMT_L8);
246 break;
247 case GL_LUMINANCE_ALPHA:
248 loadLuminanceAlphaImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output, description->Format == D3DFMT_A8L8);
249 break;
250 case GL_RGB:
251 loadRGBUByteImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
252 break;
253 case GL_RGBA:
254 loadRGBAUByteImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
255 break;
256 case GL_BGRA_EXT:
257 loadBGRAImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
258 break;
259 default: UNREACHABLE();
260 }
261 break;
262 case GL_UNSIGNED_SHORT_5_6_5:
263 switch (format)
264 {
265 case GL_RGB:
266 loadRGB565ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
267 break;
268 default: UNREACHABLE();
269 }
270 break;
271 case GL_UNSIGNED_SHORT_4_4_4_4:
272 switch (format)
273 {
274 case GL_RGBA:
275 loadRGBA4444ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
276 break;
277 default: UNREACHABLE();
278 }
279 break;
280 case GL_UNSIGNED_SHORT_5_5_5_1:
281 switch (format)
282 {
283 case GL_RGBA:
284 loadRGBA5551ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
285 break;
286 default: UNREACHABLE();
287 }
288 break;
289 case GL_FLOAT:
290 switch (format)
291 {
292 // float textures are converted to RGBA, not BGRA, as they're stored that way in D3D
293 case GL_ALPHA:
294 loadAlphaFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
295 break;
296 case GL_LUMINANCE:
297 loadLuminanceFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
298 break;
299 case GL_LUMINANCE_ALPHA:
300 loadLuminanceAlphaFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
301 break;
302 case GL_RGB:
303 loadRGBFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
304 break;
305 case GL_RGBA:
306 loadRGBAFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
307 break;
308 default: UNREACHABLE();
309 }
310 break;
311 case GL_HALF_FLOAT_OES:
312 switch (format)
313 {
314 // float textures are converted to RGBA, not BGRA, as they're stored that way in D3D
315 case GL_ALPHA:
316 loadAlphaHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
317 break;
318 case GL_LUMINANCE:
319 loadLuminanceHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
320 break;
321 case GL_LUMINANCE_ALPHA:
322 loadLuminanceAlphaHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
323 break;
324 case GL_RGB:
325 loadRGBHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
326 break;
327 case GL_RGBA:
328 loadRGBAHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
329 break;
330 default: UNREACHABLE();
331 }
332 break;
333 default: UNREACHABLE();
334 }
335}
336
337void Texture::loadAlphaImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
338 int inputPitch, const void *input, size_t outputPitch, void *output) const
339{
340 const unsigned char *source = NULL;
341 unsigned char *dest = NULL;
342
343 for (int y = 0; y < height; y++)
344 {
345 source = static_cast<const unsigned char*>(input) + y * inputPitch;
346 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
347 for (int x = 0; x < width; x++)
348 {
349 dest[4 * x + 0] = 0;
350 dest[4 * x + 1] = 0;
351 dest[4 * x + 2] = 0;
352 dest[4 * x + 3] = source[x];
353 }
354 }
355}
356
357void Texture::loadAlphaFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
358 int inputPitch, const void *input, size_t outputPitch, void *output) const
359{
360 const float *source = NULL;
361 float *dest = NULL;
362
363 for (int y = 0; y < height; y++)
364 {
365 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
366 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
367 for (int x = 0; x < width; x++)
368 {
369 dest[4 * x + 0] = 0;
370 dest[4 * x + 1] = 0;
371 dest[4 * x + 2] = 0;
372 dest[4 * x + 3] = source[x];
373 }
374 }
375}
376
377void Texture::loadAlphaHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
378 int inputPitch, const void *input, size_t outputPitch, void *output) const
379{
380 const unsigned short *source = NULL;
381 unsigned short *dest = NULL;
382
383 for (int y = 0; y < height; y++)
384 {
385 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
386 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
387 for (int x = 0; x < width; x++)
388 {
389 dest[4 * x + 0] = 0;
390 dest[4 * x + 1] = 0;
391 dest[4 * x + 2] = 0;
392 dest[4 * x + 3] = source[x];
393 }
394 }
395}
396
397void Texture::loadLuminanceImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
398 int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const
399{
400 const int destBytesPerPixel = native? 1: 4;
401 const unsigned char *source = NULL;
402 unsigned char *dest = NULL;
403
404 for (int y = 0; y < height; y++)
405 {
406 source = static_cast<const unsigned char*>(input) + y * inputPitch;
407 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * destBytesPerPixel;
408
409 if (!native) // BGRA8 destination format
410 {
411 for (int x = 0; x < width; x++)
412 {
413 dest[4 * x + 0] = source[x];
414 dest[4 * x + 1] = source[x];
415 dest[4 * x + 2] = source[x];
416 dest[4 * x + 3] = 0xFF;
417 }
418 }
419 else // L8 destination format
420 {
421 memcpy(dest, source, width);
422 }
423 }
424}
425
426void Texture::loadLuminanceFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
427 int inputPitch, const void *input, size_t outputPitch, void *output) const
428{
429 const float *source = NULL;
430 float *dest = NULL;
431
432 for (int y = 0; y < height; y++)
433 {
434 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
435 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
436 for (int x = 0; x < width; x++)
437 {
438 dest[4 * x + 0] = source[x];
439 dest[4 * x + 1] = source[x];
440 dest[4 * x + 2] = source[x];
441 dest[4 * x + 3] = 1.0f;
442 }
443 }
444}
445
446void Texture::loadLuminanceHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
447 int inputPitch, const void *input, size_t outputPitch, void *output) const
448{
449 const unsigned short *source = NULL;
450 unsigned short *dest = NULL;
451
452 for (int y = 0; y < height; y++)
453 {
454 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
455 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
456 for (int x = 0; x < width; x++)
457 {
458 dest[4 * x + 0] = source[x];
459 dest[4 * x + 1] = source[x];
460 dest[4 * x + 2] = source[x];
461 dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1
462 }
463 }
464}
465
466void Texture::loadLuminanceAlphaImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
467 int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const
468{
469 const int destBytesPerPixel = native? 2: 4;
470 const unsigned char *source = NULL;
471 unsigned char *dest = NULL;
472
473 for (int y = 0; y < height; y++)
474 {
475 source = static_cast<const unsigned char*>(input) + y * inputPitch;
476 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * destBytesPerPixel;
477
478 if (!native) // BGRA8 destination format
479 {
480 for (int x = 0; x < width; x++)
481 {
482 dest[4 * x + 0] = source[2*x+0];
483 dest[4 * x + 1] = source[2*x+0];
484 dest[4 * x + 2] = source[2*x+0];
485 dest[4 * x + 3] = source[2*x+1];
486 }
487 }
488 else
489 {
490 memcpy(dest, source, width * 2);
491 }
492 }
493}
494
495void Texture::loadLuminanceAlphaFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
496 int inputPitch, const void *input, size_t outputPitch, void *output) const
497{
498 const float *source = NULL;
499 float *dest = NULL;
500
501 for (int y = 0; y < height; y++)
502 {
503 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
504 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
505 for (int x = 0; x < width; x++)
506 {
507 dest[4 * x + 0] = source[2*x+0];
508 dest[4 * x + 1] = source[2*x+0];
509 dest[4 * x + 2] = source[2*x+0];
510 dest[4 * x + 3] = source[2*x+1];
511 }
512 }
513}
514
515void Texture::loadLuminanceAlphaHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
516 int inputPitch, const void *input, size_t outputPitch, void *output) const
517{
518 const unsigned short *source = NULL;
519 unsigned short *dest = NULL;
520
521 for (int y = 0; y < height; y++)
522 {
523 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
524 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
525 for (int x = 0; x < width; x++)
526 {
527 dest[4 * x + 0] = source[2*x+0];
528 dest[4 * x + 1] = source[2*x+0];
529 dest[4 * x + 2] = source[2*x+0];
530 dest[4 * x + 3] = source[2*x+1];
531 }
532 }
533}
534
535void Texture::loadRGBUByteImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
536 int inputPitch, const void *input, size_t outputPitch, void *output) const
537{
538 const unsigned char *source = NULL;
539 unsigned char *dest = NULL;
540
541 for (int y = 0; y < height; y++)
542 {
543 source = static_cast<const unsigned char*>(input) + y * inputPitch;
544 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
545 for (int x = 0; x < width; x++)
546 {
547 dest[4 * x + 0] = source[x * 3 + 2];
548 dest[4 * x + 1] = source[x * 3 + 1];
549 dest[4 * x + 2] = source[x * 3 + 0];
550 dest[4 * x + 3] = 0xFF;
551 }
552 }
553}
554
555void Texture::loadRGB565ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
556 int inputPitch, const void *input, size_t outputPitch, void *output) const
557{
558 const unsigned short *source = NULL;
559 unsigned char *dest = NULL;
560
561 for (int y = 0; y < height; y++)
562 {
563 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
564 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
565 for (int x = 0; x < width; x++)
566 {
567 unsigned short rgba = source[x];
568 dest[4 * x + 0] = ((rgba & 0x001F) << 3) | ((rgba & 0x001F) >> 2);
569 dest[4 * x + 1] = ((rgba & 0x07E0) >> 3) | ((rgba & 0x07E0) >> 9);
570 dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
571 dest[4 * x + 3] = 0xFF;
572 }
573 }
574}
575
576void Texture::loadRGBFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
577 int inputPitch, const void *input, size_t outputPitch, void *output) const
578{
579 const float *source = NULL;
580 float *dest = NULL;
581
582 for (int y = 0; y < height; y++)
583 {
584 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
585 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
586 for (int x = 0; x < width; x++)
587 {
588 dest[4 * x + 0] = source[x * 3 + 0];
589 dest[4 * x + 1] = source[x * 3 + 1];
590 dest[4 * x + 2] = source[x * 3 + 2];
591 dest[4 * x + 3] = 1.0f;
592 }
593 }
594}
595
596void Texture::loadRGBHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
597 int inputPitch, const void *input, size_t outputPitch, void *output) const
598{
599 const unsigned short *source = NULL;
600 unsigned short *dest = NULL;
601
602 for (int y = 0; y < height; y++)
603 {
604 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
605 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
606 for (int x = 0; x < width; x++)
607 {
608 dest[4 * x + 0] = source[x * 3 + 0];
609 dest[4 * x + 1] = source[x * 3 + 1];
610 dest[4 * x + 2] = source[x * 3 + 2];
611 dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1
612 }
613 }
614}
615
616void Texture::loadRGBAUByteImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
617 int inputPitch, const void *input, size_t outputPitch, void *output) const
618{
619 const unsigned char *source = NULL;
620 unsigned char *dest = NULL;
621
622 for (int y = 0; y < height; y++)
623 {
624 source = static_cast<const unsigned char*>(input) + y * inputPitch;
625 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
626 for (int x = 0; x < width; x++)
627 {
628 dest[4 * x + 0] = source[x * 4 + 2];
629 dest[4 * x + 1] = source[x * 4 + 1];
630 dest[4 * x + 2] = source[x * 4 + 0];
631 dest[4 * x + 3] = source[x * 4 + 3];
632 }
633 }
634}
635
636void Texture::loadRGBA4444ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
637 int inputPitch, const void *input, size_t outputPitch, void *output) const
638{
639 const unsigned short *source = NULL;
640 unsigned char *dest = NULL;
641
642 for (int y = 0; y < height; y++)
643 {
644 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
645 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
646 for (int x = 0; x < width; x++)
647 {
648 unsigned short rgba = source[x];
649 dest[4 * x + 0] = ((rgba & 0x00F0) << 0) | ((rgba & 0x00F0) >> 4);
650 dest[4 * x + 1] = ((rgba & 0x0F00) >> 4) | ((rgba & 0x0F00) >> 8);
651 dest[4 * x + 2] = ((rgba & 0xF000) >> 8) | ((rgba & 0xF000) >> 12);
652 dest[4 * x + 3] = ((rgba & 0x000F) << 4) | ((rgba & 0x000F) >> 0);
653 }
654 }
655}
656
657void Texture::loadRGBA5551ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
658 int inputPitch, const void *input, size_t outputPitch, void *output) const
659{
660 const unsigned short *source = NULL;
661 unsigned char *dest = NULL;
662
663 for (int y = 0; y < height; y++)
664 {
665 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
666 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
667 for (int x = 0; x < width; x++)
668 {
669 unsigned short rgba = source[x];
670 dest[4 * x + 0] = ((rgba & 0x003E) << 2) | ((rgba & 0x003E) >> 3);
671 dest[4 * x + 1] = ((rgba & 0x07C0) >> 3) | ((rgba & 0x07C0) >> 8);
672 dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
673 dest[4 * x + 3] = (rgba & 0x0001) ? 0xFF : 0;
674 }
675 }
676}
677
678void Texture::loadRGBAFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
679 int inputPitch, const void *input, size_t outputPitch, void *output) const
680{
681 const float *source = NULL;
682 float *dest = NULL;
683
684 for (int y = 0; y < height; y++)
685 {
686 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
687 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
688 memcpy(dest, source, width * 16);
689 }
690}
691
692void Texture::loadRGBAHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
693 int inputPitch, const void *input, size_t outputPitch, void *output) const
694{
695 const unsigned char *source = NULL;
696 unsigned char *dest = NULL;
697
698 for (int y = 0; y < height; y++)
699 {
700 source = static_cast<const unsigned char*>(input) + y * inputPitch;
701 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8;
702 memcpy(dest, source, width * 8);
703 }
704}
705
706void Texture::loadBGRAImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
707 int inputPitch, const void *input, size_t outputPitch, void *output) const
708{
709 const unsigned char *source = NULL;
710 unsigned char *dest = NULL;
711
712 for (int y = 0; y < height; y++)
713 {
714 source = static_cast<const unsigned char*>(input) + y * inputPitch;
715 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
716 memcpy(dest, source, width*4);
717 }
718}
719
720void Texture::loadCompressedImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
721 int inputPitch, const void *input, size_t outputPitch, void *output) const
722{
723 ASSERT(xoffset % 4 == 0);
724 ASSERT(yoffset % 4 == 0);
725 ASSERT(width % 4 == 0 || width == 2 || width == 1);
726 ASSERT(inputPitch % 8 == 0);
727 ASSERT(outputPitch % 8 == 0);
728
729 const unsigned int *source = reinterpret_cast<const unsigned int*>(input);
730 unsigned int *dest = reinterpret_cast<unsigned int*>(output);
731
732 switch (height)
733 {
734 case 1:
735 // Round width up in case it is 1.
736 for (int x = 0; x < (width + 1) / 2; x += 2)
737 {
738 // First 32-bits is two RGB565 colors shared by tile and does not need to be modified.
739 dest[x] = source[x];
740
741 // Second 32-bits contains 4 rows of 4 2-bit interpolants between the colors, the last 3 rows being unused. No flipping should occur.
742 dest[x + 1] = source[x + 1];
743 }
744 break;
745 case 2:
746 // Round width up in case it is 1.
747 for (int x = 0; x < (width + 1) / 2; x += 2)
748 {
749 // First 32-bits is two RGB565 colors shared by tile and does not need to be modified.
750 dest[x] = source[x];
751
752 // 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.
753 dest[x + 1] = ((source[x + 1] << 8) & 0x0000FF00) |
754 ((source[x + 1] >> 8) & 0x000000FF);
755 }
756 break;
757 default:
758 ASSERT(height % 4 == 0);
759 for (int y = 0; y < height / 4; ++y)
760 {
761 const unsigned int *source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);
762 unsigned int *dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
763
764 // Round width up in case it is 1.
765 for (int x = 0; x < (width + 1) / 2; x += 2)
766 {
767 // First 32-bits is two RGB565 colors shared by tile and does not need to be modified.
768 dest[x] = source[x];
769
770 // Second 32-bits contains 4 rows of 4 2-bit interpolants between the colors. All rows should be flipped.
771 dest[x + 1] = (source[x + 1] >> 24) |
772 ((source[x + 1] << 8) & 0x00FF0000) |
773 ((source[x + 1] >> 8) & 0x0000FF00) |
774 (source[x + 1] << 24);
775 }
776 }
777 break;
778 }
779}
780
daniel@transgaming.com61208202011-03-21 16:38:50 +0000781void Texture::createSurface(Image *image)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000782{
783 IDirect3DTexture9 *newTexture = NULL;
784 IDirect3DSurface9 *newSurface = NULL;
785
daniel@transgaming.com61208202011-03-21 16:38:50 +0000786 if (image->width != 0 && image->height != 0)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000787 {
788 int levelToFetch = 0;
daniel@transgaming.com61208202011-03-21 16:38:50 +0000789 GLsizei requestWidth = image->width;
790 GLsizei requestHeight = image->height;
791 if (IsCompressed(image->format) && (image->width % 4 != 0 || image->height % 4 != 0))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000792 {
793 bool isMult4 = false;
794 int upsampleCount = 0;
795 while (!isMult4)
796 {
797 requestWidth <<= 1;
798 requestHeight <<= 1;
799 upsampleCount++;
800 if (requestWidth % 4 == 0 && requestHeight % 4 == 0)
801 {
802 isMult4 = true;
803 }
804 }
805 levelToFetch = upsampleCount;
806 }
807
daniel@transgaming.com61208202011-03-21 16:38:50 +0000808 HRESULT result = getDevice()->CreateTexture(requestWidth, requestHeight, levelToFetch + 1, NULL, selectFormat(image->format, image->type),
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000809 D3DPOOL_SYSTEMMEM, &newTexture, NULL);
810
811 if (FAILED(result))
812 {
813 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
814 return error(GL_OUT_OF_MEMORY);
815 }
816
817 newTexture->GetSurfaceLevel(levelToFetch, &newSurface);
818 newTexture->Release();
819 }
820
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +0000821 if (image->surface)
822 {
823 image->surface->Release();
824 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000825
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +0000826 image->surface = newSurface;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000827}
828
daniel@transgaming.com61208202011-03-21 16:38:50 +0000829void Texture::setImage(GLint unpackAlignment, const void *pixels, Image *image)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000830{
daniel@transgaming.com61208202011-03-21 16:38:50 +0000831 createSurface(image);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000832
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000833 if (pixels != NULL && image->surface != NULL)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000834 {
835 D3DSURFACE_DESC description;
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000836 image->surface->GetDesc(&description);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000837
838 D3DLOCKED_RECT locked;
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000839 HRESULT result = image->surface->LockRect(&locked, NULL, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000840
841 ASSERT(SUCCEEDED(result));
842
843 if (SUCCEEDED(result))
844 {
daniel@transgaming.com61208202011-03-21 16:38:50 +0000845 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 +0000846 image->surface->UnlockRect();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000847 }
848
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000849 image->dirty = true;
daniel@transgaming.com38e76e52011-03-21 16:39:10 +0000850 mDirty = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000851 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000852}
853
daniel@transgaming.com61208202011-03-21 16:38:50 +0000854void Texture::setCompressedImage(GLsizei imageSize, const void *pixels, Image *image)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000855{
daniel@transgaming.com61208202011-03-21 16:38:50 +0000856 createSurface(image);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000857
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000858 if (pixels != NULL && image->surface != NULL)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000859 {
860 D3DLOCKED_RECT locked;
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000861 HRESULT result = image->surface->LockRect(&locked, NULL, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000862
863 ASSERT(SUCCEEDED(result));
864
865 if (SUCCEEDED(result))
866 {
daniel@transgaming.com61208202011-03-21 16:38:50 +0000867 int inputPitch = ComputeCompressedPitch(image->width, image->format);
868 int inputSize = ComputeCompressedSize(image->width, image->height, image->format);
869 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 +0000870 image->surface->UnlockRect();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000871 }
872
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000873 image->dirty = true;
daniel@transgaming.com38e76e52011-03-21 16:39:10 +0000874 mDirty = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000875 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000876}
877
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000878bool 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 +0000879{
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000880 if (width + xoffset > image->width || height + yoffset > image->height)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000881 {
882 error(GL_INVALID_VALUE);
883 return false;
884 }
885
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000886 if (!image->surface)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000887 {
daniel@transgaming.com61208202011-03-21 16:38:50 +0000888 createSurface(image);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000889 }
890
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000891 if (pixels != NULL && image->surface != NULL)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000892 {
893 D3DSURFACE_DESC description;
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000894 image->surface->GetDesc(&description);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000895
896 D3DLOCKED_RECT locked;
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000897 HRESULT result = image->surface->LockRect(&locked, NULL, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000898
899 ASSERT(SUCCEEDED(result));
900
901 if (SUCCEEDED(result))
902 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000903 loadImageData(xoffset, transformPixelYOffset(yoffset, height, image->height), width, height, format, type, unpackAlignment, pixels, locked.Pitch, locked.pBits, &description);
904 image->surface->UnlockRect();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000905 }
906
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000907 image->dirty = true;
daniel@transgaming.com38e76e52011-03-21 16:39:10 +0000908 mDirty = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000909 }
910
911 return true;
912}
913
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000914bool 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 +0000915{
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000916 if (width + xoffset > image->width || height + yoffset > image->height)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000917 {
918 error(GL_INVALID_VALUE);
919 return false;
920 }
921
922 if (format != getInternalFormat())
923 {
924 error(GL_INVALID_OPERATION);
925 return false;
926 }
927
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000928 if (!image->surface)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000929 {
daniel@transgaming.com61208202011-03-21 16:38:50 +0000930 createSurface(image);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000931 }
932
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000933 if (pixels != NULL && image->surface != NULL)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000934 {
935 RECT updateRegion;
936 updateRegion.left = xoffset;
937 updateRegion.right = xoffset + width;
938 updateRegion.bottom = yoffset + height;
939 updateRegion.top = yoffset;
940
941 D3DLOCKED_RECT locked;
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000942 HRESULT result = image->surface->LockRect(&locked, &updateRegion, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000943
944 ASSERT(SUCCEEDED(result));
945
946 if (SUCCEEDED(result))
947 {
948 int inputPitch = ComputeCompressedPitch(width, format);
949 int inputSize = ComputeCompressedSize(width, height, format);
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000950 loadCompressedImageData(xoffset, transformPixelYOffset(yoffset, height, image->height), width, height, -inputPitch, static_cast<const char*>(pixels) + inputSize - inputPitch, locked.Pitch, locked.pBits);
951 image->surface->UnlockRect();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000952 }
953
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000954 image->dirty = true;
daniel@transgaming.com38e76e52011-03-21 16:39:10 +0000955 mDirty = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000956 }
957
958 return true;
959}
960
961// This implements glCopyTex[Sub]Image2D for non-renderable internal texture formats
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +0000962void Texture::copyNonRenderable(Image *image, GLenum format, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, IDirect3DSurface9 *renderTarget)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000963{
964 IDirect3DDevice9 *device = getDevice();
965 IDirect3DSurface9 *surface = NULL;
966 D3DSURFACE_DESC description;
967 renderTarget->GetDesc(&description);
968
969 HRESULT result = device->CreateOffscreenPlainSurface(description.Width, description.Height, description.Format, D3DPOOL_SYSTEMMEM, &surface, NULL);
970
971 if (!SUCCEEDED(result))
972 {
973 ERR("Could not create matching destination surface.");
974 return error(GL_OUT_OF_MEMORY);
975 }
976
977 result = device->GetRenderTargetData(renderTarget, surface);
978
979 if (!SUCCEEDED(result))
980 {
981 ERR("GetRenderTargetData unexpectedly failed.");
982 surface->Release();
983 return error(GL_OUT_OF_MEMORY);
984 }
985
986 D3DLOCKED_RECT sourceLock = {0};
987 RECT sourceRect = transformPixelRect(x, y, width, height, description.Height);
988 result = surface->LockRect(&sourceLock, &sourceRect, 0);
989
990 if (FAILED(result))
991 {
992 ERR("Failed to lock the source surface (rectangle might be invalid).");
993 surface->UnlockRect();
994 surface->Release();
995 return error(GL_OUT_OF_MEMORY);
996 }
997
998 if (!image->surface)
999 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001000 createSurface(image);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001001 }
1002
1003 if (image->surface == NULL)
1004 {
1005 ERR("Failed to create an image surface.");
1006 surface->UnlockRect();
1007 surface->Release();
1008 return error(GL_OUT_OF_MEMORY);
1009 }
1010
1011 D3DLOCKED_RECT destLock = {0};
1012 int destYOffset = transformPixelYOffset(yoffset, height, image->height);
1013 RECT destRect = {xoffset, destYOffset, xoffset + width, destYOffset + height};
1014 result = image->surface->LockRect(&destLock, &destRect, 0);
1015
1016 if (FAILED(result))
1017 {
1018 ERR("Failed to lock the destination surface (rectangle might be invalid).");
1019 surface->UnlockRect();
1020 surface->Release();
1021 return error(GL_OUT_OF_MEMORY);
1022 }
1023
1024 if (destLock.pBits && sourceLock.pBits)
1025 {
1026 unsigned char *source = (unsigned char*)sourceLock.pBits;
1027 unsigned char *dest = (unsigned char*)destLock.pBits;
1028
1029 switch (description.Format)
1030 {
1031 case D3DFMT_X8R8G8B8:
1032 case D3DFMT_A8R8G8B8:
1033 switch(getD3DFormat())
1034 {
1035 case D3DFMT_L8:
1036 for(int y = 0; y < height; y++)
1037 {
1038 for(int x = 0; x < width; x++)
1039 {
1040 dest[x] = source[x * 4 + 2];
1041 }
1042
1043 source += sourceLock.Pitch;
1044 dest += destLock.Pitch;
1045 }
1046 break;
1047 case D3DFMT_A8L8:
1048 for(int y = 0; y < height; y++)
1049 {
1050 for(int x = 0; x < width; x++)
1051 {
1052 dest[x * 2 + 0] = source[x * 4 + 2];
1053 dest[x * 2 + 1] = source[x * 4 + 3];
1054 }
1055
1056 source += sourceLock.Pitch;
1057 dest += destLock.Pitch;
1058 }
1059 break;
1060 default:
1061 UNREACHABLE();
1062 }
1063 break;
1064 case D3DFMT_R5G6B5:
1065 switch(getD3DFormat())
1066 {
1067 case D3DFMT_L8:
1068 for(int y = 0; y < height; y++)
1069 {
1070 for(int x = 0; x < width; x++)
1071 {
1072 unsigned char red = source[x * 2 + 1] & 0xF8;
1073 dest[x] = red | (red >> 5);
1074 }
1075
1076 source += sourceLock.Pitch;
1077 dest += destLock.Pitch;
1078 }
1079 break;
1080 default:
1081 UNREACHABLE();
1082 }
1083 break;
1084 case D3DFMT_A1R5G5B5:
1085 switch(getD3DFormat())
1086 {
1087 case D3DFMT_L8:
1088 for(int y = 0; y < height; y++)
1089 {
1090 for(int x = 0; x < width; x++)
1091 {
1092 unsigned char red = source[x * 2 + 1] & 0x7C;
1093 dest[x] = (red << 1) | (red >> 4);
1094 }
1095
1096 source += sourceLock.Pitch;
1097 dest += destLock.Pitch;
1098 }
1099 break;
1100 case D3DFMT_A8L8:
1101 for(int y = 0; y < height; y++)
1102 {
1103 for(int x = 0; x < width; x++)
1104 {
1105 unsigned char red = source[x * 2 + 1] & 0x7C;
1106 dest[x * 2 + 0] = (red << 1) | (red >> 4);
1107 dest[x * 2 + 1] = (signed char)source[x * 2 + 1] >> 7;
1108 }
1109
1110 source += sourceLock.Pitch;
1111 dest += destLock.Pitch;
1112 }
1113 break;
1114 default:
1115 UNREACHABLE();
1116 }
1117 break;
1118 default:
1119 UNREACHABLE();
1120 }
1121
1122 image->dirty = true;
daniel@transgaming.com38e76e52011-03-21 16:39:10 +00001123 mDirty = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001124 }
1125
1126 image->surface->UnlockRect();
1127 surface->UnlockRect();
1128 surface->Release();
1129}
1130
1131D3DFORMAT Texture::getD3DFormat() const
1132{
daniel@transgaming.com61208202011-03-21 16:38:50 +00001133 return selectFormat(getInternalFormat(), getType());
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001134}
1135
1136IDirect3DBaseTexture9 *Texture::getTexture()
1137{
1138 if (!isComplete())
1139 {
1140 return NULL;
1141 }
1142
daniel@transgaming.comaed18322011-03-21 16:38:13 +00001143 if (!getBaseTexture())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001144 {
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001145 createTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001146 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001147
daniel@transgaming.comc50edcb2011-03-21 16:38:40 +00001148 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001149
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001150 return getBaseTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001151}
1152
1153bool Texture::isDirty() const
1154{
daniel@transgaming.com38e76e52011-03-21 16:39:10 +00001155 return mDirty;
1156}
1157
1158void Texture::resetDirty()
1159{
1160 mDirty = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001161}
1162
daniel@transgaming.coma9eb5da2011-03-21 16:39:16 +00001163unsigned int Texture::getSerial() const
1164{
1165 return mSerial;
1166}
1167
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001168GLint Texture::creationLevels(GLsizei width, GLsizei height, GLint maxlevel) const
1169{
1170 if (isPow2(width) && isPow2(height))
1171 {
1172 return maxlevel;
1173 }
1174 else
1175 {
1176 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
1177 return 1;
1178 }
1179}
1180
1181GLint Texture::creationLevels(GLsizei size, GLint maxlevel) const
1182{
1183 return creationLevels(size, size, maxlevel);
1184}
1185
1186int Texture::levelCount() const
1187{
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001188 return getBaseTexture() ? getBaseTexture()->GetLevelCount() : 0;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001189}
1190
daniel@transgaming.coma9eb5da2011-03-21 16:39:16 +00001191unsigned int Texture::issueSerial()
1192{
1193 return mCurrentSerial++;
1194}
1195
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001196Texture2D::Texture2D(GLuint id) : Texture(id)
1197{
1198 mTexture = NULL;
1199}
1200
1201Texture2D::~Texture2D()
1202{
1203 mColorbufferProxy.set(NULL);
1204
1205 if (mTexture)
1206 {
1207 mTexture->Release();
1208 mTexture = NULL;
1209 }
1210}
1211
1212GLenum Texture2D::getTarget() const
1213{
1214 return GL_TEXTURE_2D;
1215}
1216
daniel@transgaming.com61208202011-03-21 16:38:50 +00001217GLsizei Texture2D::getWidth() const
1218{
1219 return mImageArray[0].width;
1220}
1221
1222GLsizei Texture2D::getHeight() const
1223{
1224 return mImageArray[0].height;
1225}
1226
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001227GLenum Texture2D::getInternalFormat() const
1228{
1229 return mImageArray[0].format;
1230}
1231
daniel@transgaming.com61208202011-03-21 16:38:50 +00001232GLenum Texture2D::getType() const
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001233{
daniel@transgaming.com61208202011-03-21 16:38:50 +00001234 return mImageArray[0].type;
1235}
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001236
daniel@transgaming.com61208202011-03-21 16:38:50 +00001237void Texture2D::redefineTexture(GLint level, GLenum format, GLsizei width, GLsizei height, GLenum type)
1238{
daniel@transgaming.com94a4f032011-03-21 16:38:55 +00001239 GLsizei textureWidth = mImageArray[0].width;
1240 GLsizei textureHeight = mImageArray[0].height;
1241 GLenum textureFormat = mImageArray[0].format;
1242 GLenum textureType = mImageArray[0].type;
1243
daniel@transgaming.com61208202011-03-21 16:38:50 +00001244 mImageArray[level].width = width;
1245 mImageArray[level].height = height;
1246 mImageArray[level].format = format;
1247 mImageArray[level].type = type;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001248
daniel@transgaming.com61208202011-03-21 16:38:50 +00001249 if (!mTexture)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001250 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001251 return;
1252 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001253
daniel@transgaming.com94a4f032011-03-21 16:38:55 +00001254 bool widthOkay = (textureWidth >> level == width) || (textureWidth >> level == 0 && width == 1);
1255 bool heightOkay = (textureHeight >> level == height) || (textureHeight >> level == 0 && height == 1);
1256 bool textureOkay = (widthOkay && heightOkay && textureFormat == format && textureType == type);
daniel@transgaming.com61208202011-03-21 16:38:50 +00001257
1258 if (!textureOkay) // Purge all the levels and the texture.
1259 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001260 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1261 {
1262 if (mImageArray[i].surface != NULL)
1263 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001264 mImageArray[i].surface->Release();
1265 mImageArray[i].surface = NULL;
daniel@transgaming.com61208202011-03-21 16:38:50 +00001266 mImageArray[i].dirty = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001267 }
1268 }
1269
1270 if (mTexture != NULL)
1271 {
1272 mTexture->Release();
1273 mTexture = NULL;
daniel@transgaming.com38e76e52011-03-21 16:39:10 +00001274 mDirty = true;
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001275 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001276 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001277 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001278}
1279
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001280void 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 +00001281{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001282 redefineTexture(level, format, width, height, type);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001283
daniel@transgaming.com61208202011-03-21 16:38:50 +00001284 Texture::setImage(unpackAlignment, pixels, &mImageArray[level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001285}
1286
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001287void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001288{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001289 redefineTexture(level, format, width, height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001290
daniel@transgaming.com61208202011-03-21 16:38:50 +00001291 Texture::setCompressedImage(imageSize, pixels, &mImageArray[level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001292}
1293
1294void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1295{
1296 ASSERT(mImageArray[level].surface != NULL);
1297
1298 if (level < levelCount())
1299 {
1300 IDirect3DSurface9 *destLevel = NULL;
1301 HRESULT result = mTexture->GetSurfaceLevel(level, &destLevel);
1302
1303 ASSERT(SUCCEEDED(result));
1304
1305 if (SUCCEEDED(result))
1306 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001307 Image *image = &mImageArray[level];
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001308
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001309 RECT sourceRect = transformPixelRect(xoffset, yoffset, width, height, image->height);;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001310
1311 POINT destPoint;
1312 destPoint.x = sourceRect.left;
1313 destPoint.y = sourceRect.top;
1314
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001315 result = getDevice()->UpdateSurface(image->surface, &sourceRect, destLevel, &destPoint);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001316 ASSERT(SUCCEEDED(result));
1317
1318 destLevel->Release();
1319
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001320 image->dirty = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001321 }
1322 }
1323}
1324
1325void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1326{
1327 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[level]))
1328 {
1329 commitRect(level, xoffset, yoffset, width, height);
1330 }
1331}
1332
1333void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1334{
1335 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[level]))
1336 {
1337 commitRect(level, xoffset, yoffset, width, height);
1338 }
1339}
1340
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001341void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001342{
1343 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
1344
1345 if (!renderTarget)
1346 {
1347 ERR("Failed to retrieve the render target.");
1348 return error(GL_OUT_OF_MEMORY);
1349 }
1350
daniel@transgaming.com61208202011-03-21 16:38:50 +00001351 redefineTexture(level, format, width, height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001352
1353 if (!isRenderableFormat())
1354 {
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001355 copyNonRenderable(&mImageArray[level], format, 0, 0, x, y, width, height, renderTarget);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001356 }
1357 else
1358 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001359 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001360 {
1361 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001362 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00001363
1364 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001365
1366 if (width != 0 && height != 0 && level < levelCount())
1367 {
1368 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
1369 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
1370 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
1371 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
1372 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
1373
1374 IDirect3DSurface9 *dest;
1375 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
1376
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001377 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, format, 0, 0, dest);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001378 dest->Release();
1379 }
1380 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001381}
1382
1383void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1384{
1385 if (xoffset + width > mImageArray[level].width || yoffset + height > mImageArray[level].height)
1386 {
1387 return error(GL_INVALID_VALUE);
1388 }
1389
1390 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
1391
1392 if (!renderTarget)
1393 {
1394 ERR("Failed to retrieve the render target.");
1395 return error(GL_OUT_OF_MEMORY);
1396 }
1397
daniel@transgaming.com61208202011-03-21 16:38:50 +00001398 redefineTexture(0, mImageArray[0].format, mImageArray[0].width, mImageArray[0].height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001399
daniel@transgaming.comf4e36032011-03-21 16:38:59 +00001400 if (!isRenderableFormat() || (!mTexture && !isComplete()))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001401 {
1402 copyNonRenderable(&mImageArray[level], getInternalFormat(), xoffset, yoffset, x, y, width, height, renderTarget);
1403 }
1404 else
1405 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001406 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001407 {
1408 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001409 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00001410
1411 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001412
1413 if (level < levelCount())
1414 {
1415 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
1416 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
1417 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
1418 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
1419 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
1420
1421 GLint destYOffset = transformPixelYOffset(yoffset, height, mImageArray[level].height);
1422
1423 IDirect3DSurface9 *dest;
1424 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
1425
1426 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0].format, xoffset, destYOffset, dest);
1427 dest->Release();
1428 }
1429 }
1430}
1431
1432// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1433bool Texture2D::isComplete() const
1434{
1435 GLsizei width = mImageArray[0].width;
1436 GLsizei height = mImageArray[0].height;
1437
1438 if (width <= 0 || height <= 0)
1439 {
1440 return false;
1441 }
1442
1443 bool mipmapping = false;
1444
1445 switch (mMinFilter)
1446 {
1447 case GL_NEAREST:
1448 case GL_LINEAR:
1449 mipmapping = false;
1450 break;
1451 case GL_NEAREST_MIPMAP_NEAREST:
1452 case GL_LINEAR_MIPMAP_NEAREST:
1453 case GL_NEAREST_MIPMAP_LINEAR:
1454 case GL_LINEAR_MIPMAP_LINEAR:
1455 mipmapping = true;
1456 break;
1457 default: UNREACHABLE();
1458 }
1459
1460 if ((getInternalFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) ||
1461 (getInternalFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter()))
1462 {
1463 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
1464 {
1465 return false;
1466 }
1467 }
1468
1469
1470 if ((getWrapS() != GL_CLAMP_TO_EDGE && !isPow2(width))
1471 || (getWrapT() != GL_CLAMP_TO_EDGE && !isPow2(height)))
1472 {
1473 return false;
1474 }
1475
1476 if (mipmapping)
1477 {
1478 if (!isPow2(width) || !isPow2(height))
1479 {
1480 return false;
1481 }
1482
1483 int q = log2(std::max(width, height));
1484
1485 for (int level = 1; level <= q; level++)
1486 {
1487 if (mImageArray[level].format != mImageArray[0].format)
1488 {
1489 return false;
1490 }
1491
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00001492 if (mImageArray[level].type != mImageArray[0].type)
1493 {
1494 return false;
1495 }
1496
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001497 if (mImageArray[level].width != std::max(1, width >> level))
1498 {
1499 return false;
1500 }
1501
1502 if (mImageArray[level].height != std::max(1, height >> level))
1503 {
1504 return false;
1505 }
1506 }
1507 }
1508
1509 return true;
1510}
1511
1512bool Texture2D::isCompressed() const
1513{
1514 return IsCompressed(getInternalFormat());
1515}
1516
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001517IDirect3DBaseTexture9 *Texture2D::getBaseTexture() const
1518{
1519 return mTexture;
1520}
1521
1522// Constructs a Direct3D 9 texture resource from the texture images
1523void Texture2D::createTexture()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001524{
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001525 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com61208202011-03-21 16:38:50 +00001526 D3DFORMAT format = selectFormat(mImageArray[0].format, mImageArray[0].type);
1527 GLint levels = creationLevels(mImageArray[0].width, mImageArray[0].height, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001528
daniel@transgaming.com61208202011-03-21 16:38:50 +00001529 IDirect3DTexture9 *texture = NULL;
1530 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 +00001531
1532 if (FAILED(result))
1533 {
1534 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001535 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001536 }
1537
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001538 if (mTexture)
1539 {
1540 mTexture->Release();
1541 }
1542
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001543 mTexture = texture;
daniel@transgaming.com38e76e52011-03-21 16:39:10 +00001544 mDirty = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00001545 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001546}
1547
1548void Texture2D::updateTexture()
1549{
1550 IDirect3DDevice9 *device = getDevice();
1551
1552 int levels = levelCount();
1553
1554 for (int level = 0; level < levels; level++)
1555 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001556 if (mImageArray[level].surface && mImageArray[level].dirty)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001557 {
1558 IDirect3DSurface9 *levelSurface = NULL;
1559 HRESULT result = mTexture->GetSurfaceLevel(level, &levelSurface);
1560
1561 ASSERT(SUCCEEDED(result));
1562
1563 if (SUCCEEDED(result))
1564 {
1565 result = device->UpdateSurface(mImageArray[level].surface, NULL, levelSurface, NULL);
1566 ASSERT(SUCCEEDED(result));
1567
1568 levelSurface->Release();
1569
1570 mImageArray[level].dirty = false;
1571 }
1572 }
1573 }
1574}
1575
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001576void Texture2D::convertToRenderTarget()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001577{
1578 IDirect3DTexture9 *texture = NULL;
1579
daniel@transgaming.com61208202011-03-21 16:38:50 +00001580 if (mImageArray[0].width != 0 && mImageArray[0].height != 0)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001581 {
1582 egl::Display *display = getDisplay();
1583 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com61208202011-03-21 16:38:50 +00001584 D3DFORMAT format = selectFormat(mImageArray[0].format, mImageArray[0].type);
1585 GLint levels = creationLevels(mImageArray[0].width, mImageArray[0].height, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001586
daniel@transgaming.com61208202011-03-21 16:38:50 +00001587 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 +00001588
1589 if (FAILED(result))
1590 {
1591 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001592 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001593 }
1594
1595 if (mTexture != NULL)
1596 {
1597 int levels = levelCount();
1598 for (int i = 0; i < levels; i++)
1599 {
1600 IDirect3DSurface9 *source;
1601 result = mTexture->GetSurfaceLevel(i, &source);
1602
1603 if (FAILED(result))
1604 {
1605 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1606
1607 texture->Release();
1608
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001609 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001610 }
1611
1612 IDirect3DSurface9 *dest;
1613 result = texture->GetSurfaceLevel(i, &dest);
1614
1615 if (FAILED(result))
1616 {
1617 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1618
1619 texture->Release();
1620 source->Release();
1621
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001622 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001623 }
1624
1625 display->endScene();
1626 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
1627
1628 if (FAILED(result))
1629 {
1630 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1631
1632 texture->Release();
1633 source->Release();
1634 dest->Release();
1635
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001636 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001637 }
1638
1639 source->Release();
1640 dest->Release();
1641 }
1642 }
1643 }
1644
1645 if (mTexture != NULL)
1646 {
1647 mTexture->Release();
1648 }
1649
1650 mTexture = texture;
daniel@transgaming.com38e76e52011-03-21 16:39:10 +00001651 mDirty = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00001652 mIsRenderable = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001653}
1654
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001655void Texture2D::generateMipmaps()
1656{
1657 if (!isPow2(mImageArray[0].width) || !isPow2(mImageArray[0].height))
1658 {
1659 return error(GL_INVALID_OPERATION);
1660 }
1661
1662 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
daniel@transgaming.com61208202011-03-21 16:38:50 +00001663 unsigned int q = log2(std::max(mImageArray[0].width, mImageArray[0].height));
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001664 for (unsigned int i = 1; i <= q; i++)
1665 {
1666 if (mImageArray[i].surface != NULL)
1667 {
1668 mImageArray[i].surface->Release();
1669 mImageArray[i].surface = NULL;
1670 }
1671
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001672 mImageArray[i].width = std::max(mImageArray[0].width >> i, 1);
1673 mImageArray[i].height = std::max(mImageArray[0].height >> i, 1);
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00001674 mImageArray[i].format = mImageArray[0].format;
1675 mImageArray[i].type = mImageArray[0].type;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001676 }
1677
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001678 if (mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001679 {
1680 if (mTexture == NULL)
1681 {
1682 ERR(" failed because mTexture was null.");
1683 return;
1684 }
1685
1686 for (unsigned int i = 1; i <= q; i++)
1687 {
1688 IDirect3DSurface9 *upper = NULL;
1689 IDirect3DSurface9 *lower = NULL;
1690
1691 mTexture->GetSurfaceLevel(i-1, &upper);
1692 mTexture->GetSurfaceLevel(i, &lower);
1693
1694 if (upper != NULL && lower != NULL)
1695 {
1696 getBlitter()->boxFilter(upper, lower);
1697 }
1698
1699 if (upper != NULL) upper->Release();
1700 if (lower != NULL) lower->Release();
daniel@transgaming.com61208202011-03-21 16:38:50 +00001701
1702 mImageArray[i].dirty = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001703 }
1704 }
1705 else
1706 {
1707 for (unsigned int i = 1; i <= q; i++)
1708 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001709 createSurface(&mImageArray[i]);
1710
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001711 if (mImageArray[i].surface == NULL)
1712 {
1713 return error(GL_OUT_OF_MEMORY);
1714 }
1715
1716 if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[i].surface, NULL, NULL, mImageArray[i - 1].surface, NULL, NULL, D3DX_FILTER_BOX, 0)))
1717 {
1718 ERR(" failed to load filter %d to %d.", i - 1, i);
1719 }
1720
1721 mImageArray[i].dirty = true;
1722 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001723 }
1724}
1725
1726Renderbuffer *Texture2D::getRenderbuffer(GLenum target)
1727{
1728 if (target != GL_TEXTURE_2D)
1729 {
1730 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
1731 }
1732
1733 if (mColorbufferProxy.get() == NULL)
1734 {
1735 mColorbufferProxy.set(new Renderbuffer(id(), new Colorbuffer(this, target)));
1736 }
1737
1738 return mColorbufferProxy.get();
1739}
1740
1741IDirect3DSurface9 *Texture2D::getRenderTarget(GLenum target)
1742{
1743 ASSERT(target == GL_TEXTURE_2D);
1744
daniel@transgaming.com61208202011-03-21 16:38:50 +00001745 if (!mIsRenderable)
1746 {
1747 convertToRenderTarget();
1748 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001749
1750 if (mTexture == NULL)
1751 {
1752 return NULL;
1753 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00001754
1755 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001756
1757 IDirect3DSurface9 *renderTarget = NULL;
1758 mTexture->GetSurfaceLevel(0, &renderTarget);
1759
1760 return renderTarget;
1761}
1762
1763TextureCubeMap::TextureCubeMap(GLuint id) : Texture(id)
1764{
1765 mTexture = NULL;
1766}
1767
1768TextureCubeMap::~TextureCubeMap()
1769{
1770 for (int i = 0; i < 6; i++)
1771 {
1772 mFaceProxies[i].set(NULL);
1773 }
1774
1775 if (mTexture)
1776 {
1777 mTexture->Release();
1778 mTexture = NULL;
1779 }
1780}
1781
1782GLenum TextureCubeMap::getTarget() const
1783{
1784 return GL_TEXTURE_CUBE_MAP;
1785}
1786
daniel@transgaming.com61208202011-03-21 16:38:50 +00001787GLsizei TextureCubeMap::getWidth() const
1788{
1789 return mImageArray[0][0].width;
1790}
1791
1792GLsizei TextureCubeMap::getHeight() const
1793{
1794 return mImageArray[0][0].height;
1795}
1796
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001797GLenum TextureCubeMap::getInternalFormat() const
1798{
1799 return mImageArray[0][0].format;
1800}
1801
daniel@transgaming.com61208202011-03-21 16:38:50 +00001802GLenum TextureCubeMap::getType() const
1803{
1804 return mImageArray[0][0].type;
1805}
1806
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001807void 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 +00001808{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001809 setImage(0, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001810}
1811
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001812void 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 +00001813{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001814 setImage(1, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001815}
1816
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001817void 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 +00001818{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001819 setImage(2, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001820}
1821
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001822void 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 +00001823{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001824 setImage(3, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001825}
1826
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001827void 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 +00001828{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001829 setImage(4, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001830}
1831
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001832void 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 +00001833{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001834 setImage(5, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001835}
1836
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001837void 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 +00001838{
daniel@transgaming.com61208202011-03-21 16:38:50 +00001839 redefineTexture(faceIndex(face), level, format, width, height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001840
daniel@transgaming.com61208202011-03-21 16:38:50 +00001841 Texture::setCompressedImage(imageSize, pixels, &mImageArray[faceIndex(face)][level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001842}
1843
1844void TextureCubeMap::commitRect(GLenum faceTarget, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1845{
1846 int face = faceIndex(faceTarget);
1847 ASSERT(mImageArray[face][level].surface != NULL);
1848
1849 if (level < levelCount())
1850 {
1851 IDirect3DSurface9 *destLevel = getCubeMapSurface(faceTarget, level);
1852 ASSERT(destLevel != NULL);
1853
1854 if (destLevel != NULL)
1855 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001856 Image *image = &mImageArray[face][level];
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001857
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001858 RECT sourceRect = transformPixelRect(xoffset, yoffset, width, height, image->height);;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001859
1860 POINT destPoint;
1861 destPoint.x = sourceRect.left;
1862 destPoint.y = sourceRect.top;
1863
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001864 HRESULT result = getDevice()->UpdateSurface(image->surface, &sourceRect, destLevel, &destPoint);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001865 ASSERT(SUCCEEDED(result));
1866
1867 destLevel->Release();
1868
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001869 image->dirty = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001870 }
1871 }
1872}
1873
1874void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1875{
1876 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[faceIndex(target)][level]))
1877 {
1878 commitRect(target, level, xoffset, yoffset, width, height);
1879 }
1880}
1881
1882void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1883{
1884 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[faceIndex(target)][level]))
1885 {
1886 commitRect(target, level, xoffset, yoffset, width, height);
1887 }
1888}
1889
1890// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1891bool TextureCubeMap::isComplete() const
1892{
1893 int size = mImageArray[0][0].width;
1894
1895 if (size <= 0)
1896 {
1897 return false;
1898 }
1899
1900 bool mipmapping;
1901
1902 switch (mMinFilter)
1903 {
1904 case GL_NEAREST:
1905 case GL_LINEAR:
1906 mipmapping = false;
1907 break;
1908 case GL_NEAREST_MIPMAP_NEAREST:
1909 case GL_LINEAR_MIPMAP_NEAREST:
1910 case GL_NEAREST_MIPMAP_LINEAR:
1911 case GL_LINEAR_MIPMAP_LINEAR:
1912 mipmapping = true;
1913 break;
1914 default: UNREACHABLE();
1915 }
1916
1917 for (int face = 0; face < 6; face++)
1918 {
1919 if (mImageArray[face][0].width != size || mImageArray[face][0].height != size)
1920 {
1921 return false;
1922 }
1923 }
1924
1925 if ((getInternalFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) ||
1926 (getInternalFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter()))
1927 {
1928 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
1929 {
1930 return false;
1931 }
1932 }
1933
1934 if (mipmapping)
1935 {
1936 if (!isPow2(size) && (getWrapS() != GL_CLAMP_TO_EDGE || getWrapT() != GL_CLAMP_TO_EDGE))
1937 {
1938 return false;
1939 }
1940
1941 int q = log2(size);
1942
1943 for (int face = 0; face < 6; face++)
1944 {
1945 for (int level = 1; level <= q; level++)
1946 {
1947 if (mImageArray[face][level].format != mImageArray[0][0].format)
1948 {
1949 return false;
1950 }
1951
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00001952 if (mImageArray[face][level].type != mImageArray[0][0].type)
1953 {
1954 return false;
1955 }
1956
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001957 if (mImageArray[face][level].width != std::max(1, size >> level))
1958 {
1959 return false;
1960 }
1961
1962 ASSERT(mImageArray[face][level].height == mImageArray[face][level].width);
1963 }
1964 }
1965 }
1966
1967 return true;
1968}
1969
1970bool TextureCubeMap::isCompressed() const
1971{
1972 return IsCompressed(getInternalFormat());
1973}
1974
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001975IDirect3DBaseTexture9 *TextureCubeMap::getBaseTexture() const
1976{
1977 return mTexture;
1978}
1979
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001980// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001981void TextureCubeMap::createTexture()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001982{
1983 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com61208202011-03-21 16:38:50 +00001984 D3DFORMAT format = selectFormat(mImageArray[0][0].format, mImageArray[0][0].type);
1985 GLint levels = creationLevels(mImageArray[0][0].width, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001986
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00001987 IDirect3DCubeTexture9 *texture = NULL;
daniel@transgaming.com61208202011-03-21 16:38:50 +00001988 HRESULT result = device->CreateCubeTexture(mImageArray[0][0].width, levels, 0, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001989
1990 if (FAILED(result))
1991 {
1992 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001993 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001994 }
1995
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001996 if (mTexture)
1997 {
1998 mTexture->Release();
1999 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002000
2001 mTexture = texture;
daniel@transgaming.com38e76e52011-03-21 16:39:10 +00002002 mDirty = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00002003 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002004}
2005
2006void TextureCubeMap::updateTexture()
2007{
2008 IDirect3DDevice9 *device = getDevice();
2009
2010 for (int face = 0; face < 6; face++)
2011 {
2012 int levels = levelCount();
2013 for (int level = 0; level < levels; level++)
2014 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00002015 Image *image = &mImageArray[face][level];
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002016
daniel@transgaming.com61208202011-03-21 16:38:50 +00002017 if (image->surface && image->dirty)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002018 {
2019 IDirect3DSurface9 *levelSurface = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level);
2020 ASSERT(levelSurface != NULL);
2021
2022 if (levelSurface != NULL)
2023 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00002024 HRESULT result = device->UpdateSurface(image->surface, NULL, levelSurface, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002025 ASSERT(SUCCEEDED(result));
2026
2027 levelSurface->Release();
2028
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00002029 image->dirty = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002030 }
2031 }
2032 }
2033 }
2034}
2035
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002036void TextureCubeMap::convertToRenderTarget()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002037{
2038 IDirect3DCubeTexture9 *texture = NULL;
2039
daniel@transgaming.com61208202011-03-21 16:38:50 +00002040 if (mImageArray[0][0].width != 0)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002041 {
2042 egl::Display *display = getDisplay();
2043 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com61208202011-03-21 16:38:50 +00002044 D3DFORMAT format = selectFormat(mImageArray[0][0].format, mImageArray[0][0].type);
2045 GLint levels = creationLevels(mImageArray[0][0].width, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002046
daniel@transgaming.com61208202011-03-21 16:38:50 +00002047 HRESULT result = device->CreateCubeTexture(mImageArray[0][0].width, levels, D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002048
2049 if (FAILED(result))
2050 {
2051 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002052 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002053 }
2054
2055 if (mTexture != NULL)
2056 {
2057 int levels = levelCount();
2058 for (int f = 0; f < 6; f++)
2059 {
2060 for (int i = 0; i < levels; i++)
2061 {
2062 IDirect3DSurface9 *source;
2063 result = mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &source);
2064
2065 if (FAILED(result))
2066 {
2067 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2068
2069 texture->Release();
2070
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002071 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002072 }
2073
2074 IDirect3DSurface9 *dest;
2075 result = texture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &dest);
2076
2077 if (FAILED(result))
2078 {
2079 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2080
2081 texture->Release();
2082 source->Release();
2083
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002084 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002085 }
2086
2087 display->endScene();
2088 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
2089
2090 if (FAILED(result))
2091 {
2092 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2093
2094 texture->Release();
2095 source->Release();
2096 dest->Release();
2097
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002098 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002099 }
2100 }
2101 }
2102 }
2103 }
2104
2105 if (mTexture != NULL)
2106 {
2107 mTexture->Release();
2108 }
2109
2110 mTexture = texture;
daniel@transgaming.com38e76e52011-03-21 16:39:10 +00002111 mDirty = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00002112 mIsRenderable = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002113}
2114
daniel@transgaming.com61208202011-03-21 16:38:50 +00002115void 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 +00002116{
daniel@transgaming.com61208202011-03-21 16:38:50 +00002117 redefineTexture(faceIndex, level, format, width, height, type);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002118
daniel@transgaming.com61208202011-03-21 16:38:50 +00002119 Texture::setImage(unpackAlignment, pixels, &mImageArray[faceIndex][level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002120}
2121
2122unsigned int TextureCubeMap::faceIndex(GLenum face)
2123{
2124 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
2125 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
2126 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
2127 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
2128 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
2129
2130 return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
2131}
2132
daniel@transgaming.com61208202011-03-21 16:38:50 +00002133void TextureCubeMap::redefineTexture(int face, GLint level, GLenum format, GLsizei width, GLsizei height, GLenum type)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002134{
daniel@transgaming.com94a4f032011-03-21 16:38:55 +00002135 GLsizei textureWidth = mImageArray[0][0].width;
2136 GLsizei textureHeight = mImageArray[0][0].height;
2137 GLenum textureFormat = mImageArray[0][0].format;
2138 GLenum textureType = mImageArray[0][0].type;
2139
daniel@transgaming.com61208202011-03-21 16:38:50 +00002140 mImageArray[face][level].width = width;
2141 mImageArray[face][level].height = height;
2142 mImageArray[face][level].format = format;
2143 mImageArray[face][level].type = type;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002144
daniel@transgaming.com61208202011-03-21 16:38:50 +00002145 if (!mTexture)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002146 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00002147 return;
2148 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002149
daniel@transgaming.com94a4f032011-03-21 16:38:55 +00002150 bool sizeOkay = (textureWidth >> level == width);
2151 bool textureOkay = (sizeOkay && textureFormat == format && textureType == type);
daniel@transgaming.com61208202011-03-21 16:38:50 +00002152
2153 if (!textureOkay) // Purge all the levels and the texture.
2154 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002155 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
2156 {
2157 for (int f = 0; f < 6; f++)
2158 {
2159 if (mImageArray[f][i].surface != NULL)
2160 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002161 mImageArray[f][i].surface->Release();
2162 mImageArray[f][i].surface = NULL;
daniel@transgaming.com61208202011-03-21 16:38:50 +00002163 mImageArray[f][i].dirty = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002164 }
2165 }
2166 }
2167
2168 if (mTexture != NULL)
2169 {
2170 mTexture->Release();
2171 mTexture = NULL;
daniel@transgaming.com38e76e52011-03-21 16:39:10 +00002172 mDirty = true;
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002173 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002174 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002175 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002176}
2177
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002178void 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 +00002179{
2180 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
2181
2182 if (!renderTarget)
2183 {
2184 ERR("Failed to retrieve the render target.");
2185 return error(GL_OUT_OF_MEMORY);
2186 }
2187
2188 unsigned int faceindex = faceIndex(target);
daniel@transgaming.com61208202011-03-21 16:38:50 +00002189 redefineTexture(faceindex, level, format, width, height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002190
daniel@transgaming.comf4e36032011-03-21 16:38:59 +00002191 if (!isRenderableFormat() || (!mTexture && !isComplete()))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002192 {
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002193 copyNonRenderable(&mImageArray[faceindex][level], format, 0, 0, x, y, width, height, renderTarget);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002194 }
2195 else
2196 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00002197 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002198 {
2199 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002200 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00002201
2202 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002203
2204 ASSERT(width == height);
2205
2206 if (width > 0 && level < levelCount())
2207 {
2208 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
2209 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
2210 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
2211 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
2212 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
2213
2214 IDirect3DSurface9 *dest = getCubeMapSurface(target, level);
2215
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002216 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, format, 0, 0, dest);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002217 dest->Release();
2218 }
2219 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002220}
2221
2222IDirect3DSurface9 *TextureCubeMap::getCubeMapSurface(GLenum face, unsigned int level)
2223{
2224 if (mTexture == NULL)
2225 {
2226 UNREACHABLE();
2227 return NULL;
2228 }
2229
2230 IDirect3DSurface9 *surface = NULL;
2231
2232 HRESULT hr = mTexture->GetCubeMapSurface(es2dx::ConvertCubeFace(face), level, &surface);
2233
2234 return (SUCCEEDED(hr)) ? surface : NULL;
2235}
2236
2237void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
2238{
2239 GLsizei size = mImageArray[faceIndex(target)][level].width;
2240
2241 if (xoffset + width > size || yoffset + height > size)
2242 {
2243 return error(GL_INVALID_VALUE);
2244 }
2245
2246 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
2247
2248 if (!renderTarget)
2249 {
2250 ERR("Failed to retrieve the render target.");
2251 return error(GL_OUT_OF_MEMORY);
2252 }
2253
2254 unsigned int faceindex = faceIndex(target);
daniel@transgaming.com61208202011-03-21 16:38:50 +00002255 redefineTexture(0, 0, mImageArray[0][0].format, mImageArray[0][0].width, mImageArray[0][0].height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002256
2257 if (!isRenderableFormat())
2258 {
2259 copyNonRenderable(&mImageArray[faceindex][level], getInternalFormat(), 0, 0, x, y, width, height, renderTarget);
2260 }
2261 else
2262 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00002263 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002264 {
2265 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002266 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00002267
2268 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002269
2270 if (level < levelCount())
2271 {
2272 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
2273 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
2274 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
2275 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
2276 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
2277
2278 GLint destYOffset = transformPixelYOffset(yoffset, height, mImageArray[faceindex][level].width);
2279
2280 IDirect3DSurface9 *dest = getCubeMapSurface(target, level);
2281
2282 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0][0].format, xoffset, destYOffset, dest);
2283 dest->Release();
2284 }
2285 }
2286}
2287
2288bool TextureCubeMap::isCubeComplete() const
2289{
2290 if (mImageArray[0][0].width == 0)
2291 {
2292 return false;
2293 }
2294
2295 for (unsigned int f = 1; f < 6; f++)
2296 {
2297 if (mImageArray[f][0].width != mImageArray[0][0].width
2298 || mImageArray[f][0].format != mImageArray[0][0].format)
2299 {
2300 return false;
2301 }
2302 }
2303
2304 return true;
2305}
2306
2307void TextureCubeMap::generateMipmaps()
2308{
2309 if (!isPow2(mImageArray[0][0].width) || !isCubeComplete())
2310 {
2311 return error(GL_INVALID_OPERATION);
2312 }
2313
2314 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
2315 unsigned int q = log2(mImageArray[0][0].width);
2316 for (unsigned int f = 0; f < 6; f++)
2317 {
2318 for (unsigned int i = 1; i <= q; i++)
2319 {
2320 if (mImageArray[f][i].surface != NULL)
2321 {
2322 mImageArray[f][i].surface->Release();
2323 mImageArray[f][i].surface = NULL;
2324 }
2325
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002326 mImageArray[f][i].width = std::max(mImageArray[f][0].width >> i, 1);
2327 mImageArray[f][i].height = mImageArray[f][i].width;
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00002328 mImageArray[f][i].format = mImageArray[f][0].format;
2329 mImageArray[f][i].type = mImageArray[f][0].type;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002330 }
2331 }
2332
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002333 if (mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002334 {
2335 if (mTexture == NULL)
2336 {
2337 return;
2338 }
2339
2340 for (unsigned int f = 0; f < 6; f++)
2341 {
2342 for (unsigned int i = 1; i <= q; i++)
2343 {
2344 IDirect3DSurface9 *upper = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i-1);
2345 IDirect3DSurface9 *lower = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i);
2346
2347 if (upper != NULL && lower != NULL)
2348 {
2349 getBlitter()->boxFilter(upper, lower);
2350 }
2351
2352 if (upper != NULL) upper->Release();
2353 if (lower != NULL) lower->Release();
daniel@transgaming.com61208202011-03-21 16:38:50 +00002354
2355 mImageArray[f][i].dirty = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002356 }
2357 }
2358 }
2359 else
2360 {
2361 for (unsigned int f = 0; f < 6; f++)
2362 {
2363 for (unsigned int i = 1; i <= q; i++)
2364 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00002365 createSurface(&mImageArray[f][i]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002366 if (mImageArray[f][i].surface == NULL)
2367 {
2368 return error(GL_OUT_OF_MEMORY);
2369 }
2370
2371 if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[f][i].surface, NULL, NULL, mImageArray[f][i - 1].surface, NULL, NULL, D3DX_FILTER_BOX, 0)))
2372 {
2373 ERR(" failed to load filter %d to %d.", i - 1, i);
2374 }
2375
2376 mImageArray[f][i].dirty = true;
2377 }
2378 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002379 }
2380}
2381
2382Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target)
2383{
2384 if (!IsCubemapTextureTarget(target))
2385 {
2386 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
2387 }
2388
2389 unsigned int face = faceIndex(target);
2390
2391 if (mFaceProxies[face].get() == NULL)
2392 {
2393 mFaceProxies[face].set(new Renderbuffer(id(), new Colorbuffer(this, target)));
2394 }
2395
2396 return mFaceProxies[face].get();
2397}
2398
2399IDirect3DSurface9 *TextureCubeMap::getRenderTarget(GLenum target)
2400{
2401 ASSERT(IsCubemapTextureTarget(target));
2402
daniel@transgaming.com61208202011-03-21 16:38:50 +00002403 if (!mIsRenderable)
2404 {
2405 convertToRenderTarget();
2406 }
2407
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002408 if (mTexture == NULL)
2409 {
2410 return NULL;
2411 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00002412
2413 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002414
2415 IDirect3DSurface9 *renderTarget = NULL;
2416 mTexture->GetCubeMapSurface(es2dx::ConvertCubeFace(target), 0, &renderTarget);
2417
2418 return renderTarget;
2419}
2420
2421}