Edit

kc3-lang/angle/src/libGLESv2/utilities.cpp

Branch :

  • Show log

    Commit

  • Author : apatrick@chromium.org
    Date : 2011-03-17 18:44:29
    Hash : 831fe2af
    Message : Fixed framebuffer-object-attachment WebGL conformance test. We updated it with WebGL conformance test r14153 to exercise zero-size FBO attachments, which failed with ANGLE. The new conformance test passes with OpenGL and Mesa. See this Chromium bug: http://code.google.com/p/chromium/issues/detail?id=75666 D3D fails if you try to create a zero size depth buffer but OpenGL ES2 allows it. D3D / drivers seem to sometimes crash rather than fail normally, though this might just be because some users have enabled the D3D debug runtime and break on error and we're getting the reports. It was also returning unexpected results when calling GetRenderbufferParameter for parameters that do not apply to a particular buffer. For example, RED_SIZE for a zero sized depth buffer should be 0. Tested by running WebGL conformance test with retail D3D runtime (passes) and debug D3D runtime (passes and does not assert in D3D or ANGLE). Review URL: http://codereview.appspot.com/4284053 git-svn-id: https://angleproject.googlecode.com/svn/trunk@577 736b8ea6-26fd-11df-bfd4-992fa37f6226

  • src/libGLESv2/utilities.cpp
  • //
    // 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.
    //
    
    // utilities.cpp: Conversion functions and other utility routines.
    
    #include "libGLESv2/utilities.h"
    
    #include <limits>
    #include <stdio.h>
    #include <windows.h>
    
    #include "common/debug.h"
    
    #include "libGLESv2/mathutil.h"
    #include "libGLESv2/Context.h"
    
    namespace gl
    {
    
    int UniformComponentCount(GLenum type)
    {
        switch (type)
        {
          case GL_BOOL:
          case GL_FLOAT:
          case GL_INT:
          case GL_SAMPLER_2D:
          case GL_SAMPLER_CUBE:
              return 1;
          case GL_BOOL_VEC2:
          case GL_FLOAT_VEC2:
          case GL_INT_VEC2:
              return 2;
          case GL_INT_VEC3:
          case GL_FLOAT_VEC3:
          case GL_BOOL_VEC3:
              return 3;
          case GL_BOOL_VEC4:
          case GL_FLOAT_VEC4:
          case GL_INT_VEC4:
          case GL_FLOAT_MAT2:
              return 4;
          case GL_FLOAT_MAT3:
              return 9;
          case GL_FLOAT_MAT4:
              return 16;
          default:
              UNREACHABLE();
        }
    
        return 0;
    }
    
    GLenum UniformComponentType(GLenum type)
    {
        switch(type)
        {
          case GL_BOOL:
          case GL_BOOL_VEC2:
          case GL_BOOL_VEC3:
          case GL_BOOL_VEC4:
              return GL_BOOL;
          case GL_FLOAT:
          case GL_FLOAT_VEC2:
          case GL_FLOAT_VEC3:
          case GL_FLOAT_VEC4:
          case GL_FLOAT_MAT2:
          case GL_FLOAT_MAT3:
          case GL_FLOAT_MAT4:
              return GL_FLOAT;
          case GL_INT:
          case GL_SAMPLER_2D:
          case GL_SAMPLER_CUBE:
          case GL_INT_VEC2:
          case GL_INT_VEC3:
          case GL_INT_VEC4:
              return GL_INT;
          default:
              UNREACHABLE();
        }
    
        return GL_NONE;
    }
    
    size_t UniformTypeSize(GLenum type)
    {
        switch(type)
        {
          case GL_BOOL:  return sizeof(GLboolean);
          case GL_FLOAT: return sizeof(GLfloat);
          case GL_INT:   return sizeof(GLint);
        }
    
        return UniformTypeSize(UniformComponentType(type)) * UniformComponentCount(type);
    }
    
    int VariableRowCount(GLenum type)
    {
        switch (type)
        {
          case GL_NONE:
            return 0;
          case GL_BOOL:
          case GL_FLOAT:
          case GL_INT:
          case GL_BOOL_VEC2:
          case GL_FLOAT_VEC2:
          case GL_INT_VEC2:
          case GL_INT_VEC3:
          case GL_FLOAT_VEC3:
          case GL_BOOL_VEC3:
          case GL_BOOL_VEC4:
          case GL_FLOAT_VEC4:
          case GL_INT_VEC4:
            return 1;
          case GL_FLOAT_MAT2:
            return 2;
          case GL_FLOAT_MAT3:
            return 3;
          case GL_FLOAT_MAT4:
            return 4;
          default:
            UNREACHABLE();
        }
    
        return 0;
    }
    
    int VariableColumnCount(GLenum type)
    {
        switch (type)
        {
          case GL_NONE:
            return 0;
          case GL_BOOL:
          case GL_FLOAT:
          case GL_INT:
            return 1;
          case GL_BOOL_VEC2:
          case GL_FLOAT_VEC2:
          case GL_INT_VEC2:
          case GL_FLOAT_MAT2:
            return 2;
          case GL_INT_VEC3:
          case GL_FLOAT_VEC3:
          case GL_BOOL_VEC3:
          case GL_FLOAT_MAT3:
            return 3;
          case GL_BOOL_VEC4:
          case GL_FLOAT_VEC4:
          case GL_INT_VEC4:
          case GL_FLOAT_MAT4:
            return 4;
          default:
            UNREACHABLE();
        }
    
        return 0;
    }
    
    int AllocateFirstFreeBits(unsigned int *bits, unsigned int allocationSize, unsigned int bitsSize)
    {
        ASSERT(allocationSize <= bitsSize);
    
        unsigned int mask = std::numeric_limits<unsigned int>::max() >> (std::numeric_limits<unsigned int>::digits - allocationSize);
    
        for (unsigned int i = 0; i < bitsSize - allocationSize + 1; i++)
        {
            if ((*bits & mask) == 0)
            {
                *bits |= mask;
                return i;
            }
    
            mask <<= 1;
        }
    
        return -1;
    }
    
    GLsizei ComputePitch(GLsizei width, GLenum format, GLenum type, GLint alignment)
    {
        ASSERT(alignment > 0 && isPow2(alignment));
    
        GLsizei rawPitch = ComputePixelSize(format, type) * width;
        return (rawPitch + alignment - 1) & ~(alignment - 1);
    }
    
    GLsizei ComputeCompressedPitch(GLsizei width, GLenum format)
    {
        return ComputeCompressedSize(width, 1, format);
    }
    
    GLsizei ComputeCompressedSize(GLsizei width, GLsizei height, GLenum format)
    {
        switch (format)
        {
          case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
          case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
            break;
          default:
            return 0;
        }
    
        return 8 * (GLsizei)ceil((float)width / 4.0f) * (GLsizei)ceil((float)height / 4.0f);
    }
    
    bool IsCompressed(GLenum format)
    {
        if(format == GL_COMPRESSED_RGB_S3TC_DXT1_EXT ||
           format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT)
        {
            return true;
        }
        else
        {
            return false;
        }
    }
    
    // Returns the size, in bytes, of a single texel in an Image
    int ComputePixelSize(GLenum format, GLenum type)
    {
        switch (type)
        {
          case GL_UNSIGNED_BYTE:
            switch (format)
            {
              case GL_ALPHA:           return sizeof(unsigned char);
              case GL_LUMINANCE:       return sizeof(unsigned char);
              case GL_LUMINANCE_ALPHA: return sizeof(unsigned char) * 2;
              case GL_RGB:             return sizeof(unsigned char) * 3;
              case GL_RGBA:            return sizeof(unsigned char) * 4;
              case GL_BGRA_EXT:        return sizeof(unsigned char) * 4;
              default: UNREACHABLE();
            }
            break;
          case GL_UNSIGNED_SHORT_4_4_4_4:
          case GL_UNSIGNED_SHORT_5_5_5_1:
          case GL_UNSIGNED_SHORT_5_6_5:
            return sizeof(unsigned short);
          case GL_FLOAT:
            switch (format)
            {
              case GL_ALPHA:           return sizeof(float);
              case GL_LUMINANCE:       return sizeof(float);
              case GL_LUMINANCE_ALPHA: return sizeof(float) * 2;
              case GL_RGB:             return sizeof(float) * 3;
              case GL_RGBA:            return sizeof(float) * 4;
              default: UNREACHABLE();
            }
            break;
          case GL_HALF_FLOAT_OES:
            switch (format)
            {
              case GL_ALPHA:           return sizeof(unsigned short);
              case GL_LUMINANCE:       return sizeof(unsigned short);
              case GL_LUMINANCE_ALPHA: return sizeof(unsigned short) * 2;
              case GL_RGB:             return sizeof(unsigned short) * 3;
              case GL_RGBA:            return sizeof(unsigned short) * 4;
              default: UNREACHABLE();
            }
            break;
          default: UNREACHABLE();
        }
    
        return 0;
    }
    
    bool IsCubemapTextureTarget(GLenum target)
    {
        return (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z);
    }
    
    bool IsTextureTarget(GLenum target)
    {
        return target == GL_TEXTURE_2D || IsCubemapTextureTarget(target);
    }
    
    // Verify that format/type are one of the combinations from table 3.4.
    bool CheckTextureFormatType(GLenum format, GLenum type)
    {
        switch (type)
        {
          case GL_UNSIGNED_BYTE:
            switch (format)
            {
              case GL_RGBA:
              case GL_BGRA_EXT:
              case GL_RGB:
              case GL_ALPHA:
              case GL_LUMINANCE:
              case GL_LUMINANCE_ALPHA:
                return true;
    
              default:
                return false;
            }
    
          case GL_FLOAT:
          case GL_HALF_FLOAT_OES:
            switch (format)
            {
              case GL_RGBA:
              case GL_RGB:
              case GL_ALPHA:
              case GL_LUMINANCE:
              case GL_LUMINANCE_ALPHA:
                return true;
    
              default:
                return false;
            }
    
          case GL_UNSIGNED_SHORT_4_4_4_4:
          case GL_UNSIGNED_SHORT_5_5_5_1:
            return (format == GL_RGBA);
    
          case GL_UNSIGNED_SHORT_5_6_5:
            return (format == GL_RGB);
    
          default:
            return false;
        }
    }
    
    bool IsColorRenderable(GLenum internalformat)
    {
        switch (internalformat)
        {
          case GL_RGBA4:
          case GL_RGB5_A1:
          case GL_RGB565:
          case GL_RGB8_OES:
          case GL_RGBA8_OES:
            return true;
          case GL_DEPTH_COMPONENT16:
          case GL_STENCIL_INDEX8:
          case GL_DEPTH24_STENCIL8_OES:
            return false;
          default:
            UNIMPLEMENTED();
        }
    
        return false;
    }
    
    bool IsDepthRenderable(GLenum internalformat)
    {
        switch (internalformat)
        {
          case GL_DEPTH_COMPONENT16:
          case GL_DEPTH24_STENCIL8_OES:
            return true;
          case GL_STENCIL_INDEX8:
          case GL_RGBA4:
          case GL_RGB5_A1:
          case GL_RGB565:
          case GL_RGB8_OES:
          case GL_RGBA8_OES:
            return false;
          default:
            UNIMPLEMENTED();
        }
    
        return false;
    }
    
    bool IsStencilRenderable(GLenum internalformat)
    {
        switch (internalformat)
        {
          case GL_STENCIL_INDEX8:
          case GL_DEPTH24_STENCIL8_OES:
            return true;
          case GL_RGBA4:
          case GL_RGB5_A1:
          case GL_RGB565:
          case GL_RGB8_OES:
          case GL_RGBA8_OES:
          case GL_DEPTH_COMPONENT16:
            return false;
          default:
            UNIMPLEMENTED();
        }
    
        return false;
    }
    
    }
    
    namespace es2dx
    {
    
    D3DCMPFUNC ConvertComparison(GLenum comparison)
    {
        D3DCMPFUNC d3dComp = D3DCMP_ALWAYS;
        switch (comparison)
        {
          case GL_NEVER:    d3dComp = D3DCMP_NEVER;        break;
          case GL_ALWAYS:   d3dComp = D3DCMP_ALWAYS;       break;
          case GL_LESS:     d3dComp = D3DCMP_LESS;         break;
          case GL_LEQUAL:   d3dComp = D3DCMP_LESSEQUAL;    break;
          case GL_EQUAL:    d3dComp = D3DCMP_EQUAL;        break;
          case GL_GREATER:  d3dComp = D3DCMP_GREATER;      break;
          case GL_GEQUAL:   d3dComp = D3DCMP_GREATEREQUAL; break;
          case GL_NOTEQUAL: d3dComp = D3DCMP_NOTEQUAL;     break;
          default: UNREACHABLE();
        }
    
        return d3dComp;
    }
    
    D3DCOLOR ConvertColor(gl::Color color)
    {
        return D3DCOLOR_RGBA(gl::unorm<8>(color.red),
                             gl::unorm<8>(color.green),
                             gl::unorm<8>(color.blue),
                             gl::unorm<8>(color.alpha));
    }
    
    D3DBLEND ConvertBlendFunc(GLenum blend)
    {
        D3DBLEND d3dBlend = D3DBLEND_ZERO;
    
        switch (blend)
        {
          case GL_ZERO:                     d3dBlend = D3DBLEND_ZERO;           break;
          case GL_ONE:                      d3dBlend = D3DBLEND_ONE;            break;
          case GL_SRC_COLOR:                d3dBlend = D3DBLEND_SRCCOLOR;       break;
          case GL_ONE_MINUS_SRC_COLOR:      d3dBlend = D3DBLEND_INVSRCCOLOR;    break;
          case GL_DST_COLOR:                d3dBlend = D3DBLEND_DESTCOLOR;      break;
          case GL_ONE_MINUS_DST_COLOR:      d3dBlend = D3DBLEND_INVDESTCOLOR;   break;
          case GL_SRC_ALPHA:                d3dBlend = D3DBLEND_SRCALPHA;       break;
          case GL_ONE_MINUS_SRC_ALPHA:      d3dBlend = D3DBLEND_INVSRCALPHA;    break;
          case GL_DST_ALPHA:                d3dBlend = D3DBLEND_DESTALPHA;      break;
          case GL_ONE_MINUS_DST_ALPHA:      d3dBlend = D3DBLEND_INVDESTALPHA;   break;
          case GL_CONSTANT_COLOR:           d3dBlend = D3DBLEND_BLENDFACTOR;    break;
          case GL_ONE_MINUS_CONSTANT_COLOR: d3dBlend = D3DBLEND_INVBLENDFACTOR; break;
          case GL_CONSTANT_ALPHA:           d3dBlend = D3DBLEND_BLENDFACTOR;    break;
          case GL_ONE_MINUS_CONSTANT_ALPHA: d3dBlend = D3DBLEND_INVBLENDFACTOR; break;
          case GL_SRC_ALPHA_SATURATE:       d3dBlend = D3DBLEND_SRCALPHASAT;    break;
          default: UNREACHABLE();
        }
    
        return d3dBlend;
    }
    
    D3DBLENDOP ConvertBlendOp(GLenum blendOp)
    {
        D3DBLENDOP d3dBlendOp = D3DBLENDOP_ADD;
    
        switch (blendOp)
        {
          case GL_FUNC_ADD:              d3dBlendOp = D3DBLENDOP_ADD;         break;
          case GL_FUNC_SUBTRACT:         d3dBlendOp = D3DBLENDOP_SUBTRACT;    break;
          case GL_FUNC_REVERSE_SUBTRACT: d3dBlendOp = D3DBLENDOP_REVSUBTRACT; break;
          default: UNREACHABLE();
        }
    
        return d3dBlendOp;
    }
    
    D3DSTENCILOP ConvertStencilOp(GLenum stencilOp)
    {
        D3DSTENCILOP d3dStencilOp = D3DSTENCILOP_KEEP;
    
        switch (stencilOp)
        {
          case GL_ZERO:      d3dStencilOp = D3DSTENCILOP_ZERO;    break;
          case GL_KEEP:      d3dStencilOp = D3DSTENCILOP_KEEP;    break;
          case GL_REPLACE:   d3dStencilOp = D3DSTENCILOP_REPLACE; break;
          case GL_INCR:      d3dStencilOp = D3DSTENCILOP_INCRSAT; break;
          case GL_DECR:      d3dStencilOp = D3DSTENCILOP_DECRSAT; break;
          case GL_INVERT:    d3dStencilOp = D3DSTENCILOP_INVERT;  break;
          case GL_INCR_WRAP: d3dStencilOp = D3DSTENCILOP_INCR;    break;
          case GL_DECR_WRAP: d3dStencilOp = D3DSTENCILOP_DECR;    break;
          default: UNREACHABLE();
        }
    
        return d3dStencilOp;
    }
    
    D3DTEXTUREADDRESS ConvertTextureWrap(GLenum wrap)
    {
        D3DTEXTUREADDRESS d3dWrap = D3DTADDRESS_WRAP;
    
        switch (wrap)
        {
          case GL_REPEAT:            d3dWrap = D3DTADDRESS_WRAP;   break;
          case GL_CLAMP_TO_EDGE:     d3dWrap = D3DTADDRESS_CLAMP;  break;
          case GL_MIRRORED_REPEAT:   d3dWrap = D3DTADDRESS_MIRROR; break;
          default: UNREACHABLE();
        }
    
        return d3dWrap;
    }
    
    D3DCULL ConvertCullMode(GLenum cullFace, GLenum frontFace)
    {
        D3DCULL cull = D3DCULL_CCW;
        switch (cullFace)
        {
          case GL_FRONT:
            cull = (frontFace == GL_CCW ? D3DCULL_CW : D3DCULL_CCW);
            break;
          case GL_BACK:
            cull = (frontFace == GL_CCW ? D3DCULL_CCW : D3DCULL_CW);
            break;
          case GL_FRONT_AND_BACK:
            cull = D3DCULL_NONE; // culling will be handled during draw
            break;
          default: UNREACHABLE();
        }
    
        return cull;
    }
    
    D3DCUBEMAP_FACES ConvertCubeFace(GLenum cubeFace)
    {
        D3DCUBEMAP_FACES face = D3DCUBEMAP_FACE_POSITIVE_X;
    
        // Map a cube map texture target to the corresponding  D3D surface index. Note that the
        // Y faces are swapped because the Y coordinate to the texture lookup intrinsic functions
        // are negated in the pixel shader.
        switch (cubeFace)
        {
          case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
            face = D3DCUBEMAP_FACE_POSITIVE_X;
            break;
          case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
            face = D3DCUBEMAP_FACE_NEGATIVE_X;
            break;
          case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
            face = D3DCUBEMAP_FACE_NEGATIVE_Y;
            break;
          case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
            face = D3DCUBEMAP_FACE_POSITIVE_Y;
            break;
          case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
            face = D3DCUBEMAP_FACE_POSITIVE_Z;
            break;
          case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
            face = D3DCUBEMAP_FACE_NEGATIVE_Z;
            break;
          default: UNREACHABLE();
        }
    
        return face;
    }
    
    DWORD ConvertColorMask(bool red, bool green, bool blue, bool alpha)
    {
        return (red   ? D3DCOLORWRITEENABLE_RED   : 0) |
               (green ? D3DCOLORWRITEENABLE_GREEN : 0) |
               (blue  ? D3DCOLORWRITEENABLE_BLUE  : 0) |
               (alpha ? D3DCOLORWRITEENABLE_ALPHA : 0);
    }
    
    D3DTEXTUREFILTERTYPE ConvertMagFilter(GLenum magFilter)
    {
        D3DTEXTUREFILTERTYPE d3dMagFilter = D3DTEXF_POINT;
        switch (magFilter)
        {
          case GL_NEAREST: d3dMagFilter = D3DTEXF_POINT;  break;
          case GL_LINEAR:  d3dMagFilter = D3DTEXF_LINEAR; break;
          default: UNREACHABLE();
        }
    
        return d3dMagFilter;
    }
    
    void ConvertMinFilter(GLenum minFilter, D3DTEXTUREFILTERTYPE *d3dMinFilter, D3DTEXTUREFILTERTYPE *d3dMipFilter)
    {
        switch (minFilter)
        {
          case GL_NEAREST:
            *d3dMinFilter = D3DTEXF_POINT;
            *d3dMipFilter = D3DTEXF_NONE;
            break;
          case GL_LINEAR:
            *d3dMinFilter = D3DTEXF_LINEAR;
            *d3dMipFilter = D3DTEXF_NONE;
            break;
          case GL_NEAREST_MIPMAP_NEAREST:
            *d3dMinFilter = D3DTEXF_POINT;
            *d3dMipFilter = D3DTEXF_POINT;
            break;
          case GL_LINEAR_MIPMAP_NEAREST:
            *d3dMinFilter = D3DTEXF_LINEAR;
            *d3dMipFilter = D3DTEXF_POINT;
            break;
          case GL_NEAREST_MIPMAP_LINEAR:
            *d3dMinFilter = D3DTEXF_POINT;
            *d3dMipFilter = D3DTEXF_LINEAR;
            break;
          case GL_LINEAR_MIPMAP_LINEAR:
            *d3dMinFilter = D3DTEXF_LINEAR;
            *d3dMipFilter = D3DTEXF_LINEAR;
            break;
          default:
            *d3dMinFilter = D3DTEXF_POINT;
            *d3dMipFilter = D3DTEXF_NONE;
            UNREACHABLE();
        }
    }
    
    bool ConvertPrimitiveType(GLenum primitiveType, GLsizei elementCount,
                              D3DPRIMITIVETYPE *d3dPrimitiveType, int *d3dPrimitiveCount)
    {
        switch (primitiveType)
        {
          case GL_POINTS:
            *d3dPrimitiveType = D3DPT_POINTLIST;
            *d3dPrimitiveCount = elementCount;
            break;
          case GL_LINES:
            *d3dPrimitiveType = D3DPT_LINELIST;
            *d3dPrimitiveCount = elementCount / 2;
            break;
          case GL_LINE_LOOP:
            *d3dPrimitiveType = D3DPT_LINESTRIP;
            *d3dPrimitiveCount = elementCount - 1;   // D3D doesn't support line loops, so we draw the last line separately
            break;
          case GL_LINE_STRIP:
            *d3dPrimitiveType = D3DPT_LINESTRIP;
            *d3dPrimitiveCount = elementCount - 1;
            break;
          case GL_TRIANGLES:
            *d3dPrimitiveType = D3DPT_TRIANGLELIST;
            *d3dPrimitiveCount = elementCount / 3;
            break;
          case GL_TRIANGLE_STRIP:
            *d3dPrimitiveType = D3DPT_TRIANGLESTRIP;
            *d3dPrimitiveCount = elementCount - 2;
            break;
          case GL_TRIANGLE_FAN:
            *d3dPrimitiveType = D3DPT_TRIANGLEFAN;
            *d3dPrimitiveCount = elementCount - 2;
            break;
          default:
            return false;
        }
    
        return true;
    }
    
    D3DFORMAT ConvertRenderbufferFormat(GLenum format)
    {
        switch (format)
        {
          case GL_RGBA4:
          case GL_RGB5_A1:
          case GL_RGBA8_OES:            return D3DFMT_A8R8G8B8;
          case GL_RGB565:               return D3DFMT_R5G6B5;
          case GL_RGB8_OES:             return D3DFMT_X8R8G8B8;
          case GL_DEPTH_COMPONENT16:
          case GL_STENCIL_INDEX8:       
          case GL_DEPTH24_STENCIL8_OES: return D3DFMT_D24S8;
          default: UNREACHABLE();       return D3DFMT_A8R8G8B8;
        }
    }
    
    D3DMULTISAMPLE_TYPE GetMultisampleTypeFromSamples(GLsizei samples)
    {
        if (samples <= 1)
            return D3DMULTISAMPLE_NONE;
        else
            return (D3DMULTISAMPLE_TYPE)samples;
    }
    
    }
    
    namespace dx2es
    {
    
    unsigned int GetStencilSize(D3DFORMAT stencilFormat)
    {
        switch(stencilFormat)
        {
          case D3DFMT_D24FS8:
          case D3DFMT_D24S8:
            return 8;
          case D3DFMT_D24X4S4:
            return 4;
          case D3DFMT_D15S1:
            return 1;
          case D3DFMT_D16_LOCKABLE:
          case D3DFMT_D32:
          case D3DFMT_D24X8:
          case D3DFMT_D32F_LOCKABLE:
          case D3DFMT_D16:
            return 0;
        //case D3DFMT_D32_LOCKABLE:  return 0;   // DirectX 9Ex only
        //case D3DFMT_S8_LOCKABLE:   return 8;   // DirectX 9Ex only
          default:
            return 0;
        }
    }
    
    unsigned int GetAlphaSize(D3DFORMAT colorFormat)
    {
        switch (colorFormat)
        {
          case D3DFMT_A16B16G16R16F:
            return 16;
          case D3DFMT_A32B32G32R32F:
            return 32;
          case D3DFMT_A2R10G10B10:
            return 2;
          case D3DFMT_A8R8G8B8:
            return 8;
          case D3DFMT_A1R5G5B5:
            return 1;
          case D3DFMT_X8R8G8B8:
          case D3DFMT_R5G6B5:
            return 0;
          default:
            return 0;
        }
    }
    
    unsigned int GetRedSize(D3DFORMAT colorFormat)
    {
        switch (colorFormat)
        {
          case D3DFMT_A16B16G16R16F:
            return 16;
          case D3DFMT_A32B32G32R32F:
            return 32;
          case D3DFMT_A2R10G10B10:
            return 10;
          case D3DFMT_A8R8G8B8:
          case D3DFMT_X8R8G8B8:
            return 8;
          case D3DFMT_A1R5G5B5:
          case D3DFMT_R5G6B5:
            return 5;
          default:
            return 0;
        }
    }
    
    unsigned int GetGreenSize(D3DFORMAT colorFormat)
    {
        switch (colorFormat)
        {
          case D3DFMT_A16B16G16R16F:
            return 16;
          case D3DFMT_A32B32G32R32F:
            return 32;
          case D3DFMT_A2R10G10B10:
            return 10;
          case D3DFMT_A8R8G8B8:
          case D3DFMT_X8R8G8B8:
            return 8;
          case D3DFMT_A1R5G5B5:
            return 5;
          case D3DFMT_R5G6B5:
            return 6;
          default:
            return 0;
        }
    }
    
    unsigned int GetBlueSize(D3DFORMAT colorFormat)
    {
        switch (colorFormat)
        {
          case D3DFMT_A16B16G16R16F:
            return 16;
          case D3DFMT_A32B32G32R32F:
            return 32;
          case D3DFMT_A2R10G10B10:
            return 10;
          case D3DFMT_A8R8G8B8:
          case D3DFMT_X8R8G8B8:
            return 8;
          case D3DFMT_A1R5G5B5:
          case D3DFMT_R5G6B5:
            return 5;
          default:
            return 0;
        }
    }
    
    unsigned int GetDepthSize(D3DFORMAT depthFormat)
    {
        switch (depthFormat)
        {
          case D3DFMT_D16_LOCKABLE:  return 16;
          case D3DFMT_D32:           return 32;
          case D3DFMT_D15S1:         return 15;
          case D3DFMT_D24S8:         return 24;
          case D3DFMT_D24X8:         return 24;
          case D3DFMT_D24X4S4:       return 24;
          case D3DFMT_D16:           return 16;
          case D3DFMT_D32F_LOCKABLE: return 32;
          case D3DFMT_D24FS8:        return 24;
        //case D3DFMT_D32_LOCKABLE:  return 32;   // D3D9Ex only
        //case D3DFMT_S8_LOCKABLE:   return 0;    // D3D9Ex only
          default:                   return 0;
        }
    }
    
    GLsizei GetSamplesFromMultisampleType(D3DMULTISAMPLE_TYPE type)
    {
        if (type == D3DMULTISAMPLE_NONMASKABLE)
            return 0;
        else
            return type;
    }
    
    GLenum ConvertBackBufferFormat(D3DFORMAT format)
    {
        switch (format)
        {
          case D3DFMT_A4R4G4B4: return GL_RGBA4;
          case D3DFMT_A8R8G8B8: return GL_RGBA8_OES;
          case D3DFMT_A1R5G5B5: return GL_RGB5_A1;
          case D3DFMT_R5G6B5:   return GL_RGB565;
          case D3DFMT_X8R8G8B8: return GL_RGB8_OES;
          default:
            UNREACHABLE();
        }
    
        return GL_RGBA4;
    }
    
    GLenum ConvertDepthStencilFormat(D3DFORMAT format)
    {
        switch (format)
        {
          case D3DFMT_D16:
          case D3DFMT_D24X8:
            return GL_DEPTH_COMPONENT16;
          case D3DFMT_D24S8:
            return GL_DEPTH24_STENCIL8_OES;
          default:
            UNREACHABLE();
        }
    
        return GL_DEPTH24_STENCIL8_OES;
    }
    
    }
    
    std::string getTempPath()
    {
        char path[MAX_PATH];
        DWORD pathLen = GetTempPathA(sizeof(path) / sizeof(path[0]), path);
        if (pathLen == 0)
        {
            UNREACHABLE();
            return std::string();
        }
    
        UINT unique = GetTempFileNameA(path, "sh", 0, path);
        if (unique == 0)
        {
            UNREACHABLE();
            return std::string();
        }
        
        return path;
    }
    
    void writeFile(const char* path, const void* content, size_t size)
    {
        FILE* file = fopen(path, "w");
        if (!file)
        {
            UNREACHABLE();
            return;
        }
    
        fwrite(content, sizeof(char), size, file);
        fclose(file);
    }