Fixed commitRect so it correctly flips the source rectangle and dest point on Y.

Review URL: http://codereview.appspot.com/4047050

git-svn-id: https://angleproject.googlecode.com/svn/trunk@551 736b8ea6-26fd-11df-bfd4-992fa37f6226
diff --git a/src/libGLESv2/Texture.cpp b/src/libGLESv2/Texture.cpp
index 0059669..7a6ae8a 100644
--- a/src/libGLESv2/Texture.cpp
+++ b/src/libGLESv2/Texture.cpp
@@ -1,2517 +1,2509 @@
-//
-// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-//
-
-// Texture.cpp: Implements the gl::Texture class and its derived classes
-// Texture2D and TextureCubeMap. Implements GL texture objects and related
-// functionality. [OpenGL ES 2.0.24] section 3.7 page 63.
-
-#include "libGLESv2/Texture.h"
-
-#include <d3dx9tex.h>
-
-#include <algorithm>
-
-#include "common/debug.h"
-
-#include "libGLESv2/main.h"
-#include "libGLESv2/mathutil.h"
-#include "libGLESv2/utilities.h"
-#include "libGLESv2/Blit.h"
-#include "libGLESv2/Framebuffer.h"
-
-namespace gl
-{
-
-Texture::Image::Image()
-  : width(0), height(0), dirty(false), surface(NULL), format(GL_NONE)
-{
-}
-
-Texture::Image::~Image()
-{
-  if (surface) surface->Release();
-}
-
-Texture::Texture(GLuint id) : RefCountObject(id)
-{
-    mMinFilter = GL_NEAREST_MIPMAP_LINEAR;
-    mMagFilter = GL_LINEAR;
-    mWrapS = GL_REPEAT;
-    mWrapT = GL_REPEAT;
-
-    mWidth = 0;
-    mHeight = 0;
-
-    mDirtyMetaData = true;
-    mDirty = true;
-    mIsRenderable = false;
-    mType = GL_UNSIGNED_BYTE;
-    mBaseTexture = NULL;
-}
-
-Texture::~Texture()
-{
-}
-
-Blit *Texture::getBlitter()
-{
-    Context *context = getContext();
-    return context->getBlitter();
-}
-
-// Returns true on successful filter state update (valid enum parameter)
-bool Texture::setMinFilter(GLenum filter)
-{
-    switch (filter)
-    {
-      case GL_NEAREST:
-      case GL_LINEAR:
-      case GL_NEAREST_MIPMAP_NEAREST:
-      case GL_LINEAR_MIPMAP_NEAREST:
-      case GL_NEAREST_MIPMAP_LINEAR:
-      case GL_LINEAR_MIPMAP_LINEAR:
-        {
-            if (mMinFilter != filter)
-            {
-                mMinFilter = filter;
-                mDirty = true;
-            }
-            return true;
-        }
-      default:
-        return false;
-    }
-}
-
-// Returns true on successful filter state update (valid enum parameter)
-bool Texture::setMagFilter(GLenum filter)
-{
-    switch (filter)
-    {
-      case GL_NEAREST:
-      case GL_LINEAR:
-        {
-            if (mMagFilter != filter)
-            {
-                mMagFilter = filter;
-                mDirty = true;
-            }
-            return true;
-        }
-      default:
-        return false;
-    }
-}
-
-// Returns true on successful wrap state update (valid enum parameter)
-bool Texture::setWrapS(GLenum wrap)
-{
-    switch (wrap)
-    {
-      case GL_REPEAT:
-      case GL_CLAMP_TO_EDGE:
-      case GL_MIRRORED_REPEAT:
-        {
-            if (mWrapS != wrap)
-            {
-                mWrapS = wrap;
-                mDirty = true;
-            }
-            return true;
-        }
-      default:
-        return false;
-    }
-}
-
-// Returns true on successful wrap state update (valid enum parameter)
-bool Texture::setWrapT(GLenum wrap)
-{
-    switch (wrap)
-    {
-      case GL_REPEAT:
-      case GL_CLAMP_TO_EDGE:
-      case GL_MIRRORED_REPEAT:
-        {
-            if (mWrapT != wrap)
-            {
-                mWrapT = wrap;
-                mDirty = true;
-            }
-            return true;
-        }
-      default:
-        return false;
-    }
-}
-
-GLenum Texture::getMinFilter() const
-{
-    return mMinFilter;
-}
-
-GLenum Texture::getMagFilter() const
-{
-    return mMagFilter;
-}
-
-GLenum Texture::getWrapS() const
-{
-    return mWrapS;
-}
-
-GLenum Texture::getWrapT() const
-{
-    return mWrapT;
-}
-
-GLuint Texture::getWidth() const
-{
-    return mWidth;
-}
-
-GLuint Texture::getHeight() const
-{
-    return mHeight;
-}
-
-bool Texture::isFloatingPoint() const
-{
-    return (mType == GL_FLOAT || mType == GL_HALF_FLOAT_OES);
-}
-
-bool Texture::isRenderableFormat() const
-{
-    D3DFORMAT format = getD3DFormat();
-    
-    switch(format)
-    {
-      case D3DFMT_L8:
-      case D3DFMT_A8L8:
-      case D3DFMT_DXT1:
-        return false;
-      case D3DFMT_A8R8G8B8:
-      case D3DFMT_X8R8G8B8:
-      case D3DFMT_A16B16G16R16F:
-      case D3DFMT_A32B32G32R32F:
-        return true;
-      default:
-        UNREACHABLE();
-    }
-
-    return false;
-}
-
-// Selects an internal Direct3D 9 format for storing an Image
-D3DFORMAT Texture::selectFormat(GLenum format, GLenum type)
-{
-    if (format == GL_COMPRESSED_RGB_S3TC_DXT1_EXT ||
-        format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT)
-    {
-        return D3DFMT_DXT1;
-    }
-    else if (type == GL_FLOAT)
-    {
-        return D3DFMT_A32B32G32R32F;
-    }
-    else if (type == GL_HALF_FLOAT_OES)
-    {
-        return D3DFMT_A16B16G16R16F;
-    }
-    else if (type == GL_UNSIGNED_BYTE)
-    {
-        if (format == GL_LUMINANCE && getContext()->supportsLuminanceTextures())
-        {
-            return D3DFMT_L8;
-        }
-        else if (format == GL_LUMINANCE_ALPHA && getContext()->supportsLuminanceAlphaTextures())
-        {
-            return D3DFMT_A8L8;
-        }
-        else if (format == GL_RGB)
-        {
-            return D3DFMT_X8R8G8B8;
-        }
-
-        return D3DFMT_A8R8G8B8;
-    }
-
-    return D3DFMT_A8R8G8B8;
-}
-
-// Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input
-// into the target pixel rectangle at output with outputPitch bytes in between each line.
-void Texture::loadImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type,
-                            GLint unpackAlignment, const void *input, size_t outputPitch, void *output, D3DSURFACE_DESC *description) const
-{
-    GLsizei inputPitch = -ComputePitch(width, format, type, unpackAlignment);
-    input = ((char*)input) - inputPitch * (height - 1);
-
-    switch (type)
-    {
-      case GL_UNSIGNED_BYTE:
-        switch (format)
-        {
-          case GL_ALPHA:
-            loadAlphaImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
-            break;
-          case GL_LUMINANCE:
-            loadLuminanceImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output, description->Format == D3DFMT_L8);
-            break;
-          case GL_LUMINANCE_ALPHA:
-            loadLuminanceAlphaImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output, description->Format == D3DFMT_A8L8);
-            break;
-          case GL_RGB:
-            loadRGBUByteImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
-            break;
-          case GL_RGBA:
-            loadRGBAUByteImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
-            break;
-          case GL_BGRA_EXT:
-            loadBGRAImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
-            break;
-          default: UNREACHABLE();
-        }
-        break;
-      case GL_UNSIGNED_SHORT_5_6_5:
-        switch (format)
-        {
-          case GL_RGB:
-            loadRGB565ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
-            break;
-          default: UNREACHABLE();
-        }
-        break;
-      case GL_UNSIGNED_SHORT_4_4_4_4:
-        switch (format)
-        {
-          case GL_RGBA:
-            loadRGBA4444ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
-            break;
-          default: UNREACHABLE();
-        }
-        break;
-      case GL_UNSIGNED_SHORT_5_5_5_1:
-        switch (format)
-        {
-          case GL_RGBA:
-            loadRGBA5551ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
-            break;
-          default: UNREACHABLE();
-        }
-        break;
-      case GL_FLOAT:
-        switch (format)
-        {
-          // float textures are converted to RGBA, not BGRA, as they're stored that way in D3D
-          case GL_ALPHA:
-            loadAlphaFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
-            break;
-          case GL_LUMINANCE:
-            loadLuminanceFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
-            break;
-          case GL_LUMINANCE_ALPHA:
-            loadLuminanceAlphaFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
-            break;
-          case GL_RGB:
-            loadRGBFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
-            break;
-          case GL_RGBA:
-            loadRGBAFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
-            break;
-          default: UNREACHABLE();
-        }
-        break;
-      case GL_HALF_FLOAT_OES:
-        switch (format)
-        {
-          // float textures are converted to RGBA, not BGRA, as they're stored that way in D3D
-          case GL_ALPHA:
-            loadAlphaHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
-            break;
-          case GL_LUMINANCE:
-            loadLuminanceHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
-            break;
-          case GL_LUMINANCE_ALPHA:
-            loadLuminanceAlphaHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
-            break;
-          case GL_RGB:
-            loadRGBHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
-            break;
-          case GL_RGBA:
-            loadRGBAHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
-            break;
-          default: UNREACHABLE();
-        }
-        break;
-      default: UNREACHABLE();
-    }
-}
-
-void Texture::loadAlphaImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
-                                 int inputPitch, const void *input, size_t outputPitch, void *output) const
-{
-    const unsigned char *source = NULL;
-    unsigned char *dest = NULL;
-    
-    for (int y = 0; y < height; y++)
-    {
-        source = static_cast<const unsigned char*>(input) + y * inputPitch;
-        dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
-        for (int x = 0; x < width; x++)
-        {
-            dest[4 * x + 0] = 0;
-            dest[4 * x + 1] = 0;
-            dest[4 * x + 2] = 0;
-            dest[4 * x + 3] = source[x];
-        }
-    }
-}
-
-void Texture::loadAlphaFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
-                                      int inputPitch, const void *input, size_t outputPitch, void *output) const
-{
-    const float *source = NULL;
-    float *dest = NULL;
-
-    for (int y = 0; y < height; y++)
-    {
-        source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
-        dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch  + xoffset * 16);
-        for (int x = 0; x < width; x++)
-        {
-            dest[4 * x + 0] = 0;
-            dest[4 * x + 1] = 0;
-            dest[4 * x + 2] = 0;
-            dest[4 * x + 3] = source[x];
-        }
-    }
-}
-
-void Texture::loadAlphaHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
-                                          int inputPitch, const void *input, size_t outputPitch, void *output) const
-{
-    const unsigned short *source = NULL;
-    unsigned short *dest = NULL;
-
-    for (int y = 0; y < height; y++)
-    {
-        source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
-        dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
-        for (int x = 0; x < width; x++)
-        {
-            dest[4 * x + 0] = 0;
-            dest[4 * x + 1] = 0;
-            dest[4 * x + 2] = 0;
-            dest[4 * x + 3] = source[x];
-        }
-    }
-}
-
-void Texture::loadLuminanceImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
-                                     int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const
-{
-    const int destBytesPerPixel = native? 1: 4;
-    const unsigned char *source = NULL;
-    unsigned char *dest = NULL;
-
-    for (int y = 0; y < height; y++)
-    {
-        source = static_cast<const unsigned char*>(input) + y * inputPitch;
-        dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * destBytesPerPixel;
-
-        if (!native)   // BGRA8 destination format
-        {
-            for (int x = 0; x < width; x++)
-            {
-                dest[4 * x + 0] = source[x];
-                dest[4 * x + 1] = source[x];
-                dest[4 * x + 2] = source[x];
-                dest[4 * x + 3] = 0xFF;
-            }
-        }
-        else   // L8 destination format
-        {
-            memcpy(dest, source, width);
-        }
-    }
-}
-
-void Texture::loadLuminanceFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
-                                          int inputPitch, const void *input, size_t outputPitch, void *output) const
-{
-    const float *source = NULL;
-    float *dest = NULL;
-
-    for (int y = 0; y < height; y++)
-    {
-        source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
-        dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch  + xoffset * 16);
-        for (int x = 0; x < width; x++)
-        {
-            dest[4 * x + 0] = source[x];
-            dest[4 * x + 1] = source[x];
-            dest[4 * x + 2] = source[x];
-            dest[4 * x + 3] = 1.0f;
-        }
-    }
-}
-
-void Texture::loadLuminanceHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
-                                                   int inputPitch, const void *input, size_t outputPitch, void *output) const
-{
-    const unsigned short *source = NULL;
-    unsigned short *dest = NULL;
-
-    for (int y = 0; y < height; y++)
-    {
-        source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
-        dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
-        for (int x = 0; x < width; x++)
-        {
-            dest[4 * x + 0] = source[x];
-            dest[4 * x + 1] = source[x];
-            dest[4 * x + 2] = source[x];
-            dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1
-        }
-    }
-}
-
-void Texture::loadLuminanceAlphaImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
-                                          int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const
-{
-    const int destBytesPerPixel = native? 2: 4;
-    const unsigned char *source = NULL;
-    unsigned char *dest = NULL;
-
-    for (int y = 0; y < height; y++)
-    {
-        source = static_cast<const unsigned char*>(input) + y * inputPitch;
-        dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * destBytesPerPixel;
-        
-        if (!native)   // BGRA8 destination format
-        {
-            for (int x = 0; x < width; x++)
-            {
-                dest[4 * x + 0] = source[2*x+0];
-                dest[4 * x + 1] = source[2*x+0];
-                dest[4 * x + 2] = source[2*x+0];
-                dest[4 * x + 3] = source[2*x+1];
-            }
-        }
-        else
-        {
-            memcpy(dest, source, width * 2);
-        }
-    }
-}
-
-void Texture::loadLuminanceAlphaFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
-                                               int inputPitch, const void *input, size_t outputPitch, void *output) const
-{
-    const float *source = NULL;
-    float *dest = NULL;
-
-    for (int y = 0; y < height; y++)
-    {
-        source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
-        dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch  + xoffset * 16);
-        for (int x = 0; x < width; x++)
-        {
-            dest[4 * x + 0] = source[2*x+0];
-            dest[4 * x + 1] = source[2*x+0];
-            dest[4 * x + 2] = source[2*x+0];
-            dest[4 * x + 3] = source[2*x+1];
-        }
-    }
-}
-
-void Texture::loadLuminanceAlphaHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
-                                                   int inputPitch, const void *input, size_t outputPitch, void *output) const
-{
-    const unsigned short *source = NULL;
-    unsigned short *dest = NULL;
-
-    for (int y = 0; y < height; y++)
-    {
-        source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
-        dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
-        for (int x = 0; x < width; x++)
-        {
-            dest[4 * x + 0] = source[2*x+0];
-            dest[4 * x + 1] = source[2*x+0];
-            dest[4 * x + 2] = source[2*x+0];
-            dest[4 * x + 3] = source[2*x+1];
-        }
-    }
-}
-
-void Texture::loadRGBUByteImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
-                                    int inputPitch, const void *input, size_t outputPitch, void *output) const
-{
-    const unsigned char *source = NULL;
-    unsigned char *dest = NULL;
-
-    for (int y = 0; y < height; y++)
-    {
-        source = static_cast<const unsigned char*>(input) + y * inputPitch;
-        dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
-        for (int x = 0; x < width; x++)
-        {
-            dest[4 * x + 0] = source[x * 3 + 2];
-            dest[4 * x + 1] = source[x * 3 + 1];
-            dest[4 * x + 2] = source[x * 3 + 0];
-            dest[4 * x + 3] = 0xFF;
-        }
-    }
-}
-
-void Texture::loadRGB565ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
-                                  int inputPitch, const void *input, size_t outputPitch, void *output) const
-{
-    const unsigned short *source = NULL;
-    unsigned char *dest = NULL;
-
-    for (int y = 0; y < height; y++)
-    {
-        source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
-        dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
-        for (int x = 0; x < width; x++)
-        {
-            unsigned short rgba = source[x];
-            dest[4 * x + 0] = ((rgba & 0x001F) << 3) | ((rgba & 0x001F) >> 2);
-            dest[4 * x + 1] = ((rgba & 0x07E0) >> 3) | ((rgba & 0x07E0) >> 9);
-            dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
-            dest[4 * x + 3] = 0xFF;
-        }
-    }
-}
-
-void Texture::loadRGBFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
-                                    int inputPitch, const void *input, size_t outputPitch, void *output) const
-{
-    const float *source = NULL;
-    float *dest = NULL;
-
-    for (int y = 0; y < height; y++)
-    {
-        source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
-        dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch  + xoffset * 16);
-        for (int x = 0; x < width; x++)
-        {
-            dest[4 * x + 0] = source[x * 3 + 0];
-            dest[4 * x + 1] = source[x * 3 + 1];
-            dest[4 * x + 2] = source[x * 3 + 2];
-            dest[4 * x + 3] = 1.0f;
-        }
-    }
-}
-
-void Texture::loadRGBHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
-                                        int inputPitch, const void *input, size_t outputPitch, void *output) const
-{
-    const unsigned short *source = NULL;
-    unsigned short *dest = NULL;
-
-    for (int y = 0; y < height; y++)
-    {
-        source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
-        dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch  + xoffset * 8);
-        for (int x = 0; x < width; x++)
-        {
-            dest[4 * x + 0] = source[x * 3 + 0];
-            dest[4 * x + 1] = source[x * 3 + 1];
-            dest[4 * x + 2] = source[x * 3 + 2];
-            dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1
-        }
-    }
-}
-
-void Texture::loadRGBAUByteImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
-                                     int inputPitch, const void *input, size_t outputPitch, void *output) const
-{
-    const unsigned char *source = NULL;
-    unsigned char *dest = NULL;
-
-    for (int y = 0; y < height; y++)
-    {
-        source = static_cast<const unsigned char*>(input) + y * inputPitch;
-        dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
-        for (int x = 0; x < width; x++)
-        {
-            dest[4 * x + 0] = source[x * 4 + 2];
-            dest[4 * x + 1] = source[x * 4 + 1];
-            dest[4 * x + 2] = source[x * 4 + 0];
-            dest[4 * x + 3] = source[x * 4 + 3];
-        }
-    }
-}
-
-void Texture::loadRGBA4444ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
-                                    int inputPitch, const void *input, size_t outputPitch, void *output) const
-{
-    const unsigned short *source = NULL;
-    unsigned char *dest = NULL;
-
-    for (int y = 0; y < height; y++)
-    {
-        source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
-        dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
-        for (int x = 0; x < width; x++)
-        {
-            unsigned short rgba = source[x];
-            dest[4 * x + 0] = ((rgba & 0x00F0) << 0) | ((rgba & 0x00F0) >> 4);
-            dest[4 * x + 1] = ((rgba & 0x0F00) >> 4) | ((rgba & 0x0F00) >> 8);
-            dest[4 * x + 2] = ((rgba & 0xF000) >> 8) | ((rgba & 0xF000) >> 12);
-            dest[4 * x + 3] = ((rgba & 0x000F) << 4) | ((rgba & 0x000F) >> 0);
-        }
-    }
-}
-
-void Texture::loadRGBA5551ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
-                                    int inputPitch, const void *input, size_t outputPitch, void *output) const
-{
-    const unsigned short *source = NULL;
-    unsigned char *dest = NULL;
-
-    for (int y = 0; y < height; y++)
-    {
-        source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
-        dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
-        for (int x = 0; x < width; x++)
-        {
-            unsigned short rgba = source[x];
-            dest[4 * x + 0] = ((rgba & 0x003E) << 2) | ((rgba & 0x003E) >> 3);
-            dest[4 * x + 1] = ((rgba & 0x07C0) >> 3) | ((rgba & 0x07C0) >> 8);
-            dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
-            dest[4 * x + 3] = (rgba & 0x0001) ? 0xFF : 0;
-        }
-    }
-}
-
-void Texture::loadRGBAFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
-                                     int inputPitch, const void *input, size_t outputPitch, void *output) const
-{
-    const float *source = NULL;
-    float *dest = NULL;
-
-    for (int y = 0; y < height; y++)
-    {
-        source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
-        dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch  + xoffset * 16);
-        memcpy(dest, source, width * 16);
-    }
-}
-
-void Texture::loadRGBAHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
-                                        int inputPitch, const void *input, size_t outputPitch, void *output) const
-{
-    const unsigned char *source = NULL;
-    unsigned char *dest = NULL;
-
-    for (int y = 0; y < height; y++)
-    {
-        source = static_cast<const unsigned char*>(input) + y * inputPitch;
-        dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch  + xoffset * 8;
-        memcpy(dest, source, width * 8);
-    }
-}
-
-void Texture::loadBGRAImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
-                                int inputPitch, const void *input, size_t outputPitch, void *output) const
-{
-    const unsigned char *source = NULL;
-    unsigned char *dest = NULL;
-
-    for (int y = 0; y < height; y++)
-    {
-        source = static_cast<const unsigned char*>(input) + y * inputPitch;
-        dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
-        memcpy(dest, source, width*4);
-    }
-}
-
-void Texture::loadCompressedImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
-                                      int inputPitch, const void *input, size_t outputPitch, void *output) const
-{
-    ASSERT(xoffset % 4 == 0);
-    ASSERT(yoffset % 4 == 0);
-    ASSERT(width % 4 == 0 || width == 2 || width == 1);
-    ASSERT(inputPitch % 8 == 0);
-    ASSERT(outputPitch % 8 == 0);
-
-    const unsigned int *source = reinterpret_cast<const unsigned int*>(input);
-    unsigned int *dest = reinterpret_cast<unsigned int*>(output);
-
-    switch (height)
-    {
-        case 1:
-            // Round width up in case it is 1.
-            for (int x = 0; x < (width + 1) / 2; x += 2)
-            {
-                // First 32-bits is two RGB565 colors shared by tile and does not need to be modified.
-                dest[x] = source[x];
-
-                // Second 32-bits contains 4 rows of 4 2-bit interpolants between the colors, the last 3 rows being unused. No flipping should occur.
-                dest[x + 1] = source[x + 1];
-            }
-            break;
-        case 2:
-            // Round width up in case it is 1.
-            for (int x = 0; x < (width + 1) / 2; x += 2)
-            {
-                // First 32-bits is two RGB565 colors shared by tile and does not need to be modified.
-                dest[x] = source[x];
-
-                // Second 32-bits contains 4 rows of 4 2-bit interpolants between the colors, the last 2 rows being unused. Only the top 2 rows should be flipped.
-                dest[x + 1] = ((source[x + 1] << 8) & 0x0000FF00) |
-                              ((source[x + 1] >> 8) & 0x000000FF);       
-            }
-            break;
-        default:
-            ASSERT(height % 4 == 0);
-            for (int y = 0; y < height / 4; ++y)
-            {
-                const unsigned int *source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);
-                unsigned int *dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
-
-                // Round width up in case it is 1.
-                for (int x = 0; x < (width + 1) / 2; x += 2)
-                {
-                    // First 32-bits is two RGB565 colors shared by tile and does not need to be modified.
-                    dest[x] = source[x];
-
-                    // Second 32-bits contains 4 rows of 4 2-bit interpolants between the colors. All rows should be flipped.
-                    dest[x + 1] = (source[x + 1] >> 24) | 
-                                  ((source[x + 1] << 8) & 0x00FF0000) |
-                                  ((source[x + 1] >> 8) & 0x0000FF00) |
-                                  (source[x + 1] << 24);                    
-                }
-            }
-            break;
-    }
-}
-
-void Texture::createSurface(GLsizei width, GLsizei height, GLenum format, GLenum type, Image *img)
-{
-    IDirect3DTexture9 *newTexture = NULL;
-    IDirect3DSurface9 *newSurface = NULL;
-
-    if (width != 0 && height != 0)
-    {
-        int levelToFetch = 0;
-        GLsizei requestWidth = width;
-        GLsizei requestHeight = height;
-        if (IsCompressed(format) && (width % 4 != 0 || height % 4 != 0))
-        {
-            bool isMult4 = false;
-            int upsampleCount = 0;
-            while (!isMult4)
-            {
-                requestWidth <<= 1;
-                requestHeight <<= 1;
-                upsampleCount++;
-                if (requestWidth % 4 == 0 && requestHeight % 4 == 0)
-                {
-                    isMult4 = true;
-                }
-            }
-            levelToFetch = upsampleCount;
-        }
-
-        HRESULT result = getDevice()->CreateTexture(requestWidth, requestHeight, levelToFetch + 1, NULL, selectFormat(format, type),
-                                                    D3DPOOL_SYSTEMMEM, &newTexture, NULL);
-
-        if (FAILED(result))
-        {
-            ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
-            return error(GL_OUT_OF_MEMORY);
-        }
-
-        newTexture->GetSurfaceLevel(levelToFetch, &newSurface);
-        newTexture->Release();
-    }
-
-    if (img->surface) img->surface->Release();
-    img->surface = newSurface;
-
-    img->width = width;
-    img->height = height;
-    img->format = format;
-}
-
-void Texture::setImage(GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, Image *img)
-{
-    createSurface(width, height, format, type, img);
-
-    if (pixels != NULL && img->surface != NULL)
-    {
-        D3DSURFACE_DESC description;
-        img->surface->GetDesc(&description);
-
-        D3DLOCKED_RECT locked;
-        HRESULT result = img->surface->LockRect(&locked, NULL, 0);
-
-        ASSERT(SUCCEEDED(result));
-
-        if (SUCCEEDED(result))
-        {
-            loadImageData(0, 0, width, height, format, type, unpackAlignment, pixels, locked.Pitch, locked.pBits, &description);
-            img->surface->UnlockRect();
-        }
-
-        img->dirty = true;
-    }
-
-    mDirtyMetaData = true;
-}
-
-void Texture::setCompressedImage(GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, Image *img)
-{
-    createSurface(width, height, format, GL_UNSIGNED_BYTE, img);
-
-    if (pixels != NULL && img->surface != NULL)
-    {
-        D3DLOCKED_RECT locked;
-        HRESULT result = img->surface->LockRect(&locked, NULL, 0);
-
-        ASSERT(SUCCEEDED(result));
-
-        if (SUCCEEDED(result))
-        {
-            int inputPitch = ComputeCompressedPitch(width, format);
-            int inputSize = ComputeCompressedSize(width, height, format);
-            loadCompressedImageData(0, 0, width, height, -inputPitch, static_cast<const char*>(pixels) + inputSize - inputPitch, locked.Pitch, locked.pBits);
-            img->surface->UnlockRect();
-        }
-
-        img->dirty = true;
-    }
-
-    mDirtyMetaData = true;
-}
-
-bool Texture::subImage(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, Image *img)
-{
-    if (width + xoffset > img->width || height + yoffset > img->height)
-    {
-        error(GL_INVALID_VALUE);
-        return false;
-    }
-
-    if (!img->surface)
-    {
-        createSurface(img->width, img->height, format, type, img);
-    }
-
-    if (pixels != NULL && img->surface != NULL)
-    {
-        D3DSURFACE_DESC description;
-        img->surface->GetDesc(&description);
-
-        D3DLOCKED_RECT locked;
-        HRESULT result = img->surface->LockRect(&locked, NULL, 0);
-
-        ASSERT(SUCCEEDED(result));
-
-        if (SUCCEEDED(result))
-        {
-            loadImageData(xoffset, transformPixelYOffset(yoffset, height, img->height), width, height, format, type, unpackAlignment, pixels, locked.Pitch, locked.pBits, &description);
-            img->surface->UnlockRect();
-        }
-
-        img->dirty = true;
-    }
-
-    return true;
-}
-
-bool Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, Image *img)
-{
-    if (width + xoffset > img->width || height + yoffset > img->height)
-    {
-        error(GL_INVALID_VALUE);
-        return false;
-    }
-
-    if (format != getFormat())
-    {
-        error(GL_INVALID_OPERATION);
-        return false;
-    }
-
-    if (!img->surface)
-    {
-        createSurface(img->width, img->height, format, GL_UNSIGNED_BYTE, img);
-    }
-
-    if (pixels != NULL && img->surface != NULL)
-    {
-        RECT updateRegion;
-        updateRegion.left = xoffset;
-        updateRegion.right = xoffset + width;
-        updateRegion.bottom = yoffset + height;
-        updateRegion.top = yoffset;
-
-        D3DLOCKED_RECT locked;
-        HRESULT result = img->surface->LockRect(&locked, &updateRegion, 0);
-
-        ASSERT(SUCCEEDED(result));
-
-        if (SUCCEEDED(result))
-        {
-            int inputPitch = ComputeCompressedPitch(width, format);
-            int inputSize = ComputeCompressedSize(width, height, format);
-            loadCompressedImageData(xoffset, transformPixelYOffset(yoffset, height, img->height), width, height, -inputPitch, static_cast<const char*>(pixels) + inputSize - inputPitch, locked.Pitch, locked.pBits);
-            img->surface->UnlockRect();
-        }
-
-        img->dirty = true;
-    }
-
-    return true;
-}
-
-// This implements glCopyTex[Sub]Image2D for non-renderable internal texture formats
-void Texture::copyNonRenderable(Image *image, GLenum internalFormat, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, IDirect3DSurface9 *renderTarget)
-{
-    IDirect3DDevice9 *device = getDevice();
-    IDirect3DSurface9 *surface = NULL;
-    D3DSURFACE_DESC description;
-    renderTarget->GetDesc(&description);
-    
-    HRESULT result = device->CreateOffscreenPlainSurface(description.Width, description.Height, description.Format, D3DPOOL_SYSTEMMEM, &surface, NULL);
-
-    if (!SUCCEEDED(result))
-    {
-        ERR("Could not create matching destination surface.");
-        return error(GL_OUT_OF_MEMORY);
-    }
-
-    result = device->GetRenderTargetData(renderTarget, surface);
-
-    if (!SUCCEEDED(result))
-    {
-        ERR("GetRenderTargetData unexpectedly failed.");
-        surface->Release();
-        return error(GL_OUT_OF_MEMORY);
-    }
-
-    D3DLOCKED_RECT sourceLock = {0};
-    RECT sourceRect = transformPixelRect(x, y, width, height, description.Height);
-    result = surface->LockRect(&sourceLock, &sourceRect, 0);
-
-    if (FAILED(result))
-    {
-        ERR("Failed to lock the source surface (rectangle might be invalid).");
-        surface->UnlockRect();
-        surface->Release();
-        return error(GL_OUT_OF_MEMORY);
-    }
-
-    if (!image->surface)
-    {
-        createSurface(width, height, internalFormat, mType, image);
-    }
-
-    if (image->surface == NULL)
-    {
-        ERR("Failed to create an image surface.");
-        surface->UnlockRect();
-        surface->Release();
-        return error(GL_OUT_OF_MEMORY); 
-    }
-
-    D3DLOCKED_RECT destLock = {0};
-    int destYOffset = transformPixelYOffset(yoffset, height, image->height);
-    RECT destRect = {xoffset, destYOffset, xoffset + width, destYOffset + height};
-    result = image->surface->LockRect(&destLock, &destRect, 0);
-    
-    if (FAILED(result))
-    {
-        ERR("Failed to lock the destination surface (rectangle might be invalid).");
-        surface->UnlockRect();
-        surface->Release();
-        return error(GL_OUT_OF_MEMORY);
-    }
-
-    if (destLock.pBits && sourceLock.pBits)
-    {
-        unsigned char *source = (unsigned char*)sourceLock.pBits;
-        unsigned char *dest = (unsigned char*)destLock.pBits;
-
-        switch (description.Format)
-        {
-          case D3DFMT_X8R8G8B8:
-          case D3DFMT_A8R8G8B8:
-            switch(getD3DFormat())
-            {
-              case D3DFMT_L8:
-                for(int y = 0; y < height; y++)
-                {
-                    for(int x = 0; x < width; x++)
-                    {
-                        dest[x] = source[x * 4 + 2];
-                    }
-
-                    source += sourceLock.Pitch;
-                    dest += destLock.Pitch;
-                }
-                break;
-              case D3DFMT_A8L8:
-                for(int y = 0; y < height; y++)
-                {
-                    for(int x = 0; x < width; x++)
-                    {
-                        dest[x * 2 + 0] = source[x * 4 + 2];
-                        dest[x * 2 + 1] = source[x * 4 + 3];
-                    }
-
-                    source += sourceLock.Pitch;
-                    dest += destLock.Pitch;
-                }
-                break;
-              default:
-                UNREACHABLE();
-            }
-            break;
-          case D3DFMT_R5G6B5:
-            switch(getD3DFormat())
-            {
-              case D3DFMT_L8:
-                for(int y = 0; y < height; y++)
-                {
-                    for(int x = 0; x < width; x++)
-                    {
-                        unsigned char red = source[x * 2 + 1] & 0xF8;
-                        dest[x] = red | (red >> 5);
-                    }
-
-                    source += sourceLock.Pitch;
-                    dest += destLock.Pitch;
-                }
-                break;
-              default:
-                UNREACHABLE();
-            }
-            break;
-          case D3DFMT_A1R5G5B5:
-            switch(getD3DFormat())
-            {
-              case D3DFMT_L8:
-                for(int y = 0; y < height; y++)
-                {
-                    for(int x = 0; x < width; x++)
-                    {
-                        unsigned char red = source[x * 2 + 1] & 0x7C;
-                        dest[x] = (red << 1) | (red >> 4);
-                    }
-
-                    source += sourceLock.Pitch;
-                    dest += destLock.Pitch;
-                }
-                break;
-              case D3DFMT_A8L8:
-                for(int y = 0; y < height; y++)
-                {
-                    for(int x = 0; x < width; x++)
-                    {
-                        unsigned char red = source[x * 2 + 1] & 0x7C;
-                        dest[x * 2 + 0] = (red << 1) | (red >> 4);
-                        dest[x * 2 + 1] = (signed char)source[x * 2 + 1] >> 7;
-                    }
-
-                    source += sourceLock.Pitch;
-                    dest += destLock.Pitch;
-                }
-                break;
-              default:
-                UNREACHABLE();
-            }
-            break;
-          default:
-            UNREACHABLE();
-        }
-
-        image->dirty = true;
-        mDirtyMetaData = true;    
-    }
-
-    image->surface->UnlockRect();
-    surface->UnlockRect();
-    surface->Release();
-}
-
-D3DFORMAT Texture::getD3DFormat() const
-{
-    return selectFormat(getFormat(), mType);
-}
-
-IDirect3DBaseTexture9 *Texture::getTexture()
-{
-    if (!isComplete())
-    {
-        return NULL;
-    }
-
-    if (mDirtyMetaData)
-    {
-        mBaseTexture = createTexture();
-        mIsRenderable = false;
-    }
-
-    if (mDirtyMetaData || dirtyImageData())
-    {
-        updateTexture();
-    }
-
-    mDirtyMetaData = false;
-    ASSERT(!dirtyImageData());
-
-    return mBaseTexture;
-}
-
-bool Texture::isDirty() const
-{
-    return (mDirty || mDirtyMetaData || dirtyImageData());
-}
-
-// Returns the top-level texture surface as a render target
-void Texture::needRenderTarget()
-{
-    if (!mIsRenderable)
-    {
-        mBaseTexture = convertToRenderTarget();
-        mIsRenderable = true;
-    }
-
-    if (dirtyImageData())
-    {
-        updateTexture();
-    }
-
-    mDirtyMetaData = false;
-}
-
-void Texture::dropTexture()
-{
-    if (mBaseTexture)
-    {
-        mBaseTexture = NULL;
-    }
-
-    mIsRenderable = false;
-}
-
-void Texture::pushTexture(IDirect3DBaseTexture9 *newTexture, bool renderable)
-{
-    mBaseTexture = newTexture;
-    mDirtyMetaData = false;
-    mIsRenderable = renderable;
-    mDirty = true;
-}
-
-
-GLint Texture::creationLevels(GLsizei width, GLsizei height, GLint maxlevel) const
-{
-    if (isPow2(width) && isPow2(height))
-    {
-        return maxlevel;
-    }
-    else
-    {
-        // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
-        return 1;
-    }
-}
-
-GLint Texture::creationLevels(GLsizei size, GLint maxlevel) const
-{
-    return creationLevels(size, size, maxlevel);
-}
-
-int Texture::levelCount() const
-{
-    return mBaseTexture ? mBaseTexture->GetLevelCount() : 0;
-}
-
-bool Texture::isRenderable() const
-{
-    return mIsRenderable;
-}
-
-Texture2D::Texture2D(GLuint id) : Texture(id)
-{
-    mTexture = NULL;
-}
-
-Texture2D::~Texture2D()
-{
-    mColorbufferProxy.set(NULL);
-
-    if (mTexture)
-    {
-        mTexture->Release();
-        mTexture = NULL;
-    }
-}
-
-GLenum Texture2D::getTarget() const
-{
-    return GL_TEXTURE_2D;
-}
-
-GLenum Texture2D::getFormat() const
-{
-    return mImageArray[0].format;
-}
-
-// While OpenGL doesn't check texture consistency until draw-time, D3D9 requires a complete texture
-// for render-to-texture (such as CopyTexImage). We have no way of keeping individual inconsistent levels.
-// Call this when a particular level of the texture must be defined with a specific format, width and height.
-//
-// Returns true if the existing texture was unsuitable and had to be destroyed. If so, it will also set
-// a new height and width for the texture by working backwards from the given width and height.
-bool Texture2D::redefineTexture(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum type)
-{
-    bool widthOkay = (mWidth >> level == width);
-    bool heightOkay = (mHeight >> level == height);
-
-    bool sizeOkay = ((widthOkay && heightOkay)
-                     || (widthOkay && mHeight >> level == 0 && height == 1)
-                     || (heightOkay && mWidth >> level == 0 && width == 1));
-
-    bool typeOkay = (type == mType);
-
-    bool textureOkay = (sizeOkay && typeOkay && internalFormat == mImageArray[0].format);
-
-    if (!textureOkay)
-    {
-        TRACE("Redefining 2D texture (%d, 0x%04X, %d, %d => 0x%04X, %d, %d).", level,
-              mImageArray[0].format, mWidth, mHeight,
-              internalFormat, width, height);
-
-        // Purge all the levels and the texture.
-
-        for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
-        {
-            if (mImageArray[i].surface != NULL)
-            {
-                mImageArray[i].dirty = false;
-
-                mImageArray[i].surface->Release();
-                mImageArray[i].surface = NULL;
-            }
-        }
-
-        if (mTexture != NULL)
-        {
-            mTexture->Release();
-            mTexture = NULL;
-            dropTexture();
-        }
-
-        mWidth = width << level;
-        mHeight = height << level;
-        mImageArray[0].format = internalFormat;
-        mType = type;
-    }
-
-    return !textureOkay;
-}
-
-void Texture2D::setImage(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
-{
-    redefineTexture(level, internalFormat, width, height, type);
-
-    Texture::setImage(width, height, format, type, unpackAlignment, pixels, &mImageArray[level]);
-}
-
-void Texture2D::setCompressedImage(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
-{
-    redefineTexture(level, internalFormat, width, height, GL_UNSIGNED_BYTE);
-
-    Texture::setCompressedImage(width, height, internalFormat, imageSize, pixels, &mImageArray[level]);
-}
-
-void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
-{
-    ASSERT(mImageArray[level].surface != NULL);
-
-    if (level < levelCount())
-    {
-        IDirect3DSurface9 *destLevel = NULL;
-        HRESULT result = mTexture->GetSurfaceLevel(level, &destLevel);
-
-        ASSERT(SUCCEEDED(result));
-
-        if (SUCCEEDED(result))
-        {
-            Image *img = &mImageArray[level];
-
-            RECT sourceRect;
-            sourceRect.left = xoffset;
-            sourceRect.top = yoffset;
-            sourceRect.right = xoffset + width;
-            sourceRect.bottom = yoffset + height;
-
-            POINT destPoint;
-            destPoint.x = xoffset;
-            destPoint.y = yoffset;
-
-            result = getDevice()->UpdateSurface(img->surface, &sourceRect, destLevel, &destPoint);
-            ASSERT(SUCCEEDED(result));
-
-            destLevel->Release();
-
-            img->dirty = false;
-        }
-    }
-}
-
-void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
-{
-    if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[level]))
-    {
-        commitRect(level, xoffset, yoffset, width, height);
-    }
-}
-
-void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
-{
-    if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[level]))
-    {
-        commitRect(level, xoffset, yoffset, width, height);
-    }
-}
-
-void Texture2D::copyImage(GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
-{
-    IDirect3DSurface9 *renderTarget = source->getRenderTarget();
-
-    if (!renderTarget)
-    {
-        ERR("Failed to retrieve the render target.");
-        return error(GL_OUT_OF_MEMORY);
-    }
-
-    bool redefined = redefineTexture(level, internalFormat, width, height, mType);
-   
-    if (!isRenderableFormat())
-    {
-        copyNonRenderable(&mImageArray[level], internalFormat, 0, 0, x, y, width, height, renderTarget);
-    }
-    else
-    {
-        if (redefined)
-        {
-            convertToRenderTarget();
-            pushTexture(mTexture, true);
-        }
-        else
-        {
-            needRenderTarget();
-        }
-
-        if (width != 0 && height != 0 && level < levelCount())
-        {
-            RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
-            sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
-            sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
-            sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
-            sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
-            
-            IDirect3DSurface9 *dest;
-            HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
-
-            getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, internalFormat, 0, 0, dest);
-            dest->Release();
-        }
-    }
-
-    mImageArray[level].width = width;
-    mImageArray[level].height = height;
-    mImageArray[level].format = internalFormat;
-}
-
-void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
-{
-    if (xoffset + width > mImageArray[level].width || yoffset + height > mImageArray[level].height)
-    {
-        return error(GL_INVALID_VALUE);
-    }
-
-    IDirect3DSurface9 *renderTarget = source->getRenderTarget();
-
-    if (!renderTarget)
-    {
-        ERR("Failed to retrieve the render target.");
-        return error(GL_OUT_OF_MEMORY);
-    }
-
-    bool redefined = redefineTexture(0, mImageArray[0].format, mImageArray[0].width, mImageArray[0].height, mType);
-   
-    if (!isRenderableFormat())
-    {
-        copyNonRenderable(&mImageArray[level], getFormat(), xoffset, yoffset, x, y, width, height, renderTarget);
-    }
-    else
-    {
-        if (redefined)
-        {
-            convertToRenderTarget();
-            pushTexture(mTexture, true);
-        }
-        else
-        {
-            needRenderTarget();
-        }
-
-        if (level < levelCount())
-        {
-            RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
-            sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
-            sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
-            sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
-            sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
-
-            GLint destYOffset = transformPixelYOffset(yoffset, height, mImageArray[level].height);
-
-            IDirect3DSurface9 *dest;
-            HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
-
-            getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0].format, xoffset, destYOffset, dest);
-            dest->Release();
-        }
-    }
-}
-
-// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
-bool Texture2D::isComplete() const
-{
-    GLsizei width = mImageArray[0].width;
-    GLsizei height = mImageArray[0].height;
-
-    if (width <= 0 || height <= 0)
-    {
-        return false;
-    }
-
-    bool mipmapping = false;
-
-    switch (mMinFilter)
-    {
-      case GL_NEAREST:
-      case GL_LINEAR:
-        mipmapping = false;
-        break;
-      case GL_NEAREST_MIPMAP_NEAREST:
-      case GL_LINEAR_MIPMAP_NEAREST:
-      case GL_NEAREST_MIPMAP_LINEAR:
-      case GL_LINEAR_MIPMAP_LINEAR:
-        mipmapping = true;
-        break;
-     default: UNREACHABLE();
-    }
-
-    if ((getFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) ||
-        (getFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter()))
-    {
-        if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
-        {
-            return false;
-        }
-    }
-
-
-    if ((getWrapS() != GL_CLAMP_TO_EDGE && !isPow2(width))
-        || (getWrapT() != GL_CLAMP_TO_EDGE && !isPow2(height)))
-    {
-        return false;
-    }
-
-    if (mipmapping)
-    {
-        if (!isPow2(width) || !isPow2(height))
-        {
-            return false;
-        }
-
-        int q = log2(std::max(width, height));
-
-        for (int level = 1; level <= q; level++)
-        {
-            if (mImageArray[level].format != mImageArray[0].format)
-            {
-                return false;
-            }
-
-            if (mImageArray[level].width != std::max(1, width >> level))
-            {
-                return false;
-            }
-
-            if (mImageArray[level].height != std::max(1, height >> level))
-            {
-                return false;
-            }
-        }
-    }
-
-    return true;
-}
-
-bool Texture2D::isCompressed() const
-{
-    return IsCompressed(getFormat());
-}
-
-// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
-IDirect3DBaseTexture9 *Texture2D::createTexture()
-{
-    IDirect3DTexture9 *texture;
-
-    IDirect3DDevice9 *device = getDevice();
-    D3DFORMAT format = selectFormat(mImageArray[0].format, mType);
-
-    HRESULT result = device->CreateTexture(mWidth, mHeight, creationLevels(mWidth, mHeight, 0), 0, format, D3DPOOL_DEFAULT, &texture, NULL);
-
-    if (FAILED(result))
-    {
-        ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
-        return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
-    }
-
-    if (mTexture) mTexture->Release();
-    mTexture = texture;
-    return texture;
-}
-
-void Texture2D::updateTexture()
-{
-    IDirect3DDevice9 *device = getDevice();
-
-    int levels = levelCount();
-
-    for (int level = 0; level < levels; level++)
-    {
-        if (mImageArray[level].dirty)
-        {
-            IDirect3DSurface9 *levelSurface = NULL;
-            HRESULT result = mTexture->GetSurfaceLevel(level, &levelSurface);
-
-            ASSERT(SUCCEEDED(result));
-
-            if (SUCCEEDED(result))
-            {
-                result = device->UpdateSurface(mImageArray[level].surface, NULL, levelSurface, NULL);
-                ASSERT(SUCCEEDED(result));
-
-                levelSurface->Release();
-
-                mImageArray[level].dirty = false;
-            }
-        }
-    }
-}
-
-IDirect3DBaseTexture9 *Texture2D::convertToRenderTarget()
-{
-    IDirect3DTexture9 *texture = NULL;
-
-    if (mWidth != 0 && mHeight != 0)
-    {
-        egl::Display *display = getDisplay();
-        IDirect3DDevice9 *device = getDevice();
-        D3DFORMAT format = selectFormat(mImageArray[0].format, mType);
-
-        HRESULT result = device->CreateTexture(mWidth, mHeight, creationLevels(mWidth, mHeight, 0), D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL);
-
-        if (FAILED(result))
-        {
-            ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
-            return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
-        }
-
-        if (mTexture != NULL)
-        {
-            int levels = levelCount();
-            for (int i = 0; i < levels; i++)
-            {
-                IDirect3DSurface9 *source;
-                result = mTexture->GetSurfaceLevel(i, &source);
-
-                if (FAILED(result))
-                {
-                    ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
-
-                    texture->Release();
-
-                    return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
-                }
-
-                IDirect3DSurface9 *dest;
-                result = texture->GetSurfaceLevel(i, &dest);
-
-                if (FAILED(result))
-                {
-                    ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
-
-                    texture->Release();
-                    source->Release();
-
-                    return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
-                }
-
-                display->endScene();
-                result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
-
-                if (FAILED(result))
-                {
-                    ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
-
-                    texture->Release();
-                    source->Release();
-                    dest->Release();
-
-                    return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
-                }
-
-                source->Release();
-                dest->Release();
-            }
-        }
-    }
-
-    if (mTexture != NULL)
-    {
-        mTexture->Release();
-    }
-
-    mTexture = texture;
-    return mTexture;
-}
-
-bool Texture2D::dirtyImageData() const
-{
-    int q = log2(std::max(mWidth, mHeight));
-
-    for (int i = 0; i <= q; i++)
-    {
-        if (mImageArray[i].dirty) return true;
-    }
-
-    return false;
-}
-
-void Texture2D::generateMipmaps()
-{
-    if (!isPow2(mImageArray[0].width) || !isPow2(mImageArray[0].height))
-    {
-        return error(GL_INVALID_OPERATION);
-    }
-
-    // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
-    unsigned int q = log2(std::max(mWidth, mHeight));
-    for (unsigned int i = 1; i <= q; i++)
-    {
-        if (mImageArray[i].surface != NULL)
-        {
-            mImageArray[i].surface->Release();
-            mImageArray[i].surface = NULL;
-        }
-
-        mImageArray[i].dirty = false;
-
-        mImageArray[i].format = mImageArray[0].format;
-        mImageArray[i].width = std::max(mImageArray[0].width >> i, 1);
-        mImageArray[i].height = std::max(mImageArray[0].height >> i, 1);
-    }
-
-    if (isRenderable())
-    {
-        if (mTexture == NULL)
-        {
-            ERR(" failed because mTexture was null.");
-            return;
-        }
-
-        for (unsigned int i = 1; i <= q; i++)
-        {
-            IDirect3DSurface9 *upper = NULL;
-            IDirect3DSurface9 *lower = NULL;
-
-            mTexture->GetSurfaceLevel(i-1, &upper);
-            mTexture->GetSurfaceLevel(i, &lower);
-
-            if (upper != NULL && lower != NULL)
-            {
-                getBlitter()->boxFilter(upper, lower);
-            }
-
-            if (upper != NULL) upper->Release();
-            if (lower != NULL) lower->Release();
-        }
-    }
-    else
-    {
-        for (unsigned int i = 1; i <= q; i++)
-        {
-            createSurface(mImageArray[i].width, mImageArray[i].height, mImageArray[i].format, mType, &mImageArray[i]);
-            if (mImageArray[i].surface == NULL)
-            {
-                return error(GL_OUT_OF_MEMORY);
-            }
-
-            if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[i].surface, NULL, NULL, mImageArray[i - 1].surface, NULL, NULL, D3DX_FILTER_BOX, 0)))
-            {
-                ERR(" failed to load filter %d to %d.", i - 1, i);
-            }
-
-            mImageArray[i].dirty = true;
-        }
-
-        mDirtyMetaData = true;
-    }
-}
-
-Renderbuffer *Texture2D::getColorbuffer(GLenum target)
-{
-    if (target != GL_TEXTURE_2D)
-    {
-        return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
-    }
-
-    if (mColorbufferProxy.get() == NULL)
-    {
-        mColorbufferProxy.set(new Renderbuffer(id(), new TextureColorbufferProxy(this, target)));
-    }
-
-    return mColorbufferProxy.get();
-}
-
-IDirect3DSurface9 *Texture2D::getRenderTarget(GLenum target)
-{
-    ASSERT(target == GL_TEXTURE_2D);
-
-    needRenderTarget();
-
-    if (mTexture == NULL)
-    {
-        return NULL;
-    }
-    
-    IDirect3DSurface9 *renderTarget = NULL;
-    mTexture->GetSurfaceLevel(0, &renderTarget);
-
-    return renderTarget;
-}
-
-TextureCubeMap::TextureCubeMap(GLuint id) : Texture(id)
-{
-    mTexture = NULL;
-}
-
-TextureCubeMap::~TextureCubeMap()
-{
-    for (int i = 0; i < 6; i++)
-    {
-        mFaceProxies[i].set(NULL);
-    }
-
-    if (mTexture)
-    {
-        mTexture->Release();
-        mTexture = NULL;
-    }
-}
-
-GLenum TextureCubeMap::getTarget() const
-{
-    return GL_TEXTURE_CUBE_MAP;
-}
-
-GLenum TextureCubeMap::getFormat() const
-{
-    return mImageArray[0][0].format;
-}
-
-void TextureCubeMap::setImagePosX(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
-{
-    setImage(0, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
-}
-
-void TextureCubeMap::setImageNegX(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
-{
-    setImage(1, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
-}
-
-void TextureCubeMap::setImagePosY(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
-{
-    setImage(2, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
-}
-
-void TextureCubeMap::setImageNegY(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
-{
-    setImage(3, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
-}
-
-void TextureCubeMap::setImagePosZ(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
-{
-    setImage(4, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
-}
-
-void TextureCubeMap::setImageNegZ(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
-{
-    setImage(5, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
-}
-
-void TextureCubeMap::setCompressedImage(GLenum face, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
-{
-    redefineTexture(level, internalFormat, width);
-
-    Texture::setCompressedImage(width, height, internalFormat, imageSize, pixels, &mImageArray[faceIndex(face)][level]);
-}
-
-void TextureCubeMap::commitRect(GLenum faceTarget, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
-{
-    int face = faceIndex(faceTarget);
-    ASSERT(mImageArray[face][level].surface != NULL);
-
-    if (level < levelCount())
-    {
-        IDirect3DSurface9 *destLevel = getCubeMapSurface(faceTarget, level);
-        ASSERT(destLevel != NULL);
-
-        if (destLevel != NULL)
-        {
-            Image *img = &mImageArray[face][level];
-
-            RECT sourceRect;
-            sourceRect.left = xoffset;
-            sourceRect.top = yoffset;
-            sourceRect.right = xoffset + width;
-            sourceRect.bottom = yoffset + height;
-
-            POINT destPoint;
-            destPoint.x = xoffset;
-            destPoint.y = yoffset;
-
-            HRESULT result = getDevice()->UpdateSurface(img->surface, &sourceRect, destLevel, &destPoint);
-            ASSERT(SUCCEEDED(result));
-
-            destLevel->Release();
-
-            img->dirty = false;
-        }
-    }
-}
-
-void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
-{
-    if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[faceIndex(target)][level]))
-    {
-        commitRect(target, level, xoffset, yoffset, width, height);
-    }
-}
-
-void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
-{
-    if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[faceIndex(target)][level]))
-    {
-        commitRect(target, level, xoffset, yoffset, width, height);
-    }
-}
-
-// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
-bool TextureCubeMap::isComplete() const
-{
-    int size = mImageArray[0][0].width;
-
-    if (size <= 0)
-    {
-        return false;
-    }
-
-    bool mipmapping;
-
-    switch (mMinFilter)
-    {
-      case GL_NEAREST:
-      case GL_LINEAR:
-        mipmapping = false;
-        break;
-      case GL_NEAREST_MIPMAP_NEAREST:
-      case GL_LINEAR_MIPMAP_NEAREST:
-      case GL_NEAREST_MIPMAP_LINEAR:
-      case GL_LINEAR_MIPMAP_LINEAR:
-        mipmapping = true;
-        break;
-      default: UNREACHABLE();
-    }
-
-    for (int face = 0; face < 6; face++)
-    {
-        if (mImageArray[face][0].width != size || mImageArray[face][0].height != size)
-        {
-            return false;
-        }
-    }
-
-    if ((getFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) ||
-        (getFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter()))
-    {
-        if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
-        {
-            return false;
-        }
-    }
-
-    if (mipmapping)
-    {
-        if (!isPow2(size) && (getWrapS() != GL_CLAMP_TO_EDGE || getWrapT() != GL_CLAMP_TO_EDGE))
-        {
-            return false;
-        }
-
-        int q = log2(size);
-
-        for (int face = 0; face < 6; face++)
-        {
-            for (int level = 1; level <= q; level++)
-            {
-                if (mImageArray[face][level].format != mImageArray[0][0].format)
-                {
-                    return false;
-                }
-
-                if (mImageArray[face][level].width != std::max(1, size >> level))
-                {
-                    return false;
-                }
-
-                ASSERT(mImageArray[face][level].height == mImageArray[face][level].width);
-            }
-        }
-    }
-
-    return true;
-}
-
-bool TextureCubeMap::isCompressed() const
-{
-    return IsCompressed(getFormat());
-}
-
-// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
-IDirect3DBaseTexture9 *TextureCubeMap::createTexture()
-{
-    IDirect3DDevice9 *device = getDevice();
-    D3DFORMAT format = selectFormat(mImageArray[0][0].format, mType);
-
-    IDirect3DCubeTexture9 *texture;
-
-    HRESULT result = device->CreateCubeTexture(mWidth, creationLevels(mWidth, 0), 0, format, D3DPOOL_DEFAULT, &texture, NULL);
-
-    if (FAILED(result))
-    {
-        ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
-        return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
-    }
-
-    if (mTexture) mTexture->Release();
-
-    mTexture = texture;
-    return mTexture;
-}
-
-void TextureCubeMap::updateTexture()
-{
-    IDirect3DDevice9 *device = getDevice();
-
-    for (int face = 0; face < 6; face++)
-    {
-        int levels = levelCount();
-        for (int level = 0; level < levels; level++)
-        {
-            Image *img = &mImageArray[face][level];
-
-            if (img->dirty)
-            {
-                IDirect3DSurface9 *levelSurface = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level);
-                ASSERT(levelSurface != NULL);
-
-                if (levelSurface != NULL)
-                {
-                    HRESULT result = device->UpdateSurface(img->surface, NULL, levelSurface, NULL);
-                    ASSERT(SUCCEEDED(result));
-
-                    levelSurface->Release();
-
-                    img->dirty = false;
-                }
-            }
-        }
-    }
-}
-
-IDirect3DBaseTexture9 *TextureCubeMap::convertToRenderTarget()
-{
-    IDirect3DCubeTexture9 *texture = NULL;
-
-    if (mWidth != 0)
-    {
-        egl::Display *display = getDisplay();
-        IDirect3DDevice9 *device = getDevice();
-        D3DFORMAT format = selectFormat(mImageArray[0][0].format, mType);
-
-        HRESULT result = device->CreateCubeTexture(mWidth, creationLevels(mWidth, 0), D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL);
-
-        if (FAILED(result))
-        {
-            ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
-            return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
-        }
-
-        if (mTexture != NULL)
-        {
-            int levels = levelCount();
-            for (int f = 0; f < 6; f++)
-            {
-                for (int i = 0; i < levels; i++)
-                {
-                    IDirect3DSurface9 *source;
-                    result = mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &source);
-
-                    if (FAILED(result))
-                    {
-                        ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
-
-                        texture->Release();
-
-                        return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
-                    }
-
-                    IDirect3DSurface9 *dest;
-                    result = texture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &dest);
-
-                    if (FAILED(result))
-                    {
-                        ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
-
-                        texture->Release();
-                        source->Release();
-
-                        return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
-                    }
-
-                    display->endScene();
-                    result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
-
-                    if (FAILED(result))
-                    {
-                        ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
-
-                        texture->Release();
-                        source->Release();
-                        dest->Release();
-
-                        return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
-                    }
-                }
-            }
-        }
-    }
-
-    if (mTexture != NULL)
-    {
-        mTexture->Release();
-    }
-
-    mTexture = texture;
-    return mTexture;
-}
-
-void TextureCubeMap::setImage(int face, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
-{
-    redefineTexture(level, internalFormat, width);
-
-    Texture::setImage(width, height, format, type, unpackAlignment, pixels, &mImageArray[face][level]);
-}
-
-unsigned int TextureCubeMap::faceIndex(GLenum face)
-{
-    META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
-    META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
-    META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
-    META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
-    META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
-
-    return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
-}
-
-bool TextureCubeMap::dirtyImageData() const
-{
-    int q = log2(mWidth);
-
-    for (int f = 0; f < 6; f++)
-    {
-        for (int i = 0; i <= q; i++)
-        {
-            if (mImageArray[f][i].dirty) return true;
-        }
-    }
-
-    return false;
-}
-
-// While OpenGL doesn't check texture consistency until draw-time, D3D9 requires a complete texture
-// for render-to-texture (such as CopyTexImage). We have no way of keeping individual inconsistent levels & faces.
-// Call this when a particular level of the texture must be defined with a specific format, width and height.
-//
-// Returns true if the existing texture was unsuitable had to be destroyed. If so, it will also set
-// a new size for the texture by working backwards from the given size.
-bool TextureCubeMap::redefineTexture(GLint level, GLenum internalFormat, GLsizei width)
-{
-    // Are these settings compatible with level 0?
-    bool sizeOkay = (mImageArray[0][0].width >> level == width);
-
-    bool textureOkay = (sizeOkay && internalFormat == mImageArray[0][0].format);
-
-    if (!textureOkay)
-    {
-        TRACE("Redefining cube texture (%d, 0x%04X, %d => 0x%04X, %d).", level,
-              mImageArray[0][0].format, mImageArray[0][0].width,
-              internalFormat, width);
-
-        // Purge all the levels and the texture.
-        for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
-        {
-            for (int f = 0; f < 6; f++)
-            {
-                if (mImageArray[f][i].surface != NULL)
-                {
-                    mImageArray[f][i].dirty = false;
-
-                    mImageArray[f][i].surface->Release();
-                    mImageArray[f][i].surface = NULL;
-                }
-            }
-        }
-
-        if (mTexture != NULL)
-        {
-            mTexture->Release();
-            mTexture = NULL;
-            dropTexture();
-        }
-
-        mWidth = width << level;
-        mImageArray[0][0].width = width << level;
-        mHeight = width << level;
-        mImageArray[0][0].height = width << level;
-
-        mImageArray[0][0].format = internalFormat;
-    }
-
-    return !textureOkay;
-}
-
-void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
-{
-    IDirect3DSurface9 *renderTarget = source->getRenderTarget();
-
-    if (!renderTarget)
-    {
-        ERR("Failed to retrieve the render target.");
-        return error(GL_OUT_OF_MEMORY);
-    }
-
-    unsigned int faceindex = faceIndex(target);
-    bool redefined = redefineTexture(level, internalFormat, width);
-
-    if (!isRenderableFormat())
-    {
-        copyNonRenderable(&mImageArray[faceindex][level], internalFormat, 0, 0, x, y, width, height, renderTarget);
-    }
-    else
-    {
-        if (redefined)
-        {
-            convertToRenderTarget();
-            pushTexture(mTexture, true);
-        }
-        else
-        {
-            needRenderTarget();
-        }
-
-        ASSERT(width == height);
-
-        if (width > 0 && level < levelCount())
-        {
-            RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
-            sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
-            sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
-            sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
-            sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
-
-            IDirect3DSurface9 *dest = getCubeMapSurface(target, level);
-
-            getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, internalFormat, 0, 0, dest);
-            dest->Release();
-        }
-    }
-
-    mImageArray[faceindex][level].width = width;
-    mImageArray[faceindex][level].height = height;
-    mImageArray[faceindex][level].format = internalFormat;
-}
-
-IDirect3DSurface9 *TextureCubeMap::getCubeMapSurface(GLenum face, unsigned int level)
-{
-    if (mTexture == NULL)
-    {
-        UNREACHABLE();
-        return NULL;
-    }
-
-    IDirect3DSurface9 *surface = NULL;
-
-    HRESULT hr = mTexture->GetCubeMapSurface(es2dx::ConvertCubeFace(face), level, &surface);
-
-    return (SUCCEEDED(hr)) ? surface : NULL;
-}
-
-void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
-{
-    GLsizei size = mImageArray[faceIndex(target)][level].width;
-
-    if (xoffset + width > size || yoffset + height > size)
-    {
-        return error(GL_INVALID_VALUE);
-    }
-
-    IDirect3DSurface9 *renderTarget = source->getRenderTarget();
-
-    if (!renderTarget)
-    {
-        ERR("Failed to retrieve the render target.");
-        return error(GL_OUT_OF_MEMORY);
-    }
-
-    unsigned int faceindex = faceIndex(target);
-    bool redefined = redefineTexture(0, mImageArray[0][0].format, mImageArray[0][0].width);
-   
-    if (!isRenderableFormat())
-    {
-        copyNonRenderable(&mImageArray[faceindex][level], getFormat(), 0, 0, x, y, width, height, renderTarget);
-    }
-    else
-    {
-        if (redefined)
-        {
-            convertToRenderTarget();
-            pushTexture(mTexture, true);
-        }
-        else
-        {
-            needRenderTarget();
-        }
-
-        if (level < levelCount())
-        {
-            RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
-            sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
-            sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
-            sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
-            sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
-
-            GLint destYOffset = transformPixelYOffset(yoffset, height, mImageArray[faceindex][level].width);
-
-            IDirect3DSurface9 *dest = getCubeMapSurface(target, level);
-
-            getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0][0].format, xoffset, destYOffset, dest);
-            dest->Release();
-        }
-    }
-}
-
-bool TextureCubeMap::isCubeComplete() const
-{
-    if (mImageArray[0][0].width == 0)
-    {
-        return false;
-    }
-
-    for (unsigned int f = 1; f < 6; f++)
-    {
-        if (mImageArray[f][0].width != mImageArray[0][0].width
-            || mImageArray[f][0].format != mImageArray[0][0].format)
-        {
-            return false;
-        }
-    }
-
-    return true;
-}
-
-void TextureCubeMap::generateMipmaps()
-{
-    if (!isPow2(mImageArray[0][0].width) || !isCubeComplete())
-    {
-        return error(GL_INVALID_OPERATION);
-    }
-
-    // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
-    unsigned int q = log2(mImageArray[0][0].width);
-    for (unsigned int f = 0; f < 6; f++)
-    {
-        for (unsigned int i = 1; i <= q; i++)
-        {
-            if (mImageArray[f][i].surface != NULL)
-            {
-                mImageArray[f][i].surface->Release();
-                mImageArray[f][i].surface = NULL;
-            }
-
-            mImageArray[f][i].dirty = false;
-
-            mImageArray[f][i].format = mImageArray[f][0].format;
-            mImageArray[f][i].width = std::max(mImageArray[f][0].width >> i, 1);
-            mImageArray[f][i].height = mImageArray[f][i].width;
-        }
-    }
-
-    if (isRenderable())
-    {
-        if (mTexture == NULL)
-        {
-            return;
-        }
-
-        for (unsigned int f = 0; f < 6; f++)
-        {
-            for (unsigned int i = 1; i <= q; i++)
-            {
-                IDirect3DSurface9 *upper = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i-1);
-                IDirect3DSurface9 *lower = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i);
-
-                if (upper != NULL && lower != NULL)
-                {
-                    getBlitter()->boxFilter(upper, lower);
-                }
-
-                if (upper != NULL) upper->Release();
-                if (lower != NULL) lower->Release();
-            }
-        }
-    }
-    else
-    {
-        for (unsigned int f = 0; f < 6; f++)
-        {
-            for (unsigned int i = 1; i <= q; i++)
-            {
-                createSurface(mImageArray[f][i].width, mImageArray[f][i].height, mImageArray[f][i].format, mType, &mImageArray[f][i]);
-                if (mImageArray[f][i].surface == NULL)
-                {
-                    return error(GL_OUT_OF_MEMORY);
-                }
-
-                if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[f][i].surface, NULL, NULL, mImageArray[f][i - 1].surface, NULL, NULL, D3DX_FILTER_BOX, 0)))
-                {
-                    ERR(" failed to load filter %d to %d.", i - 1, i);
-                }
-
-                mImageArray[f][i].dirty = true;
-            }
-        }
-
-        mDirtyMetaData = true;
-    }
-}
-
-Renderbuffer *TextureCubeMap::getColorbuffer(GLenum target)
-{
-    if (!IsCubemapTextureTarget(target))
-    {
-        return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
-    }
-
-    unsigned int face = faceIndex(target);
-
-    if (mFaceProxies[face].get() == NULL)
-    {
-        mFaceProxies[face].set(new Renderbuffer(id(), new TextureColorbufferProxy(this, target)));
-    }
-
-    return mFaceProxies[face].get();
-}
-
-IDirect3DSurface9 *TextureCubeMap::getRenderTarget(GLenum target)
-{
-    ASSERT(IsCubemapTextureTarget(target));
-
-    needRenderTarget();
-    
-    if (mTexture == NULL)
-    {
-        return NULL;
-    }
-    
-    IDirect3DSurface9 *renderTarget = NULL;
-    mTexture->GetCubeMapSurface(es2dx::ConvertCubeFace(target), 0, &renderTarget);
-
-    return renderTarget;
-}
-
-Texture::TextureColorbufferProxy::TextureColorbufferProxy(Texture *texture, GLenum target)
-  : Colorbuffer(texture), mTexture(texture), mTarget(target)
-{
-    ASSERT(IsTextureTarget(target));
-}
-
-void Texture::TextureColorbufferProxy::addRef() const
-{
-    mTexture->addRef();
-}
-
-void Texture::TextureColorbufferProxy::release() const
-{
-    mTexture->release();
-}
-
-IDirect3DSurface9 *Texture::TextureColorbufferProxy::getRenderTarget()
-{
-    if (mRenderTarget) mRenderTarget->Release();
-
-    mRenderTarget = mTexture->getRenderTarget(mTarget);
-
-    return mRenderTarget;
-}
-
-int Texture::TextureColorbufferProxy::getWidth() const
-{
-    return mTexture->getWidth();
-}
-
-int Texture::TextureColorbufferProxy::getHeight() const
-{
-    return mTexture->getHeight();
-}
-
-GLenum Texture::TextureColorbufferProxy::getFormat() const
-{
-    return mTexture->getFormat();
-}
-
-bool Texture::TextureColorbufferProxy::isFloatingPoint() const
-{
-    return mTexture->isFloatingPoint();
-}
-
-}
+//

