Commit a99ed554 by jchen10 Committed by Commit Bot

Refactor data conversions for state commands

This mainly enforces the rules as descripted in ES 3.10, section 2.2.1 and 2.2.2, by enhancing the "queryconversions" to support more rules, removing the scattered type convertors in "utilities" , "mathutil" and "queryutils", and forcing to only use the convertors in "queryconversions". BUG=angleproject:2165 Change-Id: I73c1dc850e2b3b8a479ece1d9c5eb7ae4ce851fe Reviewed-on: https://chromium-review.googlesource.com/680094 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org>
parent d03a849d
......@@ -208,6 +208,7 @@ std::string ToString(const T &value)
#define GL_BGRA4_ANGLEX 0x6ABC
#define GL_BGR5_A1_ANGLEX 0x6ABD
#define GL_INT_64_ANGLEX 0x6ABE
#define GL_UINT_64_ANGLEX 0x6ABF
// Hidden enum for the NULL D3D device type.
#define EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE 0x6AC0
......
......@@ -60,37 +60,38 @@ inline unsigned int ceilPow2(unsigned int x)
return x;
}
inline int clampToInt(unsigned int x)
{
return static_cast<int>(std::min(x, static_cast<unsigned int>(std::numeric_limits<int>::max())));
}
template <typename DestT, typename SrcT>
inline DestT clampCast(SrcT value)
{
static const DestT destLo = std::numeric_limits<DestT>::min();
static const DestT destHi = std::numeric_limits<DestT>::max();
static const SrcT srcLo = static_cast<SrcT>(destLo);
static const SrcT srcHi = static_cast<SrcT>(destHi);
// When value is outside of or equal to the limits for DestT we use the DestT limit directly.
// This avoids undefined behaviors due to loss of precision when converting from floats to
// integers:
// destHi for ints is 2147483647 but the closest float number is around 2147483648, so when
// doing a conversion from float to int we run into an UB because the float is outside of the
// range representable by the int.
if (value <= srcLo)
// For floating-point types with denormalization, min returns the minimum positive normalized
// value. To find the value that has no values less than it, use numeric_limits::lowest.
constexpr const long double destLo =
static_cast<long double>(std::numeric_limits<DestT>::lowest());
constexpr const long double destHi =
static_cast<long double>(std::numeric_limits<DestT>::max());
constexpr const long double srcLo =
static_cast<long double>(std::numeric_limits<SrcT>::lowest());
constexpr long double srcHi = static_cast<long double>(std::numeric_limits<SrcT>::max());
if (destHi < srcHi)
{
return destLo;
}
else if (value >= srcHi)
{
return destHi;
DestT destMax = std::numeric_limits<DestT>::max();
if (value >= static_cast<SrcT>(destMax))
{
return destMax;
}
}
else
if (destLo > srcLo)
{
return static_cast<DestT>(value);
DestT destLow = std::numeric_limits<DestT>::lowest();
if (value <= static_cast<SrcT>(destLow))
{
return destLow;
}
}
return static_cast<DestT>(value);
}
template<typename T, typename MIN, typename MAX>
......
......@@ -766,43 +766,6 @@ std::string ParseResourceName(const std::string &name, size_t *outSubscript)
return name.substr(0, open);
}
template <>
GLuint ConvertToGLuint(GLfloat param)
{
return uiround<GLuint>(param);
}
template <>
GLint ConvertToGLint(uint32_t param)
{
uint32_t max = static_cast<uint32_t>(std::numeric_limits<GLint>::max());
return static_cast<GLint>(param >= max ? max : param);
}
template <>
GLint ConvertToGLint(uint64_t param)
{
uint64_t max = static_cast<uint64_t>(std::numeric_limits<GLint>::max());
return static_cast<GLint>(param >= max ? max : param);
}
template <>
GLint ConvertToGLint(GLfloat param)
{
return iround<GLint>(param);
}
template <>
GLint ConvertFromGLfloat(GLfloat param)
{
return iround<GLint>(param);
}
template <>
GLuint ConvertFromGLfloat(GLfloat param)
{
return uiround<GLuint>(param);
}
unsigned int ParseAndStripArrayIndex(std::string *name)
{
unsigned int subscript = GL_INVALID_INDEX;
......
......@@ -67,94 +67,6 @@ GLuint GetPrimitiveRestartIndex(GLenum indexType);
bool IsTriangleMode(GLenum drawMode);
bool IsIntegerFormat(GLenum unsizedFormat);
// [OpenGL ES 3.0.2] Section 2.3.1 page 14
// Data Conversion For State-Setting Commands
// Floating-point values are rounded to the nearest integer, instead of truncated, as done by static_cast.
template <typename outT> outT iround(GLfloat value) { return static_cast<outT>(value > 0.0f ? floor(value + 0.5f) : ceil(value - 0.5f)); }
template <typename outT> outT uiround(GLfloat value) { return static_cast<outT>(value + 0.5f); }
// Helper for converting arbitrary GL types to other GL types used in queries and state setting
// TODO(jie.a.chen@intel.com): Add the conversion rule for all helpers as the spec requires:
// "If a value is so large in magnitude that it cannot be represented with the requested type,"
// "then the nearest value representable using the requested type is returned."
template <typename ParamType>
GLuint ConvertToGLuint(ParamType param)
{
return static_cast<GLuint>(param);
}
template <>
GLuint ConvertToGLuint(GLfloat param);
template <typename ParamType>
GLint ConvertToGLint(ParamType param)
{
return static_cast<GLint>(param);
}
template <>
GLint ConvertToGLint(uint32_t param);
template <>
GLint ConvertToGLint(uint64_t param);
template <>
GLint ConvertToGLint(GLfloat param);
// Same conversion as uint
template <typename ParamType>
GLenum ConvertToGLenum(ParamType param)
{
return static_cast<GLenum>(ConvertToGLuint(param));
}
template <typename ParamType>
GLfloat ConvertToGLfloat(ParamType param)
{
return static_cast<GLfloat>(param);
}
template <typename ParamType>
ParamType ConvertFromGLfloat(GLfloat param)
{
return static_cast<ParamType>(param);
}
template <>
GLint ConvertFromGLfloat(GLfloat param);
template <>
GLuint ConvertFromGLfloat(GLfloat param);
template <typename ParamType>
ParamType ConvertFromGLenum(GLenum param)
{
return static_cast<ParamType>(param);
}
template <typename ParamType>
ParamType ConvertFromGLuint(GLuint param)
{
return static_cast<ParamType>(param);
}
template <typename ParamType>
ParamType ConvertFromGLint(GLint param)
{
return static_cast<ParamType>(param);
}
template <typename ParamType>
ParamType ConvertFromGLboolean(GLboolean param)
{
return static_cast<ParamType>(param ? GL_TRUE : GL_FALSE);
}
template <typename ParamType>
ParamType ConvertFromGLint64(GLint64 param)
{
return clampCast<ParamType>(param);
}
unsigned int ParseAndStripArrayIndex(std::string *name);
struct UniformTypeInfo final : angle::NonCopyable
......
......@@ -118,7 +118,7 @@ gl::Error GetQueryObjectParameter(gl::Query *query, GLenum pname, T *params)
gl::Error error = query->isResultAvailable(&available);
if (!error.isError())
{
*params = gl::ConvertFromGLboolean<T>(available);
*params = gl::CastFromStateValue<T>(pname, static_cast<GLuint>(available));
}
return error;
}
......
......@@ -12,16 +12,17 @@
#include <string.h>
#include "common/bitset_utils.h"
#include "common/matrix_utils.h"
#include "common/mathutil.h"
#include "libANGLE/Context.h"
#include "common/matrix_utils.h"
#include "libANGLE/Caps.h"
#include "libANGLE/Context.h"
#include "libANGLE/Debug.h"
#include "libANGLE/Framebuffer.h"
#include "libANGLE/FramebufferAttachment.h"
#include "libANGLE/Query.h"
#include "libANGLE/VertexArray.h"
#include "libANGLE/formatutils.h"
#include "libANGLE/queryconversions.h"
namespace
{
......@@ -1851,10 +1852,14 @@ void State::getIntegerv(const Context *context, GLenum pname, GLint *params)
break;
case GL_STENCIL_FUNC: *params = mDepthStencil.stencilFunc; break;
case GL_STENCIL_REF: *params = mStencilRef; break;
case GL_STENCIL_VALUE_MASK: *params = clampToInt(mDepthStencil.stencilMask); break;
case GL_STENCIL_VALUE_MASK:
*params = CastMaskValue(context, mDepthStencil.stencilMask);
break;
case GL_STENCIL_BACK_FUNC: *params = mDepthStencil.stencilBackFunc; break;
case GL_STENCIL_BACK_REF: *params = mStencilBackRef; break;
case GL_STENCIL_BACK_VALUE_MASK: *params = clampToInt(mDepthStencil.stencilBackMask); break;
case GL_STENCIL_BACK_VALUE_MASK:
*params = CastMaskValue(context, mDepthStencil.stencilBackMask);
break;
case GL_STENCIL_FAIL: *params = mDepthStencil.stencilFail; break;
case GL_STENCIL_PASS_DEPTH_FAIL: *params = mDepthStencil.stencilPassDepthFail; break;
case GL_STENCIL_PASS_DEPTH_PASS: *params = mDepthStencil.stencilPassDepthPass; break;
......@@ -1868,8 +1873,12 @@ void State::getIntegerv(const Context *context, GLenum pname, GLint *params)
case GL_BLEND_DST_ALPHA: *params = mBlend.destBlendAlpha; break;
case GL_BLEND_EQUATION_RGB: *params = mBlend.blendEquationRGB; break;
case GL_BLEND_EQUATION_ALPHA: *params = mBlend.blendEquationAlpha; break;
case GL_STENCIL_WRITEMASK: *params = clampToInt(mDepthStencil.stencilWritemask); break;
case GL_STENCIL_BACK_WRITEMASK: *params = clampToInt(mDepthStencil.stencilBackWritemask); break;
case GL_STENCIL_WRITEMASK:
*params = CastMaskValue(context, mDepthStencil.stencilWritemask);
break;
case GL_STENCIL_BACK_WRITEMASK:
*params = CastMaskValue(context, mDepthStencil.stencilBackWritemask);
break;
case GL_STENCIL_CLEAR_VALUE: *params = mStencilClearValue; break;
case GL_IMPLEMENTATION_COLOR_READ_TYPE:
*params = mReadFramebuffer->getImplementationColorReadType(context);
......
......@@ -24,18 +24,9 @@ GLint64 ExpandFloatToInteger(GLfloat value)
return static_cast<GLint64>((static_cast<double>(0xFFFFFFFFULL) * value - 1.0) / 2.0);
}
template <typename QueryT>
QueryT ClampToQueryRange(GLint64 value)
{
const GLint64 min = static_cast<GLint64>(std::numeric_limits<QueryT>::min());
const GLint64 max = static_cast<GLint64>(std::numeric_limits<QueryT>::max());
return static_cast<QueryT>(clamp(value, min, max));
}
template <typename QueryT, typename NativeT>
QueryT CastStateValueToInt(GLenum pname, NativeT value)
QueryT CastFromStateValueToInt(GLenum pname, NativeT value)
{
GLenum queryType = GLTypeToGLenum<QueryT>::value;
GLenum nativeType = GLTypeToGLenum<NativeT>::value;
if (nativeType == GL_FLOAT)
......@@ -43,37 +34,70 @@ QueryT CastStateValueToInt(GLenum pname, NativeT value)
// RGBA color values and DepthRangeF values are converted to integer using Equation 2.4 from Table 4.5
if (pname == GL_DEPTH_RANGE || pname == GL_COLOR_CLEAR_VALUE || pname == GL_DEPTH_CLEAR_VALUE || pname == GL_BLEND_COLOR)
{
return ClampToQueryRange<QueryT>(ExpandFloatToInteger(static_cast<GLfloat>(value)));
return clampCast<QueryT>(ExpandFloatToInteger(static_cast<GLfloat>(value)));
}
else
{
return gl::iround<QueryT>(static_cast<GLfloat>(value));
return clampCast<QueryT>(std::round(value));
}
}
// Clamp 64-bit int values when casting to int
if (nativeType == GL_INT_64_ANGLEX && queryType == GL_INT)
return clampCast<QueryT>(value);
}
template <typename NativeT, typename QueryT>
NativeT CastQueryValueToInt(GLenum pname, QueryT value)
{
GLenum queryType = GLTypeToGLenum<QueryT>::value;
if (queryType == GL_FLOAT)
{
GLint64 minIntValue = static_cast<GLint64>(std::numeric_limits<GLint>::min());
GLint64 maxIntValue = static_cast<GLint64>(std::numeric_limits<GLint>::max());
GLint64 clampedValue = std::max(std::min(static_cast<GLint64>(value), maxIntValue), minIntValue);
return static_cast<QueryT>(clampedValue);
return static_cast<NativeT>(std::round(value));
}
return static_cast<QueryT>(value);
return static_cast<NativeT>(value);
}
} // anonymous namespace
// ES 3.10 Section 2.2.2
// When querying bitmasks(such as SAMPLE_MASK_VALUE or STENCIL_WRITEMASK) with GetIntegerv, the
// mask value is treated as a signed integer, so that mask values with the high bit set will not be
// clamped when returned as signed integers.
GLint CastMaskValue(const Context *context, GLuint value)
{
return (context->getClientVersion() >= Version(3, 1) ? static_cast<GLint>(value)
: clampCast<GLint>(value));
}
template <typename QueryT, typename InternalT>
QueryT CastFromGLintStateValue(GLenum pname, InternalT value)
{
return CastFromStateValue<QueryT, GLint>(pname, clampCast<GLint, InternalT>(value));
}
template GLfloat CastFromGLintStateValue<GLfloat, GLenum>(GLenum pname, GLenum value);
template GLint CastFromGLintStateValue<GLint, GLenum>(GLenum pname, GLenum value);
template GLint64 CastFromGLintStateValue<GLint64, GLenum>(GLenum pname, GLenum value);
template GLuint CastFromGLintStateValue<GLuint, GLenum>(GLenum pname, GLenum value);
template GLfloat CastFromGLintStateValue<GLfloat, bool>(GLenum pname, bool value);
template GLuint CastFromGLintStateValue<GLuint, bool>(GLenum pname, bool value);
template GLint CastFromGLintStateValue<GLint, bool>(GLenum pname, bool value);
template GLfloat CastFromGLintStateValue<GLfloat, size_t>(GLenum pname, size_t value);
template GLint CastFromGLintStateValue<GLint, size_t>(GLenum pname, size_t value);
template <typename QueryT, typename NativeT>
QueryT CastStateValue(GLenum pname, NativeT value)
QueryT CastFromStateValue(GLenum pname, NativeT value)
{
GLenum queryType = GLTypeToGLenum<QueryT>::value;
switch (queryType)
{
case GL_INT:
return CastStateValueToInt<QueryT, NativeT>(pname, value);
case GL_INT_64_ANGLEX:
return CastStateValueToInt<QueryT, NativeT>(pname, value);
case GL_UNSIGNED_INT:
case GL_UINT_64_ANGLEX:
return CastFromStateValueToInt<QueryT, NativeT>(pname, value);
case GL_FLOAT:
return static_cast<QueryT>(value);
case GL_BOOL:
......@@ -83,8 +107,50 @@ QueryT CastStateValue(GLenum pname, NativeT value)
return 0;
}
}
template GLint CastFromStateValue<GLint, GLint>(GLenum pname, GLint value);
template GLint CastFromStateValue<GLint, GLint64>(GLenum pname, GLint64 value);
template GLint64 CastFromStateValue<GLint64, GLint>(GLenum pname, GLint value);
template GLint64 CastFromStateValue<GLint64, GLint64>(GLenum pname, GLint64 value);
template GLfloat CastFromStateValue<GLfloat, GLint>(GLenum pname, GLint value);
template GLfloat CastFromStateValue<GLfloat, GLfloat>(GLenum pname, GLfloat value);
template GLint CastFromStateValue<GLint, GLfloat>(GLenum pname, GLfloat value);
template GLuint CastFromStateValue<GLuint, GLint>(GLenum pname, GLint value);
template GLuint CastFromStateValue<GLuint, GLuint>(GLenum pname, GLuint value);
template GLint CastFromStateValue<GLint, GLboolean>(GLenum pname, GLboolean value);
template GLint64 CastFromStateValue<GLint64, GLboolean>(GLenum pname, GLboolean value);
template GLint CastFromStateValue<GLint, GLuint>(GLenum pname, GLuint value);
template GLint64 CastFromStateValue<GLint64, GLuint>(GLenum pname, GLuint value);
template GLuint64 CastFromStateValue<GLuint64, GLuint>(GLenum pname, GLuint value);
} // anonymous namespace
template <typename NativeT, typename QueryT>
NativeT CastQueryValueTo(GLenum pname, QueryT value)
{
GLenum nativeType = GLTypeToGLenum<NativeT>::value;
switch (nativeType)
{
case GL_INT:
case GL_INT_64_ANGLEX:
case GL_UNSIGNED_INT:
case GL_UINT_64_ANGLEX:
return CastQueryValueToInt<NativeT, QueryT>(pname, value);
case GL_FLOAT:
return static_cast<NativeT>(value);
case GL_BOOL:
return static_cast<NativeT>(value == static_cast<QueryT>(0) ? GL_FALSE : GL_TRUE);
default:
UNREACHABLE();
return 0;
}
}
template GLint CastQueryValueTo<GLint, GLfloat>(GLenum pname, GLfloat value);
template GLboolean CastQueryValueTo<GLboolean, GLint>(GLenum pname, GLint value);
template GLint CastQueryValueTo<GLint, GLint>(GLenum pname, GLint value);
template GLfloat CastQueryValueTo<GLfloat, GLint>(GLenum pname, GLint value);
template GLfloat CastQueryValueTo<GLfloat, GLfloat>(GLenum pname, GLfloat value);
template GLuint CastQueryValueTo<GLuint, GLint>(GLenum pname, GLint value);
template GLuint CastQueryValueTo<GLuint, GLfloat>(GLenum pname, GLfloat value);
template <typename QueryT>
void CastStateValues(Context *context, GLenum nativeType, GLenum pname,
......@@ -97,7 +163,7 @@ void CastStateValues(Context *context, GLenum nativeType, GLenum pname,
for (unsigned int i = 0; i < numParams; ++i)
{
outParams[i] = CastStateValue<QueryT>(pname, intParams[i]);
outParams[i] = CastFromStateValue<QueryT>(pname, intParams[i]);
}
}
else if (nativeType == GL_BOOL)
......@@ -117,7 +183,7 @@ void CastStateValues(Context *context, GLenum nativeType, GLenum pname,
for (unsigned int i = 0; i < numParams; ++i)
{
outParams[i] = CastStateValue<QueryT>(pname, floatParams[i]);
outParams[i] = CastFromStateValue<QueryT>(pname, floatParams[i]);
}
}
else if (nativeType == GL_INT_64_ANGLEX)
......@@ -127,7 +193,7 @@ void CastStateValues(Context *context, GLenum nativeType, GLenum pname,
for (unsigned int i = 0; i < numParams; ++i)
{
outParams[i] = CastStateValue<QueryT>(pname, int64Params[i]);
outParams[i] = CastFromStateValue<QueryT>(pname, int64Params[i]);
}
}
else UNREACHABLE();
......@@ -135,7 +201,7 @@ void CastStateValues(Context *context, GLenum nativeType, GLenum pname,
// Explicit template instantiation (how we export template functions in different files)
// The calls below will make CastStateValues successfully link with the GL state query types
// The GL state query API types are: bool, int, uint, float, int64
// The GL state query API types are: bool, int, uint, float, int64, uint64
template void CastStateValues<GLboolean>(Context *, GLenum, GLenum, unsigned int, GLboolean *);
template void CastStateValues<GLint>(Context *, GLenum, GLenum, unsigned int, GLint *);
......@@ -158,7 +224,7 @@ void CastIndexedStateValues(Context *context,
for (unsigned int i = 0; i < numParams; ++i)
{
outParams[i] = CastStateValue<QueryT>(pname, intParams[i]);
outParams[i] = CastFromStateValue<QueryT>(pname, intParams[i]);
}
}
else if (nativeType == GL_BOOL)
......@@ -179,7 +245,7 @@ void CastIndexedStateValues(Context *context,
for (unsigned int i = 0; i < numParams; ++i)
{
outParams[i] = CastStateValue<QueryT>(pname, int64Params[i]);
outParams[i] = CastFromStateValue<QueryT>(pname, int64Params[i]);
}
}
else
......
......@@ -18,7 +18,8 @@ class Context;
// Helper class for converting a GL type to a GLenum:
// We can't use CastStateValueEnum generally, because of GLboolean + GLubyte overlap.
// We restrict our use to CastStateValue, where it eliminates duplicate parameters.
// We restrict our use to CastFromStateValue and CastQueryValueTo, where it eliminates
// duplicate parameters.
template <typename GLType>
struct GLTypeToGLenum
......@@ -47,17 +48,45 @@ struct GLTypeToGLenum<GLint64>
static constexpr GLenum value = GL_INT_64_ANGLEX;
};
template <>
struct GLTypeToGLenum<GLuint64>
{
static constexpr GLenum value = GL_UINT_64_ANGLEX;
};
template <>
struct GLTypeToGLenum<GLfloat>
{
static constexpr GLenum value = GL_FLOAT;
};
// The GL state query API types are: bool, int, uint, float, int64
GLint CastMaskValue(const Context *context, GLuint value);
template <typename QueryT, typename InternalT>
QueryT CastFromGLintStateValue(GLenum pname, InternalT value);
template <typename QueryT, typename NativeT>
QueryT CastFromStateValue(GLenum pname, NativeT value);
template <typename NativeT, typename QueryT>
NativeT CastQueryValueTo(GLenum pname, QueryT value);
template <typename ParamType>
GLenum ConvertToGLenum(GLenum pname, ParamType param)
{
return static_cast<GLenum>(CastQueryValueTo<GLuint>(pname, param));
}
template <typename ParamType>
GLenum ConvertToGLenum(ParamType param)
{
return ConvertToGLenum(GL_NONE, param);
}
// The GL state query API types are: bool, int, uint, float, int64, uint64
template <typename QueryT>
void CastStateValues(Context *context, GLenum nativeType, GLenum pname,
unsigned int numParams, QueryT *outParams);
// The GL state query API types are: bool, int, uint, float, int64
// The GL state query API types are: bool, int, uint, float, int64, uint64
template <typename QueryT>
void CastIndexedStateValues(Context *context,
GLenum nativeType,
......
......@@ -21,6 +21,7 @@
#include "libANGLE/Uniform.h"
#include "libANGLE/VertexArray.h"
#include "libANGLE/formatutils.h"
#include "libANGLE/queryconversions.h"
#include "libANGLE/validationES2.h"
#include "libANGLE/validationES3.h"
......@@ -33,6 +34,7 @@ namespace gl
{
namespace
{
bool ValidateDrawAttribs(ValidationContext *context,
GLint primcount,
GLint maxVertex,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment