From f275143e9f7e740e37cbed9796e66b65b82c1de8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Sun, 9 Oct 2016 19:40:22 +0200 Subject: [PATCH] Support for indexed primitive queries. Amazing how it all still fits my original design without needing to rewrite half of the API. --- doc/opengl-mapping.dox | 2 +- doc/opengl-support.dox | 2 +- src/Magnum/AbstractQuery.h | 5 +- src/Magnum/CMakeLists.txt | 1 + src/Magnum/PrimitiveQuery.cpp | 69 ++++++++++++++++++++++++ src/Magnum/PrimitiveQuery.h | 58 ++++++++++++++++---- src/Magnum/Test/PrimitiveQueryGLTest.cpp | 63 ++++++++++++++++++++++ 7 files changed, 186 insertions(+), 14 deletions(-) create mode 100644 src/Magnum/PrimitiveQuery.cpp diff --git a/doc/opengl-mapping.dox b/doc/opengl-mapping.dox index 6a0ca874c..f00875510 100644 --- a/doc/opengl-mapping.dox +++ b/doc/opengl-mapping.dox @@ -52,7 +52,7 @@ OpenGL function | Matching API --------------------------------------- | ------------ @fn_gl{BeginConditionalRender}, `glEndConditionalRender()` | @ref SampleQuery::beginConditionalRender(), \n @ref SampleQuery::endConditionalRender() @fn_gl{BeginQuery}, `glEndQuery()` | @ref PrimitiveQuery::begin(), \n @ref SampleQuery::begin(), \n @ref TimeQuery::begin(), \n @ref AbstractQuery::end() -@fn_gl{BeginQueryIndexed}, `glEndQueryIndexed()` | | +@fn_gl{BeginQueryIndexed}, `glEndQueryIndexed()` | @ref PrimitiveQuery::begin(UnsignedInt), \n @ref PrimitiveQuery::end() @fn_gl{BeginTransformFeedback}, `glEndTransformFeedback()` | @ref TransformFeedback::begin(), @ref TransformFeedback::end() @fn_gl{BindAttribLocation} | @ref AbstractShaderProgram::bindAttributeLocation() @fn_gl{BindBuffer} | not needed, handled internally in @ref Buffer and elsewhere diff --git a/doc/opengl-support.dox b/doc/opengl-support.dox index a9bf219f6..81cc932ed 100644 --- a/doc/opengl-support.dox +++ b/doc/opengl-support.dox @@ -132,7 +132,7 @@ GLSL 4.00 | done @extension{ARB,tessellation_shader} | missing some limit queries and patch parameter specification function @extension{ARB,texture_buffer_object_rgb32} | done @extension{ARB,transform_feedback2} | missing transform feedback draw -@extension{ARB,transform_feedback3} | only advanced interleaving +@extension{ARB,transform_feedback3} | missing indexed properties query @subsection opengl-support-41 OpenGL 4.1 diff --git a/src/Magnum/AbstractQuery.h b/src/Magnum/AbstractQuery.h index 1b9d0f19f..0828a52a4 100644 --- a/src/Magnum/AbstractQuery.h +++ b/src/Magnum/AbstractQuery.h @@ -183,6 +183,9 @@ class MAGNUM_EXPORT AbstractQuery: public AbstractObject { void begin(GLenum target); #endif + GLuint _id; + GLenum _target; + private: #ifndef MAGNUM_TARGET_WEBGL AbstractQuery& setLabelInternal(Containers::ArrayView label); @@ -193,8 +196,6 @@ class MAGNUM_EXPORT AbstractQuery: public AbstractObject { void MAGNUM_LOCAL createImplementationDSA(); #endif - GLuint _id; - GLenum _target; ObjectFlags _flags; }; diff --git a/src/Magnum/CMakeLists.txt b/src/Magnum/CMakeLists.txt index fb728503c..6fdc91788 100644 --- a/src/Magnum/CMakeLists.txt +++ b/src/Magnum/CMakeLists.txt @@ -151,6 +151,7 @@ endif() if(NOT TARGET_GLES2) list(APPEND Magnum_SRCS BufferImage.cpp + PrimitiveQuery.cpp TextureArray.cpp TransformFeedback.cpp diff --git a/src/Magnum/PrimitiveQuery.cpp b/src/Magnum/PrimitiveQuery.cpp new file mode 100644 index 000000000..e2c989939 --- /dev/null +++ b/src/Magnum/PrimitiveQuery.cpp @@ -0,0 +1,69 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016 + Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include "PrimitiveQuery.h" + +namespace Magnum { + +void PrimitiveQuery::begin() { + #ifndef MAGNUM_TARGET_GLES + _index = 0; + #endif + AbstractQuery::begin(); +} + +#ifdef MAGNUM_BUILD_DEPRECATED +void PrimitiveQuery::begin(const Target target) { + #ifndef MAGNUM_TARGET_GLES + _index = 0; + #endif + AbstractQuery::begin(GLenum(target)); +} +#endif + +#ifndef MAGNUM_TARGET_GLES +void PrimitiveQuery::begin(const UnsignedInt index) { + #ifdef MAGNUM_BUILD_DEPRECATED + CORRADE_INTERNAL_ASSERT(_target); + #endif + + glBeginQueryIndexed(_target, _index = index, _id); +} +#endif + +void PrimitiveQuery::end() { + #ifdef MAGNUM_BUILD_DEPRECATED + CORRADE_INTERNAL_ASSERT(_target); + #endif + + #ifndef MAGNUM_TARGET_GLES + if(!_index) glEndQuery(_target); + else glEndQueryIndexed(_target, _index); + #else + AbstractQuery::end(); + #endif +} + +} diff --git a/src/Magnum/PrimitiveQuery.h b/src/Magnum/PrimitiveQuery.h index 588fe21c5..bb6c7bc4f 100644 --- a/src/Magnum/PrimitiveQuery.h +++ b/src/Magnum/PrimitiveQuery.h @@ -63,18 +63,19 @@ UnsignedInt primitiveCount = q.result(); @requires_gl30 Extension @extension{EXT,transform_feedback} @requires_gles30 Only sample queries are available in OpenGL ES 2.0. @requires_webgl20 Queries are not available in WebGL 1.0. -@todo glBeginQueryIndexed @todo @extension{ARB,transform_feedback_overflow_query} */ -class PrimitiveQuery: public AbstractQuery { +class MAGNUM_EXPORT PrimitiveQuery: public AbstractQuery { public: /** @brief Query target */ enum class Target: GLenum { #ifndef MAGNUM_TARGET_GLES2 /** * Count of primitives generated from vertex shader or geometry - * shader. Use @ref result() or @ref result() to - * retrieve the result. + * shader. When used with @ref begin(UnsignedInt), the index must + * be lower than @ref TransformFeedback::maxVertexStreams(). Use + * @ref result() or @ref result() to retrieve the + * result. * @requires_gles30 Not defined in OpenGL ES 2.0. * @requires_es_extension Extension @es_extension{ANDROID,extension_pack_es31a}/ * @es_extension{EXT,geometry_shader} @@ -88,7 +89,9 @@ class PrimitiveQuery: public AbstractQuery { #endif /** - * Count of primitives written to transform feedback buffer. Use + * Count of primitives written to transform feedback buffer. When + * used with @ref begin(UnsignedInt), the index must be lower than + * @ref TransformFeedback::maxVertexStreams(). Use * @ref result() or @ref result() to retrieve the * result. */ @@ -140,18 +143,49 @@ class PrimitiveQuery: public AbstractQuery { */ explicit PrimitiveQuery(NoCreateT) noexcept: AbstractQuery{NoCreate, GLenum(Target::TransformFeedbackPrimitivesWritten)} {} + /** + * @brief Begin query + * + * Begins counting until @ref end() is called. Equivalent to calling + * @ref begin(UnsignedInt) with @p index set to `0`. + * @see @fn_gl{BeginQuery} + */ + void begin(); + #ifdef MAGNUM_BUILD_DEPRECATED /** - * @copybrief AbstractQuery::begin() + * @copybrief begin() * @deprecated Use @ref begin() instead. */ - CORRADE_DEPRECATED("use begin() instead") void begin(Target target) { - AbstractQuery::begin(GLenum(target)); - } + CORRADE_DEPRECATED("use begin() instead") void begin(Target target); + #endif - using AbstractQuery::begin; + #ifndef MAGNUM_TARGET_GLES + /** + * @brief Begin indexed query + * + * Begins counting until @ref end() is called. + * @see @fn_gl{BeginQueryIndexed} + * @requires_gl40 Extension @extension{ARB,transform_feedback3} + * @requires_gl Indexed queries are not available in OpenGL ES or WebGL. + */ + void begin(UnsignedInt index); #endif + /** + * @brief End query + * + * Ends the non-indexed or indexed query started with @ref begin() or + * @ref begin(UnsignedInt). The result can be then retrieved by calling + * @ref result(). + * @see @fn_gl{EndQuery}, @fn_gl2{EndQueryIndexed,BeginQueryIndexed} + * @requires_gl40 Extension @extension{ARB,transform_feedback3} for + * indexed queries + * @requires_gl Indexed queries are not available in OpenGL ES or + * WebGL. + */ + void end(); + /* Overloads to remove WTF-factor from method chaining order */ #if !defined(DOXYGEN_GENERATING_OUTPUT) && !defined(MAGNUM_TARGET_WEBGL) PrimitiveQuery& setLabel(const std::string& label) { @@ -166,6 +200,10 @@ class PrimitiveQuery: public AbstractQuery { private: explicit PrimitiveQuery(GLuint id, Target target, ObjectFlags flags) noexcept: AbstractQuery{id, GLenum(target), flags} {} + + #ifndef MAGNUM_TARGET_GLES + GLuint _index{}; + #endif }; } diff --git a/src/Magnum/Test/PrimitiveQueryGLTest.cpp b/src/Magnum/Test/PrimitiveQueryGLTest.cpp index 3c63d9527..0e3320716 100644 --- a/src/Magnum/Test/PrimitiveQueryGLTest.cpp +++ b/src/Magnum/Test/PrimitiveQueryGLTest.cpp @@ -48,6 +48,7 @@ struct PrimitiveQueryGLTest: AbstractOpenGLTester { #ifndef MAGNUM_TARGET_GLES void primitivesGenerated(); + void primitivesGeneratedIndexed(); #endif void transformFeedbackPrimitivesWritten(); }; @@ -58,6 +59,7 @@ PrimitiveQueryGLTest::PrimitiveQueryGLTest() { #ifndef MAGNUM_TARGET_GLES &PrimitiveQueryGLTest::primitivesGenerated, + &PrimitiveQueryGLTest::primitivesGeneratedIndexed, #endif &PrimitiveQueryGLTest::transformFeedbackPrimitivesWritten}); } @@ -158,6 +160,67 @@ void PrimitiveQueryGLTest::primitivesGenerated() { CORRADE_VERIFY(availableAfter); CORRADE_COMPARE(count, 3); } + +void PrimitiveQueryGLTest::primitivesGeneratedIndexed() { + if(!Context::current().isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::transform_feedback3::string() + std::string(" is not available.")); + + /* Bind some FB to avoid errors on contexts w/o default FB */ + Renderbuffer color; + color.setStorage(RenderbufferFormat::RGBA8, Vector2i{32}); + Framebuffer fb{{{}, Vector2i{32}}}; + fb.attachRenderbuffer(Framebuffer::ColorAttachment{0}, color) + .bind(); + + struct MyShader: AbstractShaderProgram { + typedef Attribute<0, Vector2> Position; + + explicit MyShader() { + Shader vert( + #ifndef CORRADE_TARGET_APPLE + Version::GL210 + #else + Version::GL310 + #endif + , Shader::Type::Vertex); + + CORRADE_INTERNAL_ASSERT_OUTPUT(vert.addSource( + "#if __VERSION__ >= 130\n" + "#define attribute in\n" + "#endif\n" + "attribute vec4 position;\n" + "void main() {\n" + " gl_Position = position;\n" + "}\n").compile()); + + attachShader(vert); + bindAttributeLocation(Position::Location, "position"); + CORRADE_INTERNAL_ASSERT_OUTPUT(link()); + } + } shader; + + Buffer vertices; + vertices.setData({nullptr, 9*sizeof(Vector2)}, BufferUsage::StaticDraw); + + Mesh mesh; + mesh.setPrimitive(MeshPrimitive::Triangles) + .setCount(9) + .addVertexBuffer(vertices, 0, MyShader::Position()); + + MAGNUM_VERIFY_NO_ERROR(); + + PrimitiveQuery q{PrimitiveQuery::Target::PrimitivesGenerated}; + q.begin(0); + + Renderer::enable(Renderer::Feature::RasterizerDiscard); + mesh.draw(shader); + + q.end(); + const UnsignedInt count = q.result(); + + MAGNUM_VERIFY_NO_ERROR(); + CORRADE_COMPARE(count, 3); +} #endif void PrimitiveQueryGLTest::transformFeedbackPrimitivesWritten() {