+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.

+// Use of this source code is governed by a BSD-style license that can be

+// found in the LICENSE file.

+//

+

+// Texture.cpp: Implements the gl::Texture class and its derived classes

+// Texture2D and TextureCubeMap. Implements GL texture objects and related

+// functionality. [OpenGL ES 2.0.24] section 3.7 page 63.

+

+#include "libGLESv2/Texture.h"

+

+#include <d3dx9tex.h>

+

+#include <algorithm>

+

+#include "common/debug.h"

+

+#include "libGLESv2/main.h"

+#include "libGLESv2/mathutil.h"

+#include "libGLESv2/utilities.h"

+#include "libGLESv2/Blit.h"

+#include "libGLESv2/Framebuffer.h"

+

+namespace gl

+{

+

+Texture::Image::Image()

+  : width(0), height(0), dirty(false), surface(NULL), format(GL_NONE)

+{

+}

+

+Texture::Image::~Image()

+{

+  if (surface) surface->Release();

+}

+

+Texture::Texture(GLuint id) : RefCountObject(id)

+{

+    mMinFilter = GL_NEAREST_MIPMAP_LINEAR;

+    mMagFilter = GL_LINEAR;

+    mWrapS = GL_REPEAT;

+    mWrapT = GL_REPEAT;

+

+    mWidth = 0;

+    mHeight = 0;

+

+    mDirtyMetaData = true;

+    mDirty = true;

+    mIsRenderable = false;

+    mType = GL_UNSIGNED_BYTE;

+    mBaseTexture = NULL;

+}

+

+Texture::~Texture()

+{

+}

+

+Blit *Texture::getBlitter()

+{

+    Context *context = getContext();

+    return context->getBlitter();

+}

+

+// Returns true on successful filter state update (valid enum parameter)

+bool Texture::setMinFilter(GLenum filter)

+{

+    switch (filter)

+    {

+      case GL_NEAREST:

+      case GL_LINEAR:

+      case GL_NEAREST_MIPMAP_NEAREST:

+      case GL_LINEAR_MIPMAP_NEAREST:

+      case GL_NEAREST_MIPMAP_LINEAR:

+      case GL_LINEAR_MIPMAP_LINEAR:

+        {

+            if (mMinFilter != filter)

+            {

+                mMinFilter = filter;

+                mDirty = true;

+            }

+            return true;

+        }

+      default:

+        return false;

+    }

+}

+

+// Returns true on successful filter state update (valid enum parameter)

+bool Texture::setMagFilter(GLenum filter)

+{

+    switch (filter)

+    {

+      case GL_NEAREST:

+      case GL_LINEAR:

+        {

+            if (mMagFilter != filter)

+            {

+                mMagFilter = filter;

+                mDirty = true;

+            }

+            return true;

+        }

+      default:

+        return false;

+    }

+}

+

+// Returns true on successful wrap state update (valid enum parameter)

+bool Texture::setWrapS(GLenum wrap)

+{

+    switch (wrap)

+    {

+      case GL_REPEAT:

+      case GL_CLAMP_TO_EDGE:

+      case GL_MIRRORED_REPEAT:

+        {

+            if (mWrapS != wrap)

+            {

+                mWrapS = wrap;

+                mDirty = true;

+            }

+            return true;

+        }

+      default:

+        return false;

+    }

+}

+

+// Returns true on successful wrap state update (valid enum parameter)

+bool Texture::setWrapT(GLenum wrap)

+{

+    switch (wrap)

+    {

+      case GL_REPEAT:

+      case GL_CLAMP_TO_EDGE:

+      case GL_MIRRORED_REPEAT:

+        {

+            if (mWrapT != wrap)

+            {

+                mWrapT = wrap;

+                mDirty = true;

+            }

+            return true;

+        }

+      default:

+        return false;

+    }

+}

+

+GLenum Texture::getMinFilter() const

+{

+    return mMinFilter;

+}

+

+GLenum Texture::getMagFilter() const

+{

+    return mMagFilter;

+}

+

+GLenum Texture::getWrapS() const

+{

+    return mWrapS;

+}

+

+GLenum Texture::getWrapT() const

+{

+    return mWrapT;

+}

+

+GLuint Texture::getWidth() const

+{

+    return mWidth;

+}

+

+GLuint Texture::getHeight() const

+{

+    return mHeight;

+}

+

+bool Texture::isFloatingPoint() const

+{

+    return (mType == GL_FLOAT || mType == GL_HALF_FLOAT_OES);

+}

+

+bool Texture::isRenderableFormat() const

+{

+    D3DFORMAT format = getD3DFormat();

+    

+    switch(format)

+    {

+      case D3DFMT_L8:

+      case D3DFMT_A8L8:

+      case D3DFMT_DXT1:

+        return false;

+      case D3DFMT_A8R8G8B8:

+      case D3DFMT_X8R8G8B8:

+      case D3DFMT_A16B16G16R16F:

+      case D3DFMT_A32B32G32R32F:

+        return true;

+      default:

+        UNREACHABLE();

+    }

+

+    return false;

+}

+

+// Selects an internal Direct3D 9 format for storing an Image

+D3DFORMAT Texture::selectFormat(GLenum format, GLenum type)

+{

+    if (format == GL_COMPRESSED_RGB_S3TC_DXT1_EXT ||

+        format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT)

+    {

+        return D3DFMT_DXT1;

+    }

+    else if (type == GL_FLOAT)

+    {

+        return D3DFMT_A32B32G32R32F;

+    }

+    else if (type == GL_HALF_FLOAT_OES)

+    {

+        return D3DFMT_A16B16G16R16F;

+    }

+    else if (type == GL_UNSIGNED_BYTE)

+    {

+        if (format == GL_LUMINANCE && getContext()->supportsLuminanceTextures())

+        {

+            return D3DFMT_L8;

+        }

+        else if (format == GL_LUMINANCE_ALPHA && getContext()->supportsLuminanceAlphaTextures())

+        {

+            return D3DFMT_A8L8;

+        }

+        else if (format == GL_RGB)

+        {

+            return D3DFMT_X8R8G8B8;

+        }

+

+        return D3DFMT_A8R8G8B8;

+    }

+

+    return D3DFMT_A8R8G8B8;

+}

+

+// Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input

+// into the target pixel rectangle at output with outputPitch bytes in between each line.

+void Texture::loadImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type,

+                            GLint unpackAlignment, const void *input, size_t outputPitch, void *output, D3DSURFACE_DESC *description) const

+{

+    GLsizei inputPitch = -ComputePitch(width, format, type, unpackAlignment);

+    input = ((char*)input) - inputPitch * (height - 1);

+

+    switch (type)

+    {

+      case GL_UNSIGNED_BYTE:

+        switch (format)

+        {

+          case GL_ALPHA:

+            loadAlphaImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);

+            break;

+          case GL_LUMINANCE:

+            loadLuminanceImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output, description->Format == D3DFMT_L8);

+            break;

+          case GL_LUMINANCE_ALPHA:

+            loadLuminanceAlphaImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output, description->Format == D3DFMT_A8L8);

+            break;

+          case GL_RGB:

+            loadRGBUByteImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);

+            break;

+          case GL_RGBA:

+            loadRGBAUByteImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);

+            break;

+          case GL_BGRA_EXT:

+            loadBGRAImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);

+            break;

+          default: UNREACHABLE();

+        }

+        break;

+      case GL_UNSIGNED_SHORT_5_6_5:

+        switch (format)

+        {

+          case GL_RGB:

+            loadRGB565ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);

+            break;

+          default: UNREACHABLE();

+        }

+        break;

+      case GL_UNSIGNED_SHORT_4_4_4_4:

+        switch (format)

+        {

+          case GL_RGBA:

+            loadRGBA4444ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);

