• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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