blob: 0aeac592089a15ce5c7c4521621bd74db98c222a [file] [log] [blame]
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001//
2// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7// Texture.cpp: Implements the gl::Texture class and its derived classes
8// Texture2D and TextureCubeMap. Implements GL texture objects and related
9// functionality. [OpenGL ES 2.0.24] section 3.7 page 63.
10
11#include "libGLESv2/Texture.h"
12
13#include <d3dx9tex.h>
14
15#include <algorithm>
jbauman@chromium.orgf1f28c82011-05-12 20:53:34 +000016#include <intrin.h>
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +000017
18#include "common/debug.h"
19
jbauman@chromium.orgae345802011-03-30 22:04:25 +000020#include "libEGL/Display.h"
21
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +000022#include "libGLESv2/main.h"
23#include "libGLESv2/mathutil.h"
24#include "libGLESv2/utilities.h"
25#include "libGLESv2/Blit.h"
26#include "libGLESv2/Framebuffer.h"
27
28namespace gl
29{
daniel@transgaming.coma9eb5da2011-03-21 16:39:16 +000030unsigned int Texture::mCurrentSerial = 1;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +000031
daniel@transgaming.comde631782011-11-09 17:45:04 +000032Image::Image()
daniel@transgaming.comc50edcb2011-03-21 16:38:40 +000033 : width(0), height(0), dirty(false), surface(NULL), format(GL_NONE), type(GL_UNSIGNED_BYTE)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +000034{
35}
36
daniel@transgaming.comde631782011-11-09 17:45:04 +000037Image::~Image()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +000038{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +000039 if (surface)
40 {
41 surface->Release();
42 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +000043}
44
daniel@transgaming.comde631782011-11-09 17:45:04 +000045bool Image::isRenderable() const
daniel@transgaming.com549bdef2011-03-29 00:57:01 +000046{
47 switch(getD3DFormat())
48 {
49 case D3DFMT_L8:
50 case D3DFMT_A8L8:
51 case D3DFMT_DXT1:
gman@chromium.org50c526d2011-08-10 05:19:44 +000052 case D3DFMT_DXT3:
53 case D3DFMT_DXT5:
daniel@transgaming.com549bdef2011-03-29 00:57:01 +000054 return false;
55 case D3DFMT_A8R8G8B8:
56 case D3DFMT_X8R8G8B8:
57 case D3DFMT_A16B16G16R16F:
58 case D3DFMT_A32B32G32R32F:
59 return true;
60 default:
61 UNREACHABLE();
62 }
63
64 return false;
65}
66
daniel@transgaming.comde631782011-11-09 17:45:04 +000067D3DFORMAT Image::getD3DFormat() const
daniel@transgaming.com549bdef2011-03-29 00:57:01 +000068{
69 if (format == GL_COMPRESSED_RGB_S3TC_DXT1_EXT ||
70 format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT)
71 {
72 return D3DFMT_DXT1;
73 }
gman@chromium.org2ac3e732011-08-10 07:59:47 +000074 else if (format == GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE)
gman@chromium.org50c526d2011-08-10 05:19:44 +000075 {
76 return D3DFMT_DXT3;
77 }
gman@chromium.org2ac3e732011-08-10 07:59:47 +000078 else if (format == GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE)
gman@chromium.org50c526d2011-08-10 05:19:44 +000079 {
80 return D3DFMT_DXT5;
81 }
daniel@transgaming.com549bdef2011-03-29 00:57:01 +000082 else if (type == GL_FLOAT)
83 {
84 return D3DFMT_A32B32G32R32F;
85 }
86 else if (type == GL_HALF_FLOAT_OES)
87 {
88 return D3DFMT_A16B16G16R16F;
89 }
90 else if (type == GL_UNSIGNED_BYTE)
91 {
92 if (format == GL_LUMINANCE && getContext()->supportsLuminanceTextures())
93 {
94 return D3DFMT_L8;
95 }
96 else if (format == GL_LUMINANCE_ALPHA && getContext()->supportsLuminanceAlphaTextures())
97 {
98 return D3DFMT_A8L8;
99 }
100 else if (format == GL_RGB)
101 {
102 return D3DFMT_X8R8G8B8;
103 }
104
105 return D3DFMT_A8R8G8B8;
106 }
107
108 return D3DFMT_A8R8G8B8;
109}
110
daniel@transgaming.coma9eb5da2011-03-21 16:39:16 +0000111Texture::Texture(GLuint id) : RefCountObject(id), mSerial(issueSerial())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000112{
113 mMinFilter = GL_NEAREST_MIPMAP_LINEAR;
114 mMagFilter = GL_LINEAR;
115 mWrapS = GL_REPEAT;
116 mWrapT = GL_REPEAT;
daniel@transgaming.com0da803b2011-11-09 17:44:58 +0000117 mDirtyParameters = true;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +0000118
daniel@transgaming.com0da803b2011-11-09 17:44:58 +0000119 mDirtyImages = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +0000120
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000121 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000122}
123
124Texture::~Texture()
125{
126}
127
128Blit *Texture::getBlitter()
129{
130 Context *context = getContext();
131 return context->getBlitter();
132}
133
134// Returns true on successful filter state update (valid enum parameter)
135bool Texture::setMinFilter(GLenum filter)
136{
137 switch (filter)
138 {
139 case GL_NEAREST:
140 case GL_LINEAR:
141 case GL_NEAREST_MIPMAP_NEAREST:
142 case GL_LINEAR_MIPMAP_NEAREST:
143 case GL_NEAREST_MIPMAP_LINEAR:
144 case GL_LINEAR_MIPMAP_LINEAR:
145 {
146 if (mMinFilter != filter)
147 {
148 mMinFilter = filter;
daniel@transgaming.com0da803b2011-11-09 17:44:58 +0000149 mDirtyParameters = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000150 }
151 return true;
152 }
153 default:
154 return false;
155 }
156}
157
158// Returns true on successful filter state update (valid enum parameter)
159bool Texture::setMagFilter(GLenum filter)
160{
161 switch (filter)
162 {
163 case GL_NEAREST:
164 case GL_LINEAR:
165 {
166 if (mMagFilter != filter)
167 {
168 mMagFilter = filter;
daniel@transgaming.com0da803b2011-11-09 17:44:58 +0000169 mDirtyParameters = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000170 }
171 return true;
172 }
173 default:
174 return false;
175 }
176}
177
178// Returns true on successful wrap state update (valid enum parameter)
179bool Texture::setWrapS(GLenum wrap)
180{
181 switch (wrap)
182 {
183 case GL_REPEAT:
184 case GL_CLAMP_TO_EDGE:
185 case GL_MIRRORED_REPEAT:
186 {
187 if (mWrapS != wrap)
188 {
189 mWrapS = wrap;
daniel@transgaming.com0da803b2011-11-09 17:44:58 +0000190 mDirtyParameters = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000191 }
192 return true;
193 }
194 default:
195 return false;
196 }
197}
198
199// Returns true on successful wrap state update (valid enum parameter)
200bool Texture::setWrapT(GLenum wrap)
201{
202 switch (wrap)
203 {
204 case GL_REPEAT:
205 case GL_CLAMP_TO_EDGE:
206 case GL_MIRRORED_REPEAT:
207 {
208 if (mWrapT != wrap)
209 {
210 mWrapT = wrap;
daniel@transgaming.com0da803b2011-11-09 17:44:58 +0000211 mDirtyParameters = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000212 }
213 return true;
214 }
215 default:
216 return false;
217 }
218}
219
220GLenum Texture::getMinFilter() const
221{
222 return mMinFilter;
223}
224
225GLenum Texture::getMagFilter() const
226{
227 return mMagFilter;
228}
229
230GLenum Texture::getWrapS() const
231{
232 return mWrapS;
233}
234
235GLenum Texture::getWrapT() const
236{
237 return mWrapT;
238}
239
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000240// Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input
241// into the target pixel rectangle at output with outputPitch bytes in between each line.
242void Texture::loadImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type,
243 GLint unpackAlignment, const void *input, size_t outputPitch, void *output, D3DSURFACE_DESC *description) const
244{
245 GLsizei inputPitch = -ComputePitch(width, format, type, unpackAlignment);
246 input = ((char*)input) - inputPitch * (height - 1);
247
248 switch (type)
249 {
250 case GL_UNSIGNED_BYTE:
251 switch (format)
252 {
253 case GL_ALPHA:
254 loadAlphaImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
255 break;
256 case GL_LUMINANCE:
257 loadLuminanceImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output, description->Format == D3DFMT_L8);
258 break;
259 case GL_LUMINANCE_ALPHA:
260 loadLuminanceAlphaImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output, description->Format == D3DFMT_A8L8);
261 break;
262 case GL_RGB:
263 loadRGBUByteImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
264 break;
265 case GL_RGBA:
jbauman@chromium.orgf1f28c82011-05-12 20:53:34 +0000266 if (supportsSSE2())
267 {
268 loadRGBAUByteImageDataSSE2(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
269 }
270 else
271 {
272 loadRGBAUByteImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
273 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000274 break;
275 case GL_BGRA_EXT:
276 loadBGRAImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
277 break;
278 default: UNREACHABLE();
279 }
280 break;
281 case GL_UNSIGNED_SHORT_5_6_5:
282 switch (format)
283 {
284 case GL_RGB:
285 loadRGB565ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
286 break;
287 default: UNREACHABLE();
288 }
289 break;
290 case GL_UNSIGNED_SHORT_4_4_4_4:
291 switch (format)
292 {
293 case GL_RGBA:
294 loadRGBA4444ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
295 break;
296 default: UNREACHABLE();
297 }
298 break;
299 case GL_UNSIGNED_SHORT_5_5_5_1:
300 switch (format)
301 {
302 case GL_RGBA:
303 loadRGBA5551ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
304 break;
305 default: UNREACHABLE();
306 }
307 break;
308 case GL_FLOAT:
309 switch (format)
310 {
311 // float textures are converted to RGBA, not BGRA, as they're stored that way in D3D
312 case GL_ALPHA:
313 loadAlphaFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
314 break;
315 case GL_LUMINANCE:
316 loadLuminanceFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
317 break;
318 case GL_LUMINANCE_ALPHA:
319 loadLuminanceAlphaFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
320 break;
321 case GL_RGB:
322 loadRGBFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
323 break;
324 case GL_RGBA:
325 loadRGBAFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
326 break;
327 default: UNREACHABLE();
328 }
329 break;
330 case GL_HALF_FLOAT_OES:
331 switch (format)
332 {
333 // float textures are converted to RGBA, not BGRA, as they're stored that way in D3D
334 case GL_ALPHA:
335 loadAlphaHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
336 break;
337 case GL_LUMINANCE:
338 loadLuminanceHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
339 break;
340 case GL_LUMINANCE_ALPHA:
341 loadLuminanceAlphaHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
342 break;
343 case GL_RGB:
344 loadRGBHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
345 break;
346 case GL_RGBA:
347 loadRGBAHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
348 break;
349 default: UNREACHABLE();
350 }
351 break;
352 default: UNREACHABLE();
353 }
354}
355
356void Texture::loadAlphaImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
357 int inputPitch, const void *input, size_t outputPitch, void *output) const
358{
359 const unsigned char *source = NULL;
360 unsigned char *dest = NULL;
361
362 for (int y = 0; y < height; y++)
363 {
364 source = static_cast<const unsigned char*>(input) + y * inputPitch;
365 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
366 for (int x = 0; x < width; x++)
367 {
368 dest[4 * x + 0] = 0;
369 dest[4 * x + 1] = 0;
370 dest[4 * x + 2] = 0;
371 dest[4 * x + 3] = source[x];
372 }
373 }
374}
375
376void Texture::loadAlphaFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
377 int inputPitch, const void *input, size_t outputPitch, void *output) const
378{
379 const float *source = NULL;
380 float *dest = NULL;
381
382 for (int y = 0; y < height; y++)
383 {
384 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
385 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
386 for (int x = 0; x < width; x++)
387 {
388 dest[4 * x + 0] = 0;
389 dest[4 * x + 1] = 0;
390 dest[4 * x + 2] = 0;
391 dest[4 * x + 3] = source[x];
392 }
393 }
394}
395
396void Texture::loadAlphaHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
397 int inputPitch, const void *input, size_t outputPitch, void *output) const
398{
399 const unsigned short *source = NULL;
400 unsigned short *dest = NULL;
401
402 for (int y = 0; y < height; y++)
403 {
404 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
405 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
406 for (int x = 0; x < width; x++)
407 {
408 dest[4 * x + 0] = 0;
409 dest[4 * x + 1] = 0;
410 dest[4 * x + 2] = 0;
411 dest[4 * x + 3] = source[x];
412 }
413 }
414}
415
416void Texture::loadLuminanceImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
417 int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const
418{
419 const int destBytesPerPixel = native? 1: 4;
420 const unsigned char *source = NULL;
421 unsigned char *dest = NULL;
422
423 for (int y = 0; y < height; y++)
424 {
425 source = static_cast<const unsigned char*>(input) + y * inputPitch;
426 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * destBytesPerPixel;
427
428 if (!native) // BGRA8 destination format
429 {
430 for (int x = 0; x < width; x++)
431 {
432 dest[4 * x + 0] = source[x];
433 dest[4 * x + 1] = source[x];
434 dest[4 * x + 2] = source[x];
435 dest[4 * x + 3] = 0xFF;
436 }
437 }
438 else // L8 destination format
439 {
440 memcpy(dest, source, width);
441 }
442 }
443}
444
445void Texture::loadLuminanceFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
446 int inputPitch, const void *input, size_t outputPitch, void *output) const
447{
448 const float *source = NULL;
449 float *dest = NULL;
450
451 for (int y = 0; y < height; y++)
452 {
453 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
454 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
455 for (int x = 0; x < width; x++)
456 {
457 dest[4 * x + 0] = source[x];
458 dest[4 * x + 1] = source[x];
459 dest[4 * x + 2] = source[x];
460 dest[4 * x + 3] = 1.0f;
461 }
462 }
463}
464
465void Texture::loadLuminanceHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
466 int inputPitch, const void *input, size_t outputPitch, void *output) const
467{
468 const unsigned short *source = NULL;
469 unsigned short *dest = NULL;
470
471 for (int y = 0; y < height; y++)
472 {
473 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
474 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
475 for (int x = 0; x < width; x++)
476 {
477 dest[4 * x + 0] = source[x];
478 dest[4 * x + 1] = source[x];
479 dest[4 * x + 2] = source[x];
480 dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1
481 }
482 }
483}
484
485void Texture::loadLuminanceAlphaImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
486 int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const
487{
488 const int destBytesPerPixel = native? 2: 4;
489 const unsigned char *source = NULL;
490 unsigned char *dest = NULL;
491
492 for (int y = 0; y < height; y++)
493 {
494 source = static_cast<const unsigned char*>(input) + y * inputPitch;
495 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * destBytesPerPixel;
496
497 if (!native) // BGRA8 destination format
498 {
499 for (int x = 0; x < width; x++)
500 {
501 dest[4 * x + 0] = source[2*x+0];
502 dest[4 * x + 1] = source[2*x+0];
503 dest[4 * x + 2] = source[2*x+0];
504 dest[4 * x + 3] = source[2*x+1];
505 }
506 }
507 else
508 {
509 memcpy(dest, source, width * 2);
510 }
511 }
512}
513
514void Texture::loadLuminanceAlphaFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
515 int inputPitch, const void *input, size_t outputPitch, void *output) const
516{
517 const float *source = NULL;
518 float *dest = NULL;
519
520 for (int y = 0; y < height; y++)
521 {
522 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
523 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
524 for (int x = 0; x < width; x++)
525 {
526 dest[4 * x + 0] = source[2*x+0];
527 dest[4 * x + 1] = source[2*x+0];
528 dest[4 * x + 2] = source[2*x+0];
529 dest[4 * x + 3] = source[2*x+1];
530 }
531 }
532}
533
534void Texture::loadLuminanceAlphaHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
535 int inputPitch, const void *input, size_t outputPitch, void *output) const
536{
537 const unsigned short *source = NULL;
538 unsigned short *dest = NULL;
539
540 for (int y = 0; y < height; y++)
541 {
542 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
543 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
544 for (int x = 0; x < width; x++)
545 {
546 dest[4 * x + 0] = source[2*x+0];
547 dest[4 * x + 1] = source[2*x+0];
548 dest[4 * x + 2] = source[2*x+0];
549 dest[4 * x + 3] = source[2*x+1];
550 }
551 }
552}
553
554void Texture::loadRGBUByteImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
555 int inputPitch, const void *input, size_t outputPitch, void *output) const
556{
557 const unsigned char *source = NULL;
558 unsigned char *dest = NULL;
559
560 for (int y = 0; y < height; y++)
561 {
562 source = static_cast<const unsigned char*>(input) + y * inputPitch;
563 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
564 for (int x = 0; x < width; x++)
565 {
566 dest[4 * x + 0] = source[x * 3 + 2];
567 dest[4 * x + 1] = source[x * 3 + 1];
568 dest[4 * x + 2] = source[x * 3 + 0];
569 dest[4 * x + 3] = 0xFF;
570 }
571 }
572}
573
574void Texture::loadRGB565ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
575 int inputPitch, const void *input, size_t outputPitch, void *output) const
576{
577 const unsigned short *source = NULL;
578 unsigned char *dest = NULL;
579
580 for (int y = 0; y < height; y++)
581 {
582 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
583 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
584 for (int x = 0; x < width; x++)
585 {
586 unsigned short rgba = source[x];
587 dest[4 * x + 0] = ((rgba & 0x001F) << 3) | ((rgba & 0x001F) >> 2);
588 dest[4 * x + 1] = ((rgba & 0x07E0) >> 3) | ((rgba & 0x07E0) >> 9);
589 dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
590 dest[4 * x + 3] = 0xFF;
591 }
592 }
593}
594
595void Texture::loadRGBFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
596 int inputPitch, const void *input, size_t outputPitch, void *output) const
597{
598 const float *source = NULL;
599 float *dest = NULL;
600
601 for (int y = 0; y < height; y++)
602 {
603 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
604 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
605 for (int x = 0; x < width; x++)
606 {
607 dest[4 * x + 0] = source[x * 3 + 0];
608 dest[4 * x + 1] = source[x * 3 + 1];
609 dest[4 * x + 2] = source[x * 3 + 2];
610 dest[4 * x + 3] = 1.0f;
611 }
612 }
613}
614
615void Texture::loadRGBHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
616 int inputPitch, const void *input, size_t outputPitch, void *output) const
617{
618 const unsigned short *source = NULL;
619 unsigned short *dest = NULL;
620
621 for (int y = 0; y < height; y++)
622 {
623 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
624 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
625 for (int x = 0; x < width; x++)
626 {
627 dest[4 * x + 0] = source[x * 3 + 0];
628 dest[4 * x + 1] = source[x * 3 + 1];
629 dest[4 * x + 2] = source[x * 3 + 2];
630 dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1
631 }
632 }
633}
634
jbauman@chromium.orgf1f28c82011-05-12 20:53:34 +0000635void Texture::loadRGBAUByteImageDataSSE2(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
636 int inputPitch, const void *input, size_t outputPitch, void *output) const
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000637{
jbauman@chromium.orgf1f28c82011-05-12 20:53:34 +0000638 const unsigned int *source = NULL;
639 unsigned int *dest = NULL;
640 __m128i brMask = _mm_set1_epi32(0x00ff00ff);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000641
642 for (int y = 0; y < height; y++)
643 {
jbauman@chromium.orgf1f28c82011-05-12 20:53:34 +0000644 source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);
645 dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4);
646 int x = 0;
647
648 // Make output writes aligned
649 for (x = 0; ((reinterpret_cast<intptr_t>(&dest[x]) & 15) != 0) && x < width; x++)
650 {
651 unsigned int rgba = source[x];
652 dest[x] = (_rotl(rgba, 16) & 0x00ff00ff) | (rgba & 0xff00ff00);
653 }
654
655 for (; x + 3 < width; x += 4)
656 {
657 __m128i sourceData = _mm_loadu_si128(reinterpret_cast<const __m128i*>(&source[x]));
658 // Mask out g and a, which don't change
659 __m128i gaComponents = _mm_andnot_si128(brMask, sourceData);
660 // Mask out b and r
661 __m128i brComponents = _mm_and_si128(sourceData, brMask);
662 // Swap b and r
663 __m128i brSwapped = _mm_shufflehi_epi16(_mm_shufflelo_epi16(brComponents, _MM_SHUFFLE(2, 3, 0, 1)), _MM_SHUFFLE(2, 3, 0, 1));
664 __m128i result = _mm_or_si128(gaComponents, brSwapped);
665 _mm_store_si128(reinterpret_cast<__m128i*>(&dest[x]), result);
666 }
667
668 // Perform leftover writes
669 for (; x < width; x++)
670 {
671 unsigned int rgba = source[x];
672 dest[x] = (_rotl(rgba, 16) & 0x00ff00ff) | (rgba & 0xff00ff00);
673 }
674 }
675}
676
677void Texture::loadRGBAUByteImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
678 int inputPitch, const void *input, size_t outputPitch, void *output) const
679{
680 const unsigned int *source = NULL;
681 unsigned int *dest = NULL;
682 for (int y = 0; y < height; y++)
683 {
684 source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);
685 dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4);
686
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000687 for (int x = 0; x < width; x++)
688 {
jbauman@chromium.orgf1f28c82011-05-12 20:53:34 +0000689 unsigned int rgba = source[x];
690 dest[x] = (_rotl(rgba, 16) & 0x00ff00ff) | (rgba & 0xff00ff00);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000691 }
692 }
693}
694
695void Texture::loadRGBA4444ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
696 int inputPitch, const void *input, size_t outputPitch, void *output) const
697{
698 const unsigned short *source = NULL;
699 unsigned char *dest = NULL;
700
701 for (int y = 0; y < height; y++)
702 {
703 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
704 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
705 for (int x = 0; x < width; x++)
706 {
707 unsigned short rgba = source[x];
708 dest[4 * x + 0] = ((rgba & 0x00F0) << 0) | ((rgba & 0x00F0) >> 4);
709 dest[4 * x + 1] = ((rgba & 0x0F00) >> 4) | ((rgba & 0x0F00) >> 8);
710 dest[4 * x + 2] = ((rgba & 0xF000) >> 8) | ((rgba & 0xF000) >> 12);
711 dest[4 * x + 3] = ((rgba & 0x000F) << 4) | ((rgba & 0x000F) >> 0);
712 }
713 }
714}
715
716void Texture::loadRGBA5551ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
717 int inputPitch, const void *input, size_t outputPitch, void *output) const
718{
719 const unsigned short *source = NULL;
720 unsigned char *dest = NULL;
721
722 for (int y = 0; y < height; y++)
723 {
724 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
725 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
726 for (int x = 0; x < width; x++)
727 {
728 unsigned short rgba = source[x];
729 dest[4 * x + 0] = ((rgba & 0x003E) << 2) | ((rgba & 0x003E) >> 3);
730 dest[4 * x + 1] = ((rgba & 0x07C0) >> 3) | ((rgba & 0x07C0) >> 8);
731 dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
732 dest[4 * x + 3] = (rgba & 0x0001) ? 0xFF : 0;
733 }
734 }
735}
736
737void Texture::loadRGBAFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
738 int inputPitch, const void *input, size_t outputPitch, void *output) const
739{
740 const float *source = NULL;
741 float *dest = NULL;
742
743 for (int y = 0; y < height; y++)
744 {
745 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
746 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
747 memcpy(dest, source, width * 16);
748 }
749}
750
751void Texture::loadRGBAHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
752 int inputPitch, const void *input, size_t outputPitch, void *output) const
753{
754 const unsigned char *source = NULL;
755 unsigned char *dest = NULL;
756
757 for (int y = 0; y < height; y++)
758 {
759 source = static_cast<const unsigned char*>(input) + y * inputPitch;
760 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8;
761 memcpy(dest, source, width * 8);
762 }
763}
764
765void Texture::loadBGRAImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
766 int inputPitch, const void *input, size_t outputPitch, void *output) const
767{
768 const unsigned char *source = NULL;
769 unsigned char *dest = NULL;
770
771 for (int y = 0; y < height; y++)
772 {
773 source = static_cast<const unsigned char*>(input) + y * inputPitch;
774 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
775 memcpy(dest, source, width*4);
776 }
777}
778
779void Texture::loadCompressedImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
gman@chromium.org50c526d2011-08-10 05:19:44 +0000780 int inputPitch, const void *input, size_t outputPitch, void *output) const {
781 switch (getD3DFormat())
782 {
783 case D3DFMT_DXT1:
784 loadDXT1ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
785 break;
786 case D3DFMT_DXT3:
787 loadDXT3ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
788 break;
789 case D3DFMT_DXT5:
790 loadDXT5ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
791 break;
792 }
793}
794
795static void FlipCopyDXT1BlockFull(const unsigned int* source, unsigned int* dest) {
796 // A DXT1 block layout is:
797 // [0-1] color0.
798 // [2-3] color1.
799 // [4-7] color bitmap, 2 bits per pixel.
800 // So each of the 4-7 bytes represents one line, flipping a block is just
801 // flipping those bytes.
802
803 // First 32-bits is two RGB565 colors shared by tile and does not need to be modified.
804 dest[0] = source[0];
805
806 // Second 32-bits contains 4 rows of 4 2-bit interpolants between the colors. All rows should be flipped.
807 dest[1] = (source[1] >> 24) |
808 ((source[1] << 8) & 0x00FF0000) |
809 ((source[1] >> 8) & 0x0000FF00) |
810 (source[1] << 24);
811}
812
813// Flips the first 2 lines of a DXT1 block in the y direction.
814static void FlipCopyDXT1BlockHalf(const unsigned int* source, unsigned int* dest) {
815 // See layout above.
816 dest[0] = source[0];
817 dest[1] = ((source[1] << 8) & 0x0000FF00) |
818 ((source[1] >> 8) & 0x000000FF);
819}
820
821// Flips a full DXT3 block in the y direction.
822static void FlipCopyDXT3BlockFull(const unsigned int* source, unsigned int* dest) {
823 // A DXT3 block layout is:
824 // [0-7] alpha bitmap, 4 bits per pixel.
825 // [8-15] a DXT1 block.
826
827 // First and Second 32 bits are 4bit per pixel alpha and need to be flipped.
828 dest[0] = (source[1] >> 16) | (source[1] << 16);
829 dest[1] = (source[0] >> 16) | (source[0] << 16);
830
831 // And flip the DXT1 block using the above function.
832 FlipCopyDXT1BlockFull(source + 2, dest + 2);
833}
834
835// Flips the first 2 lines of a DXT3 block in the y direction.
836static void FlipCopyDXT3BlockHalf(const unsigned int* source, unsigned int* dest) {
837 // See layout above.
838 dest[0] = (source[1] >> 16) | (source[1] << 16);
839 FlipCopyDXT1BlockHalf(source + 2, dest + 2);
840}
841
842// Flips a full DXT5 block in the y direction.
843static void FlipCopyDXT5BlockFull(const unsigned int* source, unsigned int* dest) {
844 // A DXT5 block layout is:
845 // [0] alpha0.
846 // [1] alpha1.
847 // [2-7] alpha bitmap, 3 bits per pixel.
848 // [8-15] a DXT1 block.
849
850 // The alpha bitmap doesn't easily map lines to bytes, so we have to
851 // interpret it correctly. Extracted from
852 // http://www.opengl.org/registry/specs/EXT/texture_compression_s3tc.txt :
853 //
854 // The 6 "bits" bytes of the block are decoded into one 48-bit integer:
855 //
856 // bits = bits_0 + 256 * (bits_1 + 256 * (bits_2 + 256 * (bits_3 +
857 // 256 * (bits_4 + 256 * bits_5))))
858 //
859 // bits is a 48-bit unsigned integer, from which a three-bit control code
860 // is extracted for a texel at location (x,y) in the block using:
861 //
862 // code(x,y) = bits[3*(4*y+x)+1..3*(4*y+x)+0]
863 //
864 // where bit 47 is the most significant and bit 0 is the least
865 // significant bit.
866 const unsigned char* sourceBytes = static_cast<const unsigned char*>(static_cast<const void*>(source));
867 unsigned char* destBytes = static_cast<unsigned char*>(static_cast<void*>(dest));
868 unsigned int line_0_1 = sourceBytes[2] + 256 * (sourceBytes[3] + 256 * sourceBytes[4]);
869 unsigned int line_2_3 = sourceBytes[5] + 256 * (sourceBytes[6] + 256 * sourceBytes[7]);
870 // swap lines 0 and 1 in line_0_1.
871 unsigned int line_1_0 = ((line_0_1 & 0x000fff) << 12) |
872 ((line_0_1 & 0xfff000) >> 12);
873 // swap lines 2 and 3 in line_2_3.
874 unsigned int line_3_2 = ((line_2_3 & 0x000fff) << 12) |
875 ((line_2_3 & 0xfff000) >> 12);
876 destBytes[0] = sourceBytes[0];
877 destBytes[1] = sourceBytes[1];
878 destBytes[2] = line_3_2 & 0xff;
879 destBytes[3] = (line_3_2 & 0xff00) >> 8;
gman@chromium.org2ac3e732011-08-10 07:59:47 +0000880 destBytes[4] = (line_3_2 & 0xff0000) >> 16;
gman@chromium.org50c526d2011-08-10 05:19:44 +0000881 destBytes[5] = line_1_0 & 0xff;
882 destBytes[6] = (line_1_0 & 0xff00) >> 8;
gman@chromium.org2ac3e732011-08-10 07:59:47 +0000883 destBytes[7] = (line_1_0 & 0xff0000) >> 16;
gman@chromium.org50c526d2011-08-10 05:19:44 +0000884
885 // And flip the DXT1 block using the above function.
886 FlipCopyDXT1BlockFull(source + 2, dest + 2);
887}
888
889// Flips the first 2 lines of a DXT5 block in the y direction.
890static void FlipCopyDXT5BlockHalf(const unsigned int* source, unsigned int* dest) {
891 // See layout above.
892 const unsigned char* sourceBytes = static_cast<const unsigned char*>(static_cast<const void*>(source));
893 unsigned char* destBytes = static_cast<unsigned char*>(static_cast<void*>(dest));
894 unsigned int line_0_1 = sourceBytes[2] + 256 * (sourceBytes[3] + 256 * sourceBytes[4]);
895 unsigned int line_1_0 = ((line_0_1 & 0x000fff) << 12) |
896 ((line_0_1 & 0xfff000) >> 12);
897 destBytes[0] = sourceBytes[0];
898 destBytes[1] = sourceBytes[1];
899 destBytes[2] = line_1_0 & 0xff;
900 destBytes[3] = (line_1_0 & 0xff00) >> 8;
gman@chromium.org25c5cf62011-08-10 08:07:54 +0000901 destBytes[4] = (line_1_0 & 0xff0000) >> 16;
gman@chromium.org50c526d2011-08-10 05:19:44 +0000902 FlipCopyDXT1BlockHalf(source + 2, dest + 2);
903}
904
905void Texture::loadDXT1ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000906 int inputPitch, const void *input, size_t outputPitch, void *output) const
907{
908 ASSERT(xoffset % 4 == 0);
909 ASSERT(yoffset % 4 == 0);
910 ASSERT(width % 4 == 0 || width == 2 || width == 1);
911 ASSERT(inputPitch % 8 == 0);
912 ASSERT(outputPitch % 8 == 0);
913
914 const unsigned int *source = reinterpret_cast<const unsigned int*>(input);
915 unsigned int *dest = reinterpret_cast<unsigned int*>(output);
916
gman@chromium.org50c526d2011-08-10 05:19:44 +0000917 // Round width up in case it is less than 4.
918 int blocksAcross = (width + 3) / 4;
919 int intsAcross = blocksAcross * 2;
920
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000921 switch (height)
922 {
923 case 1:
gman@chromium.org50c526d2011-08-10 05:19:44 +0000924 for (int x = 0; x < intsAcross; x += 2)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000925 {
gman@chromium.org50c526d2011-08-10 05:19:44 +0000926 // just copy the block
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000927 dest[x] = source[x];
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000928 dest[x + 1] = source[x + 1];
929 }
930 break;
931 case 2:
gman@chromium.org50c526d2011-08-10 05:19:44 +0000932 for (int x = 0; x < intsAcross; x += 2)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000933 {
gman@chromium.org50c526d2011-08-10 05:19:44 +0000934 FlipCopyDXT1BlockHalf(source + x, dest + x);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000935 }
936 break;
937 default:
938 ASSERT(height % 4 == 0);
939 for (int y = 0; y < height / 4; ++y)
940 {
941 const unsigned int *source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);
942 unsigned int *dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
943
gman@chromium.org50c526d2011-08-10 05:19:44 +0000944 for (int x = 0; x < intsAcross; x += 2)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000945 {
gman@chromium.org50c526d2011-08-10 05:19:44 +0000946 FlipCopyDXT1BlockFull(source + x, dest + x);
947 }
948 }
949 break;
950 }
951}
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000952
gman@chromium.org50c526d2011-08-10 05:19:44 +0000953void Texture::loadDXT3ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
954 int inputPitch, const void *input, size_t outputPitch, void *output) const
955{
956 ASSERT(xoffset % 4 == 0);
957 ASSERT(yoffset % 4 == 0);
958 ASSERT(width % 4 == 0 || width == 2 || width == 1);
959 ASSERT(inputPitch % 16 == 0);
960 ASSERT(outputPitch % 16 == 0);
961
962 const unsigned int *source = reinterpret_cast<const unsigned int*>(input);
963 unsigned int *dest = reinterpret_cast<unsigned int*>(output);
964
965 // Round width up in case it is less than 4.
966 int blocksAcross = (width + 3) / 4;
967 int intsAcross = blocksAcross * 4;
968
969 switch (height)
970 {
971 case 1:
972 for (int x = 0; x < intsAcross; x += 4)
973 {
974 // just copy the block
975 dest[x] = source[x];
976 dest[x + 1] = source[x + 1];
977 dest[x + 2] = source[x + 2];
978 dest[x + 3] = source[x + 3];
979 }
980 break;
981 case 2:
982 for (int x = 0; x < intsAcross; x += 4)
983 {
984 FlipCopyDXT3BlockHalf(source + x, dest + x);
985 }
986 break;
987 default:
988 ASSERT(height % 4 == 0);
989 for (int y = 0; y < height / 4; ++y)
990 {
991 const unsigned int *source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);
992 unsigned int *dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
993
994 for (int x = 0; x < intsAcross; x += 4)
995 {
996 FlipCopyDXT3BlockFull(source + x, dest + x);
997 }
998 }
999 break;
1000 }
1001}
1002
1003void Texture::loadDXT5ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
1004 int inputPitch, const void *input, size_t outputPitch, void *output) const
1005{
1006 ASSERT(xoffset % 4 == 0);
1007 ASSERT(yoffset % 4 == 0);
1008 ASSERT(width % 4 == 0 || width == 2 || width == 1);
1009 ASSERT(inputPitch % 16 == 0);
1010 ASSERT(outputPitch % 16 == 0);
1011
1012 const unsigned int *source = reinterpret_cast<const unsigned int*>(input);
1013 unsigned int *dest = reinterpret_cast<unsigned int*>(output);
1014
1015 // Round width up in case it is less than 4.
1016 int blocksAcross = (width + 3) / 4;
1017 int intsAcross = blocksAcross * 4;
1018
1019 switch (height)
1020 {
1021 case 1:
1022 for (int x = 0; x < intsAcross; x += 4)
1023 {
1024 // just copy the block
1025 dest[x] = source[x];
1026 dest[x + 1] = source[x + 1];
1027 dest[x + 2] = source[x + 2];
1028 dest[x + 3] = source[x + 3];
1029 }
1030 break;
1031 case 2:
1032 for (int x = 0; x < intsAcross; x += 4)
1033 {
1034 FlipCopyDXT5BlockHalf(source + x, dest + x);
1035 }
1036 break;
1037 default:
1038 ASSERT(height % 4 == 0);
gman@chromium.org2ac3e732011-08-10 07:59:47 +00001039 for (int y = 0; y < height / 4; ++y)
gman@chromium.org50c526d2011-08-10 05:19:44 +00001040 {
1041 const unsigned int *source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);
1042 unsigned int *dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
1043
1044 for (int x = 0; x < intsAcross; x += 4)
1045 {
1046 FlipCopyDXT5BlockFull(source + x, dest + x);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001047 }
1048 }
1049 break;
1050 }
1051}
1052
daniel@transgaming.comde631782011-11-09 17:45:04 +00001053void Image::createSurface()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001054{
daniel@transgaming.com31e22e12011-11-09 17:44:44 +00001055 if(surface)
daniel@transgaming.comc9ba4ad2011-11-09 17:44:35 +00001056 {
1057 return;
1058 }
1059
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001060 IDirect3DTexture9 *newTexture = NULL;
1061 IDirect3DSurface9 *newSurface = NULL;
1062
daniel@transgaming.com31e22e12011-11-09 17:44:44 +00001063 if (width != 0 && height != 0)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001064 {
1065 int levelToFetch = 0;
daniel@transgaming.com31e22e12011-11-09 17:44:44 +00001066 GLsizei requestWidth = width;
1067 GLsizei requestHeight = height;
1068 if (IsCompressed(format) && (width % 4 != 0 || height % 4 != 0))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001069 {
1070 bool isMult4 = false;
1071 int upsampleCount = 0;
1072 while (!isMult4)
1073 {
1074 requestWidth <<= 1;
1075 requestHeight <<= 1;
1076 upsampleCount++;
1077 if (requestWidth % 4 == 0 && requestHeight % 4 == 0)
1078 {
1079 isMult4 = true;
1080 }
1081 }
1082 levelToFetch = upsampleCount;
1083 }
1084
daniel@transgaming.com31e22e12011-11-09 17:44:44 +00001085 HRESULT result = getDevice()->CreateTexture(requestWidth, requestHeight, levelToFetch + 1, NULL, getD3DFormat(),
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001086 D3DPOOL_SYSTEMMEM, &newTexture, NULL);
1087
1088 if (FAILED(result))
1089 {
1090 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1091 return error(GL_OUT_OF_MEMORY);
1092 }
1093
1094 newTexture->GetSurfaceLevel(levelToFetch, &newSurface);
1095 newTexture->Release();
1096 }
1097
daniel@transgaming.com31e22e12011-11-09 17:44:44 +00001098 surface = newSurface;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001099}
1100
daniel@transgaming.com61208202011-03-21 16:38:50 +00001101void Texture::setImage(GLint unpackAlignment, const void *pixels, Image *image)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001102{
daniel@transgaming.com31e22e12011-11-09 17:44:44 +00001103 image->createSurface();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001104
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001105 if (pixels != NULL && image->surface != NULL)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001106 {
1107 D3DSURFACE_DESC description;
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001108 image->surface->GetDesc(&description);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001109
1110 D3DLOCKED_RECT locked;
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001111 HRESULT result = image->surface->LockRect(&locked, NULL, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001112
1113 ASSERT(SUCCEEDED(result));
1114
1115 if (SUCCEEDED(result))
1116 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001117 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 +00001118 image->surface->UnlockRect();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001119 }
1120
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001121 image->dirty = true;
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001122 mDirtyImages = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001123 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001124}
1125
daniel@transgaming.com61208202011-03-21 16:38:50 +00001126void Texture::setCompressedImage(GLsizei imageSize, const void *pixels, Image *image)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001127{
daniel@transgaming.com31e22e12011-11-09 17:44:44 +00001128 image->createSurface();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001129
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001130 if (pixels != NULL && image->surface != NULL)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001131 {
1132 D3DLOCKED_RECT locked;
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001133 HRESULT result = image->surface->LockRect(&locked, NULL, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001134
1135 ASSERT(SUCCEEDED(result));
1136
1137 if (SUCCEEDED(result))
1138 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001139 int inputPitch = ComputeCompressedPitch(image->width, image->format);
1140 int inputSize = ComputeCompressedSize(image->width, image->height, image->format);
1141 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 +00001142 image->surface->UnlockRect();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001143 }
1144
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001145 image->dirty = true;
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001146 mDirtyImages = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001147 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001148}
1149
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001150bool 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 +00001151{
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001152 if (width + xoffset > image->width || height + yoffset > image->height)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001153 {
1154 error(GL_INVALID_VALUE);
1155 return false;
1156 }
1157
jbauman@chromium.orge2f954c2011-05-03 20:45:27 +00001158 if (IsCompressed(image->format))
1159 {
1160 error(GL_INVALID_OPERATION);
1161 return false;
1162 }
1163
1164 if (format != image->format)
1165 {
1166 error(GL_INVALID_OPERATION);
1167 return false;
1168 }
1169
daniel@transgaming.com31e22e12011-11-09 17:44:44 +00001170 image->createSurface();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001171
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001172 if (pixels != NULL && image->surface != NULL)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001173 {
1174 D3DSURFACE_DESC description;
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001175 image->surface->GetDesc(&description);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001176
1177 D3DLOCKED_RECT locked;
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001178 HRESULT result = image->surface->LockRect(&locked, NULL, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001179
1180 ASSERT(SUCCEEDED(result));
1181
1182 if (SUCCEEDED(result))
1183 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001184 loadImageData(xoffset, transformPixelYOffset(yoffset, height, image->height), width, height, format, type, unpackAlignment, pixels, locked.Pitch, locked.pBits, &description);
1185 image->surface->UnlockRect();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001186 }
1187
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001188 image->dirty = true;
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001189 mDirtyImages = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001190 }
1191
1192 return true;
1193}
1194
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001195bool 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 +00001196{
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001197 if (width + xoffset > image->width || height + yoffset > image->height)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001198 {
1199 error(GL_INVALID_VALUE);
1200 return false;
1201 }
1202
1203 if (format != getInternalFormat())
1204 {
1205 error(GL_INVALID_OPERATION);
1206 return false;
1207 }
1208
daniel@transgaming.com31e22e12011-11-09 17:44:44 +00001209 image->createSurface();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001210
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001211 if (pixels != NULL && image->surface != NULL)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001212 {
1213 RECT updateRegion;
1214 updateRegion.left = xoffset;
1215 updateRegion.right = xoffset + width;
1216 updateRegion.bottom = yoffset + height;
1217 updateRegion.top = yoffset;
1218
1219 D3DLOCKED_RECT locked;
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001220 HRESULT result = image->surface->LockRect(&locked, &updateRegion, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001221
1222 ASSERT(SUCCEEDED(result));
1223
1224 if (SUCCEEDED(result))
1225 {
1226 int inputPitch = ComputeCompressedPitch(width, format);
1227 int inputSize = ComputeCompressedSize(width, height, format);
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001228 loadCompressedImageData(xoffset, transformPixelYOffset(yoffset, height, image->height), width, height, -inputPitch, static_cast<const char*>(pixels) + inputSize - inputPitch, locked.Pitch, locked.pBits);
1229 image->surface->UnlockRect();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001230 }
1231
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001232 image->dirty = true;
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001233 mDirtyImages = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001234 }
1235
1236 return true;
1237}
1238
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001239// This implements glCopyTex[Sub]Image2D for non-renderable internal texture formats and incomplete textures
1240void Texture::copyToImage(Image *image, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, IDirect3DSurface9 *renderTarget)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001241{
daniel@transgaming.com31e22e12011-11-09 17:44:44 +00001242 image->createSurface();
1243
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001244 if (!image->surface)
1245 {
daniel@transgaming.com31e22e12011-11-09 17:44:44 +00001246 ERR("Failed to create an image surface.");
1247 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001248 }
1249
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001250 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001251 IDirect3DSurface9 *renderTargetData = NULL;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001252 D3DSURFACE_DESC description;
1253 renderTarget->GetDesc(&description);
1254
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001255 HRESULT result = device->CreateOffscreenPlainSurface(description.Width, description.Height, description.Format, D3DPOOL_SYSTEMMEM, &renderTargetData, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001256
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001257 if (FAILED(result))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001258 {
1259 ERR("Could not create matching destination surface.");
1260 return error(GL_OUT_OF_MEMORY);
1261 }
1262
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001263 result = device->GetRenderTargetData(renderTarget, renderTargetData);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001264
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001265 if (FAILED(result))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001266 {
1267 ERR("GetRenderTargetData unexpectedly failed.");
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001268 renderTargetData->Release();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001269 return error(GL_OUT_OF_MEMORY);
1270 }
1271
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001272 RECT sourceRect = transformPixelRect(x, y, width, height, description.Height);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001273 int destYOffset = transformPixelYOffset(yoffset, height, image->height);
1274 RECT destRect = {xoffset, destYOffset, xoffset + width, destYOffset + height};
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001275
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001276 if (image->isRenderable())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001277 {
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001278 result = D3DXLoadSurfaceFromSurface(image->surface, NULL, &destRect, renderTargetData, NULL, &sourceRect, D3DX_FILTER_BOX, 0);
1279
1280 if (FAILED(result))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001281 {
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001282 ERR("Copying surfaces unexpectedly failed.");
1283 renderTargetData->Release();
1284 return error(GL_OUT_OF_MEMORY);
1285 }
1286 }
1287 else
1288 {
1289 D3DLOCKED_RECT sourceLock = {0};
1290 result = renderTargetData->LockRect(&sourceLock, &sourceRect, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001291
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001292 if (FAILED(result))
1293 {
1294 ERR("Failed to lock the source surface (rectangle might be invalid).");
1295 renderTargetData->Release();
1296 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001297 }
1298
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001299 D3DLOCKED_RECT destLock = {0};
1300 result = image->surface->LockRect(&destLock, &destRect, 0);
1301
1302 if (FAILED(result))
1303 {
1304 ERR("Failed to lock the destination surface (rectangle might be invalid).");
1305 renderTargetData->UnlockRect();
1306 renderTargetData->Release();
1307 return error(GL_OUT_OF_MEMORY);
1308 }
1309
1310 if (destLock.pBits && sourceLock.pBits)
1311 {
1312 unsigned char *source = (unsigned char*)sourceLock.pBits;
1313 unsigned char *dest = (unsigned char*)destLock.pBits;
1314
1315 switch (description.Format)
1316 {
1317 case D3DFMT_X8R8G8B8:
1318 case D3DFMT_A8R8G8B8:
1319 switch(image->getD3DFormat())
1320 {
1321 case D3DFMT_L8:
1322 for(int y = 0; y < height; y++)
1323 {
1324 for(int x = 0; x < width; x++)
1325 {
1326 dest[x] = source[x * 4 + 2];
1327 }
1328
1329 source += sourceLock.Pitch;
1330 dest += destLock.Pitch;
1331 }
1332 break;
1333 case D3DFMT_A8L8:
1334 for(int y = 0; y < height; y++)
1335 {
1336 for(int x = 0; x < width; x++)
1337 {
1338 dest[x * 2 + 0] = source[x * 4 + 2];
1339 dest[x * 2 + 1] = source[x * 4 + 3];
1340 }
1341
1342 source += sourceLock.Pitch;
1343 dest += destLock.Pitch;
1344 }
1345 break;
1346 default:
1347 UNREACHABLE();
1348 }
1349 break;
1350 case D3DFMT_R5G6B5:
1351 switch(image->getD3DFormat())
1352 {
1353 case D3DFMT_L8:
1354 for(int y = 0; y < height; y++)
1355 {
1356 for(int x = 0; x < width; x++)
1357 {
1358 unsigned char red = source[x * 2 + 1] & 0xF8;
1359 dest[x] = red | (red >> 5);
1360 }
1361
1362 source += sourceLock.Pitch;
1363 dest += destLock.Pitch;
1364 }
1365 break;
1366 default:
1367 UNREACHABLE();
1368 }
1369 break;
1370 case D3DFMT_A1R5G5B5:
1371 switch(image->getD3DFormat())
1372 {
1373 case D3DFMT_L8:
1374 for(int y = 0; y < height; y++)
1375 {
1376 for(int x = 0; x < width; x++)
1377 {
1378 unsigned char red = source[x * 2 + 1] & 0x7C;
1379 dest[x] = (red << 1) | (red >> 4);
1380 }
1381
1382 source += sourceLock.Pitch;
1383 dest += destLock.Pitch;
1384 }
1385 break;
1386 case D3DFMT_A8L8:
1387 for(int y = 0; y < height; y++)
1388 {
1389 for(int x = 0; x < width; x++)
1390 {
1391 unsigned char red = source[x * 2 + 1] & 0x7C;
1392 dest[x * 2 + 0] = (red << 1) | (red >> 4);
1393 dest[x * 2 + 1] = (signed char)source[x * 2 + 1] >> 7;
1394 }
1395
1396 source += sourceLock.Pitch;
1397 dest += destLock.Pitch;
1398 }
1399 break;
1400 default:
1401 UNREACHABLE();
1402 }
1403 break;
1404 default:
1405 UNREACHABLE();
1406 }
1407 }
1408
1409 image->surface->UnlockRect();
1410 renderTargetData->UnlockRect();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001411 }
1412
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001413 renderTargetData->Release();
1414
1415 image->dirty = true;
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001416 mDirtyImages = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001417}
1418
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001419IDirect3DBaseTexture9 *Texture::getTexture()
1420{
1421 if (!isComplete())
1422 {
1423 return NULL;
1424 }
1425
daniel@transgaming.comaed18322011-03-21 16:38:13 +00001426 if (!getBaseTexture())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001427 {
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001428 createTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001429 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001430
daniel@transgaming.comc50edcb2011-03-21 16:38:40 +00001431 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001432
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001433 return getBaseTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001434}
1435
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001436bool Texture::hasDirtyParameters() const
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001437{
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001438 return mDirtyParameters;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00001439}
1440
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001441bool Texture::hasDirtyImages() const
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00001442{
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001443 return mDirtyImages;
daniel@transgaming.com38e76e52011-03-21 16:39:10 +00001444}
1445
1446void Texture::resetDirty()
1447{
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001448 mDirtyParameters = false;
1449 mDirtyImages = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001450}
1451
daniel@transgaming.coma9eb5da2011-03-21 16:39:16 +00001452unsigned int Texture::getSerial() const
1453{
1454 return mSerial;
1455}
1456
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001457GLint Texture::creationLevels(GLsizei width, GLsizei height, GLint maxlevel) const
1458{
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00001459 if ((isPow2(width) && isPow2(height)) || getContext()->supportsNonPower2Texture())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001460 {
1461 return maxlevel;
1462 }
1463 else
1464 {
1465 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
1466 return 1;
1467 }
1468}
1469
1470GLint Texture::creationLevels(GLsizei size, GLint maxlevel) const
1471{
1472 return creationLevels(size, size, maxlevel);
1473}
1474
1475int Texture::levelCount() const
1476{
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001477 return getBaseTexture() ? getBaseTexture()->GetLevelCount() : 0;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001478}
1479
daniel@transgaming.coma9eb5da2011-03-21 16:39:16 +00001480unsigned int Texture::issueSerial()
1481{
1482 return mCurrentSerial++;
1483}
1484
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001485Texture2D::Texture2D(GLuint id) : Texture(id)
1486{
1487 mTexture = NULL;
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001488 mSurface = NULL;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001489}
1490
1491Texture2D::~Texture2D()
1492{
1493 mColorbufferProxy.set(NULL);
1494
1495 if (mTexture)
1496 {
1497 mTexture->Release();
1498 mTexture = NULL;
1499 }
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001500
1501 if (mSurface)
1502 {
1503 mSurface->setBoundTexture(NULL);
1504 mSurface = NULL;
1505 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001506}
1507
1508GLenum Texture2D::getTarget() const
1509{
1510 return GL_TEXTURE_2D;
1511}
1512
daniel@transgaming.com61208202011-03-21 16:38:50 +00001513GLsizei Texture2D::getWidth() const
1514{
1515 return mImageArray[0].width;
1516}
1517
1518GLsizei Texture2D::getHeight() const
1519{
1520 return mImageArray[0].height;
1521}
1522
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001523GLenum Texture2D::getInternalFormat() const
1524{
1525 return mImageArray[0].format;
1526}
1527
daniel@transgaming.com61208202011-03-21 16:38:50 +00001528GLenum Texture2D::getType() const
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001529{
daniel@transgaming.com61208202011-03-21 16:38:50 +00001530 return mImageArray[0].type;
1531}
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001532
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001533D3DFORMAT Texture2D::getD3DFormat() const
1534{
1535 return mImageArray[0].getD3DFormat();
1536}
1537
daniel@transgaming.comde631782011-11-09 17:45:04 +00001538void Image::redefine(GLenum format, GLsizei width, GLsizei height, GLenum type)
daniel@transgaming.com68ae2992011-11-09 17:44:49 +00001539{
1540 this->width = width;
1541 this->height = height;
1542 this->format = format;
1543 this->type = type;
1544
1545 if (surface)
1546 {
1547 surface->Release();
1548 surface = NULL;
1549 dirty = true;
1550 }
1551
1552 createSurface();
1553}
1554
1555void Texture2D::redefineImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLenum type, bool forceRedefine)
daniel@transgaming.com61208202011-03-21 16:38:50 +00001556{
daniel@transgaming.com94a4f032011-03-21 16:38:55 +00001557 GLsizei textureWidth = mImageArray[0].width;
1558 GLsizei textureHeight = mImageArray[0].height;
1559 GLenum textureFormat = mImageArray[0].format;
1560 GLenum textureType = mImageArray[0].type;
1561
daniel@transgaming.com68ae2992011-11-09 17:44:49 +00001562 mImageArray[level].redefine(format, width, height, type);
daniel@transgaming.comc9ba4ad2011-11-09 17:44:35 +00001563
daniel@transgaming.com61208202011-03-21 16:38:50 +00001564 if (!mTexture)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001565 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001566 return;
1567 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001568
daniel@transgaming.com94a4f032011-03-21 16:38:55 +00001569 bool widthOkay = (textureWidth >> level == width) || (textureWidth >> level == 0 && width == 1);
1570 bool heightOkay = (textureHeight >> level == height) || (textureHeight >> level == 0 && height == 1);
1571 bool textureOkay = (widthOkay && heightOkay && textureFormat == format && textureType == type);
daniel@transgaming.com61208202011-03-21 16:38:50 +00001572
daniel@transgaming.comc9ba4ad2011-11-09 17:44:35 +00001573 if (!textureOkay || forceRedefine || mSurface)
daniel@transgaming.com61208202011-03-21 16:38:50 +00001574 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001575 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1576 {
daniel@transgaming.comc9ba4ad2011-11-09 17:44:35 +00001577 mImageArray[i].dirty = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001578 }
1579
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001580 mTexture->Release();
1581 mTexture = NULL;
1582 mDirtyImages = true;
1583 mIsRenderable = false;
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001584
1585 if (mSurface)
1586 {
1587 mSurface->setBoundTexture(NULL);
1588 mSurface = NULL;
1589 }
apatrick@chromium.org57a2cd62011-06-08 00:04:07 +00001590
1591 mColorbufferProxy.set(NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001592 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001593}
1594
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001595void 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 +00001596{
daniel@transgaming.com68ae2992011-11-09 17:44:49 +00001597 redefineImage(level, format, width, height, type, false);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001598
daniel@transgaming.com61208202011-03-21 16:38:50 +00001599 Texture::setImage(unpackAlignment, pixels, &mImageArray[level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001600}
1601
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001602void Texture2D::bindTexImage(egl::Surface *surface)
1603{
1604 GLenum format;
1605
1606 switch(surface->getFormat())
1607 {
1608 case D3DFMT_A8R8G8B8:
1609 format = GL_RGBA;
1610 break;
1611 case D3DFMT_X8R8G8B8:
1612 format = GL_RGB;
1613 break;
1614 default:
1615 UNIMPLEMENTED();
1616 return;
1617 }
1618
daniel@transgaming.com68ae2992011-11-09 17:44:49 +00001619 redefineImage(0, format, surface->getWidth(), surface->getHeight(), GL_UNSIGNED_BYTE, true);
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001620
1621 IDirect3DTexture9 *texture = surface->getOffscreenTexture();
1622
1623 mTexture = texture;
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001624 mDirtyImages = true;
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001625 mIsRenderable = true;
1626 mSurface = surface;
1627 mSurface->setBoundTexture(this);
1628}
1629
1630void Texture2D::releaseTexImage()
1631{
daniel@transgaming.com68ae2992011-11-09 17:44:49 +00001632 redefineImage(0, GL_RGB, 0, 0, GL_UNSIGNED_BYTE, true);
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001633}
1634
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001635void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001636{
daniel@transgaming.com68ae2992011-11-09 17:44:49 +00001637 redefineImage(level, format, width, height, GL_UNSIGNED_BYTE, false);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001638
daniel@transgaming.com61208202011-03-21 16:38:50 +00001639 Texture::setCompressedImage(imageSize, pixels, &mImageArray[level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001640}
1641
1642void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1643{
1644 ASSERT(mImageArray[level].surface != NULL);
1645
1646 if (level < levelCount())
1647 {
1648 IDirect3DSurface9 *destLevel = NULL;
1649 HRESULT result = mTexture->GetSurfaceLevel(level, &destLevel);
1650
1651 ASSERT(SUCCEEDED(result));
1652
1653 if (SUCCEEDED(result))
1654 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001655 Image *image = &mImageArray[level];
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001656
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001657 RECT sourceRect = transformPixelRect(xoffset, yoffset, width, height, image->height);;
daniel@transgaming.comb612f882011-11-09 17:44:31 +00001658 POINT destPoint = {sourceRect.left, sourceRect.top};
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001659
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001660 result = getDevice()->UpdateSurface(image->surface, &sourceRect, destLevel, &destPoint);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001661 ASSERT(SUCCEEDED(result));
1662
1663 destLevel->Release();
1664
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001665 image->dirty = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001666 }
1667 }
1668}
1669
1670void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1671{
1672 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[level]))
1673 {
1674 commitRect(level, xoffset, yoffset, width, height);
1675 }
1676}
1677
1678void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1679{
1680 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[level]))
1681 {
1682 commitRect(level, xoffset, yoffset, width, height);
1683 }
1684}
1685
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001686void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001687{
1688 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
1689
1690 if (!renderTarget)
1691 {
1692 ERR("Failed to retrieve the render target.");
1693 return error(GL_OUT_OF_MEMORY);
1694 }
1695
daniel@transgaming.com68ae2992011-11-09 17:44:49 +00001696 redefineImage(level, format, width, height, GL_UNSIGNED_BYTE, false);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001697
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001698 if (!mImageArray[level].isRenderable())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001699 {
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001700 copyToImage(&mImageArray[level], 0, 0, x, y, width, height, renderTarget);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001701 }
1702 else
1703 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001704 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001705 {
1706 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001707 }
daniel@transgaming.com3b3c1d42011-06-08 20:38:09 +00001708
daniel@transgaming.com9ab8e3e2011-11-09 17:44:39 +00001709 mImageArray[level].dirty = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001710
1711 if (width != 0 && height != 0 && level < levelCount())
1712 {
1713 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
1714 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
1715 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
1716 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
1717 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
daniel@transgaming.comeef864a2011-04-22 11:33:27 +00001718
1719 GLint destYOffset = transformPixelYOffset(0, height, mImageArray[level].height);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001720
1721 IDirect3DSurface9 *dest;
1722 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
1723
daniel@transgaming.comeef864a2011-04-22 11:33:27 +00001724 getBlitter()->copy(source->getRenderTarget(), sourceRect, format, 0, destYOffset, dest);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001725 dest->Release();
1726 }
1727 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001728}
1729
1730void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1731{
1732 if (xoffset + width > mImageArray[level].width || yoffset + height > mImageArray[level].height)
1733 {
1734 return error(GL_INVALID_VALUE);
1735 }
1736
1737 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
1738
1739 if (!renderTarget)
1740 {
1741 ERR("Failed to retrieve the render target.");
1742 return error(GL_OUT_OF_MEMORY);
1743 }
1744
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001745 if (!mImageArray[level].isRenderable() || (!mTexture && !isComplete()))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001746 {
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001747 copyToImage(&mImageArray[level], xoffset, yoffset, x, y, width, height, renderTarget);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001748 }
1749 else
1750 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001751 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001752 {
1753 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001754 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00001755
1756 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001757
1758 if (level < levelCount())
1759 {
1760 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
1761 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
1762 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
1763 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
1764 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
1765
1766 GLint destYOffset = transformPixelYOffset(yoffset, height, mImageArray[level].height);
1767
1768 IDirect3DSurface9 *dest;
1769 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
1770
daniel@transgaming.comeef864a2011-04-22 11:33:27 +00001771 getBlitter()->copy(source->getRenderTarget(), sourceRect, mImageArray[0].format, xoffset, destYOffset, dest);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001772 dest->Release();
1773 }
1774 }
1775}
1776
1777// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1778bool Texture2D::isComplete() const
1779{
1780 GLsizei width = mImageArray[0].width;
1781 GLsizei height = mImageArray[0].height;
1782
1783 if (width <= 0 || height <= 0)
1784 {
1785 return false;
1786 }
1787
1788 bool mipmapping = false;
1789
1790 switch (mMinFilter)
1791 {
1792 case GL_NEAREST:
1793 case GL_LINEAR:
1794 mipmapping = false;
1795 break;
1796 case GL_NEAREST_MIPMAP_NEAREST:
1797 case GL_LINEAR_MIPMAP_NEAREST:
1798 case GL_NEAREST_MIPMAP_LINEAR:
1799 case GL_LINEAR_MIPMAP_LINEAR:
1800 mipmapping = true;
1801 break;
1802 default: UNREACHABLE();
1803 }
1804
1805 if ((getInternalFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) ||
1806 (getInternalFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter()))
1807 {
1808 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
1809 {
1810 return false;
1811 }
1812 }
1813
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00001814 bool npot = getContext()->supportsNonPower2Texture();
1815
1816 if (!npot)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001817 {
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00001818 if ((getWrapS() != GL_CLAMP_TO_EDGE && !isPow2(width)) ||
1819 (getWrapT() != GL_CLAMP_TO_EDGE && !isPow2(height)))
1820 {
1821 return false;
1822 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001823 }
1824
1825 if (mipmapping)
1826 {
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00001827 if (!npot)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001828 {
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00001829 if (!isPow2(width) || !isPow2(height))
1830 {
1831 return false;
1832 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001833 }
1834
1835 int q = log2(std::max(width, height));
1836
1837 for (int level = 1; level <= q; level++)
1838 {
1839 if (mImageArray[level].format != mImageArray[0].format)
1840 {
1841 return false;
1842 }
1843
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00001844 if (mImageArray[level].type != mImageArray[0].type)
1845 {
1846 return false;
1847 }
1848
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001849 if (mImageArray[level].width != std::max(1, width >> level))
1850 {
1851 return false;
1852 }
1853
1854 if (mImageArray[level].height != std::max(1, height >> level))
1855 {
1856 return false;
1857 }
1858 }
1859 }
1860
1861 return true;
1862}
1863
1864bool Texture2D::isCompressed() const
1865{
1866 return IsCompressed(getInternalFormat());
1867}
1868
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001869IDirect3DBaseTexture9 *Texture2D::getBaseTexture() const
1870{
1871 return mTexture;
1872}
1873
1874// Constructs a Direct3D 9 texture resource from the texture images
1875void Texture2D::createTexture()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001876{
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001877 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001878 D3DFORMAT format = mImageArray[0].getD3DFormat();
daniel@transgaming.com61208202011-03-21 16:38:50 +00001879 GLint levels = creationLevels(mImageArray[0].width, mImageArray[0].height, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001880
daniel@transgaming.com61208202011-03-21 16:38:50 +00001881 IDirect3DTexture9 *texture = NULL;
1882 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 +00001883
1884 if (FAILED(result))
1885 {
1886 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001887 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001888 }
1889
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001890 if (mTexture)
1891 {
1892 mTexture->Release();
1893 }
1894
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001895 mTexture = texture;
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001896 mDirtyImages = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00001897 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001898}
1899
1900void Texture2D::updateTexture()
1901{
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001902 int levels = levelCount();
1903
1904 for (int level = 0; level < levels; level++)
1905 {
daniel@transgaming.comb612f882011-11-09 17:44:31 +00001906 Image *image = &mImageArray[level];
1907
1908 if (image->surface && image->dirty)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001909 {
daniel@transgaming.comb612f882011-11-09 17:44:31 +00001910 commitRect(level, 0, 0, mImageArray[level].width, mImageArray[level].height);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001911 }
1912 }
1913}
1914
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001915void Texture2D::convertToRenderTarget()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001916{
1917 IDirect3DTexture9 *texture = NULL;
1918
daniel@transgaming.com61208202011-03-21 16:38:50 +00001919 if (mImageArray[0].width != 0 && mImageArray[0].height != 0)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001920 {
1921 egl::Display *display = getDisplay();
1922 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001923 D3DFORMAT format = mImageArray[0].getD3DFormat();
daniel@transgaming.com61208202011-03-21 16:38:50 +00001924 GLint levels = creationLevels(mImageArray[0].width, mImageArray[0].height, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001925
daniel@transgaming.com61208202011-03-21 16:38:50 +00001926 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 +00001927
1928 if (FAILED(result))
1929 {
1930 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001931 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001932 }
1933
1934 if (mTexture != NULL)
1935 {
1936 int levels = levelCount();
1937 for (int i = 0; i < levels; i++)
1938 {
1939 IDirect3DSurface9 *source;
1940 result = mTexture->GetSurfaceLevel(i, &source);
1941
1942 if (FAILED(result))
1943 {
1944 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1945
1946 texture->Release();
1947
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001948 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001949 }
1950
1951 IDirect3DSurface9 *dest;
1952 result = texture->GetSurfaceLevel(i, &dest);
1953
1954 if (FAILED(result))
1955 {
1956 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1957
1958 texture->Release();
1959 source->Release();
1960
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001961 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001962 }
1963
1964 display->endScene();
1965 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
1966
1967 if (FAILED(result))
1968 {
1969 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1970
1971 texture->Release();
1972 source->Release();
1973 dest->Release();
1974
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001975 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001976 }
1977
1978 source->Release();
1979 dest->Release();
1980 }
1981 }
1982 }
1983
1984 if (mTexture != NULL)
1985 {
1986 mTexture->Release();
1987 }
1988
1989 mTexture = texture;
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001990 mDirtyImages = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00001991 mIsRenderable = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001992}
1993
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001994void Texture2D::generateMipmaps()
1995{
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00001996 if (!getContext()->supportsNonPower2Texture())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001997 {
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00001998 if (!isPow2(mImageArray[0].width) || !isPow2(mImageArray[0].height))
1999 {
2000 return error(GL_INVALID_OPERATION);
2001 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002002 }
2003
2004 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
daniel@transgaming.com61208202011-03-21 16:38:50 +00002005 unsigned int q = log2(std::max(mImageArray[0].width, mImageArray[0].height));
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002006 for (unsigned int i = 1; i <= q; i++)
2007 {
2008 if (mImageArray[i].surface != NULL)
2009 {
2010 mImageArray[i].surface->Release();
2011 mImageArray[i].surface = NULL;
2012 }
2013
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002014 mImageArray[i].width = std::max(mImageArray[0].width >> i, 1);
2015 mImageArray[i].height = std::max(mImageArray[0].height >> i, 1);
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00002016 mImageArray[i].format = mImageArray[0].format;
2017 mImageArray[i].type = mImageArray[0].type;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002018 }
2019
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002020 if (mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002021 {
2022 if (mTexture == NULL)
2023 {
2024 ERR(" failed because mTexture was null.");
2025 return;
2026 }
2027
2028 for (unsigned int i = 1; i <= q; i++)
2029 {
2030 IDirect3DSurface9 *upper = NULL;
2031 IDirect3DSurface9 *lower = NULL;
2032
2033 mTexture->GetSurfaceLevel(i-1, &upper);
2034 mTexture->GetSurfaceLevel(i, &lower);
2035
2036 if (upper != NULL && lower != NULL)
2037 {
2038 getBlitter()->boxFilter(upper, lower);
2039 }
2040
2041 if (upper != NULL) upper->Release();
2042 if (lower != NULL) lower->Release();
daniel@transgaming.com61208202011-03-21 16:38:50 +00002043
2044 mImageArray[i].dirty = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002045 }
2046 }
2047 else
2048 {
2049 for (unsigned int i = 1; i <= q; i++)
2050 {
daniel@transgaming.com31e22e12011-11-09 17:44:44 +00002051 mImageArray[i].createSurface();
daniel@transgaming.com61208202011-03-21 16:38:50 +00002052
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002053 if (mImageArray[i].surface == NULL)
2054 {
2055 return error(GL_OUT_OF_MEMORY);
2056 }
2057
2058 if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[i].surface, NULL, NULL, mImageArray[i - 1].surface, NULL, NULL, D3DX_FILTER_BOX, 0)))
2059 {
2060 ERR(" failed to load filter %d to %d.", i - 1, i);
2061 }
2062
2063 mImageArray[i].dirty = true;
2064 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002065 }
2066}
2067
2068Renderbuffer *Texture2D::getRenderbuffer(GLenum target)
2069{
2070 if (target != GL_TEXTURE_2D)
2071 {
2072 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
2073 }
2074
2075 if (mColorbufferProxy.get() == NULL)
2076 {
2077 mColorbufferProxy.set(new Renderbuffer(id(), new Colorbuffer(this, target)));
2078 }
2079
2080 return mColorbufferProxy.get();
2081}
2082
2083IDirect3DSurface9 *Texture2D::getRenderTarget(GLenum target)
2084{
2085 ASSERT(target == GL_TEXTURE_2D);
2086
daniel@transgaming.com61208202011-03-21 16:38:50 +00002087 if (!mIsRenderable)
2088 {
2089 convertToRenderTarget();
2090 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002091
2092 if (mTexture == NULL)
2093 {
2094 return NULL;
2095 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00002096
2097 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002098
2099 IDirect3DSurface9 *renderTarget = NULL;
2100 mTexture->GetSurfaceLevel(0, &renderTarget);
2101
2102 return renderTarget;
2103}
2104
2105TextureCubeMap::TextureCubeMap(GLuint id) : Texture(id)
2106{
2107 mTexture = NULL;
2108}
2109
2110TextureCubeMap::~TextureCubeMap()
2111{
2112 for (int i = 0; i < 6; i++)
2113 {
2114 mFaceProxies[i].set(NULL);
2115 }
2116
2117 if (mTexture)
2118 {
2119 mTexture->Release();
2120 mTexture = NULL;
2121 }
2122}
2123
2124GLenum TextureCubeMap::getTarget() const
2125{
2126 return GL_TEXTURE_CUBE_MAP;
2127}
2128
daniel@transgaming.com61208202011-03-21 16:38:50 +00002129GLsizei TextureCubeMap::getWidth() const
2130{
2131 return mImageArray[0][0].width;
2132}
2133
2134GLsizei TextureCubeMap::getHeight() const
2135{
2136 return mImageArray[0][0].height;
2137}
2138
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002139GLenum TextureCubeMap::getInternalFormat() const
2140{
2141 return mImageArray[0][0].format;
2142}
2143
daniel@transgaming.com61208202011-03-21 16:38:50 +00002144GLenum TextureCubeMap::getType() const
2145{
2146 return mImageArray[0][0].type;
2147}
2148
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002149D3DFORMAT TextureCubeMap::getD3DFormat() const
2150{
2151 return mImageArray[0][0].getD3DFormat();
2152}
2153
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002154void 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 +00002155{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002156 setImage(0, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002157}
2158
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002159void 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 +00002160{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002161 setImage(1, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002162}
2163
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002164void 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 +00002165{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002166 setImage(2, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002167}
2168
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002169void 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 +00002170{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002171 setImage(3, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002172}
2173
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002174void 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 +00002175{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002176 setImage(4, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002177}
2178
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002179void 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 +00002180{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002181 setImage(5, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002182}
2183
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002184void 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 +00002185{
daniel@transgaming.com68ae2992011-11-09 17:44:49 +00002186 redefineImage(faceIndex(face), level, format, width, height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002187
daniel@transgaming.com61208202011-03-21 16:38:50 +00002188 Texture::setCompressedImage(imageSize, pixels, &mImageArray[faceIndex(face)][level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002189}
2190
daniel@transgaming.comb612f882011-11-09 17:44:31 +00002191void TextureCubeMap::commitRect(int face, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002192{
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002193 ASSERT(mImageArray[face][level].surface != NULL);
2194
2195 if (level < levelCount())
2196 {
daniel@transgaming.comb612f882011-11-09 17:44:31 +00002197 IDirect3DSurface9 *destLevel = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002198 ASSERT(destLevel != NULL);
2199
2200 if (destLevel != NULL)
2201 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00002202 Image *image = &mImageArray[face][level];
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002203
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00002204 RECT sourceRect = transformPixelRect(xoffset, yoffset, width, height, image->height);;
daniel@transgaming.comb612f882011-11-09 17:44:31 +00002205 POINT destPoint = {sourceRect.left, sourceRect.top};
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002206
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00002207 HRESULT result = getDevice()->UpdateSurface(image->surface, &sourceRect, destLevel, &destPoint);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002208 ASSERT(SUCCEEDED(result));
2209
2210 destLevel->Release();
2211
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00002212 image->dirty = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002213 }
2214 }
2215}
2216
2217void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
2218{
2219 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[faceIndex(target)][level]))
2220 {
daniel@transgaming.comb612f882011-11-09 17:44:31 +00002221 commitRect(faceIndex(target), level, xoffset, yoffset, width, height);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002222 }
2223}
2224
2225void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
2226{
2227 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[faceIndex(target)][level]))
2228 {
daniel@transgaming.comb612f882011-11-09 17:44:31 +00002229 commitRect(faceIndex(target), level, xoffset, yoffset, width, height);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002230 }
2231}
2232
2233// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
2234bool TextureCubeMap::isComplete() const
2235{
2236 int size = mImageArray[0][0].width;
2237
2238 if (size <= 0)
2239 {
2240 return false;
2241 }
2242
2243 bool mipmapping;
2244
2245 switch (mMinFilter)
2246 {
2247 case GL_NEAREST:
2248 case GL_LINEAR:
2249 mipmapping = false;
2250 break;
2251 case GL_NEAREST_MIPMAP_NEAREST:
2252 case GL_LINEAR_MIPMAP_NEAREST:
2253 case GL_NEAREST_MIPMAP_LINEAR:
2254 case GL_LINEAR_MIPMAP_LINEAR:
2255 mipmapping = true;
2256 break;
2257 default: UNREACHABLE();
2258 }
2259
2260 for (int face = 0; face < 6; face++)
2261 {
2262 if (mImageArray[face][0].width != size || mImageArray[face][0].height != size)
2263 {
2264 return false;
2265 }
2266 }
2267
2268 if ((getInternalFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) ||
2269 (getInternalFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter()))
2270 {
2271 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
2272 {
2273 return false;
2274 }
2275 }
2276
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00002277 bool npot = getContext()->supportsNonPower2Texture();
2278
2279 if (!npot)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002280 {
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00002281 if ((getWrapS() != GL_CLAMP_TO_EDGE || getWrapT() != GL_CLAMP_TO_EDGE) && !isPow2(size))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002282 {
2283 return false;
2284 }
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00002285 }
2286
2287 if (mipmapping)
2288 {
2289 if (!npot)
2290 {
2291 if (!isPow2(size))
2292 {
2293 return false;
2294 }
2295 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002296
2297 int q = log2(size);
2298
2299 for (int face = 0; face < 6; face++)
2300 {
2301 for (int level = 1; level <= q; level++)
2302 {
2303 if (mImageArray[face][level].format != mImageArray[0][0].format)
2304 {
2305 return false;
2306 }
2307
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00002308 if (mImageArray[face][level].type != mImageArray[0][0].type)
2309 {
2310 return false;
2311 }
2312
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002313 if (mImageArray[face][level].width != std::max(1, size >> level))
2314 {
2315 return false;
2316 }
2317
2318 ASSERT(mImageArray[face][level].height == mImageArray[face][level].width);
2319 }
2320 }
2321 }
2322
2323 return true;
2324}
2325
2326bool TextureCubeMap::isCompressed() const
2327{
2328 return IsCompressed(getInternalFormat());
2329}
2330
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002331IDirect3DBaseTexture9 *TextureCubeMap::getBaseTexture() const
2332{
2333 return mTexture;
2334}
2335
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002336// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002337void TextureCubeMap::createTexture()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002338{
2339 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002340 D3DFORMAT format = mImageArray[0][0].getD3DFormat();
daniel@transgaming.com61208202011-03-21 16:38:50 +00002341 GLint levels = creationLevels(mImageArray[0][0].width, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002342
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00002343 IDirect3DCubeTexture9 *texture = NULL;
daniel@transgaming.com61208202011-03-21 16:38:50 +00002344 HRESULT result = device->CreateCubeTexture(mImageArray[0][0].width, levels, 0, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002345
2346 if (FAILED(result))
2347 {
2348 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002349 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002350 }
2351
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002352 if (mTexture)
2353 {
2354 mTexture->Release();
2355 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002356
2357 mTexture = texture;
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00002358 mDirtyImages = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00002359 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002360}
2361
2362void TextureCubeMap::updateTexture()
2363{
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002364 for (int face = 0; face < 6; face++)
2365 {
2366 int levels = levelCount();
2367 for (int level = 0; level < levels; level++)
2368 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00002369 Image *image = &mImageArray[face][level];
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002370
daniel@transgaming.com61208202011-03-21 16:38:50 +00002371 if (image->surface && image->dirty)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002372 {
daniel@transgaming.comb612f882011-11-09 17:44:31 +00002373 commitRect(face, level, 0, 0, image->width, image->height);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002374 }
2375 }
2376 }
2377}
2378
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002379void TextureCubeMap::convertToRenderTarget()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002380{
2381 IDirect3DCubeTexture9 *texture = NULL;
2382
daniel@transgaming.com61208202011-03-21 16:38:50 +00002383 if (mImageArray[0][0].width != 0)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002384 {
2385 egl::Display *display = getDisplay();
2386 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002387 D3DFORMAT format = mImageArray[0][0].getD3DFormat();
daniel@transgaming.com61208202011-03-21 16:38:50 +00002388 GLint levels = creationLevels(mImageArray[0][0].width, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002389
daniel@transgaming.com61208202011-03-21 16:38:50 +00002390 HRESULT result = device->CreateCubeTexture(mImageArray[0][0].width, levels, D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002391
2392 if (FAILED(result))
2393 {
2394 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002395 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002396 }
2397
2398 if (mTexture != NULL)
2399 {
2400 int levels = levelCount();
2401 for (int f = 0; f < 6; f++)
2402 {
2403 for (int i = 0; i < levels; i++)
2404 {
2405 IDirect3DSurface9 *source;
2406 result = mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &source);
2407
2408 if (FAILED(result))
2409 {
2410 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2411
2412 texture->Release();
2413
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002414 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002415 }
2416
2417 IDirect3DSurface9 *dest;
2418 result = texture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &dest);
2419
2420 if (FAILED(result))
2421 {
2422 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2423
2424 texture->Release();
2425 source->Release();
2426
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002427 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002428 }
2429
2430 display->endScene();
2431 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
2432
2433 if (FAILED(result))
2434 {
2435 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2436
2437 texture->Release();
2438 source->Release();
2439 dest->Release();
2440
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002441 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002442 }
daniel@transgaming.coma1a86202011-08-09 13:41:08 +00002443
2444 source->Release();
2445 dest->Release();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002446 }
2447 }
2448 }
2449 }
2450
2451 if (mTexture != NULL)
2452 {
2453 mTexture->Release();
2454 }
2455
2456 mTexture = texture;
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00002457 mDirtyImages = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00002458 mIsRenderable = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002459}
2460
daniel@transgaming.com61208202011-03-21 16:38:50 +00002461void 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 +00002462{
daniel@transgaming.com68ae2992011-11-09 17:44:49 +00002463 redefineImage(faceIndex, level, format, width, height, type);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002464
daniel@transgaming.com61208202011-03-21 16:38:50 +00002465 Texture::setImage(unpackAlignment, pixels, &mImageArray[faceIndex][level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002466}
2467
2468unsigned int TextureCubeMap::faceIndex(GLenum face)
2469{
2470 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
2471 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
2472 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
2473 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
2474 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
2475
2476 return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
2477}
2478
daniel@transgaming.com68ae2992011-11-09 17:44:49 +00002479void TextureCubeMap::redefineImage(int face, GLint level, GLenum format, GLsizei width, GLsizei height, GLenum type)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002480{
daniel@transgaming.com94a4f032011-03-21 16:38:55 +00002481 GLsizei textureWidth = mImageArray[0][0].width;
2482 GLsizei textureHeight = mImageArray[0][0].height;
2483 GLenum textureFormat = mImageArray[0][0].format;
2484 GLenum textureType = mImageArray[0][0].type;
2485
daniel@transgaming.com68ae2992011-11-09 17:44:49 +00002486 mImageArray[face][level].redefine(format, width, height, type);
daniel@transgaming.comc9ba4ad2011-11-09 17:44:35 +00002487
daniel@transgaming.com61208202011-03-21 16:38:50 +00002488 if (!mTexture)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002489 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00002490 return;
2491 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002492
daniel@transgaming.com94a4f032011-03-21 16:38:55 +00002493 bool sizeOkay = (textureWidth >> level == width);
2494 bool textureOkay = (sizeOkay && textureFormat == format && textureType == type);
daniel@transgaming.com61208202011-03-21 16:38:50 +00002495
daniel@transgaming.comc9ba4ad2011-11-09 17:44:35 +00002496 if (!textureOkay)
daniel@transgaming.com61208202011-03-21 16:38:50 +00002497 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002498 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
2499 {
2500 for (int f = 0; f < 6; f++)
2501 {
daniel@transgaming.comc9ba4ad2011-11-09 17:44:35 +00002502 mImageArray[f][i].dirty = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002503 }
2504 }
2505
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00002506 mTexture->Release();
2507 mTexture = NULL;
2508 mDirtyImages = true;
2509 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002510 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002511}
2512
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002513void 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 +00002514{
2515 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
2516
2517 if (!renderTarget)
2518 {
2519 ERR("Failed to retrieve the render target.");
2520 return error(GL_OUT_OF_MEMORY);
2521 }
2522
2523 unsigned int faceindex = faceIndex(target);
daniel@transgaming.com68ae2992011-11-09 17:44:49 +00002524 redefineImage(faceindex, level, format, width, height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002525
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002526 if (!mImageArray[faceindex][level].isRenderable())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002527 {
daniel@transgaming.comb6276992011-03-29 00:58:18 +00002528 copyToImage(&mImageArray[faceindex][level], 0, 0, x, y, width, height, renderTarget);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002529 }
2530 else
2531 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00002532 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002533 {
2534 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002535 }
daniel@transgaming.com3b3c1d42011-06-08 20:38:09 +00002536
daniel@transgaming.com9ab8e3e2011-11-09 17:44:39 +00002537 mImageArray[faceindex][level].dirty = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002538
2539 ASSERT(width == height);
2540
2541 if (width > 0 && level < levelCount())
2542 {
2543 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
2544 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
2545 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
2546 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
2547 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
2548
daniel@transgaming.comeef864a2011-04-22 11:33:27 +00002549 GLint destYOffset = transformPixelYOffset(0, height, mImageArray[faceindex][level].width);
2550
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002551 IDirect3DSurface9 *dest = getCubeMapSurface(target, level);
2552
daniel@transgaming.comeef864a2011-04-22 11:33:27 +00002553 getBlitter()->copy(source->getRenderTarget(), sourceRect, format, 0, destYOffset, dest);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002554 dest->Release();
2555 }
2556 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002557}
2558
daniel@transgaming.comb612f882011-11-09 17:44:31 +00002559IDirect3DSurface9 *TextureCubeMap::getCubeMapSurface(GLenum target, unsigned int level)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002560{
2561 if (mTexture == NULL)
2562 {
2563 UNREACHABLE();
2564 return NULL;
2565 }
2566
2567 IDirect3DSurface9 *surface = NULL;
2568
daniel@transgaming.comb612f882011-11-09 17:44:31 +00002569 HRESULT hr = mTexture->GetCubeMapSurface(es2dx::ConvertCubeFace(target), level, &surface);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002570
2571 return (SUCCEEDED(hr)) ? surface : NULL;
2572}
2573
2574void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
2575{
2576 GLsizei size = mImageArray[faceIndex(target)][level].width;
2577
2578 if (xoffset + width > size || yoffset + height > size)
2579 {
2580 return error(GL_INVALID_VALUE);
2581 }
2582
2583 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
2584
2585 if (!renderTarget)
2586 {
2587 ERR("Failed to retrieve the render target.");
2588 return error(GL_OUT_OF_MEMORY);
2589 }
2590
2591 unsigned int faceindex = faceIndex(target);
daniel@transgaming.com01dae852011-11-09 17:44:53 +00002592
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002593 if (!mImageArray[faceindex][level].isRenderable() || (!mTexture && !isComplete()))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002594 {
daniel@transgaming.comb6276992011-03-29 00:58:18 +00002595 copyToImage(&mImageArray[faceindex][level], 0, 0, x, y, width, height, renderTarget);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002596 }
2597 else
2598 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00002599 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002600 {
2601 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002602 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00002603
2604 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002605
2606 if (level < levelCount())
2607 {
2608 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
2609 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
2610 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
2611 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
2612 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
2613
2614 GLint destYOffset = transformPixelYOffset(yoffset, height, mImageArray[faceindex][level].width);
2615
2616 IDirect3DSurface9 *dest = getCubeMapSurface(target, level);
2617
daniel@transgaming.comeef864a2011-04-22 11:33:27 +00002618 getBlitter()->copy(source->getRenderTarget(), sourceRect, mImageArray[0][0].format, xoffset, destYOffset, dest);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002619 dest->Release();
2620 }
2621 }
2622}
2623
2624bool TextureCubeMap::isCubeComplete() const
2625{
2626 if (mImageArray[0][0].width == 0)
2627 {
2628 return false;
2629 }
2630
2631 for (unsigned int f = 1; f < 6; f++)
2632 {
2633 if (mImageArray[f][0].width != mImageArray[0][0].width
2634 || mImageArray[f][0].format != mImageArray[0][0].format)
2635 {
2636 return false;
2637 }
2638 }
2639
2640 return true;
2641}
2642
2643void TextureCubeMap::generateMipmaps()
2644{
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00002645 if (!isCubeComplete())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002646 {
2647 return error(GL_INVALID_OPERATION);
2648 }
2649
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00002650 if (!getContext()->supportsNonPower2Texture())
2651 {
2652 if (!isPow2(mImageArray[0][0].width))
2653 {
2654 return error(GL_INVALID_OPERATION);
2655 }
2656 }
2657
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002658 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
2659 unsigned int q = log2(mImageArray[0][0].width);
2660 for (unsigned int f = 0; f < 6; f++)
2661 {
2662 for (unsigned int i = 1; i <= q; i++)
2663 {
2664 if (mImageArray[f][i].surface != NULL)
2665 {
2666 mImageArray[f][i].surface->Release();
2667 mImageArray[f][i].surface = NULL;
2668 }
2669
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002670 mImageArray[f][i].width = std::max(mImageArray[f][0].width >> i, 1);
2671 mImageArray[f][i].height = mImageArray[f][i].width;
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00002672 mImageArray[f][i].format = mImageArray[f][0].format;
2673 mImageArray[f][i].type = mImageArray[f][0].type;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002674 }
2675 }
2676
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002677 if (mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002678 {
2679 if (mTexture == NULL)
2680 {
2681 return;
2682 }
2683
2684 for (unsigned int f = 0; f < 6; f++)
2685 {
2686 for (unsigned int i = 1; i <= q; i++)
2687 {
2688 IDirect3DSurface9 *upper = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i-1);
2689 IDirect3DSurface9 *lower = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i);
2690
2691 if (upper != NULL && lower != NULL)
2692 {
2693 getBlitter()->boxFilter(upper, lower);
2694 }
2695
2696 if (upper != NULL) upper->Release();
2697 if (lower != NULL) lower->Release();
daniel@transgaming.com61208202011-03-21 16:38:50 +00002698
2699 mImageArray[f][i].dirty = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002700 }
2701 }
2702 }
2703 else
2704 {
2705 for (unsigned int f = 0; f < 6; f++)
2706 {
2707 for (unsigned int i = 1; i <= q; i++)
2708 {
daniel@transgaming.com31e22e12011-11-09 17:44:44 +00002709 mImageArray[f][i].createSurface();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002710 if (mImageArray[f][i].surface == NULL)
2711 {
2712 return error(GL_OUT_OF_MEMORY);
2713 }
2714
2715 if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[f][i].surface, NULL, NULL, mImageArray[f][i - 1].surface, NULL, NULL, D3DX_FILTER_BOX, 0)))
2716 {
2717 ERR(" failed to load filter %d to %d.", i - 1, i);
2718 }
2719
2720 mImageArray[f][i].dirty = true;
2721 }
2722 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002723 }
2724}
2725
2726Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target)
2727{
2728 if (!IsCubemapTextureTarget(target))
2729 {
2730 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
2731 }
2732
2733 unsigned int face = faceIndex(target);
2734
2735 if (mFaceProxies[face].get() == NULL)
2736 {
2737 mFaceProxies[face].set(new Renderbuffer(id(), new Colorbuffer(this, target)));
2738 }
2739
2740 return mFaceProxies[face].get();
2741}
2742
2743IDirect3DSurface9 *TextureCubeMap::getRenderTarget(GLenum target)
2744{
2745 ASSERT(IsCubemapTextureTarget(target));
2746
daniel@transgaming.com61208202011-03-21 16:38:50 +00002747 if (!mIsRenderable)
2748 {
2749 convertToRenderTarget();
2750 }
2751
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002752 if (mTexture == NULL)
2753 {
2754 return NULL;
2755 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00002756
2757 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002758
2759 IDirect3DSurface9 *renderTarget = NULL;
2760 mTexture->GetCubeMapSurface(es2dx::ConvertCubeFace(target), 0, &renderTarget);
2761
2762 return renderTarget;
2763}
2764
daniel@transgaming.comb612f882011-11-09 17:44:31 +00002765}