/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef WEBGLSTRONGTYPES_H_ #define WEBGLSTRONGTYPES_H_ #include "GLDefs.h" #include "mozilla/Assertions.h" #include "mozilla/ArrayUtils.h" // Usage: // =========== // // To create a new type from a set of GLenums do the following: // // STRONG_GLENUM_BEGIN(TypeName) // STRONG_GLENUM_VALUE(ENUM1), // STRONG_GLENUM_VALUE(ENUM2), // ... // STRONG_GLENUM_END() // // where TypeName is the name you want to give the type. Now simply use TypeName // instead of GLenum. The enum values must be given without GL_ prefix. // // ~~~~~~~~~~~~~~~~ // Important Notes: // ~~~~~~~~~~~~~~~~ // // Boolean operators (==, !=) are provided in an effort to prevent some mistakes // when using constants. For example we want to make sure that GL_ENUM_X is // a valid value for the type in code like: // // if (myNewType == STRONG_GLENUM_VALUE(SOME_ENUM)) // ... // // The operators will assert that STRONG_GLENUM_VALUE(SOME_ENUM) is a value that myNewType // can have. // // ---- // // A get() method is provided to allow access to the underlying GLenum. This // method should ideally only be called when passing parameters to the gl->fXXXX // functions, and be used very minimally everywhere else. // // Definitely XXX - DO NOT DO - XXX: // // if (myNewType.get() == STRONG_GLENUM_VALUE(SOME_ENUM)) // ... // // As that undermines the debug checks that were implemented in the ==, and != // operators. If you see code like this it should be treated with suspicion. // // Background: // =========== // // This macro is the first step in an effort to make the WebGL code safer. // Many of the different functions take GLenum as their parameter which leads // to bugs because of subtle differences in the enums purpose. For example there // are two types of 'texture targets'. One is the texture binding locations: // // GL_TEXTURE_2D // GL_TEXTURE_CUBE_MAP // // Yet, this is not the same as texture image targets: // // GL_TEXTURE_2D // GL_TEXTURE_CUBE_MAP_POSITIVE_X // GL_TEXTURE_CUBE_MAP_NEGATIVE_X // GL_TEXTURE_CUBE_MAP_POSITIVE_Y // ... // // This subtle distinction has already led to many bugs in the texture code // because of invalid assumptions about what type goes where. The macro below // is an attempt at fixing this by providing a small wrapper around GLenum that // validates its values. // // Comparison between STRONG_GLENUM's vs. enum classes // =================================================== // // The present STRONG_GLENUM's differ from ordinary enum classes // in that they assert at runtime that their values are legal, and in that they // allow implicit conversion from integers to STRONG_GLENUM's but disallow // implicit conversion from STRONG_GLENUM's to integers (enum classes are the opposite). // // When to use GLenum's vs. STRONG_GLENUM's vs. enum classes // ========================================================= // // Rule of thumb: // * For unchecked GLenum constants, such as WebGL method parameters that haven't been // validated yet, use GLenum. // * For already-validated GLenum constants, use STRONG_GLENUM's. // * For custom constants that aren't GL enum values, use enum classes. template class StrongGLenum MOZ_FINAL { private: static const GLenum NonexistantGLenum = 0xdeaddead; GLenum mValue; static void AssertOnceThatEnumValuesAreSorted() { #ifdef DEBUG static bool alreadyChecked = false; if (alreadyChecked) { return; } for (size_t i = 1; i < Details::valuesCount(); i++) { MOZ_ASSERT(Details::values()[i] > Details::values()[i - 1], "GLenum values should be sorted in ascending order"); } alreadyChecked = true; #endif } public: StrongGLenum(const StrongGLenum& other) : mValue(other.mValue) { AssertOnceThatEnumValuesAreSorted(); } StrongGLenum() #ifdef DEBUG : mValue(NonexistantGLenum) #endif { AssertOnceThatEnumValuesAreSorted(); } StrongGLenum(GLenum val) : mValue(val) { AssertOnceThatEnumValuesAreSorted(); MOZ_ASSERT(IsValueLegal(mValue)); } GLenum get() const { MOZ_ASSERT(mValue != NonexistantGLenum); return mValue; } bool operator==(const StrongGLenum& other) const { return get() == other.get(); } bool operator!=(const StrongGLenum& other) const { return get() != other.get(); } static bool IsValueLegal(GLenum value) { if (value > UINT16_MAX) { return false; } return std::binary_search(Details::values(), Details::values() + Details::valuesCount(), uint16_t(value)); } }; template bool operator==(GLenum a, StrongGLenum
b) { return a == b.get(); } template bool operator!=(GLenum a, StrongGLenum
b) { return a != b.get(); } template bool operator==(StrongGLenum
a, GLenum b) { return a.get() == b; } template bool operator!=(StrongGLenum
a, GLenum b) { return a.get() != b; } #define STRONG_GLENUM_BEGIN(NAME) \ const uint16_t NAME##Values[] = { #define STRONG_GLENUM_VALUE(VALUE) LOCAL_GL_##VALUE #define STRONG_GLENUM_END(NAME) \ }; \ struct NAME##Details { \ static size_t valuesCount() { return MOZ_ARRAY_LENGTH(NAME##Values); } \ static const uint16_t* values() { return NAME##Values; } \ }; \ typedef StrongGLenum NAME; /****************************************************************************** * Add your types after this comment *****************************************************************************/ STRONG_GLENUM_BEGIN(TexImageTarget) STRONG_GLENUM_VALUE(NONE), STRONG_GLENUM_VALUE(TEXTURE_2D), STRONG_GLENUM_VALUE(TEXTURE_3D), STRONG_GLENUM_VALUE(TEXTURE_CUBE_MAP_POSITIVE_X), STRONG_GLENUM_VALUE(TEXTURE_CUBE_MAP_NEGATIVE_X), STRONG_GLENUM_VALUE(TEXTURE_CUBE_MAP_POSITIVE_Y), STRONG_GLENUM_VALUE(TEXTURE_CUBE_MAP_NEGATIVE_Y), STRONG_GLENUM_VALUE(TEXTURE_CUBE_MAP_POSITIVE_Z), STRONG_GLENUM_VALUE(TEXTURE_CUBE_MAP_NEGATIVE_Z), STRONG_GLENUM_END(TexImageTarget) STRONG_GLENUM_BEGIN(TexTarget) STRONG_GLENUM_VALUE(NONE), STRONG_GLENUM_VALUE(TEXTURE_2D), STRONG_GLENUM_VALUE(TEXTURE_3D), STRONG_GLENUM_VALUE(TEXTURE_CUBE_MAP), STRONG_GLENUM_END(TexTarget) STRONG_GLENUM_BEGIN(TexType) STRONG_GLENUM_VALUE(NONE), STRONG_GLENUM_VALUE(BYTE), STRONG_GLENUM_VALUE(UNSIGNED_BYTE), STRONG_GLENUM_VALUE(SHORT), STRONG_GLENUM_VALUE(UNSIGNED_SHORT), STRONG_GLENUM_VALUE(INT), STRONG_GLENUM_VALUE(UNSIGNED_INT), STRONG_GLENUM_VALUE(FLOAT), STRONG_GLENUM_VALUE(HALF_FLOAT), STRONG_GLENUM_VALUE(UNSIGNED_SHORT_4_4_4_4), STRONG_GLENUM_VALUE(UNSIGNED_SHORT_5_5_5_1), STRONG_GLENUM_VALUE(UNSIGNED_SHORT_5_6_5), STRONG_GLENUM_VALUE(UNSIGNED_INT_2_10_10_10_REV), STRONG_GLENUM_VALUE(UNSIGNED_INT_24_8), STRONG_GLENUM_VALUE(UNSIGNED_INT_10F_11F_11F_REV), STRONG_GLENUM_VALUE(UNSIGNED_INT_5_9_9_9_REV), STRONG_GLENUM_VALUE(HALF_FLOAT_OES), STRONG_GLENUM_VALUE(FLOAT_32_UNSIGNED_INT_24_8_REV), STRONG_GLENUM_END(TexType) STRONG_GLENUM_BEGIN(TexFormat) STRONG_GLENUM_VALUE(NONE), STRONG_GLENUM_VALUE(DEPTH_COMPONENT), STRONG_GLENUM_VALUE(RED), STRONG_GLENUM_VALUE(ALPHA), STRONG_GLENUM_VALUE(RGB), STRONG_GLENUM_VALUE(RGBA), STRONG_GLENUM_VALUE(LUMINANCE), STRONG_GLENUM_VALUE(LUMINANCE_ALPHA), STRONG_GLENUM_VALUE(RG), STRONG_GLENUM_VALUE(SRGB), STRONG_GLENUM_VALUE(SRGB_ALPHA), STRONG_GLENUM_VALUE(RG_INTEGER), STRONG_GLENUM_VALUE(DEPTH_STENCIL), STRONG_GLENUM_VALUE(RED_INTEGER), STRONG_GLENUM_VALUE(RGB_INTEGER), STRONG_GLENUM_VALUE(RGBA_INTEGER), STRONG_GLENUM_END(TexFormat) STRONG_GLENUM_BEGIN(TexInternalFormat) STRONG_GLENUM_VALUE(NONE), STRONG_GLENUM_VALUE(DEPTH_COMPONENT), STRONG_GLENUM_VALUE(ALPHA), STRONG_GLENUM_VALUE(RGB), STRONG_GLENUM_VALUE(RGBA), STRONG_GLENUM_VALUE(LUMINANCE), STRONG_GLENUM_VALUE(LUMINANCE_ALPHA), STRONG_GLENUM_VALUE(RGB8), STRONG_GLENUM_VALUE(RGBA4), STRONG_GLENUM_VALUE(RGB5_A1), STRONG_GLENUM_VALUE(RGBA8), STRONG_GLENUM_VALUE(RGB10_A2), STRONG_GLENUM_VALUE(DEPTH_COMPONENT16), STRONG_GLENUM_VALUE(DEPTH_COMPONENT24), STRONG_GLENUM_VALUE(R8), STRONG_GLENUM_VALUE(RG8), STRONG_GLENUM_VALUE(R16F), STRONG_GLENUM_VALUE(R32F), STRONG_GLENUM_VALUE(RG16F), STRONG_GLENUM_VALUE(RG32F), STRONG_GLENUM_VALUE(R8I), STRONG_GLENUM_VALUE(R8UI), STRONG_GLENUM_VALUE(R16I), STRONG_GLENUM_VALUE(R16UI), STRONG_GLENUM_VALUE(R32I), STRONG_GLENUM_VALUE(R32UI), STRONG_GLENUM_VALUE(RG8I), STRONG_GLENUM_VALUE(RG8UI), STRONG_GLENUM_VALUE(RG16I), STRONG_GLENUM_VALUE(RG16UI), STRONG_GLENUM_VALUE(RG32I), STRONG_GLENUM_VALUE(RG32UI), STRONG_GLENUM_VALUE(COMPRESSED_RGB_S3TC_DXT1_EXT), STRONG_GLENUM_VALUE(COMPRESSED_RGBA_S3TC_DXT1_EXT), STRONG_GLENUM_VALUE(COMPRESSED_RGBA_S3TC_DXT3_EXT), STRONG_GLENUM_VALUE(COMPRESSED_RGBA_S3TC_DXT5_EXT), STRONG_GLENUM_VALUE(DEPTH_STENCIL), STRONG_GLENUM_VALUE(ATC_RGBA_INTERPOLATED_ALPHA), STRONG_GLENUM_VALUE(RGBA32F), STRONG_GLENUM_VALUE(RGB32F), STRONG_GLENUM_VALUE(RGBA16F), STRONG_GLENUM_VALUE(RGB16F), STRONG_GLENUM_VALUE(DEPTH24_STENCIL8), STRONG_GLENUM_VALUE(COMPRESSED_RGB_PVRTC_4BPPV1), STRONG_GLENUM_VALUE(COMPRESSED_RGB_PVRTC_2BPPV1), STRONG_GLENUM_VALUE(COMPRESSED_RGBA_PVRTC_4BPPV1), STRONG_GLENUM_VALUE(COMPRESSED_RGBA_PVRTC_2BPPV1), STRONG_GLENUM_VALUE(R11F_G11F_B10F), STRONG_GLENUM_VALUE(RGB9_E5), STRONG_GLENUM_VALUE(SRGB), STRONG_GLENUM_VALUE(SRGB8), STRONG_GLENUM_VALUE(SRGB_ALPHA), STRONG_GLENUM_VALUE(SRGB8_ALPHA8), STRONG_GLENUM_VALUE(ATC_RGB), STRONG_GLENUM_VALUE(ATC_RGBA_EXPLICIT_ALPHA), STRONG_GLENUM_VALUE(DEPTH_COMPONENT32F), STRONG_GLENUM_VALUE(DEPTH32F_STENCIL8), STRONG_GLENUM_VALUE(RGB565), STRONG_GLENUM_VALUE(ETC1_RGB8_OES), STRONG_GLENUM_VALUE(RGBA32UI), STRONG_GLENUM_VALUE(RGB32UI), STRONG_GLENUM_VALUE(RGBA16UI), STRONG_GLENUM_VALUE(RGB16UI), STRONG_GLENUM_VALUE(RGBA8UI), STRONG_GLENUM_VALUE(RGB8UI), STRONG_GLENUM_VALUE(RGBA32I), STRONG_GLENUM_VALUE(RGB32I), STRONG_GLENUM_VALUE(RGBA16I), STRONG_GLENUM_VALUE(RGB16I), STRONG_GLENUM_VALUE(RGBA8I), STRONG_GLENUM_VALUE(RGB8I), STRONG_GLENUM_VALUE(R8_SNORM), STRONG_GLENUM_VALUE(RG8_SNORM), STRONG_GLENUM_VALUE(RGB8_SNORM), STRONG_GLENUM_VALUE(RGBA8_SNORM), STRONG_GLENUM_VALUE(RGB10_A2UI), STRONG_GLENUM_END(TexInternalFormat) #endif