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