Browse Source

Implemented Mesh::draw(..., TransformFeedback&).

Supports classic, instanced, stream and stream instanced draw. With this
I consider the transform feedback implementation complete.
pull/187/head^2
Vladimír Vondruš 10 years ago
parent
commit
a60dc74dac
  1. 4
      doc/opengl-mapping.dox
  2. 4
      doc/opengl-support.dox
  3. 39
      src/Magnum/Mesh.cpp
  4. 61
      src/Magnum/Mesh.h
  5. 11
      src/Magnum/MeshView.cpp
  6. 41
      src/Magnum/MeshView.h
  7. 166
      src/Magnum/Test/TransformFeedbackGLTest.cpp

4
doc/opengl-mapping.dox

@ -124,10 +124,10 @@ OpenGL function | Matching API
@fn_gl{DispatchCompute} | @ref AbstractShaderProgram::dispatchCompute() @fn_gl{DispatchCompute} | @ref AbstractShaderProgram::dispatchCompute()
@fn_gl_extension{DispatchComputeGroupSize,ARB,compute_variable_group_size} | | @fn_gl_extension{DispatchComputeGroupSize,ARB,compute_variable_group_size} | |
@fn_gl{DispatchComputeIndirect} | | @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{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{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 @subsection opengl-mapping-functions-e E

4
doc/opengl-support.dox

@ -131,7 +131,7 @@ GLSL 4.00 | done
@extension{ARB,shader_subroutine} | | @extension{ARB,shader_subroutine} | |
@extension{ARB,tessellation_shader} | missing some limit queries and patch parameter specification function @extension{ARB,tessellation_shader} | missing some limit queries and patch parameter specification function
@extension{ARB,texture_buffer_object_rgb32} | done @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 @extension{ARB,transform_feedback3} | missing indexed properties query
@subsection opengl-support-41 OpenGL 4.1 @subsection opengl-support-41 OpenGL 4.1
@ -154,7 +154,7 @@ GLSL 4.20 | done
@extension{ARB,texture_compression_bptc} | done @extension{ARB,texture_compression_bptc} | done
@extension{ARB,base_instance} | done @extension{ARB,base_instance} | done
@extension{ARB,shading_language_420pack} | done (shading language only) @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,compressed_texture_pixel_storage} | done
@extension{ARB,conservative_depth} | done (shading language only) @extension{ARB,conservative_depth} | done (shading language only)
@extension{ARB,internalformat_query} | | @extension{ARB,internalformat_query} | |

39
src/Magnum/Mesh.cpp

@ -31,6 +31,9 @@
#include "Magnum/Buffer.h" #include "Magnum/Buffer.h"
#include "Magnum/Context.h" #include "Magnum/Context.h"
#include "Magnum/Extensions.h" #include "Magnum/Extensions.h"
#ifndef MAGNUM_TARGET_GLES
#include "Magnum/TransformFeedback.h"
#endif
#ifndef MAGNUM_TARGET_WEBGL #ifndef MAGNUM_TARGET_WEBGL
#include "Implementation/DebugState.h" #include "Implementation/DebugState.h"
@ -363,6 +366,42 @@ void Mesh::drawInternal(Int count, Int baseVertex, Int instanceCount, GLintptr i
(this->*state.unbindImplementation)(); (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() { void Mesh::bindVAO() {
GLuint& current = Context::current().state().mesh->currentVAO; GLuint& current = Context::current().state().mesh->currentVAO;
if(current != _id) { if(current != _id) {

61
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, * 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 * 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() * @see @ref isIndexed(), @ref setBaseVertex(), @ref setInstanceCount()
*/ */
Mesh& setCount(Int count) { Mesh& setCount(Int count) {
@ -618,7 +620,8 @@ class MAGNUM_EXPORT Mesh: public AbstractObject {
* @return Reference to self (for method chaining) * @return Reference to self (for method chaining)
* *
* Sets number of vertices of which the vertex buffer will be offset * 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() * @see @ref setCount(), @ref setBaseInstance()
* @requires_gl32 Extension @extension{ARB,draw_elements_base_vertex} * @requires_gl32 Extension @extension{ARB,draw_elements_base_vertex}
* for indexed meshes * for indexed meshes
@ -638,11 +641,15 @@ class MAGNUM_EXPORT Mesh: public AbstractObject {
* @return Reference to self (for method chaining) * @return Reference to self (for method chaining)
* *
* If set to `1`, non-instanced draw commands are issued when calling * If set to `1`, non-instanced draw commands are issued when calling
* @ref draw(). If set to `0`, no draw commands are issued altogether. * @ref draw(AbstractShaderProgram&) or
* Default is `1`. * @ref draw(AbstractShaderProgram&, TransformFeedback&). If set to
* `0`, no draw commands are issued altogether. Default is `1`.
* @see @ref setBaseInstance(), @ref setCount(), * @see @ref setBaseInstance(), @ref setCount(),
* @ref addVertexBufferInstanced() * @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}, * @requires_gles30 Extension @es_extension{ANGLE,instanced_arrays},
* @es_extension2{EXT,draw_instanced,draw_instanced} or * @es_extension2{EXT,draw_instanced,draw_instanced} or
* @es_extension{NV,draw_instanced} in OpenGL ES 2.0. * @es_extension{NV,draw_instanced} in OpenGL ES 2.0.
@ -662,6 +669,7 @@ class MAGNUM_EXPORT Mesh: public AbstractObject {
* @brief Set base instance * @brief Set base instance
* @return Reference to self (for method chaining) * @return Reference to self (for method chaining)
* *
* Ignored when calling @ref draw(AbstractShaderProgram, TransformFeedback&, UnsignedInt).
* Default is `0`. * Default is `0`.
* @see @ref setInstanceCount(), @ref setBaseVertex() * @see @ref setInstanceCount(), @ref setBaseVertex()
* @requires_gl42 Extension @extension{ARB,base_instance} * @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 * 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. * available, the vertex array object is used to hold the parameters.
* *
* Ignored when calling @ref draw(AbstractShaderProgram&, TransformFeedback&, UnsignedInt).
*
* @see @ref maxElementIndex(), @ref maxElementsIndices(), * @see @ref maxElementIndex(), @ref maxElementsIndices(),
* @ref maxElementsVertices(), @ref setCount(), @ref isIndexed(), * @ref maxElementsVertices(), @ref setCount(), @ref isIndexed(),
* @fn_gl{BindVertexArray}, @fn_gl{BindBuffer} * @fn_gl{BindVertexArray}, @fn_gl{BindBuffer}
@ -868,6 +878,43 @@ class MAGNUM_EXPORT Mesh: public AbstractObject {
void draw(AbstractShaderProgram& shader); void draw(AbstractShaderProgram& shader);
void draw(AbstractShaderProgram&& shader) { draw(shader); } /**< @overload */ 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: private:
enum class AttributeKind { enum class AttributeKind {
Generic, Generic,
@ -961,6 +1008,10 @@ class MAGNUM_EXPORT Mesh: public AbstractObject {
void drawInternal(Int count, Int baseVertex, Int instanceCount, GLintptr indexOffset); void drawInternal(Int count, Int baseVertex, Int instanceCount, GLintptr indexOffset);
#endif #endif
#ifndef MAGNUM_TARGET_GLES
void drawInternal(TransformFeedback& xfb, UnsignedInt stream, Int instanceCount);
#endif
void MAGNUM_LOCAL createImplementationDefault(); void MAGNUM_LOCAL createImplementationDefault();
void MAGNUM_LOCAL createImplementationVAO(); void MAGNUM_LOCAL createImplementationVAO();
#ifndef MAGNUM_TARGET_GLES #ifndef MAGNUM_TARGET_GLES

11
src/Magnum/MeshView.cpp

@ -164,4 +164,15 @@ void MeshView::draw(AbstractShaderProgram& shader) {
#endif #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
} }

41
src/Magnum/MeshView.h

@ -79,6 +79,10 @@ class MAGNUM_EXPORT MeshView {
* @fn_gl{VertexAttribPointer}, @fn_gl{DisableVertexAttribArray} * @fn_gl{VertexAttribPointer}, @fn_gl{DisableVertexAttribArray}
* or @fn_gl{BindVertexArray}, @fn_gl{MultiDrawArrays} or * or @fn_gl{BindVertexArray}, @fn_gl{MultiDrawArrays} or
* @fn_gl{MultiDrawElements}/@fn_gl{MultiDrawElementsBaseVertex} * @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<std::reference_wrapper<MeshView>> meshes); static void draw(AbstractShaderProgram& shader, std::initializer_list<std::reference_wrapper<MeshView>> meshes);
@ -112,6 +116,7 @@ class MAGNUM_EXPORT MeshView {
* @brief Set vertex/index count * @brief Set vertex/index count
* @return Reference to self (for method chaining) * @return Reference to self (for method chaining)
* *
* Ignored when calling @ref draw(AbstractShaderProgram, TransformFeedback&, UnsignedInt).
* Default is `0`. * Default is `0`.
*/ */
MeshView& setCount(Int count) { MeshView& setCount(Int count) {
@ -127,7 +132,8 @@ class MAGNUM_EXPORT MeshView {
* @return Reference to self (for method chaining) * @return Reference to self (for method chaining)
* *
* Sets number of vertices of which the vertex buffer will be offset * 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} * @requires_gl32 Extension @extension{ARB,draw_elements_base_vertex}
* for indexed meshes * for indexed meshes
* @requires_gl Base vertex cannot be specified for indexed meshes in * @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 * performance, as only a portion of vertex buffer needs to be
* acccessed. On OpenGL ES 2.0 this function behaves the same as * acccessed. On OpenGL ES 2.0 this function behaves the same as
* @ref setIndexRange(Int), as index range functionality is not * @ref setIndexRange(Int), as index range functionality is not
* available there. * available there. Ignored when calling
* @ref draw(AbstractShaderProgram, TransformFeedback&, UnsignedInt).
* @see @ref setCount() * @see @ref setCount()
*/ */
/* MinGW/MSVC needs inline also here to avoid linkage conflicts */ /* 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) * @return Reference to self (for method chaining)
* *
* Prefer to use @ref setIndexRange(Int, UnsignedInt, UnsignedInt) for * Prefer to use @ref setIndexRange(Int, UnsignedInt, UnsignedInt) for
* better performance. * better performance. Ignored when calling
* @ref draw(AbstractShaderProgram, TransformFeedback&, UnsignedInt).
* @see @ref setCount() * @see @ref setCount()
*/ */
MeshView& setIndexRange(Int first); MeshView& setIndexRange(Int first);
@ -194,6 +202,7 @@ class MAGNUM_EXPORT MeshView {
* @brief Set base instance * @brief Set base instance
* @return Reference to self (for method chaining) * @return Reference to self (for method chaining)
* *
* Ignored when calling @ref draw(AbstractShaderProgram, TransformFeedback&, UnsignedInt).
* Default is `0`. * Default is `0`.
* @requires_gl42 Extension @extension{ARB,base_instance} * @requires_gl42 Extension @extension{ARB,base_instance}
* @requires_gl Base instance cannot be specified in OpenGL ES or * @requires_gl Base instance cannot be specified in OpenGL ES or
@ -208,7 +217,7 @@ class MAGNUM_EXPORT MeshView {
/** /**
* @brief Draw the mesh * @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<std::reference_wrapper<MeshView>>) * @see @ref draw(AbstractShaderProgram&, std::initializer_list<std::reference_wrapper<MeshView>>)
* @requires_gl32 Extension @extension{ARB,draw_elements_base_vertex} * @requires_gl32 Extension @extension{ARB,draw_elements_base_vertex}
* if the mesh is indexed and @ref baseVertex() is not `0`. * 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);
void draw(AbstractShaderProgram&& shader) { draw(shader); } /**< @overload */ 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: private:
#ifndef MAGNUM_TARGET_WEBGL #ifndef MAGNUM_TARGET_WEBGL
static MAGNUM_LOCAL void multiDrawImplementationDefault(std::initializer_list<std::reference_wrapper<MeshView>> meshes); static MAGNUM_LOCAL void multiDrawImplementationDefault(std::initializer_list<std::reference_wrapper<MeshView>> meshes);

166
src/Magnum/Test/TransformFeedbackGLTest.cpp

@ -26,7 +26,11 @@
#include "Magnum/AbstractShaderProgram.h" #include "Magnum/AbstractShaderProgram.h"
#include "Magnum/Buffer.h" #include "Magnum/Buffer.h"
#include "Magnum/Framebuffer.h" #include "Magnum/Framebuffer.h"
#include "Magnum/Image.h"
#include "Magnum/Mesh.h" #include "Magnum/Mesh.h"
#include "Magnum/PixelFormat.h"
#include "Magnum/PrimitiveQuery.h"
#include "Magnum/SampleQuery.h"
#include "Magnum/Renderbuffer.h" #include "Magnum/Renderbuffer.h"
#include "Magnum/RenderbufferFormat.h" #include "Magnum/RenderbufferFormat.h"
#include "Magnum/Shader.h" #include "Magnum/Shader.h"
@ -54,9 +58,31 @@ struct TransformFeedbackGLTest: AbstractOpenGLTester {
#ifndef MAGNUM_TARGET_GLES #ifndef MAGNUM_TARGET_GLES
void interleaved(); void interleaved();
void draw();
#endif #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() { TransformFeedbackGLTest::TransformFeedbackGLTest() {
addTests({&TransformFeedbackGLTest::construct, addTests({&TransformFeedbackGLTest::construct,
&TransformFeedbackGLTest::constructNoCreate, &TransformFeedbackGLTest::constructNoCreate,
@ -72,9 +98,13 @@ TransformFeedbackGLTest::TransformFeedbackGLTest() {
&TransformFeedbackGLTest::attachRanges, &TransformFeedbackGLTest::attachRanges,
#ifndef MAGNUM_TARGET_GLES #ifndef MAGNUM_TARGET_GLES
&TransformFeedbackGLTest::interleaved &TransformFeedbackGLTest::interleaved,
#endif #endif
}); });
#ifndef MAGNUM_TARGET_GLES
addInstancedTests({&TransformFeedbackGLTest::draw}, DrawDataCount);
#endif
} }
void TransformFeedbackGLTest::construct() { void TransformFeedbackGLTest::construct() {
@ -530,6 +560,140 @@ void TransformFeedbackGLTest::interleaved() {
CORRADE_COMPARE(data[3].y(), 3.0f); CORRADE_COMPARE(data[3].y(), 3.0f);
output.unmap(); output.unmap();
} }
void TransformFeedbackGLTest::draw() {
/* ARB_transform_feedback2 needed as base, other optional */
if(!Context::current().isExtensionSupported<Extensions::GL::ARB::transform_feedback2>())
CORRADE_SKIP(Extensions::GL::ARB::transform_feedback2::string() + std::string(" is not supported."));
if(DrawData[testCaseInstanceId()].stream && !Context::current().isExtensionSupported<Extensions::GL::ARB::transform_feedback3>())
CORRADE_SKIP(Extensions::GL::ARB::transform_feedback3::string() + std::string(" is not supported."));
if(DrawData[testCaseInstanceId()].instances && !Context::current().isExtensionSupported<Extensions::GL::ARB::transform_feedback_instanced>())
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<UnsignedInt>(), DrawData[testCaseInstanceId()].countStream0);
if(DrawData[testCaseInstanceId()].stream)
CORRADE_COMPARE(queryStreamN.result<UnsignedInt>(), 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<UnsignedInt>(), DrawData[testCaseInstanceId()].countDraw);
CORRADE_COMPARE(fb.read({{}, Vector2i{1}}, {PixelFormat::RGBA, PixelType::UnsignedByte}).data<UnsignedByte>()[0], 153);
MAGNUM_VERIFY_NO_ERROR();
}
#endif #endif
}} }}

Loading…
Cancel
Save