Branch :
#include "precompiled.h"
//
// Copyright (c) 2002-2013 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 "libGLESv2/mathutil.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:
case GL_UNSIGNED_INT:
return 1;
case GL_BOOL_VEC2:
case GL_FLOAT_VEC2:
case GL_INT_VEC2:
case GL_UNSIGNED_INT_VEC2:
return 2;
case GL_INT_VEC3:
case GL_FLOAT_VEC3:
case GL_BOOL_VEC3:
case GL_UNSIGNED_INT_VEC3:
return 3;
case GL_BOOL_VEC4:
case GL_FLOAT_VEC4:
case GL_INT_VEC4:
case GL_UNSIGNED_INT_VEC4:
case GL_FLOAT_MAT2:
return 4;
case GL_FLOAT_MAT2x3:
case GL_FLOAT_MAT3x2:
return 6;
case GL_FLOAT_MAT2x4:
case GL_FLOAT_MAT4x2:
return 8;
case GL_FLOAT_MAT3:
return 9;
case GL_FLOAT_MAT3x4:
case GL_FLOAT_MAT4x3:
return 12;
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:
case GL_FLOAT_MAT2x3:
case GL_FLOAT_MAT3x2:
case GL_FLOAT_MAT2x4:
case GL_FLOAT_MAT4x2:
case GL_FLOAT_MAT3x4:
case GL_FLOAT_MAT4x3:
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;
case GL_UNSIGNED_INT:
case GL_UNSIGNED_INT_VEC2:
case GL_UNSIGNED_INT_VEC3:
case GL_UNSIGNED_INT_VEC4:
return GL_UNSIGNED_INT;
default:
UNREACHABLE();
}
return GL_NONE;
}
size_t UniformComponentSize(GLenum type)
{
switch(type)
{
case GL_BOOL: return sizeof(GLint);
case GL_FLOAT: return sizeof(GLfloat);
case GL_INT: return sizeof(GLint);
case GL_UNSIGNED_INT: return sizeof(GLuint);
default: UNREACHABLE();
}
return 0;
}
size_t UniformInternalSize(GLenum type)
{
// Expanded to 4-element vectors
return UniformComponentSize(UniformComponentType(type)) * VariableRowCount(type) * 4;
}
size_t UniformExternalSize(GLenum type)
{
return UniformComponentSize(UniformComponentType(type)) * UniformComponentCount(type);
}
GLenum UniformBoolVectorType(GLenum type)
{
switch (type)
{
case GL_FLOAT:
case GL_INT:
case GL_UNSIGNED_INT:
return GL_BOOL;
case GL_FLOAT_VEC2:
case GL_INT_VEC2:
case GL_UNSIGNED_INT_VEC2:
return GL_BOOL_VEC2;
case GL_FLOAT_VEC3:
case GL_INT_VEC3:
case GL_UNSIGNED_INT_VEC3:
return GL_BOOL_VEC3;
case GL_FLOAT_VEC4:
case GL_INT_VEC4:
case GL_UNSIGNED_INT_VEC4:
return GL_BOOL_VEC4;
default:
UNREACHABLE();
return GL_NONE;
}
}
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:
case GL_SAMPLER_2D:
case GL_SAMPLER_CUBE:
return 1;
case GL_FLOAT_MAT2:
case GL_FLOAT_MAT3x2:
case GL_FLOAT_MAT4x2:
return 2;
case GL_FLOAT_MAT3:
case GL_FLOAT_MAT2x3:
case GL_FLOAT_MAT4x3:
return 3;
case GL_FLOAT_MAT4:
case GL_FLOAT_MAT2x4:
case GL_FLOAT_MAT3x4:
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:
case GL_SAMPLER_2D:
case GL_SAMPLER_CUBE:
return 1;
case GL_BOOL_VEC2:
case GL_FLOAT_VEC2:
case GL_INT_VEC2:
case GL_FLOAT_MAT2:
case GL_FLOAT_MAT2x3:
case GL_FLOAT_MAT2x4:
return 2;
case GL_INT_VEC3:
case GL_FLOAT_VEC3:
case GL_BOOL_VEC3:
case GL_FLOAT_MAT3:
case GL_FLOAT_MAT3x2:
case GL_FLOAT_MAT3x4:
return 3;
case GL_BOOL_VEC4:
case GL_FLOAT_VEC4:
case GL_INT_VEC4:
case GL_FLOAT_MAT4:
case GL_FLOAT_MAT4x2:
case GL_FLOAT_MAT4x3:
return 4;
default:
UNREACHABLE();
}
return 0;
}
bool IsMatrixType(GLenum type)
{
return VariableRowCount(type) > 1;
}
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 ComputeRowPitch(GLsizei width, GLint internalformat, GLint alignment)
{
ASSERT(alignment > 0 && isPow2(alignment));
GLsizei rawPitch = ComputePixelSize(internalformat) * width;
return (rawPitch + alignment - 1) & ~(alignment - 1);
}
GLsizei ComputeDepthPitch(GLsizei width, GLsizei height, GLint internalformat, GLint alignment)
{
return ComputeRowPitch(width, internalformat, alignment) * height;
}
GLsizei ComputeCompressedRowPitch(GLsizei width, GLenum internalformat)
{
return ComputeCompressedSize(width, 1, internalformat);
}
GLsizei ComputeCompressedDepthPitch(GLsizei width, GLsizei height, GLenum internalformat)
{
return ComputeCompressedSize(width, height, internalformat);
}
GLsizei ComputeCompressedSize(GLsizei width, GLsizei height, GLenum internalformat)
{
switch (internalformat)
{
case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
return 8 * ((width + 3) / 4) * ((height + 3) / 4);
case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
return 16 * ((width + 3) / 4) * ((height + 3) / 4);
default:
return 0;
}
}
bool IsCompressed(GLenum format)
{
if(format == GL_COMPRESSED_RGB_S3TC_DXT1_EXT ||
format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT ||
format == GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE ||
format == GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE)
{
return true;
}
else
{
return false;
}
}
bool IsDepthTexture(GLenum format)
{
if (format == GL_DEPTH_COMPONENT ||
format == GL_DEPTH_STENCIL_OES ||
format == GL_DEPTH_COMPONENT16 ||
format == GL_DEPTH_COMPONENT32_OES ||
format == GL_DEPTH24_STENCIL8_OES)
{
return true;
}
return false;
}
bool IsStencilTexture(GLenum format)
{
if (format == GL_DEPTH_STENCIL_OES ||
format == GL_DEPTH24_STENCIL8_OES)
{
return true;
}
return false;
}
void MakeValidSize(bool isImage, bool isCompressed, GLsizei *requestWidth, GLsizei *requestHeight, int *levelOffset)
{
int upsampleCount = 0;
if (isCompressed)
{
// Don't expand the size of full textures that are at least 4x4
// already.
if (isImage || *requestWidth < 4 || *requestHeight < 4)
{
while (*requestWidth % 4 != 0 || *requestHeight % 4 != 0)
{
*requestWidth <<= 1;
*requestHeight <<= 1;
upsampleCount++;
}
}
}
*levelOffset = upsampleCount;
}
// Returns the size, in bytes, of a single texel in an Image
int ComputePixelSize(GLint internalformat)
{
switch (internalformat)
{
case GL_ALPHA8_EXT: return sizeof(unsigned char);
case GL_LUMINANCE8_EXT: return sizeof(unsigned char);
case GL_ALPHA32F_EXT: return sizeof(float);
case GL_LUMINANCE32F_EXT: return sizeof(float);
case GL_ALPHA16F_EXT: return sizeof(unsigned short);
case GL_LUMINANCE16F_EXT: return sizeof(unsigned short);
case GL_LUMINANCE8_ALPHA8_EXT: return sizeof(unsigned char) * 2;
case GL_LUMINANCE_ALPHA32F_EXT: return sizeof(float) * 2;
case GL_LUMINANCE_ALPHA16F_EXT: return sizeof(unsigned short) * 2;
case GL_RGB8_OES: return sizeof(unsigned char) * 3;
case GL_RGB565: return sizeof(unsigned short);
case GL_RGB32F_EXT: return sizeof(float) * 3;
case GL_RGB16F_EXT: return sizeof(unsigned short) * 3;
case GL_RGBA8_OES: return sizeof(unsigned char) * 4;
case GL_RGBA4: return sizeof(unsigned short);
case GL_RGB5_A1: return sizeof(unsigned short);
case GL_RGBA32F_EXT: return sizeof(float) * 4;
case GL_RGBA16F_EXT: return sizeof(unsigned short) * 4;
case GL_BGRA8_EXT: return sizeof(unsigned char) * 4;
case GL_SRGB8_ALPHA8: return sizeof(unsigned char) * 4;
case GL_RGB10_A2: return sizeof(unsigned char) * 4;
case GL_RG8: return sizeof(unsigned char) * 2;
case GL_R8: return sizeof(unsigned char);
case GL_BGRA4_ANGLEX: return sizeof(unsigned short);
case GL_BGR5_A1_ANGLEX: return sizeof(unsigned short);
default:
UNIMPLEMENTED(); // TODO: Remaining ES3 formats
UNREACHABLE();
}
return 0;
}
bool IsCubemapTextureTarget(GLenum target)
{
return (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z);
}
bool IsInternalTextureTarget(GLenum target)
{
return target == GL_TEXTURE_2D || IsCubemapTextureTarget(target);
}
GLint ConvertSizedInternalFormat(GLenum format, GLenum type)
{
switch (format)
{
case GL_ALPHA:
switch (type)
{
case GL_UNSIGNED_BYTE: return GL_ALPHA8_EXT;
case GL_FLOAT: return GL_ALPHA32F_EXT;
case GL_HALF_FLOAT_OES: return GL_ALPHA16F_EXT;
default: UNIMPLEMENTED();
}
break;
case GL_LUMINANCE:
switch (type)
{
case GL_UNSIGNED_BYTE: return GL_LUMINANCE8_EXT;
case GL_FLOAT: return GL_LUMINANCE32F_EXT;
case GL_HALF_FLOAT_OES: return GL_LUMINANCE16F_EXT;
default: UNIMPLEMENTED();
}
break;
case GL_LUMINANCE_ALPHA:
switch (type)
{
case GL_UNSIGNED_BYTE: return GL_LUMINANCE8_ALPHA8_EXT;
case GL_FLOAT: return GL_LUMINANCE_ALPHA32F_EXT;
case GL_HALF_FLOAT_OES: return GL_LUMINANCE_ALPHA16F_EXT;
default: UNIMPLEMENTED();
}
break;
case GL_RGB:
switch (type)
{
case GL_UNSIGNED_BYTE: return GL_RGB8_OES;
case GL_UNSIGNED_SHORT_5_6_5: return GL_RGB565;
case GL_FLOAT: return GL_RGB32F_EXT;
case GL_HALF_FLOAT_OES: return GL_RGB16F_EXT;
default: UNIMPLEMENTED();
}
break;
case GL_RGBA:
switch (type)
{
case GL_UNSIGNED_BYTE: return GL_RGBA8_OES;
case GL_UNSIGNED_SHORT_4_4_4_4: return GL_RGBA4;
case GL_UNSIGNED_SHORT_5_5_5_1: return GL_RGB5_A1;
case GL_FLOAT: return GL_RGBA32F_EXT;
case GL_HALF_FLOAT_OES: return GL_RGBA16F_EXT;
break;
default: UNIMPLEMENTED();
}
break;
case GL_BGRA_EXT:
switch (type)
{
case GL_UNSIGNED_BYTE: return GL_BGRA8_EXT;
case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT: return GL_BGRA4_ANGLEX;
case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT: return GL_BGR5_A1_ANGLEX;
default: UNIMPLEMENTED();
}
break;
case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
return format;
case GL_DEPTH_COMPONENT:
switch (type)
{
case GL_UNSIGNED_SHORT: return GL_DEPTH_COMPONENT16;
case GL_UNSIGNED_INT: return GL_DEPTH_COMPONENT32_OES;
default: UNIMPLEMENTED();
}
break;
case GL_DEPTH_STENCIL_OES:
switch (type)
{
case GL_UNSIGNED_INT_24_8_OES: return GL_DEPTH24_STENCIL8_OES;
default: UNIMPLEMENTED();
}
break;
default:
UNIMPLEMENTED();
}
return GL_NONE;
}
GLenum ExtractFormat(GLenum internalformat)
{
switch (internalformat)
{
case GL_RGB565: return GL_RGB;
case GL_RGBA4: return GL_RGBA;
case GL_RGB5_A1: return GL_RGBA;
case GL_RGB8_OES: return GL_RGB;
case GL_RGBA8_OES: return GL_RGBA;
case GL_LUMINANCE8_ALPHA8_EXT: return GL_LUMINANCE_ALPHA;
case GL_LUMINANCE8_EXT: return GL_LUMINANCE;
case GL_ALPHA8_EXT: return GL_ALPHA;
case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: return GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: return GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: return GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE;
case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: return GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE;
case GL_RGBA32F_EXT: return GL_RGBA;
case GL_RGB32F_EXT: return GL_RGB;
case GL_ALPHA32F_EXT: return GL_ALPHA;
case GL_LUMINANCE32F_EXT: return GL_LUMINANCE;
case GL_LUMINANCE_ALPHA32F_EXT: return GL_LUMINANCE_ALPHA;
case GL_RGBA16F_EXT: return GL_RGBA;
case GL_RGB16F_EXT: return GL_RGB;
case GL_ALPHA16F_EXT: return GL_ALPHA;
case GL_LUMINANCE16F_EXT: return GL_LUMINANCE;
case GL_LUMINANCE_ALPHA16F_EXT: return GL_LUMINANCE_ALPHA;
case GL_BGRA8_EXT: return GL_BGRA_EXT;
case GL_DEPTH_COMPONENT16: return GL_DEPTH_COMPONENT;
case GL_DEPTH_COMPONENT32_OES: return GL_DEPTH_COMPONENT;
case GL_DEPTH24_STENCIL8_OES: return GL_DEPTH_STENCIL_OES;
default: return GL_NONE; // Unsupported
}
}
GLenum ExtractType(GLenum internalformat)
{
switch (internalformat)
{
case GL_RGB565: return GL_UNSIGNED_SHORT_5_6_5;
case GL_RGBA4: return GL_UNSIGNED_SHORT_4_4_4_4;
case GL_RGB5_A1: return GL_UNSIGNED_SHORT_5_5_5_1;
case GL_RGB8_OES: return GL_UNSIGNED_BYTE;
case GL_RGBA8_OES: return GL_UNSIGNED_BYTE;
case GL_LUMINANCE8_ALPHA8_EXT: return GL_UNSIGNED_BYTE;
case GL_LUMINANCE8_EXT: return GL_UNSIGNED_BYTE;
case GL_ALPHA8_EXT: return GL_UNSIGNED_BYTE;
case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: return GL_UNSIGNED_BYTE;
case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: return GL_UNSIGNED_BYTE;
case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: return GL_UNSIGNED_BYTE;
case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: return GL_UNSIGNED_BYTE;
case GL_RGBA32F_EXT: return GL_FLOAT;
case GL_RGB32F_EXT: return GL_FLOAT;
case GL_ALPHA32F_EXT: return GL_FLOAT;
case GL_LUMINANCE32F_EXT: return GL_FLOAT;
case GL_LUMINANCE_ALPHA32F_EXT: return GL_FLOAT;
case GL_RGBA16F_EXT: return GL_HALF_FLOAT_OES;
case GL_RGB16F_EXT: return GL_HALF_FLOAT_OES;
case GL_ALPHA16F_EXT: return GL_HALF_FLOAT_OES;
case GL_LUMINANCE16F_EXT: return GL_HALF_FLOAT_OES;
case GL_LUMINANCE_ALPHA16F_EXT: return GL_HALF_FLOAT_OES;
case GL_BGRA8_EXT: return GL_UNSIGNED_BYTE;
case GL_DEPTH_COMPONENT16: return GL_UNSIGNED_SHORT;
case GL_DEPTH_COMPONENT32_OES: return GL_UNSIGNED_INT;
case GL_DEPTH24_STENCIL8_OES: return GL_UNSIGNED_INT_24_8_OES;
default: return GL_NONE; // Unsupported
}
}
bool IsColorRenderable(GLenum internalformat)
{
switch (internalformat)
{
case GL_RGBA4:
case GL_RGB5_A1:
case GL_RGB565:
case GL_RGB8_OES:
case GL_RGBA8_OES:
case GL_BGRA8_EXT:
case GL_SRGB8_ALPHA8:
case GL_RGB10_A2:
case GL_RG8:
case GL_R8:
return true;
case GL_DEPTH_COMPONENT16:
case GL_STENCIL_INDEX8:
case GL_DEPTH24_STENCIL8_OES:
return false;
default:
UNIMPLEMENTED(); // TODO: Remaining ES3 formats
UNREACHABLE();
}
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;
}
bool IsFloat32Format(GLint internalformat)
{
switch (internalformat)
{
case GL_RGBA32F_EXT:
case GL_RGB32F_EXT:
case GL_ALPHA32F_EXT:
case GL_LUMINANCE32F_EXT:
case GL_LUMINANCE_ALPHA32F_EXT:
return true;
default:
return false;
}
}
bool IsFloat16Format(GLint internalformat)
{
switch (internalformat)
{
case GL_RGBA16F_EXT:
case GL_RGB16F_EXT:
case GL_ALPHA16F_EXT:
case GL_LUMINANCE16F_EXT:
case GL_LUMINANCE_ALPHA16F_EXT:
return true;
default:
return false;
}
}
unsigned int GetAlphaSize(GLenum colorFormat)
{
switch (colorFormat)
{
case GL_RGBA16F_EXT:
return 16;
case GL_RGBA32F_EXT:
return 32;
case GL_RGBA4:
return 4;
case GL_RGBA8_OES:
case GL_BGRA8_EXT:
return 8;
case GL_RGB5_A1:
return 1;
case GL_RGB8_OES:
case GL_RGB565:
case GL_RGB32F_EXT:
case GL_RGB16F_EXT:
return 0;
default:
return 0;
}
}
unsigned int GetRedSize(GLenum colorFormat)
{
switch (colorFormat)
{
case GL_RGBA16F_EXT:
case GL_RGB16F_EXT:
return 16;
case GL_RGBA32F_EXT:
case GL_RGB32F_EXT:
return 32;
case GL_RGBA4:
return 4;
case GL_RGBA8_OES:
case GL_BGRA8_EXT:
case GL_RGB8_OES:
return 8;
case GL_RGB5_A1:
case GL_RGB565:
return 5;
default:
return 0;
}
}
unsigned int GetGreenSize(GLenum colorFormat)
{
switch (colorFormat)
{
case GL_RGBA16F_EXT:
case GL_RGB16F_EXT:
return 16;
case GL_RGBA32F_EXT:
case GL_RGB32F_EXT:
return 32;
case GL_RGBA4:
return 4;
case GL_RGBA8_OES:
case GL_BGRA8_EXT:
case GL_RGB8_OES:
return 8;
case GL_RGB5_A1:
return 5;
case GL_RGB565:
return 6;
default:
return 0;
}
}
unsigned int GetBlueSize(GLenum colorFormat)
{
switch (colorFormat)
{
case GL_RGBA16F_EXT:
case GL_RGB16F_EXT:
return 16;
case GL_RGBA32F_EXT:
case GL_RGB32F_EXT:
return 32;
case GL_RGBA4:
return 4;
case GL_RGBA8_OES:
case GL_BGRA8_EXT:
case GL_RGB8_OES:
return 8;
case GL_RGB5_A1:
case GL_RGB565:
return 5;
default:
return 0;
}
}
unsigned int GetDepthSize(GLenum depthFormat)
{
switch (depthFormat)
{
case GL_DEPTH_COMPONENT16: return 16;
case GL_DEPTH_COMPONENT32_OES: return 32;
case GL_DEPTH24_STENCIL8_OES: return 24;
default: return 0;
}
}
unsigned int GetStencilSize(GLenum stencilFormat)
{
switch (stencilFormat)
{
case GL_DEPTH24_STENCIL8_OES: return 8;
default: return 0;
}
}
bool IsTriangleMode(GLenum drawMode)
{
switch (drawMode)
{
case GL_TRIANGLES:
case GL_TRIANGLE_FAN:
case GL_TRIANGLE_STRIP:
return true;
case GL_POINTS:
case GL_LINES:
case GL_LINE_LOOP:
case GL_LINE_STRIP:
return false;
default: UNREACHABLE();
}
return false;
}
struct FormatInfo
{
GLenum mFormat;
GLenum mType;
GLint mInternalformat;
FormatInfo(GLenum format, GLenum type, GLint internalformat)
: mFormat(format), mType(type), mInternalformat(internalformat) { }
bool operator<(const FormatInfo& other) const
{
return memcmp(this, &other, sizeof(FormatInfo)) < 0;
}
};
typedef std::set<FormatInfo> formatInfoSet;
static formatInfoSet buildValidES3FormatCombinationSet()
{
formatInfoSet set;
// From ES 3.0.1 spec, table 3.2
set.insert(FormatInfo(GL_RGBA, GL_UNSIGNED_BYTE, GL_RGBA8 ));
set.insert(FormatInfo(GL_RGBA, GL_UNSIGNED_BYTE, GL_RGB5_A1 ));
set.insert(FormatInfo(GL_RGBA, GL_UNSIGNED_BYTE, GL_RGBA4 ));
set.insert(FormatInfo(GL_RGBA, GL_UNSIGNED_BYTE, GL_SRGB8_ALPHA8 ));
set.insert(FormatInfo(GL_RGBA, GL_BYTE, GL_RGBA8_SNORM ));
set.insert(FormatInfo(GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, GL_RGBA4 ));
set.insert(FormatInfo(GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, GL_RGB10_A2 ));
set.insert(FormatInfo(GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, GL_RGB5_A1 ));
set.insert(FormatInfo(GL_RGBA, GL_HALF_FLOAT, GL_RGBA16F ));
set.insert(FormatInfo(GL_RGBA, GL_FLOAT, GL_RGBA32F ));
set.insert(FormatInfo(GL_RGBA, GL_FLOAT, GL_RGBA16F ));
set.insert(FormatInfo(GL_RGBA_INTEGER, GL_UNSIGNED_BYTE, GL_RGBA8UI ));
set.insert(FormatInfo(GL_RGBA_INTEGER, GL_BYTE, GL_RGBA8I ));
set.insert(FormatInfo(GL_RGBA_INTEGER, GL_UNSIGNED_SHORT, GL_RGBA16UI ));
set.insert(FormatInfo(GL_RGBA_INTEGER, GL_SHORT, GL_RGBA16I ));
set.insert(FormatInfo(GL_RGBA_INTEGER, GL_UNSIGNED_INT, GL_RGBA32UI ));
set.insert(FormatInfo(GL_RGBA_INTEGER, GL_INT, GL_RGBA32I ));
set.insert(FormatInfo(GL_RGBA_INTEGER, GL_UNSIGNED_INT_2_10_10_10_REV, GL_RGB10_A2UI ));
set.insert(FormatInfo(GL_RGB, GL_UNSIGNED_BYTE, GL_RGB8 ));
set.insert(FormatInfo(GL_RGB, GL_UNSIGNED_BYTE, GL_RGB565 ));
set.insert(FormatInfo(GL_RGB, GL_UNSIGNED_BYTE, GL_SRGB8 ));
set.insert(FormatInfo(GL_RGB, GL_BYTE, GL_RGB8_SNORM ));
set.insert(FormatInfo(GL_RGB, GL_UNSIGNED_SHORT_5_6_5, GL_RGB565 ));
set.insert(FormatInfo(GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV, GL_R11F_G11F_B10F ));
set.insert(FormatInfo(GL_RGB, GL_UNSIGNED_INT_5_9_9_9_REV, GL_RGB9_E5 ));
set.insert(FormatInfo(GL_RGB, GL_HALF_FLOAT, GL_RGB16F ));
set.insert(FormatInfo(GL_RGB, GL_HALF_FLOAT, GL_R11F_G11F_B10F ));
set.insert(FormatInfo(GL_RGB, GL_HALF_FLOAT, GL_RGB9_E5 ));
set.insert(FormatInfo(GL_RGB, GL_FLOAT, GL_RGB32F ));
set.insert(FormatInfo(GL_RGB, GL_FLOAT, GL_RGB16F ));
set.insert(FormatInfo(GL_RGB, GL_FLOAT, GL_R11F_G11F_B10F ));
set.insert(FormatInfo(GL_RGB, GL_FLOAT, GL_RGB9_E5 ));
set.insert(FormatInfo(GL_RGB_INTEGER, GL_UNSIGNED_BYTE, GL_RGB8UI ));
set.insert(FormatInfo(GL_RGB_INTEGER, GL_BYTE, GL_RGB8I ));
set.insert(FormatInfo(GL_RGB_INTEGER, GL_UNSIGNED_SHORT, GL_RGB16UI ));
set.insert(FormatInfo(GL_RGB_INTEGER, GL_SHORT, GL_RGB16I ));
set.insert(FormatInfo(GL_RGB_INTEGER, GL_UNSIGNED_INT, GL_RGB32UI ));
set.insert(FormatInfo(GL_RGB_INTEGER, GL_INT, GL_RGB32I ));
set.insert(FormatInfo(GL_RG, GL_UNSIGNED_BYTE, GL_RG8 ));
set.insert(FormatInfo(GL_RG, GL_BYTE, GL_RG8_SNORM ));
set.insert(FormatInfo(GL_RG, GL_HALF_FLOAT, GL_RG16F ));
set.insert(FormatInfo(GL_RG, GL_FLOAT, GL_RG32F ));
set.insert(FormatInfo(GL_RG, GL_FLOAT, GL_RG16F ));
set.insert(FormatInfo(GL_RG_INTEGER, GL_UNSIGNED_BYTE, GL_RG8UI ));
set.insert(FormatInfo(GL_RG_INTEGER, GL_BYTE, GL_RG8I ));
set.insert(FormatInfo(GL_RG_INTEGER, GL_UNSIGNED_SHORT, GL_RG16UI ));
set.insert(FormatInfo(GL_RG_INTEGER, GL_SHORT, GL_RG16I ));
set.insert(FormatInfo(GL_RG_INTEGER, GL_UNSIGNED_INT, GL_RG32UI ));
set.insert(FormatInfo(GL_RG_INTEGER, GL_INT, GL_RG32I ));
set.insert(FormatInfo(GL_RED, GL_UNSIGNED_BYTE, GL_R8 ));
set.insert(FormatInfo(GL_RED, GL_BYTE, GL_R8_SNORM ));
set.insert(FormatInfo(GL_RED, GL_HALF_FLOAT, GL_R16F ));
set.insert(FormatInfo(GL_RED, GL_FLOAT, GL_R32F ));
set.insert(FormatInfo(GL_RED, GL_FLOAT, GL_R16F ));
set.insert(FormatInfo(GL_RED_INTEGER, GL_UNSIGNED_BYTE, GL_R8UI ));
set.insert(FormatInfo(GL_RED_INTEGER, GL_BYTE, GL_R8I ));
set.insert(FormatInfo(GL_RED_INTEGER, GL_UNSIGNED_SHORT, GL_R16UI ));
set.insert(FormatInfo(GL_RED_INTEGER, GL_SHORT, GL_R16I ));
set.insert(FormatInfo(GL_RED_INTEGER, GL_UNSIGNED_INT, GL_R32UI ));
set.insert(FormatInfo(GL_RED_INTEGER, GL_INT, GL_R32I ));
set.insert(FormatInfo(GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, GL_DEPTH_COMPONENT16 ));
set.insert(FormatInfo(GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, GL_DEPTH_COMPONENT24 ));
set.insert(FormatInfo(GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, GL_DEPTH_COMPONENT16 ));
set.insert(FormatInfo(GL_DEPTH_COMPONENT, GL_FLOAT, GL_DEPTH_COMPONENT32F));
set.insert(FormatInfo(GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, GL_DEPTH24_STENCIL8 ));
set.insert(FormatInfo(GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV, GL_DEPTH32F_STENCIL8 ));
// From ES 3.0.1 spec, table 3.3
set.insert(FormatInfo(GL_RGBA, GL_UNSIGNED_BYTE, GL_RGBA ));
set.insert(FormatInfo(GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, GL_RGBA ));
set.insert(FormatInfo(GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, GL_RGBA ));
set.insert(FormatInfo(GL_RGB, GL_UNSIGNED_BYTE, GL_RGB ));
set.insert(FormatInfo(GL_RGB, GL_UNSIGNED_SHORT_5_6_5, GL_RGB ));
set.insert(FormatInfo(GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, GL_LUMINANCE_ALPHA ));
set.insert(FormatInfo(GL_LUMINANCE, GL_UNSIGNED_BYTE, GL_LUMINANCE ));
set.insert(FormatInfo(GL_ALPHA, GL_UNSIGNED_BYTE, GL_ALPHA ));
// From GL_OES_texture_float
set.insert(FormatInfo(GL_LUMINANCE_ALPHA, GL_FLOAT, GL_LUMINANCE_ALPHA ));
set.insert(FormatInfo(GL_LUMINANCE, GL_FLOAT, GL_LUMINANCE ));
set.insert(FormatInfo(GL_ALPHA, GL_FLOAT, GL_ALPHA ));
// From GL_OES_texture_half_float
set.insert(FormatInfo(GL_LUMINANCE_ALPHA, GL_HALF_FLOAT, GL_LUMINANCE_ALPHA ));
set.insert(FormatInfo(GL_LUMINANCE, GL_HALF_FLOAT, GL_LUMINANCE ));
set.insert(FormatInfo(GL_ALPHA, GL_HALF_FLOAT, GL_ALPHA ));
return set;
}
typedef std::set<GLint> internalFormatSet;
static internalFormatSet buildValidES3InternalFormatSet(const formatInfoSet& formatCombos)
{
internalFormatSet internalFormats;
for (formatInfoSet::const_iterator i = formatCombos.begin(); i != formatCombos.end(); i++)
{
internalFormats.insert(i->mInternalformat);
}
return internalFormats;
}
typedef std::set<GLenum> formatSet;
static formatSet buildValidES3FormatSet(const formatInfoSet& formatCombos)
{
formatSet formats;
for (formatInfoSet::const_iterator i = formatCombos.begin(); i != formatCombos.end(); i++)
{
formats.insert(i->mFormat);
}
return formats;
}
typedef std::set<GLenum> typeSet;
static typeSet buildValidES3TypeSet(const formatInfoSet& formatCombos)
{
typeSet types;
for (formatInfoSet::const_iterator i = formatCombos.begin(); i != formatCombos.end(); i++)
{
types.insert(i->mType);
}
return types;
}
bool IsValidES3FormatCombination(GLint internalformat, GLenum format, GLenum type, GLenum* err)
{
static const formatInfoSet combinations = buildValidES3FormatCombinationSet();
static const internalFormatSet internalFormats = buildValidES3InternalFormatSet(combinations);
static const formatSet formats = buildValidES3FormatSet(combinations);
static const typeSet types = buildValidES3TypeSet(combinations);
// Invalid internal format, format or type results in an INVALID_ENUM
if (internalFormats.find(internalformat) == internalFormats.end() ||
formats.find(format) == formats.end() ||
types.find(type) == types.end())
{
*err = GL_INVALID_ENUM;
return false;
}
// Invalid internal format + format + type combination results in an INVALID_OPERATION
if (combinations.find(FormatInfo(format, type, internalformat)) == combinations.end())
{
*err = GL_INVALID_OPERATION;
return false;
}
return true;
}
typedef std::set<GLenum> compressedFormatSet;
static compressedFormatSet buildValidES3CompressedFormats()
{
compressedFormatSet formats;
// From ES 3.0.1 spec, table 3.16
formats.insert(GL_COMPRESSED_R11_EAC );
formats.insert(GL_COMPRESSED_R11_EAC );
formats.insert(GL_COMPRESSED_SIGNED_R11_EAC );
formats.insert(GL_COMPRESSED_RG11_EAC );
formats.insert(GL_COMPRESSED_SIGNED_RG11_EAC );
formats.insert(GL_COMPRESSED_RGB8_ETC2 );
formats.insert(GL_COMPRESSED_SRGB8_ETC2 );
formats.insert(GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 );
formats.insert(GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2);
formats.insert(GL_COMPRESSED_RGBA8_ETC2_EAC );
formats.insert(GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC );
// From GL_EXT_texture_compression_dxt1
formats.insert(GL_COMPRESSED_RGB_S3TC_DXT1_EXT );
formats.insert(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT );
// From GL_ANGLE_texture_compression_dxt3
formats.insert(GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE );
// From GL_ANGLE_texture_compression_dxt5
formats.insert(GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE );
return formats;
}
bool IsValidES3CompressedFormat(GLenum format)
{
static const compressedFormatSet validCompressedFormats = buildValidES3CompressedFormats();
return validCompressedFormats.find(format) != validCompressedFormats.end();
}
struct CopyConversion
{
GLenum mTextureFormat;
GLenum mFramebufferFormat;
CopyConversion(GLenum textureFormat, GLenum framebufferFormat)
: mTextureFormat(textureFormat), mFramebufferFormat(framebufferFormat) { }
bool operator<(const CopyConversion& other) const
{
return memcmp(this, &other, sizeof(CopyConversion)) < 0;
}
};
typedef std::set<CopyConversion> copyConversionSet;
static copyConversionSet buildValidES3CopyTexImageCombinations()
{
copyConversionSet set;
// From ES 3.0.1 spec, table 3.15
set.insert(CopyConversion(GL_ALPHA, GL_RGBA));
set.insert(CopyConversion(GL_LUMINANCE, GL_RED));
set.insert(CopyConversion(GL_LUMINANCE, GL_RG));
set.insert(CopyConversion(GL_LUMINANCE, GL_RGB));
set.insert(CopyConversion(GL_LUMINANCE, GL_RGBA));
set.insert(CopyConversion(GL_LUMINANCE_ALPHA, GL_RGBA));
set.insert(CopyConversion(GL_RED, GL_RED));
set.insert(CopyConversion(GL_RED, GL_RG));
set.insert(CopyConversion(GL_RED, GL_RGB));
set.insert(CopyConversion(GL_RED, GL_RGBA));
set.insert(CopyConversion(GL_RG, GL_RG));
set.insert(CopyConversion(GL_RG, GL_RGB));
set.insert(CopyConversion(GL_RG, GL_RGBA));
set.insert(CopyConversion(GL_RGB, GL_RGB));
set.insert(CopyConversion(GL_RGB, GL_RGBA));
set.insert(CopyConversion(GL_RGBA, GL_RGBA));
return set;
}
bool IsValidES3CopyTexImageCombination(GLenum textureFormat, GLenum frameBufferFormat)
{
static const copyConversionSet conversions = buildValidES3CopyTexImageCombinations();
return conversions.find(CopyConversion(textureFormat, frameBufferFormat)) != conversions.end();
}
}
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);
}