+            break;

+          default: UNREACHABLE();

+        }

+        break;

+      case GL_UNSIGNED_SHORT_5_5_5_1:

+        switch (format)

+        {

+          case GL_RGBA:

+            loadRGBA5551ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);

+            break;

+          default: UNREACHABLE();

+        }

+        break;

+      case GL_FLOAT:

+        switch (format)

+        {

+          // float textures are converted to RGBA, not BGRA, as they're stored that way in D3D

+          case GL_ALPHA:

+            loadAlphaFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);

+            break;

+          case GL_LUMINANCE:

+            loadLuminanceFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);

+            break;

+          case GL_LUMINANCE_ALPHA:

+            loadLuminanceAlphaFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);

+            break;

+          case GL_RGB:

+            loadRGBFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);

+            break;

+          case GL_RGBA:

+            loadRGBAFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);

+            break;

+          default: UNREACHABLE();

+        }

+        break;

+      case GL_HALF_FLOAT_OES:

+        switch (format)

+        {

+          // float textures are converted to RGBA, not BGRA, as they're stored that way in D3D

+          case GL_ALPHA:

+            loadAlphaHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);

+            break;

+          case GL_LUMINANCE:

+            loadLuminanceHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);

+            break;

+          case GL_LUMINANCE_ALPHA:

