diff options
Diffstat (limited to '3rdparty/bgfx/src/renderer_gl.cpp')
-rw-r--r-- | 3rdparty/bgfx/src/renderer_gl.cpp | 2663 |
1 files changed, 1406 insertions, 1257 deletions
diff --git a/3rdparty/bgfx/src/renderer_gl.cpp b/3rdparty/bgfx/src/renderer_gl.cpp index 8f4903a2cb1..9d7e0d3d701 100644 --- a/3rdparty/bgfx/src/renderer_gl.cpp +++ b/3rdparty/bgfx/src/renderer_gl.cpp @@ -11,20 +11,6 @@ # include <bx/uint32_t.h> # include "hmd_ovr.h" -#if BGFX_CONFIG_PROFILER_REMOTERY -# define BGFX_GPU_PROFILER_BIND() rmt_BindOpenGL() -# define BGFX_GPU_PROFILER_UNBIND() rmt_UnbindOpenGL() -# define BGFX_GPU_PROFILER_BEGIN(_group, _name, _color) rmt_BeginOpenGLSample(_group##_##_name) -# define BGFX_GPU_PROFILER_BEGIN_DYNAMIC(_namestr) rmt_BeginOpenGLSampleDynamic(_namestr) -# define BGFX_GPU_PROFILER_END() rmt_EndOpenGLSample() -#else -# define BGFX_GPU_PROFILER_BIND() BX_NOOP() -# define BGFX_GPU_PROFILER_UNBIND() BX_NOOP() -# define BGFX_GPU_PROFILER_BEGIN(_group, _name, _color) BX_NOOP() -# define BGFX_GPU_PROFILER_BEGIN_DYNAMIC(_namestr) BX_NOOP() -# define BGFX_GPU_PROFILER_END() BX_NOOP() -#endif // BGFX_CONFIG_PROFILER_REMOTERY - namespace bgfx { namespace gl { static char s_viewName[BGFX_CONFIG_MAX_VIEWS][BGFX_CONFIG_MAX_VIEW_NAME]; @@ -63,6 +49,8 @@ namespace bgfx { namespace gl "a_bitangent", "a_color0", "a_color1", + "a_color2", + "a_color3", "a_indices", "a_weight", "a_texcoord0", @@ -269,7 +257,7 @@ namespace bgfx { namespace gl { GL_RGBA4, GL_ZERO, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4_REV, false }, // RGBA4 { GL_RGB5_A1, GL_ZERO, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, false }, // RGB5A1 { GL_RGB10_A2, GL_ZERO, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, false }, // RGB10A2 - { GL_R11F_G11F_B10F, GL_ZERO, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV, false }, // R11G11B10F + { GL_R11F_G11F_B10F, GL_ZERO, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV, false }, // RG11B10F { GL_ZERO, GL_ZERO, GL_ZERO, GL_ZERO, false }, // UnknownDepth { GL_DEPTH_COMPONENT16, GL_ZERO, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, false }, // D16 { GL_DEPTH_COMPONENT24, GL_ZERO, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, false }, // D24 @@ -352,7 +340,7 @@ namespace bgfx { namespace gl GL_RGBA4, // RGBA4 GL_RGB5_A1, // RGB5A1 GL_RGB10_A2, // RGB10A2 - GL_R11F_G11F_B10F, // R11G11B10F + GL_R11F_G11F_B10F, // RG11B10F GL_ZERO, // UnknownDepth GL_DEPTH_COMPONENT16, // D16 GL_DEPTH_COMPONENT24, // D24 @@ -433,7 +421,7 @@ namespace bgfx { namespace gl GL_RGBA4, // RGBA4 GL_RGB5_A1, // RGB5A1 GL_RGB10_A2, // RGB10A2 - GL_R11F_G11F_B10F, // R11G11B10F + GL_R11F_G11F_B10F, // RG11B10F GL_ZERO, // UnknownDepth GL_ZERO, // D16 GL_ZERO, // D24 @@ -896,15 +884,6 @@ namespace bgfx { namespace gl NULL }; - static const char* s_OES_texture_3D[] = - { - "texture3D", - "texture3DProj", - "texture3DLod", - "texture3DProjLod", - NULL - }; - static const char* s_uisamplers[] = { "isampler2D", @@ -918,11 +897,23 @@ namespace bgfx { namespace gl 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", @@ -940,6 +931,13 @@ namespace bgfx { namespace gl NULL }; + static const char* s_EXT_gpu_shader4[] = + { + "gl_VertexID", + "gl_InstanceID", + NULL + }; + static const char* s_ARB_gpu_shader5[] = { "bitfieldReverse", @@ -986,7 +984,7 @@ namespace bgfx { namespace gl // // If <length> is 0 then <marker> is assumed to be null-terminated. - uint32_t size = (0 == _length ? (uint32_t)bx::strnlen(_marker) : _length) + 1; + uint32_t size = (0 == _length ? (uint32_t)bx::strLen(_marker) : _length) + 1; size *= sizeof(wchar_t); wchar_t* name = (wchar_t*)alloca(size); mbstowcs(name, _marker, size-2); @@ -1045,7 +1043,7 @@ namespace bgfx { namespace gl glGetError(); // ignore error if glGetString returns NULL. if (NULL != str) { - return bx::hashMurmur2A(str, (uint32_t)bx::strnlen(str) ); + return bx::hash<bx::HashMurmur2A>(str, (uint32_t)bx::strLen(str) ); } return 0; @@ -1057,21 +1055,21 @@ namespace bgfx { namespace gl { char name[1024]; const char* pos = _extensions; - const char* end = _extensions + bx::strnlen(_extensions); + const char* end = _extensions + bx::strLen(_extensions); while (pos < end) { uint32_t len; - const char* space = bx::strnchr(pos, ' '); + const char* space = bx::strFind(pos, ' '); if (NULL != space) { len = bx::uint32_min(sizeof(name), (uint32_t)(space - pos) ); } else { - len = bx::uint32_min(sizeof(name), (uint32_t)bx::strnlen(pos) ); + len = bx::uint32_min(sizeof(name), (uint32_t)bx::strLen(pos) ); } - bx::strlncpy(name, BX_COUNTOF(name), pos, len); + bx::strCopy(name, BX_COUNTOF(name), pos, len); name[len] = '\0'; BX_TRACE("\t%s", name); @@ -1145,7 +1143,252 @@ namespace bgfx { namespace gl for (GLenum err = glGetError(); err != 0; err = glGetError() ); } - GLenum initTestTexture(TextureFormat::Enum _format, bool _srgb, bool _mipmaps) + 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 @@ -1153,13 +1396,15 @@ namespace bgfx { namespace gl : tfi.m_internalFmt ; - GLsizei size = (16*16*getBitsPerPixel(_format) )/8; + GLsizei bpp = bimg::getBitsPerPixel(bimg::TextureFormat::Enum(_format) ); + GLsizei size = (_dim*_dim*bpp)/8; void* data = NULL; - if (isDepth(_format) ) + if (bimg::isDepth(bimg::TextureFormat::Enum(_format) ) ) { _srgb = false; _mipmaps = false; + _array = false; } else { @@ -1169,35 +1414,29 @@ namespace bgfx { namespace gl flushGlError(); GLenum err = 0; - if (isCompressed(_format) ) + const GLenum target = _array + ? GL_TEXTURE_2D_ARRAY + : GL_TEXTURE_2D + ; + + if (bimg::isCompressed(bimg::TextureFormat::Enum(_format) ) ) { - glCompressedTexImage2D(GL_TEXTURE_2D, 0, internalFmt, 16, 16, 0, size, data); - err |= glGetError(); - if (_mipmaps) + for (uint32_t ii = 0, dim = _dim; ii < (_mipmaps ? 5u : 1u) && 0 == err; ++ii, dim >>= 1) { - glCompressedTexImage2D(GL_TEXTURE_2D, 1, internalFmt, 8, 8, 0, size, data); - err |= glGetError(); - glCompressedTexImage2D(GL_TEXTURE_2D, 2, internalFmt, 4, 4, 0, size, data); - err |= glGetError(); - glCompressedTexImage2D(GL_TEXTURE_2D, 3, internalFmt, 2, 2, 0, size, data); - err |= glGetError(); - glCompressedTexImage2D(GL_TEXTURE_2D, 4, internalFmt, 1, 1, 0, size, data); + 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 |= glGetError(); } } else { - glTexImage2D(GL_TEXTURE_2D, 0, internalFmt, 16, 16, 0, tfi.m_fmt, tfi.m_type, data); - err |= glGetError(); - if (_mipmaps) + for (uint32_t ii = 0, dim = _dim; ii < (_mipmaps ? 5u : 1u) && 0 == err; ++ii, dim >>= 1) { - glTexImage2D(GL_TEXTURE_2D, 1, internalFmt, 8, 8, 0, tfi.m_fmt, tfi.m_type, data); - err |= glGetError(); - glTexImage2D(GL_TEXTURE_2D, 2, internalFmt, 4, 4, 0, tfi.m_fmt, tfi.m_type, data); - err |= glGetError(); - glTexImage2D(GL_TEXTURE_2D, 3, internalFmt, 2, 2, 0, tfi.m_fmt, tfi.m_type, data); - err |= glGetError(); - glTexImage2D(GL_TEXTURE_2D, 4, internalFmt, 1, 1, 0, tfi.m_fmt, tfi.m_type, data); + dim = bx::uint32_max(1, dim); + size = (dim*dim*bpp)/8; + texImage(target, 0, ii, internalFmt, dim, dim, 0, 0, tfi.m_fmt, tfi.m_type, data); err |= glGetError(); } } @@ -1205,7 +1444,7 @@ namespace bgfx { namespace gl return err; } - static bool isTextureFormatValid(TextureFormat::Enum _format, bool _srgb = false, bool _mipAutogen = false) + static bool isTextureFormatValid(TextureFormat::Enum _format, bool _srgb = false, bool _mipAutogen = false, bool _array = false, GLsizei _dim = 16) { const TextureFormatInfo& tfi = s_textureFormat[_format]; GLenum internalFmt = _srgb @@ -1217,18 +1456,46 @@ namespace bgfx { namespace gl return false; } + const GLenum target = _array + ? GL_TEXTURE_2D_ARRAY + : GL_TEXTURE_2D + ; + GLuint id; GL_CHECK(glGenTextures(1, &id) ); - GL_CHECK(glBindTexture(GL_TEXTURE_2D, id) ); + GL_CHECK(glBindTexture(target, id) ); - GLenum err = initTestTexture(_format, _srgb, _mipAutogen); - BX_WARN(0 == err, "TextureFormat::%s is not supported (%x: %s).", getName(_format), err, glEnumName(err) ); + GLenum err = 0; + if (_array) + { + glTexStorage3D(target + , 1 + GLsizei(bx::flog2(float(_dim) ) ) + , internalFmt + , _dim + , _dim + , _dim + ); + err = glGetError(); + } - if (0 == err - && _mipAutogen) + if (0 == err) { - glGenerateMipmap(GL_TEXTURE_2D); - err = glGetError(); + 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 = glGetError(); + } } GL_CHECK(glDeleteTextures(1, &id) ); @@ -1236,7 +1503,7 @@ namespace bgfx { namespace gl return 0 == err; } - static bool isImageFormatValid(TextureFormat::Enum _format) + static bool isImageFormatValid(TextureFormat::Enum _format, GLsizei _dim = 16) { if (GL_ZERO == s_imageFormat[_format]) { @@ -1250,7 +1517,7 @@ namespace bgfx { namespace gl flushGlError(); GLenum err = 0; - glTexStorage2D(GL_TEXTURE_2D, 1, s_imageFormat[_format], 16, 16); + glTexStorage2D(GL_TEXTURE_2D, 1, s_imageFormat[_format], _dim, _dim); err |= glGetError(); if (0 == err) { @@ -1270,7 +1537,12 @@ namespace bgfx { namespace gl return 0 == err; } - static bool isFramebufferFormatValid(TextureFormat::Enum _format, bool _srgb = false) + static bool isFramebufferFormatValid( + TextureFormat::Enum _format + , bool _srgb = false + , bool _writeOnly = false + , GLsizei _dim = 16 + ) { const TextureFormatInfo& tfi = s_textureFormat[_format]; GLenum internalFmt = _srgb @@ -1283,6 +1555,24 @@ namespace bgfx { namespace gl 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 = glGetError(); + return 0 == err; + } + GLuint fbo; GL_CHECK(glGenFramebuffers(1, &fbo) ); GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, fbo) ); @@ -1291,12 +1581,12 @@ namespace bgfx { namespace gl GL_CHECK(glGenTextures(1, &id) ); GL_CHECK(glBindTexture(GL_TEXTURE_2D, id) ); - GLenum err = initTestTexture(_format, _srgb, false); + GLenum err = initTestTexture(_format, _srgb, false, false, _dim); GLenum attachment; - if (isDepth(_format) ) + if (bimg::isDepth(bimg::TextureFormat::Enum(_format) ) ) { - const ImageBlockInfo& info = getBlockInfo(_format); + const bimg::ImageBlockInfo& info = bimg::getBlockInfo(bimg::TextureFormat::Enum(_format) ); if (0 == info.depthBits) { attachment = GL_STENCIL_ATTACHMENT; @@ -1355,12 +1645,12 @@ namespace bgfx { namespace gl && extension.m_initialize) { const char* ext = _name; - if (0 == bx::strncmp(ext, "GL_", 3) ) // skip GL_ + if (0 == bx::strCmp(ext, "GL_", 3) ) // skip GL_ { ext += 3; } - if (0 == bx::strncmp(ext, extension.m_name) ) + if (0 == bx::strCmp(ext, extension.m_name) ) { extension.m_supported = true; supported = true; @@ -1379,11 +1669,11 @@ namespace bgfx { namespace gl public: VRImplOVRGL(); - virtual bool createSwapChain(const VRDesc& _desc, int _msaaSamples, int _mirrorWidth, int _mirrorHeight) BX_OVERRIDE; - virtual void destroySwapChain() BX_OVERRIDE; - virtual void destroyMirror() BX_OVERRIDE; - virtual void makeRenderTargetActive(const VRDesc& _desc) BX_OVERRIDE; - virtual bool submitSwapChain(const VRDesc& _desc) BX_OVERRIDE; + virtual bool createSwapChain(const VRDesc& _desc, int _msaaSamples, int _mirrorWidth, int _mirrorHeight) override; + virtual void destroySwapChain() override; + virtual void destroyMirror() override; + virtual void makeRenderTargetActive(const VRDesc& _desc) override; + virtual bool submitSwapChain(const VRDesc& _desc) override; private: GLuint m_eyeTarget[4]; @@ -1412,6 +1702,16 @@ namespace bgfx { namespace gl { "Intel", BGFX_PCI_ID_INTEL }, }; + struct Workaround + { + void reset() + { + m_detachShader = true; + } + + bool m_detachShader; + }; + struct RendererContextGL : public RendererContextI { RendererContextGL() @@ -1450,11 +1750,21 @@ namespace bgfx { namespace gl { } - void init() + bool init() { + struct ErrorState + { + enum Enum + { + Default, + }; + }; + + ErrorState::Enum errorState = ErrorState::Default; + m_renderdocdll = loadRenderDoc(); - m_fbh.idx = invalidHandle; + m_fbh.idx = kInvalidHandle; bx::memSet(m_uniforms, 0, sizeof(m_uniforms) ); bx::memSet(&m_resolution, 0, sizeof(m_resolution) ); @@ -1475,13 +1785,15 @@ namespace bgfx { namespace gl for (uint32_t ii = 0; ii < BX_COUNTOF(s_vendorIds); ++ii) { const VendorId& vendorId = s_vendorIds[ii]; - if (0 == bx::strncmp(vendorId.name, m_vendor, bx::strnlen(vendorId.name) ) ) + 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); @@ -1549,14 +1861,21 @@ namespace bgfx { namespace gl ; if (BX_ENABLED(BGFX_CONFIG_RENDERER_OPENGLES >= 31) - && 0 == bx::strncmp(m_vendor, "Imagination Technologies") - && NULL != bx::strnstr(m_version, "(SDK 3.5@3510720)") ) + && 0 == bx::strCmp(m_vendor, "Imagination Technologies") + && NULL != bx::strFind(m_version, "(SDK 3.5@3510720)") ) { // 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") + && NULL != bx::strFind(m_version, "1.8@905891") ) + { + m_workaround.m_detachShader = false; + } + if (BX_ENABLED(BGFX_CONFIG_RENDERER_USE_EXTENSIONS) ) { const char* extensions = (const char*)glGetString(GL_EXTENSIONS); @@ -1565,22 +1884,22 @@ namespace bgfx { namespace gl { char name[1024]; const char* pos = extensions; - const char* end = extensions + bx::strnlen(extensions); + const char* end = extensions + bx::strLen(extensions); uint32_t index = 0; while (pos < end) { uint32_t len; - const char* space = bx::strnchr(pos, ' '); + const char* space = bx::strFind(pos, ' '); if (NULL != space) { len = bx::uint32_min(sizeof(name), (uint32_t)(space - pos) ); } else { - len = bx::uint32_min(sizeof(name), (uint32_t)bx::strnlen(pos) ); + len = bx::uint32_min(sizeof(name), (uint32_t)bx::strLen(pos) ); } - bx::strlncpy(name, BX_COUNTOF(name), pos, len); + bx::strCopy(name, BX_COUNTOF(name), pos, len); name[len] = '\0'; updateExtension(name); @@ -1612,624 +1931,642 @@ namespace bgfx { namespace gl } } - // 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 (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; + } - 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) + // 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 (GL_COMPRESSED_RGB_S3TC_DXT1_EXT == cmpFormat[ii]) + // If RGBA_S3TC_DXT1 is not supported, maybe RGB_S3TC_DXT1 is? + for (GLint ii = 0; ii < numCmpFormats; ++ii) { - setTextureFormat(TextureFormat::BC1, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_COMPRESSED_RGB_S3TC_DXT1_EXT); - s_textureFormat[TextureFormat::BC1].m_supported = true; - break; + 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 - ; + 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 + ; - 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); - } + 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::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); - } + 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); + } - 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; + 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 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; + 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; - 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 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; - 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; + 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 ptc2Supported = s_extension[Extension::IMG_texture_compression_pvrtc2].m_supported; - s_textureFormat[TextureFormat::PTC22].m_supported |= ptc2Supported; - s_textureFormat[TextureFormat::PTC24].m_supported |= ptc2Supported; + 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; - if (BX_ENABLED(BGFX_CONFIG_RENDERER_OPENGLES) ) - { - setTextureFormat(TextureFormat::D32, GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT); + 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 < 30) ) + if (BX_ENABLED(BGFX_CONFIG_RENDERER_OPENGLES) ) { - setTextureFormat(TextureFormat::RGBA16F, GL_RGBA, GL_RGBA, GL_HALF_FLOAT); - 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::R5G6B5, GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5_REV); - setTextureFormat(TextureFormat::RGBA4, GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4_REV); - setTextureFormat(TextureFormat::RGB5A1, GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV); + setTextureFormat(TextureFormat::D32, GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT); - if (s_extension[Extension::OES_texture_half_float].m_supported - || s_extension[Extension::OES_texture_float ].m_supported) + if (BX_ENABLED(BGFX_CONFIG_RENDERER_OPENGLES < 30) ) { - // 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; - } + setTextureFormat(TextureFormat::RGBA16F, GL_RGBA, GL_RGBA, GL_HALF_FLOAT); + 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::R5G6B5, GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5_REV); + setTextureFormat(TextureFormat::RGBA4, GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4_REV); + setTextureFormat(TextureFormat::RGB5A1, GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV); + + 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_IOS) || BX_ENABLED(BX_PLATFORM_EMSCRIPTEN)) - { - setTextureFormat(TextureFormat::D16, GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT); - setTextureFormat(TextureFormat::D24S8, GL_DEPTH_STENCIL, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8); + if (BX_ENABLED(BX_PLATFORM_IOS) || BX_ENABLED(BX_PLATFORM_EMSCRIPTEN)) + { + setTextureFormat(TextureFormat::D16, GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT); + setTextureFormat(TextureFormat::D24S8, GL_DEPTH_STENCIL, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8); + } } } - } - - if (BX_ENABLED(BGFX_CONFIG_RENDERER_OPENGL) - || BX_ENABLED(BGFX_CONFIG_RENDERER_OPENGLES >= 30) ) - { - 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 - || s_extension[Extension::APPLE_texture_format_BGRA8888].m_supported) - { - if (BX_ENABLED(BGFX_CONFIG_RENDERER_OPENGL) ) + if (BX_ENABLED(BGFX_CONFIG_RENDERER_OPENGL) + || BX_ENABLED(BGFX_CONFIG_RENDERER_OPENGLES >= 30) ) { - m_readPixelsFmt = GL_BGRA; + 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); } - // Mixing GLES and GL extensions here. OpenGL EXT_bgra and - // APPLE_texture_format_BGRA8888 wants - // format to be BGRA but internal format to stay RGBA, but - // EXT_texture_format_BGRA8888 wants both format and internal - // format to be BGRA. - // - // Reference: - // https://www.khronos.org/registry/gles/extensions/EXT/EXT_texture_format_BGRA8888.txt - // https://www.opengl.org/registry/specs/EXT/bgra.txt - // https://www.khronos.org/registry/gles/extensions/APPLE/APPLE_texture_format_BGRA8888.txt - if (!s_extension[Extension::EXT_bgra ].m_supported - && !s_extension[Extension::APPLE_texture_format_BGRA8888].m_supported) + 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 + || s_extension[Extension::APPLE_texture_format_BGRA8888].m_supported) { - s_textureFormat[TextureFormat::BGRA8].m_internalFmt = GL_BGRA; + if (BX_ENABLED(BGFX_CONFIG_RENDERER_OPENGL) ) + { + m_readPixelsFmt = GL_BGRA; + } + + // Mixing GLES and GL extensions here. OpenGL EXT_bgra and + // APPLE_texture_format_BGRA8888 wants + // format to be BGRA but internal format to stay RGBA, but + // EXT_texture_format_BGRA8888 wants both format and internal + // format to be BGRA. + // + // Reference: + // https://www.khronos.org/registry/gles/extensions/EXT/EXT_texture_format_BGRA8888.txt + // https://www.opengl.org/registry/specs/EXT/bgra.txt + // https://www.khronos.org/registry/gles/extensions/APPLE/APPLE_texture_format_BGRA8888.txt + if (!s_extension[Extension::EXT_bgra ].m_supported + && !s_extension[Extension::APPLE_texture_format_BGRA8888].m_supported) + { + s_textureFormat[TextureFormat::BGRA8].m_internalFmt = GL_BGRA; + } + + if (!isTextureFormatValid(TextureFormat::BGRA8) ) + { + // Revert back to RGBA if texture can't be created. + setTextureFormat(TextureFormat::BGRA8, GL_RGBA, GL_BGRA, GL_UNSIGNED_BYTE); + } } - if (!isTextureFormatValid(TextureFormat::BGRA8) ) + if (BX_ENABLED(BX_PLATFORM_EMSCRIPTEN) + || !isTextureFormatValid(TextureFormat::R8) ) { - // Revert back to RGBA if texture can't be created. - setTextureFormat(TextureFormat::BGRA8, GL_RGBA, GL_BGRA, GL_UNSIGNED_BYTE); + // GL core has to use GL_R8 Issue#208, GLES2 has to use GL_LUMINANCE issue#226 + s_textureFormat[TextureFormat::R8].m_internalFmt = GL_LUMINANCE; + s_textureFormat[TextureFormat::R8].m_fmt = GL_LUMINANCE; } - } - if (BX_ENABLED(BX_PLATFORM_EMSCRIPTEN) - || !isTextureFormatValid(TextureFormat::R8) ) - { - // GL core has to use GL_R8 Issue#208, GLES2 has to use GL_LUMINANCE issue#226 - s_textureFormat[TextureFormat::R8].m_internalFmt = GL_LUMINANCE; - s_textureFormat[TextureFormat::R8].m_fmt = GL_LUMINANCE; - } - - for (uint32_t ii = BX_ENABLED(BX_PLATFORM_IOS) ? TextureFormat::Unknown : 0 // skip test on iOS! - ; ii < TextureFormat::Count - ; ++ii - ) - { - if (TextureFormat::Unknown != ii - && TextureFormat::UnknownDepth != ii) + for (uint32_t ii = BX_ENABLED(BX_PLATFORM_IOS) ? TextureFormat::Unknown : 0 // skip test on iOS! + ; ii < TextureFormat::Count + ; ++ii + ) { - s_textureFormat[ii].m_supported = isTextureFormatValid(TextureFormat::Enum(ii) ); + if (TextureFormat::Unknown != ii + && TextureFormat::UnknownDepth != ii) + { + s_textureFormat[ii].m_supported = isTextureFormatValid(TextureFormat::Enum(ii) ); + } } - } - if (BX_ENABLED(0) ) - { - // Disable all compressed texture formats. For testing only. - for (uint32_t ii = 0; ii < TextureFormat::Unknown; ++ii) + if (BX_ENABLED(0) ) { - s_textureFormat[ii].m_supported = false; + // Disable all compressed texture formats. For testing only. + for (uint32_t ii = 0; ii < TextureFormat::Unknown; ++ii) + { + s_textureFormat[ii].m_supported = false; + } } - } - - const bool computeSupport = false - || !!(BGFX_CONFIG_RENDERER_OPENGLES >= 31) - || s_extension[Extension::ARB_compute_shader].m_supported - ; - for (uint32_t ii = 0; ii < TextureFormat::Count; ++ii) - { - uint16_t supported = BGFX_CAPS_FORMAT_TEXTURE_NONE; - supported |= s_textureFormat[ii].m_supported - ? BGFX_CAPS_FORMAT_TEXTURE_2D - | BGFX_CAPS_FORMAT_TEXTURE_3D - | BGFX_CAPS_FORMAT_TEXTURE_CUBE - : BGFX_CAPS_FORMAT_TEXTURE_NONE - ; - - supported |= isTextureFormatValid(TextureFormat::Enum(ii), true) - ? BGFX_CAPS_FORMAT_TEXTURE_2D_SRGB - | BGFX_CAPS_FORMAT_TEXTURE_3D_SRGB - | BGFX_CAPS_FORMAT_TEXTURE_CUBE_SRGB - : BGFX_CAPS_FORMAT_TEXTURE_NONE + const bool computeSupport = false + || !!(BGFX_CONFIG_RENDERER_OPENGLES >= 31) + || s_extension[Extension::ARB_compute_shader].m_supported ; - supported |= isTextureFormatValid(TextureFormat::Enum(ii), false, true) - ? BGFX_CAPS_FORMAT_TEXTURE_MIP_AUTOGEN - : BGFX_CAPS_FORMAT_TEXTURE_NONE - ; + for (uint32_t ii = 0; ii < TextureFormat::Count; ++ii) + { + uint16_t supported = BGFX_CAPS_FORMAT_TEXTURE_NONE; + supported |= s_textureFormat[ii].m_supported + ? BGFX_CAPS_FORMAT_TEXTURE_2D + | BGFX_CAPS_FORMAT_TEXTURE_3D + | BGFX_CAPS_FORMAT_TEXTURE_CUBE + : BGFX_CAPS_FORMAT_TEXTURE_NONE + ; - supported |= computeSupport - && isImageFormatValid(TextureFormat::Enum(ii) ) - ? BGFX_CAPS_FORMAT_TEXTURE_IMAGE - : BGFX_CAPS_FORMAT_TEXTURE_NONE - ; + supported |= isTextureFormatValid(TextureFormat::Enum(ii), true) + ? BGFX_CAPS_FORMAT_TEXTURE_2D_SRGB + | BGFX_CAPS_FORMAT_TEXTURE_3D_SRGB + | BGFX_CAPS_FORMAT_TEXTURE_CUBE_SRGB + : BGFX_CAPS_FORMAT_TEXTURE_NONE + ; - supported |= isFramebufferFormatValid(TextureFormat::Enum(ii) ) - ? BGFX_CAPS_FORMAT_TEXTURE_FRAMEBUFFER - : BGFX_CAPS_FORMAT_TEXTURE_NONE - ; + supported |= isTextureFormatValid(TextureFormat::Enum(ii), false, true) + ? BGFX_CAPS_FORMAT_TEXTURE_MIP_AUTOGEN + : BGFX_CAPS_FORMAT_TEXTURE_NONE + ; - if (NULL != glGetInternalformativ) - { - GLint maxSamples; - glGetInternalformativ(GL_RENDERBUFFER - , s_textureFormat[ii].m_internalFmt - , GL_SAMPLES - , 1 - , &maxSamples - ); - GLenum err = glGetError(); - supported |= 0 == err && maxSamples > 0 - ? BGFX_CAPS_FORMAT_TEXTURE_FRAMEBUFFER_MSAA + supported |= computeSupport + && isImageFormatValid(TextureFormat::Enum(ii) ) + ? BGFX_CAPS_FORMAT_TEXTURE_IMAGE : BGFX_CAPS_FORMAT_TEXTURE_NONE ; - glGetInternalformativ(GL_TEXTURE_2D_MULTISAMPLE - , s_textureFormat[ii].m_internalFmt - , GL_SAMPLES - , 1 - , &maxSamples - ); - err = glGetError(); - supported |= 0 == err && maxSamples > 0 - ? BGFX_CAPS_FORMAT_TEXTURE_MSAA + supported |= isFramebufferFormatValid(TextureFormat::Enum(ii) ) + ? BGFX_CAPS_FORMAT_TEXTURE_FRAMEBUFFER : BGFX_CAPS_FORMAT_TEXTURE_NONE ; - } - g_caps.formats[ii] = supported; - } + supported |= isFramebufferFormatValid(TextureFormat::Enum(ii), false, true) + ? BGFX_CAPS_FORMAT_TEXTURE_FRAMEBUFFER + : BGFX_CAPS_FORMAT_TEXTURE_NONE + ; - g_caps.supported |= !!(BGFX_CONFIG_RENDERER_OPENGL || BGFX_CONFIG_RENDERER_OPENGLES >= 30) - || s_extension[Extension::OES_texture_3D].m_supported - ? BGFX_CAPS_TEXTURE_3D - : 0 - ; - g_caps.supported |= !!(BGFX_CONFIG_RENDERER_OPENGL || BGFX_CONFIG_RENDERER_OPENGLES >= 30) - || s_extension[Extension::EXT_shadow_samplers].m_supported - ? BGFX_CAPS_TEXTURE_COMPARE_ALL - : 0 - ; - g_caps.supported |= !!(BGFX_CONFIG_RENDERER_OPENGL || BGFX_CONFIG_RENDERER_OPENGLES >= 30) - || s_extension[Extension::OES_vertex_half_float].m_supported - ? BGFX_CAPS_VERTEX_ATTRIB_HALF - : 0 - ; - g_caps.supported |= false - || s_extension[Extension::ARB_vertex_type_2_10_10_10_rev].m_supported - || s_extension[Extension::OES_vertex_type_10_10_10_2].m_supported - ? BGFX_CAPS_VERTEX_ATTRIB_UINT10 - : 0 - ; - g_caps.supported |= !!(BGFX_CONFIG_RENDERER_OPENGL || BGFX_CONFIG_RENDERER_OPENGLES >= 30) - || s_extension[Extension::EXT_frag_depth].m_supported - ? BGFX_CAPS_FRAGMENT_DEPTH - : 0 - ; - g_caps.supported |= s_extension[Extension::ARB_draw_buffers_blend].m_supported - ? BGFX_CAPS_BLEND_INDEPENDENT - : 0 - ; - g_caps.supported |= s_extension[Extension::INTEL_fragment_shader_ordering].m_supported - ? BGFX_CAPS_FRAGMENT_ORDERING - : 0 - ; - g_caps.supported |= !!(BGFX_CONFIG_RENDERER_OPENGL || BGFX_CONFIG_RENDERER_OPENGLES >= 30) - || s_extension[Extension::OES_element_index_uint].m_supported - ? BGFX_CAPS_INDEX32 - : 0 - ; + if (NULL != glGetInternalformativ) + { + GLint maxSamples; + glGetInternalformativ(GL_RENDERBUFFER + , s_textureFormat[ii].m_internalFmt + , GL_SAMPLES + , 1 + , &maxSamples + ); + GLenum err = glGetError(); + supported |= 0 == err && maxSamples > 0 + ? BGFX_CAPS_FORMAT_TEXTURE_FRAMEBUFFER_MSAA + : BGFX_CAPS_FORMAT_TEXTURE_NONE + ; - const bool drawIndirectSupported = false - || s_extension[Extension::AMD_multi_draw_indirect].m_supported - || s_extension[Extension::ARB_draw_indirect ].m_supported - || s_extension[Extension::ARB_multi_draw_indirect].m_supported - || s_extension[Extension::EXT_multi_draw_indirect].m_supported - ; + glGetInternalformativ(GL_TEXTURE_2D_MULTISAMPLE + , s_textureFormat[ii].m_internalFmt + , GL_SAMPLES + , 1 + , &maxSamples + ); + err = glGetError(); + supported |= 0 == err && maxSamples > 0 + ? BGFX_CAPS_FORMAT_TEXTURE_MSAA + : BGFX_CAPS_FORMAT_TEXTURE_NONE + ; + } - if (drawIndirectSupported) - { - if (NULL == glMultiDrawArraysIndirect - || NULL == glMultiDrawElementsIndirect) - { - glMultiDrawArraysIndirect = stubMultiDrawArraysIndirect; - glMultiDrawElementsIndirect = stubMultiDrawElementsIndirect; + g_caps.formats[ii] = supported; } - } - g_caps.supported |= drawIndirectSupported - ? BGFX_CAPS_DRAW_INDIRECT - : 0 - ; + g_caps.supported |= !!(BGFX_CONFIG_RENDERER_OPENGL || BGFX_CONFIG_RENDERER_OPENGLES >= 30) + || s_extension[Extension::OES_texture_3D].m_supported + ? BGFX_CAPS_TEXTURE_3D + : 0 + ; + g_caps.supported |= !!(BGFX_CONFIG_RENDERER_OPENGL || BGFX_CONFIG_RENDERER_OPENGLES >= 30) + || s_extension[Extension::EXT_shadow_samplers].m_supported + ? BGFX_CAPS_TEXTURE_COMPARE_ALL + : 0 + ; + g_caps.supported |= !!(BGFX_CONFIG_RENDERER_OPENGL || BGFX_CONFIG_RENDERER_OPENGLES >= 30) + || s_extension[Extension::OES_vertex_half_float].m_supported + ? BGFX_CAPS_VERTEX_ATTRIB_HALF + : 0 + ; + g_caps.supported |= false + || s_extension[Extension::ARB_vertex_type_2_10_10_10_rev].m_supported + || s_extension[Extension::OES_vertex_type_10_10_10_2].m_supported + ? BGFX_CAPS_VERTEX_ATTRIB_UINT10 + : 0 + ; + g_caps.supported |= !!(BGFX_CONFIG_RENDERER_OPENGL || BGFX_CONFIG_RENDERER_OPENGLES >= 30) + || s_extension[Extension::EXT_frag_depth].m_supported + ? BGFX_CAPS_FRAGMENT_DEPTH + : 0 + ; + g_caps.supported |= s_extension[Extension::ARB_draw_buffers_blend].m_supported + ? BGFX_CAPS_BLEND_INDEPENDENT + : 0 + ; + g_caps.supported |= s_extension[Extension::INTEL_fragment_shader_ordering].m_supported + ? BGFX_CAPS_FRAGMENT_ORDERING + : 0 + ; + g_caps.supported |= !!(BGFX_CONFIG_RENDERER_OPENGL || BGFX_CONFIG_RENDERER_OPENGLES >= 30) + || s_extension[Extension::OES_element_index_uint].m_supported + ? BGFX_CAPS_INDEX32 + : 0 + ; - if (NULL == glPolygonMode) - { - glPolygonMode = stubPolygonMode; - } + const bool drawIndirectSupported = false + || s_extension[Extension::AMD_multi_draw_indirect].m_supported + || s_extension[Extension::ARB_draw_indirect ].m_supported + || s_extension[Extension::ARB_multi_draw_indirect].m_supported + || s_extension[Extension::EXT_multi_draw_indirect].m_supported + ; - if (s_extension[Extension::ARB_copy_image].m_supported - || s_extension[Extension::EXT_copy_image].m_supported - || s_extension[Extension:: NV_copy_image].m_supported - || s_extension[Extension::OES_copy_image].m_supported) - { - m_blitSupported = NULL != glCopyImageSubData; - g_caps.supported |= m_blitSupported - ? BGFX_CAPS_TEXTURE_BLIT + if (drawIndirectSupported) + { + if (NULL == glMultiDrawArraysIndirect + || NULL == glMultiDrawElementsIndirect) + { + glMultiDrawArraysIndirect = stubMultiDrawArraysIndirect; + glMultiDrawElementsIndirect = stubMultiDrawElementsIndirect; + } + } + + g_caps.supported |= drawIndirectSupported + ? BGFX_CAPS_DRAW_INDIRECT : 0 ; - } - g_caps.supported |= m_readBackSupported - ? BGFX_CAPS_TEXTURE_READ_BACK - : 0 - ; + if (NULL == glPolygonMode) + { + glPolygonMode = stubPolygonMode; + } - g_caps.supported |= false - || s_extension[Extension::EXT_texture_array].m_supported - || s_extension[Extension::EXT_gpu_shader4].m_supported - || !!(BGFX_CONFIG_RENDERER_OPENGLES >= 30) - ? BGFX_CAPS_TEXTURE_2D_ARRAY - : 0 - ; + if (s_extension[Extension::ARB_copy_image].m_supported + || s_extension[Extension::EXT_copy_image].m_supported + || s_extension[Extension:: NV_copy_image].m_supported + || s_extension[Extension::OES_copy_image].m_supported) + { + m_blitSupported = NULL != glCopyImageSubData; + g_caps.supported |= m_blitSupported + ? BGFX_CAPS_TEXTURE_BLIT + : 0 + ; + } - g_caps.supported |= false - || s_extension[Extension::ARB_texture_cube_map_array].m_supported - || s_extension[Extension::EXT_texture_cube_map_array].m_supported - ? BGFX_CAPS_TEXTURE_CUBE_ARRAY - : 0 - ; + g_caps.supported |= m_readBackSupported + ? BGFX_CAPS_TEXTURE_READ_BACK + : 0 + ; - g_caps.limits.maxTextureSize = uint16_t(glGet(GL_MAX_TEXTURE_SIZE) ); + g_caps.supported |= false + || s_extension[Extension::EXT_texture_array].m_supported + || s_extension[Extension::EXT_gpu_shader4].m_supported + || !!(BGFX_CONFIG_RENDERER_OPENGLES >= 30) + ? BGFX_CAPS_TEXTURE_2D_ARRAY + : 0 + ; - if (BX_ENABLED(BGFX_CONFIG_RENDERER_OPENGL) - || BX_ENABLED(BGFX_CONFIG_RENDERER_OPENGLES >= 30) - || s_extension[Extension::EXT_draw_buffers ].m_supported - || s_extension[Extension::WEBGL_draw_buffers].m_supported) - { - g_caps.limits.maxFBAttachments = uint8_t(bx::uint32_min(glGet(GL_MAX_DRAW_BUFFERS) - , BGFX_CONFIG_MAX_FRAME_BUFFER_ATTACHMENTS) - ); - } + g_caps.supported |= false + || s_extension[Extension::ARB_texture_cube_map_array].m_supported + || s_extension[Extension::EXT_texture_cube_map_array].m_supported + ? BGFX_CAPS_TEXTURE_CUBE_ARRAY + : 0 + ; -// if (s_extension[Extension::ARB_clip_control].m_supported) -// { -// GL_CHECK(glClipControl(GL_LOWER_LEFT, GL_ZERO_TO_ONE) ); -// g_caps.originBottomLeft = true; -// } -// else - { - g_caps.homogeneousDepth = true; - g_caps.originBottomLeft = true; - } + g_caps.limits.maxTextureSize = uint16_t(glGet(GL_MAX_TEXTURE_SIZE) ); - m_vaoSupport = !!(BGFX_CONFIG_RENDERER_OPENGLES >= 30) - || s_extension[Extension::ARB_vertex_array_object].m_supported - || s_extension[Extension::OES_vertex_array_object].m_supported - ; + if (BX_ENABLED(BGFX_CONFIG_RENDERER_OPENGL) + || BX_ENABLED(BGFX_CONFIG_RENDERER_OPENGLES >= 30) + || s_extension[Extension::EXT_draw_buffers ].m_supported + || s_extension[Extension::WEBGL_draw_buffers].m_supported) + { + g_caps.limits.maxFBAttachments = uint8_t(bx::uint32_min(glGet(GL_MAX_DRAW_BUFFERS) + , BGFX_CONFIG_MAX_FRAME_BUFFER_ATTACHMENTS) + ); + } - if (BX_ENABLED(BX_PLATFORM_NACL) ) - { - m_vaoSupport &= true - && NULL != glGenVertexArrays - && NULL != glDeleteVertexArrays - && NULL != glBindVertexArray + // if (s_extension[Extension::ARB_clip_control].m_supported) + // { + // GL_CHECK(glClipControl(GL_LOWER_LEFT, GL_ZERO_TO_ONE) ); + // g_caps.originBottomLeft = true; + // } + // else + { + g_caps.homogeneousDepth = true; + g_caps.originBottomLeft = true; + } + + m_vaoSupport = !!(BGFX_CONFIG_RENDERER_OPENGLES >= 30) + || s_extension[Extension::ARB_vertex_array_object].m_supported + || s_extension[Extension::OES_vertex_array_object].m_supported ; - } - if (m_vaoSupport) - { - GL_CHECK(glGenVertexArrays(1, &m_vao) ); - } + if (m_vaoSupport) + { + GL_CHECK(glGenVertexArrays(1, &m_vao) ); + } - m_samplerObjectSupport = !!(BGFX_CONFIG_RENDERER_OPENGLES >= 30) - || s_extension[Extension::ARB_sampler_objects].m_supported - ; + m_samplerObjectSupport = !!(BGFX_CONFIG_RENDERER_OPENGLES >= 30) + || s_extension[Extension::ARB_sampler_objects].m_supported + ; - m_shadowSamplersSupport = !!(BGFX_CONFIG_RENDERER_OPENGL || BGFX_CONFIG_RENDERER_OPENGLES >= 30) - || s_extension[Extension::EXT_shadow_samplers].m_supported - ; + m_shadowSamplersSupport = !!(BGFX_CONFIG_RENDERER_OPENGL || BGFX_CONFIG_RENDERER_OPENGLES >= 30) + || s_extension[Extension::EXT_shadow_samplers].m_supported + ; - m_programBinarySupport = !!(BGFX_CONFIG_RENDERER_OPENGLES >= 30) - || s_extension[Extension::ARB_get_program_binary].m_supported - || s_extension[Extension::OES_get_program_binary].m_supported - || s_extension[Extension::IMG_shader_binary ].m_supported - ; + m_programBinarySupport = !!(BGFX_CONFIG_RENDERER_OPENGLES >= 30) + || s_extension[Extension::ARB_get_program_binary].m_supported + || s_extension[Extension::OES_get_program_binary].m_supported + || s_extension[Extension::IMG_shader_binary ].m_supported + ; - m_textureSwizzleSupport = false - || s_extension[Extension::ARB_texture_swizzle].m_supported - || s_extension[Extension::EXT_texture_swizzle].m_supported - ; + m_textureSwizzleSupport = false + || s_extension[Extension::ARB_texture_swizzle].m_supported + || s_extension[Extension::EXT_texture_swizzle].m_supported + ; - m_depthTextureSupport = !!(BGFX_CONFIG_RENDERER_OPENGL || BGFX_CONFIG_RENDERER_OPENGLES >= 30) - || s_extension[Extension::ANGLE_depth_texture ].m_supported - || s_extension[Extension::CHROMIUM_depth_texture ].m_supported - || s_extension[Extension::GOOGLE_depth_texture ].m_supported - || s_extension[Extension::OES_depth_texture ].m_supported - || s_extension[Extension::MOZ_WEBGL_depth_texture ].m_supported - || s_extension[Extension::WEBGL_depth_texture ].m_supported - || s_extension[Extension::WEBKIT_WEBGL_depth_texture].m_supported - ; + m_depthTextureSupport = !!(BGFX_CONFIG_RENDERER_OPENGL || BGFX_CONFIG_RENDERER_OPENGLES >= 30) + || s_extension[Extension::ANGLE_depth_texture ].m_supported + || s_extension[Extension::CHROMIUM_depth_texture ].m_supported + || s_extension[Extension::GOOGLE_depth_texture ].m_supported + || s_extension[Extension::OES_depth_texture ].m_supported + || s_extension[Extension::MOZ_WEBGL_depth_texture ].m_supported + || s_extension[Extension::WEBGL_depth_texture ].m_supported + || s_extension[Extension::WEBKIT_WEBGL_depth_texture].m_supported + ; - m_timerQuerySupport = false - || s_extension[Extension::ANGLE_timer_query ].m_supported - || s_extension[Extension::ARB_timer_query ].m_supported - || s_extension[Extension::EXT_disjoint_timer_query].m_supported - || s_extension[Extension::EXT_timer_query ].m_supported - ; + m_timerQuerySupport = false + || s_extension[Extension::ANGLE_timer_query ].m_supported + || s_extension[Extension::ARB_timer_query ].m_supported + || s_extension[Extension::EXT_disjoint_timer_query].m_supported + || s_extension[Extension::EXT_timer_query ].m_supported + ; - m_timerQuerySupport &= true - && NULL != glQueryCounter - && NULL != glGetQueryObjectiv - && NULL != glGetQueryObjectui64v - ; + m_timerQuerySupport &= true + && NULL != glQueryCounter + && NULL != glGetQueryObjectiv + && NULL != glGetQueryObjectui64v + ; - m_occlusionQuerySupport = false - || s_extension[Extension::ARB_occlusion_query ].m_supported - || s_extension[Extension::ARB_occlusion_query2 ].m_supported - || s_extension[Extension::EXT_occlusion_query_boolean].m_supported - || s_extension[Extension::NV_occlusion_query ].m_supported - ; + m_occlusionQuerySupport = false + || s_extension[Extension::ARB_occlusion_query ].m_supported + || s_extension[Extension::ARB_occlusion_query2 ].m_supported + || s_extension[Extension::EXT_occlusion_query_boolean].m_supported + || s_extension[Extension::NV_occlusion_query ].m_supported + ; - m_occlusionQuerySupport &= true - && NULL != glGenQueries - && NULL != glDeleteQueries - && NULL != glBeginQuery - && NULL != glEndQuery - ; + m_occlusionQuerySupport &= true + && NULL != glGenQueries + && NULL != glDeleteQueries + && NULL != glBeginQuery + && NULL != glEndQuery + ; - m_atocSupport = s_extension[Extension::ARB_multisample].m_supported; - m_conservativeRasterSupport = s_extension[Extension::NV_conservative_raster].m_supported; + m_atocSupport = s_extension[Extension::ARB_multisample].m_supported; + m_conservativeRasterSupport = s_extension[Extension::NV_conservative_raster].m_supported; - g_caps.supported |= 0 - | (m_atocSupport ? BGFX_CAPS_ALPHA_TO_COVERAGE : 0) - | (m_conservativeRasterSupport ? BGFX_CAPS_CONSERVATIVE_RASTER : 0) - | (m_occlusionQuerySupport ? BGFX_CAPS_OCCLUSION_QUERY : 0) - | (m_depthTextureSupport ? BGFX_CAPS_TEXTURE_COMPARE_LEQUAL : 0) - | (computeSupport ? BGFX_CAPS_COMPUTE : 0) - ; + g_caps.supported |= 0 + | (m_atocSupport ? BGFX_CAPS_ALPHA_TO_COVERAGE : 0) + | (m_conservativeRasterSupport ? BGFX_CAPS_CONSERVATIVE_RASTER : 0) + | (m_occlusionQuerySupport ? BGFX_CAPS_OCCLUSION_QUERY : 0) + | (m_depthTextureSupport ? BGFX_CAPS_TEXTURE_COMPARE_LEQUAL : 0) + | (computeSupport ? BGFX_CAPS_COMPUTE : 0) + ; - g_caps.supported |= m_glctx.getCaps(); + g_caps.supported |= m_glctx.getCaps(); - if (BX_ENABLED(BGFX_CONFIG_RENDERER_OPENGLES) ) - { - m_srgbWriteControlSupport = s_extension[Extension::EXT_sRGB_write_control].m_supported; + if (BX_ENABLED(BGFX_CONFIG_RENDERER_OPENGLES) ) + { + m_srgbWriteControlSupport = s_extension[Extension::EXT_sRGB_write_control].m_supported; - m_borderColorSupport = s_extension[Extension::NV_texture_border_clamp].m_supported; - s_textureAddress[BGFX_TEXTURE_U_BORDER>>BGFX_TEXTURE_U_SHIFT] = s_extension[Extension::NV_texture_border_clamp].m_supported - ? GL_CLAMP_TO_BORDER - : GL_CLAMP_TO_EDGE - ; - } + m_borderColorSupport = s_extension[Extension::NV_texture_border_clamp].m_supported; + s_textureAddress[BGFX_TEXTURE_U_BORDER>>BGFX_TEXTURE_U_SHIFT] = s_extension[Extension::NV_texture_border_clamp].m_supported + ? GL_CLAMP_TO_BORDER + : GL_CLAMP_TO_EDGE + ; + } - if (s_extension[Extension::EXT_texture_filter_anisotropic].m_supported) - { - GL_CHECK(glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &m_maxAnisotropyDefault) ); - } + if (s_extension[Extension::EXT_texture_filter_anisotropic].m_supported) + { + GL_CHECK(glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &m_maxAnisotropyDefault) ); + } - if (s_extension[Extension::ARB_texture_multisample].m_supported - || s_extension[Extension::ANGLE_framebuffer_multisample].m_supported) - { - GL_CHECK(glGetIntegerv(GL_MAX_SAMPLES, &m_maxMsaa) ); - } + if (s_extension[Extension::ARB_texture_multisample].m_supported + || s_extension[Extension::ANGLE_framebuffer_multisample].m_supported) + { + GL_CHECK(glGetIntegerv(GL_MAX_SAMPLES, &m_maxMsaa) ); + } - if (s_extension[Extension::OES_read_format].m_supported - && (s_extension[Extension::IMG_read_format].m_supported || s_extension[Extension::EXT_read_format_bgra].m_supported) ) - { - m_readPixelsFmt = GL_BGRA; - } - else - { - m_readPixelsFmt = GL_RGBA; - } + if (s_extension[Extension::OES_read_format].m_supported + && (s_extension[Extension::IMG_read_format].m_supported || s_extension[Extension::EXT_read_format_bgra].m_supported) ) + { + m_readPixelsFmt = GL_BGRA; + } + else + { + m_readPixelsFmt = GL_RGBA; + } - if (BX_ENABLED(BGFX_CONFIG_RENDERER_OPENGLES >= 30) ) - { - g_caps.supported |= BGFX_CAPS_INSTANCING; - } - else - { - if (s_extension[Extension::ANGLE_instanced_arrays].m_supported - || s_extension[Extension::ARB_instanced_arrays].m_supported - || s_extension[Extension::EXT_instanced_arrays].m_supported) + if (BX_ENABLED(BGFX_CONFIG_RENDERER_OPENGLES >= 30) ) + { + g_caps.supported |= BGFX_CAPS_INSTANCING; + } + else { - if (NULL != glVertexAttribDivisor - && NULL != glDrawArraysInstanced - && NULL != glDrawElementsInstanced) + if (s_extension[Extension::ANGLE_instanced_arrays].m_supported + || s_extension[Extension::ARB_instanced_arrays].m_supported + || s_extension[Extension::EXT_instanced_arrays].m_supported) { - g_caps.supported |= BGFX_CAPS_INSTANCING; + if (NULL != glVertexAttribDivisor + && NULL != glDrawArraysInstanced + && NULL != glDrawElementsInstanced) + { + g_caps.supported |= BGFX_CAPS_INSTANCING; + } } - } - if (0 == (g_caps.supported & BGFX_CAPS_INSTANCING) ) - { - glVertexAttribDivisor = stubVertexAttribDivisor; - glDrawArraysInstanced = stubDrawArraysInstanced; - glDrawElementsInstanced = stubDrawElementsInstanced; + if (0 == (g_caps.supported & BGFX_CAPS_INSTANCING) ) + { + glVertexAttribDivisor = stubVertexAttribDivisor; + glDrawArraysInstanced = stubDrawArraysInstanced; + glDrawElementsInstanced = stubDrawElementsInstanced; + } } - } - if (s_extension[Extension::ARB_debug_output].m_supported - || s_extension[Extension::KHR_debug].m_supported) - { - if (NULL != glDebugMessageControl - && NULL != glDebugMessageInsert - && NULL != glDebugMessageCallback - && NULL != glGetDebugMessageLog) + if (s_extension[Extension::ARB_debug_output].m_supported + || s_extension[Extension::KHR_debug].m_supported) { - GL_CHECK(glDebugMessageCallback(debugProcCb, NULL) ); - GL_CHECK(glDebugMessageControl(GL_DONT_CARE + if (NULL != glDebugMessageControl + && NULL != glDebugMessageInsert + && NULL != glDebugMessageCallback + && NULL != glGetDebugMessageLog) + { + GL_CHECK(glDebugMessageCallback(debugProcCb, NULL) ); + GL_CHECK(glDebugMessageControl(GL_DONT_CARE , GL_DONT_CARE , GL_DEBUG_SEVERITY_MEDIUM , 0 , NULL , GL_TRUE ) ); + } } - } - if (s_extension[Extension::ARB_seamless_cube_map].m_supported) - { - GL_CHECK(glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS) ); - } + if (s_extension[Extension::ARB_seamless_cube_map].m_supported) + { + GL_CHECK(glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS) ); + } - if (NULL == glFrameTerminatorGREMEDY - || !s_extension[Extension::GREMEDY_frame_terminator].m_supported) - { - glFrameTerminatorGREMEDY = stubFrameTerminatorGREMEDY; - } + if (NULL == glFrameTerminatorGREMEDY + || !s_extension[Extension::GREMEDY_frame_terminator].m_supported) + { + glFrameTerminatorGREMEDY = stubFrameTerminatorGREMEDY; + } - if (NULL == glInsertEventMarker - || !s_extension[Extension::EXT_debug_marker].m_supported) - { - glInsertEventMarker = (NULL != glStringMarkerGREMEDY && s_extension[Extension::GREMEDY_string_marker].m_supported) - ? stubInsertEventMarkerGREMEDY - : stubInsertEventMarker - ; - } + if (NULL == glInsertEventMarker + || !s_extension[Extension::EXT_debug_marker].m_supported) + { + glInsertEventMarker = (NULL != glStringMarkerGREMEDY && s_extension[Extension::GREMEDY_string_marker].m_supported) + ? stubInsertEventMarkerGREMEDY + : stubInsertEventMarker + ; + } - setGraphicsDebuggerPresent(s_extension[Extension::EXT_debug_tool].m_supported); + setGraphicsDebuggerPresent(s_extension[Extension::EXT_debug_tool].m_supported); - if (NULL == glObjectLabel) - { - glObjectLabel = stubObjectLabel; - } + if (NULL == glObjectLabel) + { + glObjectLabel = stubObjectLabel; + } - if (NULL == glInvalidateFramebuffer) - { - glInvalidateFramebuffer = stubInvalidateFramebuffer; - } + if (NULL == glInvalidateFramebuffer) + { + glInvalidateFramebuffer = stubInvalidateFramebuffer; + } - if (m_timerQuerySupport) - { - m_gpuTimer.create(); - } + if (m_timerQuerySupport) + { + m_gpuTimer.create(); + } - if (m_occlusionQuerySupport) - { - m_occlusionQuery.create(); + if (m_occlusionQuerySupport) + { + m_occlusionQuery.create(); + } + + // Init reserved part of view name. + for (uint32_t ii = 0; ii < BGFX_CONFIG_MAX_VIEWS; ++ii) + { + bx::snprintf(s_viewName[ii], BGFX_CONFIG_MAX_VIEW_NAME_RESERVED+1, "%3d ", ii); + } + + ovrPostReset(); + + m_needPresent = false; } - // Init reserved part of view name. - for (uint32_t ii = 0; ii < BGFX_CONFIG_MAX_VIEWS; ++ii) + return true; + + error: + switch (errorState) { - bx::snprintf(s_viewName[ii], BGFX_CONFIG_MAX_VIEW_NAME_RESERVED+1, "%3d ", ii); + case ErrorState::Default: + break; } - ovrPostReset(); + ovrPreReset(); + m_ovr.shutdown(); - m_needPresent = false; + m_glctx.destroy(); - BGFX_GPU_PROFILER_BIND(); + unloadRenderDoc(m_renderdocdll); + return false; } void shutdown() { - BGFX_GPU_PROFILER_UNBIND(); - ovrPreReset(); m_ovr.shutdown(); @@ -2262,7 +2599,7 @@ namespace bgfx { namespace gl unloadRenderDoc(m_renderdocdll); } - RendererType::Enum getRendererType() const BX_OVERRIDE + RendererType::Enum getRendererType() const override { if (BX_ENABLED(BGFX_CONFIG_RENDERER_OPENGL) ) { @@ -2272,12 +2609,17 @@ namespace bgfx { namespace gl return RendererType::OpenGLES; } - const char* getRendererName() const BX_OVERRIDE + const char* getRendererName() const override { return BGFX_RENDERER_OPENGL_NAME; } - void flip(HMD& _hmd) + bool isDeviceRemoved() override + { + return false; + } + + void flip(HMD& _hmd) override { if (m_flip) { @@ -2307,113 +2649,113 @@ namespace bgfx { namespace gl } } - void createIndexBuffer(IndexBufferHandle _handle, Memory* _mem, uint16_t _flags) BX_OVERRIDE + void createIndexBuffer(IndexBufferHandle _handle, Memory* _mem, uint16_t _flags) override { m_indexBuffers[_handle.idx].create(_mem->size, _mem->data, _flags); } - void destroyIndexBuffer(IndexBufferHandle _handle) BX_OVERRIDE + void destroyIndexBuffer(IndexBufferHandle _handle) override { m_indexBuffers[_handle.idx].destroy(); } - void createVertexDecl(VertexDeclHandle _handle, const VertexDecl& _decl) BX_OVERRIDE + void createVertexDecl(VertexDeclHandle _handle, const VertexDecl& _decl) override { VertexDecl& decl = m_vertexDecls[_handle.idx]; bx::memCopy(&decl, &_decl, sizeof(VertexDecl) ); dump(decl); } - void destroyVertexDecl(VertexDeclHandle /*_handle*/) BX_OVERRIDE + void destroyVertexDecl(VertexDeclHandle /*_handle*/) override { } - void createVertexBuffer(VertexBufferHandle _handle, Memory* _mem, VertexDeclHandle _declHandle, uint16_t _flags) BX_OVERRIDE + void createVertexBuffer(VertexBufferHandle _handle, Memory* _mem, VertexDeclHandle _declHandle, uint16_t _flags) override { m_vertexBuffers[_handle.idx].create(_mem->size, _mem->data, _declHandle, _flags); } - void destroyVertexBuffer(VertexBufferHandle _handle) BX_OVERRIDE + void destroyVertexBuffer(VertexBufferHandle _handle) override { m_vertexBuffers[_handle.idx].destroy(); } - void createDynamicIndexBuffer(IndexBufferHandle _handle, uint32_t _size, uint16_t _flags) BX_OVERRIDE + void createDynamicIndexBuffer(IndexBufferHandle _handle, uint32_t _size, uint16_t _flags) override { m_indexBuffers[_handle.idx].create(_size, NULL, _flags); } - void updateDynamicIndexBuffer(IndexBufferHandle _handle, uint32_t _offset, uint32_t _size, Memory* _mem) BX_OVERRIDE + void updateDynamicIndexBuffer(IndexBufferHandle _handle, uint32_t _offset, uint32_t _size, Memory* _mem) override { m_indexBuffers[_handle.idx].update(_offset, bx::uint32_min(_size, _mem->size), _mem->data); } - void destroyDynamicIndexBuffer(IndexBufferHandle _handle) BX_OVERRIDE + void destroyDynamicIndexBuffer(IndexBufferHandle _handle) override { m_indexBuffers[_handle.idx].destroy(); } - void createDynamicVertexBuffer(VertexBufferHandle _handle, uint32_t _size, uint16_t _flags) BX_OVERRIDE + void createDynamicVertexBuffer(VertexBufferHandle _handle, uint32_t _size, uint16_t _flags) override { VertexDeclHandle decl = BGFX_INVALID_HANDLE; m_vertexBuffers[_handle.idx].create(_size, NULL, decl, _flags); } - void updateDynamicVertexBuffer(VertexBufferHandle _handle, uint32_t _offset, uint32_t _size, Memory* _mem) BX_OVERRIDE + void updateDynamicVertexBuffer(VertexBufferHandle _handle, uint32_t _offset, uint32_t _size, Memory* _mem) override { m_vertexBuffers[_handle.idx].update(_offset, bx::uint32_min(_size, _mem->size), _mem->data); } - void destroyDynamicVertexBuffer(VertexBufferHandle _handle) BX_OVERRIDE + void destroyDynamicVertexBuffer(VertexBufferHandle _handle) override { m_vertexBuffers[_handle.idx].destroy(); } - void createShader(ShaderHandle _handle, Memory* _mem) BX_OVERRIDE + void createShader(ShaderHandle _handle, Memory* _mem) override { m_shaders[_handle.idx].create(_mem); } - void destroyShader(ShaderHandle _handle) BX_OVERRIDE + void destroyShader(ShaderHandle _handle) override { m_shaders[_handle.idx].destroy(); } - void createProgram(ProgramHandle _handle, ShaderHandle _vsh, ShaderHandle _fsh) BX_OVERRIDE + void createProgram(ProgramHandle _handle, ShaderHandle _vsh, ShaderHandle _fsh) override { ShaderGL dummyFragmentShader; m_program[_handle.idx].create(m_shaders[_vsh.idx], isValid(_fsh) ? m_shaders[_fsh.idx] : dummyFragmentShader); } - void destroyProgram(ProgramHandle _handle) BX_OVERRIDE + void destroyProgram(ProgramHandle _handle) override { m_program[_handle.idx].destroy(); } - void createTexture(TextureHandle _handle, Memory* _mem, uint32_t _flags, uint8_t _skip) BX_OVERRIDE + void createTexture(TextureHandle _handle, Memory* _mem, uint32_t _flags, uint8_t _skip) override { m_textures[_handle.idx].create(_mem, _flags, _skip); } - void updateTextureBegin(TextureHandle /*_handle*/, uint8_t /*_side*/, uint8_t /*_mip*/) BX_OVERRIDE + void updateTextureBegin(TextureHandle /*_handle*/, uint8_t /*_side*/, uint8_t /*_mip*/) override { } - void updateTexture(TextureHandle _handle, uint8_t _side, uint8_t _mip, const Rect& _rect, uint16_t _z, uint16_t _depth, uint16_t _pitch, const Memory* _mem) BX_OVERRIDE + void updateTexture(TextureHandle _handle, uint8_t _side, uint8_t _mip, const Rect& _rect, uint16_t _z, uint16_t _depth, uint16_t _pitch, const Memory* _mem) override { m_textures[_handle.idx].update(_side, _mip, _rect, _z, _depth, _pitch, _mem); } - void updateTextureEnd() BX_OVERRIDE + void updateTextureEnd() override { } - void readTexture(TextureHandle _handle, void* _data, uint8_t _mip) BX_OVERRIDE + void readTexture(TextureHandle _handle, void* _data, uint8_t _mip) override { if (m_readBackSupported) { const TextureGL& texture = m_textures[_handle.idx]; - const bool compressed = isCompressed(TextureFormat::Enum(texture.m_textureFormat) ); + const bool compressed = bimg::isCompressed(bimg::TextureFormat::Enum(texture.m_textureFormat) ); GL_CHECK(glBindTexture(texture.m_target, texture.m_id) ); @@ -2436,9 +2778,54 @@ namespace bgfx { namespace gl GL_CHECK(glBindTexture(texture.m_target, 0) ); } + else + { + const TextureGL& texture = m_textures[_handle.idx]; + const bool compressed = bimg::isCompressed(bimg::TextureFormat::Enum(texture.m_textureFormat) ); + + if(!compressed) + { + Attachment attachment[1]; + attachment[0].handle = _handle; + attachment[0].mip = 0; + attachment[0].layer = 0; + + FrameBufferGL frameBuffer; + frameBuffer.create(1, attachment); + GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer.m_fbo[0]) ); + GL_CHECK(glFramebufferTexture2D( + GL_FRAMEBUFFER + , GL_COLOR_ATTACHMENT0 + , GL_TEXTURE_2D + , texture.m_id + , attachment[0].mip + ) ); + + if (!BX_ENABLED(BX_PLATFORM_EMSCRIPTEN) + && !BX_ENABLED(BX_PLATFORM_IOS)) + { + GL_CHECK(glReadBuffer(GL_COLOR_ATTACHMENT0) ); + } + + if (GL_FRAMEBUFFER_COMPLETE == glCheckFramebufferStatus(GL_FRAMEBUFFER) ) + { + GL_CHECK(glReadPixels( + 0 + , 0 + , texture.m_width + , texture.m_height + , m_readPixelsFmt + , GL_UNSIGNED_BYTE + , _data + ) ); + } + + frameBuffer.destroy(); + } + } } - void resizeTexture(TextureHandle _handle, uint16_t _width, uint16_t _height, uint8_t _numMips) BX_OVERRIDE + void resizeTexture(TextureHandle _handle, uint16_t _width, uint16_t _height, uint8_t _numMips) override { TextureGL& texture = m_textures[_handle.idx]; @@ -2466,34 +2853,34 @@ namespace bgfx { namespace gl release(mem); } - void overrideInternal(TextureHandle _handle, uintptr_t _ptr) BX_OVERRIDE + void overrideInternal(TextureHandle _handle, uintptr_t _ptr) override { m_textures[_handle.idx].overrideInternal(_ptr); } - uintptr_t getInternal(TextureHandle _handle) BX_OVERRIDE + uintptr_t getInternal(TextureHandle _handle) override { return uintptr_t(m_textures[_handle.idx].m_id); } - void destroyTexture(TextureHandle _handle) BX_OVERRIDE + void destroyTexture(TextureHandle _handle) override { m_textures[_handle.idx].destroy(); } - void createFrameBuffer(FrameBufferHandle _handle, uint8_t _num, const Attachment* _attachment) BX_OVERRIDE + void createFrameBuffer(FrameBufferHandle _handle, uint8_t _num, const Attachment* _attachment) override { m_frameBuffers[_handle.idx].create(_num, _attachment); } - void createFrameBuffer(FrameBufferHandle _handle, void* _nwh, uint32_t _width, uint32_t _height, TextureFormat::Enum _depthFormat) BX_OVERRIDE + void createFrameBuffer(FrameBufferHandle _handle, void* _nwh, uint32_t _width, uint32_t _height, TextureFormat::Enum _depthFormat) override { uint16_t denseIdx = m_numWindows++; m_windows[denseIdx] = _handle; m_frameBuffers[_handle.idx].create(denseIdx, _nwh, _width, _height, _depthFormat); } - void destroyFrameBuffer(FrameBufferHandle _handle) BX_OVERRIDE + void destroyFrameBuffer(FrameBufferHandle _handle) override { uint16_t denseIdx = m_frameBuffers[_handle.idx].destroy(); if (UINT16_MAX != denseIdx) @@ -2508,7 +2895,7 @@ namespace bgfx { namespace gl } } - void createUniform(UniformHandle _handle, UniformType::Enum _type, uint16_t _num, const char* _name) BX_OVERRIDE + void createUniform(UniformHandle _handle, UniformType::Enum _type, uint16_t _num, const char* _name) override { if (NULL != m_uniforms[_handle.idx]) { @@ -2522,14 +2909,14 @@ namespace bgfx { namespace gl m_uniformReg.add(_handle, _name, m_uniforms[_handle.idx]); } - void destroyUniform(UniformHandle _handle) BX_OVERRIDE + void destroyUniform(UniformHandle _handle) override { BX_FREE(g_allocator, m_uniforms[_handle.idx]); m_uniforms[_handle.idx] = NULL; m_uniformReg.remove(_handle); } - void requestScreenShot(FrameBufferHandle _handle, const char* _filePath) BX_OVERRIDE + void requestScreenShot(FrameBufferHandle _handle, const char* _filePath) override { SwapChainGL* swapChain = NULL; uint32_t width = m_resolution.m_width; @@ -2558,7 +2945,7 @@ namespace bgfx { namespace gl if (GL_RGBA == m_readPixelsFmt) { - imageSwizzleBgra8(data, width, height, width*4, data); + bimg::imageSwizzleBgra8(data, width*4, width, height, data, width*4); } g_callback->screenShot(_filePath @@ -2572,32 +2959,52 @@ namespace bgfx { namespace gl BX_FREE(g_allocator, data); } - void updateViewName(uint8_t _id, const char* _name) BX_OVERRIDE + void updateViewName(ViewId _id, const char* _name) override { - bx::strlcpy(&s_viewName[_id][BGFX_CONFIG_MAX_VIEW_NAME_RESERVED] - , _name + bx::strCopy(&s_viewName[_id][BGFX_CONFIG_MAX_VIEW_NAME_RESERVED] , BX_COUNTOF(s_viewName[0])-BGFX_CONFIG_MAX_VIEW_NAME_RESERVED + , _name ); } - void updateUniform(uint16_t _loc, const void* _data, uint32_t _size) BX_OVERRIDE + void updateUniform(uint16_t _loc, const void* _data, uint32_t _size) override { bx::memCopy(m_uniforms[_loc], _data, _size); } - void setMarker(const char* _marker, uint32_t _size) BX_OVERRIDE + void setMarker(const char* _marker, uint32_t _size) override { GL_CHECK(glInsertEventMarker(_size, _marker) ); } - void invalidateOcclusionQuery(OcclusionQueryHandle _handle) BX_OVERRIDE + void invalidateOcclusionQuery(OcclusionQueryHandle _handle) override { m_occlusionQuery.invalidate(_handle); } - void submit(Frame* _render, ClearQuad& _clearQuad, TextVideoMemBlitter& _textVideoMemBlitter) BX_OVERRIDE; + virtual void setName(Handle _handle, const char* _name) override + { + switch (_handle.type) + { + case Handle::Shader: + GL_CHECK(glObjectLabel(GL_SHADER, m_shaders[_handle.idx].m_id, -1, _name) ); + break; + + case Handle::Texture: + GL_CHECK(glObjectLabel(GL_TEXTURE, m_textures[_handle.idx].m_id, -1, _name) ); + break; - void blitSetup(TextVideoMemBlitter& _blitter) BX_OVERRIDE + default: + BX_CHECK(false, "Invalid handle type?! %d", _handle.type); + break; + } + } + + void submitBlit(BlitState& _bs, uint16_t _view); + + void submit(Frame* _render, ClearQuad& _clearQuad, TextVideoMemBlitter& _textVideoMemBlitter) override; + + void blitSetup(TextVideoMemBlitter& _blitter) override { if (0 != m_vao) { @@ -2623,7 +3030,7 @@ namespace bgfx { namespace gl GL_CHECK(glUniform1i(program.m_sampler[0], 0) ); float proj[16]; - bx::mtxOrtho(proj, 0.0f, (float)width, (float)height, 0.0f, 0.0f, 1000.0f); + bx::mtxOrtho(proj, 0.0f, (float)width, (float)height, 0.0f, 0.0f, 1000.0f, 0.0f, true); GL_CHECK(glUniformMatrix4fv(program.m_predefined[0].m_loc , 1 @@ -2647,7 +3054,7 @@ namespace bgfx { namespace gl } } - void blitRender(TextVideoMemBlitter& _blitter, uint32_t _numIndices) BX_OVERRIDE + void blitRender(TextVideoMemBlitter& _blitter, uint32_t _numIndices) override { const uint32_t numVertices = _numIndices*4/6; if (0 < numVertices) @@ -2955,11 +3362,6 @@ namespace bgfx { namespace gl void invalidateCache() { - if (m_vaoSupport) - { - m_vaoStateCache.invalidate(); - } - if ( (BX_ENABLED(BGFX_CONFIG_RENDERER_OPENGL) || BX_ENABLED(BGFX_CONFIG_RENDERER_OPENGLES >= 30) ) && m_samplerObjectSupport) { @@ -3034,13 +3436,15 @@ namespace bgfx { namespace gl GL_CHECK(glSamplerParameteri(sampler, GL_TEXTURE_MAG_FILTER, magFilter) ); GL_CHECK(glSamplerParameteri(sampler, GL_TEXTURE_MIN_FILTER, minFilter) ); - if (BX_ENABLED(BGFX_CONFIG_RENDERER_OPENGL) - || m_borderColorSupport) + if (BX_ENABLED(BGFX_CONFIG_RENDERER_OPENGL) ) { - if (hasBorderColor) - { - GL_CHECK(glSamplerParameterfv(sampler, GL_TEXTURE_BORDER_COLOR, _rgba) ); - } + GL_CHECK(glSamplerParameterf(sampler, GL_TEXTURE_LOD_BIAS, float(BGFX_CONFIG_MIP_LOD_BIAS) ) ); + } + + if (m_borderColorSupport + && hasBorderColor) + { + GL_CHECK(glSamplerParameterfv(sampler, GL_TEXTURE_BORDER_COLOR, _rgba) ); } if (0 != (_flags & (BGFX_TEXTURE_MIN_ANISOTROPIC|BGFX_TEXTURE_MAG_ANISOTROPIC) ) @@ -3127,7 +3531,14 @@ namespace bgfx { namespace gl if (GL_RGBA == m_readPixelsFmt) { - imageSwizzleBgra8(m_capture, m_resolution.m_width, m_resolution.m_height, m_resolution.m_width*4, m_capture); + bimg::imageSwizzleBgra8( + m_capture + , m_resolution.m_width*4 + , m_resolution.m_width + , m_resolution.m_height + , m_capture + , m_resolution.m_width*4 + ); } g_callback->captureFrame(m_capture, m_captureSize); @@ -3474,7 +3885,6 @@ namespace bgfx { namespace gl TimerQueryGL m_gpuTimer; OcclusionQueryGL m_occlusionQuery; - VaoStateCache m_vaoStateCache; SamplerStateCache m_samplerStateCache; TextVideoMem m_textVideoMem; @@ -3520,6 +3930,8 @@ namespace bgfx { namespace gl const char* m_version; const char* m_glslVersion; + Workaround m_workaround; + GLuint m_currentFbo; VR m_ovr; @@ -3533,7 +3945,11 @@ namespace bgfx { namespace gl RendererContextI* rendererCreate() { s_renderGL = BX_NEW(g_allocator, RendererContextGL); - s_renderGL->init(); + if (!s_renderGL->init() ) + { + BX_DELETE(g_allocator, s_renderGL); + s_renderGL = NULL; + } return s_renderGL; } @@ -4018,7 +4434,8 @@ namespace bgfx { namespace gl init(); - if (!cached) + if (!cached + && s_renderGL->m_workaround.m_detachShader) { // Must be after init, otherwise init might fail to lookup shader // info (NVIDIA Tegra 3 OpenGL ES 2.0 14.01003). @@ -4046,8 +4463,6 @@ namespace bgfx { namespace gl GL_CHECK(glDeleteProgram(m_id) ); m_id = 0; } - - m_vcref.invalidate(s_renderGL->m_vaoStateCache); } void ProgramGL::init() @@ -4172,13 +4587,13 @@ namespace bgfx { namespace gl num = bx::uint32_max(num, 1); int offset = 0; - char* array = const_cast<char*>(bx::strnchr(name, '[') ); + char* array = const_cast<char*>(bx::strFind(name, '[') ); if (NULL != array) { BX_TRACE("--- %s", name); *array = '\0'; array++; - char* end = const_cast<char*>(bx::strnchr(array, ']') ); + char* end = const_cast<char*>(bx::strFind(array, ']') ); if (NULL != end) { // Some devices (Amazon Fire) might not return terminating brace. *end = '\0'; @@ -4384,21 +4799,21 @@ namespace bgfx { namespace gl && !normalized) { GL_CHECK(glVertexAttribIPointer(loc - , num - , s_attribType[type] - , _vertexDecl.m_stride - , (void*)(uintptr_t)baseVertex) - ); + , num + , s_attribType[type] + , _vertexDecl.m_stride + , (void*)(uintptr_t)baseVertex) + ); } else { GL_CHECK(glVertexAttribPointer(loc - , num - , s_attribType[type] - , normalized - , _vertexDecl.m_stride - , (void*)(uintptr_t)baseVertex) - ); + , num + , s_attribType[type] + , normalized + , _vertexDecl.m_stride + , (void*)(uintptr_t)baseVertex) + ); } m_unboundUsedAttrib[ii] = Attrib::Count; @@ -4424,248 +4839,12 @@ namespace bgfx { namespace gl { GL_CHECK(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0) ); GL_CHECK(glDeleteBuffers(1, &m_id) ); - - m_vcref.invalidate(s_renderGL->m_vaoStateCache); } void VertexBufferGL::destroy() { GL_CHECK(glBindBuffer(GL_ARRAY_BUFFER, 0) ); GL_CHECK(glDeleteBuffers(1, &m_id) ); - - m_vcref.invalidate(s_renderGL->m_vaoStateCache); - } - - 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) - { - GL_CHECK(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); - GL_CHECK(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) - { - GL_CHECK(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) - { - GL_CHECK(glTexImage2DMultisample( - _target - , _msaaQuality - , _internalFormat - , _width - , _height - , false - ) ); - } - else - { - GL_CHECK(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) - { - GL_CHECK(glCompressedTexSubImage3D( - _target - , _level - , _xoffset - , _yoffset - , _zoffset - , _width - , _height - , _depth - , _format - , _imageSize - , _data - ) ); - } - else - { - BX_UNUSED(_zoffset, _depth); - GL_CHECK(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) - { - GL_CHECK(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); - GL_CHECK(glCompressedTexImage2D( - _target - , _level - , _internalformat - , _width - , _height - , _border - , _imageSize - , _data - ) ); - } } bool TextureGL::init(GLenum _target, uint32_t _width, uint32_t _height, uint32_t _depth, uint8_t _numMips, uint32_t _flags) @@ -4680,6 +4859,7 @@ namespace bgfx { namespace gl const bool writeOnly = 0 != (m_flags&BGFX_TEXTURE_RT_WRITE_ONLY); const bool computeWrite = 0 != (m_flags&BGFX_TEXTURE_COMPUTE_WRITE ); + const bool srgb = 0 != (m_flags&BGFX_TEXTURE_SRGB); const bool textureArray = false || _target == GL_TEXTURE_2D_ARRAY || _target == GL_TEXTURE_CUBE_MAP_ARRAY @@ -4714,11 +4894,16 @@ namespace bgfx { namespace gl m_type = tfiRgba8.m_type; } + const GLenum internalFmt = srgb + ? s_textureFormat[m_textureFormat].m_internalFmtSrgb + : s_textureFormat[m_textureFormat].m_internalFmt + ; + if (textureArray) { GL_CHECK(glTexStorage3D(_target , _numMips - , s_textureFormat[m_textureFormat].m_internalFmt + , internalFmt , m_width , m_height , _depth @@ -4730,21 +4915,21 @@ namespace bgfx { namespace gl if (_target == GL_TEXTURE_3D) { GL_CHECK(glTexStorage3D(_target - , _numMips - , s_textureFormat[m_textureFormat].m_internalFmt - , m_width - , m_height - , _depth - ) ); + , _numMips + , internalFmt + , m_width + , m_height + , _depth + ) ); } else { GL_CHECK(glTexStorage2D(_target - , _numMips - , s_textureFormat[m_textureFormat].m_internalFmt - , m_width - , m_height - ) ); + , _numMips + , internalFmt + , m_width + , m_height + ) ); } } @@ -4810,9 +4995,9 @@ namespace bgfx { namespace gl void TextureGL::create(const Memory* _mem, uint32_t _flags, uint8_t _skip) { - ImageContainer imageContainer; + bimg::ImageContainer imageContainer; - if (imageParse(imageContainer, _mem->data, _mem->size) ) + if (bimg::imageParse(imageContainer, _mem->data, _mem->size) ) { uint8_t numMips = imageContainer.m_numMips; const uint8_t startLod = uint8_t(bx::uint32_min(_skip, numMips-1) ); @@ -4822,7 +5007,7 @@ namespace bgfx { namespace gl uint32_t textureHeight; uint32_t textureDepth; { - const ImageBlockInfo& ibi = getBlockInfo(TextureFormat::Enum(imageContainer.m_format) ); + const bimg::ImageBlockInfo& ibi = bimg::getBlockInfo(bimg::TextureFormat::Enum(imageContainer.m_format) ); textureWidth = bx::uint32_max(ibi.blockWidth, imageContainer.m_width >>startLod); textureHeight = bx::uint32_max(ibi.blockHeight, imageContainer.m_height>>startLod); textureDepth = 1 < imageContainer.m_depth @@ -4856,9 +5041,9 @@ namespace bgfx { namespace gl { switch (target) { - case GL_TEXTURE_CUBE_MAP: target = GL_TEXTURE_CUBE_MAP_ARRAY; - case GL_TEXTURE_2D_MULTISAMPLE: target = GL_TEXTURE_2D_MULTISAMPLE_ARRAY; - default: target = GL_TEXTURE_2D_ARRAY; + case GL_TEXTURE_CUBE_MAP: target = GL_TEXTURE_CUBE_MAP_ARRAY; break; + case GL_TEXTURE_2D_MULTISAMPLE: target = GL_TEXTURE_2D_MULTISAMPLE_ARRAY; break; + default: target = GL_TEXTURE_2D_ARRAY; break; } } @@ -4888,16 +5073,17 @@ namespace bgfx { namespace gl && !s_textureFormat[m_requestedFormat].m_supported && !s_renderGL->m_textureSwizzleSupport ; - const bool compressed = isCompressed(TextureFormat::Enum(m_requestedFormat) ); + const bool compressed = bimg::isCompressed(bimg::TextureFormat::Enum(m_requestedFormat) ); const bool convert = false || m_textureFormat != m_requestedFormat || swizzle ; - BX_TRACE("Texture%-4s %3d: %s (requested: %s), layers %d, %dx%dx%d%s." + BX_TRACE("Texture%-4s %3d: %s %s(requested: %s), layers %d, %dx%dx%d%s." , imageContainer.m_cubeMap ? "Cube" : (1 < imageContainer.m_depth ? "3D" : "2D") , this - s_renderGL->m_textures , getName( (TextureFormat::Enum)m_textureFormat) + , srgb ? "+sRGB " : "" , getName( (TextureFormat::Enum)m_requestedFormat) , numLayers , textureWidth @@ -4907,12 +5093,12 @@ namespace bgfx { namespace gl ); BX_WARN(!convert, "Texture %s%s%s from %s to %s." - , swizzle ? "swizzle" : "" - , swizzle&&convert ? " and " : "" - , convert ? "convert" : "" - , getName( (TextureFormat::Enum)m_requestedFormat) - , getName( (TextureFormat::Enum)m_textureFormat) - ); + , swizzle ? "swizzle" : "" + , swizzle&&convert ? " and " : "" + , convert ? "convert" : "" + , getName( (TextureFormat::Enum)m_requestedFormat) + , getName( (TextureFormat::Enum)m_textureFormat) + ); uint8_t* temp = NULL; if (convert) @@ -4941,13 +5127,13 @@ namespace bgfx { namespace gl : side ; - ImageMip mip; - if (imageGetRawData(imageContainer, side, lod+startLod, _mem->data, _mem->size, mip) ) + bimg::ImageMip mip; + if (bimg::imageGetRawData(imageContainer, side, lod+startLod, _mem->data, _mem->size, mip) ) { if (compressed && !convert) { - compressedTexImage(imageTarget + GL_CHECK(compressedTexImage(imageTarget , lod , internalFmt , width @@ -4956,7 +5142,7 @@ namespace bgfx { namespace gl , 0 , mip.m_size , mip.m_data - ); + ) ); } else { @@ -4965,16 +5151,16 @@ namespace bgfx { namespace gl if (convert) { imageDecodeToRgba8(temp - , mip.m_data - , mip.m_width - , mip.m_height - , mip.m_width*4 - , mip.m_format - ); + , mip.m_data + , mip.m_width + , mip.m_height + , mip.m_width*4 + , mip.m_format + ); data = temp; } - texImage(imageTarget + GL_CHECK(texImage(imageTarget , msaaQuality , lod , internalFmt @@ -4985,7 +5171,7 @@ namespace bgfx { namespace gl , m_fmt , m_type , data - ); + ) ); } } else if (!computeWrite) @@ -4994,10 +5180,10 @@ namespace bgfx { namespace gl { uint32_t size = bx::uint32_max(1, (width + 3)>>2) * bx::uint32_max(1, (height + 3)>>2) - * 4*4*getBitsPerPixel(TextureFormat::Enum(m_textureFormat) )/8 + * 4*4* bimg::getBitsPerPixel(bimg::TextureFormat::Enum(m_textureFormat) )/8 ; - compressedTexImage(imageTarget + GL_CHECK(compressedTexImage(imageTarget , lod , internalFmt , width @@ -5006,11 +5192,11 @@ namespace bgfx { namespace gl , 0 , size , NULL - ); + ) ); } else { - texImage(imageTarget + GL_CHECK(texImage(imageTarget , msaaQuality , lod , internalFmt @@ -5021,7 +5207,7 @@ namespace bgfx { namespace gl , m_fmt , m_type , NULL - ); + ) ); } } @@ -5066,7 +5252,7 @@ namespace bgfx { namespace gl void TextureGL::update(uint8_t _side, uint8_t _mip, const Rect& _rect, uint16_t _z, uint16_t _depth, uint16_t _pitch, const Memory* _mem) { - const uint32_t bpp = getBitsPerPixel(TextureFormat::Enum(m_textureFormat) ); + const uint32_t bpp = bimg::getBitsPerPixel(bimg::TextureFormat::Enum(m_textureFormat) ); const uint32_t rectpitch = _rect.m_width*bpp/8; uint32_t srcpitch = UINT16_MAX == _pitch ? rectpitch : _pitch; @@ -5084,7 +5270,7 @@ namespace bgfx { namespace gl && !s_renderGL->m_textureSwizzleSupport ; const bool unpackRowLength = BX_IGNORE_C4127(!!BGFX_CONFIG_RENDERER_OPENGL || s_extension[Extension::EXT_unpack_subimage].m_supported); - const bool compressed = isCompressed(TextureFormat::Enum(m_requestedFormat) ); + const bool compressed = bimg::isCompressed(bimg::TextureFormat::Enum(m_requestedFormat) ); const bool convert = false || (compressed && m_textureFormat != m_requestedFormat) || swizzle @@ -5110,7 +5296,7 @@ namespace bgfx { namespace gl if (!unpackRowLength) { - imageCopy(temp, width, height, bpp, srcpitch, data); + bimg::imageCopy(temp, width, height, bpp, srcpitch, data); data = temp; } @@ -5133,7 +5319,7 @@ namespace bgfx { namespace gl if (convert) { - imageDecodeToRgba8(temp, data, width, height, srcpitch, TextureFormat::Enum(m_requestedFormat) ); + bimg::imageDecodeToRgba8(temp, data, width, height, srcpitch, bimg::TextureFormat::Enum(m_requestedFormat) ); data = temp; srcpitch = rectpitch; } @@ -5141,7 +5327,7 @@ namespace bgfx { namespace gl if (!unpackRowLength && !convert) { - imageCopy(temp, width, height, bpp, srcpitch, data); + bimg::imageCopy(temp, width, height, bpp, srcpitch, data); data = temp; } @@ -5233,13 +5419,15 @@ namespace bgfx { namespace gl GL_CHECK(glTexParameteri(target, GL_TEXTURE_MAG_FILTER, magFilter) ); GL_CHECK(glTexParameteri(target, GL_TEXTURE_MIN_FILTER, minFilter) ); - if (BX_ENABLED(BGFX_CONFIG_RENDERER_OPENGL) - || s_renderGL->m_borderColorSupport) + if (BX_ENABLED(BGFX_CONFIG_RENDERER_OPENGL) ) { - if (hasBorderColor) - { - GL_CHECK(glTexParameterfv(target, GL_TEXTURE_BORDER_COLOR, _rgba) ); - } + GL_CHECK(glTexParameterf(target, GL_TEXTURE_LOD_BIAS, float(BGFX_CONFIG_MIP_LOD_BIAS) ) ); + } + + if (s_renderGL->m_borderColorSupport + && hasBorderColor) + { + GL_CHECK(glTexParameterfv(target, GL_TEXTURE_BORDER_COLOR, _rgba) ); } if (0 != (flags & (BGFX_TEXTURE_MIN_ANISOTROPIC|BGFX_TEXTURE_MAG_ANISOTROPIC) ) @@ -5318,7 +5506,7 @@ namespace bgfx { namespace gl void writeString(bx::WriterI* _writer, const char* _str) { - bx::write(_writer, _str, (int32_t)bx::strnlen(_str) ); + bx::write(_writer, _str, (int32_t)bx::strLen(_str) ); } void writeStringf(bx::WriterI* _writer, const char* _format, ...) @@ -5335,15 +5523,15 @@ namespace bgfx { namespace gl void strins(char* _str, const char* _insert) { - size_t len = bx::strnlen(_insert); - bx::memMove(&_str[len], _str, bx::strnlen(_str)+1); + size_t len = bx::strLen(_insert); + bx::memMove(&_str[len], _str, bx::strLen(_str)+1); bx::memCopy(_str, _insert, len); } void ShaderGL::create(Memory* _mem) { bx::MemoryReader reader(_mem->data, _mem->size); - m_hash = bx::hashMurmur2A(_mem->data, _mem->size); + m_hash = bx::hash<bx::HashMurmur2A>(_mem->data, _mem->size); uint32_t magic; bx::read(&reader, magic); @@ -5404,9 +5592,10 @@ namespace bgfx { namespace gl if (0 != m_id) { - if (GL_COMPUTE_SHADER != m_type) + if (GL_COMPUTE_SHADER != m_type + && 0 != bx::strCmp(code, "#version 430", 12) ) { - int32_t codeLen = (int32_t)bx::strnlen(code); + int32_t codeLen = (int32_t)bx::strLen(code); int32_t tempLen = codeLen + (4<<10); char* temp = (char*)alloca(tempLen); bx::StaticMemoryBlockWriter writer(temp, tempLen); @@ -5432,7 +5621,7 @@ namespace bgfx { namespace gl bool usesShadowSamplers = !!bx::findIdentifierMatch(code, s_EXT_shadow_samplers); bool usesTexture3D = s_extension[Extension::OES_texture_3D].m_supported - && bx::findIdentifierMatch(code, s_OES_texture_3D) + && bx::findIdentifierMatch(code, s_texture3D) ; bool usesTextureLod = !!bx::findIdentifierMatch(code, s_EXT_shader_texture_lod); @@ -5506,7 +5695,8 @@ namespace bgfx { namespace gl if (usesTextureLod) { BX_WARN(s_extension[Extension::ARB_shader_texture_lod].m_supported - , "ARB_shader_texture_lod is used but not supported by GLES2 driver." + || s_extension[Extension::EXT_shader_texture_lod].m_supported + , "(ARB|EXT)_shader_texture_lod is used but not supported by GLES2 driver." ); if (s_extension[Extension::ARB_shader_texture_lod].m_supported) @@ -5523,11 +5713,23 @@ namespace bgfx { namespace gl } else { - writeString(&writer - , "#define texture2DLod(_sampler, _coord, _level) texture2D(_sampler, _coord)\n" - "#define texture2DProjLod(_sampler, _coord, _level) texture2DProj(_sampler, _coord)\n" - "#define textureCubeLod(_sampler, _coord, _level) textureCube(_sampler, _coord)\n" + if(s_extension[Extension::EXT_shader_texture_lod].m_supported) + { + writeString(&writer + , "#extension GL_EXT_shader_texture_lod : enable\n" + "#define texture2DLod texture2DLodEXT\n" + "#define texture2DProjLod texture2DProjLodEXT\n" + "#define textureCubeLod textureCubeLodEXT\n" ); + } + else + { + writeString(&writer + , "#define texture2DLod(_sampler, _coord, _level) texture2D(_sampler, _coord)\n" + "#define texture2DProjLod(_sampler, _coord, _level) texture2DProj(_sampler, _coord)\n" + "#define textureCubeLod(_sampler, _coord, _level) textureCube(_sampler, _coord)\n" + ); + } } } @@ -5552,10 +5754,10 @@ namespace bgfx { namespace gl if (insertFragDepth) { - const char* entry = bx::strnstr(temp, "void main ()"); + const char* entry = bx::strFind(temp, "void main ()"); if (NULL != entry) { - char* brace = const_cast<char*>(bx::strnstr(entry, "{") ); + char* brace = const_cast<char*>(bx::strFind(entry, "{") ); if (NULL != brace) { const char* end = bx::strmb(brace, '{', '}'); @@ -5582,15 +5784,17 @@ namespace bgfx { namespace gl && s_extension[Extension::ARB_shader_texture_lod].m_supported && bx::findIdentifierMatch(code, s_ARB_shader_texture_lod) ; + const bool usesGpuShader4 = !!bx::findIdentifierMatch(code, s_EXT_gpu_shader4); const bool usesGpuShader5 = !!bx::findIdentifierMatch(code, s_ARB_gpu_shader5); const bool usesIUsamplers = !!bx::findIdentifierMatch(code, s_uisamplers); const bool usesTexelFetch = !!bx::findIdentifierMatch(code, s_texelFetch); const bool usesTextureArray = !!bx::findIdentifierMatch(code, s_textureArray); + const bool usesTexture3D = !!bx::findIdentifierMatch(code, s_texture3D); const bool usesTextureMS = !!bx::findIdentifierMatch(code, s_ARB_texture_multisample); const bool usesPacking = !!bx::findIdentifierMatch(code, s_ARB_shading_language_packing); - uint32_t version = - usesIUsamplers || usesTexelFetch || usesGpuShader5 ? 130 + uint32_t version = BX_ENABLED(BX_PLATFORM_OSX) ? 120 + : usesTextureArray || usesTexture3D || usesIUsamplers|| usesTexelFetch || usesGpuShader5 ? 130 : usesTextureLod ? 120 : 120 ; @@ -5613,6 +5817,11 @@ namespace bgfx { namespace gl } } + if (usesGpuShader4) + { + writeString(&writer, "#extension GL_EXT_gpu_shader4 : enable\n"); + } + if (usesGpuShader5) { writeString(&writer, "#extension GL_ARB_gpu_shader5 : enable\n"); @@ -5631,6 +5840,29 @@ namespace bgfx { namespace gl if (usesTextureArray) { writeString(&writer, "#extension GL_EXT_texture_array : enable\n"); + + if (BX_ENABLED(BX_PLATFORM_OSX) ) + { + writeString(&writer, "#define texture2DArrayLodEXT texture2DArray\n"); + } + else + { + writeString(&writer, "#define texture2DArrayLodEXT texture2DArrayLod\n"); + } + } + + if (usesTexture3D) + { + writeString(&writer, "#define texture3DEXT texture3D\n"); + + if (BX_ENABLED(BX_PLATFORM_OSX) ) + { + writeString(&writer, "#define texture3DLodEXT texture3D\n"); + } + else + { + writeString(&writer, "#define texture3DLodEXT texture3DLod\n"); + } } if (130 <= version) @@ -5653,7 +5885,7 @@ namespace bgfx { namespace gl { char tmpFragData[16]; bx::snprintf(tmpFragData, BX_COUNTOF(tmpFragData), "gl_FragData[%d]", ii); - fragData = bx::uint32_max(fragData, NULL == bx::strnstr(code, tmpFragData) ? 0 : ii+1); + fragData = bx::uint32_max(fragData, NULL == bx::strFind(code, tmpFragData) ? 0 : ii+1); } BGFX_FATAL(0 != fragData, Fatal::InvalidShader, "Unable to find and patch gl_FragData!"); @@ -5746,7 +5978,7 @@ namespace bgfx { namespace gl { char tmpFragData[16]; bx::snprintf(tmpFragData, BX_COUNTOF(tmpFragData), "gl_FragData[%d]", ii); - fragData = bx::uint32_max(fragData, NULL == bx::strnstr(code, tmpFragData) ? 0 : ii+1); + fragData = bx::uint32_max(fragData, NULL == bx::strFind(code, tmpFragData) ? 0 : ii+1); } BGFX_FATAL(0 != fragData, Fatal::InvalidShader, "Unable to find and patch gl_FragData!"); @@ -5801,6 +6033,26 @@ namespace bgfx { namespace gl code = temp; } + else if (GL_COMPUTE_SHADER == m_type) + { + int32_t codeLen = (int32_t)bx::strLen(code); + int32_t tempLen = codeLen + (4<<10); + char* temp = (char*)alloca(tempLen); + bx::StaticMemoryBlockWriter writer(temp, tempLen); + + writeString(&writer, "#version 430\n"); + writeString(&writer, "#define texture2DLod textureLod\n"); + writeString(&writer, "#define texture3DLod textureLod\n"); + writeString(&writer, "#define textureCubeLod textureLod\n"); + writeString(&writer, "#define texture2DGrad textureGrad\n"); + writeString(&writer, "#define texture3DGrad textureGrad\n"); + writeString(&writer, "#define textureCubeGrad textureGrad\n"); + + bx::write(&writer, code+bx::strLen("#version 430"), codeLen); + bx::write(&writer, '\0'); + + code = temp; + } GL_CHECK(glShaderSource(m_id, 1, (const GLchar**)&code, NULL) ); GL_CHECK(glCompileShader(m_id) ); @@ -5810,7 +6062,24 @@ namespace bgfx { namespace gl if (0 == compiled) { - BX_TRACE("\n####\n%s\n####", code); + LineReader lineReader(code); + bx::Error err; + for (int32_t line = 1; err.isOk(); ++line) + { + char str[4096]; + int32_t len = bx::read(&lineReader, str, BX_COUNTOF(str)-1, &err); + + if (err.isOk() ) + { + str[len] = '\0'; + const char* eol = bx::streol(str); + if (eol != str) + { + *const_cast<char*>(eol) = '\0'; + } + BX_TRACE("%3d %s", line, str); + } + } GLsizei len; char log[1024]; @@ -5883,10 +6152,10 @@ namespace bgfx { namespace gl } GLenum attachment = GL_COLOR_ATTACHMENT0 + colorIdx; - TextureFormat::Enum format = (TextureFormat::Enum)texture.m_textureFormat; - if (isDepth(format) ) + bimg::TextureFormat::Enum format = bimg::TextureFormat::Enum(texture.m_textureFormat); + if (bimg::isDepth(format) ) { - const ImageBlockInfo& info = getBlockInfo(format); + const bimg::ImageBlockInfo& info = bimg::getBlockInfo(format); if (0 < info.stencilBits) { attachment = GL_DEPTH_STENCIL_ATTACHMENT; @@ -5973,7 +6242,7 @@ namespace bgfx { namespace gl if (0 != texture.m_id) { GLenum attachment = GL_COLOR_ATTACHMENT0 + colorIdx; - if (!isDepth( (TextureFormat::Enum)texture.m_textureFormat) ) + if (!bimg::isDepth(bimg::TextureFormat::Enum(texture.m_textureFormat) ) ) { ++colorIdx; @@ -6181,15 +6450,54 @@ namespace bgfx { namespace gl Query& query = m_query[(m_control.m_read + ii) % size]; if (query.m_handle.idx == _handle.idx) { - query.m_handle.idx = bgfx::invalidHandle; + query.m_handle.idx = bgfx::kInvalidHandle; } } } - void RendererContextGL::submit(Frame* _render, ClearQuad& _clearQuad, TextVideoMemBlitter& _textVideoMemBlitter) + void RendererContextGL::submitBlit(BlitState& _bs, uint16_t _view) { - BGFX_GPU_PROFILER_BEGIN_DYNAMIC("rendererSubmit"); + if (m_blitSupported) + { + while (_bs.hasItem(_view) ) + { + const BlitItem& bi = _bs.advance(); + + const TextureGL& src = m_textures[bi.m_src.idx]; + const TextureGL& dst = m_textures[bi.m_dst.idx]; + + uint32_t srcWidth = bx::uint32_min(src.m_width, bi.m_srcX + bi.m_width) - bi.m_srcX; + uint32_t srcHeight = bx::uint32_min(src.m_height, bi.m_srcY + bi.m_height) - bi.m_srcY; + uint32_t srcDepth = bx::uint32_min(src.m_depth, bi.m_srcZ + bi.m_depth) - bi.m_srcZ; + uint32_t dstWidth = bx::uint32_min(dst.m_width, bi.m_dstX + bi.m_width) - bi.m_dstX; + uint32_t dstHeight = bx::uint32_min(dst.m_height, bi.m_dstY + bi.m_height) - bi.m_dstY; + uint32_t dstDepth = bx::uint32_min(dst.m_depth, bi.m_dstZ + bi.m_depth) - bi.m_dstZ; + uint32_t width = bx::uint32_min(srcWidth, dstWidth); + uint32_t height = bx::uint32_min(srcHeight, dstHeight); + uint32_t depth = bx::uint32_min(srcDepth, dstDepth); + + GL_CHECK(glCopyImageSubData(src.m_id + , src.m_target + , bi.m_srcMip + , bi.m_srcX + , bi.m_srcY + , bi.m_srcZ + , dst.m_id + , dst.m_target + , bi.m_dstMip + , bi.m_dstX + , bi.m_dstY + , bi.m_dstZ + , width + , height + , bx::uint32_imax(depth, 1) + ) ); + } + } + } + void RendererContextGL::submit(Frame* _render, ClearQuad& _clearQuad, TextVideoMemBlitter& _textVideoMemBlitter) + { if (_render->m_capture) { renderDocTriggerCapture(); @@ -6202,7 +6510,6 @@ namespace bgfx { namespace gl GL_CHECK(glBindVertexArray(0) ); GL_CHECK(glDeleteVertexArrays(1, &m_vao) ); m_vao = 0; - m_vaoStateCache.invalidate(); } m_glctx.makeCurrent(NULL); @@ -6217,12 +6524,15 @@ namespace bgfx { namespace gl updateResolution(_render->m_resolution); - int64_t elapsed = -bx::getHPCounter(); + int64_t timeBegin = bx::getHPCounter(); int64_t captureElapsed = 0; - if (m_timerQuerySupport) + uint32_t frameQueryIdx = UINT32_MAX; + + if (m_timerQuerySupport + && !BX_ENABLED(BX_PLATFORM_OSX) ) { - m_gpuTimer.begin(); + frameQueryIdx = m_gpuTimer.begin(BGFX_CONFIG_MAX_VIEWS); } if (0 < _render->m_iboffset) @@ -6244,21 +6554,21 @@ namespace bgfx { namespace gl currentState.m_stateFlags = BGFX_STATE_NONE; currentState.m_stencil = packStencil(BGFX_STENCIL_NONE, BGFX_STENCIL_NONE); + RenderBind currentBind; + currentBind.clear(); + _render->m_hmdInitialized = m_ovr.isInitialized(); const bool hmdEnabled = m_ovr.isEnabled(); static ViewState viewState; viewState.reset(_render, hmdEnabled); - uint16_t programIdx = invalidHandle; + uint16_t programIdx = kInvalidHandle; SortKey key; uint16_t view = UINT16_MAX; FrameBufferHandle fbh = { BGFX_CONFIG_MAX_FRAME_BUFFERS }; - BlitKey blitKey; - blitKey.decode(_render->m_blitKeys[0]); - uint16_t numBlitItems = _render->m_numBlitItems; - uint16_t blitItem = 0; + BlitState bs(_render); int32_t resolutionHeight = hmdEnabled ? _render->m_hmd.height @@ -6279,7 +6589,6 @@ namespace bgfx { namespace gl : GL_FILL ) ); - GLuint currentVao = 0; bool wasCompute = false; bool viewHasScissor = false; Rect viewScissorRect; @@ -6287,9 +6596,10 @@ namespace bgfx { namespace gl uint16_t discardFlags = BGFX_CLEAR_NONE; const bool blendIndependentSupported = s_extension[Extension::ARB_draw_buffers_blend].m_supported; - const bool computeSupported = (BX_ENABLED(BGFX_CONFIG_RENDERER_OPENGL) && s_extension[Extension::ARB_compute_shader].m_supported) - || BX_ENABLED(BGFX_CONFIG_RENDERER_OPENGLES >= 31) - ; + const bool computeSupported = false + || (BX_ENABLED(BGFX_CONFIG_RENDERER_OPENGL) && s_extension[Extension::ARB_compute_shader].m_supported) + || BX_ENABLED(BGFX_CONFIG_RENDERER_OPENGLES >= 31) + ; uint32_t statsNumPrimsSubmitted[BX_COUNTOF(s_primInfo)] = {}; uint32_t statsNumPrimsRendered[BX_COUNTOF(s_primInfo)] = {}; @@ -6297,6 +6607,13 @@ namespace bgfx { namespace gl uint32_t statsNumIndices = 0; uint32_t statsKeyType[2] = {}; + Profiler<TimerQueryGL> profiler( + _render + , m_gpuTimer + , s_viewName + , m_timerQuerySupport && !BX_ENABLED(BX_PLATFORM_OSX) + ); + if (m_occlusionQuerySupport) { m_occlusionQuery.resolve(_render); @@ -6310,9 +6627,9 @@ namespace bgfx { namespace gl bool viewRestart = false; uint8_t restartState = 0; - viewState.m_rect = _render->m_rect[0]; + viewState.m_rect = _render->m_view[0].m_rect; - int32_t numItems = _render->m_num; + int32_t numItems = _render->m_numRenderItems; for (int32_t item = 0, restartItem = numItems; item < numItems || restartItem < numItems;) { const uint64_t encodedKey = _render->m_sortKeys[item]; @@ -6324,7 +6641,9 @@ namespace bgfx { namespace gl || item == numItems ; - const RenderItem& renderItem = _render->m_renderItem[_render->m_sortValues[item] ]; + const uint32_t itemIdx = _render->m_sortValues[item]; + const RenderItem& renderItem = _render->m_renderItem[itemIdx]; + const RenderBind& renderBind = _render->m_renderItemBind[itemIdx]; ++item; if (viewChanged) @@ -6339,11 +6658,11 @@ namespace bgfx { namespace gl } view = key.m_view; - programIdx = invalidHandle; + programIdx = kInvalidHandle; - if (_render->m_fb[view].idx != fbh.idx) + if (_render->m_view[view].m_fbh.idx != fbh.idx) { - fbh = _render->m_fb[view]; + fbh = _render->m_view[view].m_fbh; resolutionHeight = hmdEnabled ? _render->m_hmd.height : _render->m_resolution.m_height @@ -6351,7 +6670,7 @@ namespace bgfx { namespace gl resolutionHeight = setFrameBuffer(fbh, resolutionHeight, discardFlags); } - viewRestart = ( (BGFX_VIEW_STEREO == (_render->m_viewFlags[view] & BGFX_VIEW_STEREO) ) ); + viewRestart = ( (BGFX_VIEW_STEREO == (_render->m_view[view].m_flags & BGFX_VIEW_STEREO) ) ); viewRestart &= hmdEnabled; if (viewRestart) { @@ -6371,13 +6690,12 @@ namespace bgfx { namespace gl if (item > 1) { - BGFX_GPU_PROFILER_END(); - BGFX_PROFILER_END(); + profiler.end(); } - BGFX_PROFILER_BEGIN_DYNAMIC(s_viewName[view]); - BGFX_GPU_PROFILER_BEGIN_DYNAMIC(s_viewName[view]); - viewState.m_rect = _render->m_rect[view]; + profiler.begin(view); + + viewState.m_rect = _render->m_view[view].m_rect; if (viewRestart) { if (BX_ENABLED(BGFX_CONFIG_DEBUG_PIX) ) @@ -6409,7 +6727,7 @@ namespace bgfx { namespace gl } } - const Rect& scissorRect = _render->m_scissor[view]; + const Rect& scissorRect = _render->m_view[view].m_scissor; viewHasScissor = !scissorRect.isZero(); viewScissorRect = viewHasScissor ? scissorRect : viewState.m_rect; @@ -6419,13 +6737,12 @@ namespace bgfx { namespace gl , viewState.m_rect.m_height ) ); - Clear& clear = _render->m_clear[view]; + Clear& clear = _render->m_view[view].m_clear; discardFlags = clear.m_flags & BGFX_CLEAR_DISCARD_MASK; if (BGFX_CLEAR_NONE != (clear.m_flags & BGFX_CLEAR_MASK) ) { clearQuad(_clearQuad, viewState.m_rect, clear, resolutionHeight, _render->m_colorPalette); - currentVao = UINT32_MAX; // clearQuad will mess with VAO, invalidate it. } GL_CHECK(glDisable(GL_STENCIL_TEST) ); @@ -6434,45 +6751,7 @@ namespace bgfx { namespace gl GL_CHECK(glEnable(GL_CULL_FACE) ); GL_CHECK(glDisable(GL_BLEND) ); - if (m_blitSupported) - { - const uint8_t blitView = SortKey::decodeView(encodedKey); - for (; blitItem < numBlitItems && blitKey.m_view <= blitView; blitItem++) - { - const BlitItem& bi = _render->m_blitItem[blitItem]; - blitKey.decode(_render->m_blitKeys[blitItem + 1]); - - const TextureGL& src = m_textures[bi.m_src.idx]; - const TextureGL& dst = m_textures[bi.m_dst.idx]; - - uint32_t srcWidth = bx::uint32_min(src.m_width, bi.m_srcX + bi.m_width) - bi.m_srcX; - uint32_t srcHeight = bx::uint32_min(src.m_height, bi.m_srcY + bi.m_height) - bi.m_srcY; - uint32_t srcDepth = bx::uint32_min(src.m_depth, bi.m_srcZ + bi.m_depth) - bi.m_srcZ; - uint32_t dstWidth = bx::uint32_min(dst.m_width, bi.m_dstX + bi.m_width) - bi.m_dstX; - uint32_t dstHeight = bx::uint32_min(dst.m_height, bi.m_dstY + bi.m_height) - bi.m_dstY; - uint32_t dstDepth = bx::uint32_min(dst.m_depth, bi.m_dstZ + bi.m_depth) - bi.m_dstZ; - uint32_t width = bx::uint32_min(srcWidth, dstWidth); - uint32_t height = bx::uint32_min(srcHeight, dstHeight); - uint32_t depth = bx::uint32_min(srcDepth, dstDepth); - - GL_CHECK(glCopyImageSubData(src.m_id - , src.m_target - , bi.m_srcMip - , bi.m_srcX - , bi.m_srcY - , bi.m_srcZ - , dst.m_id - , dst.m_target - , bi.m_dstMip - , bi.m_dstX - , bi.m_dstY - , bi.m_dstZ - , width - , height - , bx::uint32_imax(depth, 1) - ) ); - } - } + submitBlit(bs, view); } if (isCompute) @@ -6499,18 +6778,25 @@ namespace bgfx { namespace gl GLbitfield barrier = 0; for (uint32_t ii = 0; ii < BGFX_MAX_COMPUTE_BINDINGS; ++ii) { - const Binding& bind = compute.m_bind[ii]; - if (invalidHandle != bind.m_idx) + const Binding& bind = renderBind.m_bind[ii]; + if (kInvalidHandle != bind.m_idx) { switch (bind.m_type) { + case Binding::Texture: + { + TextureGL& texture = m_textures[bind.m_idx]; + texture.commit(ii, bind.m_un.m_draw.m_textureFlags, _render->m_colorPalette); + } + break; + case Binding::Image: { const TextureGL& texture = m_textures[bind.m_idx]; GL_CHECK(glBindImageTexture(ii , texture.m_id , bind.m_un.m_compute.m_mip - , texture.isCubeMap()?GL_TRUE:GL_FALSE + , texture.isCubeMap() ? GL_TRUE : GL_FALSE , 0 , s_access[bind.m_un.m_compute.m_access] , s_imageFormat[bind.m_un.m_compute.m_format]) @@ -6540,8 +6826,8 @@ namespace bgfx { namespace gl if (0 != barrier) { - bool constantsChanged = compute.m_constBegin < compute.m_constEnd; - rendererUpdateUniforms(this, _render->m_uniformBuffer, compute.m_constBegin, compute.m_constEnd); + bool constantsChanged = compute.m_uniformBegin < compute.m_uniformEnd; + rendererUpdateUniforms(this, _render->m_uniformBuffer[compute.m_uniformIdx], compute.m_uniformBegin, compute.m_uniformEnd); if (constantsChanged && NULL != program.m_constantBuffer) @@ -6576,7 +6862,7 @@ namespace bgfx { namespace gl { if (isValid(currentState.m_indirectBuffer) ) { - currentState.m_indirectBuffer.idx = invalidHandle; + currentState.m_indirectBuffer.idx = kInvalidHandle; GL_CHECK(glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, 0) ); } @@ -6616,11 +6902,9 @@ namespace bgfx { namespace gl const uint64_t newFlags = draw.m_stateFlags; uint64_t changedFlags = currentState.m_stateFlags ^ draw.m_stateFlags; - currentState.m_stateFlags = newFlags; const uint64_t newStencil = draw.m_stencil; uint64_t changedStencil = currentState.m_stencil ^ draw.m_stencil; - currentState.m_stencil = newStencil; if (resetState) { @@ -6628,8 +6912,8 @@ namespace bgfx { namespace gl currentState.m_scissor = !draw.m_scissor; changedFlags = BGFX_STATE_MASK; changedStencil = packStencil(BGFX_STENCIL_MASK, BGFX_STENCIL_MASK); - currentState.m_stateFlags = newFlags; - currentState.m_stencil = newStencil; + + currentBind.clear(); } uint16_t scissor = draw.m_scissor; @@ -6656,7 +6940,7 @@ namespace bgfx { namespace gl else { Rect scissorRect; - scissorRect.setIntersect(viewScissorRect, _render->m_rectCache.m_cache[scissor]); + scissorRect.setIntersect(viewScissorRect, _render->m_frameCache.m_rectCache.m_cache[scissor]); if (scissorRect.isZeroArea() ) { continue; @@ -6671,6 +6955,9 @@ namespace bgfx { namespace gl } } + currentState.m_stateFlags = newFlags; + currentState.m_stencil = newStencil; + if (0 != changedStencil) { if (0 != newStencil) @@ -6952,17 +7239,17 @@ namespace bgfx { namespace gl } bool programChanged = false; - bool constantsChanged = draw.m_constBegin < draw.m_constEnd; + bool constantsChanged = draw.m_uniformBegin < draw.m_uniformEnd; bool bindAttribs = false; - rendererUpdateUniforms(this, _render->m_uniformBuffer, draw.m_constBegin, draw.m_constEnd); + rendererUpdateUniforms(this, _render->m_uniformBuffer[draw.m_uniformIdx], draw.m_uniformBegin, draw.m_uniformEnd); if (key.m_program != programIdx) { programIdx = key.m_program; - GLuint id = invalidHandle == programIdx ? 0 : m_program[programIdx].m_id; + GLuint id = kInvalidHandle == programIdx ? 0 : m_program[programIdx].m_id; // Skip rendering if program index is valid, but program is invalid. - programIdx = 0 == id ? invalidHandle : programIdx; + programIdx = 0 == id ? kInvalidHandle : programIdx; GL_CHECK(glUseProgram(id) ); programChanged = @@ -6970,7 +7257,7 @@ namespace bgfx { namespace gl bindAttribs = true; } - if (invalidHandle != programIdx) + if (kInvalidHandle != programIdx) { ProgramGL& program = m_program[programIdx]; @@ -6985,16 +7272,38 @@ namespace bgfx { namespace gl { for (uint32_t stage = 0; stage < BGFX_CONFIG_MAX_TEXTURE_SAMPLERS; ++stage) { - const Binding& bind = draw.m_bind[stage]; - Binding& current = currentState.m_bind[stage]; + const Binding& bind = renderBind.m_bind[stage]; + Binding& current = currentBind.m_bind[stage]; if (current.m_idx != bind.m_idx + || current.m_type != bind.m_type || current.m_un.m_draw.m_textureFlags != bind.m_un.m_draw.m_textureFlags || programChanged) { - if (invalidHandle != bind.m_idx) + if (kInvalidHandle != bind.m_idx) { - TextureGL& texture = m_textures[bind.m_idx]; - texture.commit(stage, bind.m_un.m_draw.m_textureFlags, _render->m_colorPalette); + switch (bind.m_type) + { + case Binding::Texture: + { + TextureGL& texture = m_textures[bind.m_idx]; + texture.commit(stage, bind.m_un.m_draw.m_textureFlags, _render->m_colorPalette); + } + break; + + case Binding::IndexBuffer: + { + const IndexBufferGL& buffer = m_indexBuffers[bind.m_idx]; + GL_CHECK(glBindBufferBase(GL_SHADER_STORAGE_BUFFER, stage, buffer.m_id) ); + } + break; + + case Binding::VertexBuffer: + { + const VertexBufferGL& buffer = m_vertexBuffers[bind.m_idx]; + GL_CHECK(glBindBufferBase(GL_SHADER_STORAGE_BUFFER, stage, buffer.m_id) ); + } + break; + } } } @@ -7002,153 +7311,7 @@ namespace bgfx { namespace gl } } - if (0 != defaultVao - && 0 == draw.m_stream[0].m_startVertex - && 0 == draw.m_instanceDataOffset) - { - bool diffStartVertex = false; - bool diffStreamHandles = false; - for (uint32_t idx = 0, streamMask = draw.m_streamMask, ntz = bx::uint32_cnttz(streamMask) - ; 0 != streamMask - ; streamMask >>= 1, idx += 1, ntz = bx::uint32_cnttz(streamMask) - ) - { - streamMask >>= ntz; - idx += ntz; - - if (currentState.m_stream[idx].m_handle.idx != draw.m_stream[idx].m_handle.idx) - { - diffStreamHandles = true; - break; - } - - if (currentState.m_stream[idx].m_startVertex != draw.m_stream[idx].m_startVertex) - { - diffStartVertex = true; - break; - } - } - - if (programChanged - || currentState.m_streamMask != draw.m_streamMask - || currentState.m_indexBuffer.idx != draw.m_indexBuffer.idx - || currentState.m_instanceDataOffset != draw.m_instanceDataOffset - || currentState.m_instanceDataStride != draw.m_instanceDataStride - || currentState.m_instanceDataBuffer.idx != draw.m_instanceDataBuffer.idx - || diffStartVertex - || diffStreamHandles) - { - bx::HashMurmur2A murmur; - murmur.begin(); - - for (uint32_t idx = 0, streamMask = draw.m_streamMask, ntz = bx::uint32_cnttz(streamMask) - ; 0 != streamMask - ; streamMask >>= 1, idx += 1, ntz = bx::uint32_cnttz(streamMask) - ) - { - streamMask >>= ntz; - idx += ntz; - - const Stream& stream = draw.m_stream[idx]; - murmur.add(stream.m_handle.idx); - - if (isValid(stream.m_handle) ) - { - const VertexBufferGL& vb = m_vertexBuffers[stream.m_handle.idx]; - uint16_t decl = !isValid(vb.m_decl) ? stream.m_decl.idx : vb.m_decl.idx; - murmur.add(decl); - } - - currentState.m_stream[idx].m_handle = stream.m_handle; - currentState.m_stream[idx].m_startVertex = stream.m_startVertex; - } - currentState.m_streamMask = draw.m_streamMask; - - murmur.add(draw.m_indexBuffer.idx); - murmur.add(draw.m_instanceDataBuffer.idx); - murmur.add(draw.m_instanceDataOffset); - murmur.add(draw.m_instanceDataStride); - murmur.add(programIdx); - uint32_t hash = murmur.end(); - - currentState.m_indexBuffer = draw.m_indexBuffer; - currentState.m_instanceDataOffset = draw.m_instanceDataOffset; - currentState.m_instanceDataStride = draw.m_instanceDataStride; - - GLuint id = m_vaoStateCache.find(hash); - if (UINT32_MAX != id) - { - currentVao = id; - GL_CHECK(glBindVertexArray(id) ); - } - else - { - id = m_vaoStateCache.add(hash); - currentVao = id; - GL_CHECK(glBindVertexArray(id) ); - - program.add(hash); - - program.bindAttributesBegin(); - for (uint32_t idx = 0, streamMask = draw.m_streamMask, ntz = bx::uint32_cnttz(streamMask) - ; 0 != streamMask - ; streamMask >>= 1, idx += 1, ntz = bx::uint32_cnttz(streamMask) - ) - { - streamMask >>= ntz; - idx += ntz; - - const Stream& stream = draw.m_stream[idx]; - - if (isValid(stream.m_handle) ) - { - VertexBufferGL& vb = m_vertexBuffers[stream.m_handle.idx]; - vb.add(hash); - - uint16_t decl = !isValid(vb.m_decl) ? stream.m_decl.idx : vb.m_decl.idx; - GL_CHECK(glBindBuffer(GL_ARRAY_BUFFER, vb.m_id) ); - program.bindAttributes(m_vertexDecls[decl], stream.m_startVertex); - } - - if (isValid(draw.m_instanceDataBuffer) ) - { - VertexBufferGL& instanceVb = m_vertexBuffers[draw.m_instanceDataBuffer.idx]; - instanceVb.add(hash); - GL_CHECK(glBindBuffer(GL_ARRAY_BUFFER, instanceVb.m_id) ); - program.bindInstanceData(draw.m_instanceDataStride, draw.m_instanceDataOffset); - } - } - program.bindAttributesEnd(); - - if (isValid(draw.m_indexBuffer) ) - { - IndexBufferGL& ib = m_indexBuffers[draw.m_indexBuffer.idx]; - ib.add(hash); - GL_CHECK(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ib.m_id) ); - } - else - { - GL_CHECK(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0) ); - } - } - } - } - else { - if (0 != defaultVao - && 0 != currentVao) - { - GL_CHECK(glBindVertexArray(defaultVao) ); - currentState.m_streamMask = 0; - for (size_t ii = 0; ii < BGFX_CONFIG_MAX_VERTEX_STREAMS; ++ii) - { - currentState.m_stream[ii].m_handle.idx = invalidHandle; - } - currentState.m_indexBuffer.idx = invalidHandle; - bindAttribs = true; - currentVao = 0; - } - bool diffStreamHandles = false; for (uint32_t idx = 0, streamMask = draw.m_streamMask, ntz = bx::uint32_cnttz(streamMask) ; 0 != streamMask @@ -7196,7 +7359,7 @@ namespace bgfx { namespace gl currentState.m_indexBuffer = draw.m_indexBuffer; uint16_t handle = draw.m_indexBuffer.idx; - if (invalidHandle != handle) + if (kInvalidHandle != handle) { IndexBufferGL& ib = m_indexBuffers[handle]; GL_CHECK(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ib.m_id) ); @@ -7335,7 +7498,7 @@ namespace bgfx { namespace gl { if (isValid(currentState.m_indirectBuffer) ) { - currentState.m_indirectBuffer.idx = invalidHandle; + currentState.m_indirectBuffer.idx = kInvalidHandle; GL_CHECK(glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0) ); } @@ -7405,6 +7568,8 @@ namespace bgfx { namespace gl } } + submitBlit(bs, BGFX_CONFIG_MAX_VIEWS); + blitMsaaFbo(); if (m_vaoSupport) @@ -7412,7 +7577,7 @@ namespace bgfx { namespace gl GL_CHECK(glBindVertexArray(m_vao) ); } - if (0 < _render->m_num) + if (0 < _render->m_numRenderItems) { if (0 != (m_resolution.m_flags & BGFX_RESET_FLUSH_AFTER_RENDER) ) { @@ -7423,24 +7588,13 @@ namespace bgfx { namespace gl capture(); captureElapsed += bx::getHPCounter(); - BGFX_GPU_PROFILER_END(); - BGFX_PROFILER_END(); + profiler.end(); } } - BGFX_GPU_PROFILER_END(); - m_glctx.makeCurrent(NULL); - int64_t now = bx::getHPCounter(); - elapsed += now; - - static int64_t last = now; - - Stats& perfStats = _render->m_perfStats; - perfStats.cpuTimeBegin = last; - - int64_t frameTime = now - last; - last = now; + int64_t timeEnd = bx::getHPCounter(); + int64_t frameTime = timeEnd - timeBegin; static int64_t min = frameTime; static int64_t max = frameTime; @@ -7450,43 +7604,45 @@ namespace bgfx { namespace gl static uint32_t maxGpuLatency = 0; static double maxGpuElapsed = 0.0f; double elapsedGpuMs = 0.0; - uint64_t elapsedGl = 0; - if (m_timerQuerySupport) + if (UINT32_MAX != frameQueryIdx) { - m_gpuTimer.end(); - do - { - elapsedGl = m_gpuTimer.m_elapsed; - elapsedGpuMs = double(elapsedGl)/1e6; - maxGpuElapsed = elapsedGpuMs > maxGpuElapsed ? elapsedGpuMs : maxGpuElapsed; - } - while (m_gpuTimer.get() ); + m_gpuTimer.end(frameQueryIdx); - maxGpuLatency = bx::uint32_imax(maxGpuLatency, m_gpuTimer.m_control.available()-1); + const TimerQueryGL::Result& result = m_gpuTimer.m_result[BGFX_CONFIG_MAX_VIEWS]; + double toGpuMs = 1000.0 / 1e9; + elapsedGpuMs = (result.m_end - result.m_begin) * toGpuMs; + maxGpuElapsed = elapsedGpuMs > maxGpuElapsed ? elapsedGpuMs : maxGpuElapsed; + + maxGpuLatency = bx::uint32_imax(maxGpuLatency, result.m_pending-1); } const int64_t timerFreq = bx::getHPFrequency(); - perfStats.cpuTimeEnd = now; + Stats& perfStats = _render->m_perfStats; + perfStats.cpuTimeBegin = timeBegin; + perfStats.cpuTimeEnd = timeEnd; perfStats.cpuTimerFreq = timerFreq; - perfStats.gpuTimeBegin = m_gpuTimer.m_begin; - perfStats.gpuTimeEnd = m_gpuTimer.m_end; + const TimerQueryGL::Result& result = m_gpuTimer.m_result[BGFX_CONFIG_MAX_VIEWS]; + perfStats.gpuTimeBegin = result.m_begin; + perfStats.gpuTimeEnd = result.m_end; perfStats.gpuTimerFreq = 1000000000; perfStats.numDraw = statsKeyType[0]; perfStats.numCompute = statsKeyType[1]; perfStats.maxGpuLatency = maxGpuLatency; + perfStats.gpuMemoryMax = -INT64_MAX; + perfStats.gpuMemoryUsed = -INT64_MAX; if (_render->m_debug & (BGFX_DEBUG_IFH|BGFX_DEBUG_STATS) ) { m_needPresent = true; TextVideoMem& tvm = m_textVideoMem; - static int64_t next = now; + static int64_t next = timeEnd; - if (now >= next) + if (timeEnd >= next) { - next = now + timerFreq; + next = timeEnd + timerFreq; double freq = double(timerFreq); double toMs = 1000.0/freq; @@ -7524,9 +7680,9 @@ namespace bgfx { namespace gl , !!(m_resolution.m_flags&BGFX_RESET_MAXANISOTROPY) ? '\xfe' : ' ' ); - double elapsedCpuMs = double(elapsed)*toMs; + double elapsedCpuMs = double(frameTime)*toMs; tvm.printf(10, pos++, 0x8e, " Submitted: %5d (draw %5d, compute %4d) / CPU %7.4f [ms] %c GPU %7.4f [ms] (latency %d) " - , _render->m_num + , _render->m_numRenderItems , statsKeyType[0] , statsKeyType[1] , elapsedCpuMs @@ -7553,15 +7709,14 @@ namespace bgfx { namespace gl } tvm.printf(10, pos++, 0x8e, " Indices: %7d ", statsNumIndices); - tvm.printf(10, pos++, 0x8e, " Uniform size: %7d, Max: %7d ", _render->m_uniformEnd, _render->m_uniformMax); +// tvm.printf(10, pos++, 0x8e, " Uniform size: %7d, Max: %7d ", _render->m_uniformEnd, _render->m_uniformMax); tvm.printf(10, pos++, 0x8e, " DVB size: %7d ", _render->m_vboffset); tvm.printf(10, pos++, 0x8e, " DIB size: %7d ", _render->m_iboffset); pos++; tvm.printf(10, pos++, 0x8e, " State cache: "); - tvm.printf(10, pos++, 0x8e, " VAO | Sampler "); - tvm.printf(10, pos++, 0x8e, " %6d | %6d " - , m_vaoStateCache.getCount() + tvm.printf(10, pos++, 0x8e, " Sampler "); + tvm.printf(10, pos++, 0x8e, " %6d " , m_samplerStateCache.getCount() ); @@ -7661,12 +7816,6 @@ namespace bgfx { namespace gl } } } // namespace bgfx -#undef BGFX_GPU_PROFILER_BIND -#undef BGFX_GPU_PROFILER_UNBIND -#undef BGFX_GPU_PROFILER_BEGIN -#undef BGFX_GPU_PROFILER_BEGIN_DYNAMIC -#undef BGFX_GPU_PROFILER_END - #else namespace bgfx { namespace gl |