<NME> renderer_gl.cpp <BEF> /* * Copyright 2011-2022 Branimir Karadzic. All rights reserved. * License: https://github.com/bkaradzic/bgfx/blob/master/LICENSE */ #include "bgfx_p.h" #if (BGFX_CONFIG_RENDERER_OPENGLES || BGFX_CONFIG_RENDERER_OPENGL) # include "renderer_gl.h" # include <bx/timer.h> # include <bx/uint32_t.h> # include "emscripten.h" namespace bgfx { namespace gl { static char s_viewName[BGFX_CONFIG_MAX_VIEWS][BGFX_CONFIG_MAX_VIEW_NAME]; inline void setViewType(ViewId _view, const bx::StringView _str) { if (BX_ENABLED(BGFX_CONFIG_DEBUG_ANNOTATION || BGFX_CONFIG_PROFILER) ) { bx::memCopy(&s_viewName[_view][3], _str.getPtr(), _str.getLength() ); } } struct PrimInfo { GLenum m_type; uint32_t m_min; uint32_t m_div; uint32_t m_sub; }; static const PrimInfo s_primInfo[] = { { GL_TRIANGLES, 3, 3, 0 }, { GL_TRIANGLE_STRIP, 3, 1, 2 }, { GL_LINES, 2, 2, 0 }, { GL_LINE_STRIP, 2, 1, 1 }, { GL_POINTS, 1, 1, 0 }, { GL_ZERO, 0, 0, 0 }, }; BX_STATIC_ASSERT(Topology::Count == BX_COUNTOF(s_primInfo)-1); static const char* s_attribName[] = { "a_position", "a_normal", "a_tangent", "a_bitangent", "a_color0", "a_color1", "a_color2", "a_color3", "a_indices", "a_weight", "a_texcoord0", "a_texcoord1", "a_texcoord2", "a_texcoord3", "a_texcoord4", "a_texcoord5", "a_texcoord6", "a_texcoord7", }; BX_STATIC_ASSERT(Attrib::Count == BX_COUNTOF(s_attribName) ); static const char* s_instanceDataName[] = { "i_data0", "i_data1", "i_data2", "i_data3", "i_data4", }; BX_STATIC_ASSERT(BGFX_CONFIG_MAX_INSTANCE_DATA_COUNT == BX_COUNTOF(s_instanceDataName) ); static const GLenum s_access[] = { GL_READ_ONLY, GL_WRITE_ONLY, GL_READ_WRITE, }; BX_STATIC_ASSERT(Access::Count == BX_COUNTOF(s_access) ); static const GLenum s_attribType[] = { GL_UNSIGNED_BYTE, // Uint8 GL_UNSIGNED_INT_10_10_10_2, // Uint10 GL_SHORT, // Int16 GL_HALF_FLOAT, // Half GL_FLOAT, // Float }; BX_STATIC_ASSERT(AttribType::Count == BX_COUNTOF(s_attribType) ); struct Blend { GLenum m_src; GLenum m_dst; bool m_factor; }; static const Blend s_blendFactor[] = { { 0, 0, false }, // ignored { GL_ZERO, GL_ZERO, false }, // ZERO { GL_ONE, GL_ONE, false }, // ONE { GL_SRC_COLOR, GL_SRC_COLOR, false }, // SRC_COLOR { GL_ONE_MINUS_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR, false }, // INV_SRC_COLOR { GL_SRC_ALPHA, GL_SRC_ALPHA, false }, // SRC_ALPHA { GL_ONE_MINUS_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, false }, // INV_SRC_ALPHA { GL_DST_ALPHA, GL_DST_ALPHA, false }, // DST_ALPHA { GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_DST_ALPHA, false }, // INV_DST_ALPHA { GL_DST_COLOR, GL_DST_COLOR, false }, // DST_COLOR { GL_ONE_MINUS_DST_COLOR, GL_ONE_MINUS_DST_COLOR, false }, // INV_DST_COLOR { GL_SRC_ALPHA_SATURATE, GL_ONE, false }, // SRC_ALPHA_SAT { GL_CONSTANT_COLOR, GL_CONSTANT_COLOR, true }, // FACTOR { GL_ONE_MINUS_CONSTANT_COLOR, GL_ONE_MINUS_CONSTANT_COLOR, true }, // INV_FACTOR }; static const GLenum s_blendEquation[] = { GL_FUNC_ADD, GL_FUNC_SUBTRACT, GL_FUNC_REVERSE_SUBTRACT, GL_MIN, GL_MAX, }; static const GLenum s_cmpFunc[] = { 0, // ignored GL_LESS, GL_LEQUAL, GL_EQUAL, GL_GEQUAL, GL_GREATER, GL_NOTEQUAL, GL_NEVER, GL_ALWAYS, }; static const GLenum s_stencilOp[] = { GL_ZERO, GL_KEEP, GL_REPLACE, GL_INCR_WRAP, GL_INCR, GL_DECR_WRAP, GL_DECR, GL_INVERT, }; static const GLenum s_stencilFace[] = { GL_FRONT_AND_BACK, GL_FRONT, GL_BACK, }; static GLenum s_textureAddress[] = { GL_REPEAT, GL_MIRRORED_REPEAT, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_BORDER, }; static const GLenum s_textureFilterMag[] = { GL_LINEAR, GL_NEAREST, GL_LINEAR, }; static const GLenum s_textureFilterMin[][3] = { { GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR_MIPMAP_NEAREST }, { GL_NEAREST, GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST_MIPMAP_NEAREST }, { GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR_MIPMAP_NEAREST }, }; struct TextureFormatInfo { GLenum m_internalFmt; GLenum m_internalFmtSrgb; GLenum m_fmt; GLenum m_fmtSrgb; GLenum m_type; bool m_supported; GLint m_mapping[4]; }; // In desktop OpenGL 4+ and OpenGL ES 3.0+, specific GL formats GL_x_INTEGER are used for integer textures. // For older desktop OpenGL contexts, GL names without _INTEGER suffix were used. // See http://docs.gl/gl4/glTexImage2D, http://docs.gl/gl3/glTexImage2D, http://docs.gl/es3/glTexImage2D #if BGFX_CONFIG_RENDERER_OPENGL >= 40 || BGFX_CONFIG_RENDERER_OPENGLES # define RED_INTEGER GL_RED_INTEGER # define RG_INTEGER GL_RG_INTEGER # define RGB_INTEGER GL_RGB_INTEGER # define RGBA_INTEGER GL_RGBA_INTEGER #else # define RED_INTEGER GL_RED # define RG_INTEGER GL_RG # define RGB_INTEGER GL_RGB # define RGBA_INTEGER GL_RGBA #endif static TextureFormatInfo s_textureFormat[] = { #define $_ -1 #define $0 GL_ZERO #define $1 GL_ONE #define $R GL_RED #define $G GL_GREEN #define $B GL_BLUE #define $A GL_ALPHA { GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, GL_ZERO, false, { $_, $_, $_, $_ } }, // BC1 { GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, GL_ZERO, false, { $_, $_, $_, $_ } }, // BC2 { GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_ZERO, false, { $_, $_, $_, $_ } }, // BC3 { GL_COMPRESSED_LUMINANCE_LATC1_EXT, GL_ZERO, GL_COMPRESSED_LUMINANCE_LATC1_EXT, GL_COMPRESSED_LUMINANCE_LATC1_EXT, GL_ZERO, false, { $_, $_, $_, $_ } }, // BC4 { GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT, GL_ZERO, GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT, GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT, GL_ZERO, false, { $_, $_, $_, $_ } }, // BC5 { GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB, GL_ZERO, GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB, GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB, GL_ZERO, false, { $_, $_, $_, $_ } }, // BC6H { GL_COMPRESSED_RGBA_BPTC_UNORM_ARB, GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB, GL_COMPRESSED_RGBA_BPTC_UNORM_ARB, GL_COMPRESSED_RGBA_BPTC_UNORM_ARB, GL_ZERO, false, { $_, $_, $_, $_ } }, // BC7 { GL_ETC1_RGB8_OES, GL_ZERO, GL_ETC1_RGB8_OES, GL_ETC1_RGB8_OES, GL_ZERO, false, { $_, $_, $_, $_ } }, // ETC1 { GL_COMPRESSED_RGB8_ETC2, GL_ZERO, GL_COMPRESSED_RGB8_ETC2, GL_COMPRESSED_RGB8_ETC2, GL_ZERO, false, { $_, $_, $_, $_ } }, // ETC2 { GL_COMPRESSED_RGBA8_ETC2_EAC, GL_COMPRESSED_SRGB8_ETC2, GL_COMPRESSED_RGBA8_ETC2_EAC, GL_COMPRESSED_RGBA8_ETC2_EAC, GL_ZERO, false, { $_, $_, $_, $_ } }, // ETC2A { GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2, GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2, GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2, GL_ZERO, false, { $_, $_, $_, $_ } }, // ETC2A1 { GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG, GL_COMPRESSED_SRGB_PVRTC_2BPPV1_EXT, GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG, GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG, GL_ZERO, false, { $_, $_, $_, $_ } }, // PTC12 { GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG, GL_COMPRESSED_SRGB_PVRTC_4BPPV1_EXT, GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG, GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG, GL_ZERO, false, { $_, $_, $_, $_ } }, // PTC14 { GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG, GL_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV1_EXT, GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG, GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG, GL_ZERO, false, { $_, $_, $_, $_ } }, // PTC12A { GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG, GL_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV1_EXT, GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG, GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG, GL_ZERO, false, { $_, $_, $_, $_ } }, // PTC14A { GL_COMPRESSED_RGBA_PVRTC_2BPPV2_IMG, GL_ZERO, GL_COMPRESSED_RGBA_PVRTC_2BPPV2_IMG, GL_COMPRESSED_RGBA_PVRTC_2BPPV2_IMG, GL_ZERO, false, { $_, $_, $_, $_ } }, // PTC22 { GL_COMPRESSED_RGBA_PVRTC_4BPPV2_IMG, GL_ZERO, GL_COMPRESSED_RGBA_PVRTC_4BPPV2_IMG, GL_COMPRESSED_RGBA_PVRTC_4BPPV2_IMG, GL_ZERO, false, { $_, $_, $_, $_ } }, // PTC24 { GL_ATC_RGB_AMD, GL_ZERO, GL_ATC_RGB_AMD, GL_ATC_RGB_AMD, GL_ZERO, false, { $_, $_, $_, $_ } }, // ATC { GL_ATC_RGBA_EXPLICIT_ALPHA_AMD, GL_ZERO, GL_ATC_RGBA_EXPLICIT_ALPHA_AMD, GL_ATC_RGBA_EXPLICIT_ALPHA_AMD, GL_ZERO, false, { $_, $_, $_, $_ } }, // ATCE { GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD, GL_ZERO, GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD, GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD, GL_ZERO, false, { $_, $_, $_, $_ } }, // ATCI { GL_COMPRESSED_RGBA_ASTC_4x4_KHR, GL_COMPRESSED_SRGB8_ASTC_4x4_KHR, GL_COMPRESSED_RGBA_ASTC_4x4_KHR, GL_COMPRESSED_RGBA_ASTC_4x4_KHR, GL_ZERO, false, { $_, $_, $_, $_ } }, // ASTC4x4 { GL_COMPRESSED_RGBA_ASTC_5x4_KHR, GL_COMPRESSED_SRGB8_ASTC_5x4_KHR, GL_COMPRESSED_RGBA_ASTC_5x4_KHR, GL_COMPRESSED_RGBA_ASTC_5x4_KHR, GL_ZERO, false, { $_, $_, $_, $_ } }, // ASTC5x4 { GL_COMPRESSED_RGBA_ASTC_5x5_KHR, GL_COMPRESSED_SRGB8_ASTC_5x5_KHR, GL_COMPRESSED_RGBA_ASTC_5x5_KHR, GL_COMPRESSED_RGBA_ASTC_5x5_KHR, GL_ZERO, false, { $_, $_, $_, $_ } }, // ASTC5x5 { GL_COMPRESSED_RGBA_ASTC_6x5_KHR, GL_COMPRESSED_SRGB8_ASTC_6x5_KHR, GL_COMPRESSED_RGBA_ASTC_6x5_KHR, GL_COMPRESSED_RGBA_ASTC_6x5_KHR, GL_ZERO, false, { $_, $_, $_, $_ } }, // ASTC6x5 { GL_COMPRESSED_RGBA_ASTC_6x6_KHR, GL_COMPRESSED_SRGB8_ASTC_6x6_KHR, GL_COMPRESSED_RGBA_ASTC_6x6_KHR, GL_COMPRESSED_RGBA_ASTC_6x6_KHR, GL_ZERO, false, { $_, $_, $_, $_ } }, // ASTC6x6 { GL_COMPRESSED_RGBA_ASTC_8x5_KHR, GL_COMPRESSED_SRGB8_ASTC_8x5_KHR, GL_COMPRESSED_RGBA_ASTC_8x5_KHR, GL_COMPRESSED_RGBA_ASTC_8x5_KHR, GL_ZERO, false, { $_, $_, $_, $_ } }, // ASTC8x5 { GL_COMPRESSED_RGBA_ASTC_8x6_KHR, GL_COMPRESSED_SRGB8_ASTC_8x6_KHR, GL_COMPRESSED_RGBA_ASTC_8x6_KHR, GL_COMPRESSED_RGBA_ASTC_8x6_KHR, GL_ZERO, false, { $_, $_, $_, $_ } }, // ASTC8x6 { GL_COMPRESSED_RGBA_ASTC_8x8_KHR, GL_COMPRESSED_SRGB8_ASTC_8x8_KHR, GL_COMPRESSED_RGBA_ASTC_8x8_KHR, GL_COMPRESSED_RGBA_ASTC_8x8_KHR, GL_ZERO, false, { $_, $_, $_, $_ } }, // ASTC8x8 { GL_COMPRESSED_RGBA_ASTC_10x5_KHR, GL_COMPRESSED_SRGB8_ASTC_10x5_KHR, GL_COMPRESSED_RGBA_ASTC_10x5_KHR, GL_COMPRESSED_RGBA_ASTC_10x5_KHR, GL_ZERO, false, { $_, $_, $_, $_ } }, // ASTC10x5 { GL_COMPRESSED_RGBA_ASTC_10x6_KHR, GL_COMPRESSED_SRGB8_ASTC_10x6_KHR, GL_COMPRESSED_RGBA_ASTC_10x6_KHR, GL_COMPRESSED_RGBA_ASTC_10x6_KHR, GL_ZERO, false, { $_, $_, $_, $_ } }, // ASTC10x6 { GL_COMPRESSED_RGBA_ASTC_10x8_KHR, GL_COMPRESSED_SRGB8_ASTC_10x8_KHR, GL_COMPRESSED_RGBA_ASTC_10x8_KHR, GL_COMPRESSED_RGBA_ASTC_10x8_KHR, GL_ZERO, false, { $_, $_, $_, $_ } }, // ASTC10x8 { GL_COMPRESSED_RGBA_ASTC_10x10_KHR, GL_COMPRESSED_SRGB8_ASTC_10x10_KHR, GL_COMPRESSED_RGBA_ASTC_10x10_KHR, GL_COMPRESSED_RGBA_ASTC_10x10_KHR, GL_ZERO, false, { $_, $_, $_, $_ } }, // ASTC10x10 { GL_COMPRESSED_RGBA_ASTC_12x10_KHR, GL_COMPRESSED_SRGB8_ASTC_12x10_KHR, GL_COMPRESSED_RGBA_ASTC_12x10_KHR, GL_COMPRESSED_RGBA_ASTC_12x10_KHR, GL_ZERO, false, { $_, $_, $_, $_ } }, // ASTC12x10 { GL_COMPRESSED_RGBA_ASTC_12x12_KHR, GL_COMPRESSED_SRGB8_ASTC_12x12_KHR, GL_COMPRESSED_RGBA_ASTC_12x12_KHR, GL_COMPRESSED_RGBA_ASTC_12x12_KHR, GL_ZERO, false, { $_, $_, $_, $_ } }, // ASTC12x12 { GL_ZERO, GL_ZERO, GL_ZERO, GL_ZERO, GL_ZERO, false, { $_, $_, $_, $_ } }, // Unknown { GL_ZERO, GL_ZERO, GL_ZERO, GL_ZERO, GL_ZERO, false, { $_, $_, $_, $_ } }, // R1 { GL_ALPHA, GL_ZERO, GL_ALPHA, GL_ALPHA, GL_UNSIGNED_BYTE, false, { $_, $_, $_, $_ } }, // A8 { GL_R8, GL_ZERO, GL_RED, GL_RED, GL_UNSIGNED_BYTE, false, { $_, $_, $_, $_ } }, // R8 { GL_R8I, GL_ZERO, RED_INTEGER, GL_RED_INTEGER, GL_BYTE, false, { $_, $_, $_, $_ } }, // R8I { GL_R8UI, GL_ZERO, RED_INTEGER, GL_RED_INTEGER, GL_UNSIGNED_BYTE, false, { $_, $_, $_, $_ } }, // R8U { GL_R8_SNORM, GL_ZERO, GL_RED, GL_RED, GL_BYTE, false, { $_, $_, $_, $_ } }, // R8S { GL_R16, GL_ZERO, GL_RED, GL_RED, GL_UNSIGNED_SHORT, false, { $_, $_, $_, $_ } }, // R16 { GL_R16I, GL_ZERO, RED_INTEGER, GL_RED_INTEGER, GL_SHORT, false, { $_, $_, $_, $_ } }, // R16I { GL_R16UI, GL_ZERO, RED_INTEGER, GL_RED_INTEGER, GL_UNSIGNED_SHORT, false, { $_, $_, $_, $_ } }, // R16U { GL_R16F, GL_ZERO, GL_RED, GL_RED, GL_HALF_FLOAT, false, { $_, $_, $_, $_ } }, // R16F { GL_R16_SNORM, GL_ZERO, GL_RED, GL_RED, GL_SHORT, false, { $_, $_, $_, $_ } }, // R16S { GL_R32I, GL_ZERO, RED_INTEGER, GL_RED_INTEGER, GL_INT, false, { $_, $_, $_, $_ } }, // R32I { GL_R32UI, GL_ZERO, RED_INTEGER, GL_RED_INTEGER, GL_UNSIGNED_INT, false, { $_, $_, $_, $_ } }, // R32U { GL_R32F, GL_ZERO, GL_RED, GL_RED, GL_FLOAT, false, { $_, $_, $_, $_ } }, // R32F { GL_RG8, GL_ZERO, GL_RG, GL_RG, GL_UNSIGNED_BYTE, false, { $_, $_, $_, $_ } }, // RG8 { GL_RG8I, GL_ZERO, RG_INTEGER, GL_RG_INTEGER, GL_BYTE, false, { $_, $_, $_, $_ } }, // RG8I { GL_RG8UI, GL_ZERO, RG_INTEGER, GL_RG_INTEGER, GL_UNSIGNED_BYTE, false, { $_, $_, $_, $_ } }, // RG8U { GL_RG8_SNORM, GL_ZERO, GL_RG, GL_RG, GL_BYTE, false, { $_, $_, $_, $_ } }, // RG8S { GL_RG16, GL_ZERO, GL_RG, GL_RG, GL_UNSIGNED_SHORT, false, { $_, $_, $_, $_ } }, // RG16 { GL_RG16I, GL_ZERO, RG_INTEGER, GL_RG_INTEGER, GL_SHORT, false, { $_, $_, $_, $_ } }, // RG16I { GL_RG16UI, GL_ZERO, RG_INTEGER, GL_RG_INTEGER, GL_UNSIGNED_SHORT, false, { $_, $_, $_, $_ } }, // RG16U { GL_RG16F, GL_ZERO, GL_RG, GL_RG, GL_HALF_FLOAT, false, { $_, $_, $_, $_ } }, // RG16F { GL_RG16_SNORM, GL_ZERO, GL_RG, GL_RG, GL_SHORT, false, { $_, $_, $_, $_ } }, // RG16S { GL_RG32I, GL_ZERO, RG_INTEGER, GL_RG_INTEGER, GL_INT, false, { $_, $_, $_, $_ } }, // RG32I { GL_RG32UI, GL_ZERO, RG_INTEGER, GL_RG_INTEGER, GL_UNSIGNED_INT, false, { $_, $_, $_, $_ } }, // RG32U { GL_RG32F, GL_ZERO, GL_RG, GL_RG, GL_FLOAT, false, { $_, $_, $_, $_ } }, // RG32F { GL_RGB8, GL_SRGB8, GL_RGB, GL_RGB, GL_UNSIGNED_BYTE, false, { $_, $_, $_, $_ } }, // RGB8 { GL_RGB8I, GL_ZERO, RGB_INTEGER, GL_RGB_INTEGER, GL_BYTE, false, { $_, $_, $_, $_ } }, // RGB8I { GL_RGB8UI, GL_ZERO, RGB_INTEGER, GL_RGB_INTEGER, GL_UNSIGNED_BYTE, false, { $_, $_, $_, $_ } }, // RGB8U { GL_RGB8_SNORM, GL_ZERO, GL_RGB, GL_RGB, GL_BYTE, false, { $_, $_, $_, $_ } }, // RGB8S { GL_RGB9_E5, GL_ZERO, GL_RGB, GL_RGB, GL_UNSIGNED_INT_5_9_9_9_REV, false, { $_, $_, $_, $_ } }, // RGB9E5F { GL_RGBA8, GL_SRGB8_ALPHA8, GL_BGRA, GL_BGRA, GL_UNSIGNED_BYTE, false, { $_, $_, $_, $_ } }, // BGRA8 { GL_RGBA8, GL_SRGB8_ALPHA8, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, false, { $_, $_, $_, $_ } }, // RGBA8 { GL_RGBA8I, GL_ZERO, RGBA_INTEGER, GL_RGBA_INTEGER, GL_BYTE, false, { $_, $_, $_, $_ } }, // RGBA8I { GL_RGBA8UI, GL_ZERO, RGBA_INTEGER, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE, false, { $_, $_, $_, $_ } }, // RGBA8U { GL_RGBA8_SNORM, GL_ZERO, GL_RGBA, GL_RGBA, GL_BYTE, false, { $_, $_, $_, $_ } }, // RGBA8S { GL_RGBA16, GL_ZERO, GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT, false, { $_, $_, $_, $_ } }, // RGBA16 { GL_RGBA16I, GL_ZERO, RGBA_INTEGER, GL_RGBA_INTEGER, GL_SHORT, false, { $_, $_, $_, $_ } }, // RGBA16I { GL_RGBA16UI, GL_ZERO, RGBA_INTEGER, GL_RGBA_INTEGER, GL_UNSIGNED_SHORT, false, { $_, $_, $_, $_ } }, // RGBA16U { GL_RGBA16F, GL_ZERO, GL_RGBA, GL_RGBA, GL_HALF_FLOAT, false, { $_, $_, $_, $_ } }, // RGBA16F { GL_RGBA16_SNORM, GL_ZERO, GL_RGBA, GL_RGBA, GL_SHORT, false, { $_, $_, $_, $_ } }, // RGBA16S { GL_RGBA32I, GL_ZERO, RGBA_INTEGER, GL_RGBA_INTEGER, GL_INT, false, { $_, $_, $_, $_ } }, // RGBA32I { GL_RGBA32UI, GL_ZERO, RGBA_INTEGER, GL_RGBA_INTEGER, GL_UNSIGNED_INT, false, { $_, $_, $_, $_ } }, // RGBA32U { GL_RGBA32F, GL_ZERO, GL_RGBA, GL_RGBA, GL_FLOAT, false, { $_, $_, $_, $_ } }, // RGBA32F { GL_RGB565, GL_ZERO, GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, false, { $_, $_, $_, $_ } }, // B5G6R5 { GL_RGB565, GL_ZERO, GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, false, { $_, $_, $_, $_ } }, // R5G6B5 { GL_RGBA4, GL_ZERO, GL_BGRA, GL_BGRA, GL_UNSIGNED_SHORT_4_4_4_4_REV, false, { $_, $_, $_, $_ } }, // BGRA4 { GL_RGBA4, GL_ZERO, GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4_REV, false, { $_, $_, $_, $_ } }, // RGBA4 { GL_RGB5_A1, GL_ZERO, GL_BGRA, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV, false, { $_, $_, $_, $_ } }, // BGR5A1 { GL_RGB5_A1, GL_ZERO, GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, false, { $_, $_, $_, $_ } }, // RGB5A1 { GL_RGB10_A2, GL_ZERO, GL_RGBA, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, false, { $_, $_, $_, $_ } }, // RGB10A2 { GL_R11F_G11F_B10F, GL_ZERO, GL_RGB, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV, false, { $_, $_, $_, $_ } }, // RG11B10F { GL_ZERO, GL_ZERO, GL_ZERO, GL_ZERO, GL_ZERO, false, { $_, $_, $_, $_ } }, // UnknownDepth { GL_DEPTH_COMPONENT16, GL_ZERO, GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, false, { $_, $_, $_, $_ } }, // D16 { GL_DEPTH_COMPONENT24, GL_ZERO, GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, false, { $_, $_, $_, $_ } }, // D24 { GL_DEPTH24_STENCIL8, GL_ZERO, GL_DEPTH_STENCIL, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, false, { $_, $_, $_, $_ } }, // D24S8 { GL_DEPTH_COMPONENT32, GL_ZERO, GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, false, { $_, $_, $_, $_ } }, // D32 { GL_DEPTH_COMPONENT32F, GL_ZERO, GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_FLOAT, false, { $_, $_, $_, $_ } }, // D16F { GL_DEPTH_COMPONENT32F, GL_ZERO, GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_FLOAT, false, { $_, $_, $_, $_ } }, // D24F { GL_DEPTH_COMPONENT32F, GL_ZERO, GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_FLOAT, false, { $_, $_, $_, $_ } }, // D32F { GL_STENCIL_INDEX8, GL_ZERO, GL_STENCIL_INDEX, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, false, { $_, $_, $_, $_ } }, // D0S8 #undef $_ #undef $0 #undef $1 #undef $R #undef $G #undef $B #undef $A }; BX_STATIC_ASSERT(TextureFormat::Count == BX_COUNTOF(s_textureFormat) ); static bool s_textureFilter[TextureFormat::Count+1]; static GLenum s_rboFormat[] = { GL_ZERO, // BC1 GL_ZERO, // BC2 GL_ZERO, // BC3 GL_ZERO, // BC4 GL_ZERO, // BC5 GL_ZERO, // BC6H GL_ZERO, // BC7 GL_ZERO, // ETC1 GL_ZERO, // ETC2 GL_ZERO, // ETC2A GL_ZERO, // ETC2A1 GL_ZERO, // PTC12 GL_ZERO, // PTC14 GL_ZERO, // PTC12A GL_ZERO, // PTC14A GL_ZERO, // PTC22 GL_ZERO, // PTC24 GL_ZERO, // ATC GL_ZERO, // ATCE GL_ZERO, // ATCI GL_ZERO, // ASTC4x4 GL_ZERO, // ASTC5x4 GL_ZERO, // ASTC5x5 GL_ZERO, // ASTC6x5 GL_ZERO, // ASTC6x6 GL_ZERO, // ASTC8x5 GL_ZERO, // ASTC8x6 GL_ZERO, // ASTC8x8 GL_ZERO, // ASTC10x5 GL_ZERO, // ASTC10x6 GL_ZERO, // ASTC10x8 GL_ZERO, // ASTC10x10 GL_ZERO, // ASTC12x10 GL_ZERO, // ASTC12x12 GL_ZERO, // Unknown GL_ZERO, // R1 GL_ALPHA, // A8 GL_R8, // R8 GL_R8I, // R8I GL_R8UI, // R8U GL_R8_SNORM, // R8S GL_R16, // R16 GL_R16I, // R16I GL_R16UI, // R16U GL_R16F, // R16F GL_R16_SNORM, // R16S GL_R32I, // R32I GL_R32UI, // R32U GL_R32F, // R32F GL_RG8, // RG8 GL_RG8I, // RG8I GL_RG8UI, // RG8U GL_RG8_SNORM, // RG8S GL_RG16, // RG16 GL_RG16I, // RG16I GL_RG16UI, // RG16U GL_RG16F, // RG16F GL_RG16_SNORM, // RG16S GL_RG32I, // RG32I GL_RG32UI, // RG32U GL_RG32F, // RG32F GL_RGB8, // RGB8 GL_RGB8I, // RGB8I GL_RGB8UI, // RGB8UI GL_RGB8_SNORM, // RGB8S GL_RGB9_E5, // RGB9E5F GL_RGBA8, // BGRA8 GL_RGBA8, // RGBA8 GL_RGBA8I, // RGBA8I GL_RGBA8UI, // RGBA8UI GL_RGBA8_SNORM, // RGBA8S GL_RGBA16, // RGBA16 GL_RGBA16I, // RGBA16I GL_RGBA16UI, // RGBA16U GL_RGBA16F, // RGBA16F GL_RGBA16_SNORM, // RGBA16S GL_RGBA32I, // RGBA32I GL_RGBA32UI, // RGBA32U GL_RGBA32F, // RGBA32F GL_RGB565, // B5G6R5 GL_RGB565, // R5G6B5 GL_RGBA4, // BGRA4 GL_RGBA4, // RGBA4 GL_RGB5_A1, // BGR5A1 GL_RGB5_A1, // RGB5A1 GL_RGB10_A2, // RGB10A2 GL_R11F_G11F_B10F, // RG11B10F GL_ZERO, // UnknownDepth GL_DEPTH_COMPONENT16, // D16 GL_DEPTH_COMPONENT24, // D24 GL_DEPTH24_STENCIL8, // D24S8 GL_DEPTH_COMPONENT32, // D32 GL_DEPTH_COMPONENT32F, // D16F GL_DEPTH_COMPONENT32F, // D24F GL_DEPTH_COMPONENT32F, // D32F GL_STENCIL_INDEX8, // D0S8 }; BX_STATIC_ASSERT(TextureFormat::Count == BX_COUNTOF(s_rboFormat) ); static GLenum s_imageFormat[] = { GL_ZERO, // BC1 GL_ZERO, // BC2 GL_ZERO, // BC3 GL_ZERO, // BC4 GL_ZERO, // BC5 GL_ZERO, // BC6H GL_ZERO, // BC7 GL_ZERO, // ETC1 GL_ZERO, // ETC2 GL_ZERO, // ETC2A GL_ZERO, // ETC2A1 GL_ZERO, // PTC12 GL_ZERO, // PTC14 GL_ZERO, // PTC12A GL_ZERO, // PTC14A GL_ZERO, // PTC22 GL_ZERO, // PTC24 GL_ZERO, // ATC GL_ZERO, // ATCE GL_ZERO, // ATCI GL_ZERO, // ASTC4x4 GL_ZERO, // ASTC5x4 GL_ZERO, // ASTC5x5 GL_ZERO, // ASTC6x5 GL_ZERO, // ASTC6x6 GL_ZERO, // ASTC8x5 GL_ZERO, // ASTC8x6 GL_ZERO, // ASTC8x8 GL_ZERO, // ASTC10x5 GL_ZERO, // ASTC10x6 GL_ZERO, // ASTC10x8 GL_ZERO, // ASTC10x10 GL_ZERO, // ASTC12x10 GL_ZERO, // ASTC12x12 GL_ZERO, // Unknown GL_ZERO, // R1 GL_ALPHA, // A8 GL_R8, // R8 GL_R8I, // R8I GL_R8UI, // R8UI GL_R8_SNORM, // R8S GL_R16, // R16 GL_R16I, // R16I GL_R16UI, // R16U GL_R16F, // R16F GL_R16_SNORM, // R16S GL_R32I, // R32I GL_R32UI, // R32U GL_R32F, // R32F GL_RG8, // RG8 GL_RG8I, // RG8I GL_RG8UI, // RG8U GL_RG8_SNORM, // RG8S GL_RG16, // RG16 GL_RG16I, // RG16I GL_RG16UI, // RG16U GL_RG16F, // RG16F GL_RG16_SNORM, // RG16S GL_RG32I, // RG32I GL_RG32UI, // RG32U GL_RG32F, // RG32F GL_RGB8, // RGB8 GL_RGB8I, // RGB8I GL_RGB8UI, // RGB8UI GL_RGB8_SNORM, // RGB8S GL_RGB9_E5, // RGB9E5F GL_RGBA8, // BGRA8 GL_RGBA8, // RGBA8 GL_RGBA8I, // RGBA8I GL_RGBA8UI, // RGBA8UI GL_RGBA8_SNORM, // RGBA8S GL_RGBA16, // RGBA16 GL_RGBA16I, // RGBA16I GL_RGBA16UI, // RGBA16U GL_RGBA16F, // RGBA16F GL_RGBA16_SNORM, // RGBA16S GL_RGBA32I, // RGBA32I GL_RGBA32UI, // RGBA32U GL_RGBA32F, // RGBA32F GL_RGB565, // B5G6R5 GL_RGB565, // R5G6B5 GL_RGBA4, // BGRA4 GL_RGBA4, // RGBA4 GL_RGB5_A1, // BGR5A1 GL_RGB5_A1, // RGB5A1 GL_RGB10_A2, // RGB10A2 GL_R11F_G11F_B10F, // RG11B10F GL_ZERO, // UnknownDepth GL_ZERO, // D16 GL_ZERO, // D24 GL_ZERO, // D24S8 GL_ZERO, // D32 GL_ZERO, // D16F GL_ZERO, // D24F GL_ZERO, // D32F GL_ZERO, // D0S8 }; BX_STATIC_ASSERT(TextureFormat::Count == BX_COUNTOF(s_imageFormat) ); struct Extension { enum Enum { AMD_conservative_depth, AMD_multi_draw_indirect, ANGLE_depth_texture, ANGLE_framebuffer_blit, ANGLE_framebuffer_multisample, ANGLE_instanced_arrays, ANGLE_texture_compression_dxt1, ANGLE_texture_compression_dxt3, ANGLE_texture_compression_dxt5, ANGLE_timer_query, ANGLE_translated_shader_source, APPLE_texture_format_BGRA8888, APPLE_texture_max_level, ARB_clip_control, ARB_compute_shader, ARB_conservative_depth, ARB_copy_image, ARB_debug_label, ARB_debug_output, ARB_depth_buffer_float, ARB_depth_clamp, ARB_draw_buffers_blend, ARB_draw_indirect, ARB_draw_instanced, ARB_ES3_compatibility, ARB_framebuffer_object, ARB_framebuffer_sRGB, ARB_get_program_binary, ARB_half_float_pixel, ARB_half_float_vertex, ARB_indirect_parameters, ARB_instanced_arrays, ARB_internalformat_query, ARB_internalformat_query2, ARB_invalidate_subdata, ARB_map_buffer_range, ARB_multi_draw_indirect, ARB_multisample, ARB_occlusion_query, ARB_occlusion_query2, ARB_program_interface_query, ARB_provoking_vertex, ARB_sampler_objects, ARB_seamless_cube_map, ARB_shader_bit_encoding, ARB_shader_image_load_store, ARB_shader_storage_buffer_object, ARB_shader_texture_lod, ARB_shader_viewport_layer_array, ARB_texture_compression_bptc, ARB_texture_compression_rgtc, ARB_texture_cube_map_array, ARB_texture_float, ARB_texture_multisample, ARB_texture_rg, ARB_texture_rgb10_a2ui, ARB_texture_stencil8, ARB_texture_storage, ARB_texture_swizzle, ARB_timer_query, ARB_uniform_buffer_object, ARB_vertex_array_object, ARB_vertex_type_2_10_10_10_rev, ATI_meminfo, CHROMIUM_color_buffer_float_rgb, CHROMIUM_color_buffer_float_rgba, CHROMIUM_depth_texture, CHROMIUM_framebuffer_multisample, CHROMIUM_texture_compression_dxt3, CHROMIUM_texture_compression_dxt5, EXT_bgra, EXT_blend_color, EXT_blend_minmax, EXT_blend_subtract, EXT_color_buffer_half_float, EXT_color_buffer_float, EXT_copy_image, EXT_compressed_ETC1_RGB8_sub_texture, EXT_debug_label, EXT_debug_marker, EXT_debug_tool, EXT_discard_framebuffer, EXT_disjoint_timer_query, EXT_draw_buffers, EXT_draw_instanced, EXT_instanced_arrays, EXT_frag_depth, EXT_framebuffer_blit, EXT_framebuffer_object, EXT_framebuffer_sRGB, EXT_gpu_shader4, EXT_multi_draw_indirect, EXT_occlusion_query_boolean, EXT_packed_float, EXT_read_format_bgra, EXT_shader_image_load_store, EXT_shader_texture_lod, EXT_shadow_samplers, EXT_sRGB_write_control, EXT_texture_array, EXT_texture_compression_dxt1, EXT_texture_compression_latc, EXT_texture_compression_rgtc, EXT_texture_compression_s3tc, EXT_texture_cube_map_array, EXT_texture_filter_anisotropic, EXT_texture_format_BGRA8888, EXT_texture_rg, EXT_texture_shared_exponent, EXT_texture_snorm, EXT_texture_sRGB, EXT_texture_storage, EXT_texture_swizzle, EXT_texture_type_2_10_10_10_REV, EXT_timer_query, EXT_unpack_subimage, EXT_sRGB, EXT_multisampled_render_to_texture, GOOGLE_depth_texture, IMG_multisampled_render_to_texture, IMG_read_format, IMG_shader_binary, IMG_texture_compression_pvrtc, IMG_texture_compression_pvrtc2, IMG_texture_format_BGRA8888, INTEL_fragment_shader_ordering, KHR_debug, KHR_no_error, MOZ_WEBGL_compressed_texture_s3tc, MOZ_WEBGL_depth_texture, NV_conservative_raster, NV_copy_image, NV_draw_buffers, NV_draw_instanced, NV_instanced_arrays, NV_occlusion_query, NV_texture_border_clamp, NVX_gpu_memory_info, OES_copy_image, OES_compressed_ETC1_RGB8_texture, OES_depth24, OES_depth32, OES_depth_texture, OES_element_index_uint, OES_fragment_precision_high, OES_fbo_render_mipmap, OES_get_program_binary, OES_required_internalformat, OES_packed_depth_stencil, OES_read_format, OES_rgb8_rgba8, OES_standard_derivatives, OES_texture_3D, OES_texture_float, OES_texture_float_linear, OES_texture_npot, OES_texture_half_float, OES_texture_half_float_linear, OES_texture_stencil8, OES_texture_storage_multisample_2d_array, OES_vertex_array_object, OES_vertex_half_float, OES_vertex_type_10_10_10_2, WEBGL_color_buffer_float, WEBGL_compressed_texture_etc1, WEBGL_compressed_texture_s3tc, WEBGL_compressed_texture_pvrtc, WEBGL_depth_texture, WEBGL_draw_buffers, WEBKIT_EXT_texture_filter_anisotropic, WEBKIT_WEBGL_compressed_texture_s3tc, WEBKIT_WEBGL_depth_texture, Count }; const char* m_name; bool m_supported; bool m_initialize; }; // Extension registry // // ANGLE: // https://github.com/google/angle/tree/master/extensions // // CHROMIUM: // https://chromium.googlesource.com/chromium/src.git/+/refs/heads/git-svn/gpu/GLES2/extensions/CHROMIUM // // EGL: // https://www.khronos.org/registry/egl/extensions/ // // GL: // https://www.opengl.org/registry/ // // GLES: // https://www.khronos.org/registry/gles/extensions/ // // WEBGL: // https://www.khronos.org/registry/webgl/extensions/ // static Extension s_extension[] = { { "AMD_conservative_depth", false, true }, { "AMD_multi_draw_indirect", false, true }, { "ANGLE_depth_texture", false, true }, { "ANGLE_framebuffer_blit", false, true }, { "ANGLE_framebuffer_multisample", false, false }, { "ANGLE_instanced_arrays", false, true }, { "ANGLE_texture_compression_dxt1", false, true }, { "ANGLE_texture_compression_dxt3", false, true }, { "ANGLE_texture_compression_dxt5", false, true }, { "ANGLE_timer_query", false, true }, { "ANGLE_translated_shader_source", false, true }, { "APPLE_texture_format_BGRA8888", false, true }, { "APPLE_texture_max_level", false, true }, { "ARB_clip_control", BGFX_CONFIG_RENDERER_OPENGL >= 43, true }, { "ARB_compute_shader", BGFX_CONFIG_RENDERER_OPENGL >= 43, true }, { "ARB_conservative_depth", BGFX_CONFIG_RENDERER_OPENGL >= 42, true }, { "ARB_copy_image", BGFX_CONFIG_RENDERER_OPENGL >= 42, true }, { "ARB_debug_label", false, true }, { "ARB_debug_output", BGFX_CONFIG_RENDERER_OPENGL >= 43, true }, { "ARB_depth_buffer_float", BGFX_CONFIG_RENDERER_OPENGL >= 33, true }, { "ARB_depth_clamp", BGFX_CONFIG_RENDERER_OPENGL >= 32, true }, { "ARB_draw_buffers_blend", BGFX_CONFIG_RENDERER_OPENGL >= 40, true }, { "ARB_draw_indirect", BGFX_CONFIG_RENDERER_OPENGL >= 40, true }, { "ARB_draw_instanced", BGFX_CONFIG_RENDERER_OPENGL >= 33, true }, { "ARB_ES3_compatibility", BGFX_CONFIG_RENDERER_OPENGL >= 43, true }, { "ARB_framebuffer_object", BGFX_CONFIG_RENDERER_OPENGL >= 30, true }, { "ARB_framebuffer_sRGB", BGFX_CONFIG_RENDERER_OPENGL >= 30, true }, { "ARB_get_program_binary", BGFX_CONFIG_RENDERER_OPENGL >= 41, true }, { "ARB_half_float_pixel", BGFX_CONFIG_RENDERER_OPENGL >= 30, true }, { "ARB_half_float_vertex", BGFX_CONFIG_RENDERER_OPENGL >= 30, true }, { "ARB_indirect_parameters", BGFX_CONFIG_RENDERER_OPENGL >= 46, true }, { "ARB_instanced_arrays", BGFX_CONFIG_RENDERER_OPENGL >= 33, true }, { "ARB_internalformat_query", BGFX_CONFIG_RENDERER_OPENGL >= 42, true }, { "ARB_internalformat_query2", BGFX_CONFIG_RENDERER_OPENGL >= 43, true }, { "ARB_invalidate_subdata", BGFX_CONFIG_RENDERER_OPENGL >= 43, true }, { "ARB_map_buffer_range", BGFX_CONFIG_RENDERER_OPENGL >= 30, true }, { "ARB_multi_draw_indirect", BGFX_CONFIG_RENDERER_OPENGL >= 43, true }, { "ARB_multisample", false, true }, { "ARB_occlusion_query", BGFX_CONFIG_RENDERER_OPENGL >= 33, true }, { "ARB_occlusion_query2", BGFX_CONFIG_RENDERER_OPENGL >= 33, true }, { "ARB_program_interface_query", BGFX_CONFIG_RENDERER_OPENGL >= 43, true }, { "ARB_provoking_vertex", BGFX_CONFIG_RENDERER_OPENGL >= 32, true }, { "ARB_sampler_objects", BGFX_CONFIG_RENDERER_OPENGL >= 33, true }, { "ARB_seamless_cube_map", BGFX_CONFIG_RENDERER_OPENGL >= 32, true }, { "ARB_shader_bit_encoding", BGFX_CONFIG_RENDERER_OPENGL >= 33, true }, { "ARB_shader_image_load_store", BGFX_CONFIG_RENDERER_OPENGL >= 42, true }, { "ARB_shader_storage_buffer_object", BGFX_CONFIG_RENDERER_OPENGL >= 43, true }, { "ARB_shader_texture_lod", BGFX_CONFIG_RENDERER_OPENGL >= 30, true }, { "ARB_shader_viewport_layer_array", false, true }, { "ARB_texture_compression_bptc", BGFX_CONFIG_RENDERER_OPENGL >= 44, true }, { "ARB_texture_compression_rgtc", BGFX_CONFIG_RENDERER_OPENGL >= 30, true }, { "ARB_texture_cube_map_array", BGFX_CONFIG_RENDERER_OPENGL >= 40, true }, { "ARB_texture_float", BGFX_CONFIG_RENDERER_OPENGL >= 30, true }, { "ARB_texture_multisample", BGFX_CONFIG_RENDERER_OPENGL >= 32, true }, { "ARB_texture_rg", BGFX_CONFIG_RENDERER_OPENGL >= 30, true }, { "ARB_texture_rgb10_a2ui", BGFX_CONFIG_RENDERER_OPENGL >= 33, true }, { "ARB_texture_stencil8", false, true }, { "ARB_texture_storage", BGFX_CONFIG_RENDERER_OPENGL >= 42, true }, { "ARB_texture_swizzle", BGFX_CONFIG_RENDERER_OPENGL >= 33, true }, { "ARB_timer_query", BGFX_CONFIG_RENDERER_OPENGL >= 33, true }, { "ARB_uniform_buffer_object", BGFX_CONFIG_RENDERER_OPENGL >= 31, true }, { "ARB_vertex_array_object", BGFX_CONFIG_RENDERER_OPENGL >= 30, true }, { "ARB_vertex_type_2_10_10_10_rev", false, true }, { "ATI_meminfo", false, true }, { "CHROMIUM_color_buffer_float_rgb", false, true }, { "CHROMIUM_color_buffer_float_rgba", false, true }, { "CHROMIUM_depth_texture", false, true }, { "CHROMIUM_framebuffer_multisample", false, true }, { "CHROMIUM_texture_compression_dxt3", false, true }, { "CHROMIUM_texture_compression_dxt5", false, true }, { "EXT_bgra", false, true }, { "EXT_blend_color", BGFX_CONFIG_RENDERER_OPENGL >= 31, true }, { "EXT_blend_minmax", BGFX_CONFIG_RENDERER_OPENGL >= 14, true }, { "EXT_blend_subtract", BGFX_CONFIG_RENDERER_OPENGL >= 14, true }, { "EXT_color_buffer_half_float", false, true }, // GLES2 extension. { "EXT_color_buffer_float", false, true }, // GLES2 extension. { "EXT_copy_image", false, true }, // GLES2 extension. { "EXT_compressed_ETC1_RGB8_sub_texture", false, true }, // GLES2 extension. { "EXT_debug_label", false, true }, { "EXT_debug_marker", false, true }, { "EXT_debug_tool", false, true }, // RenderDoc extension. { "EXT_discard_framebuffer", false, true }, // GLES2 extension. { "EXT_disjoint_timer_query", false, true }, // GLES2 extension. { "EXT_draw_buffers", false, true }, // GLES2 extension. { "EXT_draw_instanced", false, true }, // GLES2 extension. { "EXT_instanced_arrays", false, true }, // GLES2 extension. { "EXT_frag_depth", false, true }, // GLES2 extension. { "EXT_framebuffer_blit", BGFX_CONFIG_RENDERER_OPENGL >= 30, true }, { "EXT_framebuffer_object", BGFX_CONFIG_RENDERER_OPENGL >= 30, true }, { "EXT_framebuffer_sRGB", BGFX_CONFIG_RENDERER_OPENGL >= 30, true }, { "EXT_gpu_shader4", BGFX_CONFIG_RENDERER_OPENGL >= 31, true }, { "EXT_multi_draw_indirect", false, true }, // GLES3.1 extension. { "EXT_occlusion_query_boolean", false, true }, // GLES2 extension. { "EXT_packed_float", BGFX_CONFIG_RENDERER_OPENGL >= 33, true }, { "EXT_read_format_bgra", false, true }, { "EXT_shader_image_load_store", false, true }, { "EXT_shader_texture_lod", false, true }, // GLES2 extension. { "EXT_shadow_samplers", false, true }, { "EXT_sRGB_write_control", false, true }, // GLES2 extension. { "EXT_texture_array", BGFX_CONFIG_RENDERER_OPENGL >= 30, true }, { "EXT_texture_compression_dxt1", false, true }, { "EXT_texture_compression_latc", false, true }, { "EXT_texture_compression_rgtc", BGFX_CONFIG_RENDERER_OPENGL >= 30, true }, { "EXT_texture_compression_s3tc", false, true }, { "EXT_texture_cube_map_array", false, true }, // GLES3.1 extension. { "EXT_texture_filter_anisotropic", false, true }, { "EXT_texture_format_BGRA8888", false, true }, { "EXT_texture_rg", false, true }, // GLES2 extension. { "EXT_texture_shared_exponent", false, true }, { "EXT_texture_snorm", BGFX_CONFIG_RENDERER_OPENGL >= 30, true }, { "EXT_texture_sRGB", false, true }, { "EXT_texture_storage", false, true }, { "EXT_texture_swizzle", false, true }, { "EXT_texture_type_2_10_10_10_REV", false, true }, { "EXT_timer_query", BGFX_CONFIG_RENDERER_OPENGL >= 33, true }, { "EXT_unpack_subimage", false, true }, { "EXT_sRGB", false, true }, // GLES2 extension. { "EXT_multisampled_render_to_texture", false, true }, // GLES2 extension. { "GOOGLE_depth_texture", false, true }, { "IMG_multisampled_render_to_texture", false, true }, { "IMG_read_format", false, true }, { "IMG_shader_binary", false, true }, { "IMG_texture_compression_pvrtc", false, true }, { "IMG_texture_compression_pvrtc2", false, true }, { "IMG_texture_format_BGRA8888", false, true }, { "INTEL_fragment_shader_ordering", false, true }, { "KHR_debug", BGFX_CONFIG_RENDERER_OPENGL >= 43, true }, { "KHR_no_error", false, true }, { "MOZ_WEBGL_compressed_texture_s3tc", false, true }, { "MOZ_WEBGL_depth_texture", false, true }, { "NV_conservative_raster", false, true }, { "NV_copy_image", false, true }, { "NV_draw_buffers", false, true }, // GLES2 extension. { "NV_draw_instanced", false, true }, // GLES2 extension. { "NV_instanced_arrays", false, true }, // GLES2 extension. { "NV_occlusion_query", false, true }, { "NV_texture_border_clamp", false, true }, // GLES2 extension. { "NVX_gpu_memory_info", false, true }, { "OES_copy_image", false, true }, { "OES_compressed_ETC1_RGB8_texture", false, true }, { "OES_depth24", false, true }, { "OES_depth32", false, true }, { "OES_depth_texture", false, true }, { "OES_element_index_uint", false, true }, { "OES_fragment_precision_high", false, true }, { "OES_fbo_render_mipmap", false, true }, { "OES_get_program_binary", false, true }, { "OES_required_internalformat", false, true }, { "OES_packed_depth_stencil", false, true }, { "OES_read_format", false, true }, { "OES_rgb8_rgba8", false, true }, { "OES_standard_derivatives", false, true }, { "OES_texture_3D", false, true }, { "OES_texture_float", false, true }, { "OES_texture_float_linear", false, true }, { "OES_texture_npot", false, true }, { "OES_texture_half_float", false, true }, { "OES_texture_half_float_linear", false, true }, { "OES_texture_stencil8", false, true }, { "OES_texture_storage_multisample_2d_array", false, true }, { "OES_vertex_array_object", false, !BX_PLATFORM_IOS }, { "OES_vertex_half_float", false, true }, { "OES_vertex_type_10_10_10_2", false, true }, { "WEBGL_color_buffer_float", false, true }, { "WEBGL_compressed_texture_etc1", false, true }, { "WEBGL_compressed_texture_s3tc", false, true }, { "WEBGL_compressed_texture_pvrtc", false, true }, { "WEBGL_depth_texture", false, true }, { "WEBGL_draw_buffers", false, true }, { "WEBKIT_EXT_texture_filter_anisotropic", false, true }, { "WEBKIT_WEBGL_compressed_texture_s3tc", false, true }, { "WEBKIT_WEBGL_depth_texture", false, true }, }; BX_STATIC_ASSERT(Extension::Count == BX_COUNTOF(s_extension) ); static const char* s_ARB_shader_texture_lod[] = { "texture2DLod", "texture2DArrayLod", // BK - interacts with ARB_texture_array. "texture2DProjLod", "texture2DGrad", "texture2DProjGrad", "texture3DLod", "texture3DProjLod", "texture3DGrad", "texture3DProjGrad", "textureCubeLod", "textureCubeGrad", "shadow2DLod", "shadow2DProjLod", NULL // "texture1DLod", // "texture1DProjLod", // "shadow1DLod", // "shadow1DProjLod", }; static const char* s_EXT_shader_texture_lod[] = { "texture2DLod", "texture2DProjLod", "textureCubeLod", "texture2DGrad", "texture2DProjGrad", "textureCubeGrad", NULL }; static const char* s_ARB_shader_viewport_layer_array[] = { "gl_ViewportIndex", "gl_Layer", NULL }; static const char* s_EXT_shadow_samplers[] = { "shadow2D", "shadow2DProj", NULL }; static const char* s_OES_standard_derivatives[] = { "dFdx", "dFdy", "fwidth", NULL }; static const char* s_uisamplers[] = { "isampler2D", "usampler2D", "isampler3D", "usampler3D", "isamplerCube", "usamplerCube", NULL }; static const char* s_uint[] = { "uint", "uvec2", "uvec3", "uvec4", NULL }; static const char* s_texelFetch[] = { "texture", "textureLod", "textureGrad", "textureProj", "textureProjLod", "texelFetch", "texelFetchOffset", NULL }; static const char* s_texture3D[] = { "sampler3D", "sampler3DArray", NULL }; static const char* s_textureArray[] = { "sampler2DArray", "sampler2DMSArray", "samplerCubeArray", "sampler2DArrayShadow", NULL }; static const char* s_ARB_texture_multisample[] = { "sampler2DMS", "isampler2DMS", "usampler2DMS", NULL }; static const char* s_EXT_gpu_shader4[] = { "gl_VertexID", "gl_InstanceID", "uint", NULL }; static const char* s_ARB_gpu_shader5[] = { "bitfieldReverse", "floatBitsToInt", "floatBitsToUint", "intBitsToFloat", "uintBitsToFloat", NULL }; static const char* s_ARB_shading_language_packing[] = { "packHalf2x16", "unpackHalf2x16", NULL }; static const char* s_intepolationQualifier[] = { "flat", "smooth", "noperspective", "centroid", NULL }; static void GL_APIENTRY stubVertexAttribDivisor(GLuint /*_index*/, GLuint /*_divisor*/) { } static void GL_APIENTRY stubDrawArraysInstanced(GLenum _mode, GLint _first, GLsizei _count, GLsizei /*_primcount*/) { GL_CHECK(glDrawArrays(_mode, _first, _count) ); } static void GL_APIENTRY stubDrawElementsInstanced(GLenum _mode, GLsizei _count, GLenum _type, const GLvoid* _indices, GLsizei /*_primcount*/) { GL_CHECK(glDrawElements(_mode, _count, _type, _indices) ); } static void GL_APIENTRY stubInsertEventMarker(GLsizei /*_length*/, const char* /*_marker*/) { } static void GL_APIENTRY stubPushDebugGroup(GLenum /*_source*/, GLuint /*_id*/, GLsizei /*_length*/, const char* /*_message*/) { } static void GL_APIENTRY stubPopDebugGroup() { } static void GL_APIENTRY stubObjectLabel(GLenum /*_identifier*/, GLuint /*_name*/, GLsizei /*_length*/, const char* /*_label*/) { } static void GL_APIENTRY stubInvalidateFramebuffer(GLenum /*_target*/, GLsizei /*_numAttachments*/, const GLenum* /*_attachments*/) { } static void GL_APIENTRY stubFramebufferTexture(GLenum _target, GLenum _attachment, GLuint _texture, GLint _level) { GL_CHECK(glFramebufferTextureLayer(_target , _attachment , _texture , _level , 0 ) ); } static void GL_APIENTRY stubMultiDrawArraysIndirect(GLenum _mode, const void* _indirect, GLsizei _drawCount, GLsizei _stride) { const uint8_t* args = (const uint8_t*)_indirect; for (GLsizei ii = 0; ii < _drawCount; ++ii) { GL_CHECK(glDrawArraysIndirect(_mode, (void*)args) ); args += _stride; } } static void GL_APIENTRY stubMultiDrawElementsIndirect(GLenum _mode, GLenum _type, const void* _indirect, GLsizei _drawCount, GLsizei _stride) { const uint8_t* args = (const uint8_t*)_indirect; for (GLsizei ii = 0; ii < _drawCount; ++ii) { GL_CHECK(glDrawElementsIndirect(_mode, _type, (void*)args) ); args += _stride; } } static void GL_APIENTRY stubPolygonMode(GLenum /*_face*/, GLenum /*_mode*/) { } typedef void (*PostSwapBuffersFn)(uint32_t _width, uint32_t _height); void flushGlError() { for (GLenum err = glGetError(); err != 0; err = glGetError() ); } GLenum getGlError() { GLenum err = glGetError(); flushGlError(); return err; } static const char* getGLString(GLenum _name) { const char* str = (const char*)glGetString(_name); getGlError(); // ignore error if glGetString returns NULL. if (NULL != str) { return str; } return "<unknown>"; } static uint32_t getGLStringHash(GLenum _name) { const char* str = (const char*)glGetString(_name); getGlError(); // ignore error if glGetString returns NULL. if (NULL != str) { return bx::hash<bx::HashMurmur2A>(str, (uint32_t)bx::strLen(str) ); } return 0; } void dumpExtensions(const char* _extensions) { if (NULL != _extensions) { char name[1024]; const char* pos = _extensions; const char* end = _extensions + bx::strLen(_extensions); while (pos < end) { uint32_t len; bx::StringView space = bx::strFind(pos, ' '); if (!space.isEmpty() ) { len = bx::uint32_min(sizeof(name), (uint32_t)(space.getPtr() - pos) ); } else { len = bx::uint32_min(sizeof(name), (uint32_t)bx::strLen(pos) ); } bx::strCopy(name, BX_COUNTOF(name), pos, len); name[len] = '\0'; BX_TRACE("\t%s", name); pos += len+1; } } } const char* toString(GLenum _enum) { switch (_enum) { case GL_DEBUG_SOURCE_API: return "API"; case GL_DEBUG_SOURCE_WINDOW_SYSTEM: return "WinSys"; case GL_DEBUG_SOURCE_SHADER_COMPILER: return "Shader"; case GL_DEBUG_SOURCE_THIRD_PARTY: return "3rdparty"; case GL_DEBUG_SOURCE_APPLICATION: return "Application"; case GL_DEBUG_SOURCE_OTHER: return "Other"; case GL_DEBUG_TYPE_ERROR: return "Error"; case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR: return "Deprecated behavior"; case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR: return "Undefined behavior"; case GL_DEBUG_TYPE_PORTABILITY: return "Portability"; case GL_DEBUG_TYPE_PERFORMANCE: return "Performance"; case GL_DEBUG_TYPE_OTHER: return "Other"; case GL_DEBUG_SEVERITY_HIGH: return "High"; case GL_DEBUG_SEVERITY_MEDIUM: return "Medium"; case GL_DEBUG_SEVERITY_LOW: return "Low"; case GL_DEBUG_SEVERITY_NOTIFICATION: return "SPAM"; default: break; } return "<unknown>"; } void GL_APIENTRY debugProcCb(GLenum _source, GLenum _type, GLuint _id, GLenum _severity, GLsizei /*_length*/, const GLchar* _message, const void* /*_userParam*/) { if (GL_DEBUG_SEVERITY_NOTIFICATION != _severity) { BX_TRACE("src %s, type %s, id %d, severity %s, '%s'" , toString(_source) , toString(_type) , _id , toString(_severity) , _message ); BX_UNUSED(_source, _type, _id, _severity, _message); } } GLint glGet(GLenum _pname) { GLint result = 0; glGetIntegerv(_pname, &result); GLenum err = getGlError(); BX_WARN(0 == err, "glGetIntegerv(0x%04x, ...) failed with GL error: 0x%04x.", _pname, err); return 0 == err ? result : 0; } static uint64_t s_currentlyEnabledVertexAttribArrays = 0; static uint64_t s_vertexAttribArraysPendingDisable = 0; static uint64_t s_vertexAttribArraysPendingEnable = 0; void lazyEnableVertexAttribArray(GLuint index) { if (BX_ENABLED(BX_PLATFORM_EMSCRIPTEN) ) { if (index >= 64) { // On WebGL platform calling out to WebGL API is detrimental to performance, so optimize // out redundant API calls to glEnable/DisableVertexAttribArray. GL_CHECK(glEnableVertexAttribArray(index) ); return; } const uint64_t mask = UINT64_C(1) << index; s_vertexAttribArraysPendingEnable |= mask & (~s_currentlyEnabledVertexAttribArrays); s_vertexAttribArraysPendingDisable &= ~mask; } else { GL_CHECK(glEnableVertexAttribArray(index) ); } } void lazyDisableVertexAttribArray(GLuint index) { if (BX_ENABLED(BX_PLATFORM_EMSCRIPTEN) ) { if (index >= 64) { // On WebGL platform calling out to WebGL API is detrimental to performance, so optimize // out redundant API calls to glEnable/DisableVertexAttribArray. GL_CHECK(glDisableVertexAttribArray(index) ); return; } const uint64_t mask = UINT64_C(1) << index; s_vertexAttribArraysPendingDisable |= mask & s_currentlyEnabledVertexAttribArrays; s_vertexAttribArraysPendingEnable &= ~mask; } else { GL_CHECK(glDisableVertexAttribArray(index) ); } } void applyLazyEnabledVertexAttributes() { if (BX_ENABLED(BX_PLATFORM_EMSCRIPTEN) ) { while (s_vertexAttribArraysPendingDisable) { uint32_t index = bx::uint32_cnttz(s_vertexAttribArraysPendingDisable); uint64_t mask = ~(UINT64_C(1) << index); s_vertexAttribArraysPendingDisable &= mask; s_currentlyEnabledVertexAttribArrays &= mask; GL_CHECK(glDisableVertexAttribArray(index) ); } while (s_vertexAttribArraysPendingEnable) { uint32_t index = bx::uint32_cnttz(s_vertexAttribArraysPendingEnable); uint64_t mask = UINT64_C(1) << index; s_vertexAttribArraysPendingEnable &= ~mask; s_currentlyEnabledVertexAttribArrays |= mask; GL_CHECK(glEnableVertexAttribArray(index) ); } } } void setTextureFormat(TextureFormat::Enum _format, GLenum _internalFmt, GLenum _fmt, GLenum _type = GL_ZERO) { TextureFormatInfo& tfi = s_textureFormat[_format]; tfi.m_internalFmt = _internalFmt; tfi.m_fmt = _fmt; tfi.m_fmtSrgb = _fmt; tfi.m_type = _type; } void setTextureFormatSrgb(TextureFormat::Enum _format, GLenum _internalFmtSrgb, GLenum _fmtSrgb) { TextureFormatInfo& tfi = s_textureFormat[_format]; tfi.m_internalFmtSrgb = _internalFmtSrgb; tfi.m_fmtSrgb = _fmtSrgb; } static void texSubImage( GLenum _target , GLint _level , GLint _xoffset , GLint _yoffset , GLint _zoffset , GLsizei _width , GLsizei _height , GLsizei _depth , GLenum _format , GLenum _type , const GLvoid* _data ) { if (NULL == _data) { return; } if (_target == GL_TEXTURE_3D || _target == GL_TEXTURE_2D_ARRAY || _target == GL_TEXTURE_CUBE_MAP_ARRAY) { glTexSubImage3D( _target , _level , _xoffset , _yoffset , _zoffset , _width , _height , _depth , _format , _type , _data ); } else if (_target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY) { } else { BX_UNUSED(_zoffset, _depth); glTexSubImage2D( _target , _level , _xoffset , _yoffset , _width , _height , _format , _type , _data ); } } static void texImage( GLenum _target , uint32_t _msaaQuality , GLint _level , GLint _internalFormat , GLsizei _width , GLsizei _height , GLsizei _depth , GLint _border , GLenum _format , GLenum _type , const GLvoid* _data ) { if (_target == GL_TEXTURE_3D) { glTexImage3D( _target , _level , _internalFormat , _width , _height , _depth , _border , _format , _type , _data ); } else if (_target == GL_TEXTURE_2D_ARRAY || _target == GL_TEXTURE_CUBE_MAP_ARRAY) { texSubImage( _target , _level , 0 , 0 , _depth , _width , _height , 1 , _format , _type , _data ); } else if (_target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY) { } else if (_target == GL_TEXTURE_2D_MULTISAMPLE) { glTexImage2DMultisample( _target , _msaaQuality , _internalFormat , _width , _height , false ); } else { glTexImage2D( _target , _level , _internalFormat , _width , _height , _border , _format , _type , _data ); } BX_UNUSED(_msaaQuality, _depth, _border, _data); } static void compressedTexSubImage( GLenum _target , GLint _level , GLint _xoffset , GLint _yoffset , GLint _zoffset , GLsizei _width , GLsizei _height , GLsizei _depth , GLenum _format , GLsizei _imageSize , const GLvoid* _data ) { if (_target == GL_TEXTURE_3D || _target == GL_TEXTURE_2D_ARRAY) { glCompressedTexSubImage3D( _target , _level , _xoffset , _yoffset , _zoffset , _width , _height , _depth , _format , _imageSize , _data ); } else { BX_UNUSED(_zoffset, _depth); glCompressedTexSubImage2D( _target , _level , _xoffset , _yoffset , _width , _height , _format , _imageSize , _data ); } } static void compressedTexImage( GLenum _target , GLint _level , GLenum _internalformat , GLsizei _width , GLsizei _height , GLsizei _depth , GLint _border , GLsizei _imageSize , const GLvoid* _data ) { if (_target == GL_TEXTURE_3D) { glCompressedTexImage3D( _target , _level , _internalformat , _width , _height , _depth , _border , _imageSize , _data ); } else if (_target == GL_TEXTURE_2D_ARRAY || _target == GL_TEXTURE_CUBE_MAP_ARRAY) { compressedTexSubImage( _target , _level , 0 , 0 , _depth , _width , _height , 1 , _internalformat , _imageSize , _data ); } else if (_target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY) { } else { BX_UNUSED(_depth); glCompressedTexImage2D( _target , _level , _internalformat , _width , _height , _border , _imageSize , _data ); } } GLenum initTestTexture(TextureFormat::Enum _format, bool _srgb, bool _mipmaps, bool _array, GLsizei _dim) { const TextureFormatInfo& tfi = s_textureFormat[_format]; GLenum internalFmt = _srgb ? tfi.m_internalFmtSrgb : tfi.m_internalFmt ; GLenum fmt = _srgb ? tfi.m_fmtSrgb : tfi.m_fmt ; GLsizei bpp = bimg::getBitsPerPixel(bimg::TextureFormat::Enum(_format) ); GLsizei size = (_dim*_dim*bpp)/8; void* data = NULL; if (bimg::isDepth(bimg::TextureFormat::Enum(_format) ) ) { _srgb = false; _mipmaps = false; _array = false; } else { data = bx::alignPtr(alloca(size+16), 0, 16); } flushGlError(); GLenum err = 0; const GLenum target = _array ? GL_TEXTURE_2D_ARRAY : GL_TEXTURE_2D ; if (bimg::isCompressed(bimg::TextureFormat::Enum(_format) ) ) { for (uint32_t ii = 0, dim = _dim; ii < (_mipmaps ? 5u : 1u) && 0 == err; ++ii, dim >>= 1) { dim = bx::uint32_max(1, dim); uint32_t block = bx::uint32_max(4, dim); size = (block*block*bpp)/8; compressedTexImage(target, ii, internalFmt, dim, dim, 0, 0, size, data); err |= getGlError(); } } else { for (uint32_t ii = 0, dim = _dim; ii < (_mipmaps ? 5u : 1u) && 0 == err; ++ii, dim >>= 1) { dim = bx::uint32_max(1, dim); size = (dim*dim*bpp)/8; texImage(target, 0, ii, internalFmt, dim, dim, 0, 0, fmt, tfi.m_type, data); err |= getGlError(); } } return err; } #if BX_PLATFORM_EMSCRIPTEN static bool isTextureFormatValidPerSpec( TextureFormat::Enum _format , bool _srgb , bool _mipAutogen ) { // Avoid creating test textures for WebGL, that causes error noise in the browser // console; instead examine the supported texture formats from the spec. EMSCRIPTEN_WEBGL_CONTEXT_HANDLE ctx = emscripten_webgl_get_current_context(); EmscriptenWebGLContextAttributes attrs; EMSCRIPTEN_CHECK(emscripten_webgl_get_context_attributes(ctx, &attrs) ); const int glesVersion = attrs.majorVersion + 1; switch(_format) { case TextureFormat::A8: case TextureFormat::R8: // Luminance case TextureFormat::B5G6R5: case TextureFormat::R5G6B5: case TextureFormat::BGRA4: case TextureFormat::RGBA4: case TextureFormat::BGR5A1: case TextureFormat::RGB5A1: // GLES2 formats without sRGB. return !_srgb; case TextureFormat::D16: // GLES2 formats without sRGB, depth textures do not support mipmaps. return !_srgb && !_mipAutogen ; case TextureFormat::R16F: case TextureFormat::R32F: case TextureFormat::RG8: case TextureFormat::RG16F: case TextureFormat::RG32F: case TextureFormat::RGB10A2: case TextureFormat::RG11B10F: // GLES3 formats without sRGB return !_srgb && glesVersion >= 3 ; case TextureFormat::R8I: case TextureFormat::R8U: case TextureFormat::R16I: case TextureFormat::R16U: case TextureFormat::R32I: case TextureFormat::R32U: case TextureFormat::RG8I: case TextureFormat::RG8U: case TextureFormat::RG16I: case TextureFormat::RG16U: case TextureFormat::RG32I: case TextureFormat::RG32U: case TextureFormat::RGB8I: case TextureFormat::RGB8U: case TextureFormat::RGBA8I: case TextureFormat::RGBA8U: case TextureFormat::RGBA16I: case TextureFormat::RGBA16U: case TextureFormat::RGBA32I: case TextureFormat::RGBA32U: case TextureFormat::D32F: case TextureFormat::R8S: case TextureFormat::RG8S: case TextureFormat::RGB8S: case TextureFormat::RGBA8S: case TextureFormat::RGB9E5F: // GLES3 formats without sRGB that are not texture filterable or color renderable. return !_srgb && glesVersion >= 3 && !_mipAutogen ; case TextureFormat::D24: case TextureFormat::D24S8: case TextureFormat::D32: // GLES3 formats without sRGB, depth textures do not support mipmaps. return !_srgb && !_mipAutogen && (glesVersion >= 3 || emscripten_webgl_enable_extension(ctx, "WEBGL_depth_texture") ) ; case TextureFormat::D16F: case TextureFormat::D24F: // GLES3 depth formats without sRGB, depth textures do not support mipmaps. return !_srgb && !_mipAutogen && glesVersion >= 3 ; case TextureFormat::RGBA16F: case TextureFormat::RGBA32F: // GLES3 formats without sRGB return !_srgb && (glesVersion >= 3 || emscripten_webgl_enable_extension(ctx, "OES_texture_half_float") ) ; case TextureFormat::RGB8: case TextureFormat::RGBA8: // sRGB formats return !_srgb || glesVersion >= 3 || emscripten_webgl_enable_extension(ctx, "EXT_sRGB") ; case TextureFormat::BC1: case TextureFormat::BC2: case TextureFormat::BC3: return emscripten_webgl_enable_extension(ctx, "WEBGL_compressed_texture_s3tc") && (!_srgb || emscripten_webgl_enable_extension(ctx, "WEBGL_compressed_texture_s3tc_srgb") ) ; case TextureFormat::PTC12: case TextureFormat::PTC14: case TextureFormat::PTC12A: case TextureFormat::PTC14A: return !_srgb && emscripten_webgl_enable_extension(ctx, "WEBGL_compressed_texture_pvrtc") ; case TextureFormat::ETC1: return !_srgb && emscripten_webgl_enable_extension(ctx, "WEBGL_compressed_texture_etc1") ; case TextureFormat::ETC2: case TextureFormat::ETC2A: case TextureFormat::ETC2A1: return emscripten_webgl_enable_extension(ctx, "WEBGL_compressed_texture_etc"); case TextureFormat::ASTC4x4: case TextureFormat::ASTC5x5: case TextureFormat::ASTC6x6: case TextureFormat::ASTC8x5: case TextureFormat::ASTC8x6: case TextureFormat::ASTC10x5: return emscripten_webgl_enable_extension(ctx, "WEBGL_compressed_texture_astc"); default: break; } return false; } #endif // BX_PLATFORM_EMSCRIPTEN static bool isTextureFormatValid( TextureFormat::Enum _format , bool _srgb = false , bool _mipAutogen = false , bool _array = false , GLsizei _dim = 16 ) { #if BX_PLATFORM_EMSCRIPTEN // On web platform read the validity of textures based on the available GL context and extensions // to avoid developer unfriendly console error noise that would come from probing. BX_UNUSED(_array, _dim); return isTextureFormatValidPerSpec(_format, _srgb, _mipAutogen); #else // On other platforms probe the supported textures. const TextureFormatInfo& tfi = s_textureFormat[_format]; GLenum internalFmt = _srgb ? tfi.m_internalFmtSrgb : tfi.m_internalFmt ; if (GL_ZERO == internalFmt) { return false; } const GLenum target = _array ? GL_TEXTURE_2D_ARRAY : GL_TEXTURE_2D ; GLuint id; GL_CHECK(glGenTextures(1, &id) ); GL_CHECK(glBindTexture(target, id) ); GLenum err = 0; if (_array) { glTexStorage3D(target , 1 + GLsizei(bx::log2( (int32_t)_dim) ) , internalFmt , _dim , _dim , _dim ); err = getGlError(); } if (0 == err) { err = initTestTexture(_format, _srgb, _mipAutogen, _array, _dim); BX_WARN(0 == err, "TextureFormat::%s %s%s%sis not supported (%x: %s)." , getName(_format) , _srgb ? "+sRGB " : "" , _mipAutogen ? "+mipAutoGen " : "" , _array ? "+array " : "" , err , glEnumName(err) ); if (0 == err && _mipAutogen) { glGenerateMipmap(target); err = getGlError(); } } GL_CHECK(glDeleteTextures(1, &id) ); return 0 == err; #endif } static bool isImageFormatValid(TextureFormat::Enum _format, GLsizei _dim = 16) { if (GL_ZERO == s_imageFormat[_format]) { return false; } GLuint id; GL_CHECK(glGenTextures(1, &id) ); GL_CHECK(glBindTexture(GL_TEXTURE_2D, id) ); flushGlError(); GLenum err = 0; glTexStorage2D(GL_TEXTURE_2D, 1, s_imageFormat[_format], _dim, _dim); err |= getGlError(); if (0 == err) { glBindImageTexture(0 , id , 0 , GL_FALSE , 0 , GL_READ_WRITE , s_imageFormat[_format] ); err |= getGlError(); } GL_CHECK(glDeleteTextures(1, &id) ); return 0 == err; } #if BX_PLATFORM_EMSCRIPTEN static bool isFramebufferFormatValidPerSpec( TextureFormat::Enum _format , bool _srgb , bool _writeOnly ) { // Avoid creating test textures for WebGL, that causes error noise in the browser console; instead examine the supported texture formats from the spec. EMSCRIPTEN_WEBGL_CONTEXT_HANDLE ctx = emscripten_webgl_get_current_context(); EmscriptenWebGLContextAttributes attrs; EMSCRIPTEN_CHECK(emscripten_webgl_get_context_attributes(ctx, &attrs) ); const int glesVersion = attrs.majorVersion + 1; switch(_format) { // GLES2 textures case TextureFormat::B5G6R5: case TextureFormat::R5G6B5: case TextureFormat::BGRA4: case TextureFormat::RGBA4: case TextureFormat::BGR5A1: case TextureFormat::RGB5A1: case TextureFormat::D16: return !_srgb; // GLES2 renderbuffers not a texture in GLES3 case TextureFormat::D0S8: return !_srgb && _writeOnly ; // GLES2 textures that are not renderbuffers case TextureFormat::RGB8: case TextureFormat::RGBA8: return !_srgb && (!_writeOnly || glesVersion >= 3) ; // GLES3 EXT_color_buffer_float renderbuffer formats case TextureFormat::R16F: case TextureFormat::RG16F: case TextureFormat::R32F: case TextureFormat::RG32F: case TextureFormat::RG11B10F: if (_writeOnly) { return emscripten_webgl_enable_extension(ctx, "EXT_color_buffer_float"); } return !_srgb && glesVersion >= 3; // GLES2 float extension: case TextureFormat::RGBA16F: if (_writeOnly && emscripten_webgl_enable_extension(ctx, "EXT_color_buffer_half_float") ) { return true; } BX_FALLTHROUGH; case TextureFormat::RGBA32F: if (_writeOnly) { return emscripten_webgl_enable_extension(ctx, "EXT_color_buffer_float") || emscripten_webgl_enable_extension(ctx, "WEBGL_color_buffer_float"); } // GLES3 formats without sRGB return !_srgb && (glesVersion >= 3 || emscripten_webgl_enable_extension(ctx, "OES_texture_half_float") ) ; case TextureFormat::D24: case TextureFormat::D24S8: // GLES3 formats without sRGB, depth textures do not support mipmaps. return !_srgb && (glesVersion >= 3 || (!_writeOnly && emscripten_webgl_enable_extension(ctx, "WEBGL_depth_texture") ) ) ; case TextureFormat::D32: // GLES3 formats without sRGB, depth textures do not support mipmaps. return !_srgb && !_writeOnly && (glesVersion >= 3 || emscripten_webgl_enable_extension(ctx, "WEBGL_depth_texture") ) ; // GLES3 textures case TextureFormat::R8: case TextureFormat::RG8: case TextureFormat::R8I: case TextureFormat::R8U: case TextureFormat::R16I: case TextureFormat::R16U: case TextureFormat::R32I: case TextureFormat::R32U: case TextureFormat::RG8I: case TextureFormat::RG8U: case TextureFormat::RGBA8I: case TextureFormat::RGBA8U: case TextureFormat::RG16I: case TextureFormat::RG16U: case TextureFormat::RG32I: case TextureFormat::RG32U: case TextureFormat::RGBA16I: case TextureFormat::RGBA16U: case TextureFormat::RGBA32I: case TextureFormat::RGBA32U: case TextureFormat::RGB10A2: case TextureFormat::D16F: case TextureFormat::D24F: case TextureFormat::D32F: return !_srgb && glesVersion >= 3 ; case TextureFormat::BGRA8: return !_srgb && _writeOnly && glesVersion >= 3 ; default: break; } return false; } #endif static bool isFramebufferFormatValid( TextureFormat::Enum _format , bool _srgb = false , bool _writeOnly = false , GLsizei _dim = 16 ) { #if BX_PLATFORM_EMSCRIPTEN // On web platform read the validity of framebuffers based on the available GL context and extensions // to avoid developer unfriendly console error noise that would come from probing. BX_UNUSED(_dim); return isFramebufferFormatValidPerSpec(_format, _srgb, _writeOnly); #else // On other platforms probe the supported textures. const TextureFormatInfo& tfi = s_textureFormat[_format]; GLenum internalFmt = _srgb ? tfi.m_internalFmtSrgb : tfi.m_internalFmt ; if (GL_ZERO == internalFmt) { return false; } if (_writeOnly) { GLuint rbo; glGenRenderbuffers(1, &rbo); glBindRenderbuffer(GL_RENDERBUFFER, rbo); glRenderbufferStorage(GL_RENDERBUFFER , s_rboFormat[_format] , _dim , _dim ); glBindRenderbuffer(GL_RENDERBUFFER, 0); glDeleteRenderbuffers(1, &rbo); GLenum err = getGlError(); return 0 == err; } GLuint fbo; GL_CHECK(glGenFramebuffers(1, &fbo) ); GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, fbo) ); GLuint id; GL_CHECK(glGenTextures(1, &id) ); GL_CHECK(glBindTexture(GL_TEXTURE_2D, id) ); GLenum err = initTestTexture(_format, _srgb, false, false, _dim); GLenum attachment; if (bimg::isDepth(bimg::TextureFormat::Enum(_format) ) ) { const bimg::ImageBlockInfo& info = bimg::getBlockInfo(bimg::TextureFormat::Enum(_format) ); if (0 == info.depthBits) { attachment = GL_STENCIL_ATTACHMENT; } else if (0 == info.stencilBits) { attachment = GL_DEPTH_ATTACHMENT; } else { attachment = GL_DEPTH_STENCIL_ATTACHMENT; } } else { attachment = GL_COLOR_ATTACHMENT0; } glFramebufferTexture2D(GL_FRAMEBUFFER , attachment , GL_TEXTURE_2D , id , 0 ); err = getGlError(); if (0 == err) { err = glCheckFramebufferStatus(GL_FRAMEBUFFER); } GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, 0) ); GL_CHECK(glDeleteFramebuffers(1, &fbo) ); GL_CHECK(glDeleteTextures(1, &id) ); return GL_FRAMEBUFFER_COMPLETE == err; #endif } static void getFilters(uint32_t _flags, bool _hasMips, GLenum& _magFilter, GLenum& _minFilter) { const uint32_t mag = (_flags&BGFX_SAMPLER_MAG_MASK)>>BGFX_SAMPLER_MAG_SHIFT; const uint32_t min = (_flags&BGFX_SAMPLER_MIN_MASK)>>BGFX_SAMPLER_MIN_SHIFT; const uint32_t mip = (_flags&BGFX_SAMPLER_MIP_MASK)>>BGFX_SAMPLER_MIP_SHIFT; _magFilter = s_textureFilterMag[mag]; _minFilter = s_textureFilterMin[min][_hasMips ? mip+1 : 0]; } void updateExtension(const bx::StringView& _name) { bx::StringView ext(_name); if (0 == bx::strCmp(ext, "GL_", 3) ) // skip GL_ { ext.set(ext.getPtr()+3, ext.getTerm() ); } bool supported = false; for (uint32_t ii = 0; ii < Extension::Count; ++ii) { Extension& extension = s_extension[ii]; if (!extension.m_supported && extension.m_initialize) { if (0 == bx::strCmp(ext, extension.m_name) ) { #if BX_PLATFORM_EMSCRIPTEN EMSCRIPTEN_WEBGL_CONTEXT_HANDLE ctx = emscripten_webgl_get_current_context(); supported = emscripten_webgl_enable_extension(ctx, extension.m_name); #else supported = true; #endif extension.m_supported = supported; break; } } } BX_TRACE("GL_EXTENSION %s: %.*s", supported ? " (supported)" : "", _name.getLength(), _name.getPtr() ); BX_UNUSED(supported); } struct VendorId { const char* name; uint16_t id; }; static const VendorId s_vendorIds[] = { { "NVIDIA Corporation", BGFX_PCI_ID_NVIDIA }, { "Advanced Micro Devices, Inc.", BGFX_PCI_ID_AMD }, { "Intel", BGFX_PCI_ID_INTEL }, { "ATI Technologies Inc.", BGFX_PCI_ID_AMD }, { "ARM", BGFX_PCI_ID_ARM }, }; struct Workaround { void reset() { m_detachShader = true; } bool m_detachShader; }; struct RendererContextGL : public RendererContextI { RendererContextGL() : m_numWindows(1) , m_rtMsaa(false) , m_fbDiscard(BGFX_CLEAR_NONE) , m_capture(NULL) , m_captureSize(0) , m_maxAnisotropy(0.0f) , m_maxAnisotropyDefault(0.0f) , m_maxMsaa(0) , m_vao(0) , m_blitSupported(false) , m_readBackSupported(BX_ENABLED(BGFX_CONFIG_RENDERER_OPENGL) ) , m_vaoSupport(false) , m_samplerObjectSupport(false) , m_shadowSamplersSupport(false) , m_srgbWriteControlSupport(BX_ENABLED(BGFX_CONFIG_RENDERER_OPENGL) ) , m_borderColorSupport(BX_ENABLED(BGFX_CONFIG_RENDERER_OPENGL) ) , m_programBinarySupport(false) , m_textureSwizzleSupport(false) , m_depthTextureSupport(false) , m_timerQuerySupport(false) , m_occlusionQuerySupport(false) , m_atocSupport(false) , m_conservativeRasterSupport(false) , m_flip(false) , m_hash( (BX_PLATFORM_WINDOWS<<1) | BX_ARCH_64BIT) , m_backBufferFbo(0) , m_msaaBackBufferFbo(0) , m_msaaBlitProgram(0) , m_clearQuadColor(BGFX_INVALID_HANDLE) , m_clearQuadDepth(BGFX_INVALID_HANDLE) { bx::memSet(m_msaaBackBufferRbos, 0, sizeof(m_msaaBackBufferRbos) ); } ~RendererContextGL() { } bool init(const Init& _init) { struct ErrorState { enum Enum { Default, }; }; ErrorState::Enum errorState = ErrorState::Default; if (_init.debug || _init.profile) { m_renderdocdll = loadRenderDoc(); } m_fbh.idx = kInvalidHandle; bx::memSet(m_uniforms, 0, sizeof(m_uniforms) ); bx::memSet(&m_resolution, 0, sizeof(m_resolution) ); setRenderContextSize(_init.resolution.width, _init.resolution.height, _init.resolution.reset); m_vendor = getGLString(GL_VENDOR); m_renderer = getGLString(GL_RENDERER); m_version = getGLString(GL_VERSION); m_glslVersion = getGLString(GL_SHADING_LANGUAGE_VERSION); { if (BX_ENABLED(BX_PLATFORM_EMSCRIPTEN) ) { int32_t majorGlVersion = 0; int32_t minorGlVersion = 0; const char* version = m_version; while (*version && !bx::isNumeric(*version) ) { ++version; } bx::fromString(&majorGlVersion, version); bx::fromString(&minorGlVersion, version + 2); int32_t glVersion = majorGlVersion*10 + minorGlVersion; BX_TRACE("WebGL context version %d (%d.%d).", glVersion, majorGlVersion, minorGlVersion); m_gles3 = glVersion >= 30; } else { m_gles3 = BX_ENABLED(BGFX_CONFIG_RENDERER_OPENGLES >= 30); } } for (uint32_t ii = 0; ii < BX_COUNTOF(s_vendorIds); ++ii) { const VendorId& vendorId = s_vendorIds[ii]; if (0 == bx::strCmp(vendorId.name, m_vendor, bx::strLen(vendorId.name) ) ) { g_caps.vendorId = vendorId.id; break; } } m_workaround.reset(); GLint numCmpFormats = 0; GL_CHECK(glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &numCmpFormats) ); BX_TRACE("GL_NUM_COMPRESSED_TEXTURE_FORMATS %d", numCmpFormats); GLint* cmpFormat = NULL; if (0 < numCmpFormats) { numCmpFormats = numCmpFormats > 256 ? 256 : numCmpFormats; cmpFormat = (GLint*)alloca(sizeof(GLint)*numCmpFormats); GL_CHECK(glGetIntegerv(GL_COMPRESSED_TEXTURE_FORMATS, cmpFormat) ); for (GLint ii = 0; ii < numCmpFormats; ++ii) { GLint internalFmt = cmpFormat[ii]; uint32_t fmt = uint32_t(TextureFormat::Unknown); for (uint32_t jj = 0; jj < fmt; ++jj) { if (s_textureFormat[jj].m_internalFmt == (GLenum)internalFmt) { s_textureFormat[jj].m_supported = true; fmt = jj; } } BX_TRACE(" %3d: %8x %s", ii, internalFmt, getName( (TextureFormat::Enum)fmt) ); } } if (BX_ENABLED(BGFX_CONFIG_DEBUG) ) { #define GL_GET(_pname, _min) BX_TRACE(" " #_pname " %d (min: %d)", glGet(_pname), _min) BX_TRACE("Defaults:"); #if BGFX_CONFIG_RENDERER_OPENGL >= 41 || BGFX_CONFIG_RENDERER_OPENGLES GL_GET(GL_MAX_FRAGMENT_UNIFORM_VECTORS, 16); GL_GET(GL_MAX_VERTEX_UNIFORM_VECTORS, 128); GL_GET(GL_MAX_VARYING_VECTORS, 8); #else GL_GET(GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, 16 * 4); GL_GET(GL_MAX_VERTEX_UNIFORM_COMPONENTS, 128 * 4); GL_GET(GL_MAX_VARYING_FLOATS, 8 * 4); #endif // BGFX_CONFIG_RENDERER_OPENGL >= 41 || BGFX_CONFIG_RENDERER_OPENGLES GL_GET(GL_MAX_VERTEX_ATTRIBS, 8); GL_GET(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, 8); GL_GET(GL_MAX_CUBE_MAP_TEXTURE_SIZE, 16); GL_GET(GL_MAX_TEXTURE_IMAGE_UNITS, 8); GL_GET(GL_MAX_TEXTURE_SIZE, 64); GL_GET(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, 0); GL_GET(GL_MAX_RENDERBUFFER_SIZE, 1); GL_GET(GL_MAX_COLOR_ATTACHMENTS, 1); GL_GET(GL_MAX_DRAW_BUFFERS, 1); #undef GL_GET BX_TRACE(" Vendor: %s", m_vendor); BX_TRACE(" Renderer: %s", m_renderer); BX_TRACE(" Version: %s", m_version); BX_TRACE("GLSL version: %s", m_glslVersion); } // Initial binary shader hash depends on driver version. m_hash = ( (BX_PLATFORM_WINDOWS<<1) | BX_ARCH_64BIT) ^ (uint64_t(getGLStringHash(GL_VENDOR ) )<<32) ^ (uint64_t(getGLStringHash(GL_RENDERER) )<<0 ) ^ (uint64_t(getGLStringHash(GL_VERSION ) )<<16) ; if (BX_ENABLED(BGFX_CONFIG_RENDERER_OPENGLES >= 31) && 0 == bx::strCmp(m_vendor, "Imagination Technologies") && !bx::strFind(m_version, "(SDK 3.5@3510720)").isEmpty() ) { // Skip initializing extensions that are broken in emulator. s_extension[Extension::ARB_program_interface_query ].m_initialize = s_extension[Extension::ARB_shader_storage_buffer_object].m_initialize = false; } if (BX_ENABLED(BGFX_CONFIG_RENDERER_OPENGLES) && 0 == bx::strCmp(m_vendor, "Imagination Technologies") && !bx::strFind(m_version, "1.8@905891").isEmpty() ) { m_workaround.m_detachShader = false; } if (BX_ENABLED(BGFX_CONFIG_RENDERER_USE_EXTENSIONS) ) { const char* extensions = (const char*)glGetString(GL_EXTENSIONS); getGlError(); // ignore error if glGetString returns NULL. if (NULL != extensions) { bx::StringView ext(extensions); while (!ext.isEmpty() ) { const bx::StringView space = bx::strFind(ext, ' '); const bx::StringView token = bx::StringView(ext.getPtr(), space.getPtr() ); updateExtension(token); ext.set(space.getPtr() + (space.isEmpty() ? 0 : 1), ext.getTerm() ); } } else if (NULL != glGetStringi) { GLint numExtensions = 0; glGetIntegerv(GL_NUM_EXTENSIONS, &numExtensions); getGlError(); // ignore error if glGetIntegerv returns NULL. for (GLint index = 0; index < numExtensions; ++index) { const char* name = (const char*)glGetStringi(GL_EXTENSIONS, index); updateExtension(name); } } BX_TRACE("Supported extensions:"); for (uint32_t ii = 0; ii < Extension::Count; ++ii) { if (s_extension[ii].m_supported) { BX_TRACE("\t%2d: %s", ii, s_extension[ii].m_name); } } } if (BX_ENABLED(BGFX_CONFIG_RENDERER_OPENGL) && !s_extension[Extension::ARB_framebuffer_object].m_supported) { BX_TRACE("Init error: ARB_framebuffer_object not supported."); goto error; } { // Allow all texture filters. bx::memSet(s_textureFilter, true, BX_COUNTOF(s_textureFilter) ); bool bc123Supported = 0 || s_extension[Extension::EXT_texture_compression_s3tc ].m_supported || s_extension[Extension::MOZ_WEBGL_compressed_texture_s3tc ].m_supported || s_extension[Extension::WEBGL_compressed_texture_s3tc ].m_supported || s_extension[Extension::WEBKIT_WEBGL_compressed_texture_s3tc].m_supported ; s_textureFormat[TextureFormat::BC1].m_supported |= bc123Supported || s_extension[Extension::ANGLE_texture_compression_dxt1].m_supported || s_extension[Extension::EXT_texture_compression_dxt1 ].m_supported ; if (!s_textureFormat[TextureFormat::BC1].m_supported && ( s_textureFormat[TextureFormat::BC2].m_supported || s_textureFormat[TextureFormat::BC3].m_supported) ) { // If RGBA_S3TC_DXT1 is not supported, maybe RGB_S3TC_DXT1 is? for (GLint ii = 0; ii < numCmpFormats; ++ii) { if (GL_COMPRESSED_RGB_S3TC_DXT1_EXT == cmpFormat[ii]) { setTextureFormat(TextureFormat::BC1, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_COMPRESSED_RGB_S3TC_DXT1_EXT); s_textureFormat[TextureFormat::BC1].m_supported = true; break; } } } s_textureFormat[TextureFormat::BC2].m_supported |= bc123Supported || s_extension[Extension::ANGLE_texture_compression_dxt3 ].m_supported || s_extension[Extension::CHROMIUM_texture_compression_dxt3].m_supported ; s_textureFormat[TextureFormat::BC3].m_supported |= bc123Supported || s_extension[Extension::ANGLE_texture_compression_dxt5 ].m_supported || s_extension[Extension::CHROMIUM_texture_compression_dxt5].m_supported ; if (s_extension[Extension::EXT_texture_compression_latc].m_supported) { setTextureFormat(TextureFormat::BC4, GL_COMPRESSED_LUMINANCE_LATC1_EXT, GL_COMPRESSED_LUMINANCE_LATC1_EXT); setTextureFormat(TextureFormat::BC5, GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT, GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT); } if (s_extension[Extension::ARB_texture_compression_rgtc].m_supported || s_extension[Extension::EXT_texture_compression_rgtc].m_supported) { setTextureFormat(TextureFormat::BC4, GL_COMPRESSED_RED_RGTC1, GL_COMPRESSED_RED_RGTC1); setTextureFormat(TextureFormat::BC5, GL_COMPRESSED_RG_RGTC2, GL_COMPRESSED_RG_RGTC2); } bool etc1Supported = 0 || s_extension[Extension::OES_compressed_ETC1_RGB8_texture].m_supported || s_extension[Extension::WEBGL_compressed_texture_etc1 ].m_supported ; s_textureFormat[TextureFormat::ETC1].m_supported |= etc1Supported; bool etc2Supported = !!(BGFX_CONFIG_RENDERER_OPENGLES >= 30) || s_extension[Extension::ARB_ES3_compatibility].m_supported ; s_textureFormat[TextureFormat::ETC2 ].m_supported |= etc2Supported; s_textureFormat[TextureFormat::ETC2A ].m_supported |= etc2Supported; s_textureFormat[TextureFormat::ETC2A1].m_supported |= etc2Supported; if (!s_textureFormat[TextureFormat::ETC1].m_supported && s_textureFormat[TextureFormat::ETC2].m_supported) { // When ETC2 is supported override ETC1 texture format settings. s_textureFormat[TextureFormat::ETC1].m_internalFmt = GL_COMPRESSED_RGB8_ETC2; s_textureFormat[TextureFormat::ETC1].m_fmt = GL_COMPRESSED_RGB8_ETC2; s_textureFormat[TextureFormat::ETC1].m_supported = true; } bool ptc1Supported = 0 || s_extension[Extension::IMG_texture_compression_pvrtc ].m_supported || s_extension[Extension::WEBGL_compressed_texture_pvrtc].m_supported ; s_textureFormat[TextureFormat::PTC12 ].m_supported |= ptc1Supported; s_textureFormat[TextureFormat::PTC14 ].m_supported |= ptc1Supported; s_textureFormat[TextureFormat::PTC12A].m_supported |= ptc1Supported; s_textureFormat[TextureFormat::PTC14A].m_supported |= ptc1Supported; bool ptc2Supported = s_extension[Extension::IMG_texture_compression_pvrtc2].m_supported; s_textureFormat[TextureFormat::PTC22].m_supported |= ptc2Supported; s_textureFormat[TextureFormat::PTC24].m_supported |= ptc2Supported; if (BX_ENABLED(BGFX_CONFIG_RENDERER_OPENGLES) ) { if (m_gles3) { setTextureFormat(TextureFormat::R16F, GL_R16F, GL_RED, 0x140B /* == GL_HALF_FLOAT, but bgfx overwrites it globally with GL_HALF_FLOAT_OES */); setTextureFormat(TextureFormat::RG16F, GL_RG16F, GL_RG, 0x140B /* == GL_HALF_FLOAT, but bgfx overwrites it globally with GL_HALF_FLOAT_OES */); setTextureFormat(TextureFormat::RGBA16F, GL_RGBA16F, GL_RGBA, 0x140B /* == GL_HALF_FLOAT, but bgfx overwrites it globally with GL_HALF_FLOAT_OES */); } else { setTextureFormat(TextureFormat::RGBA16F, GL_RGBA, GL_RGBA, GL_HALF_FLOAT); // Note: this is actually GL_HALF_FLOAT_OES and not GL_HALF_FLOAT if compiling for GLES target. setTextureFormat(TextureFormat::RGBA32F, GL_RGBA, GL_RGBA, GL_FLOAT); // internalFormat and format must match: // https://www.khronos.org/opengles/sdk/docs/man/xhtml/glTexImage2D.xml setTextureFormat(TextureFormat::RGBA8, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE); setTextureFormat(TextureFormat::B5G6R5, GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5_REV); setTextureFormat(TextureFormat::R5G6B5, GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5_REV); setTextureFormat(TextureFormat::BGRA4, GL_BGRA, GL_BGRA, GL_UNSIGNED_SHORT_4_4_4_4_REV); setTextureFormat(TextureFormat::RGBA4, GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4_REV); setTextureFormat(TextureFormat::BGR5A1, GL_BGRA, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV); setTextureFormat(TextureFormat::RGB5A1, GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV); if (s_extension[Extension::EXT_sRGB].m_supported) { setTextureFormatSrgb(TextureFormat::RGBA8, GL_SRGB_ALPHA_EXT, GL_SRGB_ALPHA_EXT); setTextureFormatSrgb(TextureFormat::RGB8, GL_SRGB_EXT, GL_SRGB_EXT); } if (s_extension[Extension::EXT_texture_swizzle].m_supported) { s_textureFormat[TextureFormat::R5G6B5].m_mapping[0] = GL_BLUE; s_textureFormat[TextureFormat::R5G6B5].m_mapping[2] = GL_RED; } if (s_extension[Extension::OES_texture_half_float].m_supported || s_extension[Extension::OES_texture_float ].m_supported) { // https://www.khronos.org/registry/gles/extensions/OES/OES_texture_float.txt // When half/float is available via extensions texture will be marked as // incomplete if it uses anything other than nearest filter. const bool linear16F = s_extension[Extension::OES_texture_half_float_linear].m_supported; const bool linear32F = s_extension[Extension::OES_texture_float_linear ].m_supported; s_textureFilter[TextureFormat::R16F] = linear16F; s_textureFilter[TextureFormat::RG16F] = linear16F; s_textureFilter[TextureFormat::RGBA16F] = linear16F; s_textureFilter[TextureFormat::R32F] = linear32F; s_textureFilter[TextureFormat::RG32F] = linear32F; s_textureFilter[TextureFormat::RGBA32F] = linear32F; } } if (BX_ENABLED(BX_PLATFORM_EMSCRIPTEN) && (s_extension[Extension::WEBGL_depth_texture].m_supported || s_extension[Extension::MOZ_WEBGL_depth_texture].m_supported || s_extension[Extension::WEBKIT_WEBGL_depth_texture].m_supported) ) { setTextureFormat(TextureFormat::D16, GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT); setTextureFormat(TextureFormat::D24, GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT); // N.b. OpenGL ES does not guarantee that there are 24 bits available here, could be 16. See https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/ setTextureFormat(TextureFormat::D32, GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT); // N.b. same as above. setTextureFormat(TextureFormat::D24S8, GL_DEPTH_STENCIL, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8); } // OpenGL ES 3.0 depth formats. if (m_gles3) { setTextureFormat(TextureFormat::D16, GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT); setTextureFormat(TextureFormat::D24, GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT); setTextureFormat(TextureFormat::D32, GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT); setTextureFormat(TextureFormat::D24S8, GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8); setTextureFormat(TextureFormat::D16F, GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT); // GLES 3.0 does not have D16F, overshoot to D32F setTextureFormat(TextureFormat::D24F, GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT); // GLES 3.0 does not have D24F, overshoot to D32F setTextureFormat(TextureFormat::D32F, GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT); setTextureFormat(TextureFormat::D0S8, GL_STENCIL_INDEX8, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE); // Only works as renderbuffer, not as texture } } else { setTextureFormat(TextureFormat::R5G6B5, GL_BGR, GL_BGR, GL_UNSIGNED_SHORT_5_6_5); setTextureFormatSrgb(TextureFormat::R5G6B5, GL_ZERO, GL_BGR); } if (BX_ENABLED(BGFX_CONFIG_RENDERER_OPENGL) || m_gles3) { setTextureFormat(TextureFormat::R8I, GL_R8I, GL_RED_INTEGER, GL_BYTE); setTextureFormat(TextureFormat::R8U, GL_R8UI, GL_RED_INTEGER, GL_UNSIGNED_BYTE); setTextureFormat(TextureFormat::R16I, GL_R16I, GL_RED_INTEGER, GL_SHORT); setTextureFormat(TextureFormat::R16U, GL_R16UI, GL_RED_INTEGER, GL_UNSIGNED_SHORT); // setTextureFormat(TextureFormat::RG16, GL_RG16UI, GL_RG_INTEGER, GL_UNSIGNED_SHORT); // setTextureFormat(TextureFormat::RGBA16, GL_RGBA16UI, GL_RGBA_INTEGER, GL_UNSIGNED_SHORT); setTextureFormat(TextureFormat::R32U, GL_R32UI, GL_RED_INTEGER, GL_UNSIGNED_INT); setTextureFormat(TextureFormat::RG32U, GL_RG32UI, GL_RG_INTEGER, GL_UNSIGNED_INT); setTextureFormat(TextureFormat::RGBA32U, GL_RGBA32UI, GL_RGBA_INTEGER, GL_UNSIGNED_INT); } if (s_extension[Extension::EXT_texture_format_BGRA8888 ].m_supported || s_extension[Extension::EXT_bgra ].m_supported || s_extension[Extension::IMG_texture_format_BGRA8888 ].m_supported ||
{'addition_count': 3, 'commit_subject': 'Fixes #2000. Restored old behavior of handling shaders with "#version 430" in them.', 'deletion_count': 2, 'file_extension': '.cpp', 'lang': 'cpp', 'license': 'bsd-2-clause', 'repo_name': 'bkaradzic/bgfx'}