+            loadLuminanceAlphaHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);

+            break;

+          case GL_RGB:

+            loadRGBHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);

+            break;

+          case GL_RGBA:

+            loadRGBAHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);

+            break;

+          default: UNREACHABLE();

+        }

+        break;

+      default: UNREACHABLE();

+    }

+}

+

+void Texture::loadAlphaImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,

+                                 int inputPitch, const void *input, size_t outputPitch, void *output) const

+{

+    const unsigned char *source = NULL;

+    unsigned char *dest = NULL;

+    

+    for (int y = 0; y < height; y++)

+    {

+        source = static_cast<const unsigned char*>(input) + y * inputPitch;

+        dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;

+        for (int x = 0; x < width; x++)

+        {

+            dest[4 * x + 0] = 0;

+            dest[4 * x + 1] = 0;

+            dest[4 * x + 2] = 0;

+            dest[4 * x + 3] = source[x];

+        }

+    }

+}

+

+void Texture::loadAlphaFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,

+                                      int inputPitch, const void *input, size_t outputPitch, void *output) const

+{

+    const float *source = NULL;

+    float *dest = NULL;

+

+    for (int y = 0; y < height; y++)

+    {

+        source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);

+        dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch  + xoffset * 16);

+        for (int x = 0; x < width; x++)

+        {

+            dest[4 * x + 0] = 0;

+            dest[4 * x + 1] = 0;

+            dest[4 * x + 2] = 0;

+            dest[4 * x + 3] = source[x];

+        }

+    }

+}

+

+void Texture::loadAlphaHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,

+                                          int inputPitch, const void *input, size_t outputPitch, void *output) const

+{

+    const unsigned short *source = NULL;

+    unsigned short *dest = NULL;

+

+    for (int y = 0; y < height; y++)

+    {

+        source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);

+        dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);

+        for (int x = 0; x < width; x++)

+        {

+            dest[4 * x + 0] = 0;

+            dest[4 * x + 1] = 0;

+            dest[4 * x + 2] = 0;

+            dest[4 * x + 3] = source[x];

+        }

+    }

+}

+

+void Texture::loadLuminanceImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,

+                                     int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const

+{

+    const int destBytesPerPixel = native? 1: 4;

+    const unsigned char *source = NULL;

+    unsigned char *dest = NULL;

+

+    for (int y = 0; y < height; y++)

+    {

+        source = static_cast<const unsigned char*>(input) + y * inputPitch;

+        dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * destBytesPerPixel;

+

+        if (!native)   // BGRA8 destination format

+        {

+            for (int x = 0; x < width; x++)

+            {

+                dest[4 * x + 0] = source[x];

+                dest[4 * x + 1] = source[x];

+                dest[4 * x + 2] = source[x];

+                dest[4 * x + 3] = 0xFF;

+            }

+        }

+        else   // L8 destination format

+        {

+            memcpy(dest, source, width);

+        }

+    }

+}

+

+void Texture::loadLuminanceFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,

+                                          int inputPitch, const void *input, size_t outputPitch, void *output) const

+{

+    const float *source = NULL;

+    float *dest = NULL;

+

+    for (int y = 0; y < height; y++)

+    {

+        source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);

+        dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch  + xoffset * 16);

+        for (int x = 0; x < width; x++)

+        {

+            dest[4 * x + 0] = source[x];

+            dest[4 * x + 1] = source[x];

+            dest[4 * x + 2] = source[x];

+            dest[4 * x + 3] = 1.0f;

+        }

+    }

+}

+

+void Texture::loadLuminanceHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,

+                                                   int inputPitch, const void *input, size_t outputPitch, void *output) const

+{

+    const unsigned short *source = NULL;

+    unsigned short *dest = NULL;

+

+    for (int y = 0; y < height; y++)

+    {

+        source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);

+        dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);

+        for (int x = 0; x < width; x++)

+        {

+            dest[4 * x + 0] = source[x];

+            dest[4 * x + 1] = source[x];

+            dest[4 * x + 2] = source[x];

+            dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1

+        }

+    }

+}

+

+void Texture::loadLuminanceAlphaImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,

+                                          int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const

+{

+    const int destBytesPerPixel = native? 2: 4;

+    const unsigned char *source = NULL;

+    unsigned char *dest = NULL;

+

+    for (int y = 0; y < height; y++)

+    {

+        source = static_cast<const unsigned char*>(input) + y * inputPitch;

+        dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * destBytesPerPixel;

+        

+        if (!native)   // BGRA8 destination format

+        {

+            for (int x = 0; x < width; x++)

+            {

+                dest[4 * x + 0] = source[2*x+0];

+                dest[4 * x + 1] = source[2*x+0];

+                dest[4 * x + 2] = source[2*x+0];

+                dest[4 * x + 3] = source[2*x+1];

+            }

+        }

+        else

+        {

+            memcpy(dest, source, width * 2);

+        }

+    }

+}

+

+void Texture::loadLuminanceAlphaFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,

+                                               int inputPitch, const void *input, size_t outputPitch, void *output) const

+{

+    const float *source = NULL;

+    float *dest = NULL;

+

+    for (int y = 0; y < height; y++)

+    {

+        source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);

+        dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch  + xoffset * 16);

+        for (int x = 0; x < width; x++)

+        {

+            dest[4 * x + 0] = source[2*x+0];

+            dest[4 * x + 1] = source[2*x+0];

+            dest[4 * x + 2] = source[2*x+0];

+            dest[4 * x + 3] = source[2*x+1];

+        }

+    }

+}

+

+void Texture::loadLuminanceAlphaHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,

+                                                   int inputPitch, const void *input, size_t outputPitch, void *output) const

+{

+    const unsigned short *source = NULL;

+    unsigned short *dest = NULL;

+

+    for (int y = 0; y < height; y++)

+    {

+        source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);

+        dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);

+        for (int x = 0; x < width; x++)

+        {

+            dest[4 * x + 0] = source[2*x+0];

+            dest[4 * x + 1] = source[2*x+0];

+            dest[4 * x + 2] = source[2*x+0];

+            dest[4 * x + 3] = source[2*x+1];

+        }

+    }

+}

+

+void Texture::loadRGBUByteImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,

+                                    int inputPitch, const void *input, size_t outputPitch, void *output) const

+{

+    const unsigned char *source = NULL;

+    unsigned char *dest = NULL;

+

+    for (int y = 0; y < height; y++)

+    {

+        source = static_cast<const unsigned char*>(input) + y * inputPitch;

+        dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;

+        for (int x = 0; x < width; x++)

+        {

+            dest[4 * x + 0] = source[x * 3 + 2];

+            dest[4 * x + 1] = source[x * 3 + 1];

+            dest[4 * x + 2] = source[x * 3 + 0];

+            dest[4 * x + 3] = 0xFF;

+        }

+    }

+}

+

+void Texture::loadRGB565ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,

+                                  int inputPitch, const void *input, size_t outputPitch, void *output) const

+{

+    const unsigned short *source = NULL;

+    unsigned char *dest = NULL;

+

+    for (int y = 0; y < height; y++)

+    {

+        source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);

+        dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;

+        for (int x = 0; x < width; x++)

+        {

+            unsigned short rgba = source[x];

+            dest[4 * x + 0] = ((rgba & 0x001F) << 3) | ((rgba & 0x001F) >> 2);

+            dest[4 * x + 1] = ((rgba & 0x07E0) >> 3) | ((rgba & 0x07E0) >> 9);

+            dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);

+            dest[4 * x + 3] = 0xFF;

+        }

+    }

+}

+

+void Texture::loadRGBFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,

+                                    int inputPitch, const void *input, size_t outputPitch, void *output) const

+{

+    const float *source = NULL;

+    float *dest = NULL;

+

+    for (int y = 0; y < height; y++)

+    {

+        source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);

+        dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch  + xoffset * 16);

+        for (int x = 0; x < width; x++)

+        {

+            dest[4 * x + 0] = source[x * 3 + 0];

+            dest[4 * x + 1] = source[x * 3 + 1];

+            dest[4 * x + 2] = source[x * 3 + 2];

+            dest[4 * x + 3] = 1.0f;

+        }

+    }

+}

+

+void Texture::loadRGBHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,

+                                        int inputPitch, const void *input, size_t outputPitch, void *output) const

+{

+    const unsigned short *source = NULL;

+    unsigned short *dest = NULL;

+

+    for (int y = 0; y < height; y++)

+    {

+        source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);

+        dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch  + xoffset * 8);

+        for (int x = 0; x < width; x++)

+        {

+            dest[4 * x + 0] = source[x * 3 + 0];

+            dest[4 * x + 1] = source[x * 3 + 1];

+            dest[4 * x + 2] = source[x * 3 + 2];

+            dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1

+        }

+    }

+}

+

+void Texture::loadRGBAUByteImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,

