diff --git a/README.md b/README.md index 90a69016..b75c548e 100644 --- a/README.md +++ b/README.md @@ -206,7 +206,6 @@ Todo - OSX and iOS platforms. - DX11: MSAA. - GL: MSAA. - - GL: ARB_vertex_array_object + OES_vertex_array_object. Notice ------ diff --git a/examples/common/math.h b/examples/common/math.h index a477e57c..f543b66f 100644 --- a/examples/common/math.h +++ b/examples/common/math.h @@ -12,21 +12,21 @@ #include #include -inline float fmin(float _a, float _b) -{ - return _a < _b ? _a : _b; -} - -inline float fmax(float _a, float _b) -{ - return _a > _b ? _a : _b; -} - -inline float flerp(float _a, float _b, float _t) -{ - return _a + (_b - _a) * _t; -} - +inline float fmin(float _a, float _b) +{ + return _a < _b ? _a : _b; +} + +inline float fmax(float _a, float _b) +{ + return _a > _b ? _a : _b; +} + +inline float flerp(float _a, float _b, float _t) +{ + return _a + (_b - _a) * _t; +} + inline void vec3Add(float* __restrict _result, const float* __restrict _a, const float* __restrict _b) { _result[0] = _a[0] + _b[0]; @@ -224,13 +224,13 @@ inline void mtxRotateXYZ(float* _result, float _ax, float _ay, float _az) _result[ 0] = cy*cz; _result[ 1] = -cy*sz; _result[ 2] = sy; - _result[ 4] = cz*sx*sy + cx*sz; - _result[ 5] = cx*cz - sx*sy*sz; + _result[ 4] = cz*sx*sy + cx*sz; + _result[ 5] = cx*cz - sx*sy*sz; _result[ 6] = -cy*sx; - _result[ 8] = -cx*cz*sy + sx*sz; - _result[ 9] = cz*sx + cx*sy*sz; - _result[10] = cx*cy; - _result[15] = 1.0f; + _result[ 8] = -cx*cz*sy + sx*sz; + _result[ 9] = cz*sx + cx*sy*sz; + _result[10] = cx*cy; + _result[15] = 1.0f; } inline void mtxRotateZYX(float* _result, float _ax, float _ay, float _az) @@ -243,16 +243,16 @@ inline void mtxRotateZYX(float* _result, float _ax, float _ay, float _az) float cz = cosf(_az); memset(_result, 0, sizeof(float)*16); - _result[ 0] = cy*cz; - _result[ 1] = cz*sx*sy-cx*sz; - _result[ 2] = cx*cz*sy+sx*sz; - _result[ 4] = cy*sz; - _result[ 5] = cx*cz + sx*sy*sz; - _result[ 6] = -cz*sx + cx*sy*sz; - _result[ 8] = -sy; - _result[ 9] = cy*sx; - _result[10] = cx*cy; - _result[15] = 1.0f; + _result[ 0] = cy*cz; + _result[ 1] = cz*sx*sy-cx*sz; + _result[ 2] = cx*cz*sy+sx*sz; + _result[ 4] = cy*sz; + _result[ 5] = cx*cz + sx*sy*sz; + _result[ 6] = -cz*sx + cx*sy*sz; + _result[ 8] = -sy; + _result[ 9] = cy*sx; + _result[10] = cx*cy; + _result[15] = 1.0f; }; inline void vec3MulMtx(float* __restrict _result, const float* __restrict _vec, const float* __restrict _mat) diff --git a/src/glimports.h b/src/glimports.h index fa9956d2..9560b3ae 100644 --- a/src/glimports.h +++ b/src/glimports.h @@ -154,6 +154,10 @@ GL_IMPORT(true, PFNGLGETTRANSLATEDSHADERSOURCEANGLEPROC, glGetTranslatedShaderS GL_IMPORT(true, PFNGLGETPROGRAMBINARYOESPROC, glGetProgramBinaryOES); GL_IMPORT(true, PFNGLPROGRAMBINARYOESPROC, glProgramBinaryOES); +GL_IMPORT(true, PFNGLBINDVERTEXARRAYOESPROC, glBindVertexArray); +GL_IMPORT(true, PFNGLDELETEVERTEXARRAYSOESPROC, glDeleteVertexArrays); +GL_IMPORT(true, PFNGLGENVERTEXARRAYSOESPROC, glGenVertexArrays); + #endif // BGFX_CONFIG_RENDERER_ #if !BGFX_CONFIG_RENDERER_OPENGLES3 diff --git a/src/renderer_gl.cpp b/src/renderer_gl.cpp index 1ff567ab..90e40461 100644 --- a/src/renderer_gl.cpp +++ b/src/renderer_gl.cpp @@ -10,20 +10,6 @@ # include # include -#if !BGFX_CONFIG_RENDERER_OPENGL -# define glClearDepth glClearDepthf -#endif // !BGFX_CONFIG_RENDERER_OPENGL - -#if BGFX_CONFIG_RENDERER_OPENGLES2 -# define glProgramBinary glProgramBinaryOES -# define glGetProgramBinary glGetProgramBinaryOES -# define GL_PROGRAM_BINARY_LENGTH GL_PROGRAM_BINARY_LENGTH_OES -# define GL_HALF_FLOAT GL_HALF_FLOAT_OES -# define GL_RGB10_A2 GL_RGB10_A2_EXT -# define GL_UNSIGNED_INT_2_10_10_10_REV GL_UNSIGNED_INT_2_10_10_10_REV_EXT -# define GL_SAMPLER_3D GL_SAMPLER_3D_OES -#endif // BGFX_CONFIG_RENDERER_OPENGLES2 - namespace bgfx { struct Extension @@ -64,6 +50,7 @@ namespace bgfx OES_vertex_type_10_10_10_2, EXT_occlusion_query_boolean, ARB_vertex_array_object, + OES_vertex_array_object, ATI_meminfo, NVX_gpu_memory_info, @@ -111,6 +98,7 @@ namespace bgfx { "GL_OES_vertex_type_10_10_10_2", false, true }, { "GL_EXT_occlusion_query_boolean", false, true }, { "GL_ARB_vertex_array_object", false, true }, + { "OES_vertex_array_object", false, true }, { "GL_ATI_meminfo", false, true }, { "GL_NVX_gpu_memory_info", false, true }, }; @@ -187,6 +175,7 @@ namespace bgfx , m_captureSize(0) , m_maxAnisotropy(0.0f) , m_dxtSupport(false) + , m_vaoSupport(false) , m_programBinarySupport(false) , m_textureSwizzleSupport(false) , m_flip(false) @@ -613,6 +602,11 @@ namespace bgfx } } + void invalidateCache() + { + m_vaoCache.invalidate(); + } + void updateCapture() { if (m_resolution.m_flags&BGFX_RESET_CAPTURE) @@ -695,6 +689,8 @@ namespace bgfx void shutdown() { + invalidateCache(); + #if BGFX_CONFIG_RENDERER_OPENGL m_queries.destroy(); #endif // BGFX_CONFIG_RENDERER_OPENGL @@ -731,6 +727,8 @@ namespace bgfx Queries m_queries; #endif // BGFX_CONFIG_RENDERER_OPENGL + VaoCache m_vaoCache; + TextVideoMem m_textVideoMem; Resolution m_resolution; @@ -738,6 +736,7 @@ namespace bgfx uint32_t m_captureSize; float m_maxAnisotropy; bool m_dxtSupport; + bool m_vaoSupport; bool m_programBinarySupport; bool m_textureSwizzleSupport; bool m_flip; @@ -2054,6 +2053,11 @@ namespace bgfx void TextVideoMemBlitter::setup() { + if (s_renderCtx.m_vaoSupport) + { + GL_CHECK(glBindVertexArray(0) ); + } + uint32_t width = s_renderCtx.m_resolution.m_width; uint32_t height = s_renderCtx.m_resolution.m_height; @@ -2223,6 +2227,11 @@ namespace bgfx s_extension[Extension::EXT_texture_compression_s3tc].m_supported ; + s_renderCtx.m_vaoSupport = !!BGFX_CONFIG_RENDERER_OPENGLES3 + || s_extension[Extension::ARB_vertex_array_object].m_supported + || s_extension[Extension::OES_vertex_array_object].m_supported + ; + s_renderCtx.m_programBinarySupport = !!BGFX_CONFIG_RENDERER_OPENGLES3 || s_extension[Extension::ARB_get_program_binary].m_supported || s_extension[Extension::OES_get_program_binary].m_supported @@ -2903,57 +2912,124 @@ namespace bgfx } } - if (currentState.m_vertexBuffer.idx != state.m_vertexBuffer.idx || programChanged) + if (s_renderCtx.m_vaoSupport) { - currentState.m_vertexBuffer = state.m_vertexBuffer; + if (programChanged + || currentState.m_vertexBuffer.idx != state.m_vertexBuffer.idx + || baseVertex != state.m_startVertex + || currentState.m_indexBuffer.idx != state.m_indexBuffer.idx) + { + uint64_t hash = (uint64_t(state.m_vertexBuffer.idx)<<48) + | (uint64_t(state.m_indexBuffer.idx)<<32) + | (uint64_t(state.m_instanceDataBuffer.idx)<<16) + | programIdx + ; + hash ^= state.m_startVertex; - uint16_t handle = state.m_vertexBuffer.idx; - if (invalidHandle != handle) - { - VertexBuffer& vb = s_renderCtx.m_vertexBuffers[handle]; - GL_CHECK(glBindBuffer(GL_ARRAY_BUFFER, vb.m_id) ); - bindAttribs = true; - } - else - { - GL_CHECK(glBindBuffer(GL_ARRAY_BUFFER, 0) ); + currentState.m_vertexBuffer = state.m_vertexBuffer; + currentState.m_indexBuffer = state.m_indexBuffer; + baseVertex = state.m_startVertex; + + GLuint id = s_renderCtx.m_vaoCache.find(hash); + if (UINT32_MAX != id) + { + GL_CHECK(glBindVertexArray(id) ); + } + else + { + id = s_renderCtx.m_vaoCache.add(hash); + GL_CHECK(glBindVertexArray(id) ); + + if (invalidHandle != state.m_vertexBuffer.idx) + { + VertexBuffer& vb = s_renderCtx.m_vertexBuffers[state.m_vertexBuffer.idx]; + GL_CHECK(glBindBuffer(GL_ARRAY_BUFFER, vb.m_id) ); + + uint16_t decl = vb.m_decl.idx == invalidHandle ? state.m_vertexDecl.idx : vb.m_decl.idx; + const Program& program = s_renderCtx.m_program[programIdx]; + program.bindAttributes(s_renderCtx.m_vertexDecls[decl], state.m_startVertex); + + if (invalidHandle != state.m_instanceDataBuffer.idx) + { + GL_CHECK(glBindBuffer(GL_ARRAY_BUFFER, s_renderCtx.m_vertexBuffers[state.m_instanceDataBuffer.idx].m_id) ); + program.bindInstanceData(state.m_instanceDataStride, state.m_instanceDataOffset); + } + } + else + { + GL_CHECK(glBindBuffer(GL_ARRAY_BUFFER, 0) ); + } + + if (invalidHandle != state.m_indexBuffer.idx) + { + IndexBuffer& ib = s_renderCtx.m_indexBuffers[state.m_indexBuffer.idx]; + GL_CHECK(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ib.m_id) ); + } + else + { + GL_CHECK(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0) ); + } + } } } - - if (currentState.m_indexBuffer.idx != state.m_indexBuffer.idx) + else { - currentState.m_indexBuffer = state.m_indexBuffer; + if (programChanged + || currentState.m_vertexBuffer.idx != state.m_vertexBuffer.idx) + { + currentState.m_vertexBuffer = state.m_vertexBuffer; - uint16_t handle = state.m_indexBuffer.idx; - if (invalidHandle != handle) - { - IndexBuffer& ib = s_renderCtx.m_indexBuffers[handle]; - GL_CHECK(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ib.m_id) ); + uint16_t handle = state.m_vertexBuffer.idx; + if (invalidHandle != handle) + { + VertexBuffer& vb = s_renderCtx.m_vertexBuffers[handle]; + GL_CHECK(glBindBuffer(GL_ARRAY_BUFFER, vb.m_id) ); + bindAttribs = true; + } + else + { + GL_CHECK(glBindBuffer(GL_ARRAY_BUFFER, 0) ); + } } - else + + if (currentState.m_indexBuffer.idx != state.m_indexBuffer.idx) { - GL_CHECK(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0) ); + currentState.m_indexBuffer = state.m_indexBuffer; + + uint16_t handle = state.m_indexBuffer.idx; + if (invalidHandle != handle) + { + IndexBuffer& ib = s_renderCtx.m_indexBuffers[handle]; + GL_CHECK(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ib.m_id) ); + } + else + { + GL_CHECK(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0) ); + } + } + + if (invalidHandle != currentState.m_vertexBuffer.idx) + { + if (baseVertex != state.m_startVertex + || bindAttribs) + { + baseVertex = state.m_startVertex; + const VertexBuffer& vb = s_renderCtx.m_vertexBuffers[state.m_vertexBuffer.idx]; + uint16_t decl = vb.m_decl.idx == invalidHandle ? state.m_vertexDecl.idx : vb.m_decl.idx; + const Program& program = s_renderCtx.m_program[programIdx]; + program.bindAttributes(s_renderCtx.m_vertexDecls[decl], state.m_startVertex); + + if (invalidHandle != state.m_instanceDataBuffer.idx) + { + GL_CHECK(glBindBuffer(GL_ARRAY_BUFFER, s_renderCtx.m_vertexBuffers[state.m_instanceDataBuffer.idx].m_id) ); + program.bindInstanceData(state.m_instanceDataStride, state.m_instanceDataOffset); + } + } } } if (invalidHandle != currentState.m_vertexBuffer.idx) { - if (baseVertex != state.m_startVertex - || bindAttribs) - { - baseVertex = state.m_startVertex; - const VertexBuffer& vb = s_renderCtx.m_vertexBuffers[state.m_vertexBuffer.idx]; - uint16_t decl = vb.m_decl.idx == invalidHandle ? state.m_vertexDecl.idx : vb.m_decl.idx; - const Program& program = s_renderCtx.m_program[programIdx]; - program.bindAttributes(s_renderCtx.m_vertexDecls[decl], state.m_startVertex); - - if (invalidHandle != state.m_instanceDataBuffer.idx) - { - GL_CHECK(glBindBuffer(GL_ARRAY_BUFFER, s_renderCtx.m_vertexBuffers[state.m_instanceDataBuffer.idx].m_id) ); - program.bindInstanceData(state.m_instanceDataStride, state.m_instanceDataOffset); - } - } - uint32_t numVertices = state.m_numVertices; if (UINT32_C(0xffffffff) == numVertices) { diff --git a/src/renderer_gl.h b/src/renderer_gl.h index c12661f1..ae764426 100644 --- a/src/renderer_gl.h +++ b/src/renderer_gl.h @@ -196,6 +196,23 @@ typedef void (APIENTRYP PFNGLSTENCILOPPROC) (GLenum fail, GLenum zfail, GLenum z # define GL_APIENTRYP GL_APIENTRY* #endif // GL_APIENTRYP +#if !BGFX_CONFIG_RENDERER_OPENGL +# define glClearDepth glClearDepthf +#endif // !BGFX_CONFIG_RENDERER_OPENGL + +#if BGFX_CONFIG_RENDERER_OPENGLES2 +# define glProgramBinary glProgramBinaryOES +# define glGetProgramBinary glGetProgramBinaryOES +# define glBindVertexArray glBindVertexArrayOES +# define glDeleteVertexArrays glDeleteVertexArraysOES +# define glGenVertexArrays glGenVertexArraysOES +# define GL_PROGRAM_BINARY_LENGTH GL_PROGRAM_BINARY_LENGTH_OES +# define GL_HALF_FLOAT GL_HALF_FLOAT_OES +# define GL_RGB10_A2 GL_RGB10_A2_EXT +# define GL_UNSIGNED_INT_2_10_10_10_REV GL_UNSIGNED_INT_2_10_10_10_REV_EXT +# define GL_SAMPLER_3D GL_SAMPLER_3D_OES +#endif // BGFX_CONFIG_RENDERER_OPENGLES2 + namespace bgfx { typedef void (GL_APIENTRYP PFNGLVERTEXATTRIBDIVISORBGFXPROC)(GLuint _index, GLuint _divisor); @@ -331,6 +348,56 @@ namespace bgfx VertexDeclHandle m_decl; }; + class VaoCache + { + public: + GLuint add(uint64_t _hash) + { + invalidate(_hash); + + GLuint arrayId; + GL_CHECK(glGenVertexArrays(1, &arrayId) ); + + m_hashMap.insert(stl::make_pair(_hash, arrayId) ); + + return arrayId; + } + + GLuint find(uint64_t _hash) + { + HashMap::iterator it = m_hashMap.find(_hash); + if (it != m_hashMap.end() ) + { + return it->second; + } + + return UINT32_MAX; + } + + void invalidate(uint64_t _hash) + { + HashMap::iterator it = m_hashMap.find(_hash); + if (it != m_hashMap.end() ) + { + GL_CHECK(glDeleteVertexArrays(1, &it->second) ); + m_hashMap.erase(it); + } + } + + void invalidate() + { + for (HashMap::iterator it = m_hashMap.begin(), itEnd = m_hashMap.end(); it != itEnd; ++it) + { + GL_CHECK(glDeleteVertexArrays(1, &it->second) ); + } + m_hashMap.clear(); + } + + private: + typedef stl::unordered_map HashMap; + HashMap m_hashMap; + }; + struct Texture { Texture()