diff --git a/doc/opengl-mapping.dox b/doc/opengl-mapping.dox index 963caaa5f..cb2563022 100644 --- a/doc/opengl-mapping.dox +++ b/doc/opengl-mapping.dox @@ -124,10 +124,10 @@ OpenGL function | Matching API @fn_gl{DispatchCompute} | @ref AbstractShaderProgram::dispatchCompute() @fn_gl_extension{DispatchComputeGroupSize,ARB,compute_variable_group_size} | | @fn_gl{DispatchComputeIndirect} | | -@fn_gl{DrawArrays}, \n @fn_gl{DrawArraysInstanced}, \n @fn_gl{DrawArraysInstancedBaseInstance}, \n @fn_gl{DrawElements}, \n @fn_gl{DrawRangeElements}, \n @fn_gl{DrawElementsBaseVertex}, \n @fn_gl{DrawRangeElementsBaseVertex}, \n @fn_gl{DrawElementsInstanced}, \n @fn_gl{DrawElementsInstancedBaseInstance}, \n @fn_gl{DrawElementsInstancedBaseVertex}, \n @fn_gl{DrawElementsInstancedBaseVertexBaseInstance} | @ref Mesh::draw(), \n @ref MeshView::draw() +@fn_gl{DrawArrays}, \n @fn_gl{DrawArraysInstanced}, \n @fn_gl{DrawArraysInstancedBaseInstance}, \n @fn_gl{DrawElements}, \n @fn_gl{DrawRangeElements}, \n @fn_gl{DrawElementsBaseVertex}, \n @fn_gl{DrawRangeElementsBaseVertex}, \n @fn_gl{DrawElementsInstanced}, \n @fn_gl{DrawElementsInstancedBaseInstance}, \n @fn_gl{DrawElementsInstancedBaseVertex}, \n @fn_gl{DrawElementsInstancedBaseVertexBaseInstance} | @ref Mesh::draw(AbstractShaderProgram&), \n @ref MeshView::draw(AbstractShaderProgram&) @fn_gl{DrawArraysIndirect}, \n @fn_gl{DrawElementsIndirect}, \n @fn_gl{MultiDrawArraysIndirect}, \n @fn_gl{MultiDrawElementsIndirect} | | @fn_gl{DrawBuffer}, \n `glNamedFramebufferDrawBuffer()`, \n @fn_gl_extension{FramebufferDrawBuffer,EXT,direct_state_access}, \n @fn_gl{DrawBuffers}, \n `glNamedFramebufferDrawBuffers()`, \n @fn_gl_extension{FramebufferDrawBuffers,EXT,direct_state_access} | @ref DefaultFramebuffer::mapForDraw(), \n @ref Framebuffer::mapForDraw() -@fn_gl{DrawTransformFeedback}, \n @fn_gl{DrawTransformFeedbackInstanced}, \n @fn_gl{DrawTransformFeedbackStream}, \n @fn_gl{DrawTransformFeedbackStreamInstanced} | | +@fn_gl{DrawTransformFeedback}, \n @fn_gl{DrawTransformFeedbackInstanced}, \n @fn_gl{DrawTransformFeedbackStream}, \n @fn_gl{DrawTransformFeedbackStreamInstanced} | @ref Mesh::draw(AbstractShaderProgram&, TransformFeedback&, UnsignedInt), \n @ref MeshView::draw(AbstractShaderProgram&, TransformFeedback&, UnsignedInt) @subsection opengl-mapping-functions-e E diff --git a/doc/opengl-support.dox b/doc/opengl-support.dox index 9216190c8..ea6d1f582 100644 --- a/doc/opengl-support.dox +++ b/doc/opengl-support.dox @@ -131,7 +131,7 @@ GLSL 4.00 | done @extension{ARB,shader_subroutine} | | @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_feedback2} | done @extension{ARB,transform_feedback3} | missing indexed properties query @subsection opengl-support-41 OpenGL 4.1 @@ -154,7 +154,7 @@ GLSL 4.20 | done @extension{ARB,texture_compression_bptc} | done @extension{ARB,base_instance} | done @extension{ARB,shading_language_420pack} | done (shading language only) -@extension{ARB,transform_feedback_instanced} | | +@extension{ARB,transform_feedback_instanced} | done @extension{ARB,compressed_texture_pixel_storage} | done @extension{ARB,conservative_depth} | done (shading language only) @extension{ARB,internalformat_query} | | diff --git a/src/Magnum/Mesh.cpp b/src/Magnum/Mesh.cpp index 507d58c5b..bc4da4c0a 100644 --- a/src/Magnum/Mesh.cpp +++ b/src/Magnum/Mesh.cpp @@ -31,6 +31,9 @@ #include "Magnum/Buffer.h" #include "Magnum/Context.h" #include "Magnum/Extensions.h" +#ifndef MAGNUM_TARGET_GLES +#include "Magnum/TransformFeedback.h" +#endif #ifndef MAGNUM_TARGET_WEBGL #include "Implementation/DebugState.h" @@ -363,6 +366,42 @@ void Mesh::drawInternal(Int count, Int baseVertex, Int instanceCount, GLintptr i (this->*state.unbindImplementation)(); } +#ifndef MAGNUM_TARGET_GLES +void Mesh::drawInternal(TransformFeedback& xfb, const UnsignedInt stream, const Int instanceCount) { + const Implementation::MeshState& state = *Context::current().state().mesh; + + (this->*state.bindImplementation)(); + + /* Default stream */ + if(stream == 0) { + /* Non-instanced mesh */ + if(instanceCount == 1) glDrawTransformFeedback(GLenum(_primitive), xfb.id()); + + /* Instanced mesh */ + else glDrawTransformFeedbackInstanced(GLenum(_primitive), xfb.id(), instanceCount); + + /* Specific stream */ + } else { + /* Non-instanced mesh */ + if(instanceCount == 1) glDrawTransformFeedbackStream(GLenum(_primitive), xfb.id(), stream); + + /* Instanced mesh */ + else glDrawTransformFeedbackStreamInstanced(GLenum(_primitive), xfb.id(), stream, instanceCount); + } + + (this->*state.unbindImplementation)(); +} + +void Mesh::draw(AbstractShaderProgram& shader, TransformFeedback& xfb, UnsignedInt stream) { + /* Nothing to draw, exit without touching any state */ + if(!_instanceCount) return; + + shader.use(); + + drawInternal(xfb, stream, _instanceCount); +} +#endif + void Mesh::bindVAO() { GLuint& current = Context::current().state().mesh->currentVAO; if(current != _id) { diff --git a/src/Magnum/Mesh.h b/src/Magnum/Mesh.h index 7239fa1a6..9cf148540 100644 --- a/src/Magnum/Mesh.h +++ b/src/Magnum/Mesh.h @@ -602,7 +602,9 @@ class MAGNUM_EXPORT Mesh: public AbstractObject { * * If the mesh is indexed, the value is treated as index count, * otherwise the value is vertex count. If set to `0`, no draw commands - * are issued when calling @ref draw(). Default is `0`. + * are issued when calling @ref draw(AbstractShaderProgram&). Ignored + * when calling @ref draw(AbstractShaderProgram, TransformFeedback&, UsingnedInt). + * Default is `0`. * @see @ref isIndexed(), @ref setBaseVertex(), @ref setInstanceCount() */ Mesh& setCount(Int count) { @@ -618,7 +620,8 @@ class MAGNUM_EXPORT Mesh: public AbstractObject { * @return Reference to self (for method chaining) * * Sets number of vertices of which the vertex buffer will be offset - * when drawing. Default is `0`. + * when drawing. Ignored when calling + * @ref draw(AbstractShaderProgram, TransformFeedback&) Default is `0`. * @see @ref setCount(), @ref setBaseInstance() * @requires_gl32 Extension @extension{ARB,draw_elements_base_vertex} * for indexed meshes @@ -638,11 +641,15 @@ class MAGNUM_EXPORT Mesh: public AbstractObject { * @return Reference to self (for method chaining) * * If set to `1`, non-instanced draw commands are issued when calling - * @ref draw(). If set to `0`, no draw commands are issued altogether. - * Default is `1`. + * @ref draw(AbstractShaderProgram&) or + * @ref draw(AbstractShaderProgram&, TransformFeedback&). If set to + * `0`, no draw commands are issued altogether. Default is `1`. * @see @ref setBaseInstance(), @ref setCount(), * @ref addVertexBufferInstanced() - * @requires_gl31 Extension @extension{ARB,draw_instanced} + * @requires_gl31 Extension @extension{ARB,draw_instanced} if using + * @ref draw(AbstractShaderProgram&) + * @requires_gl42 Extension @extension{ARB,transform_feedback_instanced} + * @ref draw(AbstractShaderProgram&, TransformFeedback&, UnsignedInt) * @requires_gles30 Extension @es_extension{ANGLE,instanced_arrays}, * @es_extension2{EXT,draw_instanced,draw_instanced} or * @es_extension{NV,draw_instanced} in OpenGL ES 2.0. @@ -662,6 +669,7 @@ class MAGNUM_EXPORT Mesh: public AbstractObject { * @brief Set base instance * @return Reference to self (for method chaining) * + * Ignored when calling @ref draw(AbstractShaderProgram, TransformFeedback&, UnsignedInt). * Default is `0`. * @see @ref setInstanceCount(), @ref setBaseVertex() * @requires_gl42 Extension @extension{ARB,base_instance} @@ -803,6 +811,8 @@ class MAGNUM_EXPORT Mesh: public AbstractObject { * ES 2.0 or @webgl_extension{OES,vertex_array_object} in WebGL 1.0 is * available, the vertex array object is used to hold the parameters. * + * Ignored when calling @ref draw(AbstractShaderProgram&, TransformFeedback&, UnsignedInt). + * * @see @ref maxElementIndex(), @ref maxElementsIndices(), * @ref maxElementsVertices(), @ref setCount(), @ref isIndexed(), * @fn_gl{BindVertexArray}, @fn_gl{BindBuffer} @@ -868,6 +878,43 @@ class MAGNUM_EXPORT Mesh: public AbstractObject { void draw(AbstractShaderProgram& shader); void draw(AbstractShaderProgram&& shader) { draw(shader); } /**< @overload */ + #ifndef MAGNUM_TARGET_GLES + /** + * @brief Draw the mesh with vertices coming out of transform feedback + * @param shader Shader to use for drawing + * @param xfb Transform feedback to use for vertex count + * @param stream Transform feedback stream ID + * + * Expects that the @p shader is compatible with this mesh, is fully + * set up and that the output buffer(s) from @p xfb are used as vertex + * buffers in this mesh. Everything set by @ref setCount(), + * @ref setBaseInstance(), @ref setBaseVertex() and @ref setIndexBuffer() + * is ignored, the mesh is drawn as non-indexed and the vertex count is + * taken from the @p xfb object. If @p stream is `0`, non-stream draw + * command is used. If @extension{ARB,vertex_array_object} (part of + * OpenGL 3.0) is available, the associated vertex array object is + * bound instead of setting up the mesh from scratch. + * @see @ref setInstanceCount(), + * @ref MeshView::draw(AbstractShaderProgram, TransformFeedback& xfb, UnsignedInt), + * @fn_gl{UseProgram}, @fn_gl{EnableVertexAttribArray}, + * @fn_gl{BindBuffer}, @fn_gl{VertexAttribPointer}, + * @fn_gl{DisableVertexAttribArray} or @fn_gl{BindVertexArray}, + * @fn_gl{DrawTransformFeedback}/@fn_gl{DrawTransformFeedbackInstanced} or + * @fn_gl{DrawTransformFeedbackStream}/@fn_gl{DrawTransformFeedbackStreamInstanced} + * @requires_gl40 Extension @extension{ARB,transform_feedback2} + * @requires_gl40 Extension @extension{ARB,transform_feedback3} if + * @p stream is not `0` + * @requires_gl42 Extension @extension{ARB,transform_feedback_instanced} + * if @ref instanceCount() is more than `1`. + */ + void draw(AbstractShaderProgram& shader, TransformFeedback& xfb, UnsignedInt stream = 0); + + /** @overload */ + void draw(AbstractShaderProgram&& shader, TransformFeedback& xfb, UnsignedInt stream = 0) { + draw(shader, xfb, stream); + } + #endif + private: enum class AttributeKind { Generic, @@ -961,6 +1008,10 @@ class MAGNUM_EXPORT Mesh: public AbstractObject { void drawInternal(Int count, Int baseVertex, Int instanceCount, GLintptr indexOffset); #endif + #ifndef MAGNUM_TARGET_GLES + void drawInternal(TransformFeedback& xfb, UnsignedInt stream, Int instanceCount); + #endif + void MAGNUM_LOCAL createImplementationDefault(); void MAGNUM_LOCAL createImplementationVAO(); #ifndef MAGNUM_TARGET_GLES diff --git a/src/Magnum/MeshView.cpp b/src/Magnum/MeshView.cpp index 1bc587204..9d84adefa 100644 --- a/src/Magnum/MeshView.cpp +++ b/src/Magnum/MeshView.cpp @@ -164,4 +164,15 @@ void MeshView::draw(AbstractShaderProgram& shader) { #endif } +#ifndef MAGNUM_TARGET_GLES +void MeshView::draw(AbstractShaderProgram& shader, TransformFeedback& xfb, UnsignedInt stream) { + /* Nothing to draw, exit without touching any state */ + if(!_instanceCount) return; + + shader.use(); + + _original.get().drawInternal(xfb, stream, _instanceCount); +} +#endif + } diff --git a/src/Magnum/MeshView.h b/src/Magnum/MeshView.h index 011dca7be..2f7c4e6b5 100644 --- a/src/Magnum/MeshView.h +++ b/src/Magnum/MeshView.h @@ -79,6 +79,10 @@ class MAGNUM_EXPORT MeshView { * @fn_gl{VertexAttribPointer}, @fn_gl{DisableVertexAttribArray} * or @fn_gl{BindVertexArray}, @fn_gl{MultiDrawArrays} or * @fn_gl{MultiDrawElements}/@fn_gl{MultiDrawElementsBaseVertex} + * @requires_gl32 Extension @extension{ARB,draw_elements_base_vertex} + * if the mesh is indexed and @ref baseVertex() is not `0`. + * @requires_gl Specifying base vertex for indexed meshes is not + * available in OpenGL ES or WebGL. */ static void draw(AbstractShaderProgram& shader, std::initializer_list> meshes); @@ -112,6 +116,7 @@ class MAGNUM_EXPORT MeshView { * @brief Set vertex/index count * @return Reference to self (for method chaining) * + * Ignored when calling @ref draw(AbstractShaderProgram, TransformFeedback&, UnsignedInt). * Default is `0`. */ MeshView& setCount(Int count) { @@ -127,7 +132,8 @@ class MAGNUM_EXPORT MeshView { * @return Reference to self (for method chaining) * * Sets number of vertices of which the vertex buffer will be offset - * when drawing. Default is `0`. + * when drawing. Ignored when calling @ref draw(AbstractShaderProgram, TransformFeedback&, UnsignedInt). + * Default is `0`. * @requires_gl32 Extension @extension{ARB,draw_elements_base_vertex} * for indexed meshes * @requires_gl Base vertex cannot be specified for indexed meshes in @@ -149,7 +155,8 @@ class MAGNUM_EXPORT MeshView { * performance, as only a portion of vertex buffer needs to be * acccessed. On OpenGL ES 2.0 this function behaves the same as * @ref setIndexRange(Int), as index range functionality is not - * available there. + * available there. Ignored when calling + * @ref draw(AbstractShaderProgram, TransformFeedback&, UnsignedInt). * @see @ref setCount() */ /* MinGW/MSVC needs inline also here to avoid linkage conflicts */ @@ -161,7 +168,8 @@ class MAGNUM_EXPORT MeshView { * @return Reference to self (for method chaining) * * Prefer to use @ref setIndexRange(Int, UnsignedInt, UnsignedInt) for - * better performance. + * better performance. Ignored when calling + * @ref draw(AbstractShaderProgram, TransformFeedback&, UnsignedInt). * @see @ref setCount() */ MeshView& setIndexRange(Int first); @@ -194,6 +202,7 @@ class MAGNUM_EXPORT MeshView { * @brief Set base instance * @return Reference to self (for method chaining) * + * Ignored when calling @ref draw(AbstractShaderProgram, TransformFeedback&, UnsignedInt). * Default is `0`. * @requires_gl42 Extension @extension{ARB,base_instance} * @requires_gl Base instance cannot be specified in OpenGL ES or @@ -208,7 +217,7 @@ class MAGNUM_EXPORT MeshView { /** * @brief Draw the mesh * - * See @ref Mesh::draw() for more information. + * See @ref Mesh::draw(AbstractShaderProgram&) for more information. * @see @ref draw(AbstractShaderProgram&, std::initializer_list>) * @requires_gl32 Extension @extension{ARB,draw_elements_base_vertex} * if the mesh is indexed and @ref baseVertex() is not `0`. @@ -228,6 +237,30 @@ class MAGNUM_EXPORT MeshView { void draw(AbstractShaderProgram& shader); void draw(AbstractShaderProgram&& shader) { draw(shader); } /**< @overload */ + #ifndef MAGNUM_TARGET_GLES + /** + * @brief Draw the mesh with vertices coming out of transform feedback + * + * Everything set by @ref setCount(), @ref setBaseInstance(), + * @ref setBaseVertex(), @ref setIndexRange() and @ref Mesh::setIndexBuffer() + * is ignored, the mesh is drawn as non-indexed and the vertex count is + * taken from the @p xfb object. See + * @ref Mesh::draw(AbstractShaderProgram&, TransformFeedback&, UnsignedInt) + * for more information. + * @requires_gl40 Extension @extension{ARB,transform_feedback2} + * @requires_gl40 Extension @extension{ARB,transform_feedback3} if + * @p stream is not `0` + * @requires_gl42 Extension @extension{ARB,transform_feedback_instanced} + * if @ref instanceCount() is more than `1`. + */ + void draw(AbstractShaderProgram& shader, TransformFeedback& xfb, UnsignedInt stream = 0); + + /** @overload */ + void draw(AbstractShaderProgram&& shader, TransformFeedback& xfb, UnsignedInt stream = 0) { + draw(shader, xfb, stream); + } + #endif + private: #ifndef MAGNUM_TARGET_WEBGL static MAGNUM_LOCAL void multiDrawImplementationDefault(std::initializer_list> meshes); diff --git a/src/Magnum/Test/TransformFeedbackGLTest.cpp b/src/Magnum/Test/TransformFeedbackGLTest.cpp index 396ef680e..f122c4c57 100644 --- a/src/Magnum/Test/TransformFeedbackGLTest.cpp +++ b/src/Magnum/Test/TransformFeedbackGLTest.cpp @@ -26,7 +26,11 @@ #include "Magnum/AbstractShaderProgram.h" #include "Magnum/Buffer.h" #include "Magnum/Framebuffer.h" +#include "Magnum/Image.h" #include "Magnum/Mesh.h" +#include "Magnum/PixelFormat.h" +#include "Magnum/PrimitiveQuery.h" +#include "Magnum/SampleQuery.h" #include "Magnum/Renderbuffer.h" #include "Magnum/RenderbufferFormat.h" #include "Magnum/Shader.h" @@ -54,9 +58,31 @@ struct TransformFeedbackGLTest: AbstractOpenGLTester { #ifndef MAGNUM_TARGET_GLES void interleaved(); + + void draw(); #endif }; +namespace { + +enum: std::size_t { DrawDataCount = 4 }; + +const struct { + const char* name; + UnsignedInt stream; + Int instances; + UnsignedInt countStream0; + UnsignedInt countStreamN; + UnsignedInt countDraw; +} DrawData[DrawDataCount] = { + {"basic", 0, 1, 6, 6, 6}, + {"instanced", 0, 5, 6, 6, 30}, + {"stream", 1, 1, 0, 6, 6}, + {"streamInstanced", 1, 5, 0, 6, 30} +}; + +} + TransformFeedbackGLTest::TransformFeedbackGLTest() { addTests({&TransformFeedbackGLTest::construct, &TransformFeedbackGLTest::constructNoCreate, @@ -72,9 +98,13 @@ TransformFeedbackGLTest::TransformFeedbackGLTest() { &TransformFeedbackGLTest::attachRanges, #ifndef MAGNUM_TARGET_GLES - &TransformFeedbackGLTest::interleaved + &TransformFeedbackGLTest::interleaved, #endif }); + + #ifndef MAGNUM_TARGET_GLES + addInstancedTests({&TransformFeedbackGLTest::draw}, DrawDataCount); + #endif } void TransformFeedbackGLTest::construct() { @@ -530,6 +560,140 @@ void TransformFeedbackGLTest::interleaved() { CORRADE_COMPARE(data[3].y(), 3.0f); output.unmap(); } + +void TransformFeedbackGLTest::draw() { + /* ARB_transform_feedback2 needed as base, other optional */ + if(!Context::current().isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::transform_feedback2::string() + std::string(" is not supported.")); + if(DrawData[testCaseInstanceId()].stream && !Context::current().isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::transform_feedback3::string() + std::string(" is not supported.")); + if(DrawData[testCaseInstanceId()].instances && !Context::current().isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::transform_feedback_instanced::string() + std::string(" is not supported.")); + + setTestCaseDescription(DrawData[testCaseInstanceId()].name); + + /* Bind some FB to avoid errors on contexts w/o default FB */ + Renderbuffer color; + color.setStorage(RenderbufferFormat::RGBA8, Vector2i{1}); + Framebuffer fb{{{}, Vector2i{1}}}; + fb.attachRenderbuffer(Framebuffer::ColorAttachment{0}, color) + .bind(); + + struct XfbShader: AbstractShaderProgram { + explicit XfbShader(UnsignedInt stream) { + Shader vert{stream ? Version::GL400 : Version::GL320, Shader::Type::Vertex}, + geom{stream ? Version::GL400 : Version::GL320, Shader::Type::Geometry}; + vert.addSource( + "out mediump vec2 vertexOutput;\n" + "void main() {\n" + " vertexOutput = vec2(0.3);\n" + " gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n" + "}\n"); + if(stream) geom.addSource( + "#define STREAM " + std::to_string(stream) + "\n" + + "layout(stream = 0) out mediump float otherOutput;\n" + + "layout(stream = STREAM) out mediump vec2 geomOutput;\n"); + else geom.addSource( + "out mediump vec2 geomOutput;\n"); + geom.addSource( + "layout(points) in;\n" + "layout(points, max_vertices = 1) out;\n" + "in mediump vec2 vertexOutput[];\n" + "void main() {\n" + " geomOutput = vertexOutput[0] - vec2(0.1);\n"); + if(stream) geom.addSource( + " EmitStreamVertex(STREAM);\n"); + else geom.addSource( + " EmitVertex();\n"); + geom.addSource("}\n"); + CORRADE_INTERNAL_ASSERT_OUTPUT(Shader::compile({vert, geom})); + attachShaders({vert, geom}); + setTransformFeedbackOutputs({"geomOutput"}, TransformFeedbackBufferMode::SeparateAttributes); + CORRADE_INTERNAL_ASSERT_OUTPUT(link()); + } + } xfbShader{DrawData[testCaseInstanceId()].stream}; + + Buffer outputBuffer; + outputBuffer.setData({nullptr, 32*sizeof(Vector2)}, BufferUsage::StaticDraw); + + Mesh inputMesh; + inputMesh.setPrimitive(MeshPrimitive::Points) + .setCount(6); + + TransformFeedback feedback; + feedback.attachBuffer(0, outputBuffer); + + MAGNUM_VERIFY_NO_ERROR(); + + PrimitiveQuery queryStream0{PrimitiveQuery::Target::TransformFeedbackPrimitivesWritten}, + queryStreamN{PrimitiveQuery::Target::TransformFeedbackPrimitivesWritten}; + + queryStream0.begin(); + if(DrawData[testCaseInstanceId()].stream) + queryStreamN.begin(DrawData[testCaseInstanceId()].stream); + + Renderer::enable(Renderer::Feature::RasterizerDiscard); + feedback.begin(xfbShader, TransformFeedback::PrimitiveMode::Points); + inputMesh.draw(xfbShader); + feedback.end(); + Renderer::disable(Renderer::Feature::RasterizerDiscard); + + if(DrawData[testCaseInstanceId()].stream) + queryStreamN.end(); + queryStream0.end(); + + MAGNUM_VERIFY_NO_ERROR(); + + CORRADE_COMPARE(queryStream0.result(), DrawData[testCaseInstanceId()].countStream0); + if(DrawData[testCaseInstanceId()].stream) + CORRADE_COMPARE(queryStreamN.result(), DrawData[testCaseInstanceId()].countStreamN); + + struct DrawShader: AbstractShaderProgram { + typedef Attribute<0, Vector2> Input; + + explicit DrawShader() { + Shader vert{Version::GL320, Shader::Type::Vertex}, + frag{Version::GL320, Shader::Type::Fragment}; + vert.addSource( + "in mediump vec2 inputData;\n" + "out mediump vec2 interleaved;\n" + "void main() {\n" + " interleaved = inputData;\n" + " gl_Position = vec4(1.0);\n" + "}\n"); + frag.addSource( + "in mediump vec2 interleaved;\n" + "out mediump float outputData;\n" + "void main() {\n" + " outputData = interleaved.x + 2*interleaved.y;\n" + "}\n"); + + CORRADE_INTERNAL_ASSERT_OUTPUT(Shader::compile({vert, frag})); + attachShaders({vert, frag}); + bindAttributeLocation(Input::Location, "inputData"); + CORRADE_INTERNAL_ASSERT_OUTPUT(link()); + } + } drawShader; + + Renderer::setPointSize(2.0f); + + Mesh outputMesh; + outputMesh.setPrimitive(MeshPrimitive::Points) + .setInstanceCount(DrawData[testCaseInstanceId()].instances) + .addVertexBuffer(outputBuffer, 0, DrawShader::Input{}); + + PrimitiveQuery q{PrimitiveQuery::Target::PrimitivesGenerated}; + q.begin(); + outputMesh.draw(drawShader, feedback, DrawData[testCaseInstanceId()].stream); + q.end(); + + MAGNUM_VERIFY_NO_ERROR(); + + CORRADE_COMPARE(q.result(), DrawData[testCaseInstanceId()].countDraw); + CORRADE_COMPARE(fb.read({{}, Vector2i{1}}, {PixelFormat::RGBA, PixelType::UnsignedByte}).data()[0], 153); + + MAGNUM_VERIFY_NO_ERROR(); +} #endif }}