+                                     int inputPitch, const void *input, size_t outputPitch, void *output) const

+{

+    const unsigned char *source = NULL;

+    unsigned char *dest = NULL;

+

+    for (int y = 0; y < height; y++)

+    {

+        source = static_cast<const unsigned char*>(input) + y * inputPitch;

+        dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;

+        for (int x = 0; x < width; x++)

+        {

+            dest[4 * x + 0] = source[x * 4 + 2];

+            dest[4 * x + 1] = source[x * 4 + 1];

+            dest[4 * x + 2] = source[x * 4 + 0];

+            dest[4 * x + 3] = source[x * 4 + 3];

+        }

+    }

+}

+

+void Texture::loadRGBA4444ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,

+                                    int inputPitch, const void *input, size_t outputPitch, void *output) const

+{

+    const unsigned short *source = NULL;

+    unsigned char *dest = NULL;

+

+    for (int y = 0; y < height; y++)

+    {

+        source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);

+        dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;

+        for (int x = 0; x < width; x++)

+        {

+            unsigned short rgba = source[x];

+            dest[4 * x + 0] = ((rgba & 0x00F0) << 0) | ((rgba & 0x00F0) >> 4);

+            dest[4 * x + 1] = ((rgba & 0x0F00) >> 4) | ((rgba & 0x0F00) >> 8);

+            dest[4 * x + 2] = ((rgba & 0xF000) >> 8) | ((rgba & 0xF000) >> 12);

+            dest[4 * x + 3] = ((rgba & 0x000F) << 4) | ((rgba & 0x000F) >> 0);

+        }

+    }

+}

+

+void Texture::loadRGBA5551ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,

+                                    int inputPitch, const void *input, size_t outputPitch, void *output) const

+{

+    const unsigned short *source = NULL;

+    unsigned char *dest = NULL;

+

+    for (int y = 0; y < height; y++)

+    {

+        source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);

+        dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;

+        for (int x = 0; x < width; x++)

+        {

+            unsigned short rgba = source[x];

+            dest[4 * x + 0] = ((rgba & 0x003E) << 2) | ((rgba & 0x003E) >> 3);

+            dest[4 * x + 1] = ((rgba & 0x07C0) >> 3) | ((rgba & 0x07C0) >> 8);

+            dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);

+            dest[4 * x + 3] = (rgba & 0x0001) ? 0xFF : 0;

+        }

+    }

+}

+

+void Texture::loadRGBAFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,

+                                     int inputPitch, const void *input, size_t outputPitch, void *output) const

+{

+    const float *source = NULL;

+    float *dest = NULL;

+

+    for (int y = 0; y < height; y++)

+    {

+        source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);

+        dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch  + xoffset * 16);

+        memcpy(dest, source, width * 16);

+    }

+}

+

+void Texture::loadRGBAHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,

+                                        int inputPitch, const void *input, size_t outputPitch, void *output) const

+{

+    const unsigned char *source = NULL;

+    unsigned char *dest = NULL;

+

+    for (int y = 0; y < height; y++)

+    {

+        source = static_cast<const unsigned char*>(input) + y * inputPitch;

+        dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch  + xoffset * 8;

+        memcpy(dest, source, width * 8);

+    }

+}

+

+void Texture::loadBGRAImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,

+                                int inputPitch, const void *input, size_t outputPitch, void *output) const

+{

+    const unsigned char *source = NULL;

+    unsigned char *dest = NULL;

+

+    for (int y = 0; y < height; y++)

+    {

+        source = static_cast<const unsigned char*>(input) + y * inputPitch;

+        dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;

+        memcpy(dest, source, width*4);

+    }

+}

+

+void Texture::loadCompressedImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,

+                                      int inputPitch, const void *input, size_t outputPitch, void *output) const

+{

+    ASSERT(xoffset % 4 == 0);

+    ASSERT(yoffset % 4 == 0);

+    ASSERT(width % 4 == 0 || width == 2 || width == 1);

+    ASSERT(inputPitch % 8 == 0);

+    ASSERT(outputPitch % 8 == 0);

+

+    const unsigned int *source = reinterpret_cast<const unsigned int*>(input);

+    unsigned int *dest = reinterpret_cast<unsigned int*>(output);

+

+    switch (height)

+    {

+        case 1:

+            // Round width up in case it is 1.

+            for (int x = 0; x < (width + 1) / 2; x += 2)

+            {

+                // First 32-bits is two RGB565 colors shared by tile and does not need to be modified.

+                dest[x] = source[x];

+

+                // Second 32-bits contains 4 rows of 4 2-bit interpolants between the colors, the last 3 rows being unused. No flipping should occur.

+                dest[x + 1] = source[x + 1];

+            }

+            break;

+        case 2:

+            // Round width up in case it is 1.

+            for (int x = 0; x < (width + 1) / 2; x += 2)

+            {

+                // First 32-bits is two RGB565 colors shared by tile and does not need to be modified.

+                dest[x] = source[x];

+

+                // Second 32-bits contains 4 rows of 4 2-bit interpolants between the colors, the last 2 rows being unused. Only the top 2 rows should be flipped.

+                dest[x + 1] = ((source[x + 1] << 8) & 0x0000FF00) |

+                              ((source[x + 1] >> 8) & 0x000000FF);       

+            }

+            break;

+        default:

+            ASSERT(height % 4 == 0);

+            for (int y = 0; y < height / 4; ++y)

+            {

+                const unsigned int *source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);

+                unsigned int *dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);

+

+                // Round width up in case it is 1.

+                for (int x = 0; x < (width + 1) / 2; x += 2)

+                {

+                    // First 32-bits is two RGB565 colors shared by tile and does not need to be modified.

+                    dest[x] = source[x];

+

+                    // Second 32-bits contains 4 rows of 4 2-bit interpolants between the colors. All rows should be flipped.

+                    dest[x + 1] = (source[x + 1] >> 24) | 

+                                  ((source[x + 1] << 8) & 0x00FF0000) |

+                                  ((source[x + 1] >> 8) & 0x0000FF00) |

+                                  (source[x + 1] << 24);                    

+                }

+            }

+            break;

+    }

+}

+

+void Texture::createSurface(GLsizei width, GLsizei height, GLenum format, GLenum type, Image *img)

+{

+    IDirect3DTexture9 *newTexture = NULL;

+    IDirect3DSurface9 *newSurface = NULL;

+

+    if (width != 0 && height != 0)

+    {

+        int levelToFetch = 0;

+        GLsizei requestWidth = width;

+        GLsizei requestHeight = height;

+        if (IsCompressed(format) && (width % 4 != 0 || height % 4 != 0))

+        {

+            bool isMult4 = false;

+            int upsampleCount = 0;

+            while (!isMult4)

+            {

+                requestWidth <<= 1;

+                requestHeight <<= 1;

+                upsampleCount++;

+                if (requestWidth % 4 == 0 && requestHeight % 4 == 0)

+                {

+                    isMult4 = true;

+                }

+            }

+            levelToFetch = upsampleCount;

+        }

+

+        HRESULT result = getDevice()->CreateTexture(requestWidth, requestHeight, levelToFetch + 1, NULL, selectFormat(format, type),

+                                                    D3DPOOL_SYSTEMMEM, &newTexture, NULL);

+

+        if (FAILED(result))

+        {

+            ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);

+            return error(GL_OUT_OF_MEMORY);

+        }

+

+        newTexture->GetSurfaceLevel(levelToFetch, &newSurface);

+        newTexture->Release();

+    }

+

+    if (img->surface) img->surface->Release();

+    img->surface = newSurface;

+

+    img->width = width;

+    img->height = height;

+    img->format = format;

+}

+

+void Texture::setImage(GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, Image *img)

+{

+    createSurface(width, height, format, type, img);

+

+    if (pixels != NULL && img->surface != NULL)

+    {

+        D3DSURFACE_DESC description;

+        img->surface->GetDesc(&description);

+

+        D3DLOCKED_RECT locked;

+        HRESULT result = img->surface->LockRect(&locked, NULL, 0);

+

+        ASSERT(SUCCEEDED(result));

+

+        if (SUCCEEDED(result))

+        {

+            loadImageData(0, 0, width, height, format, type, unpackAlignment, pixels, locked.Pitch, locked.pBits, &description);

+            img->surface->UnlockRect();

+        }

+

+        img->dirty = true;

+    }

+

+    mDirtyMetaData = true;

+}

+

+void Texture::setCompressedImage(GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, Image *img)

+{

+    createSurface(width, height, format, GL_UNSIGNED_BYTE, img);

+

+    if (pixels != NULL && img->surface != NULL)

+    {

+        D3DLOCKED_RECT locked;

+        HRESULT result = img->surface->LockRect(&locked, NULL, 0);

+

+        ASSERT(SUCCEEDED(result));

+

+        if (SUCCEEDED(result))

+        {

+            int inputPitch = ComputeCompressedPitch(width, format);

+            int inputSize = ComputeCompressedSize(width, height, format);

+            loadCompressedImageData(0, 0, width, height, -inputPitch, static_cast<const char*>(pixels) + inputSize - inputPitch, locked.Pitch, locked.pBits);

+            img->surface->UnlockRect();

+        }

+

+        img->dirty = true;

+    }

+

+    mDirtyMetaData = true;

+}

+

+bool Texture::subImage(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, Image *img)

+{

+    if (width + xoffset > img->width || height + yoffset > img->height)

+    {

+        error(GL_INVALID_VALUE);

+        return false;

+    }

+

+    if (!img->surface)

+    {

+        createSurface(img->width, img->height, format, type, img);

+    }

+

+    if (pixels != NULL && img->surface != NULL)

+    {

+        D3DSURFACE_DESC description;

+        img->surface->GetDesc(&description);

+

+        D3DLOCKED_RECT locked;

+        HRESULT result = img->surface->LockRect(&locked, NULL, 0);

+

+        ASSERT(SUCCEEDED(result));

+

+        if (SUCCEEDED(result))

+        {

+            loadImageData(xoffset, transformPixelYOffset(yoffset, height, img->height), width, height, format, type, unpackAlignment, pixels, locked.Pitch, locked.pBits, &description);

+            img->surface->UnlockRect();

+        }

+

+        img->dirty = true;

+    }

+

+    return true;

+}

+

+bool Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, Image *img)

+{

+    if (width + xoffset > img->width || height + yoffset > img->height)

+    {

+        error(GL_INVALID_VALUE);

+        return false;

+    }

+

+    if (format != getFormat())

+    {

+        error(GL_INVALID_OPERATION);

+        return false;

+    }

+

+    if (!img->surface)

+    {

+        createSurface(img->width, img->height, format, GL_UNSIGNED_BYTE, img);

+    }

+

+    if (pixels != NULL && img->surface != NULL)

+    {

+        RECT updateRegion;

+        updateRegion.left = xoffset;

+        updateRegion.right = xoffset + width;

+        updateRegion.bottom = yoffset + height;

+        updateRegion.top = yoffset;

+

+        D3DLOCKED_RECT locked;

+        HRESULT result = img->surface->LockRect(&locked, &updateRegion, 0);

+

+        ASSERT(SUCCEEDED(result));

+

+        if (SUCCEEDED(result))

+        {

+            int inputPitch = ComputeCompressedPitch(width, format);

+            int inputSize = ComputeCompressedSize(width, height, format);

+            loadCompressedImageData(xoffset, transformPixelYOffset(yoffset, height, img->height), width, height, -inputPitch, static_cast<const char*>(pixels) + inputSize - inputPitch, locked.Pitch, locked.pBits);

+            img->surface->UnlockRect();

+        }

+

+        img->dirty = true;

+    }

+

+    return true;

+}

+

+// This implements glCopyTex[Sub]Image2D for non-renderable internal texture formats

+void Texture::copyNonRenderable(Image *image, GLenum internalFormat, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, IDirect3DSurface9 *renderTarget)

+{

+    IDirect3DDevice9 *device = getDevice();

+    IDirect3DSurface9 *surface = NULL;

+    D3DSURFACE_DESC description;

+    renderTarget->GetDesc(&description);

+    

+    HRESULT result = device->CreateOffscreenPlainSurface(description.Width, description.Height, description.Format, D3DPOOL_SYSTEMMEM, &surface, NULL);

+

+    if (!SUCCEEDED(result))

+    {

+        ERR("Could not create matching destination surface.");

+        return error(GL_OUT_OF_MEMORY);

+    }

+

+    result = device->GetRenderTargetData(renderTarget, surface);

+

+    if (!SUCCEEDED(result))

+    {

+        ERR("GetRenderTargetData unexpectedly failed.");

+        surface->Release();

+        return error(GL_OUT_OF_MEMORY);

+    }

+

+    D3DLOCKED_RECT sourceLock = {0};

+    RECT sourceRect = transformPixelRect(x, y, width, height, description.Height);

+    result = surface->LockRect(&sourceLock, &sourceRect, 0);

+

+    if (FAILED(result))

+    {

+        ERR("Failed to lock the source surface (rectangle might be invalid).");

+        surface->UnlockRect();

+        surface->Release();

+        return error(GL_OUT_OF_MEMORY);

+    }

+

+    if (!image->surface)

+    {

+        createSurface(width, height, internalFormat, mType, image);

+    }

+

+    if (image->surface == NULL)

+    {

+        ERR("Failed to create an image surface.");

+        surface->UnlockRect();

+        surface->Release();

+        return error(GL_OUT_OF_MEMORY); 

+    }

+

+    D3DLOCKED_RECT destLock = {0};

+    int destYOffset = transformPixelYOffset(yoffset, height, image->height);

+    RECT destRect = {xoffset, destYOffset, xoffset + width, destYOffset + height};

+    result = image->surface->LockRect(&destLock, &destRect, 0);

+    

+    if (FAILED(result))

+    {

+        ERR("Failed to lock the destination surface (rectangle might be invalid).");

+        surface->UnlockRect();

+        surface->Release();

+        return error(GL_OUT_OF_MEMORY);

+    }

+

+    if (destLock.pBits && sourceLock.pBits)

+    {

+        unsigned char *source = (unsigned char*)sourceLock.pBits;

+        unsigned char *dest = (unsigned char*)destLock.pBits;

+

+        switch (description.Format)

+        {

+          case D3DFMT_X8R8G8B8:

+          case D3DFMT_A8R8G8B8:

+            switch(getD3DFormat())

+            {

+              case D3DFMT_L8:

+                for(int y = 0; y < height; y++)

+                {

+                    for(int x = 0; x < width; x++)

+                    {

+                        dest[x] = source[x * 4 + 2];

+                    }

+

+                    source += sourceLock.Pitch;

+                    dest += destLock.Pitch;

+                }

+                break;

+              case D3DFMT_A8L8:

+                for(int y = 0; y < height; y++)

+                {

+                    for(int x = 0; x < width; x++)

+                    {

+                        dest[x * 2 + 0] = source[x * 4 + 2];

+                        dest[x * 2 + 1] = source[x * 4 + 3];

+                    }

+

+                    source += sourceLock.Pitch;

+                    dest += destLock.Pitch;

+                }

+                break;

+              default:

+                UNREACHABLE();

+            }

+            break;

+          case D3DFMT_R5G6B5:

+            switch(getD3DFormat())

+            {

+              case D3DFMT_L8:

+                for(int y = 0; y < height; y++)

+                {

+                    for(int x = 0; x < width; x++)

+                    {

+                        unsigned char red = source[x * 2 + 1] & 0xF8;

+                        dest[x] = red | (red >> 5);

+                    }

+

+                    source += sourceLock.Pitch;

+                    dest += destLock.Pitch;

+                }

+                break;

+              default:

+                UNREACHABLE();

+            }

+            break;

+          case D3DFMT_A1R5G5B5:

+            switch(getD3DFormat())

+            {

+              case D3DFMT_L8:

+                for(int y = 0; y < height; y++)

+                {

+                    for(int x = 0; x < width; x++)

+                    {

+                        unsigned char red = source[x * 2 + 1] & 0x7C;

+                        dest[x] = (red << 1) | (red >> 4);

+                    }

+

+                    source += sourceLock.Pitch;

+                    dest += destLock.Pitch;

+                }

+                break;

+              case D3DFMT_A8L8:

+                for(int y = 0; y < height; y++)

+                {

+                    for(int x = 0; x < width; x++)

+                    {

+                        unsigned char red = source[x * 2 + 1] & 0x7C;

+                        dest[x * 2 + 0] = (red << 1) | (red >> 4);

+                        dest[x * 2 + 1] = (signed char)source[x * 2 + 1] >> 7;

+                    }

+

+                    source += sourceLock.Pitch;

+                    dest += destLock.Pitch;

+                }

+                break;

+              default:

+                UNREACHABLE();

+            }

+            break;

+          default:

+            UNREACHABLE();

+        }

+

+        image->dirty = true;

+        mDirtyMetaData = true;    

+    }

+

+    image->surface->UnlockRect();

+    surface->UnlockRect();

+    surface->Release();

+}

+

+D3DFORMAT Texture::getD3DFormat() const

+{

+    return selectFormat(getFormat(), mType);

+}

+

+IDirect3DBaseTexture9 *Texture::getTexture()

+{

+    if (!isComplete())

+    {

+        return NULL;

+    }

+

+    if (mDirtyMetaData)

+    {

+        mBaseTexture = createTexture();

+        mIsRenderable = false;

+    }

+

+    if (mDirtyMetaData || dirtyImageData())

+    {

+        updateTexture();

+    }

+

+    mDirtyMetaData = false;

+    ASSERT(!dirtyImageData());

+

+    return mBaseTexture;

+}

