void TransformFeedbackGLTest::attachRange() { XfbShader shader; Buffer input; input.setData(inputData, BufferUsage::StaticDraw); Buffer output; output.setData({nullptr, 512 + 2*sizeof(Vector2)}, BufferUsage::StaticRead); Mesh mesh; mesh.setPrimitive(MeshPrimitive::Points) .addVertexBuffer(input, 0, XfbShader::Input{}) .setCount(2); TransformFeedback feedback; feedback.attachBuffer(0, output, 256, 2*sizeof(Vector2)); MAGNUM_VERIFY_NO_ERROR(); Renderer::enable(Renderer::Feature::RasterizerDiscard); feedback.begin(shader, TransformFeedback::PrimitiveMode::Points); mesh.draw(shader); feedback.end(); MAGNUM_VERIFY_NO_ERROR(); Vector2* data = reinterpret_cast<Vector2*>(output.map(256, 2*sizeof(Vector2), Buffer::MapFlag::Read)); CORRADE_COMPARE(data[0], Vector2(1.0f, -1.0f)); CORRADE_COMPARE(data[1], Vector2(0.0f, 0.0f)); output.unmap(); }
GLuint Context::createTransformFeedback() { GLuint handle = mTransformFeedbackAllocator.allocate(); TransformFeedback *transformFeedback = new TransformFeedback(mRenderer->createTransformFeedback(), handle, mCaps); transformFeedback->addRef(); mTransformFeedbackMap[handle] = transformFeedback; return handle; }
void TransformFeedbackGLTest::construct() { { TransformFeedback feedback; MAGNUM_VERIFY_NO_ERROR(); CORRADE_VERIFY(feedback.id() > 0); } MAGNUM_VERIFY_NO_ERROR(); }
void TransformFeedbackGLTest::label() { /* No-Op version is tested in AbstractObjectGLTest */ if(!Context::current()->isExtensionSupported<Extensions::GL::KHR::debug>() && !Context::current()->isExtensionSupported<Extensions::GL::EXT::debug_label>()) CORRADE_SKIP("Required extension is not available"); TransformFeedback feedback; CORRADE_COMPARE(feedback.label(), ""); MAGNUM_VERIFY_NO_ERROR(); feedback.setLabel("MyXfb"); MAGNUM_VERIFY_NO_ERROR(); CORRADE_COMPARE(feedback.label(), "MyXfb"); }
void TransformFeedbackGLTest::attachRanges() { Buffer input; input.setData(inputData, BufferUsage::StaticDraw); Buffer output1, output2; output1.setData({nullptr, 512 + 2*sizeof(Vector2)}, BufferUsage::StaticRead); output2.setData({nullptr, 768 + 2*sizeof(Float)}, BufferUsage::StaticRead); XfbMultiShader shader; Mesh mesh; mesh.setPrimitive(MeshPrimitive::Points) .addVertexBuffer(input, 0, XfbMultiShader::Input{}) .setCount(2); TransformFeedback feedback; feedback.attachBuffers(0, { std::make_tuple(&output1, 256, 2*sizeof(Vector2)), std::make_tuple(&output2, 512, 2*sizeof(Float)) }); MAGNUM_VERIFY_NO_ERROR(); Renderer::enable(Renderer::Feature::RasterizerDiscard); feedback.begin(shader, TransformFeedback::PrimitiveMode::Points); mesh.draw(shader); feedback.end(); MAGNUM_VERIFY_NO_ERROR(); Vector2* data1 = reinterpret_cast<Vector2*>(output1.map(256, 2*sizeof(Vector2), Buffer::MapFlag::Read)); CORRADE_COMPARE(data1[0], Vector2(1.0f, -1.0f)); CORRADE_COMPARE(data1[1], Vector2(0.0f, 0.0f)); output1.unmap(); Float* data2 = reinterpret_cast<Float*>(output2.map(512, 2*sizeof(Float), Buffer::MapFlag::Read)); CORRADE_COMPARE(data2[0], 0.0f); CORRADE_COMPARE(data2[1], -2.0f); output2.unmap(); }
void TransformFeedbackGLTest::constructMove() { TransformFeedback a; const Int id = a.id(); MAGNUM_VERIFY_NO_ERROR(); CORRADE_VERIFY(id > 0); TransformFeedback b{std::move(a)}; CORRADE_COMPARE(a.id(), 0); CORRADE_COMPARE(b.id(), id); TransformFeedback c; const Int cId = c.id(); c = std::move(b); MAGNUM_VERIFY_NO_ERROR(); CORRADE_VERIFY(cId > 0); CORRADE_COMPARE(b.id(), cId); CORRADE_COMPARE(c.id(), id); }
namespace Magnum { namespace Test { struct PrimitiveQueryGLTest: AbstractOpenGLTester { explicit PrimitiveQueryGLTest(); void wrap(); #ifndef MAGNUM_TARGET_GLES void primitivesGenerated(); #endif void transformFeedbackPrimitivesWritten(); }; PrimitiveQueryGLTest::PrimitiveQueryGLTest() { addTests({&PrimitiveQueryGLTest::wrap, #ifndef MAGNUM_TARGET_GLES &PrimitiveQueryGLTest::primitivesGenerated, #endif &PrimitiveQueryGLTest::transformFeedbackPrimitivesWritten}); } void PrimitiveQueryGLTest::wrap() { #ifndef MAGNUM_TARGET_GLES if(!Context::current()->isExtensionSupported<Extensions::GL::ARB::transform_feedback2>()) CORRADE_SKIP(Extensions::GL::ARB::transform_feedback2::string() + std::string(" is not available.")); #endif GLuint id; glGenQueries(1, &id); /* Releasing won't delete anything */ { auto query = PrimitiveQuery::wrap(id, PrimitiveQuery::Target::TransformFeedbackPrimitivesWritten, ObjectFlag::DeleteOnDestruction); CORRADE_COMPARE(query.release(), id); } /* ...so we can wrap it again */ PrimitiveQuery::wrap(id, PrimitiveQuery::Target::TransformFeedbackPrimitivesWritten); glDeleteQueries(1, &id); } #ifndef MAGNUM_TARGET_GLES void PrimitiveQueryGLTest::primitivesGenerated() { if(!Context::current()->isExtensionSupported<Extensions::GL::EXT::transform_feedback>()) CORRADE_SKIP(Extensions::GL::EXT::transform_feedback::string() + std::string(" is not available.")); struct MyShader: AbstractShaderProgram { typedef Attribute<0, Vector2> Position; explicit MyShader() { Shader vert(Version::GL210, Shader::Type::Vertex); CORRADE_INTERNAL_ASSERT_OUTPUT(vert.addSource( "attribute lowp 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(); Renderer::enable(Renderer::Feature::RasterizerDiscard); mesh.draw(shader); q.end(); const bool availableBefore = q.resultAvailable(); const UnsignedInt count = q.result<UnsignedInt>(); const bool availableAfter = q.resultAvailable(); MAGNUM_VERIFY_NO_ERROR(); CORRADE_VERIFY(!availableBefore); CORRADE_VERIFY(availableAfter); CORRADE_COMPARE(count, 3); } #endif void PrimitiveQueryGLTest::transformFeedbackPrimitivesWritten() { #ifndef MAGNUM_TARGET_GLES if(!Context::current()->isExtensionSupported<Extensions::GL::ARB::transform_feedback2>()) CORRADE_SKIP(Extensions::GL::ARB::transform_feedback2::string() + std::string(" is not available.")); #endif struct MyShader: AbstractShaderProgram { explicit MyShader() { #ifndef MAGNUM_TARGET_GLES Shader vert(Version::GL300, Shader::Type::Vertex); #else Shader vert(Version::GLES300, Shader::Type::Vertex); Shader frag(Version::GLES300, Shader::Type::Fragment); #endif CORRADE_INTERNAL_ASSERT_OUTPUT(vert.addSource( "out mediump vec2 outputData;\n" "void main() {\n" " outputData = vec2(1.0, -1.0);\n" "}\n").compile()); #ifndef MAGNUM_TARGET_GLES attachShader(vert); #else /* ES for some reason needs both vertex and fragment shader */ CORRADE_INTERNAL_ASSERT_OUTPUT(frag.addSource("void main() {}\n").compile()); attachShaders({vert, frag}); #endif setTransformFeedbackOutputs({"outputData"}, TransformFeedbackBufferMode::SeparateAttributes); CORRADE_INTERNAL_ASSERT_OUTPUT(link()); } } shader; Buffer output; output.setData({nullptr, 18*sizeof(Vector2)}, BufferUsage::StaticDraw); Mesh mesh; mesh.setPrimitive(MeshPrimitive::Triangles) .setCount(9); MAGNUM_VERIFY_NO_ERROR(); TransformFeedback feedback; feedback.attachBuffer(0, output); PrimitiveQuery q{PrimitiveQuery::Target::TransformFeedbackPrimitivesWritten}; q.begin(); Renderer::enable(Renderer::Feature::RasterizerDiscard); mesh.draw(shader); /* Draw once without XFB (shouldn't be counted) */ feedback.begin(shader, TransformFeedback::PrimitiveMode::Triangles); mesh.draw(shader); feedback.end(); q.end(); const UnsignedInt count = q.result<UnsignedInt>(); MAGNUM_VERIFY_NO_ERROR(); CORRADE_COMPARE(count, 3); /* Three triangles (9 vertices) */ } }}
namespace Magnum { namespace Test { struct TransformFeedbackGLTest: AbstractOpenGLTester { explicit TransformFeedbackGLTest(); void construct(); void constructCopy(); void constructMove(); void label(); void attachBase(); void attachRange(); void attachBases(); void attachRanges(); void interleaved(); }; TransformFeedbackGLTest::TransformFeedbackGLTest() { addTests({&TransformFeedbackGLTest::construct, &TransformFeedbackGLTest::constructCopy, &TransformFeedbackGLTest::constructMove, &TransformFeedbackGLTest::label, &TransformFeedbackGLTest::attachBase, &TransformFeedbackGLTest::attachRange, &TransformFeedbackGLTest::attachBases, &TransformFeedbackGLTest::attachRanges, &TransformFeedbackGLTest::interleaved}); } void TransformFeedbackGLTest::construct() { { TransformFeedback feedback; MAGNUM_VERIFY_NO_ERROR(); CORRADE_VERIFY(feedback.id() > 0); } MAGNUM_VERIFY_NO_ERROR(); } void TransformFeedbackGLTest::constructCopy() { CORRADE_VERIFY(!(std::is_constructible<TransformFeedback, const TransformFeedback&>{})); CORRADE_VERIFY(!(std::is_assignable<TransformFeedback, const TransformFeedback&>{})); } void TransformFeedbackGLTest::constructMove() { TransformFeedback a; const Int id = a.id(); MAGNUM_VERIFY_NO_ERROR(); CORRADE_VERIFY(id > 0); TransformFeedback b{std::move(a)}; CORRADE_COMPARE(a.id(), 0); CORRADE_COMPARE(b.id(), id); TransformFeedback c; const Int cId = c.id(); c = std::move(b); MAGNUM_VERIFY_NO_ERROR(); CORRADE_VERIFY(cId > 0); CORRADE_COMPARE(b.id(), cId); CORRADE_COMPARE(c.id(), id); } void TransformFeedbackGLTest::label() { /* No-Op version is tested in AbstractObjectGLTest */ if(!Context::current()->isExtensionSupported<Extensions::GL::KHR::debug>() && !Context::current()->isExtensionSupported<Extensions::GL::EXT::debug_label>()) CORRADE_SKIP("Required extension is not available"); TransformFeedback feedback; CORRADE_COMPARE(feedback.label(), ""); MAGNUM_VERIFY_NO_ERROR(); feedback.setLabel("MyXfb"); MAGNUM_VERIFY_NO_ERROR(); CORRADE_COMPARE(feedback.label(), "MyXfb"); } namespace { constexpr const Vector2 inputData[] = { {0.0f, 0.0f}, {-1.0f, 1.0f} }; struct XfbShader: AbstractShaderProgram { typedef Attribute<0, Vector2> Input; explicit XfbShader(); }; XfbShader::XfbShader() { #ifndef MAGNUM_TARGET_GLES Shader vert(Version::GL300, Shader::Type::Vertex); #else Shader vert(Version::GLES300, Shader::Type::Vertex); Shader frag(Version::GLES300, Shader::Type::Fragment); #endif CORRADE_INTERNAL_ASSERT_OUTPUT(vert.addSource( "in mediump vec2 inputData;\n" "out mediump vec2 outputData;\n" "void main() {\n" " outputData = inputData + vec2(1.0, -1.0);\n" "}\n").compile()); #ifndef MAGNUM_TARGET_GLES attachShader(vert); #else /* ES for some reason needs both vertex and fragment shader */ CORRADE_INTERNAL_ASSERT_OUTPUT(frag.addSource("void main() {}\n").compile()); attachShaders({vert, frag}); #endif bindAttributeLocation(Input::Location, "inputData"); setTransformFeedbackOutputs({"outputData"}, TransformFeedbackBufferMode::SeparateAttributes); CORRADE_INTERNAL_ASSERT_OUTPUT(link()); } } void TransformFeedbackGLTest::attachBase() { XfbShader shader; Buffer input; input.setData(inputData, BufferUsage::StaticDraw); Buffer output; output.setData({nullptr, 2*sizeof(Vector2)}, BufferUsage::StaticRead); Mesh mesh; mesh.setPrimitive(MeshPrimitive::Points) .addVertexBuffer(input, 0, XfbShader::Input{}) .setCount(2); TransformFeedback feedback; feedback.attachBuffer(0, output); MAGNUM_VERIFY_NO_ERROR(); Renderer::enable(Renderer::Feature::RasterizerDiscard); feedback.begin(shader, TransformFeedback::PrimitiveMode::Points); mesh.draw(shader); feedback.end(); MAGNUM_VERIFY_NO_ERROR(); Vector2* data = reinterpret_cast<Vector2*>(output.map(0, 2*sizeof(Vector2), Buffer::MapFlag::Read)); CORRADE_COMPARE(data[0], Vector2(1.0f, -1.0f)); CORRADE_COMPARE(data[1], Vector2(0.0f, 0.0f)); output.unmap(); } void TransformFeedbackGLTest::attachRange() { XfbShader shader; Buffer input; input.setData(inputData, BufferUsage::StaticDraw); Buffer output; output.setData({nullptr, 512 + 2*sizeof(Vector2)}, BufferUsage::StaticRead); Mesh mesh; mesh.setPrimitive(MeshPrimitive::Points) .addVertexBuffer(input, 0, XfbShader::Input{}) .setCount(2); TransformFeedback feedback; feedback.attachBuffer(0, output, 256, 2*sizeof(Vector2)); MAGNUM_VERIFY_NO_ERROR(); Renderer::enable(Renderer::Feature::RasterizerDiscard); feedback.begin(shader, TransformFeedback::PrimitiveMode::Points); mesh.draw(shader); feedback.end(); MAGNUM_VERIFY_NO_ERROR(); Vector2* data = reinterpret_cast<Vector2*>(output.map(256, 2*sizeof(Vector2), Buffer::MapFlag::Read)); CORRADE_COMPARE(data[0], Vector2(1.0f, -1.0f)); CORRADE_COMPARE(data[1], Vector2(0.0f, 0.0f)); output.unmap(); } namespace { struct XfbMultiShader: AbstractShaderProgram { typedef Attribute<0, Vector2> Input; explicit XfbMultiShader(); }; XfbMultiShader::XfbMultiShader() { #ifndef MAGNUM_TARGET_GLES Shader vert(Version::GL300, Shader::Type::Vertex); #else Shader vert(Version::GLES300, Shader::Type::Vertex); Shader frag(Version::GLES300, Shader::Type::Fragment); #endif CORRADE_INTERNAL_ASSERT_OUTPUT(vert.addSource( "in mediump vec2 inputData;\n" "out mediump vec2 output1;\n" "out mediump float output2;\n" "void main() {\n" " output1 = inputData + vec2(1.0, -1.0);\n" " output2 = inputData.x - inputData.y;\n" "}\n").compile()); #ifndef MAGNUM_TARGET_GLES attachShader(vert); #else /* ES for some reason needs both vertex and fragment shader */ CORRADE_INTERNAL_ASSERT_OUTPUT(frag.addSource("void main() {}\n").compile()); attachShaders({vert, frag}); #endif bindAttributeLocation(Input::Location, "inputData"); setTransformFeedbackOutputs({"output1", "output2"}, TransformFeedbackBufferMode::SeparateAttributes); CORRADE_INTERNAL_ASSERT_OUTPUT(link()); } } void TransformFeedbackGLTest::attachBases() { XfbMultiShader shader; Buffer input; input.setData(inputData, BufferUsage::StaticDraw); Buffer output1, output2; output1.setData({nullptr, 2*sizeof(Vector2)}, BufferUsage::StaticRead); output2.setData({nullptr, 2*sizeof(Float)}, BufferUsage::StaticRead); Mesh mesh; mesh.setPrimitive(MeshPrimitive::Points) .addVertexBuffer(input, 0, XfbMultiShader::Input{}) .setCount(2); TransformFeedback feedback; feedback.attachBuffers(0, {&output1, &output2}); MAGNUM_VERIFY_NO_ERROR(); Renderer::enable(Renderer::Feature::RasterizerDiscard); feedback.begin(shader, TransformFeedback::PrimitiveMode::Points); mesh.draw(shader); feedback.end(); MAGNUM_VERIFY_NO_ERROR(); Vector2* data1 = reinterpret_cast<Vector2*>(output1.map(0, 2*sizeof(Vector2), Buffer::MapFlag::Read)); CORRADE_COMPARE(data1[0], Vector2(1.0f, -1.0f)); CORRADE_COMPARE(data1[1], Vector2(0.0f, 0.0f)); output1.unmap(); Float* data2 = reinterpret_cast<Float*>(output2.map(0, 2*sizeof(Float), Buffer::MapFlag::Read)); CORRADE_COMPARE(data2[0], 0.0f); CORRADE_COMPARE(data2[1], -2.0f); output2.unmap(); } void TransformFeedbackGLTest::attachRanges() { Buffer input; input.setData(inputData, BufferUsage::StaticDraw); Buffer output1, output2; output1.setData({nullptr, 512 + 2*sizeof(Vector2)}, BufferUsage::StaticRead); output2.setData({nullptr, 768 + 2*sizeof(Float)}, BufferUsage::StaticRead); XfbMultiShader shader; Mesh mesh; mesh.setPrimitive(MeshPrimitive::Points) .addVertexBuffer(input, 0, XfbMultiShader::Input{}) .setCount(2); TransformFeedback feedback; feedback.attachBuffers(0, { std::make_tuple(&output1, 256, 2*sizeof(Vector2)), std::make_tuple(&output2, 512, 2*sizeof(Float)) }); MAGNUM_VERIFY_NO_ERROR(); Renderer::enable(Renderer::Feature::RasterizerDiscard); feedback.begin(shader, TransformFeedback::PrimitiveMode::Points); mesh.draw(shader); feedback.end(); MAGNUM_VERIFY_NO_ERROR(); Vector2* data1 = reinterpret_cast<Vector2*>(output1.map(256, 2*sizeof(Vector2), Buffer::MapFlag::Read)); CORRADE_COMPARE(data1[0], Vector2(1.0f, -1.0f)); CORRADE_COMPARE(data1[1], Vector2(0.0f, 0.0f)); output1.unmap(); Float* data2 = reinterpret_cast<Float*>(output2.map(512, 2*sizeof(Float), Buffer::MapFlag::Read)); CORRADE_COMPARE(data2[0], 0.0f); CORRADE_COMPARE(data2[1], -2.0f); output2.unmap(); } void TransformFeedbackGLTest::interleaved() { struct XfbInterleavedShader: AbstractShaderProgram { typedef Attribute<0, Vector2> Input; explicit XfbInterleavedShader() { #ifndef MAGNUM_TARGET_GLES Shader vert(Version::GL300, Shader::Type::Vertex); #else Shader vert(Version::GLES300, Shader::Type::Vertex); Shader frag(Version::GLES300, Shader::Type::Fragment); #endif CORRADE_INTERNAL_ASSERT_OUTPUT(vert.addSource( "in mediump vec2 inputData;\n" "out mediump vec2 output1;\n" "out mediump float output2;\n" "void main() {\n" " output1 = inputData + vec2(1.0, -1.0);\n" " output2 = inputData.x - inputData.y + 5.0;\n" "}\n").compile()); #ifndef MAGNUM_TARGET_GLES attachShader(vert); #else /* ES for some reason needs both vertex and fragment shader */ CORRADE_INTERNAL_ASSERT_OUTPUT(frag.addSource("void main() {}\n").compile()); attachShaders({vert, frag}); #endif bindAttributeLocation(Input::Location, "inputData"); setTransformFeedbackOutputs({"output1", "gl_SkipComponents1", "output2"}, TransformFeedbackBufferMode::InterleavedAttributes); CORRADE_INTERNAL_ASSERT_OUTPUT(link()); } } shader; Buffer input; input.setData(inputData, BufferUsage::StaticDraw); Buffer output; output.setData({nullptr, 4*sizeof(Vector2)}, BufferUsage::StaticRead); Mesh mesh; mesh.setPrimitive(MeshPrimitive::Points) .addVertexBuffer(input, 0, XfbInterleavedShader::Input{}) .setCount(2); TransformFeedback feedback; feedback.attachBuffer(0, output); MAGNUM_VERIFY_NO_ERROR(); Renderer::enable(Renderer::Feature::RasterizerDiscard); feedback.begin(shader, TransformFeedback::PrimitiveMode::Points); mesh.draw(shader); feedback.end(); MAGNUM_VERIFY_NO_ERROR(); Vector2* data = reinterpret_cast<Vector2*>(output.map(0, 4*sizeof(Vector2), Buffer::MapFlag::Read)); CORRADE_COMPARE(data[0], Vector2(1.0f, -1.0f)); CORRADE_COMPARE(data[1].y(), 5.0f); CORRADE_COMPARE(data[2], Vector2(0.0f, 0.0f)); CORRADE_COMPARE(data[3].y(), 3.0f); output.unmap(); } }}