mirror of https://github.com/mosra/magnum.git
Browse Source
Full support for EXT_transform_feedback, transform feedback objects from ARB_transform_feedback2 and equivalent OpenGL ES 3.0 functionality. Example usage is in src/Magnum/Test/TransformFeedbackGLTest.cpp, I'll add some example later.pull/77/head
19 changed files with 1328 additions and 24 deletions
@ -0,0 +1,45 @@
|
||||
#include "TransformFeedbackState.h" |
||||
|
||||
#include "Magnum/Extensions.h" |
||||
#include "Magnum/TransformFeedback.h" |
||||
|
||||
#include "State.h" |
||||
|
||||
namespace Magnum { namespace Implementation { |
||||
|
||||
TransformFeedbackState::TransformFeedbackState(Context& context, std::vector<std::string>& extensions): maxInterleavedComponents{0}, maxSeparateAttributes{0}, maxSeparateComponents{0} |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
, maxBuffers{0} |
||||
#endif |
||||
{ |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
if(context.isExtensionSupported<Extensions::GL::ARB::direct_state_access>()) { |
||||
extensions.push_back(Extensions::GL::ARB::direct_state_access::string()); |
||||
|
||||
createImplementation = &TransformFeedback::createImplementationDSA; |
||||
attachRangeImplementation = &TransformFeedback::attachImplementationDSA; |
||||
attachBaseImplementation = &TransformFeedback::attachImplementationDSA; |
||||
attachRangesImplementation = &TransformFeedback::attachImplementationDSA; |
||||
attachBasesImplementation = &TransformFeedback::attachImplementationDSA; |
||||
|
||||
} else |
||||
#endif |
||||
{ |
||||
createImplementation = &TransformFeedback::createImplementationDefault; |
||||
attachRangeImplementation = &TransformFeedback::attachImplementationFallback; |
||||
attachBaseImplementation = &TransformFeedback::attachImplementationFallback; |
||||
attachRangesImplementation = &TransformFeedback::attachImplementationFallback; |
||||
attachBasesImplementation = &TransformFeedback::attachImplementationFallback; |
||||
} |
||||
|
||||
#ifdef MAGNUM_TARGET_GLES |
||||
static_cast<void>(context); |
||||
static_cast<void>(extensions); |
||||
#endif |
||||
} |
||||
|
||||
void TransformFeedbackState::reset() { |
||||
binding = State::DisengagedBinding; |
||||
} |
||||
|
||||
}} |
||||
@ -0,0 +1,55 @@
|
||||
#ifndef Magnum_Implementation_TransformFeedbackState_h |
||||
#define Magnum_Implementation_TransformFeedbackState_h |
||||
/*
|
||||
This file is part of Magnum. |
||||
|
||||
Copyright © 2010, 2011, 2012, 2013, 2014 |
||||
Vladimír Vondruš <mosra@centrum.cz> |
||||
|
||||
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 "Magnum/Context.h" |
||||
|
||||
namespace Magnum { namespace Implementation { |
||||
|
||||
struct TransformFeedbackState { |
||||
explicit TransformFeedbackState(Context& context, std::vector<std::string>& extensions); |
||||
|
||||
void reset(); |
||||
|
||||
GLint maxInterleavedComponents, |
||||
maxSeparateAttributes, |
||||
maxSeparateComponents; |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
GLint maxBuffers; |
||||
#endif |
||||
|
||||
GLuint binding; |
||||
|
||||
void(TransformFeedback::*createImplementation)(); |
||||
void(TransformFeedback::*attachRangeImplementation)(GLuint, Buffer&, GLintptr, GLsizeiptr); |
||||
void(TransformFeedback::*attachBaseImplementation)(GLuint, Buffer&); |
||||
void(TransformFeedback::*attachRangesImplementation)(GLuint, std::initializer_list<std::tuple<Buffer*, GLintptr, GLsizeiptr>>); |
||||
void(TransformFeedback::*attachBasesImplementation)(GLuint, std::initializer_list<Buffer*>); |
||||
}; |
||||
|
||||
}} |
||||
|
||||
#endif |
||||
@ -0,0 +1,406 @@
|
||||
/*
|
||||
This file is part of Magnum. |
||||
|
||||
Copyright © 2010, 2011, 2012, 2013, 2014 |
||||
Vladimír Vondruš <mosra@centrum.cz> |
||||
|
||||
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 "Magnum/AbstractShaderProgram.h" |
||||
#include "Magnum/Buffer.h" |
||||
#include "Magnum/Mesh.h" |
||||
#include "Magnum/Shader.h" |
||||
#include "Magnum/TransformFeedback.h" |
||||
#include "Magnum/Math/Vector2.h" |
||||
#include "Magnum/Test/AbstractOpenGLTester.h" |
||||
|
||||
namespace Magnum { namespace Test { |
||||
|
||||
class TransformFeedbackGLTest: public AbstractOpenGLTester { |
||||
public: |
||||
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(); |
||||
|
||||
shader.use(); |
||||
|
||||
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(); |
||||
} |
||||
|
||||
}} |
||||
|
||||
CORRADE_TEST_MAIN(Magnum::Test::TransformFeedbackGLTest) |
||||
@ -0,0 +1,258 @@
|
||||
/*
|
||||
This file is part of Magnum. |
||||
|
||||
Copyright © 2010, 2011, 2012, 2013, 2014 |
||||
Vladimír Vondruš <mosra@centrum.cz> |
||||
|
||||
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 "TransformFeedback.h" |
||||
|
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
#include <Corrade/Utility/Assert.h> |
||||
|
||||
#include "Magnum/AbstractShaderProgram.h" |
||||
#include "Magnum/Buffer.h" |
||||
#include "Magnum/Context.h" |
||||
#include "Magnum/Extensions.h" |
||||
#include "Magnum/Implementation/DebugState.h" |
||||
#include "Magnum/Implementation/State.h" |
||||
#include "Magnum/Implementation/TransformFeedbackState.h" |
||||
|
||||
namespace Magnum { |
||||
|
||||
Int TransformFeedback::maxInterleavedComponents() { |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
if(!Context::current()->isExtensionSupported<Extensions::GL::EXT::transform_feedback>()) |
||||
return 0; |
||||
#endif |
||||
|
||||
GLint& value = Context::current()->state().transformFeedback->maxInterleavedComponents; |
||||
|
||||
if(value == 0) |
||||
glGetIntegerv(GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS, &value); |
||||
|
||||
return value; |
||||
} |
||||
|
||||
Int TransformFeedback::maxSeparateAttributes() { |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
if(!Context::current()->isExtensionSupported<Extensions::GL::EXT::transform_feedback>()) |
||||
return 0; |
||||
#endif |
||||
|
||||
GLint& value = Context::current()->state().transformFeedback->maxSeparateAttributes; |
||||
|
||||
if(value == 0) |
||||
glGetIntegerv(GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS, &value); |
||||
|
||||
return value; |
||||
} |
||||
|
||||
Int TransformFeedback::maxSeparateComponents() { |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
if(!Context::current()->isExtensionSupported<Extensions::GL::EXT::transform_feedback>()) |
||||
return 0; |
||||
#endif |
||||
|
||||
GLint& value = Context::current()->state().transformFeedback->maxSeparateComponents; |
||||
|
||||
if(value == 0) |
||||
glGetIntegerv(GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS, &value); |
||||
|
||||
return value; |
||||
} |
||||
|
||||
#ifndef MAGNUM_TARGET_GLES |
||||
Int TransformFeedback::maxBuffers() { |
||||
if(!Context::current()->isExtensionSupported<Extensions::GL::ARB::transform_feedback3>()) |
||||
return maxSeparateAttributes(); |
||||
|
||||
GLint& value = Context::current()->state().transformFeedback->maxBuffers; |
||||
|
||||
if(value == 0) |
||||
glGetIntegerv(GL_MAX_TRANSFORM_FEEDBACK_BUFFERS, &value); |
||||
|
||||
return value; |
||||
} |
||||
#endif |
||||
|
||||
TransformFeedback::TransformFeedback() { |
||||
(this->*Context::current()->state().transformFeedback->createImplementation)(); |
||||
CORRADE_INTERNAL_ASSERT(_id != Implementation::State::DisengagedBinding); |
||||
} |
||||
|
||||
void TransformFeedback::createImplementationDefault() { |
||||
glGenTransformFeedbacks(1, &_id); |
||||
_created = false; |
||||
} |
||||
|
||||
#ifndef MAGNUM_TARGET_GLES |
||||
void TransformFeedback::createImplementationDSA() { |
||||
glCreateTransformFeedbacks(1, &_id); |
||||
_created = true; |
||||
} |
||||
#endif |
||||
|
||||
TransformFeedback::~TransformFeedback() { |
||||
if(!_id) return; |
||||
|
||||
/* If bound, remove itself from state */ |
||||
GLuint& binding = Context::current()->state().transformFeedback->binding; |
||||
if(binding == _id) binding = 0; |
||||
|
||||
glDeleteTransformFeedbacks(1, &_id); |
||||
} |
||||
|
||||
void TransformFeedback::bindInternal() { |
||||
GLuint& bound = Context::current()->state().transformFeedback->binding; |
||||
|
||||
/* Already bound, nothing to do */ |
||||
if(bound == _id) return; |
||||
|
||||
/* Bind the transform feedback otherwise, which will also finally create it */ |
||||
bound = _id; |
||||
_created = true; |
||||
glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, _id); |
||||
} |
||||
|
||||
inline void TransformFeedback::createIfNotAlready() { |
||||
if(_created) return; |
||||
|
||||
/* glGen*() does not create the object, just reserves the name. Some
|
||||
commands (such as glObjectLabel()) operate with IDs directly and they |
||||
require the object to be created. Binding the transform feedback finally |
||||
creates it. Also all EXT DSA functions implicitly create it. */ |
||||
bindInternal(); |
||||
CORRADE_INTERNAL_ASSERT(_created); |
||||
} |
||||
|
||||
std::string TransformFeedback::label() { |
||||
createIfNotAlready(); |
||||
return Context::current()->state().debug->getLabelImplementation(GL_TRANSFORM_FEEDBACK, _id); |
||||
} |
||||
|
||||
TransformFeedback& TransformFeedback::setLabelInternal(const Containers::ArrayReference<const char> label) { |
||||
createIfNotAlready(); |
||||
Context::current()->state().debug->labelImplementation(GL_TRANSFORM_FEEDBACK, _id, label); |
||||
return *this; |
||||
} |
||||
|
||||
TransformFeedback& TransformFeedback::attachBuffer(const UnsignedInt index, Buffer& buffer, const GLintptr offset, const GLsizeiptr size) { |
||||
(this->*Context::current()->state().transformFeedback->attachRangeImplementation)(index, buffer, offset, size); |
||||
return *this; |
||||
} |
||||
|
||||
TransformFeedback& TransformFeedback::attachBuffer(const UnsignedInt index, Buffer& buffer) { |
||||
(this->*Context::current()->state().transformFeedback->attachBaseImplementation)(index, buffer); |
||||
return *this; |
||||
} |
||||
|
||||
void TransformFeedback::attachImplementationFallback(const GLuint index, Buffer& buffer, const GLintptr offset, const GLsizeiptr size) { |
||||
bindInternal(); |
||||
buffer.bind(Buffer::Target(GL_TRANSFORM_FEEDBACK_BUFFER), index, offset, size); |
||||
} |
||||
|
||||
#ifndef MAGNUM_TARGET_GLES |
||||
void TransformFeedback::attachImplementationDSA(const GLuint index, Buffer& buffer, const GLintptr offset, const GLsizeiptr size) { |
||||
glTransformFeedbackBufferRange(_id, index, buffer.id(), offset, size); |
||||
} |
||||
#endif |
||||
|
||||
void TransformFeedback::attachImplementationFallback(const GLuint index, Buffer& buffer) { |
||||
bindInternal(); |
||||
buffer.bind(Buffer::Target(GL_TRANSFORM_FEEDBACK_BUFFER), index); |
||||
} |
||||
|
||||
#ifndef MAGNUM_TARGET_GLES |
||||
void TransformFeedback::attachImplementationDSA(const GLuint index, Buffer& buffer) { |
||||
glTransformFeedbackBufferBase(_id, index, buffer.id()); |
||||
} |
||||
#endif |
||||
|
||||
/** @todoc const std::initializer_list makes Doxygen grumpy */ |
||||
TransformFeedback& TransformFeedback::attachBuffers(const UnsignedInt firstIndex, std::initializer_list<std::tuple<Buffer*, GLintptr, GLsizeiptr>> buffers) { |
||||
(this->*Context::current()->state().transformFeedback->attachRangesImplementation)(firstIndex, buffers); |
||||
return *this; |
||||
} |
||||
|
||||
/** @todoc const std::initializer_list makes Doxygen grumpy */ |
||||
TransformFeedback& TransformFeedback::attachBuffers(const UnsignedInt firstIndex, std::initializer_list<Buffer*> buffers) { |
||||
(this->*Context::current()->state().transformFeedback->attachBasesImplementation)(firstIndex, buffers); |
||||
return *this; |
||||
} |
||||
|
||||
/** @todoc const std::initializer_list makes Doxygen grumpy */ |
||||
void TransformFeedback::attachImplementationFallback(const GLuint firstIndex, std::initializer_list<std::tuple<Buffer*, GLintptr, GLsizeiptr>> buffers) { |
||||
bindInternal(); |
||||
Buffer::bind(Buffer::Target(GL_TRANSFORM_FEEDBACK_BUFFER), firstIndex, buffers); |
||||
} |
||||
|
||||
#ifndef MAGNUM_TARGET_GLES |
||||
/** @todoc const Containers::ArrayReference makes Doxygen grumpy */ |
||||
void TransformFeedback::attachImplementationDSA(const GLuint firstIndex, std::initializer_list<std::tuple<Buffer*, GLintptr, GLsizeiptr>> buffers) { |
||||
for(std::size_t i = 0; i != buffers.size(); ++i) { |
||||
Buffer* buffer; |
||||
GLintptr offset; |
||||
GLsizeiptr size; |
||||
std::tie(buffer, offset, size) = *(buffers.begin() + i); |
||||
|
||||
glTransformFeedbackBufferRange(_id, firstIndex + i, buffer ? buffer->id() : 0, offset, size); |
||||
} |
||||
} |
||||
#endif |
||||
|
||||
/** @todoc const Containers::ArrayReference makes Doxygen grumpy */ |
||||
void TransformFeedback::attachImplementationFallback(const GLuint firstIndex, std::initializer_list<Buffer*> buffers) { |
||||
bindInternal(); |
||||
Buffer::bind(Buffer::Target(GL_TRANSFORM_FEEDBACK_BUFFER), firstIndex, buffers); |
||||
} |
||||
|
||||
#ifndef MAGNUM_TARGET_GLES |
||||
/** @todoc const Containers::ArrayReference makes Doxygen grumpy */ |
||||
void TransformFeedback::attachImplementationDSA(const GLuint firstIndex, std::initializer_list<Buffer*> buffers) { |
||||
for(std::size_t i = 0; i != buffers.size(); ++i) |
||||
glTransformFeedbackBufferBase(_id, firstIndex + i, *(buffers.begin() + i) ? (*(buffers.begin() + i))->id() : 0); |
||||
} |
||||
#endif |
||||
|
||||
void TransformFeedback::begin(AbstractShaderProgram& shader, const PrimitiveMode mode) { |
||||
shader.use(); |
||||
bindInternal(); |
||||
glBeginTransformFeedback(GLenum(mode)); |
||||
} |
||||
|
||||
void TransformFeedback::pause() { |
||||
bindInternal(); |
||||
glPauseTransformFeedback(); |
||||
} |
||||
|
||||
void TransformFeedback::resume() { |
||||
bindInternal(); |
||||
glResumeTransformFeedback(); |
||||
} |
||||
|
||||
void TransformFeedback::end() { |
||||
bindInternal(); |
||||
glEndTransformFeedback(); |
||||
} |
||||
|
||||
} |
||||
#endif |
||||
@ -0,0 +1,375 @@
|
||||
#ifndef Magnum_TransformFeedback_h |
||||
#define Magnum_TransformFeedback_h |
||||
/*
|
||||
This file is part of Magnum. |
||||
|
||||
Copyright © 2010, 2011, 2012, 2013, 2014 |
||||
Vladimír Vondruš <mosra@centrum.cz> |
||||
|
||||
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 <Corrade/Containers/Array.h> |
||||
|
||||
#include "Magnum/AbstractObject.h" |
||||
|
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
/** @file
|
||||
* @brief Class @ref Magnum::TransformFeedback |
||||
*/ |
||||
#endif |
||||
|
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
namespace Magnum { |
||||
|
||||
namespace Implementation { struct TransformFeedbackState; } |
||||
|
||||
/**
|
||||
@brief Transform feedback |
||||
|
||||
@see @ref PrimitiveQuery |
||||
@requires_gl40 %Extension @extension{ARB,transform_feedback2} |
||||
@requires_gles30 Transform feedback is not available in OpenGL ES 2.0 |
||||
@todo @extension{AMD,transform_feedback3_lines_triangles}? |
||||
*/ |
||||
class MAGNUM_EXPORT TransformFeedback: public AbstractObject { |
||||
friend struct Implementation::TransformFeedbackState; |
||||
|
||||
public: |
||||
/**
|
||||
* @brief Transform feedback primitive mode |
||||
* |
||||
* @see @ref begin() |
||||
*/ |
||||
enum class PrimitiveMode: GLenum { |
||||
/**
|
||||
* Points. If no geometry shader is present, allowed only in |
||||
* combination with @ref MeshPrimitive::Points mesh primitive type. |
||||
* If geometry shader is present, allowed only in combination with |
||||
* `points` output primitive type. |
||||
*/ |
||||
Points = GL_POINTS, |
||||
|
||||
/**
|
||||
* Lines. If no geometry shader is present, allowed only in |
||||
* combination with @ref MeshPrimitive::LineStrip, |
||||
* @ref MeshPrimitive::LineLoop, @ref MeshPrimitive::Lines, |
||||
* @ref MeshPrimitive::LineStripAdjacency and |
||||
* @ref MeshPrimitive::LinesAdjacency mesh primitive type. If |
||||
* geometry shader is present, allowed only in combination with |
||||
* `line_strip` output primitive type. |
||||
*/ |
||||
Lines = GL_LINES, |
||||
|
||||
/**
|
||||
* Triangles. If no geometry shader is present, allowed only in |
||||
* combination with @ref MeshPrimitive::TriangleStrip, |
||||
* @ref MeshPrimitive::TriangleFan, @ref MeshPrimitive::Triangles, |
||||
* @ref MeshPrimitive::TriangleStripAdjacency and |
||||
* @ref MeshPrimitive::TrianglesAdjacency mesh primitive type. If |
||||
* geometry shader is present, allowed only in commbination with |
||||
* `triangle_strip` output primitive type. |
||||
*/ |
||||
Triangles = GL_TRIANGLES |
||||
}; |
||||
|
||||
/**
|
||||
* @brief Max supported interleaved component count |
||||
* |
||||
* The result is cached, repeated queries don't result in repeated |
||||
* OpenGL calls. If extension @extension{EXT,transform_feedback} |
||||
* (part of OpenGL 3.0) is not available, returns `0`. |
||||
* @see @fn_gl{Get} with @def_gl{MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS} |
||||
*/ |
||||
static Int maxInterleavedComponents(); |
||||
|
||||
/**
|
||||
* @brief Max supported separate attribute count |
||||
* |
||||
* The result is cached, repeated queries don't result in repeated |
||||
* OpenGL calls. If extension @extension{EXT,transform_feedback} |
||||
* (part of OpenGL 3.0) is not available, returns `0`. |
||||
* @see @fn_gl{Get} with @def_gl{MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS} |
||||
*/ |
||||
static Int maxSeparateAttributes(); |
||||
|
||||
/**
|
||||
* @brief Max supported separate component count |
||||
* |
||||
* The result is cached, repeated queries don't result in repeated |
||||
* OpenGL calls. If extension @extension{EXT,transform_feedback} |
||||
* (part of OpenGL 3.0) is not available, returns `0`. |
||||
* @see @fn_gl{Get} with @def_gl{MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS} |
||||
*/ |
||||
static Int maxSeparateComponents(); |
||||
|
||||
#ifndef MAGNUM_TARGET_GLES |
||||
/**
|
||||
* @brief Max supported buffer count |
||||
* |
||||
* The result is cached, repeated queries don't result in repeated |
||||
* OpenGL calls. If extension @extension{ARB,transform_feedback3} |
||||
* (part of OpenGL 4.0) is not available, returns the same value as |
||||
* @ref maxSeparateAttributes(). |
||||
* @see @fn_gl{Get} with @def_gl{MAX_TRANSFORM_FEEDBACK_BUFFERS} |
||||
* @requires_gl Use @ref Magnum::TransformFeedback::maxSeparateAttributes() "maxSeparateAttributes()" |
||||
* in OpenGL ES. |
||||
*/ |
||||
static Int maxBuffers(); |
||||
#endif |
||||
|
||||
/**
|
||||
* @brief Constructor |
||||
* |
||||
* Creates new OpenGL transform feedback object. If |
||||
* @extension{ARB,direct_state_access} (part of OpenGL 4.5) is not |
||||
* supported, the transform feedback object is created on first use. |
||||
* @see @fn_gl{CreateTransformFeedbacks}, eventually |
||||
* @fn_gl{GenTransformFeedbacks} |
||||
*/ |
||||
explicit TransformFeedback(); |
||||
|
||||
/** @brief Copying is not allowed */ |
||||
TransformFeedback(const TransformFeedback&) = delete; |
||||
|
||||
/** @brief Move constructor */ |
||||
TransformFeedback(TransformFeedback&& other) noexcept; |
||||
|
||||
/**
|
||||
* @brief Destructor |
||||
* |
||||
* Deletes associated OpenGL transform feedback object. |
||||
* @see @fn_gl{DeleteTransformFeedbacks} |
||||
*/ |
||||
~TransformFeedback(); |
||||
|
||||
/** @brief Copying is not allowed */ |
||||
TransformFeedback& operator=(const TransformFeedback&) = delete; |
||||
|
||||
/** @brief Move assignment */ |
||||
TransformFeedback& operator=(TransformFeedback&& other) noexcept; |
||||
|
||||
/** @brief OpenGL transform feedback ID */ |
||||
GLuint id() const { return _id; } |
||||
|
||||
/**
|
||||
* @brief %Buffer label |
||||
* |
||||
* The result is *not* cached, repeated queries will result in repeated |
||||
* OpenGL calls. If OpenGL 4.3 is not supported and neither |
||||
* @extension{KHR,debug} nor @extension2{EXT,debug_label} desktop or ES |
||||
* extension is available, this function returns empty string. |
||||
* @see @fn_gl{GetObjectLabel} or @fn_gl_extension2{GetObjectLabel,EXT,debug_label} |
||||
* with @def_gl{BUFFER_OBJECT_EXT} |
||||
*/ |
||||
std::string label(); |
||||
|
||||
/**
|
||||
* @brief Set buffer label |
||||
* @return Reference to self (for method chaining) |
||||
* |
||||
* Default is empty string. If OpenGL 4.3 is not supported and neither |
||||
* @extension{KHR,debug} nor @extension2{EXT,debug_label} desktop or ES |
||||
* extension is available, this function does nothing. |
||||
* @see @ref maxLabelLength(), @fn_gl{ObjectLabel} or |
||||
* @fn_gl_extension2{LabelObject,EXT,debug_label} with |
||||
* @def_gl{TRANSFORM_FEEDBACK} |
||||
*/ |
||||
TransformFeedback& setLabel(const std::string& label) { |
||||
return setLabelInternal({label.data(), label.size()}); |
||||
} |
||||
|
||||
/** @overload */ |
||||
template<std::size_t size> TransformFeedback& setLabel(const char(&label)[size]) { |
||||
return setLabelInternal(label); |
||||
} |
||||
|
||||
/**
|
||||
* @brief Attach range of buffer |
||||
* @return Reference to self (for method chaining) |
||||
* |
||||
* The @p offset parameter must be aligned to 4 bytes. If on OpenGL ES |
||||
* or @extension{ARB,direct_state_access} (part of OpenGL 4.5) is not |
||||
* available, the transform feedback object is bound (if not already) |
||||
* and the operation is then done equivalently to |
||||
* @ref Buffer::bind(Buffer::Target, UnsignedInt, GLintptr, GLsizeiptr). |
||||
* @note This function is meant to be used only internally from |
||||
* @ref AbstractShaderProgram subclasses. See its documentation |
||||
* for more information. |
||||
* @see @ref attachBuffers(), @ref maxBuffers()/@ref maxSeparateAttributes(), |
||||
* @fn_gl{TransformFeedbackBufferRange}, eventually |
||||
* @fn_gl{BindTransformFeedback} and @fn_gl{BindBuffersRange} or |
||||
* @fn_gl{BindBufferRange} |
||||
*/ |
||||
TransformFeedback& attachBuffer(UnsignedInt index, Buffer& buffer, GLintptr offset, GLsizeiptr size); |
||||
|
||||
/**
|
||||
* @brief Attach buffer |
||||
* @return Reference to self (for method chaining) |
||||
* |
||||
* If on OpenGL ES or @extension{ARB,direct_state_access} (part of |
||||
* OpenGL 4.5) is not available, the transform feedback object is bound |
||||
* (if not already) and the operation is then done equivalently to |
||||
* @ref Buffer::bind(Buffer::Target, UnsignedInt). |
||||
* @note This function is meant to be used only internally from |
||||
* @ref AbstractShaderProgram subclasses. See its documentation |
||||
* for more information. |
||||
* @see @ref attachBuffers(), @ref maxBuffers()/@ref maxSeparateAttributes(), |
||||
* @fn_gl{TransformFeedbackBufferRange}, eventually |
||||
* @fn_gl{BindTransformFeedback} and @fn_gl{BindBuffersRange} or |
||||
* @fn_gl{BindBufferRange} |
||||
*/ |
||||
TransformFeedback& attachBuffer(UnsignedInt index, Buffer& buffer); |
||||
|
||||
/**
|
||||
* @brief Attach ranges of buffers |
||||
* @return Reference to self (for method chaining) |
||||
* |
||||
* Attches first buffer in the list to @p firstIndex, second to |
||||
* `firstIndex + 1` etc. Second parameter is offset, third is size. If |
||||
* any buffer is `nullptr`, given attachment point is detached. The |
||||
* range of indices must respect @ref maxBuffers() (@ref maxSeparateComponents() |
||||
* in OpenGL ES or if @extension{ARB,transform_feedback3} (part of |
||||
* OpenGL 4.0) is not available). The offsets must be aligned to 4 |
||||
* bytes. All the buffers must have allocated data store. If on OpenGL |
||||
* ES or @extension{ARB,direct_state_access} (part of OpenGL 4.5) is |
||||
* not available, the transform feedback object is bound (if not |
||||
* already) and the operation is then done equivalently to |
||||
* @ref Buffer::bind(Buffer::Target, UnsignedInt, std::initializer_list<std::tuple<Buffer*, GLintptr, GLsizeiptr>>). |
||||
* @note This function is meant to be used only internally from |
||||
* @ref AbstractShaderProgram subclasses. See its documentation |
||||
* for more information. |
||||
* @see @ref attachBuffer(), @fn_gl{TransformFeedbackBufferRange}, |
||||
* eventually @fn_gl{BindTransformFeedback} and |
||||
* @fn_gl{BindBuffersRange} or @fn_gl{BindBufferRange} |
||||
*/ |
||||
TransformFeedback& attachBuffers(UnsignedInt firstIndex, std::initializer_list<std::tuple<Buffer*, GLintptr, GLsizeiptr>> buffers); |
||||
|
||||
/**
|
||||
* @brief Attach buffers |
||||
* @return Reference to self (for method chaining) |
||||
* |
||||
* Attches first buffer in the list to @p firstIndex, second to |
||||
* `firstIndex + 1` etc. If any buffer is `nullptr`, given index is |
||||
* detached. The range of indices must respect @ref maxBuffers() |
||||
* (@ref maxSeparateComponents() in OpenGL ES or if |
||||
* @extension{ARB,transform_feedback3} (part of OpenGL 4.0) is not |
||||
* available). All the buffers must have allocated data store. If on |
||||
* OpenGL ES or @extension{ARB,direct_state_access} (part of OpenGL |
||||
* 4.5) is not available, the transform feedback object is bound (if |
||||
* not already) and the operation then is done equivalently to |
||||
* @ref Buffer::bind(Buffer::Target, UnsignedInt, std::initializer_list<Buffer*>). |
||||
* @note This function is meant to be used only internally from |
||||
* @ref AbstractShaderProgram subclasses. See its documentation |
||||
* for more information. |
||||
* @see @ref attachBuffer(), @fn_gl{TransformFeedbackBufferBase}, |
||||
* eventually @fn_gl{BindTransformFeedback} and |
||||
* @fn_gl{BindBuffersBase} or @fn_gl{BindBufferBase} |
||||
*/ |
||||
TransformFeedback& attachBuffers(UnsignedInt firstIndex, std::initializer_list<Buffer*> buffers); |
||||
|
||||
/**
|
||||
* @brief Begin transform feedback |
||||
* @param shader Shader from which to capture data |
||||
* @param mode Primitive mode |
||||
* |
||||
* When transform feedback is active, only shader given in @p shader |
||||
* and meshes with primitive type (or geometry shaders with output |
||||
* primitive type) compatible with @p mode can be used. Only one |
||||
* transform feedback object can be active at a time. |
||||
* @see @ref pause(), @ref end(), @fn_gl{BindTransformFeedback} and |
||||
* @fn_gl{BeginTransformFeedback} |
||||
*/ |
||||
void begin(AbstractShaderProgram& shader, PrimitiveMode mode); |
||||
|
||||
/**
|
||||
* @brief Pause transform feedback |
||||
* |
||||
* Pausing transform feedback makes it inactive, allowing to use |
||||
* different shader, or starting another transform feedback. |
||||
* @see @ref resume(), @ref end(), @fn_gl{BindTransformFeedback} and |
||||
* @fn_gl{PauseTransformFeedback} |
||||
*/ |
||||
void pause(); |
||||
|
||||
/**
|
||||
* @brief Resume transform feedback |
||||
* |
||||
* Resumes transform feedback so the next captured data are appended to |
||||
* already captured ones. The restrictions specified for @ref begin() |
||||
* still apply after resuming. Only one transform feedback object can |
||||
* be active at a time. |
||||
* @see @ref pause(), @ref end(), @fn_gl{BindTransformFeedback} and |
||||
* @fn_gl{ResumeTransformFeedback} |
||||
*/ |
||||
void resume(); |
||||
|
||||
/**
|
||||
* @brief End transform feedback |
||||
* |
||||
* Ends transform feedback so the captured data can be used. |
||||
* @see @ref begin(), @fn_gl{BindTransformFeedback} and |
||||
* @fn_gl{EndTransformFeedback} |
||||
*/ |
||||
void end(); |
||||
|
||||
private: |
||||
void bindInternal(); |
||||
|
||||
void MAGNUM_LOCAL createIfNotAlready(); |
||||
|
||||
void MAGNUM_LOCAL createImplementationDefault(); |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
void MAGNUM_LOCAL createImplementationDSA(); |
||||
#endif |
||||
|
||||
void MAGNUM_LOCAL attachImplementationFallback(GLuint index, Buffer& buffer, GLintptr offset, GLsizeiptr size); |
||||
void MAGNUM_LOCAL attachImplementationFallback(GLuint index, Buffer& buffer); |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
void MAGNUM_LOCAL attachImplementationDSA(GLuint index, Buffer& buffer, GLintptr offset, GLsizeiptr size); |
||||
void MAGNUM_LOCAL attachImplementationDSA(GLuint index, Buffer& buffer); |
||||
#endif |
||||
|
||||
void MAGNUM_LOCAL attachImplementationFallback(GLuint firstIndex, std::initializer_list<std::tuple<Buffer*, GLintptr, GLsizeiptr>> buffers); |
||||
void MAGNUM_LOCAL attachImplementationFallback(GLuint firstIndex, std::initializer_list<Buffer*> buffers); |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
void MAGNUM_LOCAL attachImplementationDSA(GLuint firstIndex, std::initializer_list<std::tuple<Buffer*, GLintptr, GLsizeiptr>> buffers); |
||||
void MAGNUM_LOCAL attachImplementationDSA(GLuint firstIndex, std::initializer_list<Buffer*> buffers); |
||||
#endif |
||||
|
||||
TransformFeedback& setLabelInternal(Containers::ArrayReference<const char> label); |
||||
|
||||
GLuint _id; |
||||
bool _created; /* see createIfNotAlready() for details */ |
||||
}; |
||||
|
||||
inline TransformFeedback::TransformFeedback(TransformFeedback&& other) noexcept: _id{other._id}, _created{other._created} { |
||||
other._id = 0; |
||||
} |
||||
|
||||
inline TransformFeedback& TransformFeedback::operator=(TransformFeedback&& other) noexcept { |
||||
std::swap(_id, other._id); |
||||
std::swap(_created, other._created); |
||||
return *this; |
||||
} |
||||
|
||||
} |
||||
#endif |
||||
|
||||
#endif |
||||
Loading…
Reference in new issue