+

+bool Texture::isDirty() const

+{

+    return (mDirty || mDirtyMetaData || dirtyImageData());

+}

+

+// Returns the top-level texture surface as a render target

+void Texture::needRenderTarget()

+{

+    if (!mIsRenderable)

+    {

+        mBaseTexture = convertToRenderTarget();

+        mIsRenderable = true;

+    }

+

+    if (dirtyImageData())

+    {

+        updateTexture();

+    }

+

+    mDirtyMetaData = false;

+}

+

+void Texture::dropTexture()

+{

+    if (mBaseTexture)

+    {

+        mBaseTexture = NULL;

+    }

+

+    mIsRenderable = false;

+}

+

+void Texture::pushTexture(IDirect3DBaseTexture9 *newTexture, bool renderable)

+{

+    mBaseTexture = newTexture;

+    mDirtyMetaData = false;

+    mIsRenderable = renderable;

+    mDirty = true;

+}

+

+

+GLint Texture::creationLevels(GLsizei width, GLsizei height, GLint maxlevel) const

+{

+    if (isPow2(width) && isPow2(height))

+    {

+        return maxlevel;

+    }

+    else

+    {

+        // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.

+        return 1;

+    }

+}

+

+GLint Texture::creationLevels(GLsizei size, GLint maxlevel) const

+{

+    return creationLevels(size, size, maxlevel);

+}

+

+int Texture::levelCount() const

+{

+    return mBaseTexture ? mBaseTexture->GetLevelCount() : 0;

+}

+

+bool Texture::isRenderable() const

+{

+    return mIsRenderable;

+}

+

+Texture2D::Texture2D(GLuint id) : Texture(id)

+{

+    mTexture = NULL;

+}

+

+Texture2D::~Texture2D()

+{

+    mColorbufferProxy.set(NULL);

+

+    if (mTexture)

+    {

+        mTexture->Release();

+        mTexture = NULL;

+    }

+}

+

+GLenum Texture2D::getTarget() const

+{

+    return GL_TEXTURE_2D;

+}

+

+GLenum Texture2D::getFormat() const

+{

+    return mImageArray[0].format;

+}

+

+// While OpenGL doesn't check texture consistency until draw-time, D3D9 requires a complete texture

+// for render-to-texture (such as CopyTexImage). We have no way of keeping individual inconsistent levels.

+// Call this when a particular level of the texture must be defined with a specific format, width and height.

+//

+// Returns true if the existing texture was unsuitable and had to be destroyed. If so, it will also set

+// a new height and width for the texture by working backwards from the given width and height.

+bool Texture2D::redefineTexture(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum type)

+{

+    bool widthOkay = (mWidth >> level == width);

+    bool heightOkay = (mHeight >> level == height);

+

+    bool sizeOkay = ((widthOkay && heightOkay)

+                     || (widthOkay && mHeight >> level == 0 && height == 1)

+                     || (heightOkay && mWidth >> level == 0 && width == 1));

+

+    bool typeOkay = (type == mType);

+

+    bool textureOkay = (sizeOkay && typeOkay && internalFormat == mImageArray[0].format);

+

+    if (!textureOkay)

+    {

+        TRACE("Redefining 2D texture (%d, 0x%04X, %d, %d => 0x%04X, %d, %d).", level,

+              mImageArray[0].format, mWidth, mHeight,

+              internalFormat, width, height);

+

+        // Purge all the levels and the texture.

+

+        for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)

+        {

+            if (mImageArray[i].surface != NULL)

+            {

+                mImageArray[i].dirty = false;

+

+                mImageArray[i].surface->Release();

+                mImageArray[i].surface = NULL;

+            }

+        }

+

+        if (mTexture != NULL)

+        {

+            mTexture->Release();

+            mTexture = NULL;

+            dropTexture();

+        }

+

+        mWidth = width << level;

+        mHeight = height << level;

+        mImageArray[0].format = internalFormat;

+        mType = type;

+    }

+

+    return !textureOkay;

+}

+

+void Texture2D::setImage(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)

+{

+    redefineTexture(level, internalFormat, width, height, type);

+

+    Texture::setImage(width, height, format, type, unpackAlignment, pixels, &mImageArray[level]);

+}

+

+void Texture2D::setCompressedImage(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)

+{

+    redefineTexture(level, internalFormat, width, height, GL_UNSIGNED_BYTE);

+

+    Texture::setCompressedImage(width, height, internalFormat, imageSize, pixels, &mImageArray[level]);

+}

+

+void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)

+{

+    ASSERT(mImageArray[level].surface != NULL);

+

+    if (level < levelCount())

+    {

+        IDirect3DSurface9 *destLevel = NULL;

+        HRESULT result = mTexture->GetSurfaceLevel(level, &destLevel);

+

+        ASSERT(SUCCEEDED(result));

+

+        if (SUCCEEDED(result))

+        {

+            Image *img = &mImageArray[level];

+

+            RECT sourceRect = transformPixelRect(xoffset, yoffset, width, height, img->height);;

+

+            POINT destPoint;

+            destPoint.x = sourceRect.left;

+            destPoint.y = sourceRect.top;

+

+            result = getDevice()->UpdateSurface(img->surface, &sourceRect, destLevel, &destPoint);

+            ASSERT(SUCCEEDED(result));

+

+            destLevel->Release();

+

+            img->dirty = false;

+        }

+    }

+}

+

+void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)

+{

+    if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[level]))

+    {

+        commitRect(level, xoffset, yoffset, width, height);

+    }

+}

+

+void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)

+{

+    if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[level]))

+    {

+        commitRect(level, xoffset, yoffset, width, height);

+    }

+}

+

+void Texture2D::copyImage(GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)

+{

+    IDirect3DSurface9 *renderTarget = source->getRenderTarget();

+

+    if (!renderTarget)

+    {

+        ERR("Failed to retrieve the render target.");

+        return error(GL_OUT_OF_MEMORY);

+    }

+

+    bool redefined = redefineTexture(level, internalFormat, width, height, mType);

+   

+    if (!isRenderableFormat())

+    {

+        copyNonRenderable(&mImageArray[level], internalFormat, 0, 0, x, y, width, height, renderTarget);

+    }

+    else

+    {

+        if (redefined)

+        {

+            convertToRenderTarget();

+            pushTexture(mTexture, true);

+        }

+        else

+        {

+            needRenderTarget();

+        }

+

+        if (width != 0 && height != 0 && level < levelCount())

+        {

+            RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());

+            sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());

+            sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());

+            sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());

+            sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());

+            

+            IDirect3DSurface9 *dest;

+            HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);

+

+            getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, internalFormat, 0, 0, dest);

+            dest->Release();

+        }

+    }

+

+    mImageArray[level].width = width;

+    mImageArray[level].height = height;

+    mImageArray[level].format = internalFormat;

+}

+

+void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)

+{

+    if (xoffset + width > mImageArray[level].width || yoffset + height > mImageArray[level].height)

+    {

+        return error(GL_INVALID_VALUE);

+    }

+

+    IDirect3DSurface9 *renderTarget = source->getRenderTarget();

+

+    if (!renderTarget)

+    {

+        ERR("Failed to retrieve the render target.");

+        return error(GL_OUT_OF_MEMORY);

+    }

+

+    bool redefined = redefineTexture(0, mImageArray[0].format, mImageArray[0].width, mImageArray[0].height, mType);

+   

+    if (!isRenderableFormat())

+    {

+        copyNonRenderable(&mImageArray[level], getFormat(), xoffset, yoffset, x, y, width, height, renderTarget);

+    }

+    else

+    {

+        if (redefined)

+        {

+            convertToRenderTarget();

+            pushTexture(mTexture, true);

+        }

+        else

+        {

+            needRenderTarget();

+        }

+

+        if (level < levelCount())

+        {

+            RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());

+            sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());

+            sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());

+            sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());

+            sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());

+

+            GLint destYOffset = transformPixelYOffset(yoffset, height, mImageArray[level].height);

+

+            IDirect3DSurface9 *dest;

+            HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);

+

+            getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0].format, xoffset, destYOffset, dest);

+            dest->Release();

+        }

+    }

+}

+

+// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.

+bool Texture2D::isComplete() const

+{

+    GLsizei width = mImageArray[0].width;

+    GLsizei height = mImageArray[0].height;

+

+    if (width <= 0 || height <= 0)

+    {

+        return false;

+    }

+

+    bool mipmapping = false;

+

+    switch (mMinFilter)

+    {

+      case GL_NEAREST:

+      case GL_LINEAR:

+        mipmapping = false;

+        break;

+      case GL_NEAREST_MIPMAP_NEAREST:

+      case GL_LINEAR_MIPMAP_NEAREST:

+      case GL_NEAREST_MIPMAP_LINEAR:

+      case GL_LINEAR_MIPMAP_LINEAR:

+        mipmapping = true;

+        break;

+     default: UNREACHABLE();

+    }

+

+    if ((getFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) ||

+        (getFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter()))

+    {

+        if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))

+        {

+            return false;

+        }

+    }

+

+

+    if ((getWrapS() != GL_CLAMP_TO_EDGE && !isPow2(width))

+        || (getWrapT() != GL_CLAMP_TO_EDGE && !isPow2(height)))

+    {

+        return false;

+    }

+

+    if (mipmapping)

+    {

+        if (!isPow2(width) || !isPow2(height))

+        {

+            return false;

+        }

+

+        int q = log2(std::max(width, height));

+

+        for (int level = 1; level <= q; level++)

+        {

+            if (mImageArray[level].format != mImageArray[0].format)

+            {

+                return false;

+            }

+

+            if (mImageArray[level].width != std::max(1, width >> level))

+            {

+                return false;

+            }

+

+            if (mImageArray[level].height != std::max(1, height >> level))

+            {

+                return false;

+            }

+        }

+    }

+

+    return true;

+}

+

+bool Texture2D::isCompressed() const

+{

+    return IsCompressed(getFormat());

+}

+

+// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one

+IDirect3DBaseTexture9 *Texture2D::createTexture()

+{

+    IDirect3DTexture9 *texture;

+

+    IDirect3DDevice9 *device = getDevice();

+    D3DFORMAT format = selectFormat(mImageArray[0].format, mType);

+

+    HRESULT result = device->CreateTexture(mWidth, mHeight, creationLevels(mWidth, mHeight, 0), 0, format, D3DPOOL_DEFAULT, &texture, NULL);

+

+    if (FAILED(result))

+    {

+        ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);

+        return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);

+    }

+

+    if (mTexture) mTexture->Release();

+    mTexture = texture;

+    return texture;

+}

+

+void Texture2D::updateTexture()

+{

+    IDirect3DDevice9 *device = getDevice();

+

+    int levels = levelCount();

+

+    for (int level = 0; level < levels; level++)

+    {

+        if (mImageArray[level].dirty)

+        {

+            IDirect3DSurface9 *levelSurface = NULL;

+            HRESULT result = mTexture->GetSurfaceLevel(level, &levelSurface);

+

+            ASSERT(SUCCEEDED(result));

+

+            if (SUCCEEDED(result))

+            {

+                result = device->UpdateSurface(mImageArray[level].surface, NULL, levelSurface, NULL);

+                ASSERT(SUCCEEDED(result));

+

+                levelSurface->Release();

+

+                mImageArray[level].dirty = false;

+            }

+        }

+    }

+}

+

+IDirect3DBaseTexture9 *Texture2D::convertToRenderTarget()

+{

+    IDirect3DTexture9 *texture = NULL;

+

+    if (mWidth != 0 && mHeight != 0)

+    {

+        egl::Display *display = getDisplay();

+        IDirect3DDevice9 *device = getDevice();

+        D3DFORMAT format = selectFormat(mImageArray[0].format, mType);

+

+        HRESULT result = device->CreateTexture(mWidth, mHeight, creationLevels(mWidth, mHeight, 0), D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL);

+

+        if (FAILED(result))

+        {

+            ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);

+            return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);

+        }

+

+        if (mTexture != NULL)

+        {

+            int levels = levelCount();

+            for (int i = 0; i < levels; i++)

+            {

+                IDirect3DSurface9 *source;

+                result = mTexture->GetSurfaceLevel(i, &source);

+

+                if (FAILED(result))

+                {

+                    ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);

+

+                    texture->Release();

+

+                    return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);

+                }

+

+                IDirect3DSurface9 *dest;

+                result = texture->GetSurfaceLevel(i, &dest);

+

+                if (FAILED(result))

+                {

+                    ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);

+

+                    texture->Release();

+                    source->Release();

+

+                    return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);

+                }

+

+                display->endScene();

+                result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);

+

+                if (FAILED(result))

+                {

+                    ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);

+

+                    texture->Release();

+                    source->Release();

+                    dest->Release();

+

+                    return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);

+                }

+

+                source->Release();

+                dest->Release();

+            }

+        }

+    }

+

+    if (mTexture != NULL)

+    {

+        mTexture->Release();

+    }

+

+    mTexture = texture;

+    return mTexture;

+}

+

+bool Texture2D::dirtyImageData() const

+{

+    int q = log2(std::max(mWidth, mHeight));

+

+    for (int i = 0; i <= q; i++)

+    {

+        if (mImageArray[i].dirty) return true;

+    }

+

+    return false;

+}

+

+void Texture2D::generateMipmaps()

+{

+    if (!isPow2(mImageArray[0].width) || !isPow2(mImageArray[0].height))

+    {

+        return error(GL_INVALID_OPERATION);

+    }

+

+    // Purge array levels 1 through q and reset them to represent the generated mipmap levels.

+    unsigned int q = log2(std::max(mWidth, mHeight));

+    for (unsigned int i = 1; i <= q; i++)

+    {

+        if (mImageArray[i].surface != NULL)

+        {

+            mImageArray[i].surface->Release();

+            mImageArray[i].surface = NULL;

+        }

+

+        mImageArray[i].dirty = false;

+

+        mImageArray[i].format = mImageArray[0].format;

+        mImageArray[i].width = std::max(mImageArray[0].width >> i, 1);

+        mImageArray[i].height = std::max(mImageArray[0].height >> i, 1);

+    }

+

+    if (isRenderable())

+    {

+        if (mTexture == NULL)

+        {

+            ERR(" failed because mTexture was null.");

+            return;

+        }

+

+        for (unsigned int i = 1; i <= q; i++)

+        {

+            IDirect3DSurface9 *upper = NULL;

+            IDirect3DSurface9 *lower = NULL;

+

+            mTexture->GetSurfaceLevel(i-1, &upper);

+            mTexture->GetSurfaceLevel(i, &lower);

+

+            if (upper != NULL && lower != NULL)

+            {

+                getBlitter()->boxFilter(upper, lower);

+            }

+

+            if (upper != NULL) upper->Release();

+            if (lower != NULL) lower->Release();

+        }

+    }

+    else

+    {

+        for (unsigned int i = 1; i <= q; i++)

+        {

+            createSurface(mImageArray[i].width, mImageArray[i].height, mImageArray[i].format, mType, &mImageArray[i]);

+            if (mImageArray[i].surface == NULL)

+            {

+                return error(GL_OUT_OF_MEMORY);

+            }

+

+            if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[i].surface, NULL, NULL, mImageArray[i - 1].surface, NULL, NULL, D3DX_FILTER_BOX, 0)))

+            {

+                ERR(" failed to load filter %d to %d.", i - 1, i);

+            }

+

+            mImageArray[i].dirty = true;

+        }

+

+        mDirtyMetaData = true;

+    }

+}

+

+Renderbuffer *Texture2D::getColorbuffer(GLenum target)

+{

+    if (target != GL_TEXTURE_2D)

+    {

+        return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);

+    }

+

+    if (mColorbufferProxy.get() == NULL)

+    {

+        mColorbufferProxy.set(new Renderbuffer(id(), new TextureColorbufferProxy(this, target)));

+    }

+

+    return mColorbufferProxy.get();

+}

+

+IDirect3DSurface9 *Texture2D::getRenderTarget(GLenum target)

+{

+    ASSERT(target == GL_TEXTURE_2D);

+

+    needRenderTarget();

+

+    if (mTexture == NULL)

+    {

+        return NULL;

+    }

+    

+    IDirect3DSurface9 *renderTarget = NULL;

+    mTexture->GetSurfaceLevel(0, &renderTarget);

+

+    return renderTarget;

+}

+

+TextureCubeMap::TextureCubeMap(GLuint id) : Texture(id)

+{

+    mTexture = NULL;

+}

+

+TextureCubeMap::~TextureCubeMap()

+{

+    for (int i = 0; i < 6; i++)

+    {

+        mFaceProxies[i].set(NULL);

+    }

+

+    if (mTexture)

+    {

+        mTexture->Release();

+        mTexture = NULL;

+    }

+}

+

+GLenum TextureCubeMap::getTarget() const

+{

+    return GL_TEXTURE_CUBE_MAP;

+}

+

+GLenum TextureCubeMap::getFormat() const

+{

+    return mImageArray[0][0].format;

+}

+

+void TextureCubeMap::setImagePosX(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)

+{

+    setImage(0, level, internalFormat, width, height, format, type, unpackAlignment, pixels);

+}

+

+void TextureCubeMap::setImageNegX(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)

+{

+    setImage(1, level, internalFormat, width, height, format, type, unpackAlignment, pixels);

+}

+

+void TextureCubeMap::setImagePosY(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)

+{

+    setImage(2, level, internalFormat, width, height, format, type, unpackAlignment, pixels);

+}

+

+void TextureCubeMap::setImageNegY(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)

