Home | History | Annotate | Download | only in libGLESv2
      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 
     27 Texture::Image::Image()
     28   : width(0), height(0), dirty(false), surface(NULL), format(GL_NONE)
     29 {
     30 }
     31 
     32 Texture::Image::~Image()
     33 {
     34   if (surface) surface->Release();
     35 }
     36 
     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 
     54 Texture::~Texture()
     55 {
     56 }
     57 
     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)
     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)
     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)
    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)
    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 
    150 GLenum Texture::getMinFilter() const
    151 {
    152     return mMinFilter;
    153 }
    154 
    155 GLenum Texture::getMagFilter() const
    156 {
    157     return mMagFilter;
    158 }
    159 
    160 GLenum Texture::getWrapS() const
    161 {
    162     return mWrapS;
    163 }
    164 
    165 GLenum Texture::getWrapT() const
    166 {
    167     return mWrapT;
    168 }
    169 
    170 GLuint Texture::getWidth() const
    171 {
    172     return mWidth;
    173 }
    174 
    175 GLuint Texture::getHeight() const
    176 {
    177     return mHeight;
    178 }
    179 
    180 bool Texture::isFloatingPoint() const
    181 {
    182     return (mType == GL_FLOAT || mType == GL_HALF_FLOAT_OES);
    183 }
    184 
    185 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
    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.
    246 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 
    352 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 
    372 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 
    392 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 
    412 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 
    441 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 
    461 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 
    481 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 
    510 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 
    530 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 
    550 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 
    570 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 
    591 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 
    611 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 
    631 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 
    651 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 
    672 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 
    693 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 
    707 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 
    721 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 
    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 
    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 
    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 
    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 
    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
    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 
   1085 D3DFORMAT Texture::getD3DFormat() const
   1086 {
   1087     return selectFormat(getFormat(), mType);
   1088 }
   1089 
   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 
   1114 bool Texture::isDirty() const
   1115 {
   1116     return (mDirty || mDirtyMetaData || dirtyImageData());
   1117 }
   1118 
   1119 // Returns the top-level texture surface as a render target
   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 
   1136 void Texture::dropTexture()
   1137 {
   1138     if (mBaseTexture)
   1139     {
   1140         mBaseTexture = NULL;
   1141     }
   1142 
   1143     mIsRenderable = false;
   1144 }
   1145 
   1146 void Texture::pushTexture(IDirect3DBaseTexture9 *newTexture, bool renderable)
   1147 {
   1148     mBaseTexture = newTexture;
   1149     mDirtyMetaData = false;
   1150     mIsRenderable = renderable;
   1151     mDirty = true;
   1152 }
   1153 
   1154 
   1155 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 
   1168 GLint Texture::creationLevels(GLsizei size, GLint maxlevel) const
   1169 {
   1170     return creationLevels(size, size, maxlevel);
   1171 }
   1172 
   1173 int Texture::levelCount() const
   1174 {
   1175     return mBaseTexture ? mBaseTexture->GetLevelCount() : 0;
   1176 }
   1177 
   1178 bool Texture::isRenderable() const
   1179 {
   1180     return mIsRenderable;
   1181 }
   1182 
   1183 Texture2D::Texture2D(GLuint id) : Texture(id)
   1184 {
   1185     mTexture = NULL;
   1186 }
   1187 
   1188 Texture2D::~Texture2D()
   1189 {
   1190     mColorbufferProxy.set(NULL);
   1191 
   1192     if (mTexture)
   1193     {
   1194         mTexture->Release();
   1195         mTexture = NULL;
   1196     }
   1197 }
   1198 
   1199 GLenum Texture2D::getTarget() const
   1200 {
   1201     return GL_TEXTURE_2D;
   1202 }
   1203 
   1204 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.
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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.
   1428 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 
   1502 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
   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 
   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 
   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 
   1633 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 
   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 
   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 
   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 
   1748 TextureCubeMap::TextureCubeMap(GLuint id) : Texture(id)
   1749 {
   1750     mTexture = NULL;
   1751 }
   1752 
   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 
   1767 GLenum TextureCubeMap::getTarget() const
   1768 {
   1769     return GL_TEXTURE_CUBE_MAP;
   1770 }
   1771 
   1772 GLenum TextureCubeMap::getFormat() const
   1773 {
   1774     return mImageArray[0][0].format;
   1775 }
   1776 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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.
   1866 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 
   1940 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
   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 
   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 
   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 
   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 
   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 
   2092 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.
   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 
   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 
   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 
   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 
   2293 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 
   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 
   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 
   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 
   2422 Texture::TextureColorbufferProxy::TextureColorbufferProxy(Texture *texture, GLenum target)
   2423   : Colorbuffer(texture), mTexture(texture), mTarget(target)
   2424 {
   2425     ASSERT(IsTextureTarget(target));
   2426 }
   2427 
   2428 void Texture::TextureColorbufferProxy::addRef() const
   2429 {
   2430     mTexture->addRef();
   2431 }
   2432 
   2433 void Texture::TextureColorbufferProxy::release() const
   2434 {
   2435     mTexture->release();
   2436 }
   2437 
   2438 IDirect3DSurface9 *Texture::TextureColorbufferProxy::getRenderTarget()
   2439 {
   2440     if (mRenderTarget) mRenderTarget->Release();
   2441 
   2442     mRenderTarget = mTexture->getRenderTarget(mTarget);
   2443 
   2444     return mRenderTarget;
   2445 }
   2446 
   2447 int Texture::TextureColorbufferProxy::getWidth() const
   2448 {
   2449     return mTexture->getWidth();
   2450 }
   2451 
   2452 int Texture::TextureColorbufferProxy::getHeight() const
   2453 {
   2454     return mTexture->getHeight();
   2455 }
   2456 
   2457 GLenum Texture::TextureColorbufferProxy::getFormat() const
   2458 {
   2459     return mTexture->getFormat();
   2460 }
   2461 
   2462 bool Texture::TextureColorbufferProxy::isFloatingPoint() const
   2463 {
   2464     return mTexture->isFloatingPoint();
   2465 }
   2466 
   2467 }
   2468