blob: e9149e14d8b1d8ff38b1b69b4e6a303806727375 [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.coma06aa872011-03-21 17:22:21 +000048 mDirtyParameter = true;
49
50 mDirtyImage = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +000051
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +000052 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +000053}
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;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +000080 mDirtyParameter = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +000081 }
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;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +0000100 mDirtyParameter = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000101 }
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;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +0000121 mDirtyParameter = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000122 }
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;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +0000142 mDirtyParameter = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000143 }
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
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000171bool Texture::isRenderableFormat() const
172{
173 D3DFORMAT format = getD3DFormat();
174
175 switch(format)
176 {
177 case D3DFMT_L8:
178 case D3DFMT_A8L8:
179 case D3DFMT_DXT1:
180 return false;
181 case D3DFMT_A8R8G8B8:
182 case D3DFMT_X8R8G8B8:
183 case D3DFMT_A16B16G16R16F:
184 case D3DFMT_A32B32G32R32F:
185 return true;
186 default:
187 UNREACHABLE();
188 }
189
190 return false;
191}
192
193// Selects an internal Direct3D 9 format for storing an Image
194D3DFORMAT Texture::selectFormat(GLenum format, GLenum type)
195{
196 if (format == GL_COMPRESSED_RGB_S3TC_DXT1_EXT ||
197 format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT)
198 {
199 return D3DFMT_DXT1;
200 }
201 else if (type == GL_FLOAT)
202 {
203 return D3DFMT_A32B32G32R32F;
204 }
205 else if (type == GL_HALF_FLOAT_OES)
206 {
207 return D3DFMT_A16B16G16R16F;
208 }
209 else if (type == GL_UNSIGNED_BYTE)
210 {
211 if (format == GL_LUMINANCE && getContext()->supportsLuminanceTextures())
212 {
213 return D3DFMT_L8;
214 }
215 else if (format == GL_LUMINANCE_ALPHA && getContext()->supportsLuminanceAlphaTextures())
216 {
217 return D3DFMT_A8L8;
218 }
219 else if (format == GL_RGB)
220 {
221 return D3DFMT_X8R8G8B8;
222 }
223
224 return D3DFMT_A8R8G8B8;
225 }
226
227 return D3DFMT_A8R8G8B8;
228}
229
230// Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input
231// into the target pixel rectangle at output with outputPitch bytes in between each line.
232void Texture::loadImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type,
233 GLint unpackAlignment, const void *input, size_t outputPitch, void *output, D3DSURFACE_DESC *description) const
234{
235 GLsizei inputPitch = -ComputePitch(width, format, type, unpackAlignment);
236 input = ((char*)input) - inputPitch * (height - 1);
237
238 switch (type)
239 {
240 case GL_UNSIGNED_BYTE:
241 switch (format)
242 {
243 case GL_ALPHA:
244 loadAlphaImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
245 break;
246 case GL_LUMINANCE:
247 loadLuminanceImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output, description->Format == D3DFMT_L8);
248 break;
249 case GL_LUMINANCE_ALPHA:
250 loadLuminanceAlphaImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output, description->Format == D3DFMT_A8L8);
251 break;
252 case GL_RGB:
253 loadRGBUByteImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
254 break;
255 case GL_RGBA:
256 loadRGBAUByteImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
257 break;
258 case GL_BGRA_EXT:
259 loadBGRAImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
260 break;
261 default: UNREACHABLE();
262 }
263 break;
264 case GL_UNSIGNED_SHORT_5_6_5:
265 switch (format)
266 {
267 case GL_RGB:
268 loadRGB565ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
269 break;
270 default: UNREACHABLE();
271 }
272 break;
273 case GL_UNSIGNED_SHORT_4_4_4_4:
274 switch (format)
275 {
276 case GL_RGBA:
277 loadRGBA4444ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
278 break;
279 default: UNREACHABLE();
280 }
281 break;
282 case GL_UNSIGNED_SHORT_5_5_5_1:
283 switch (format)
284 {
285 case GL_RGBA:
286 loadRGBA5551ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
287 break;
288 default: UNREACHABLE();
289 }
290 break;
291 case GL_FLOAT:
292 switch (format)
293 {
294 // float textures are converted to RGBA, not BGRA, as they're stored that way in D3D
295 case GL_ALPHA:
296 loadAlphaFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
297 break;
298 case GL_LUMINANCE:
299 loadLuminanceFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
300 break;
301 case GL_LUMINANCE_ALPHA:
302 loadLuminanceAlphaFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
303 break;
304 case GL_RGB:
305 loadRGBFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
306 break;
307 case GL_RGBA:
308 loadRGBAFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
309 break;
310 default: UNREACHABLE();
311 }
312 break;
313 case GL_HALF_FLOAT_OES:
314 switch (format)
315 {
316 // float textures are converted to RGBA, not BGRA, as they're stored that way in D3D
317 case GL_ALPHA:
318 loadAlphaHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
319 break;
320 case GL_LUMINANCE:
321 loadLuminanceHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
322 break;
323 case GL_LUMINANCE_ALPHA:
324 loadLuminanceAlphaHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
325 break;
326 case GL_RGB:
327 loadRGBHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
328 break;
329 case GL_RGBA:
330 loadRGBAHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
331 break;
332 default: UNREACHABLE();
333 }
334 break;
335 default: UNREACHABLE();
336 }
337}
338
339void Texture::loadAlphaImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
340 int inputPitch, const void *input, size_t outputPitch, void *output) const
341{
342 const unsigned char *source = NULL;
343 unsigned char *dest = NULL;
344
345 for (int y = 0; y < height; y++)
346 {
347 source = static_cast<const unsigned char*>(input) + y * inputPitch;
348 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
349 for (int x = 0; x < width; x++)
350 {
351 dest[4 * x + 0] = 0;
352 dest[4 * x + 1] = 0;
353 dest[4 * x + 2] = 0;
354 dest[4 * x + 3] = source[x];
355 }
356 }
357}
358
359void Texture::loadAlphaFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
360 int inputPitch, const void *input, size_t outputPitch, void *output) const
361{
362 const float *source = NULL;
363 float *dest = NULL;
364
365 for (int y = 0; y < height; y++)
366 {
367 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
368 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
369 for (int x = 0; x < width; x++)
370 {
371 dest[4 * x + 0] = 0;
372 dest[4 * x + 1] = 0;
373 dest[4 * x + 2] = 0;
374 dest[4 * x + 3] = source[x];
375 }
376 }
377}
378
379void Texture::loadAlphaHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
380 int inputPitch, const void *input, size_t outputPitch, void *output) const
381{
382 const unsigned short *source = NULL;
383 unsigned short *dest = NULL;
384
385 for (int y = 0; y < height; y++)
386 {
387 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
388 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
389 for (int x = 0; x < width; x++)
390 {
391 dest[4 * x + 0] = 0;
392 dest[4 * x + 1] = 0;
393 dest[4 * x + 2] = 0;
394 dest[4 * x + 3] = source[x];
395 }
396 }
397}
398
399void Texture::loadLuminanceImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
400 int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const
401{
402 const int destBytesPerPixel = native? 1: 4;
403 const unsigned char *source = NULL;
404 unsigned char *dest = NULL;
405
406 for (int y = 0; y < height; y++)
407 {
408 source = static_cast<const unsigned char*>(input) + y * inputPitch;
409 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * destBytesPerPixel;
410
411 if (!native) // BGRA8 destination format
412 {
413 for (int x = 0; x < width; x++)
414 {
415 dest[4 * x + 0] = source[x];
416 dest[4 * x + 1] = source[x];
417 dest[4 * x + 2] = source[x];
418 dest[4 * x + 3] = 0xFF;
419 }
420 }
421 else // L8 destination format
422 {
423 memcpy(dest, source, width);
424 }
425 }
426}
427
428void Texture::loadLuminanceFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
429 int inputPitch, const void *input, size_t outputPitch, void *output) const
430{
431 const float *source = NULL;
432 float *dest = NULL;
433
434 for (int y = 0; y < height; y++)
435 {
436 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
437 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
438 for (int x = 0; x < width; x++)
439 {
440 dest[4 * x + 0] = source[x];
441 dest[4 * x + 1] = source[x];
442 dest[4 * x + 2] = source[x];
443 dest[4 * x + 3] = 1.0f;
444 }
445 }
446}
447
448void Texture::loadLuminanceHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
449 int inputPitch, const void *input, size_t outputPitch, void *output) const
450{
451 const unsigned short *source = NULL;
452 unsigned short *dest = NULL;
453
454 for (int y = 0; y < height; y++)
455 {
456 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
457 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
458 for (int x = 0; x < width; x++)
459 {
460 dest[4 * x + 0] = source[x];
461 dest[4 * x + 1] = source[x];
462 dest[4 * x + 2] = source[x];
463 dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1
464 }
465 }
466}
467
468void Texture::loadLuminanceAlphaImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
469 int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const
470{
471 const int destBytesPerPixel = native? 2: 4;
472 const unsigned char *source = NULL;
473 unsigned char *dest = NULL;
474
475 for (int y = 0; y < height; y++)
476 {
477 source = static_cast<const unsigned char*>(input) + y * inputPitch;
478 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * destBytesPerPixel;
479
480 if (!native) // BGRA8 destination format
481 {
482 for (int x = 0; x < width; x++)
483 {
484 dest[4 * x + 0] = source[2*x+0];
485 dest[4 * x + 1] = source[2*x+0];
486 dest[4 * x + 2] = source[2*x+0];
487 dest[4 * x + 3] = source[2*x+1];
488 }
489 }
490 else
491 {
492 memcpy(dest, source, width * 2);
493 }
494 }
495}
496
497void Texture::loadLuminanceAlphaFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
498 int inputPitch, const void *input, size_t outputPitch, void *output) const
499{
500 const float *source = NULL;
501 float *dest = NULL;
502
503 for (int y = 0; y < height; y++)
504 {
505 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
506 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
507 for (int x = 0; x < width; x++)
508 {
509 dest[4 * x + 0] = source[2*x+0];
510 dest[4 * x + 1] = source[2*x+0];
511 dest[4 * x + 2] = source[2*x+0];
512 dest[4 * x + 3] = source[2*x+1];
513 }
514 }
515}
516
517void Texture::loadLuminanceAlphaHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
518 int inputPitch, const void *input, size_t outputPitch, void *output) const
519{
520 const unsigned short *source = NULL;
521 unsigned short *dest = NULL;
522
523 for (int y = 0; y < height; y++)
524 {
525 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
526 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
527 for (int x = 0; x < width; x++)
528 {
529 dest[4 * x + 0] = source[2*x+0];
530 dest[4 * x + 1] = source[2*x+0];
531 dest[4 * x + 2] = source[2*x+0];
532 dest[4 * x + 3] = source[2*x+1];
533 }
534 }
535}
536
537void Texture::loadRGBUByteImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
538 int inputPitch, const void *input, size_t outputPitch, void *output) const
539{
540 const unsigned char *source = NULL;
541 unsigned char *dest = NULL;
542
543 for (int y = 0; y < height; y++)
544 {
545 source = static_cast<const unsigned char*>(input) + y * inputPitch;
546 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
547 for (int x = 0; x < width; x++)
548 {
549 dest[4 * x + 0] = source[x * 3 + 2];
550 dest[4 * x + 1] = source[x * 3 + 1];
551 dest[4 * x + 2] = source[x * 3 + 0];
552 dest[4 * x + 3] = 0xFF;
553 }
554 }
555}
556
557void Texture::loadRGB565ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
558 int inputPitch, const void *input, size_t outputPitch, void *output) const
559{
560 const unsigned short *source = NULL;
561 unsigned char *dest = NULL;
562
563 for (int y = 0; y < height; y++)
564 {
565 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
566 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
567 for (int x = 0; x < width; x++)
568 {
569 unsigned short rgba = source[x];
570 dest[4 * x + 0] = ((rgba & 0x001F) << 3) | ((rgba & 0x001F) >> 2);
571 dest[4 * x + 1] = ((rgba & 0x07E0) >> 3) | ((rgba & 0x07E0) >> 9);
572 dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
573 dest[4 * x + 3] = 0xFF;
574 }
575 }
576}
577
578void Texture::loadRGBFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
579 int inputPitch, const void *input, size_t outputPitch, void *output) const
580{
581 const float *source = NULL;
582 float *dest = NULL;
583
584 for (int y = 0; y < height; y++)
585 {
586 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
587 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
588 for (int x = 0; x < width; x++)
589 {
590 dest[4 * x + 0] = source[x * 3 + 0];
591 dest[4 * x + 1] = source[x * 3 + 1];
592 dest[4 * x + 2] = source[x * 3 + 2];
593 dest[4 * x + 3] = 1.0f;
594 }
595 }
596}
597
598void Texture::loadRGBHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
599 int inputPitch, const void *input, size_t outputPitch, void *output) const
600{
601 const unsigned short *source = NULL;
602 unsigned short *dest = NULL;
603
604 for (int y = 0; y < height; y++)
605 {
606 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
607 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
608 for (int x = 0; x < width; x++)
609 {
610 dest[4 * x + 0] = source[x * 3 + 0];
611 dest[4 * x + 1] = source[x * 3 + 1];
612 dest[4 * x + 2] = source[x * 3 + 2];
613 dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1
614 }
615 }
616}
617
618void Texture::loadRGBAUByteImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
619 int inputPitch, const void *input, size_t outputPitch, void *output) const
620{
621 const unsigned char *source = NULL;
622 unsigned char *dest = NULL;
623
624 for (int y = 0; y < height; y++)
625 {
626 source = static_cast<const unsigned char*>(input) + y * inputPitch;
627 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
628 for (int x = 0; x < width; x++)
629 {
630 dest[4 * x + 0] = source[x * 4 + 2];
631 dest[4 * x + 1] = source[x * 4 + 1];
632 dest[4 * x + 2] = source[x * 4 + 0];
633 dest[4 * x + 3] = source[x * 4 + 3];
634 }
635 }
636}
637
638void Texture::loadRGBA4444ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
639 int inputPitch, const void *input, size_t outputPitch, void *output) const
640{
641 const unsigned short *source = NULL;
642 unsigned char *dest = NULL;
643
644 for (int y = 0; y < height; y++)
645 {
646 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
647 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
648 for (int x = 0; x < width; x++)
649 {
650 unsigned short rgba = source[x];
651 dest[4 * x + 0] = ((rgba & 0x00F0) << 0) | ((rgba & 0x00F0) >> 4);
652 dest[4 * x + 1] = ((rgba & 0x0F00) >> 4) | ((rgba & 0x0F00) >> 8);
653 dest[4 * x + 2] = ((rgba & 0xF000) >> 8) | ((rgba & 0xF000) >> 12);
654 dest[4 * x + 3] = ((rgba & 0x000F) << 4) | ((rgba & 0x000F) >> 0);
655 }
656 }
657}
658
659void Texture::loadRGBA5551ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
660 int inputPitch, const void *input, size_t outputPitch, void *output) const
661{
662 const unsigned short *source = NULL;
663 unsigned char *dest = NULL;
664
665 for (int y = 0; y < height; y++)
666 {
667 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
668 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
669 for (int x = 0; x < width; x++)
670 {
671 unsigned short rgba = source[x];
672 dest[4 * x + 0] = ((rgba & 0x003E) << 2) | ((rgba & 0x003E) >> 3);
673 dest[4 * x + 1] = ((rgba & 0x07C0) >> 3) | ((rgba & 0x07C0) >> 8);
674 dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
675 dest[4 * x + 3] = (rgba & 0x0001) ? 0xFF : 0;
676 }
677 }
678}
679
680void Texture::loadRGBAFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
681 int inputPitch, const void *input, size_t outputPitch, void *output) const
682{
683 const float *source = NULL;
684 float *dest = NULL;
685
686 for (int y = 0; y < height; y++)
687 {
688 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
689 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
690 memcpy(dest, source, width * 16);
691 }
692}
693
694void Texture::loadRGBAHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
695 int inputPitch, const void *input, size_t outputPitch, void *output) const
696{
697 const unsigned char *source = NULL;
698 unsigned char *dest = NULL;
699
700 for (int y = 0; y < height; y++)
701 {
702 source = static_cast<const unsigned char*>(input) + y * inputPitch;
703 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8;
704 memcpy(dest, source, width * 8);
705 }
706}
707
708void Texture::loadBGRAImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
709 int inputPitch, const void *input, size_t outputPitch, void *output) const
710{
711 const unsigned char *source = NULL;
712 unsigned char *dest = NULL;
713
714 for (int y = 0; y < height; y++)
715 {
716 source = static_cast<const unsigned char*>(input) + y * inputPitch;
717 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
718 memcpy(dest, source, width*4);
719 }
720}
721
722void Texture::loadCompressedImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
723 int inputPitch, const void *input, size_t outputPitch, void *output) const
724{
725 ASSERT(xoffset % 4 == 0);
726 ASSERT(yoffset % 4 == 0);
727 ASSERT(width % 4 == 0 || width == 2 || width == 1);
728 ASSERT(inputPitch % 8 == 0);
729 ASSERT(outputPitch % 8 == 0);
730
731 const unsigned int *source = reinterpret_cast<const unsigned int*>(input);
732 unsigned int *dest = reinterpret_cast<unsigned int*>(output);
733
734 switch (height)
735 {
736 case 1:
737 // Round width up in case it is 1.
738 for (int x = 0; x < (width + 1) / 2; x += 2)
739 {
740 // First 32-bits is two RGB565 colors shared by tile and does not need to be modified.
741 dest[x] = source[x];
742
743 // Second 32-bits contains 4 rows of 4 2-bit interpolants between the colors, the last 3 rows being unused. No flipping should occur.
744 dest[x + 1] = source[x + 1];
745 }
746 break;
747 case 2:
748 // Round width up in case it is 1.
749 for (int x = 0; x < (width + 1) / 2; x += 2)
750 {
751 // First 32-bits is two RGB565 colors shared by tile and does not need to be modified.
752 dest[x] = source[x];
753
754 // 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.
755 dest[x + 1] = ((source[x + 1] << 8) & 0x0000FF00) |
756 ((source[x + 1] >> 8) & 0x000000FF);
757 }
758 break;
759 default:
760 ASSERT(height % 4 == 0);
761 for (int y = 0; y < height / 4; ++y)
762 {
763 const unsigned int *source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);
764 unsigned int *dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
765
766 // Round width up in case it is 1.
767 for (int x = 0; x < (width + 1) / 2; x += 2)
768 {
769 // First 32-bits is two RGB565 colors shared by tile and does not need to be modified.
770 dest[x] = source[x];
771
772 // Second 32-bits contains 4 rows of 4 2-bit interpolants between the colors. All rows should be flipped.
773 dest[x + 1] = (source[x + 1] >> 24) |
774 ((source[x + 1] << 8) & 0x00FF0000) |
775 ((source[x + 1] >> 8) & 0x0000FF00) |
776 (source[x + 1] << 24);
777 }
778 }
779 break;
780 }
781}
782
daniel@transgaming.com61208202011-03-21 16:38:50 +0000783void Texture::createSurface(Image *image)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000784{
785 IDirect3DTexture9 *newTexture = NULL;
786 IDirect3DSurface9 *newSurface = NULL;
787
daniel@transgaming.com61208202011-03-21 16:38:50 +0000788 if (image->width != 0 && image->height != 0)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000789 {
790 int levelToFetch = 0;
daniel@transgaming.com61208202011-03-21 16:38:50 +0000791 GLsizei requestWidth = image->width;
792 GLsizei requestHeight = image->height;
793 if (IsCompressed(image->format) && (image->width % 4 != 0 || image->height % 4 != 0))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000794 {
795 bool isMult4 = false;
796 int upsampleCount = 0;
797 while (!isMult4)
798 {
799 requestWidth <<= 1;
800 requestHeight <<= 1;
801 upsampleCount++;
802 if (requestWidth % 4 == 0 && requestHeight % 4 == 0)
803 {
804 isMult4 = true;
805 }
806 }
807 levelToFetch = upsampleCount;
808 }
809
daniel@transgaming.com61208202011-03-21 16:38:50 +0000810 HRESULT result = getDevice()->CreateTexture(requestWidth, requestHeight, levelToFetch + 1, NULL, selectFormat(image->format, image->type),
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000811 D3DPOOL_SYSTEMMEM, &newTexture, NULL);
812
813 if (FAILED(result))
814 {
815 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
816 return error(GL_OUT_OF_MEMORY);
817 }
818
819 newTexture->GetSurfaceLevel(levelToFetch, &newSurface);
820 newTexture->Release();
821 }
822
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +0000823 if (image->surface)
824 {
825 image->surface->Release();
826 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000827
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +0000828 image->surface = newSurface;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000829}
830
daniel@transgaming.com61208202011-03-21 16:38:50 +0000831void Texture::setImage(GLint unpackAlignment, const void *pixels, Image *image)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000832{
daniel@transgaming.com61208202011-03-21 16:38:50 +0000833 createSurface(image);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000834
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000835 if (pixels != NULL && image->surface != NULL)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000836 {
837 D3DSURFACE_DESC description;
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000838 image->surface->GetDesc(&description);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000839
840 D3DLOCKED_RECT locked;
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000841 HRESULT result = image->surface->LockRect(&locked, NULL, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000842
843 ASSERT(SUCCEEDED(result));
844
845 if (SUCCEEDED(result))
846 {
daniel@transgaming.com61208202011-03-21 16:38:50 +0000847 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 +0000848 image->surface->UnlockRect();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000849 }
850
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000851 image->dirty = true;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +0000852 mDirtyImage = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000853 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000854}
855
daniel@transgaming.com61208202011-03-21 16:38:50 +0000856void Texture::setCompressedImage(GLsizei imageSize, const void *pixels, Image *image)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000857{
daniel@transgaming.com61208202011-03-21 16:38:50 +0000858 createSurface(image);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000859
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000860 if (pixels != NULL && image->surface != NULL)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000861 {
862 D3DLOCKED_RECT locked;
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000863 HRESULT result = image->surface->LockRect(&locked, NULL, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000864
865 ASSERT(SUCCEEDED(result));
866
867 if (SUCCEEDED(result))
868 {
daniel@transgaming.com61208202011-03-21 16:38:50 +0000869 int inputPitch = ComputeCompressedPitch(image->width, image->format);
870 int inputSize = ComputeCompressedSize(image->width, image->height, image->format);
871 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 +0000872 image->surface->UnlockRect();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000873 }
874
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000875 image->dirty = true;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +0000876 mDirtyImage = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000877 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000878}
879
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000880bool 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 +0000881{
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000882 if (width + xoffset > image->width || height + yoffset > image->height)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000883 {
884 error(GL_INVALID_VALUE);
885 return false;
886 }
887
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000888 if (!image->surface)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000889 {
daniel@transgaming.com61208202011-03-21 16:38:50 +0000890 createSurface(image);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000891 }
892
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000893 if (pixels != NULL && image->surface != NULL)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000894 {
895 D3DSURFACE_DESC description;
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000896 image->surface->GetDesc(&description);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000897
898 D3DLOCKED_RECT locked;
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000899 HRESULT result = image->surface->LockRect(&locked, NULL, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000900
901 ASSERT(SUCCEEDED(result));
902
903 if (SUCCEEDED(result))
904 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000905 loadImageData(xoffset, transformPixelYOffset(yoffset, height, image->height), width, height, format, type, unpackAlignment, pixels, locked.Pitch, locked.pBits, &description);
906 image->surface->UnlockRect();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000907 }
908
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000909 image->dirty = true;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +0000910 mDirtyImage = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000911 }
912
913 return true;
914}
915
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000916bool 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 +0000917{
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000918 if (width + xoffset > image->width || height + yoffset > image->height)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000919 {
920 error(GL_INVALID_VALUE);
921 return false;
922 }
923
924 if (format != getInternalFormat())
925 {
926 error(GL_INVALID_OPERATION);
927 return false;
928 }
929
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000930 if (!image->surface)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000931 {
daniel@transgaming.com61208202011-03-21 16:38:50 +0000932 createSurface(image);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000933 }
934
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000935 if (pixels != NULL && image->surface != NULL)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000936 {
937 RECT updateRegion;
938 updateRegion.left = xoffset;
939 updateRegion.right = xoffset + width;
940 updateRegion.bottom = yoffset + height;
941 updateRegion.top = yoffset;
942
943 D3DLOCKED_RECT locked;
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000944 HRESULT result = image->surface->LockRect(&locked, &updateRegion, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000945
946 ASSERT(SUCCEEDED(result));
947
948 if (SUCCEEDED(result))
949 {
950 int inputPitch = ComputeCompressedPitch(width, format);
951 int inputSize = ComputeCompressedSize(width, height, format);
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000952 loadCompressedImageData(xoffset, transformPixelYOffset(yoffset, height, image->height), width, height, -inputPitch, static_cast<const char*>(pixels) + inputSize - inputPitch, locked.Pitch, locked.pBits);
953 image->surface->UnlockRect();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000954 }
955
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000956 image->dirty = true;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +0000957 mDirtyImage = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000958 }
959
960 return true;
961}
962
963// This implements glCopyTex[Sub]Image2D for non-renderable internal texture formats
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +0000964void 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 +0000965{
966 IDirect3DDevice9 *device = getDevice();
967 IDirect3DSurface9 *surface = NULL;
968 D3DSURFACE_DESC description;
969 renderTarget->GetDesc(&description);
970
971 HRESULT result = device->CreateOffscreenPlainSurface(description.Width, description.Height, description.Format, D3DPOOL_SYSTEMMEM, &surface, NULL);
972
973 if (!SUCCEEDED(result))
974 {
975 ERR("Could not create matching destination surface.");
976 return error(GL_OUT_OF_MEMORY);
977 }
978
979 result = device->GetRenderTargetData(renderTarget, surface);
980
981 if (!SUCCEEDED(result))
982 {
983 ERR("GetRenderTargetData unexpectedly failed.");
984 surface->Release();
985 return error(GL_OUT_OF_MEMORY);
986 }
987
988 D3DLOCKED_RECT sourceLock = {0};
989 RECT sourceRect = transformPixelRect(x, y, width, height, description.Height);
990 result = surface->LockRect(&sourceLock, &sourceRect, 0);
991
992 if (FAILED(result))
993 {
994 ERR("Failed to lock the source surface (rectangle might be invalid).");
995 surface->UnlockRect();
996 surface->Release();
997 return error(GL_OUT_OF_MEMORY);
998 }
999
1000 if (!image->surface)
1001 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001002 createSurface(image);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001003 }
1004
1005 if (image->surface == NULL)
1006 {
1007 ERR("Failed to create an image surface.");
1008 surface->UnlockRect();
1009 surface->Release();
1010 return error(GL_OUT_OF_MEMORY);
1011 }
1012
1013 D3DLOCKED_RECT destLock = {0};
1014 int destYOffset = transformPixelYOffset(yoffset, height, image->height);
1015 RECT destRect = {xoffset, destYOffset, xoffset + width, destYOffset + height};
1016 result = image->surface->LockRect(&destLock, &destRect, 0);
1017
1018 if (FAILED(result))
1019 {
1020 ERR("Failed to lock the destination surface (rectangle might be invalid).");
1021 surface->UnlockRect();
1022 surface->Release();
1023 return error(GL_OUT_OF_MEMORY);
1024 }
1025
1026 if (destLock.pBits && sourceLock.pBits)
1027 {
1028 unsigned char *source = (unsigned char*)sourceLock.pBits;
1029 unsigned char *dest = (unsigned char*)destLock.pBits;
1030
1031 switch (description.Format)
1032 {
1033 case D3DFMT_X8R8G8B8:
1034 case D3DFMT_A8R8G8B8:
1035 switch(getD3DFormat())
1036 {
1037 case D3DFMT_L8:
1038 for(int y = 0; y < height; y++)
1039 {
1040 for(int x = 0; x < width; x++)
1041 {
1042 dest[x] = source[x * 4 + 2];
1043 }
1044
1045 source += sourceLock.Pitch;
1046 dest += destLock.Pitch;
1047 }
1048 break;
1049 case D3DFMT_A8L8:
1050 for(int y = 0; y < height; y++)
1051 {
1052 for(int x = 0; x < width; x++)
1053 {
1054 dest[x * 2 + 0] = source[x * 4 + 2];
1055 dest[x * 2 + 1] = source[x * 4 + 3];
1056 }
1057
1058 source += sourceLock.Pitch;
1059 dest += destLock.Pitch;
1060 }
1061 break;
1062 default:
1063 UNREACHABLE();
1064 }
1065 break;
1066 case D3DFMT_R5G6B5:
1067 switch(getD3DFormat())
1068 {
1069 case D3DFMT_L8:
1070 for(int y = 0; y < height; y++)
1071 {
1072 for(int x = 0; x < width; x++)
1073 {
1074 unsigned char red = source[x * 2 + 1] & 0xF8;
1075 dest[x] = red | (red >> 5);
1076 }
1077
1078 source += sourceLock.Pitch;
1079 dest += destLock.Pitch;
1080 }
1081 break;
1082 default:
1083 UNREACHABLE();
1084 }
1085 break;
1086 case D3DFMT_A1R5G5B5:
1087 switch(getD3DFormat())
1088 {
1089 case D3DFMT_L8:
1090 for(int y = 0; y < height; y++)
1091 {
1092 for(int x = 0; x < width; x++)
1093 {
1094 unsigned char red = source[x * 2 + 1] & 0x7C;
1095 dest[x] = (red << 1) | (red >> 4);
1096 }
1097
1098 source += sourceLock.Pitch;
1099 dest += destLock.Pitch;
1100 }
1101 break;
1102 case D3DFMT_A8L8:
1103 for(int y = 0; y < height; y++)
1104 {
1105 for(int x = 0; x < width; x++)
1106 {
1107 unsigned char red = source[x * 2 + 1] & 0x7C;
1108 dest[x * 2 + 0] = (red << 1) | (red >> 4);
1109 dest[x * 2 + 1] = (signed char)source[x * 2 + 1] >> 7;
1110 }
1111
1112 source += sourceLock.Pitch;
1113 dest += destLock.Pitch;
1114 }
1115 break;
1116 default:
1117 UNREACHABLE();
1118 }
1119 break;
1120 default:
1121 UNREACHABLE();
1122 }
1123
1124 image->dirty = true;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00001125 mDirtyImage = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001126 }
1127
1128 image->surface->UnlockRect();
1129 surface->UnlockRect();
1130 surface->Release();
1131}
1132
1133D3DFORMAT Texture::getD3DFormat() const
1134{
daniel@transgaming.com61208202011-03-21 16:38:50 +00001135 return selectFormat(getInternalFormat(), getType());
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001136}
1137
1138IDirect3DBaseTexture9 *Texture::getTexture()
1139{
1140 if (!isComplete())
1141 {
1142 return NULL;
1143 }
1144
daniel@transgaming.comaed18322011-03-21 16:38:13 +00001145 if (!getBaseTexture())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001146 {
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001147 createTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001148 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001149
daniel@transgaming.comc50edcb2011-03-21 16:38:40 +00001150 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001151
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001152 return getBaseTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001153}
1154
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00001155bool Texture::isDirtyParameter() const
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001156{
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00001157 return mDirtyParameter;
1158}
1159
1160bool Texture::isDirtyImage() const
1161{
1162 return mDirtyImage;
daniel@transgaming.com38e76e52011-03-21 16:39:10 +00001163}
1164
1165void Texture::resetDirty()
1166{
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00001167 mDirtyParameter = false;
1168 mDirtyImage = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001169}
1170
daniel@transgaming.coma9eb5da2011-03-21 16:39:16 +00001171unsigned int Texture::getSerial() const
1172{
1173 return mSerial;
1174}
1175
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001176GLint Texture::creationLevels(GLsizei width, GLsizei height, GLint maxlevel) const
1177{
1178 if (isPow2(width) && isPow2(height))
1179 {
1180 return maxlevel;
1181 }
1182 else
1183 {
1184 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
1185 return 1;
1186 }
1187}
1188
1189GLint Texture::creationLevels(GLsizei size, GLint maxlevel) const
1190{
1191 return creationLevels(size, size, maxlevel);
1192}
1193
1194int Texture::levelCount() const
1195{
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001196 return getBaseTexture() ? getBaseTexture()->GetLevelCount() : 0;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001197}
1198
daniel@transgaming.coma9eb5da2011-03-21 16:39:16 +00001199unsigned int Texture::issueSerial()
1200{
1201 return mCurrentSerial++;
1202}
1203
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001204Texture2D::Texture2D(GLuint id) : Texture(id)
1205{
1206 mTexture = NULL;
1207}
1208
1209Texture2D::~Texture2D()
1210{
1211 mColorbufferProxy.set(NULL);
1212
1213 if (mTexture)
1214 {
1215 mTexture->Release();
1216 mTexture = NULL;
1217 }
1218}
1219
1220GLenum Texture2D::getTarget() const
1221{
1222 return GL_TEXTURE_2D;
1223}
1224
daniel@transgaming.com61208202011-03-21 16:38:50 +00001225GLsizei Texture2D::getWidth() const
1226{
1227 return mImageArray[0].width;
1228}
1229
1230GLsizei Texture2D::getHeight() const
1231{
1232 return mImageArray[0].height;
1233}
1234
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001235GLenum Texture2D::getInternalFormat() const
1236{
1237 return mImageArray[0].format;
1238}
1239
daniel@transgaming.com61208202011-03-21 16:38:50 +00001240GLenum Texture2D::getType() const
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001241{
daniel@transgaming.com61208202011-03-21 16:38:50 +00001242 return mImageArray[0].type;
1243}
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001244
daniel@transgaming.com61208202011-03-21 16:38:50 +00001245void Texture2D::redefineTexture(GLint level, GLenum format, GLsizei width, GLsizei height, GLenum type)
1246{
daniel@transgaming.com94a4f032011-03-21 16:38:55 +00001247 GLsizei textureWidth = mImageArray[0].width;
1248 GLsizei textureHeight = mImageArray[0].height;
1249 GLenum textureFormat = mImageArray[0].format;
1250 GLenum textureType = mImageArray[0].type;
1251
daniel@transgaming.com61208202011-03-21 16:38:50 +00001252 mImageArray[level].width = width;
1253 mImageArray[level].height = height;
1254 mImageArray[level].format = format;
1255 mImageArray[level].type = type;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001256
daniel@transgaming.com61208202011-03-21 16:38:50 +00001257 if (!mTexture)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001258 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001259 return;
1260 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001261
daniel@transgaming.com94a4f032011-03-21 16:38:55 +00001262 bool widthOkay = (textureWidth >> level == width) || (textureWidth >> level == 0 && width == 1);
1263 bool heightOkay = (textureHeight >> level == height) || (textureHeight >> level == 0 && height == 1);
1264 bool textureOkay = (widthOkay && heightOkay && textureFormat == format && textureType == type);
daniel@transgaming.com61208202011-03-21 16:38:50 +00001265
1266 if (!textureOkay) // Purge all the levels and the texture.
1267 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001268 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1269 {
1270 if (mImageArray[i].surface != NULL)
1271 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001272 mImageArray[i].surface->Release();
1273 mImageArray[i].surface = NULL;
daniel@transgaming.com61208202011-03-21 16:38:50 +00001274 mImageArray[i].dirty = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001275 }
1276 }
1277
1278 if (mTexture != NULL)
1279 {
1280 mTexture->Release();
1281 mTexture = NULL;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00001282 mDirtyImage = true;
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001283 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001284 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001285 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001286}
1287
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001288void 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 +00001289{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001290 redefineTexture(level, format, width, height, type);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001291
daniel@transgaming.com61208202011-03-21 16:38:50 +00001292 Texture::setImage(unpackAlignment, pixels, &mImageArray[level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001293}
1294
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001295void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001296{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001297 redefineTexture(level, format, width, height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001298
daniel@transgaming.com61208202011-03-21 16:38:50 +00001299 Texture::setCompressedImage(imageSize, pixels, &mImageArray[level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001300}
1301
1302void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1303{
1304 ASSERT(mImageArray[level].surface != NULL);
1305
1306 if (level < levelCount())
1307 {
1308 IDirect3DSurface9 *destLevel = NULL;
1309 HRESULT result = mTexture->GetSurfaceLevel(level, &destLevel);
1310
1311 ASSERT(SUCCEEDED(result));
1312
1313 if (SUCCEEDED(result))
1314 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001315 Image *image = &mImageArray[level];
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001316
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001317 RECT sourceRect = transformPixelRect(xoffset, yoffset, width, height, image->height);;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001318
1319 POINT destPoint;
1320 destPoint.x = sourceRect.left;
1321 destPoint.y = sourceRect.top;
1322
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001323 result = getDevice()->UpdateSurface(image->surface, &sourceRect, destLevel, &destPoint);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001324 ASSERT(SUCCEEDED(result));
1325
1326 destLevel->Release();
1327
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001328 image->dirty = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001329 }
1330 }
1331}
1332
1333void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1334{
1335 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[level]))
1336 {
1337 commitRect(level, xoffset, yoffset, width, height);
1338 }
1339}
1340
1341void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1342{
1343 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[level]))
1344 {
1345 commitRect(level, xoffset, yoffset, width, height);
1346 }
1347}
1348
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001349void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001350{
1351 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
1352
1353 if (!renderTarget)
1354 {
1355 ERR("Failed to retrieve the render target.");
1356 return error(GL_OUT_OF_MEMORY);
1357 }
1358
daniel@transgaming.com61208202011-03-21 16:38:50 +00001359 redefineTexture(level, format, width, height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001360
1361 if (!isRenderableFormat())
1362 {
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001363 copyNonRenderable(&mImageArray[level], format, 0, 0, x, y, width, height, renderTarget);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001364 }
1365 else
1366 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001367 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001368 {
1369 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001370 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00001371
1372 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001373
1374 if (width != 0 && height != 0 && level < levelCount())
1375 {
1376 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
1377 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
1378 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
1379 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
1380 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
1381
1382 IDirect3DSurface9 *dest;
1383 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
1384
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001385 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, format, 0, 0, dest);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001386 dest->Release();
1387 }
1388 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001389}
1390
1391void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1392{
1393 if (xoffset + width > mImageArray[level].width || yoffset + height > mImageArray[level].height)
1394 {
1395 return error(GL_INVALID_VALUE);
1396 }
1397
1398 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
1399
1400 if (!renderTarget)
1401 {
1402 ERR("Failed to retrieve the render target.");
1403 return error(GL_OUT_OF_MEMORY);
1404 }
1405
daniel@transgaming.com61208202011-03-21 16:38:50 +00001406 redefineTexture(0, mImageArray[0].format, mImageArray[0].width, mImageArray[0].height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001407
daniel@transgaming.comf4e36032011-03-21 16:38:59 +00001408 if (!isRenderableFormat() || (!mTexture && !isComplete()))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001409 {
1410 copyNonRenderable(&mImageArray[level], getInternalFormat(), xoffset, yoffset, x, y, width, height, renderTarget);
1411 }
1412 else
1413 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001414 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001415 {
1416 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001417 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00001418
1419 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001420
1421 if (level < levelCount())
1422 {
1423 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
1424 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
1425 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
1426 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
1427 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
1428
1429 GLint destYOffset = transformPixelYOffset(yoffset, height, mImageArray[level].height);
1430
1431 IDirect3DSurface9 *dest;
1432 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
1433
1434 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0].format, xoffset, destYOffset, dest);
1435 dest->Release();
1436 }
1437 }
1438}
1439
1440// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1441bool Texture2D::isComplete() const
1442{
1443 GLsizei width = mImageArray[0].width;
1444 GLsizei height = mImageArray[0].height;
1445
1446 if (width <= 0 || height <= 0)
1447 {
1448 return false;
1449 }
1450
1451 bool mipmapping = false;
1452
1453 switch (mMinFilter)
1454 {
1455 case GL_NEAREST:
1456 case GL_LINEAR:
1457 mipmapping = false;
1458 break;
1459 case GL_NEAREST_MIPMAP_NEAREST:
1460 case GL_LINEAR_MIPMAP_NEAREST:
1461 case GL_NEAREST_MIPMAP_LINEAR:
1462 case GL_LINEAR_MIPMAP_LINEAR:
1463 mipmapping = true;
1464 break;
1465 default: UNREACHABLE();
1466 }
1467
1468 if ((getInternalFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) ||
1469 (getInternalFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter()))
1470 {
1471 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
1472 {
1473 return false;
1474 }
1475 }
1476
1477
1478 if ((getWrapS() != GL_CLAMP_TO_EDGE && !isPow2(width))
1479 || (getWrapT() != GL_CLAMP_TO_EDGE && !isPow2(height)))
1480 {
1481 return false;
1482 }
1483
1484 if (mipmapping)
1485 {
1486 if (!isPow2(width) || !isPow2(height))
1487 {
1488 return false;
1489 }
1490
1491 int q = log2(std::max(width, height));
1492
1493 for (int level = 1; level <= q; level++)
1494 {
1495 if (mImageArray[level].format != mImageArray[0].format)
1496 {
1497 return false;
1498 }
1499
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00001500 if (mImageArray[level].type != mImageArray[0].type)
1501 {
1502 return false;
1503 }
1504
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001505 if (mImageArray[level].width != std::max(1, width >> level))
1506 {
1507 return false;
1508 }
1509
1510 if (mImageArray[level].height != std::max(1, height >> level))
1511 {
1512 return false;
1513 }
1514 }
1515 }
1516
1517 return true;
1518}
1519
1520bool Texture2D::isCompressed() const
1521{
1522 return IsCompressed(getInternalFormat());
1523}
1524
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001525IDirect3DBaseTexture9 *Texture2D::getBaseTexture() const
1526{
1527 return mTexture;
1528}
1529
1530// Constructs a Direct3D 9 texture resource from the texture images
1531void Texture2D::createTexture()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001532{
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001533 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com61208202011-03-21 16:38:50 +00001534 D3DFORMAT format = selectFormat(mImageArray[0].format, mImageArray[0].type);
1535 GLint levels = creationLevels(mImageArray[0].width, mImageArray[0].height, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001536
daniel@transgaming.com61208202011-03-21 16:38:50 +00001537 IDirect3DTexture9 *texture = NULL;
1538 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 +00001539
1540 if (FAILED(result))
1541 {
1542 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001543 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001544 }
1545
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001546 if (mTexture)
1547 {
1548 mTexture->Release();
1549 }
1550
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001551 mTexture = texture;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00001552 mDirtyImage = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00001553 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001554}
1555
1556void Texture2D::updateTexture()
1557{
1558 IDirect3DDevice9 *device = getDevice();
1559
1560 int levels = levelCount();
1561
1562 for (int level = 0; level < levels; level++)
1563 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001564 if (mImageArray[level].surface && mImageArray[level].dirty)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001565 {
1566 IDirect3DSurface9 *levelSurface = NULL;
1567 HRESULT result = mTexture->GetSurfaceLevel(level, &levelSurface);
1568
1569 ASSERT(SUCCEEDED(result));
1570
1571 if (SUCCEEDED(result))
1572 {
1573 result = device->UpdateSurface(mImageArray[level].surface, NULL, levelSurface, NULL);
1574 ASSERT(SUCCEEDED(result));
1575
1576 levelSurface->Release();
1577
1578 mImageArray[level].dirty = false;
1579 }
1580 }
1581 }
1582}
1583
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001584void Texture2D::convertToRenderTarget()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001585{
1586 IDirect3DTexture9 *texture = NULL;
1587
daniel@transgaming.com61208202011-03-21 16:38:50 +00001588 if (mImageArray[0].width != 0 && mImageArray[0].height != 0)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001589 {
1590 egl::Display *display = getDisplay();
1591 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com61208202011-03-21 16:38:50 +00001592 D3DFORMAT format = selectFormat(mImageArray[0].format, mImageArray[0].type);
1593 GLint levels = creationLevels(mImageArray[0].width, mImageArray[0].height, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001594
daniel@transgaming.com61208202011-03-21 16:38:50 +00001595 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 +00001596
1597 if (FAILED(result))
1598 {
1599 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001600 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001601 }
1602
1603 if (mTexture != NULL)
1604 {
1605 int levels = levelCount();
1606 for (int i = 0; i < levels; i++)
1607 {
1608 IDirect3DSurface9 *source;
1609 result = mTexture->GetSurfaceLevel(i, &source);
1610
1611 if (FAILED(result))
1612 {
1613 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1614
1615 texture->Release();
1616
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001617 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001618 }
1619
1620 IDirect3DSurface9 *dest;
1621 result = texture->GetSurfaceLevel(i, &dest);
1622
1623 if (FAILED(result))
1624 {
1625 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1626
1627 texture->Release();
1628 source->Release();
1629
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001630 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001631 }
1632
1633 display->endScene();
1634 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
1635
1636 if (FAILED(result))
1637 {
1638 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1639
1640 texture->Release();
1641 source->Release();
1642 dest->Release();
1643
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001644 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001645 }
1646
1647 source->Release();
1648 dest->Release();
1649 }
1650 }
1651 }
1652
1653 if (mTexture != NULL)
1654 {
1655 mTexture->Release();
1656 }
1657
1658 mTexture = texture;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00001659 mDirtyImage = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00001660 mIsRenderable = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001661}
1662
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001663void Texture2D::generateMipmaps()
1664{
1665 if (!isPow2(mImageArray[0].width) || !isPow2(mImageArray[0].height))
1666 {
1667 return error(GL_INVALID_OPERATION);
1668 }
1669
1670 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
daniel@transgaming.com61208202011-03-21 16:38:50 +00001671 unsigned int q = log2(std::max(mImageArray[0].width, mImageArray[0].height));
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001672 for (unsigned int i = 1; i <= q; i++)
1673 {
1674 if (mImageArray[i].surface != NULL)
1675 {
1676 mImageArray[i].surface->Release();
1677 mImageArray[i].surface = NULL;
1678 }
1679
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001680 mImageArray[i].width = std::max(mImageArray[0].width >> i, 1);
1681 mImageArray[i].height = std::max(mImageArray[0].height >> i, 1);
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00001682 mImageArray[i].format = mImageArray[0].format;
1683 mImageArray[i].type = mImageArray[0].type;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001684 }
1685
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001686 if (mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001687 {
1688 if (mTexture == NULL)
1689 {
1690 ERR(" failed because mTexture was null.");
1691 return;
1692 }
1693
1694 for (unsigned int i = 1; i <= q; i++)
1695 {
1696 IDirect3DSurface9 *upper = NULL;
1697 IDirect3DSurface9 *lower = NULL;
1698
1699 mTexture->GetSurfaceLevel(i-1, &upper);
1700 mTexture->GetSurfaceLevel(i, &lower);
1701
1702 if (upper != NULL && lower != NULL)
1703 {
1704 getBlitter()->boxFilter(upper, lower);
1705 }
1706
1707 if (upper != NULL) upper->Release();
1708 if (lower != NULL) lower->Release();
daniel@transgaming.com61208202011-03-21 16:38:50 +00001709
1710 mImageArray[i].dirty = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001711 }
1712 }
1713 else
1714 {
1715 for (unsigned int i = 1; i <= q; i++)
1716 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001717 createSurface(&mImageArray[i]);
1718
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001719 if (mImageArray[i].surface == NULL)
1720 {
1721 return error(GL_OUT_OF_MEMORY);
1722 }
1723
1724 if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[i].surface, NULL, NULL, mImageArray[i - 1].surface, NULL, NULL, D3DX_FILTER_BOX, 0)))
1725 {
1726 ERR(" failed to load filter %d to %d.", i - 1, i);
1727 }
1728
1729 mImageArray[i].dirty = true;
1730 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001731 }
1732}
1733
1734Renderbuffer *Texture2D::getRenderbuffer(GLenum target)
1735{
1736 if (target != GL_TEXTURE_2D)
1737 {
1738 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
1739 }
1740
1741 if (mColorbufferProxy.get() == NULL)
1742 {
1743 mColorbufferProxy.set(new Renderbuffer(id(), new Colorbuffer(this, target)));
1744 }
1745
1746 return mColorbufferProxy.get();
1747}
1748
1749IDirect3DSurface9 *Texture2D::getRenderTarget(GLenum target)
1750{
1751 ASSERT(target == GL_TEXTURE_2D);
1752
daniel@transgaming.com61208202011-03-21 16:38:50 +00001753 if (!mIsRenderable)
1754 {
1755 convertToRenderTarget();
1756 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001757
1758 if (mTexture == NULL)
1759 {
1760 return NULL;
1761 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00001762
1763 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001764
1765 IDirect3DSurface9 *renderTarget = NULL;
1766 mTexture->GetSurfaceLevel(0, &renderTarget);
1767
1768 return renderTarget;
1769}
1770
1771TextureCubeMap::TextureCubeMap(GLuint id) : Texture(id)
1772{
1773 mTexture = NULL;
1774}
1775
1776TextureCubeMap::~TextureCubeMap()
1777{
1778 for (int i = 0; i < 6; i++)
1779 {
1780 mFaceProxies[i].set(NULL);
1781 }
1782
1783 if (mTexture)
1784 {
1785 mTexture->Release();
1786 mTexture = NULL;
1787 }
1788}
1789
1790GLenum TextureCubeMap::getTarget() const
1791{
1792 return GL_TEXTURE_CUBE_MAP;
1793}
1794
daniel@transgaming.com61208202011-03-21 16:38:50 +00001795GLsizei TextureCubeMap::getWidth() const
1796{
1797 return mImageArray[0][0].width;
1798}
1799
1800GLsizei TextureCubeMap::getHeight() const
1801{
1802 return mImageArray[0][0].height;
1803}
1804
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001805GLenum TextureCubeMap::getInternalFormat() const
1806{
1807 return mImageArray[0][0].format;
1808}
1809
daniel@transgaming.com61208202011-03-21 16:38:50 +00001810GLenum TextureCubeMap::getType() const
1811{
1812 return mImageArray[0][0].type;
1813}
1814
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001815void 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 +00001816{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001817 setImage(0, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001818}
1819
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001820void 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 +00001821{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001822 setImage(1, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001823}
1824
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001825void 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 +00001826{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001827 setImage(2, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001828}
1829
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001830void 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 +00001831{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001832 setImage(3, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001833}
1834
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001835void 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 +00001836{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001837 setImage(4, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001838}
1839
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001840void 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 +00001841{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001842 setImage(5, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001843}
1844
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001845void 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 +00001846{
daniel@transgaming.com61208202011-03-21 16:38:50 +00001847 redefineTexture(faceIndex(face), level, format, width, height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001848
daniel@transgaming.com61208202011-03-21 16:38:50 +00001849 Texture::setCompressedImage(imageSize, pixels, &mImageArray[faceIndex(face)][level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001850}
1851
1852void TextureCubeMap::commitRect(GLenum faceTarget, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1853{
1854 int face = faceIndex(faceTarget);
1855 ASSERT(mImageArray[face][level].surface != NULL);
1856
1857 if (level < levelCount())
1858 {
1859 IDirect3DSurface9 *destLevel = getCubeMapSurface(faceTarget, level);
1860 ASSERT(destLevel != NULL);
1861
1862 if (destLevel != NULL)
1863 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001864 Image *image = &mImageArray[face][level];
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001865
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001866 RECT sourceRect = transformPixelRect(xoffset, yoffset, width, height, image->height);;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001867
1868 POINT destPoint;
1869 destPoint.x = sourceRect.left;
1870 destPoint.y = sourceRect.top;
1871
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001872 HRESULT result = getDevice()->UpdateSurface(image->surface, &sourceRect, destLevel, &destPoint);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001873 ASSERT(SUCCEEDED(result));
1874
1875 destLevel->Release();
1876
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001877 image->dirty = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001878 }
1879 }
1880}
1881
1882void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1883{
1884 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[faceIndex(target)][level]))
1885 {
1886 commitRect(target, level, xoffset, yoffset, width, height);
1887 }
1888}
1889
1890void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1891{
1892 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[faceIndex(target)][level]))
1893 {
1894 commitRect(target, level, xoffset, yoffset, width, height);
1895 }
1896}
1897
1898// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1899bool TextureCubeMap::isComplete() const
1900{
1901 int size = mImageArray[0][0].width;
1902
1903 if (size <= 0)
1904 {
1905 return false;
1906 }
1907
1908 bool mipmapping;
1909
1910 switch (mMinFilter)
1911 {
1912 case GL_NEAREST:
1913 case GL_LINEAR:
1914 mipmapping = false;
1915 break;
1916 case GL_NEAREST_MIPMAP_NEAREST:
1917 case GL_LINEAR_MIPMAP_NEAREST:
1918 case GL_NEAREST_MIPMAP_LINEAR:
1919 case GL_LINEAR_MIPMAP_LINEAR:
1920 mipmapping = true;
1921 break;
1922 default: UNREACHABLE();
1923 }
1924
1925 for (int face = 0; face < 6; face++)
1926 {
1927 if (mImageArray[face][0].width != size || mImageArray[face][0].height != size)
1928 {
1929 return false;
1930 }
1931 }
1932
1933 if ((getInternalFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) ||
1934 (getInternalFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter()))
1935 {
1936 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
1937 {
1938 return false;
1939 }
1940 }
1941
1942 if (mipmapping)
1943 {
1944 if (!isPow2(size) && (getWrapS() != GL_CLAMP_TO_EDGE || getWrapT() != GL_CLAMP_TO_EDGE))
1945 {
1946 return false;
1947 }
1948
1949 int q = log2(size);
1950
1951 for (int face = 0; face < 6; face++)
1952 {
1953 for (int level = 1; level <= q; level++)
1954 {
1955 if (mImageArray[face][level].format != mImageArray[0][0].format)
1956 {
1957 return false;
1958 }
1959
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00001960 if (mImageArray[face][level].type != mImageArray[0][0].type)
1961 {
1962 return false;
1963 }
1964
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001965 if (mImageArray[face][level].width != std::max(1, size >> level))
1966 {
1967 return false;
1968 }
1969
1970 ASSERT(mImageArray[face][level].height == mImageArray[face][level].width);
1971 }
1972 }
1973 }
1974
1975 return true;
1976}
1977
1978bool TextureCubeMap::isCompressed() const
1979{
1980 return IsCompressed(getInternalFormat());
1981}
1982
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001983IDirect3DBaseTexture9 *TextureCubeMap::getBaseTexture() const
1984{
1985 return mTexture;
1986}
1987
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001988// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001989void TextureCubeMap::createTexture()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001990{
1991 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com61208202011-03-21 16:38:50 +00001992 D3DFORMAT format = selectFormat(mImageArray[0][0].format, mImageArray[0][0].type);
1993 GLint levels = creationLevels(mImageArray[0][0].width, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001994
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00001995 IDirect3DCubeTexture9 *texture = NULL;
daniel@transgaming.com61208202011-03-21 16:38:50 +00001996 HRESULT result = device->CreateCubeTexture(mImageArray[0][0].width, levels, 0, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001997
1998 if (FAILED(result))
1999 {
2000 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002001 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002002 }
2003
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002004 if (mTexture)
2005 {
2006 mTexture->Release();
2007 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002008
2009 mTexture = texture;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00002010 mDirtyImage = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00002011 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002012}
2013
2014void TextureCubeMap::updateTexture()
2015{
2016 IDirect3DDevice9 *device = getDevice();
2017
2018 for (int face = 0; face < 6; face++)
2019 {
2020 int levels = levelCount();
2021 for (int level = 0; level < levels; level++)
2022 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00002023 Image *image = &mImageArray[face][level];
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002024
daniel@transgaming.com61208202011-03-21 16:38:50 +00002025 if (image->surface && image->dirty)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002026 {
2027 IDirect3DSurface9 *levelSurface = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level);
2028 ASSERT(levelSurface != NULL);
2029
2030 if (levelSurface != NULL)
2031 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00002032 HRESULT result = device->UpdateSurface(image->surface, NULL, levelSurface, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002033 ASSERT(SUCCEEDED(result));
2034
2035 levelSurface->Release();
2036
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00002037 image->dirty = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002038 }
2039 }
2040 }
2041 }
2042}
2043
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002044void TextureCubeMap::convertToRenderTarget()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002045{
2046 IDirect3DCubeTexture9 *texture = NULL;
2047
daniel@transgaming.com61208202011-03-21 16:38:50 +00002048 if (mImageArray[0][0].width != 0)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002049 {
2050 egl::Display *display = getDisplay();
2051 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com61208202011-03-21 16:38:50 +00002052 D3DFORMAT format = selectFormat(mImageArray[0][0].format, mImageArray[0][0].type);
2053 GLint levels = creationLevels(mImageArray[0][0].width, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002054
daniel@transgaming.com61208202011-03-21 16:38:50 +00002055 HRESULT result = device->CreateCubeTexture(mImageArray[0][0].width, levels, D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002056
2057 if (FAILED(result))
2058 {
2059 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002060 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002061 }
2062
2063 if (mTexture != NULL)
2064 {
2065 int levels = levelCount();
2066 for (int f = 0; f < 6; f++)
2067 {
2068 for (int i = 0; i < levels; i++)
2069 {
2070 IDirect3DSurface9 *source;
2071 result = mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &source);
2072
2073 if (FAILED(result))
2074 {
2075 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2076
2077 texture->Release();
2078
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002079 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002080 }
2081
2082 IDirect3DSurface9 *dest;
2083 result = texture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &dest);
2084
2085 if (FAILED(result))
2086 {
2087 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2088
2089 texture->Release();
2090 source->Release();
2091
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002092 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002093 }
2094
2095 display->endScene();
2096 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
2097
2098 if (FAILED(result))
2099 {
2100 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2101
2102 texture->Release();
2103 source->Release();
2104 dest->Release();
2105
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002106 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002107 }
2108 }
2109 }
2110 }
2111 }
2112
2113 if (mTexture != NULL)
2114 {
2115 mTexture->Release();
2116 }
2117
2118 mTexture = texture;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00002119 mDirtyImage = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00002120 mIsRenderable = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002121}
2122
daniel@transgaming.com61208202011-03-21 16:38:50 +00002123void 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 +00002124{
daniel@transgaming.com61208202011-03-21 16:38:50 +00002125 redefineTexture(faceIndex, level, format, width, height, type);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002126
daniel@transgaming.com61208202011-03-21 16:38:50 +00002127 Texture::setImage(unpackAlignment, pixels, &mImageArray[faceIndex][level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002128}
2129
2130unsigned int TextureCubeMap::faceIndex(GLenum face)
2131{
2132 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
2133 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
2134 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
2135 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
2136 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
2137
2138 return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
2139}
2140
daniel@transgaming.com61208202011-03-21 16:38:50 +00002141void TextureCubeMap::redefineTexture(int face, GLint level, GLenum format, GLsizei width, GLsizei height, GLenum type)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002142{
daniel@transgaming.com94a4f032011-03-21 16:38:55 +00002143 GLsizei textureWidth = mImageArray[0][0].width;
2144 GLsizei textureHeight = mImageArray[0][0].height;
2145 GLenum textureFormat = mImageArray[0][0].format;
2146 GLenum textureType = mImageArray[0][0].type;
2147
daniel@transgaming.com61208202011-03-21 16:38:50 +00002148 mImageArray[face][level].width = width;
2149 mImageArray[face][level].height = height;
2150 mImageArray[face][level].format = format;
2151 mImageArray[face][level].type = type;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002152
daniel@transgaming.com61208202011-03-21 16:38:50 +00002153 if (!mTexture)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002154 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00002155 return;
2156 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002157
daniel@transgaming.com94a4f032011-03-21 16:38:55 +00002158 bool sizeOkay = (textureWidth >> level == width);
2159 bool textureOkay = (sizeOkay && textureFormat == format && textureType == type);
daniel@transgaming.com61208202011-03-21 16:38:50 +00002160
2161 if (!textureOkay) // Purge all the levels and the texture.
2162 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002163 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
2164 {
2165 for (int f = 0; f < 6; f++)
2166 {
2167 if (mImageArray[f][i].surface != NULL)
2168 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002169 mImageArray[f][i].surface->Release();
2170 mImageArray[f][i].surface = NULL;
daniel@transgaming.com61208202011-03-21 16:38:50 +00002171 mImageArray[f][i].dirty = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002172 }
2173 }
2174 }
2175
2176 if (mTexture != NULL)
2177 {
2178 mTexture->Release();
2179 mTexture = NULL;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00002180 mDirtyImage = true;
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002181 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002182 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002183 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002184}
2185
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002186void 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 +00002187{
2188 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
2189
2190 if (!renderTarget)
2191 {
2192 ERR("Failed to retrieve the render target.");
2193 return error(GL_OUT_OF_MEMORY);
2194 }
2195
2196 unsigned int faceindex = faceIndex(target);
daniel@transgaming.com61208202011-03-21 16:38:50 +00002197 redefineTexture(faceindex, level, format, width, height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002198
daniel@transgaming.comf4e36032011-03-21 16:38:59 +00002199 if (!isRenderableFormat() || (!mTexture && !isComplete()))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002200 {
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002201 copyNonRenderable(&mImageArray[faceindex][level], format, 0, 0, x, y, width, height, renderTarget);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002202 }
2203 else
2204 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00002205 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002206 {
2207 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002208 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00002209
2210 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002211
2212 ASSERT(width == height);
2213
2214 if (width > 0 && level < levelCount())
2215 {
2216 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
2217 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
2218 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
2219 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
2220 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
2221
2222 IDirect3DSurface9 *dest = getCubeMapSurface(target, level);
2223
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002224 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, format, 0, 0, dest);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002225 dest->Release();
2226 }
2227 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002228}
2229
2230IDirect3DSurface9 *TextureCubeMap::getCubeMapSurface(GLenum face, unsigned int level)
2231{
2232 if (mTexture == NULL)
2233 {
2234 UNREACHABLE();
2235 return NULL;
2236 }
2237
2238 IDirect3DSurface9 *surface = NULL;
2239
2240 HRESULT hr = mTexture->GetCubeMapSurface(es2dx::ConvertCubeFace(face), level, &surface);
2241
2242 return (SUCCEEDED(hr)) ? surface : NULL;
2243}
2244
2245void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
2246{
2247 GLsizei size = mImageArray[faceIndex(target)][level].width;
2248
2249 if (xoffset + width > size || yoffset + height > size)
2250 {
2251 return error(GL_INVALID_VALUE);
2252 }
2253
2254 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
2255
2256 if (!renderTarget)
2257 {
2258 ERR("Failed to retrieve the render target.");
2259 return error(GL_OUT_OF_MEMORY);
2260 }
2261
2262 unsigned int faceindex = faceIndex(target);
daniel@transgaming.com61208202011-03-21 16:38:50 +00002263 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 +00002264
2265 if (!isRenderableFormat())
2266 {
2267 copyNonRenderable(&mImageArray[faceindex][level], getInternalFormat(), 0, 0, x, y, width, height, renderTarget);
2268 }
2269 else
2270 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00002271 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002272 {
2273 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002274 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00002275
2276 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002277
2278 if (level < levelCount())
2279 {
2280 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
2281 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
2282 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
2283 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
2284 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
2285
2286 GLint destYOffset = transformPixelYOffset(yoffset, height, mImageArray[faceindex][level].width);
2287
2288 IDirect3DSurface9 *dest = getCubeMapSurface(target, level);
2289
2290 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0][0].format, xoffset, destYOffset, dest);
2291 dest->Release();
2292 }
2293 }
2294}
2295
2296bool TextureCubeMap::isCubeComplete() const
2297{
2298 if (mImageArray[0][0].width == 0)
2299 {
2300 return false;
2301 }
2302
2303 for (unsigned int f = 1; f < 6; f++)
2304 {
2305 if (mImageArray[f][0].width != mImageArray[0][0].width
2306 || mImageArray[f][0].format != mImageArray[0][0].format)
2307 {
2308 return false;
2309 }
2310 }
2311
2312 return true;
2313}
2314
2315void TextureCubeMap::generateMipmaps()
2316{
2317 if (!isPow2(mImageArray[0][0].width) || !isCubeComplete())
2318 {
2319 return error(GL_INVALID_OPERATION);
2320 }
2321
2322 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
2323 unsigned int q = log2(mImageArray[0][0].width);
2324 for (unsigned int f = 0; f < 6; f++)
2325 {
2326 for (unsigned int i = 1; i <= q; i++)
2327 {
2328 if (mImageArray[f][i].surface != NULL)
2329 {
2330 mImageArray[f][i].surface->Release();
2331 mImageArray[f][i].surface = NULL;
2332 }
2333
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002334 mImageArray[f][i].width = std::max(mImageArray[f][0].width >> i, 1);
2335 mImageArray[f][i].height = mImageArray[f][i].width;
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00002336 mImageArray[f][i].format = mImageArray[f][0].format;
2337 mImageArray[f][i].type = mImageArray[f][0].type;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002338 }
2339 }
2340
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002341 if (mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002342 {
2343 if (mTexture == NULL)
2344 {
2345 return;
2346 }
2347
2348 for (unsigned int f = 0; f < 6; f++)
2349 {
2350 for (unsigned int i = 1; i <= q; i++)
2351 {
2352 IDirect3DSurface9 *upper = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i-1);
2353 IDirect3DSurface9 *lower = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i);
2354
2355 if (upper != NULL && lower != NULL)
2356 {
2357 getBlitter()->boxFilter(upper, lower);
2358 }
2359
2360 if (upper != NULL) upper->Release();
2361 if (lower != NULL) lower->Release();
daniel@transgaming.com61208202011-03-21 16:38:50 +00002362
2363 mImageArray[f][i].dirty = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002364 }
2365 }
2366 }
2367 else
2368 {
2369 for (unsigned int f = 0; f < 6; f++)
2370 {
2371 for (unsigned int i = 1; i <= q; i++)
2372 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00002373 createSurface(&mImageArray[f][i]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002374 if (mImageArray[f][i].surface == NULL)
2375 {
2376 return error(GL_OUT_OF_MEMORY);
2377 }
2378
2379 if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[f][i].surface, NULL, NULL, mImageArray[f][i - 1].surface, NULL, NULL, D3DX_FILTER_BOX, 0)))
2380 {
2381 ERR(" failed to load filter %d to %d.", i - 1, i);
2382 }
2383
2384 mImageArray[f][i].dirty = true;
2385 }
2386 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002387 }
2388}
2389
2390Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target)
2391{
2392 if (!IsCubemapTextureTarget(target))
2393 {
2394 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
2395 }
2396
2397 unsigned int face = faceIndex(target);
2398
2399 if (mFaceProxies[face].get() == NULL)
2400 {
2401 mFaceProxies[face].set(new Renderbuffer(id(), new Colorbuffer(this, target)));
2402 }
2403
2404 return mFaceProxies[face].get();
2405}
2406
2407IDirect3DSurface9 *TextureCubeMap::getRenderTarget(GLenum target)
2408{
2409 ASSERT(IsCubemapTextureTarget(target));
2410
daniel@transgaming.com61208202011-03-21 16:38:50 +00002411 if (!mIsRenderable)
2412 {
2413 convertToRenderTarget();
2414 }
2415
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002416 if (mTexture == NULL)
2417 {
2418 return NULL;
2419 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00002420
2421 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002422
2423 IDirect3DSurface9 *renderTarget = NULL;
2424 mTexture->GetCubeMapSurface(es2dx::ConvertCubeFace(target), 0, &renderTarget);
2425
2426 return renderTarget;
2427}
2428
2429}