Browse Source

Classes for querying primitive count, passed sample count etc.

vectorfields
Vladimír Vondruš 14 years ago
parent
commit
74449f8e13
  1. 1
      src/CMakeLists.txt
  2. 82
      src/Query.cpp
  3. 272
      src/Query.h

1
src/CMakeLists.txt

@ -17,6 +17,7 @@ set(Magnum_SRCS
IndexedMesh.cpp
Light.cpp
Mesh.cpp
Query.cpp
Renderbuffer.cpp
Scene.cpp
Shader.cpp

82
src/Query.cpp

@ -0,0 +1,82 @@
/*
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz>
This file is part of Magnum.
Magnum is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 3
only, as published by the Free Software Foundation.
Magnum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License version 3 for more details.
*/
#include "Query.h"
namespace Magnum {
bool AbstractQuery::resultAvailable() {
GLuint result;
glGetQueryObjectuiv(query, GL_QUERY_RESULT_AVAILABLE, &result);
return result == GL_TRUE;
}
template<> bool AbstractQuery::result<bool>() {
GLuint result;
glGetQueryObjectuiv(query, GL_QUERY_RESULT, &result);
return result == GL_TRUE;
}
template<> GLuint AbstractQuery::result<GLuint>() {
GLuint result;
glGetQueryObjectuiv(query, GL_QUERY_RESULT, &result);
return result;
}
template<> GLint AbstractQuery::result<GLint>() {
GLint result;
glGetQueryObjectiv(query, GL_QUERY_RESULT, &result);
return result;
}
template<> GLuint64 AbstractQuery::result<GLuint64>() {
GLuint64 result;
glGetQueryObjectui64v(query, GL_QUERY_RESULT, &result);
return result;
}
template<> GLint64 AbstractQuery::result<GLint64>() {
GLint64 result;
glGetQueryObjecti64v(query, GL_QUERY_RESULT, &result);
return result;
}
void Query::begin(Query::Target target) {
glBeginQuery(static_cast<GLenum>(target), query);
this->target = new Target(target);
}
void Query::end() {
if(!target) return;
glEndQuery(static_cast<GLenum>(*target));
delete target;
target = 0;
}
void SampleQuery::begin(SampleQuery::Target target) {
glBeginQuery(static_cast<GLenum>(target), query);
this->target = new Target(target);
}
void SampleQuery::end() {
if(!target) return;
glEndQuery(static_cast<GLenum>(*target));
delete target;
target = 0;
}
}

272
src/Query.h

@ -0,0 +1,272 @@
#ifndef Magnum_Query_h
#define Magnum_Query_h
/*
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz>
This file is part of Magnum.
Magnum is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 3
only, as published by the Free Software Foundation.
Magnum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License version 3 for more details.
*/
/** @file
* @brief Class Magnum::AbstractQuery, Magnum::Query, Magnum::SampleQuery, Magnum::TimeQuery
*/
#include "Magnum.h"
namespace Magnum {
/**
@brief Base class for queries
See Query, SampleQuery, TimeQuery documentation for more information.
*/
class MAGNUM_EXPORT AbstractQuery {
public:
/**
* @brief Constructor
*
* Generates one OpenGL query.
*/
inline AbstractQuery() { glGenQueries(1, &query); }
/**
* @brief Destructor
*
* Deletes assigned OpenGL query.
*/
virtual inline ~AbstractQuery() { glDeleteQueries(1, &query); }
/**
* @brief Whether the result is available
*/
bool resultAvailable();
/**
* @brief Result
* @tparam T Result type. Can be either `bool`, `GLuint`,
* `GLint`, `GLuint64` or `GLint64`.
*
* Note that this function is blocking until the result is available.
* See resultAvailable().
*/
template<class T> T result() = delete;
protected:
GLuint query; /**< @brief OpenGL internal query ID */
};
#ifndef DOXYGEN_GENERATING_OUTPUT
template<> bool MAGNUM_EXPORT AbstractQuery::result<bool>();
template<> GLuint MAGNUM_EXPORT AbstractQuery::result<GLuint>();
template<> GLint MAGNUM_EXPORT AbstractQuery::result<GLint>();
template<> GLuint64 MAGNUM_EXPORT AbstractQuery::result<GLuint64>();
template<> GLint64 MAGNUM_EXPORT AbstractQuery::result<GLint64>();
#endif
/**
@brief %Query for primitives and elapsed time
Queries count of generated primitives from vertex shader, geometry shader or
transform feedback and elapsed time. Example usage:
@code
Query q;
q.begin(Query::Target::PrimitivesGenerated);
// rendering...
q.end();
if(!q.resultAvailable()) {
// do some work until to give OpenGL some time...
}
// ...or block until the result is available
GLuint primitiveCount = q.result<GLuint>();
@endcode
*/
class MAGNUM_EXPORT Query: public AbstractQuery {
public:
/** @brief %Query target */
enum Target: GLenum {
/**
* Count of primitives generated from vertex shader or geometry
* shader.
*/
PrimitivesGenerated = GL_PRIMITIVES_GENERATED,
/** Count of primitives written to transform feedback buffer. */
TransformFeedbackPrimitivesWritten = GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN,
/** Elapsed time */
TimeElapsed = GL_TIME_ELAPSED
};
inline Query(): target(nullptr) {}
inline ~Query() { delete target; }
/**
* @brief Begin query
*
* Begins counting of given @p target until end() is called.
*/
void begin(Target target);
/**
* @brief End query
*
* The result can be then retrieved by calling result().
*/
void end();
private:
Target* target;
};
/**
@brief %Query for samples
Queries count of samples passed from fragment shader or boolean value
indicating whether any samples passed. Can be used for example for conditional
rendering:
@code
SampleQuery q;
q.begin(SampleQuery::Target::AnySamplesPassed);
// render simplified object to test whether it is visible at all...
q.end();
// render full version of the object only if it is visible
if(q.result<bool>()) {
// ...
}
@endcode
This approach has some drawbacks, as the rendering is blocked until result is
available for the CPU to decide. This can be improved by using conditional
rendering on GPU itself. The drawing commands will be sent to the GPU and
processed or discarded later, so CPU can continue executing the code without
waiting for the result.
@code
SampleQuery q;
q.begin(SampleQuery::Target::AnySamplesPassed);
// render simplified object to test whether it is visible at all...
q.end();
q.beginConditionalRender(SampleQuery::ConditionalRenderMode::Wait);
// render full version of the object only if the query returns nonzero result
q.endConditionalRender();
@endcode
*/
class MAGNUM_EXPORT SampleQuery: public AbstractQuery {
public:
/** @brief %Query target */
enum Target: GLenum {
/** Count of samples passed from fragment shader */
SamplesPassed = GL_SAMPLES_PASSED,
/** Whether any samples passed from fragment shader */
AnySamplesPassed = GL_ANY_SAMPLES_PASSED
};
/** @brief Conditional render mode */
enum class ConditionalRenderMode: GLenum {
/**
* If query result is not yet available, waits for it and
* then begins conditional rendering based on result value.
*/
Wait = GL_QUERY_WAIT,
/**
* If query result is not yet available, OpenGL may begin
* rendering like if the result value was nonzero.
*/
NoWait = GL_QUERY_NO_WAIT,
/**
* The same as Wait, but regions untouched by the sample query may
* not be rendered at all.
*/
ByRegionWait = GL_QUERY_BY_REGION_WAIT,
/**
* The same as NoWait, but regions untouched by the sample query
* may not be rendered at all.
*/
ByRegionNoWait = GL_QUERY_BY_REGION_NO_WAIT
};
inline SampleQuery(): target(nullptr) {}
inline ~SampleQuery() { delete target; }
/** @copydoc Query::begin() */
void begin(Target target);
/** @copydoc Query::end() */
void end();
/** @brief Begin conditional rendering based on result value */
inline void beginConditionalRender(ConditionalRenderMode mode) {
glBeginConditionalRender(query, static_cast<GLenum>(mode));
}
/** @brief End conditional render */
inline void endConditionalRender() {
glEndConditionalRender();
}
private:
Target* target;
};
/**
@brief %Query for elapsed time
Queries timestamp after all previous OpenGL calls have been processed. It is
similar to Query::Target::TimeElapsed query, but this query just retrieves
timestamp, not time duration between Query::begin() and Query::end() calls.
Example usage, compared to Query::Target::TimeElapsed:
@code
Query q1, q2;
q1.begin(Query::Target::TimeElapsed);
// rendering...
q1.end();
q2.begin(Query::Target::TimeElapsed);
// another rendering...
q2.end();
GLuint timeElapsed1 = q1.result<GLuint>();
GLuint timeElapsed2 = q2.result<GLuint>();
@endcode
@code
TimeQuery q1, q2, q3;
q1.timestamp();
// rendering...
q2.timestamp();
// another rendering...
q3.timestamp();
GLuint tmp = q2.result<GLuint>();
GLuint timeElapsed1 = tmp-q1.result<GLuint>();
GLuint timeElapsed2 = q3.result<GLuint>()-tmp;
@endcode
Using this query results in fewer OpenGL calls when doing more measures.
*/
class TimeQuery: public AbstractQuery {
public:
/** @brief Query timestamp */
inline void timestamp() {
glQueryCounter(query, GL_TIMESTAMP);
}
};
}
#endif
Loading…
Cancel
Save