+{

+    setImage(3, level, internalFormat, width, height, format, type, unpackAlignment, pixels);

+}

+

+void TextureCubeMap::setImagePosZ(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)

+{

+    setImage(4, level, internalFormat, width, height, format, type, unpackAlignment, pixels);

+}

+

+void TextureCubeMap::setImageNegZ(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)

+{

+    setImage(5, level, internalFormat, width, height, format, type, unpackAlignment, pixels);

+}

+

+void TextureCubeMap::setCompressedImage(GLenum face, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)

+{

+    redefineTexture(level, internalFormat, width);

+

+    Texture::setCompressedImage(width, height, internalFormat, imageSize, pixels, &mImageArray[faceIndex(face)][level]);

+}

+

+void TextureCubeMap::commitRect(GLenum faceTarget, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)

+{

+    int face = faceIndex(faceTarget);

+    ASSERT(mImageArray[face][level].surface != NULL);

+

+    if (level < levelCount())

+    {

+        IDirect3DSurface9 *destLevel = getCubeMapSurface(faceTarget, level);

+        ASSERT(destLevel != NULL);

+

+        if (destLevel != NULL)

+        {

+            Image *img = &mImageArray[face][level];

+

+            RECT sourceRect = transformPixelRect(xoffset, yoffset, width, height, img->height);;

+

+            POINT destPoint;

+            destPoint.x = sourceRect.left;

+            destPoint.y = sourceRect.top;

+

+            HRESULT result = getDevice()->UpdateSurface(img->surface, &sourceRect, destLevel, &destPoint);

+            ASSERT(SUCCEEDED(result));

+

+            destLevel->Release();

+

+            img->dirty = false;

+        }

+    }

+}

+

+void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)

+{

+    if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[faceIndex(target)][level]))

+    {

+        commitRect(target, level, xoffset, yoffset, width, height);

+    }

+}

+

+void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)

+{

+    if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[faceIndex(target)][level]))

+    {

+        commitRect(target, level, xoffset, yoffset, width, height);

+    }

+}

+

+// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.

+bool TextureCubeMap::isComplete() const

+{

+    int size = mImageArray[0][0].width;

+

+    if (size <= 0)

+    {

+        return false;

+    }

+

+    bool mipmapping;

+

+    switch (mMinFilter)

+    {

+      case GL_NEAREST:

+      case GL_LINEAR:

+        mipmapping = false;

+        break;

+      case GL_NEAREST_MIPMAP_NEAREST:

+      case GL_LINEAR_MIPMAP_NEAREST:

+      case GL_NEAREST_MIPMAP_LINEAR:

+      case GL_LINEAR_MIPMAP_LINEAR:

+        mipmapping = true;

+        break;

+      default: UNREACHABLE();

+    }

+

+    for (int face = 0; face < 6; face++)

+    {

+        if (mImageArray[face][0].width != size || mImageArray[face][0].height != size)

+        {

+            return false;

+        }

+    }

+

+    if ((getFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) ||

+        (getFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter()))

+    {

+        if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))

+        {

+            return false;

+        }

+    }

+

+    if (mipmapping)

+    {

+        if (!isPow2(size) && (getWrapS() != GL_CLAMP_TO_EDGE || getWrapT() != GL_CLAMP_TO_EDGE))

+        {

+            return false;

+        }

+

+        int q = log2(size);

+

+        for (int face = 0; face < 6; face++)

+        {

+            for (int level = 1; level <= q; level++)

+            {

+                if (mImageArray[face][level].format != mImageArray[0][0].format)

+                {

+                    return false;

+                }

+

+                if (mImageArray[face][level].width != std::max(1, size >> level))

+                {

+                    return false;

+                }

+

+                ASSERT(mImageArray[face][level].height == mImageArray[face][level].width);

+            }

+        }

+    }

+

+    return true;

+}

+

+bool TextureCubeMap::isCompressed() const

+{

+    return IsCompressed(getFormat());

+}

+

+// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one

+IDirect3DBaseTexture9 *TextureCubeMap::createTexture()

+{

+    IDirect3DDevice9 *device = getDevice();

+    D3DFORMAT format = selectFormat(mImageArray[0][0].format, mType);

+

+    IDirect3DCubeTexture9 *texture;

+

+    HRESULT result = device->CreateCubeTexture(mWidth, creationLevels(mWidth, 0), 0, format, D3DPOOL_DEFAULT, &texture, NULL);

+

+    if (FAILED(result))

+    {

+        ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);

+        return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);

+    }

+

+    if (mTexture) mTexture->Release();

+

+    mTexture = texture;

+    return mTexture;

+}

+

+void TextureCubeMap::updateTexture()

+{

+    IDirect3DDevice9 *device = getDevice();

+

+    for (int face = 0; face < 6; face++)

+    {

+        int levels = levelCount();

+        for (int level = 0; level < levels; level++)

+        {

+            Image *img = &mImageArray[face][level];

+

+            if (img->dirty)

+            {

+                IDirect3DSurface9 *levelSurface = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level);

+                ASSERT(levelSurface != NULL);

+

+                if (levelSurface != NULL)

+                {

+                    HRESULT result = device->UpdateSurface(img->surface, NULL, levelSurface, NULL);

+                    ASSERT(SUCCEEDED(result));

+

+                    levelSurface->Release();

+

+                    img->dirty = false;

+                }

+            }

+        }

+    }

+}

+

+IDirect3DBaseTexture9 *TextureCubeMap::convertToRenderTarget()

+{

+    IDirect3DCubeTexture9 *texture = NULL;

+

+    if (mWidth != 0)

+    {

+        egl::Display *display = getDisplay();

+        IDirect3DDevice9 *device = getDevice();

+        D3DFORMAT format = selectFormat(mImageArray[0][0].format, mType);

+

+        HRESULT result = device->CreateCubeTexture(mWidth, creationLevels(mWidth, 0), D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL);

+

+        if (FAILED(result))

+        {

+            ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);

+            return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);

+        }

+

+        if (mTexture != NULL)

+        {

+            int levels = levelCount();

+            for (int f = 0; f < 6; f++)

+            {

+                for (int i = 0; i < levels; i++)

+                {

+                    IDirect3DSurface9 *source;

+                    result = mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &source);

+

+                    if (FAILED(result))

+                    {

+                        ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);

+

+                        texture->Release();

+

+                        return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);

+                    }

+

+                    IDirect3DSurface9 *dest;

+                    result = texture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &dest);

+

+                    if (FAILED(result))

+                    {

+                        ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);

+

+                        texture->Release();

+                        source->Release();

+

+                        return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);

+                    }

+

+                    display->endScene();

+                    result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);

+

+                    if (FAILED(result))

+                    {

+                        ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);

+

+                        texture->Release();

+                        source->Release();

+                        dest->Release();

+

+                        return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);

+                    }

+                }

+            }

+        }

+    }

+

+    if (mTexture != NULL)

+    {

+        mTexture->Release();

+    }

+

+    mTexture = texture;

+    return mTexture;

+}

+

+void TextureCubeMap::setImage(int face, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)

+{

+    redefineTexture(level, internalFormat, width);

+

+    Texture::setImage(width, height, format, type, unpackAlignment, pixels, &mImageArray[face][level]);

+}

+

+unsigned int TextureCubeMap::faceIndex(GLenum face)

+{

+    META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);

+    META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);

+    META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);

+    META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);

+    META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);

+

+    return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;

+}

+

+bool TextureCubeMap::dirtyImageData() const

+{

+    int q = log2(mWidth);

+

+    for (int f = 0; f < 6; f++)

+    {

+        for (int i = 0; i <= q; i++)

+        {

+            if (mImageArray[f][i].dirty) return true;

+        }

+    }

+

+    return false;

+}

+

+// While OpenGL doesn't check texture consistency until draw-time, D3D9 requires a complete texture

+// for render-to-texture (such as CopyTexImage). We have no way of keeping individual inconsistent levels & faces.

+// Call this when a particular level of the texture must be defined with a specific format, width and height.

+//

+// Returns true if the existing texture was unsuitable had to be destroyed. If so, it will also set

+// a new size for the texture by working backwards from the given size.

+bool TextureCubeMap::redefineTexture(GLint level, GLenum internalFormat, GLsizei width)

+{

+    // Are these settings compatible with level 0?

+    bool sizeOkay = (mImageArray[0][0].width >> level == width);

+

+    bool textureOkay = (sizeOkay && internalFormat == mImageArray[0][0].format);

+

+    if (!textureOkay)

+    {

+        TRACE("Redefining cube texture (%d, 0x%04X, %d => 0x%04X, %d).", level,

+              mImageArray[0][0].format, mImageArray[0][0].width,

+              internalFormat, width);

+

+        // Purge all the levels and the texture.

+        for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)

+        {

+            for (int f = 0; f < 6; f++)

+            {

+                if (mImageArray[f][i].surface != NULL)

+                {

+                    mImageArray[f][i].dirty = false;

+

+                    mImageArray[f][i].surface->Release();

+                    mImageArray[f][i].surface = NULL;

+                }

+            }

+        }

+

+        if (mTexture != NULL)

+        {

+            mTexture->Release();

+            mTexture = NULL;

+            dropTexture();

+        }

+

+        mWidth = width << level;

+        mImageArray[0][0].width = width << level;

+        mHeight = width << level;

+        mImageArray[0][0].height = width << level;

+

+        mImageArray[0][0].format = internalFormat;

+    }

+

+    return !textureOkay;

+}

+

+void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)

+{

+    IDirect3DSurface9 *renderTarget = source->getRenderTarget();

+

+    if (!renderTarget)

+    {

+        ERR("Failed to retrieve the render target.");

+        return error(GL_OUT_OF_MEMORY);

+    }

+

+    unsigned int faceindex = faceIndex(target);

+    bool redefined = redefineTexture(level, internalFormat, width);

+

+    if (!isRenderableFormat())

+    {

+        copyNonRenderable(&mImageArray[faceindex][level], internalFormat, 0, 0, x, y, width, height, renderTarget);

+    }

+    else

+    {

+        if (redefined)

+        {

+            convertToRenderTarget();

+            pushTexture(mTexture, true);

+        }

+        else

+        {

+            needRenderTarget();

+        }

+

+        ASSERT(width == height);

+

+        if (width > 0 && level < levelCount())

+        {

+            RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());

+            sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());

+            sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());

+            sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());

+            sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());

+

+            IDirect3DSurface9 *dest = getCubeMapSurface(target, level);

+

+            getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, internalFormat, 0, 0, dest);

+            dest->Release();

+        }

+    }

+

+    mImageArray[faceindex][level].width = width;

+    mImageArray[faceindex][level].height = height;

+    mImageArray[faceindex][level].format = internalFormat;

+}

+

+IDirect3DSurface9 *TextureCubeMap::getCubeMapSurface(GLenum face, unsigned int level)

+{

+    if (mTexture == NULL)

+    {

+        UNREACHABLE();

+        return NULL;

+    }

+

+    IDirect3DSurface9 *surface = NULL;

+

+    HRESULT hr = mTexture->GetCubeMapSurface(es2dx::ConvertCubeFace(face), level, &surface);

+

+    return (SUCCEEDED(hr)) ? surface : NULL;

+}

+

+void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)

+{

+    GLsizei size = mImageArray[faceIndex(target)][level].width;

+

+    if (xoffset + width > size || yoffset + height > size)

+    {

+        return error(GL_INVALID_VALUE);

+    }

+

+    IDirect3DSurface9 *renderTarget = source->getRenderTarget();

+

+    if (!renderTarget)

+    {

+        ERR("Failed to retrieve the render target.");

+        return error(GL_OUT_OF_MEMORY);

+    }

+

+    unsigned int faceindex = faceIndex(target);

+    bool redefined = redefineTexture(0, mImageArray[0][0].format, mImageArray[0][0].width);

+   

+    if (!isRenderableFormat())

+    {

+        copyNonRenderable(&mImageArray[faceindex][level], getFormat(), 0, 0, x, y, width, height, renderTarget);

+    }

+    else

+    {

+        if (redefined)

+        {

+            convertToRenderTarget();

+            pushTexture(mTexture, true);

+        }

+        else

+        {

+            needRenderTarget();

+        }

+

+        if (level < levelCount())

+        {

+            RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());

+            sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());

+            sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());

+            sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());

+            sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());

+

+            GLint destYOffset = transformPixelYOffset(yoffset, height, mImageArray[faceindex][level].width);

+

+            IDirect3DSurface9 *dest = getCubeMapSurface(target, level);

+

+            getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0][0].format, xoffset, destYOffset, dest);

+            dest->Release();

+        }

+    }

+}

+

+bool TextureCubeMap::isCubeComplete() const

+{

+    if (mImageArray[0][0].width == 0)

+    {

+        return false;

+    }

+

+    for (unsigned int f = 1; f < 6; f++)

+    {

+        if (mImageArray[f][0].width != mImageArray[0][0].width

+            || mImageArray[f][0].format != mImageArray[0][0].format)

+        {

+            return false;

+        }

+    }

+

+    return true;

+}

+

+void TextureCubeMap::generateMipmaps()

+{

+    if (!isPow2(mImageArray[0][0].width) || !isCubeComplete())

+    {

+        return error(GL_INVALID_OPERATION);

+    }

+

+    // Purge array levels 1 through q and reset them to represent the generated mipmap levels.

+    unsigned int q = log2(mImageArray[0][0].width);

+    for (unsigned int f = 0; f < 6; f++)

+    {

+        for (unsigned int i = 1; i <= q; i++)

+        {

+            if (mImageArray[f][i].surface != NULL)

+            {

+                mImageArray[f][i].surface->Release();

+                mImageArray[f][i].surface = NULL;

+            }

+

+            mImageArray[f][i].dirty = false;

+

+            mImageArray[f][i].format = mImageArray[f][0].format;

+            mImageArray[f][i].width = std::max(mImageArray[f][0].width >> i, 1);

+            mImageArray[f][i].height = mImageArray[f][i].width;

+        }

+    }

+

+    if (isRenderable())

+    {

+        if (mTexture == NULL)

+        {

+            return;

+        }

+

+        for (unsigned int f = 0; f < 6; f++)

+        {

+            for (unsigned int i = 1; i <= q; i++)

+            {

+                IDirect3DSurface9 *upper = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i-1);

+                IDirect3DSurface9 *lower = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i);

+

+                if (upper != NULL && lower != NULL)

+                {

+                    getBlitter()->boxFilter(upper, lower);

+                }

+

+                if (upper != NULL) upper->Release();

+                if (lower != NULL) lower->Release();

+            }

+        }

+    }

+    else

+    {

+        for (unsigned int f = 0; f < 6; f++)

+        {

+            for (unsigned int i = 1; i <= q; i++)

+            {

+                createSurface(mImageArray[f][i].width, mImageArray[f][i].height, mImageArray[f][i].format, mType, &mImageArray[f][i]);

+                if (mImageArray[f][i].surface == NULL)

+                {

+                    return error(GL_OUT_OF_MEMORY);

+                }

+

+                if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[f][i].surface, NULL, NULL, mImageArray[f][i - 1].surface, NULL, NULL, D3DX_FILTER_BOX, 0)))

+                {

+                    ERR(" failed to load filter %d to %d.", i - 1, i);

+                }

+

+                mImageArray[f][i].dirty = true;

+            }

+        }

+

+        mDirtyMetaData = true;

+    }

+}

+

+Renderbuffer *TextureCubeMap::getColorbuffer(GLenum target)

+{

+    if (!IsCubemapTextureTarget(target))

+    {

+        return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);

+    }

+

+    unsigned int face = faceIndex(target);

+

+    if (mFaceProxies[face].get() == NULL)

+    {

+        mFaceProxies[face].set(new Renderbuffer(id(), new TextureColorbufferProxy(this, target)));

+    }

+

+    return mFaceProxies[face].get();

+}

+

+IDirect3DSurface9 *TextureCubeMap::getRenderTarget(GLenum target)

+{

+    ASSERT(IsCubemapTextureTarget(target));

+

+    needRenderTarget();

+    

+    if (mTexture == NULL)

+    {

+        return NULL;

+    }

+    

+    IDirect3DSurface9 *renderTarget = NULL;

+    mTexture->GetCubeMapSurface(es2dx::ConvertCubeFace(target), 0, &renderTarget);

+

+    return renderTarget;

+}

+

+Texture::TextureColorbufferProxy::TextureColorbufferProxy(Texture *texture, GLenum target)

+  : Colorbuffer(texture), mTexture(texture), mTarget(target)

+{

+    ASSERT(IsTextureTarget(target));

+}

+

+void Texture::TextureColorbufferProxy::addRef() const

+{

+    mTexture->addRef();

+}

+

+void Texture::TextureColorbufferProxy::release() const

+{

+    mTexture->release();

+}

+

+IDirect3DSurface9 *Texture::TextureColorbufferProxy::getRenderTarget()

+{

+    if (mRenderTarget) mRenderTarget->Release();

+

+    mRenderTarget = mTexture->getRenderTarget(mTarget);

+

+    return mRenderTarget;

+}

+

+int Texture::TextureColorbufferProxy::getWidth() const

+{

+    return mTexture->getWidth();

+}

+

+int Texture::TextureColorbufferProxy::getHeight() const

+{

+    return mTexture->getHeight();

+}

+

+GLenum Texture::TextureColorbufferProxy::getFormat() const

+{

+    return mTexture->getFormat();

+}

+

+bool Texture::TextureColorbufferProxy::isFloatingPoint() const

+{

+    return mTexture->isFloatingPoint();

+}

+

+}