From dbe31b15b311cb8b8d79d61d7d616b46731c0a9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Thu, 4 Jul 2013 17:53:32 +0200 Subject: [PATCH 1/3] Added CHROMIUM_map_sub NaCl-specific ES2 extension to the list. --- src/Context.cpp | 1 + src/Extensions.h | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/Context.cpp b/src/Context.cpp index 0a9f5e6b9..a2d290dee 100644 --- a/src/Context.cpp +++ b/src/Context.cpp @@ -199,6 +199,7 @@ const std::vector& Extension::extensions(Version version) { #else static const std::vector extensions{ _extension(GL,APPLE,texture_format_BGRA8888), + _extension(GL,CHROMIUM,map_sub), _extension(GL,EXT,texture_filter_anisotropic), _extension(GL,EXT,texture_format_BGRA8888), _extension(GL,EXT,read_format_bgra), diff --git a/src/Extensions.h b/src/Extensions.h index f1582d657..249dad0db 100644 --- a/src/Extensions.h +++ b/src/Extensions.h @@ -193,6 +193,8 @@ namespace GL { _extension(GL,APPLE,texture_format_BGRA8888, GLES200, None) // #79 } namespace ARM { _extension(GL,ARM,rgba8, GLES200, GLES300) // #82 + } namespace CHROMIUM { + _extension(GL,CHROMIUM,map_sub, GLES200, None) } namespace EXT { _extension(GL,EXT,texture_filter_anisotropic, GLES200, None) // #41 _extension(GL,EXT,texture_type_2_10_10_10_REV, GLES200, GLES300) // #42 From fbdbd4aa01dc33f0a1424bfa50ce7d032fb84658 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Thu, 4 Jul 2013 17:54:23 +0200 Subject: [PATCH 2/3] Implemented CHROMIUM_map_sub for Buffer. --- src/Buffer.cpp | 33 ++++++++++++++++++++++++++ src/Buffer.h | 50 ++++++++++++++++++++++++++++++++++----- src/OpenGL.h | 4 ++++ src/Test/BufferGLTest.cpp | 29 +++++++++++++++++++++++ 4 files changed, 110 insertions(+), 6 deletions(-) diff --git a/src/Buffer.cpp b/src/Buffer.cpp index 69bddf75c..7957e2461 100644 --- a/src/Buffer.cpp +++ b/src/Buffer.cpp @@ -78,6 +78,14 @@ void Buffer::initializeContextBasedFunctionality(Context* context) { #endif } +Buffer::Buffer(Buffer::Target targetHint): _targetHint(targetHint) + #ifdef CORRADE_TARGET_NACL + , _mappedBuffer(nullptr) + #endif +{ + glGenBuffers(1, &_id); +} + Buffer::~Buffer() { GLuint* bindings = Context::current()->state()->buffer->bindings; @@ -127,6 +135,31 @@ Int Buffer::size() { return size; } +#ifdef MAGNUM_TARGET_GLES2 +void* Buffer::mapSub(const GLintptr offset, const GLsizeiptr length, const MapAccess access) { + /** @todo Enable also in Emscripten (?) when extension wrangler is available */ + #ifdef CORRADE_TARGET_NACL + CORRADE_ASSERT(!_mappedBuffer, "Buffer::mapSub(): the buffer is already mapped", nullptr); + return _mappedBuffer = glMapBufferSubDataCHROMIUM(static_cast(bindInternal(_targetHint)), offset, length, GLenum(access)); + #else + CORRADE_INTERNAL_ASSERT(false); + static_cast(offset); + static_cast(length); + static_cast(access); + #endif +} + +void Buffer::unmapSub() { + #ifdef CORRADE_TARGET_NACL + CORRADE_ASSERT(_mappedBuffer, "Buffer::unmapSub(): the buffer is not mapped", ); + glUnmapBufferSubDataCHROMIUM(_mappedBuffer); + _mappedBuffer = nullptr; + #else + CORRADE_INTERNAL_ASSERT(false); + #endif +} +#endif + #ifndef MAGNUM_TARGET_GLES2 void Buffer::copyImplementationDefault(Buffer* read, Buffer* write, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size) { glCopyBufferSubData(static_cast(read->bindInternal(Target::CopyRead)), static_cast(write->bindInternal(Target::CopyWrite)), readOffset, writeOffset, size); diff --git a/src/Buffer.h b/src/Buffer.h index 5f16b13a1..7cbc99ae2 100644 --- a/src/Buffer.h +++ b/src/Buffer.h @@ -324,9 +324,10 @@ class MAGNUM_EXPORT Buffer { * * @deprecated Prefer to use @ref Magnum::Buffer::map(GLintptr, GLsizeiptr, MapFlags) "map(GLintptr, GLsizeiptr, MapFlags)" * instead, as it has more complete set of features. - * @see map(MapAccess) - * @requires_es_extension %Extension @es_extension{OES,mapbuffer} in - * OpenGL ES 2.0, use @ref Magnum::Buffer::map(GLintptr, GLsizeiptr, MapFlags) "map(GLintptr, GLsizeiptr, MapFlags)" + * @see map(MapAccess), mapSub() + * @requires_es_extension %Extension @es_extension{OES,mapbuffer} or + * @es_extension{CHROMIUM,map_sub} in OpenGL ES 2.0, use + * @ref Magnum::Buffer::map(GLintptr, GLsizeiptr, MapFlags) "map(GLintptr, GLsizeiptr, MapFlags)" * in OpenGL ES 3.0 instead. */ enum class MapAccess: GLenum { @@ -471,9 +472,7 @@ class MAGNUM_EXPORT Buffer { * Generates new OpenGL buffer. * @see @fn_gl{GenBuffers} */ - explicit Buffer(Target targetHint = Target::Array): _targetHint(targetHint) { - glGenBuffers(1, &_id); - } + explicit Buffer(Target targetHint = Target::Array); /** * @brief Destructor @@ -728,6 +727,27 @@ class MAGNUM_EXPORT Buffer { } #endif + #if defined(MAGNUM_TARGET_GLES2) || defined(DOXYGEN_GENERATING_OUTPUT) + /** + * @brief Map portion of buffer to client memory + * @param offset Offset into the buffer + * @param length Length of the mapped memory + * @param access Access + * @return Pointer to buffer data + * + * If the buffer is not already bound somewhere, it is bound to hinted + * target before the operation. + * @deprecated Prefer to use @ref Magnum::Buffer::map(GLintptr, GLsizeiptr, MapFlags) "map(GLintptr, GLsizeiptr, MapFlags)" + * instead, as it has more complete set of features. + * @see unmapSub(), setTargetHint(), @fn_gl_extension{MapBufferSubData,CHROMIUM,map_sub} + * @requires_gles20 Not available in ES 3.0 or desktop OpenGL. Use + * @ref Magnum::Buffer::map(GLintptr, GLsizeiptr, MapFlags) "map(GLintptr, GLsizeiptr, MapFlags)" + * instead. + * @requires_es_extension %Extension @es_extension{CHROMIUM,map_sub} + */ + void* mapSub(GLintptr offset, GLsizeiptr length, MapAccess access); + #endif + /** * @brief Map buffer to client memory * @param offset Offset into the buffer @@ -789,6 +809,21 @@ class MAGNUM_EXPORT Buffer { return (this->*unmapImplementation)(); } + #if defined(MAGNUM_TARGET_GLES2) || defined(DOXYGEN_GENERATING_OUTPUT) + /** + * @brief Unmap portion of buffer + * + * Unmaps portion of buffer previously mapped with mapSub(), + * invalidating the pointer returned by the function. + * @see @fn_gl_extension{UnmapBufferSubData,CHROMIUM,map_sub} + * @requires_gles20 Not available in ES 3.0 or desktop OpenGL. Use + * @ref Magnum::Buffer::map(GLintptr, GLsizeiptr, MapFlags) "map(GLintptr, GLsizeiptr, MapFlags)" + * instead. + * @requires_es_extension %Extension @es_extension{CHROMIUM,map_sub} + */ + void unmapSub(); + #endif + private: static void MAGNUM_LOCAL initializeContextBasedFunctionality(Context* context); @@ -878,6 +913,9 @@ class MAGNUM_EXPORT Buffer { GLuint _id; Target _targetHint; + #ifdef CORRADE_TARGET_NACL + void* _mappedBuffer; + #endif }; CORRADE_ENUMSET_OPERATORS(Buffer::MapFlags) diff --git a/src/OpenGL.h b/src/OpenGL.h index a63f743d2..8e8645a57 100644 --- a/src/OpenGL.h +++ b/src/OpenGL.h @@ -40,6 +40,10 @@ to NaCl's gl2ext.h we are including our own to prevent undeclared symbol errors with some recent extensions. */ #elif defined(CORRADE_TARGET_NACL) + +/* Enable function prototypes (the supported ones shouldn't fail at link time) */ +#define GL_GLEXT_PROTOTYPES + #include #include #undef __gl2ext_h_ diff --git a/src/Test/BufferGLTest.cpp b/src/Test/BufferGLTest.cpp index a87a06da7..fc21ff125 100644 --- a/src/Test/BufferGLTest.cpp +++ b/src/Test/BufferGLTest.cpp @@ -38,6 +38,9 @@ class BufferGLTest: public AbstractOpenGLTester { void construct(); void data(); void map(); + #ifdef MAGNUM_TARGET_GLES2 + void mapSub(); + #endif void mapRange(); void mapRangeExplicitFlush(); #ifndef MAGNUM_TARGET_GLES2 @@ -52,6 +55,9 @@ BufferGLTest::BufferGLTest() { addTests({&BufferGLTest::construct, &BufferGLTest::data, &BufferGLTest::map, + #ifdef MAGNUM_TARGET_GLES2 + &BufferGLTest::mapSub, + #endif &BufferGLTest::mapRange, &BufferGLTest::mapRangeExplicitFlush, #ifndef MAGNUM_TARGET_GLES2 @@ -147,6 +153,29 @@ void BufferGLTest::map() { } #endif +#ifdef MAGNUM_TARGET_GLES2 +void BufferGLTest::mapSub() { + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::CHROMIUM::map_sub::string() + std::string(" is not supported")); + + Buffer buffer; + + constexpr char data[] = {2, 7, 5, 13, 25}; + buffer.setData(data, Buffer::Usage::StaticDraw); + + char* contents = reinterpret_cast(buffer.mapSub(1, 4, Buffer::MapAccess::WriteOnly)); + MAGNUM_VERIFY_NO_ERROR(); + + CORRADE_VERIFY(contents); + contents[3] = 107; + + buffer.unmapSub(); + MAGNUM_VERIFY_NO_ERROR(); + + /** @todo How to verify the contents in ES? */ +} +#endif + void BufferGLTest::mapRange() { #ifndef MAGNUM_TARGET_GLES2 if(!Context::current()->isExtensionSupported()) From 475216609762ce4443bd4f9ddc5524db845bd0bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Thu, 4 Jul 2013 18:08:33 +0200 Subject: [PATCH 3/3] Text: use CHROMIUM_map_sub rather than OES_mapbuffer. OES_mapbuffer isn't available in (my) NaCl anyway and CHROMIUM_map_sub should be faster. --- src/Text/TextRenderer.cpp | 76 ++++++++++++++++++++++++++------------- src/Text/TextRenderer.h | 25 +++++++++++-- 2 files changed, 73 insertions(+), 28 deletions(-) diff --git a/src/Text/TextRenderer.cpp b/src/Text/TextRenderer.cpp index c2d7d0686..4f04aaccd 100644 --- a/src/Text/TextRenderer.cpp +++ b/src/Text/TextRenderer.cpp @@ -205,14 +205,55 @@ template std::tuple TextRendererisExtensionSupported()) { + if(Context::current()->isExtensionSupported()) { + bufferMapImplementation = &AbstractTextRenderer::bufferMapImplementationRange; + } else if(Context::current()->isExtensionSupported()) { + bufferMapImplementation = &AbstractTextRenderer::bufferMapImplementationSub; + bufferUnmapImplementation = &AbstractTextRenderer::bufferUnmapImplementationSub; + } else { MAGNUM_ASSERT_EXTENSION_SUPPORTED(Extensions::GL::OES::mapbuffer); - Warning() << "Text::TextRenderer:" << Extensions::GL::EXT::map_buffer_range::string() - << "is not supported, using less efficient" << Extensions::GL::OES::mapbuffer::string() + Warning() << "Text::TextRenderer: neither" << Extensions::GL::EXT::map_buffer_range::string() + << "nor" << Extensions::GL::CHROMIUM::map_sub::string() + << "is supported, using inefficient" << Extensions::GL::OES::mapbuffer::string() << "instead"; } #endif @@ -258,15 +299,8 @@ void AbstractTextRenderer::reserve(const uint32_t glyphCount, const Buffer::Usag ->setIndexBuffer(&_indexBuffer, 0, indexType, 0, vertexCount); /* Map buffer for filling */ - void* indices; - #ifdef MAGNUM_TARGET_GLES2 - if(Context::current()->isExtensionSupported()) - #endif - CORRADE_INTERNAL_ASSERT_OUTPUT(indices = _indexBuffer.map(0, indicesSize, - Buffer::MapFlag::InvalidateBuffer|Buffer::MapFlag::Write)); - #ifdef MAGNUM_TARGET_GLES2 - else CORRADE_INTERNAL_ASSERT_OUTPUT(indices = _indexBuffer.map(Buffer::MapAccess::WriteOnly)); - #endif + void* const indices = bufferMapImplementation(_indexBuffer, indicesSize); + CORRADE_INTERNAL_ASSERT(indices); /* Prefill index buffer */ if(vertexCount < 255) @@ -275,7 +309,7 @@ void AbstractTextRenderer::reserve(const uint32_t glyphCount, const Buffer::Usag createIndices(indices, glyphCount); else createIndices(indices, glyphCount); - CORRADE_INTERNAL_ASSERT_OUTPUT(_indexBuffer.unmap()); + bufferUnmapImplementation(_indexBuffer); } void AbstractTextRenderer::render(const std::string& text) { @@ -288,17 +322,9 @@ void AbstractTextRenderer::render(const std::string& text) { _rectangle = {}; /* Map buffer for rendering */ - Vertex* vertices; - #ifdef MAGNUM_TARGET_GLES2 - if(Context::current()->isExtensionSupported()) - #endif - CORRADE_INTERNAL_ASSERT_OUTPUT(vertices = static_cast(_vertexBuffer.map(0, - layouter->glyphCount()*4*sizeof(Vertex), - Buffer::MapFlag::InvalidateBuffer|Buffer::MapFlag::Write))); - #ifdef MAGNUM_TARGET_GLES2 - else CORRADE_INTERNAL_ASSERT_OUTPUT(vertices = - static_cast(_vertexBuffer.map(Buffer::MapAccess::WriteOnly))); - #endif + Vertex* const vertices = static_cast(bufferMapImplementation(_vertexBuffer, + layouter->glyphCount()*4*sizeof(Vertex))); + CORRADE_INTERNAL_ASSERT_OUTPUT(vertices); /* Render all glyphs */ Vector2 cursorPosition; @@ -325,7 +351,7 @@ void AbstractTextRenderer::render(const std::string& text) { /* Advance cursor position to next character */ cursorPosition += advance; } - CORRADE_INTERNAL_ASSERT_OUTPUT(_vertexBuffer.unmap()); + bufferUnmapImplementation(_vertexBuffer); /* Update index count */ _mesh.setIndexCount(layouter->glyphCount()*6); diff --git a/src/Text/TextRenderer.h b/src/Text/TextRenderer.h index 289d44940..ce0d0b0db 100644 --- a/src/Text/TextRenderer.h +++ b/src/Text/TextRenderer.h @@ -134,6 +134,25 @@ class MAGNUM_TEXT_EXPORT AbstractTextRenderer { Float size; UnsignedInt _capacity; Rectangle _rectangle; + + #ifdef MAGNUM_TARGET_GLES2 + typedef void*(*BufferMapImplementation)(Buffer&, GLsizeiptr); + static MAGNUM_TEXT_LOCAL void* bufferMapImplementationFull(Buffer& buffer, GLsizeiptr length); + static MAGNUM_TEXT_LOCAL void* bufferMapImplementationSub(Buffer& buffer, GLsizeiptr length); + static MAGNUM_TEXT_LOCAL void* bufferMapImplementationRange(Buffer& buffer, GLsizeiptr length); + static BufferMapImplementation bufferMapImplementation; + #else + static void* bufferMapImplementation(Buffer& buffer, GLsizeiptr length); + #endif + + #ifdef MAGNUM_TARGET_GLES2 + typedef void(*BufferUnmapImplementation)(Buffer&); + static MAGNUM_TEXT_LOCAL void bufferUnmapImplementationDefault(Buffer& buffer); + static MAGNUM_TEXT_LOCAL void bufferUnmapImplementationSub(Buffer& buffer); + static MAGNUM_TEXT_LOCAL BufferUnmapImplementation bufferUnmapImplementation; + #else + static void bufferUnmapImplementation(Buffer& buffer); + #endif }; /** @@ -198,9 +217,9 @@ renderer.mesh().draw(); @section TextRenderer-extensions Required OpenGL functionality Mutable text rendering requires @extension{ARB,map_buffer_range} on desktop -OpenGL (also part of OpenGL ES 3.0). If @es_extension{EXT,map_buffer_range} is -not available in ES 2.0, at least @es_extension{OES,mapbuffer} must be -supported for asynchronous buffer updates. +OpenGL (also part of OpenGL ES 3.0). If neither @es_extension{EXT,map_buffer_range} +nor @es_extension{CHROMIUM,map_sub} is not available in ES 2.0, at least +@es_extension{OES,mapbuffer} must be supported for asynchronous buffer updates. @see TextRenderer2D, TextRenderer3D, Font, Shaders::AbstractVectorShader */