// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// utilities.cpp: Conversion functions and other utility routines.
#include "utilities.h"
#include "mathutil.h"
#include "Context.h"
#include "common/debug.h"
#include <limits>
#include <stdio.h>
namespace es1
{
bool IsCompressed(GLenum format)
{
return format == GL_COMPRESSED_RGB_S3TC_DXT1_EXT ||
format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT ||
format == GL_ETC1_RGB8_OES;
}
bool IsSizedInternalFormat(GLint internalformat)
{
switch(internalformat)
{
case GL_ALPHA8_EXT:
case GL_LUMINANCE8_ALPHA8_EXT:
case GL_LUMINANCE8_EXT:
case GL_RGBA4_OES:
case GL_RGB5_A1_OES:
case GL_RGB565_OES:
case GL_RGB8_OES:
case GL_RGBA8_OES:
case GL_BGRA8_EXT: // GL_APPLE_texture_format_BGRA8888
case GL_DEPTH_COMPONENT16_OES:
case GL_STENCIL_INDEX8_OES:
case GL_DEPTH24_STENCIL8_OES:
return true;
default:
return false;
}
}
GLenum ValidateSubImageParams(bool compressed, bool copy, GLenum target, GLint level, GLint xoffset, GLint yoffset,
GLsizei width, GLsizei height, GLenum format, GLenum type, Texture *texture)
{
if(!texture)
{
return GL_INVALID_OPERATION;
}
GLenum sizedInternalFormat = texture->getFormat(target, level);
if(compressed)
{
if(format != sizedInternalFormat)
{
return GL_INVALID_OPERATION;
}
}
else if(!copy) // CopyTexSubImage doesn't have format/type parameters.
{
GLenum validationError = ValidateTextureFormatType(format, type, sizedInternalFormat, target);
if(validationError != GL_NO_ERROR)
{
return validationError;
}
}
if(compressed)
{
if((width % 4 != 0 && width != texture->getWidth(target, 0)) ||
(height % 4 != 0 && height != texture->getHeight(target, 0)))
{
return GL_INVALID_OPERATION;
}
}
if(xoffset + width > texture->getWidth(target, level) ||
yoffset + height > texture->getHeight(target, level))
{
return GL_INVALID_VALUE;
}
return GL_NO_ERROR;
}
bool IsDepthTexture(GLenum format)
{
return format == GL_DEPTH_STENCIL_OES;
}
bool IsStencilTexture(GLenum format)
{
return format == GL_DEPTH_STENCIL_OES;
}
bool IsCubemapTextureTarget(GLenum target)
{
return (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X_OES && target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_OES);
}
int CubeFaceIndex(GLenum cubeFace)
{
switch(cubeFace)
{
case GL_TEXTURE_CUBE_MAP_OES:
case GL_TEXTURE_CUBE_MAP_POSITIVE_X_OES: return 0;
case GL_TEXTURE_CUBE_MAP_NEGATIVE_X_OES: return 1;
case GL_TEXTURE_CUBE_MAP_POSITIVE_Y_OES: return 2;
case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_OES: return 3;
case GL_TEXTURE_CUBE_MAP_POSITIVE_Z_OES: return 4;
case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_OES: return 5;
default: UNREACHABLE(cubeFace); return 0;
}
}
bool IsTextureTarget(GLenum target)
{
return target == GL_TEXTURE_2D;
}
// Verify that format/type are one of the combinations from table 3.4.
GLenum ValidateTextureFormatType(GLenum format, GLenum type, GLint internalformat, GLenum target)
{
switch(type)
{
case GL_UNSIGNED_BYTE:
case GL_UNSIGNED_SHORT_4_4_4_4:
case GL_UNSIGNED_SHORT_5_5_5_1:
case GL_UNSIGNED_SHORT_5_6_5:
case GL_UNSIGNED_INT_24_8_OES: // GL_OES_packed_depth_stencil
break;
default:
return GL_INVALID_ENUM;
}
switch(format)
{
case GL_ALPHA:
case GL_RGB:
case GL_RGBA:
case GL_LUMINANCE:
case GL_LUMINANCE_ALPHA:
case GL_BGRA_EXT: // GL_EXT_texture_format_BGRA8888
break;
case GL_DEPTH_STENCIL_OES: // GL_OES_packed_depth_stencil (GL_DEPTH_STENCIL_OES)
switch(target)
{
case GL_TEXTURE_2D:
break;
default:
return GL_INVALID_OPERATION;
}
break;
default:
return GL_INVALID_ENUM;
}
if((GLenum)internalformat != format)
{
if(gl::IsUnsizedInternalFormat(internalformat))
{
return GL_INVALID_OPERATION;
}
if(!IsSizedInternalFormat(internalformat))
{
return GL_INVALID_VALUE;
}
}
if((GLenum)internalformat == format)
{
// Validate format, type, and unsized internalformat combinations [OpenGL ES 1.1 Table 3.3]
switch(format)
{
case GL_RGBA:
switch(type)
{
case GL_UNSIGNED_BYTE:
case GL_UNSIGNED_SHORT_4_4_4_4:
case GL_UNSIGNED_SHORT_5_5_5_1:
break;
default:
return GL_INVALID_OPERATION;
}
break;
case GL_RGB:
switch(type)
{
case GL_UNSIGNED_BYTE:
case GL_UNSIGNED_SHORT_5_6_5:
break;
default:
return GL_INVALID_OPERATION;
}
break;
case GL_LUMINANCE_ALPHA:
case GL_LUMINANCE:
case GL_ALPHA:
switch(type)
{
case GL_UNSIGNED_BYTE:
break;
default:
return GL_INVALID_OPERATION;
}
break;
case GL_DEPTH_STENCIL_OES:
switch(type)
{
case GL_UNSIGNED_INT_24_8_OES: // GL_OES_packed_depth_stencil
break;
default:
return GL_INVALID_OPERATION;
}
break;
case GL_BGRA_EXT:
if(type != GL_UNSIGNED_BYTE) // GL_APPLE_texture_format_BGRA8888 / GL_EXT_texture_format_BGRA8888
{
return GL_INVALID_OPERATION;
}
break;
default:
UNREACHABLE(format);
return GL_INVALID_ENUM;
}
return GL_NO_ERROR;
}
// Validate format, type, and sized internalformat combinations [OpenGL ES 3.0 Table 3.2]
bool validSizedInternalformat = false;
#define VALIDATE_INTERNALFORMAT(...) { GLint validInternalformats[] = {__VA_ARGS__}; for(GLint v : validInternalformats) {if(internalformat == v) validSizedInternalformat = true;} } break;
switch(format)
{
case GL_RGBA:
switch(type)
{
case GL_UNSIGNED_BYTE: VALIDATE_INTERNALFORMAT(GL_RGBA8_OES, GL_RGB5_A1_OES, GL_RGBA4_OES)
case GL_UNSIGNED_SHORT_4_4_4_4: VALIDATE_INTERNALFORMAT(GL_RGBA4_OES)
case GL_UNSIGNED_SHORT_5_5_5_1: VALIDATE_INTERNALFORMAT(GL_RGB5_A1_OES)
default: return GL_INVALID_OPERATION;
}
break;
case GL_RGB:
switch(type)
{
case GL_UNSIGNED_BYTE: VALIDATE_INTERNALFORMAT(GL_RGB8_OES, GL_RGB565_OES)
case GL_UNSIGNED_SHORT_5_6_5: VALIDATE_INTERNALFORMAT(GL_RGB565_OES)
default: return GL_INVALID_OPERATION;
}
break;
case GL_DEPTH_STENCIL_OES:
switch(type)
{
case GL_UNSIGNED_INT_24_8_OES: VALIDATE_INTERNALFORMAT(GL_DEPTH24_STENCIL8_OES)
default: return GL_INVALID_OPERATION;
}
break;
case GL_LUMINANCE_ALPHA:
switch(type)
{
case GL_UNSIGNED_BYTE: VALIDATE_INTERNALFORMAT(GL_LUMINANCE8_ALPHA8_EXT)
default:
return GL_INVALID_OPERATION;
}
break;
case GL_LUMINANCE:
switch(type)
{
case GL_UNSIGNED_BYTE: VALIDATE_INTERNALFORMAT(GL_LUMINANCE8_EXT)
default:
return GL_INVALID_OPERATION;
}
break;
case GL_ALPHA:
switch(type)
{
case GL_UNSIGNED_BYTE: VALIDATE_INTERNALFORMAT(GL_ALPHA8_EXT)
default:
return GL_INVALID_OPERATION;
}
break;
case GL_BGRA_EXT: // GL_APPLE_texture_format_BGRA8888
switch(type)
{
case GL_UNSIGNED_BYTE: VALIDATE_INTERNALFORMAT(GL_BGRA8_EXT)
default: return GL_INVALID_OPERATION;
}
break;
default:
UNREACHABLE(format);
return GL_INVALID_ENUM;
}
#undef VALIDATE_INTERNALFORMAT
if(!validSizedInternalformat)
{
return GL_INVALID_OPERATION;
}
return GL_NO_ERROR;
}
bool IsColorRenderable(GLint internalformat)
{
switch(internalformat)
{
case GL_RGBA4_OES:
case GL_RGB5_A1_OES:
case GL_RGB565_OES:
case GL_RGB8_OES:
case GL_RGBA8_OES:
return true;
case GL_DEPTH_COMPONENT16_OES:
case GL_STENCIL_INDEX8_OES:
case GL_DEPTH24_STENCIL8_OES:
return false;
default:
UNIMPLEMENTED();
}
return false;
}
bool IsDepthRenderable(GLint internalformat)
{
switch(internalformat)
{
case GL_DEPTH_COMPONENT16_OES:
case GL_DEPTH24_STENCIL8_OES:
return true;
case GL_STENCIL_INDEX8_OES:
case GL_RGBA4_OES:
case GL_RGB5_A1_OES:
case GL_RGB565_OES:
case GL_RGB8_OES:
case GL_RGBA8_OES:
return false;
default:
UNIMPLEMENTED();
}
return false;
}
bool IsStencilRenderable(GLint internalformat)
{
switch(internalformat)
{
case GL_STENCIL_INDEX8_OES:
case GL_DEPTH24_STENCIL8_OES:
return true;
case GL_RGBA4_OES:
case GL_RGB5_A1_OES:
case GL_RGB565_OES:
case GL_RGB8_OES:
case GL_RGBA8_OES:
case GL_DEPTH_COMPONENT16_OES:
return false;
default:
UNIMPLEMENTED();
}
return false;
}
GLuint GetAlphaSize(GLint internalformat)
{
switch(internalformat)
{
case GL_NONE_OES: return 0;
case GL_RGBA4_OES: return 4;
case GL_RGB5_A1_OES: return 1;
case GL_RGB565_OES: return 0;
case GL_RGB8_OES: return 0;
case GL_RGBA8_OES: return 8;
case GL_BGRA8_EXT: return 8;
default:
// UNREACHABLE(internalformat);
return 0;
}
}
GLuint GetRedSize(GLint internalformat)
{
switch(internalformat)
{
case GL_NONE_OES: return 0;
case GL_RGBA4_OES: return 4;
case GL_RGB5_A1_OES: return 5;
case GL_RGB565_OES: return 5;
case GL_RGB8_OES: return 8;
case GL_RGBA8_OES: return 8;
case GL_BGRA8_EXT: return 8;
default:
// UNREACHABLE(internalformat);
return 0;
}
}
GLuint GetGreenSize(GLint internalformat)
{
switch(internalformat)
{
case GL_NONE_OES: return 0;
case GL_RGBA4_OES: return 4;
case GL_RGB5_A1_OES: return 5;
case GL_RGB565_OES: return 6;
case GL_RGB8_OES: return 8;
case GL_RGBA8_OES: return 8;
case GL_BGRA8_EXT: return 8;
default:
// UNREACHABLE(internalformat);
return 0;
}
}
GLuint GetBlueSize(GLint internalformat)
{
switch(internalformat)
{
case GL_NONE_OES: return 0;
case GL_RGBA4_OES: return 4;
case GL_RGB5_A1_OES: return 5;
case GL_RGB565_OES: return 5;
case GL_RGB8_OES: return 8;
case GL_RGBA8_OES: return 8;
case GL_BGRA8_EXT: return 8;
default:
// UNREACHABLE(internalformat);
return 0;
}
}
GLuint GetDepthSize(GLint internalformat)
{
switch(internalformat)
{
case GL_STENCIL_INDEX8_OES: return 0;
case GL_DEPTH_COMPONENT16_OES: return 16;
case GL_DEPTH24_STENCIL8_OES: return 24;
default:
// UNREACHABLE(internalformat);
return 0;
}
}
GLuint GetStencilSize(GLint internalformat)
{
switch(internalformat)
{
case GL_STENCIL_INDEX8_OES: return 8;
case GL_DEPTH_COMPONENT16_OES: return 0;
case GL_DEPTH24_STENCIL8_OES: return 8;
default:
// UNREACHABLE(internalformat);
return 0;
}
}
bool IsAlpha(GLint internalformat)
{
switch(internalformat)
{
case GL_ALPHA8_EXT:
return true;
default:
return false;
}
}
bool IsRGB(GLint internalformat)
{
switch(internalformat)
{
case GL_LUMINANCE8_EXT:
case GL_RGB565_OES:
case GL_RGB8_OES:
case SW_YV12_BT601:
case SW_YV12_BT709:
case SW_YV12_JFIF:
return true;
default:
return false;
}
}
bool IsRGBA(GLint internalformat)
{
switch(internalformat)
{
case GL_LUMINANCE8_ALPHA8_EXT:
case GL_RGBA:
case GL_BGRA8_EXT: // GL_EXT_texture_format_BGRA8888
case GL_RGBA4_OES:
case GL_RGB5_A1_OES:
case GL_RGBA8_OES:
return true;
default:
return false;
}
}
}
namespace es2sw
{
sw::DepthCompareMode ConvertDepthComparison(GLenum comparison)
{
switch(comparison)
{
case GL_NEVER: return sw::DEPTH_NEVER;
case GL_ALWAYS: return sw::DEPTH_ALWAYS;
case GL_LESS: return sw::DEPTH_LESS;
case GL_LEQUAL: return sw::DEPTH_LESSEQUAL;
case GL_EQUAL: return sw::DEPTH_EQUAL;
case GL_GREATER: return sw::DEPTH_GREATER;
case GL_GEQUAL: return sw::DEPTH_GREATEREQUAL;
case GL_NOTEQUAL: return sw::DEPTH_NOTEQUAL;
default: UNREACHABLE(comparison);
}
return sw::DEPTH_ALWAYS;
}
sw::StencilCompareMode ConvertStencilComparison(GLenum comparison)
{
switch(comparison)
{
case GL_NEVER: return sw::STENCIL_NEVER;
case GL_ALWAYS: return sw::STENCIL_ALWAYS;
case GL_LESS: return sw::STENCIL_LESS;
case GL_LEQUAL: return sw::STENCIL_LESSEQUAL;
case GL_EQUAL: return sw::STENCIL_EQUAL;
case GL_GREATER: return sw::STENCIL_GREATER;
case GL_GEQUAL: return sw::STENCIL_GREATEREQUAL;
case GL_NOTEQUAL: return sw::STENCIL_NOTEQUAL;
default: UNREACHABLE(comparison);
}
return sw::STENCIL_ALWAYS;
}
sw::AlphaCompareMode ConvertAlphaComparison(GLenum comparison)
{
switch(comparison)
{
case GL_NEVER: return sw::ALPHA_NEVER;
case GL_ALWAYS: return sw::ALPHA_ALWAYS;
case GL_LESS: return sw::ALPHA_LESS;
case GL_LEQUAL: return sw::ALPHA_LESSEQUAL;
case GL_EQUAL: return sw::ALPHA_EQUAL;
case GL_GREATER: return sw::ALPHA_GREATER;
case GL_GEQUAL: return sw::ALPHA_GREATEREQUAL;
case GL_NOTEQUAL: return sw::ALPHA_NOTEQUAL;
default: UNREACHABLE(comparison);
}
return sw::ALPHA_ALWAYS;
}
sw::Color<float> ConvertColor(es1::Color color)
{
return sw::Color<float>(color.red, color.green, color.blue, color.alpha);
}
sw::BlendFactor ConvertBlendFunc(GLenum blend)
{
switch(blend)
{
case GL_ZERO: return sw::BLEND_ZERO;
case GL_ONE: return sw::BLEND_ONE;
case GL_SRC_COLOR: return sw::BLEND_SOURCE;
case GL_ONE_MINUS_SRC_COLOR: return sw::BLEND_INVSOURCE;
case GL_DST_COLOR: return sw::BLEND_DEST;
case GL_ONE_MINUS_DST_COLOR: return sw::BLEND_INVDEST;
case GL_SRC_ALPHA: return sw::BLEND_SOURCEALPHA;
case GL_ONE_MINUS_SRC_ALPHA: return sw::BLEND_INVSOURCEALPHA;
case GL_DST_ALPHA: return sw::BLEND_DESTALPHA;
case GL_ONE_MINUS_DST_ALPHA: return sw::BLEND_INVDESTALPHA;
case GL_SRC_ALPHA_SATURATE: return sw::BLEND_SRCALPHASAT;
default: UNREACHABLE(blend);
}
return sw::BLEND_ZERO;
}
sw::BlendOperation ConvertBlendOp(GLenum blendOp)
{
switch(blendOp)
{
case GL_FUNC_ADD_OES: return sw::BLENDOP_ADD;
case GL_FUNC_SUBTRACT_OES: return sw::BLENDOP_SUB;
case GL_FUNC_REVERSE_SUBTRACT_OES: return sw::BLENDOP_INVSUB;
case GL_MIN_EXT: return sw::BLENDOP_MIN;
case GL_MAX_EXT: return sw::BLENDOP_MAX;
default: UNREACHABLE(blendOp);
}
return sw::BLENDOP_ADD;
}
sw::LogicalOperation ConvertLogicalOperation(GLenum logicalOperation)
{
switch(logicalOperation)
{
case GL_CLEAR: return sw::LOGICALOP_CLEAR;
case GL_SET: return sw::LOGICALOP_SET;
case GL_COPY: return sw::LOGICALOP_COPY;
case GL_COPY_INVERTED: return sw::LOGICALOP_COPY_INVERTED;
case GL_NOOP: return sw::LOGICALOP_NOOP;
case GL_INVERT: return sw::LOGICALOP_INVERT;
case GL_AND: return sw::LOGICALOP_AND;
case GL_NAND: return sw::LOGICALOP_NAND;
case GL_OR: return sw::LOGICALOP_OR;
case GL_NOR: return sw::LOGICALOP_NOR;
case GL_XOR: return sw::LOGICALOP_XOR;
case GL_EQUIV: return sw::LOGICALOP_EQUIV;
case GL_AND_REVERSE: return sw::LOGICALOP_AND_REVERSE;
case GL_AND_INVERTED: return sw::LOGICALOP_AND_INVERTED;
case GL_OR_REVERSE: return sw::LOGICALOP_OR_REVERSE;
case GL_OR_INVERTED: return sw::LOGICALOP_OR_INVERTED;
default: UNREACHABLE(logicalOperation);
}
return sw::LOGICALOP_COPY;
}
sw::StencilOperation ConvertStencilOp(GLenum stencilOp)
{
switch(stencilOp)
{
case GL_ZERO: return sw::OPERATION_ZERO;
case GL_KEEP: return sw::OPERATION_KEEP;
case GL_REPLACE: return sw::OPERATION_REPLACE;
case GL_INCR: return sw::OPERATION_INCRSAT;
case GL_DECR: return sw::OPERATION_DECRSAT;
case GL_INVERT: return sw::OPERATION_INVERT;
case GL_INCR_WRAP_OES: return sw::OPERATION_INCR;
case GL_DECR_WRAP_OES: return sw::OPERATION_DECR;
default: UNREACHABLE(stencilOp);
}
return sw::OPERATION_KEEP;
}
sw::AddressingMode ConvertTextureWrap(GLenum wrap)
{
switch(wrap)
{
case GL_REPEAT: return sw::ADDRESSING_WRAP;
case GL_CLAMP_TO_EDGE: return sw::ADDRESSING_CLAMP;
case GL_MIRRORED_REPEAT_OES: return sw::ADDRESSING_MIRROR;
default: UNREACHABLE(wrap);
}
return sw::ADDRESSING_WRAP;
}
sw::CullMode ConvertCullMode(GLenum cullFace, GLenum frontFace)
{
switch(cullFace)
{
case GL_FRONT:
return (frontFace == GL_CCW ? sw::CULL_CLOCKWISE : sw::CULL_COUNTERCLOCKWISE);
case GL_BACK:
return (frontFace == GL_CCW ? sw::CULL_COUNTERCLOCKWISE : sw::CULL_CLOCKWISE);
case GL_FRONT_AND_BACK:
return sw::CULL_NONE; // culling will be handled during draw
default: UNREACHABLE(cullFace);
}
return sw::CULL_COUNTERCLOCKWISE;
}
unsigned int ConvertColorMask(bool red, bool green, bool blue, bool alpha)
{
return (red ? 0x00000001 : 0) |
(green ? 0x00000002 : 0) |
(blue ? 0x00000004 : 0) |
(alpha ? 0x00000008 : 0);
}
sw::MipmapType ConvertMipMapFilter(GLenum minFilter)
{
switch(minFilter)
{
case GL_NEAREST:
case GL_LINEAR:
return sw::MIPMAP_NONE;
break;
case GL_NEAREST_MIPMAP_NEAREST:
case GL_LINEAR_MIPMAP_NEAREST:
return sw::MIPMAP_POINT;
break;
case GL_NEAREST_MIPMAP_LINEAR:
case GL_LINEAR_MIPMAP_LINEAR:
return sw::MIPMAP_LINEAR;
break;
default:
UNREACHABLE(minFilter);
return sw::MIPMAP_NONE;
}
}
sw::FilterType ConvertTextureFilter(GLenum minFilter, GLenum magFilter, float maxAnisotropy)
{
if(maxAnisotropy > 1.0f)
{
return sw::FILTER_ANISOTROPIC;
}
sw::FilterType magFilterType = sw::FILTER_POINT;
switch(magFilter)
{
case GL_NEAREST: magFilterType = sw::FILTER_POINT; break;
case GL_LINEAR: magFilterType = sw::FILTER_LINEAR; break;
default: UNREACHABLE(magFilter);
}
switch(minFilter)
{
case GL_NEAREST:
case GL_NEAREST_MIPMAP_NEAREST:
case GL_NEAREST_MIPMAP_LINEAR:
return (magFilterType == sw::FILTER_POINT) ? sw::FILTER_POINT : sw::FILTER_MIN_POINT_MAG_LINEAR;
case GL_LINEAR:
case GL_LINEAR_MIPMAP_NEAREST:
case GL_LINEAR_MIPMAP_LINEAR:
return (magFilterType == sw::FILTER_POINT) ? sw::FILTER_MIN_LINEAR_MAG_POINT : sw::FILTER_LINEAR;
default:
UNREACHABLE(minFilter);
return (magFilterType == sw::FILTER_POINT) ? sw::FILTER_POINT : sw::FILTER_MIN_POINT_MAG_LINEAR;
}
}
bool ConvertPrimitiveType(GLenum primitiveType, GLsizei elementCount, GLenum elementType, sw::DrawType &drawType, int &primitiveCount)
{
switch(primitiveType)
{
case GL_POINTS:
drawType = sw::DRAW_POINTLIST;
primitiveCount = elementCount;
break;
case GL_LINES:
drawType = sw::DRAW_LINELIST;
primitiveCount = elementCount / 2;
break;
case GL_LINE_LOOP:
drawType = sw::DRAW_LINELOOP;
primitiveCount = elementCount;
break;
case GL_LINE_STRIP:
drawType = sw::DRAW_LINESTRIP;
primitiveCount = elementCount - 1;
break;
case GL_TRIANGLES:
drawType = sw::DRAW_TRIANGLELIST;
primitiveCount = elementCount / 3;
break;
case GL_TRIANGLE_STRIP:
drawType = sw::DRAW_TRIANGLESTRIP;
primitiveCount = elementCount - 2;
break;
case GL_TRIANGLE_FAN:
drawType = sw::DRAW_TRIANGLEFAN;
primitiveCount = elementCount - 2;
break;
default:
return false;
}
sw::DrawType elementSize;
switch(elementType)
{
case GL_NONE_OES: elementSize = sw::DRAW_NONINDEXED; break;
case GL_UNSIGNED_BYTE: elementSize = sw::DRAW_INDEXED8; break;
case GL_UNSIGNED_SHORT: elementSize = sw::DRAW_INDEXED16; break;
case GL_UNSIGNED_INT: elementSize = sw::DRAW_INDEXED32; break;
default: return false;
}
drawType = sw::DrawType(drawType | elementSize);
return true;
}
sw::TextureStage::StageOperation ConvertCombineOperation(GLenum operation)
{
switch(operation)
{
case GL_REPLACE: return sw::TextureStage::STAGE_SELECTARG1;
case GL_MODULATE: return sw::TextureStage::STAGE_MODULATE;
case GL_ADD: return sw::TextureStage::STAGE_ADD;
case GL_ADD_SIGNED: return sw::TextureStage::STAGE_ADDSIGNED;
case GL_INTERPOLATE: return sw::TextureStage::STAGE_LERP;
case GL_SUBTRACT: return sw::TextureStage::STAGE_SUBTRACT;
case GL_DOT3_RGB: return sw::TextureStage::STAGE_DOT3;
case GL_DOT3_RGBA: return sw::TextureStage::STAGE_DOT3;
default: UNREACHABLE(operation); return sw::TextureStage::STAGE_SELECTARG1;
}
}
sw::TextureStage::SourceArgument ConvertSourceArgument(GLenum argument)
{
switch(argument)
{
case GL_TEXTURE: return sw::TextureStage::SOURCE_TEXTURE;
case GL_CONSTANT: return sw::TextureStage::SOURCE_CONSTANT;
case GL_PRIMARY_COLOR: return sw::TextureStage::SOURCE_DIFFUSE;
case GL_PREVIOUS: return sw::TextureStage::SOURCE_CURRENT;
default: UNREACHABLE(argument); return sw::TextureStage::SOURCE_CURRENT;
}
}
sw::TextureStage::ArgumentModifier ConvertSourceOperand(GLenum operand)
{
switch(operand)
{
case GL_SRC_COLOR: return sw::TextureStage::MODIFIER_COLOR;
case GL_ONE_MINUS_SRC_COLOR: return sw::TextureStage::MODIFIER_INVCOLOR;
case GL_SRC_ALPHA: return sw::TextureStage::MODIFIER_ALPHA;
case GL_ONE_MINUS_SRC_ALPHA: return sw::TextureStage::MODIFIER_INVALPHA;
default: UNREACHABLE(operand); return sw::TextureStage::MODIFIER_COLOR;
}
}
}
namespace sw2es
{
GLenum ConvertBackBufferFormat(sw::Format format)
{
switch(format)
{
case sw::FORMAT_A4R4G4B4: return GL_RGBA4_OES;
case sw::FORMAT_A8R8G8B8: return GL_RGBA8_OES;
case sw::FORMAT_A8B8G8R8: return GL_RGBA8_OES;
case sw::FORMAT_A1R5G5B5: return GL_RGB5_A1_OES;
case sw::FORMAT_R5G6B5: return GL_RGB565_OES;
case sw::FORMAT_X8R8G8B8: return GL_RGB8_OES;
case sw::FORMAT_X8B8G8R8: return GL_RGB8_OES;
default:
UNREACHABLE(format);
}
return GL_RGBA4_OES;
}
GLenum ConvertDepthStencilFormat(sw::Format format)
{
switch(format)
{
case sw::FORMAT_D16:
case sw::FORMAT_D24X8:
case sw::FORMAT_D32:
return GL_DEPTH_COMPONENT16_OES;
case sw::FORMAT_D24S8:
return GL_DEPTH24_STENCIL8_OES;
default:
UNREACHABLE(format);
}
return GL_DEPTH24_STENCIL8_OES;
}
}