10.12., 9:00 - 11:00: Due to updates GitLab may be unavailable for some minutes between 09:00 and 11:00.

Refactoring pipeline concept #2: Got rid of distinguishing between...

Refactoring pipeline concept #2: Got rid of distinguishing between AbstractPipeline and VisualizationPipeline. Every AbstractPipeline is also a VisualizationPipeline. However, AbstractPipeline does not care about evaluating its components - this has to be implemented in its subclasses.
AutoEvaluationPipeline subclasses AbstractPipeline and automatically evaluates the pipeline by listening to the signals of its components and calling the corresponding process() methods.
parent 215b212e
......@@ -41,7 +41,7 @@
#include "core/datastructures/imagedata.h"
#include "core/datastructures/renderdata.h"
#include "core/pipeline/autoevaluationpipeline.h"
#include "core/pipeline/abstractpipeline.h"
#include "core/tools/job.h"
#include "core/tools/opengljobprocessor.h"
#include "core/tools/quadrenderer.h"
......@@ -49,7 +49,7 @@
namespace campvis {
const std::string CampVisPainter::loggerCat_ = "CAMPVis.core.CampVisPainter";
CampVisPainter::CampVisPainter(tgt::GLCanvas* canvas, AutoEvaluationPipeline* pipeline)
CampVisPainter::CampVisPainter(tgt::GLCanvas* canvas, AbstractPipeline* pipeline)
: Runnable()
, tgt::Painter(canvas)
, _pipeline(0)
......@@ -175,7 +175,7 @@ namespace campvis {
}
}
void CampVisPainter::setPipeline(AutoEvaluationPipeline* pipeline) {
void CampVisPainter::setPipeline(AbstractPipeline* pipeline) {
tgtAssert(pipeline != 0, "The given pipeline must not be 0.");
if (_pipeline != 0) {
_pipeline->s_renderTargetChanged.disconnect(this);
......
......@@ -44,16 +44,16 @@ namespace tgt {
}
namespace campvis {
class AutoEvaluationPipeline;
class AbstractPipeline;
/**
* Painter class for CAMPVis, rendering the render target of a AutoEvaluationPipeline.
* Painter class for CAMPVis, rendering the render target of an AbstractPipeline.
* This painter implements Runnable, hence, it runs in its own thread and the associated canvas
* must be of type QtThreadedCanvas.
* Rendering is implemented using condidional wait - hence the canvas is only updated when
* \a pipeline emits the s_RenderTargetChanged signal.
*
* \sa Runnable, AutoEvaluationPipeline
* \sa Runnable, AbstractPipeline
*/
class CampVisPainter : public Runnable, public tgt::Painter, public sigslot::has_slots<> {
public:
......@@ -62,7 +62,7 @@ namespace campvis {
* \param canvas Canvas to render on
* \param pipeline Pipeline to render
*/
CampVisPainter(tgt::GLCanvas* canvas, AutoEvaluationPipeline* pipeline);
CampVisPainter(tgt::GLCanvas* canvas, AbstractPipeline* pipeline);
/**
* Destructor, stops and waits for the rendering thread if it's still running.
......@@ -106,7 +106,7 @@ namespace campvis {
* Pipeline with the render target to render.
* \param pipeline Pipeline to render
*/
void setPipeline(AutoEvaluationPipeline* pipeline);
void setPipeline(AbstractPipeline* pipeline);
/**
* Slot being notified when the pipeline's render target changed.
......@@ -121,7 +121,7 @@ namespace campvis {
static const std::string loggerCat_;
AutoEvaluationPipeline* _pipeline; ///< Pipeline to render
AbstractPipeline* _pipeline; ///< Pipeline to render
tgt::Shader* _copyShader; ///< Shader for copying the render target to the framebuffer.
tbb::atomic<bool> _dirty; ///< Flag whether render result is dirty and needs to be rerendered.
std::condition_variable _renderCondition; ///< conditional wait condition for rendering
......
......@@ -30,32 +30,71 @@
#include "abstractpipeline.h"
#include "tgt/exception.h"
#include "tgt/glcanvas.h"
#include "tgt/glcontext.h"
#include "tgt/tgt_gl.h"
#include "core/pipeline/abstractprocessor.h"
#include "core/pipeline/visualizationprocessor.h"
#include "core/tools/job.h"
#include "core/tools/opengljobprocessor.h"
#include "core/tools/simplejobprocessor.h"
#include <ctime>
// Anonymous OpenGL helper functions
namespace {
GLboolean getGlBool(GLenum param) {
GLboolean toReturn;
glGetBooleanv(param, &toReturn);
return toReturn;
};
GLint getGlInt(GLenum param) {
GLint toReturn;
glGetIntegerv(param, &toReturn);
return toReturn;
};
GLfloat getGlFloat(GLenum param) {
GLfloat toReturn;
glGetFloatv(param, &toReturn);
return toReturn;
}
}
namespace campvis {
const std::string AbstractPipeline::loggerCat_ = "CAMPVis.core.datastructures.AbstractPipeline";
AbstractPipeline::AbstractPipeline()
: HasPropertyCollection()
, tgt::EventHandler()
, tgt::EventListener()
, _canvas(0)
, _canvasSize("CanvasSize", "Canvas Size", tgt::ivec2(128, 128), tgt::ivec2(1, 1), tgt::ivec2(4096, 4096))
, _ignoreCanvasSizeUpdate(false)
, _renderTargetID("renderTargetID", "Render Target ID", "AbstractPipeline.renderTarget", DataNameProperty::READ)
{
_enabled = true;
addProperty(&_renderTargetID);
addProperty(&_canvasSize);
}
AbstractPipeline::~AbstractPipeline() {
}
void AbstractPipeline::init() {
_renderTargetID.s_changed.connect<AbstractPipeline>(this, &AbstractPipeline::onPropertyChanged);
_data.s_dataAdded.connect(this, &AbstractPipeline::onDataContainerDataAdded);
initAllProperties();
// initialize all processors:
for (std::vector<AbstractProcessor*>::iterator it = _processors.begin(); it != _processors.end(); ++it) {
try {
(*it)->init();
(*it)->s_invalidated.connect(this, &AbstractPipeline::onProcessorInvalidated);
}
catch (tgt::Exception& e) {
LERROR("Caught Exception during initialization of processor: " << e.what());
......@@ -77,17 +116,27 @@ namespace campvis {
}
}
_data.s_dataAdded.disconnect(this);
_renderTargetID.s_changed.disconnect(this);
// clear DataContainer
_data.clear();
}
void AbstractPipeline::onPropertyChanged(const AbstractProperty* prop) {
if (prop == &_renderTargetID) {
s_renderTargetChanged();
}
else if (prop == &_canvasSize && _canvas != 0 && !_ignoreCanvasSizeUpdate) {
if (_canvasSize.getValue() != _canvas->getSize()) {
_ignoreCanvasSizeUpdate = true;
_canvas->setSize(_canvasSize.getValue());
_ignoreCanvasSizeUpdate = false;
}
}
else {
HasPropertyCollection::onPropertyChanged(prop);
}
void AbstractPipeline::onProcessorInvalidated(AbstractProcessor* processor) {
if (processor->getEnabled())
SimpleJobProc.enqueueJob(makeJob(this, &AbstractPipeline::executeProcessor, processor, false));
}
const DataContainer& AbstractPipeline::getDataContainer() const {
......@@ -153,6 +202,36 @@ namespace campvis {
_enabled = enabled;
}
void AbstractPipeline::onEvent(tgt::Event* e) {
// copy and paste from tgt::EventHandler::onEvent() but without deleting e
for (size_t i = 0 ; i < listeners_.size() ; ++i) {
// check if current listener listens to the eventType of e
if(listeners_[i]->getEventTypes() & e->getEventType() ){
listeners_[i]->onEvent(e);
if (e->isAccepted())
break;
}
}
}
void AbstractPipeline::setCanvas(tgt::GLCanvas* canvas) {
_canvas = canvas;
}
void AbstractPipeline::setRenderTargetSize(const tgt::ivec2& size) {
if (_canvasSize.getValue() != size && !_ignoreCanvasSizeUpdate) {
_canvasSize.setValue(size);
}
}
const tgt::ivec2& AbstractPipeline::getRenderTargetSize() const {
return _canvasSize.getValue();
}
const std::string& AbstractPipeline::getRenderTargetID() const {
return _renderTargetID.getValue();
}
void AbstractPipeline::addProcessor(AbstractProcessor* processor) {
tgtAssert(processor != 0, "Processor must not be 0.")
_processors.push_back(processor);
......@@ -168,5 +247,44 @@ namespace campvis {
(*it)->unlockProcessor();
}
void AbstractPipeline::lockGLContextAndExecuteProcessor(AbstractProcessor* processor) {
tgtAssert(_canvas != 0, "Set a valid canvas before calling this method!");
GLJobProc.enqueueJob(
_canvas,
makeJobOnHeap<AbstractPipeline, AbstractProcessor*, bool>(this, &AbstractPipeline::executeProcessor, processor, true),
OpenGLJobProcessor::SerialJob);
}
void AbstractPipeline::executeProcessorAndCheckOpenGLState(AbstractProcessor* processor) {
AbstractPipeline::executeProcessor(processor, true);
#ifdef CAMPVIS_DEBUG
tgtAssert(getGlBool(GL_DEPTH_TEST) == false, "Invalid OpenGL state after processor execution, GL_DEPTH_TEST != false.");
tgtAssert(getGlBool(GL_SCISSOR_TEST) == false, "Invalid OpenGL state after processor execution, GL_SCISSOR_TEST != false.");
tgtAssert(getGlInt(GL_CULL_FACE_MODE) == GL_BACK, "Invalid OpenGL state after processor execution, GL_CULL_FACE_MODE != GL_BACk.");
tgtAssert(getGlInt(GL_DEPTH_FUNC) == GL_LESS, "Invalid OpenGL state after processor execution, GL_DEPTH_FUNC != GL_LESS.");
tgtAssert(getGlFloat(GL_DEPTH_CLEAR_VALUE) == 1.f, "Invalid OpenGL state after processor execution, GL_DEPTH_CLEAR_VALUE != 1.f.");
tgtAssert(getGlFloat(GL_RED_SCALE) == 1.f, "Invalid OpenGL state after processor execution, GL_RED_SCALE != 1.f.");
tgtAssert(getGlFloat(GL_GREEN_SCALE) == 1.f, "Invalid OpenGL state after processor execution, GL_GREEN_SCALE != 1.f.");
tgtAssert(getGlFloat(GL_BLUE_SCALE) == 1.f, "Invalid OpenGL state after processor execution, GL_BLUE_SCALE != 1.f.");
tgtAssert(getGlFloat(GL_ALPHA_SCALE) == 1.f, "Invalid OpenGL state after processor execution, GL_ALPHA_SCALE != 1.f.");
tgtAssert(getGlFloat(GL_RED_BIAS) == 0.f, "Invalid OpenGL state after processor execution, GL_RED_BIAS != 0.f.");
tgtAssert(getGlFloat(GL_GREEN_BIAS) == 0.f, "Invalid OpenGL state after processor execution, GL_GREEN_BIAS != 0.f.");
tgtAssert(getGlFloat(GL_BLUE_BIAS) == 0.f, "Invalid OpenGL state after processor execution, GL_BLUE_BIAS != 0.f.");
tgtAssert(getGlFloat(GL_ALPHA_BIAS) == 0.f, "Invalid OpenGL state after processor execution, GL_ALPHA_BIAS != 0.f.");
#endif
}
void AbstractPipeline::onDataContainerDataAdded(const std::string& name, const DataHandle& dh) {
if (name == _renderTargetID.getValue()) {
s_renderTargetChanged();
}
}
}
......@@ -31,28 +31,38 @@
#define ABSTRACTPIPELINE_H__
#include "sigslot/sigslot.h"
#include "tgt/logmanager.h"
#include "tgt/vector.h"
#include "tgt/event/eventhandler.h"
#include "tgt/event/eventlistener.h"
#include "tbb/spin_mutex.h"
#include "tbb/mutex.h"
#include "core/datastructures/datacontainer.h"
#include "core/properties/datanameproperty.h"
#include "core/properties/floatingpointproperty.h"
#include "core/properties/propertycollection.h"
#include <vector>
namespace tgt {
class GLCanvas;
}
namespace campvis {
class AbstractProcessor;
class PipelineEvaluator;
/**
* Abstract base class for CAMPVis Pipelines.
*
*/
class AbstractPipeline : public HasPropertyCollection {
friend class PipelineEvaluator;
class AbstractPipeline : public HasPropertyCollection, public tgt::EventHandler, public tgt::EventListener {
public:
/**
* Creates a AbstractPipeline.
* If you derive from AbstractPipeline, you will have to implement the pipeline evaluation
* logic yourself. You might want to have a look at AutoEvaluationPipeline.
*/
AbstractPipeline();
......@@ -61,21 +71,50 @@ namespace campvis {
**/
virtual ~AbstractPipeline();
/**
* Gets the name of this very pipeline. To be defined by every subclass.
* \return The name of this pipeline.
*/
virtual const std::string getName() const = 0;
/**
* Initializes this pipeline and all of its processors.
* Everything that requires a valid OpenGL context or is otherwise expensive gets in here.
* Initializes this pipeline, its OpenGL context and all of its processors.
* Everything that requires a valid OpenGL context, valid construction of all other
* processors/properties or is otherwise expensive gets in here.
*
* \note Must be called with a valid and locked OpenGL context.
* \note When overwriting this method, make sure to call the base class version first.
*/
virtual void init();
/**
* Deinitializes this pipeline and all of its processors.
* Deinitializes this pipeline, its OpenGL context and all of its processors.
* Everything that requires a valid OpenGL context, cannont be executed during destruction
* or is otherwise expensive gets in here.
*
* \note Must be called with a valid and locked OpenGL context.
* \note When overwriting this method, make sure to call the base class version first.
*/
virtual void deinit();
/**
* Adds the processor \a processor to this pipeline's processor list.
* \note The s_invalidated signal of each processor on this list will be automatically
* connected to onProcessorInvalidated() during initialization and disconnected
* during deinitialization.
* \param processor The processor to add.
*/
virtual void addProcessor(AbstractProcessor* processor);
/**
* Performs the event handling for the assigned canvas.
* Default behaviour is to execute all assigned EventHandlers, may be overwritten by subclasses.
* \param e event parameters
*/
virtual void onEvent(tgt::Event* e);
/**
* Returns the DataContainer of this pipeline, const version.
* \return _data
......@@ -88,27 +127,12 @@ namespace campvis {
*/
DataContainer& getDataContainer();
/**
* Adds the processor \a processor to this pipeline's processor list.
* \note The s_invalidated signal of each processor on this list will be automatically
* connected to onProcessorInvalidated() during initialization and disconnected
* during deinitialization.
* \param processor The processor to add.
*/
void addProcessor(AbstractProcessor* processor);
/**
* Returns the list of processors of this pipeline.
* \return _processors
*/
const std::vector<AbstractProcessor*>& getProcessors() const;
/**
* Gets the name of this very pipeline. To be defined by every subclass.
* \return The name of this pipeline.
*/
virtual const std::string getName() const = 0;
/**
* Gets the flag whether this pipeline is currently enabled.
* \return _enabled
......@@ -121,6 +145,34 @@ namespace campvis {
*/
void setEnabled(bool enabled);
/**
* Sets the Canvas hosting the OpenGL context for this pipeline.
* \param canvas Canvas hosting the OpenGL context for this pipeline
*/
void setCanvas(tgt::GLCanvas* canvas);
/**
* Sets the size of the render target
* \param size New viewport dimensions
*/
void setRenderTargetSize(const tgt::ivec2& size);
/**
* Returns the viewport size of the target canvas
* \return _canvasSize
*/
const tgt::ivec2& getRenderTargetSize() const;
/**
* Returns the ID of the render target image to be rendered to the canvas
* \return The DataHandle named _renderTargetID in the pipeline's DataContainer, 0 if no such handle exists.
*/
const std::string& getRenderTargetID() const;
/// Signal emitted when the pipeline's render target has changed
sigslot::signal0<> s_renderTargetChanged;
protected:
/**
* Locks all processors.
......@@ -133,25 +185,32 @@ namespace campvis {
void unlockAllProcessors();
/**
* Slot getting called when one of the observed properties changed and notifies its observers.
* The default behaviour is just to set the invalidation level to invalid.
* \param prop Property that emitted the signal
* Executes the processor \a processor on the pipeline's data and locks its properties meanwhile.
* \param processor Processor to execute.
* \param unlockInExtraThred If true, the call to processor->unlock() will be done in an extra thread.
*/
virtual void onPropertyChanged(const AbstractProperty* prop);
void executeProcessor(AbstractProcessor* processor, bool unlockInExtraThred);
/**
* Slot getting called when one of the observed processors got invalidated.
* The default behaviour is to dispatch a job to execute the invalidated processor and emit the s_invalidated signal.
* \param processor The processor that emitted the signal
* Acquires and locks the OpenGL context, executes the processor \a processor on the pipeline's data
* and locks its properties meanwhile.
* \param processor Processor to execute.
*/
virtual void onProcessorInvalidated(AbstractProcessor* processor);
void lockGLContextAndExecuteProcessor(AbstractProcessor* processor);
/**
* Executes the processor \a processor on the pipeline's data and locks its properties meanwhile.
* \param processor Processor to execute.
* \param unlockInExtraThred If true, the call to processor->unlock() will be done in an extra thread.
* Executes \a processor and afterwards checks the OpenGL state to be valid.
* \note Only call from with a valid OpenGL context
* \param processor Processor to execute
*/
void executeProcessor(AbstractProcessor* processor, bool unlockInExtraThred);
void executeProcessorAndCheckOpenGLState(AbstractProcessor* processor);
/**
* Slot getting called when one of the observed properties changed and notifies its observers.
* The default behaviour is just to set the invalidation level to invalid.
* \param prop Property that emitted the signal
*/
virtual void onPropertyChanged(const AbstractProperty* prop);
DataContainer _data; ///< DataContainer containing local working set of data for this Pipeline
......@@ -159,9 +218,24 @@ namespace campvis {
std::vector<AbstractProcessor*> _processors; ///< List of all processors of this pipeline
tbb::atomic<bool> _enabled; ///< flag whether this pipeline is currently enabled
//tbb::spin_mutex _localMutex; ///< mutex for altering local members
tgt::GLCanvas* _canvas; ///< Canvas hosting the OpenGL context for this pipeline.
IVec2Property _canvasSize; ///< original canvas size
bool _ignoreCanvasSizeUpdate;
DataNameProperty _renderTargetID; ///< ID of the render target image to be rendered to the canvas
static const std::string loggerCat_;
private:
/**
* Gets called when the data collection of this pipeline has changed and thus has notified its observers.
* If \a name equals the name of the renderTarget, the s_renderTargetChanged signal will be emitted.
* \param name Name of the added data.
* \param dh DataHandle to the newly added data.
*/
void onDataContainerDataAdded(const std::string& name, const DataHandle& dh);
};
}
......
......@@ -36,114 +36,33 @@
#include "core/tools/opengljobprocessor.h"
#include "core/tools/simplejobprocessor.h"
namespace {
GLboolean getGlBool(GLenum param) {
GLboolean toReturn;
glGetBooleanv(param, &toReturn);
return toReturn;
};
GLint getGlInt(GLenum param) {
GLint toReturn;
glGetIntegerv(param, &toReturn);
return toReturn;
};
GLfloat getGlFloat(GLenum param) {
GLfloat toReturn;
glGetFloatv(param, &toReturn);
return toReturn;
}
}
namespace campvis {
const std::string AutoEvaluationPipeline::loggerCat_ = "CAMPVis.core.datastructures.AutoEvaluationPipeline";
AutoEvaluationPipeline::AutoEvaluationPipeline()
: AbstractPipeline()
, tgt::EventHandler()
, tgt::EventListener()
, _ignoreCanvasSizeUpdate(false)
, _canvasSize("CanvasSize", "Canvas Size", tgt::ivec2(128, 128), tgt::ivec2(1, 1), tgt::ivec2(4096, 4096))
, _renderTargetID("renderTargetID", "Render Target ID", "AutoEvaluationPipeline.renderTarget", DataNameProperty::READ)
, _canvas(0)
{
_data.s_dataAdded.connect(this, &AutoEvaluationPipeline::onDataContainerDataAdded);
addProperty(&_renderTargetID);
addProperty(&_canvasSize);
_renderTargetID.s_changed.connect<AutoEvaluationPipeline>(this, &AutoEvaluationPipeline::onPropertyChanged);
}
AutoEvaluationPipeline::~AutoEvaluationPipeline() {
}
void AutoEvaluationPipeline::onEvent(tgt::Event* e) {
// copy and paste from tgt::EventHandler::onEvent() but without deleting e
for (size_t i = 0 ; i < listeners_.size() ; ++i) {
// check if current listener listens to the eventType of e
if(listeners_[i]->getEventTypes() & e->getEventType() ){
listeners_[i]->onEvent(e);
if (e->isAccepted())
break;
}
}
}
void AutoEvaluationPipeline::init() {
AbstractPipeline::init();
}
void AutoEvaluationPipeline::deinit() {
_data.s_dataAdded.disconnect(this);
_renderTargetID.s_changed.disconnect(this);
AbstractPipeline::deinit();
}
const tgt::ivec2& AutoEvaluationPipeline::getRenderTargetSize() const {
return _canvasSize.getValue();
}
void AutoEvaluationPipeline::setRenderTargetSize(const tgt::ivec2& size) {
if (_canvasSize.getValue() != size && !_ignoreCanvasSizeUpdate) {
_canvasSize.setValue(size);
}
}
void AutoEvaluationPipeline::onDataContainerDataAdded(const std::string& name, const DataHandle& dh) {
if (name == _renderTargetID.getValue()) {
s_renderTargetChanged();
// connect invalidation of each processor
for (std::vector<AbstractProcessor*>::iterator it = _processors.begin(); it != _processors.end(); ++it) {
(*it)->s_invalidated.connect(this, &AutoEvaluationPipeline::onProcessorInvalidated);
}
}
const std::string& AutoEvaluationPipeline::getRenderTargetID() const {
return _renderTargetID.getValue();
}
void AutoEvaluationPipeline::lockGLContextAndExecuteProcessor(AbstractProcessor* processor) {
tgtAssert(_canvas != 0, "Set a valid canvas before calling this method!");
GLJobProc.enqueueJob(
_canvas,
makeJobOnHeap<AutoEvaluationPipeline, AbstractProcessor*, bool>(this, &AutoEvaluationPipeline::executeProcessor, processor, true),
OpenGLJobProcessor::SerialJob);
}
void AutoEvaluationPipeline::setCanvas(tgt::GLCanvas* canvas) {
_canvas = canvas;
void AutoEvaluationPipeline::deinit() {
for (std::vector<AbstractProcessor*>::iterator it = _processors.begin(); it != _processors.end(); ++it) {
(*it)->s_invalidated.disconnect(this);
}
void AutoEvaluationPipeline::onPropertyChanged(const AbstractProperty* prop) {
if (prop == &_renderTargetID)
s_renderTargetChanged();
else if (prop == &_canvasSize && _canvas != 0 && !_ignoreCanvasSizeUpdate) {
if (_canvasSize.getValue() != _canvas->getSize()) {
_ignoreCanvasSizeUpdate = true;
_canvas->setSize(_canvasSize.getValue());
_ignoreCanvasSizeUpdate = false;
}
}
else
AbstractPipeline::onPropertyChanged(prop);
AbstractPipeline::deinit();
}
void AutoEvaluationPipeline::onProcessorInvalidated(AbstractProcessor* processor) {
......@@ -174,28 +93,4 @@ namespace campvis {
AbstractPipeline::addProcessor(processor);
}
void AutoEvaluationPipeline::executeProcessorAndCheckOpenGLState(AbstractProcessor* processor) {
AbstractPipeline::executeProcessor(processor, true);
#ifdef CAMPVIS_DEBUG
tgtAssert(getGlBool(GL_DEPTH_TEST) == false, "Invalid OpenGL state after processor execution, GL_DEPTH_TEST != false.");
tgtAssert(getGlBool(GL_SCISSOR_TEST) == false, "Invalid OpenGL state after processor execution, GL_SCISSOR_TEST != false.");
tgtAssert(getGlInt(GL_CULL_FACE_MODE) == GL_BACK, "Invalid OpenGL state after processor execution, GL_CULL_FACE_MODE != GL_BACk.");
tgtAssert(getGlInt(GL_DEPTH_FUNC) == GL_LESS, "Invalid OpenGL state after processor execution, GL_DEPTH_FUNC != GL_LESS.");
tgtAssert(getGlFloat(GL_DEPTH_CLEAR_VALUE) == 1.f, "Invalid OpenGL state after processor execution, GL_DEPTH_CLEAR_VALUE != 1.f.");
tgtAssert(getGlFloat(GL_RED_SCALE) == 1.f, "Invalid OpenGL state after processor execution, GL_RED_SCALE != 1.f.");
tgtAssert(getGlFloat(GL_GREEN_SCALE) == 1.f, "Invalid OpenGL state after processor execution, GL_GREEN_SCALE != 1.f.");
tgtAssert(getGlFloat(GL_BLUE_SCALE) == 1.f, "Invalid OpenGL state after processor execution, GL_BLUE_SCALE != 1.f.");
tgtAssert(getGlFloat(GL_ALPHA_SCALE) == 1.f, "Invalid OpenGL state after processor execution, GL_ALPHA_SCALE != 1.f.");
tgtAssert(getGlFloat(GL_RED_BIAS) == 0.f, "Invalid OpenGL state after processor execution, GL_RED_BIAS != 0.f.");
tgtAssert(getGlFloat(GL_GREEN_BIAS) == 0.f, "Invalid OpenGL state after processor execution, GL_GREEN_BIAS != 0.f.");
tgtAssert(getGlFloat(GL_BLUE_BIAS) == 0.f, "Invalid OpenGL state after processor execution, GL_BLUE_BIAS != 0.f.");
tgtAssert(getGlFloat(GL_ALPHA_BIAS) == 0.f, "Invalid OpenGL state after processor execution, GL_ALPHA_BIAS != 0.f.");
#endif
}