Commit 3541659a authored by Robert Menzel's avatar Robert Menzel
Browse files

Added more error checks, comments, minor bugfixes

* Added additional OpenGL error checks
* OpenGL error checks are better usable with namespaces
* Removed checks for OpenGL objects == 0 which would get ignored by OpenGL anyway and are rare
* Added comments
* improved OpenGL ES compatibility
parent d53f361c
...@@ -32,7 +32,7 @@ inline GLint getGLTypeSize ( GLenum _type ) ...@@ -32,7 +32,7 @@ inline GLint getGLTypeSize ( GLenum _type )
// for every OpenGL error enum this will return a human readable version of it // for every OpenGL error enum this will return a human readable version of it
// similar to gluErrorString, but that function is not available on all plattforms // similar to gluErrorString, but that function is not available on all plattforms
// (read: iOS) // (read: iOS)
const GLubyte* acglErrorString( GLenum err ); const GLubyte* acglErrorString( GLenum _errorCode );
/* /*
* This function can be used outside of the ACGL framework to check always(!) for * This function can be used outside of the ACGL framework to check always(!) for
...@@ -83,31 +83,34 @@ GLenum openGLError_( const char *_fileName, const unsigned long _lineNumber ); ...@@ -83,31 +83,34 @@ GLenum openGLError_( const char *_fileName, const unsigned long _lineNumber );
* same defines, this can be used in application code as well. * same defines, this can be used in application code as well.
* *
*/ */
inline GLenum openGLErrorDummy() { return GL_NO_ERROR; }
inline bool openGLErrorOccuredDummy() { return false; }
#ifdef ACGL_CHECK_CRITICAL_GL_ERRORS #ifdef ACGL_CHECK_CRITICAL_GL_ERRORS
# define openGLCriticalError() openGLError_( __FILE__, __LINE__ ) # define openGLCriticalError() ACGL::GLUtils::Tools::openGLError_( __FILE__, __LINE__ )
# define openGLCriticalErrorOccured() (openGLError_( __FILE__, __LINE__ ) != GL_NO_ERROR) # define openGLCriticalErrorOccured() (ACGL::GLUtils::Tools::openGLError_( __FILE__, __LINE__ ) != GL_NO_ERROR)
#else #else
inline GLenum openGLCriticalError() { return GL_NO_ERROR; } # define openGLCriticalError() ACGL::GLUtils::Tools::openGLErrorDummy()
inline bool openGLCriticalErrorOccured() { return false; } # define openGLCriticalErrorOccured() ACGL::GLUtils::Tools::openGLErrorOccuredDummy()
#endif #endif
#ifdef ACGL_CHECK_COMMON_GL_ERRORS #ifdef ACGL_CHECK_COMMON_GL_ERRORS
# define openGLCommonError() openGLError_( __FILE__, __LINE__ ) # define openGLCommonError() ACGL::GLUtils::Tools::openGLError_( __FILE__, __LINE__ )
# define openGLCommonErrorOccured() (openGLError_( __FILE__, __LINE__ ) != GL_NO_ERROR) # define openGLCommonErrorOccured() (ACGL::GLUtils::Tools::openGLError_( __FILE__, __LINE__ ) != GL_NO_ERROR)
#else #else
inline GLenum openGLCommonError() { return GL_NO_ERROR; } # define openGLCommonError() ACGL::GLUtils::Tools::openGLErrorDummy()
inline bool openGLCommonErrorOccured() { return false; } # define openGLCommonErrorOccured() ACGL::GLUtils::Tools::openGLErrorOccuredDummy()
#endif #endif
#ifdef ACGL_CHECK_RARE_GL_ERRORS #ifdef ACGL_CHECK_RARE_GL_ERRORS
# define openGLRareError() openGLError_( __FILE__, __LINE__ ) # define openGLRareError() ACGL::GLUtils::Tools::openGLError_( __FILE__, __LINE__ )
# define openGLRareErrorOccured() (openGLError_( __FILE__, __LINE__ ) != GL_NO_ERROR) # define openGLRareErrorOccured() (ACGL::GLUtils::Tools::openGLError_( __FILE__, __LINE__ ) != GL_NO_ERROR)
#else #else
inline GLenum openGLRareError() { return GL_NO_ERROR; } # define openGLRareError() ACGL::GLUtils::Tools::openGLErrorDummy()
inline bool openGLRareErrorOccured() { return false; } # define openGLRareErrorOccured() ACGL::GLUtils::Tools::openGLErrorOccuredDummy()
#endif #endif
} // Tools } // Tools
} // GLUtils } // GLUtils
} // ACGL } // ACGL
......
...@@ -52,12 +52,15 @@ public: ...@@ -52,12 +52,15 @@ public:
mAttributes() mAttributes()
{ {
glGenBuffers(1, &mContext); glGenBuffers(1, &mContext);
if (openGLCriticalErrorOccured() ) {
ACGL::Utils::error() << "could not generate array buffer!" << std::endl;
}
} }
virtual ~ArrayBuffer(void) virtual ~ArrayBuffer(void)
{ {
if(mContext != 0) // buffer 0 will get ignored by OpenGL
glDeleteBuffers(1, &mContext); glDeleteBuffers(1, &mContext);
} }
// ==================================================================================================== \/ // ==================================================================================================== \/
......
...@@ -30,12 +30,16 @@ public: ...@@ -30,12 +30,16 @@ public:
mSizeOfType(GLUtils::Tools::getGLTypeSize(_type)) mSizeOfType(GLUtils::Tools::getGLTypeSize(_type))
{ {
glGenBuffers(1, &mContext); glGenBuffers(1, &mContext);
if (openGLCriticalErrorOccured() ) {
ACGL::Utils::error() << "could not generate element array buffer!" << std::endl;
}
} }
virtual ~ElementArrayBuffer(void) virtual ~ElementArrayBuffer(void)
{ {
if(mContext != 0) // buffer 0 will get ignored by OpenGL
glDeleteBuffers(1, &mContext); glDeleteBuffers(1, &mContext);
} }
// ==================================================================================================== \/ // ==================================================================================================== \/
......
...@@ -6,12 +6,30 @@ ...@@ -6,12 +6,30 @@
#ifndef ACGL_RESOURCE_FRAMEBUFFER_HH #ifndef ACGL_RESOURCE_FRAMEBUFFER_HH
#define ACGL_RESOURCE_FRAMEBUFFER_HH #define ACGL_RESOURCE_FRAMEBUFFER_HH
/*
* This FrameBuffer class encapsulates an OpenGL frame buffer object (FBO).
* A FrameBuffer is a target for rendering and thus consists of different "layers":
*
* one or no depthbuffer
* one or no stencilbuffer
* one (OpenGL ES) to many (hardware dependent limit) colorbuffers
*
* These buffers get attached to the FrameBuffer.
*
* There exists one system-provided frame buffer object for rendering to the screen
* and optionaly multiple user defined frame buffer objects for offscreen rendering.
*
* This class does not encapsulate the system-provided FBO.
*/
#include <ACGL/ACGL.hh>
#include <ACGL/Resource/ResourceTypes.hh> #include <ACGL/Resource/ResourceTypes.hh>
#include <ACGL/Resource/RenderBuffer.hh> #include <ACGL/Resource/RenderBuffer.hh>
#include <ACGL/Resource/Texture.hh> #include <ACGL/Resource/Texture.hh>
#include <ACGL/Utils/Log.hh> #include <ACGL/Utils/Log.hh>
#include <ACGL/Utils/StringOperations.hh> #include <ACGL/Utils/StringOperations.hh>
#include <ACGL/GL.hh> #include <ACGL/GL.hh>
#include <ACGL/GLUtils/Tools.hh>
namespace ACGL{ namespace ACGL{
namespace Resource{ namespace Resource{
...@@ -36,6 +54,14 @@ public: ...@@ -36,6 +54,14 @@ public:
SharedRenderBuffer renderBuffer; SharedRenderBuffer renderBuffer;
}; };
// Per default an FBO is used for reading (glReadPixels etc) and drawing (glDraw*) but a
// read-only/draw-only setup is also possible.
enum TargetType {
READ_FRAMEBUFFER = GL_READ_FRAMEBUFFER,
DRAW_FRAMEBUFFER = GL_DRAW_FRAMEBUFFER,
READ_DRAW_FRAMEBUFFER = GL_FRAMEBUFFER
};
// ===================================================================================================== \/ // ===================================================================================================== \/
// ============================================================================================ TYPEDEFS \/ // ============================================================================================ TYPEDEFS \/
// ===================================================================================================== \/ // ===================================================================================================== \/
...@@ -55,6 +81,10 @@ public: ...@@ -55,6 +81,10 @@ public:
mDepthAttachment() mDepthAttachment()
{ {
glGenFramebuffers(1, &mContext); glGenFramebuffers(1, &mContext);
if (openGLCriticalErrorOccured() ) {
ACGL::Utils::error() << "could not generate framebuffer!" << std::endl;
return;
}
mDepthAttachment.name = ""; mDepthAttachment.name = "";
mDepthAttachment.texture = SharedTexture(); mDepthAttachment.texture = SharedTexture();
mDepthAttachment.renderBuffer = SharedRenderBuffer(); mDepthAttachment.renderBuffer = SharedRenderBuffer();
...@@ -62,8 +92,8 @@ public: ...@@ -62,8 +92,8 @@ public:
virtual ~FrameBuffer(void) virtual ~FrameBuffer(void)
{ {
if(mContext != 0) // buffer 0 will get ignored by OpenGL
glDeleteFramebuffers(1, &mContext); glDeleteFramebuffers(1, &mContext);
} }
// ==================================================================================================== \/ // ==================================================================================================== \/
...@@ -83,18 +113,24 @@ public: ...@@ -83,18 +113,24 @@ public:
public: public:
inline void bindAsRenderTarget(void) const inline void bindAsRenderTarget(void) const
{ {
glBindFramebuffer(GL_FRAMEBUFFER, mContext); bind();
glDrawBuffers(mDrawBuffers, msBuffers); setDrawBuffers();
} }
inline void bind(void) const /**
* Per default a FrameBuffer gets used for read/write operations, but we can
* bind two different FrameBuffers for these operations!
*/
inline void bind( TargetType _type = READ_DRAW_FRAMEBUFFER ) const
{ {
glBindFramebuffer(GL_FRAMEBUFFER, mContext); glBindFramebuffer(_type, mContext);
openGLRareError(); // glBindFramebuffer can only fail if the contect is no valid FBO which shouldn't happen using this framework
} }
inline void setDrawBuffers(void) const inline void setDrawBuffers(void) const
{ {
glDrawBuffers(mDrawBuffers, msBuffers); glDrawBuffers(mDrawBuffers, msBuffers);
openGLRareError();
} }
inline void setViewport(void) const inline void setViewport(void) const
...@@ -110,6 +146,10 @@ public: ...@@ -110,6 +146,10 @@ public:
return false; return false;
} }
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + mDrawBuffers, GL_RENDERBUFFER, _renderBuffer->getContext()); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + mDrawBuffers, GL_RENDERBUFFER, _renderBuffer->getContext());
if (openGLCommonErrorOccured()) {
Utils::error() << "Attaching of texture to the FBO failed" << std::endl;
return false;
}
mDrawBuffers++; mDrawBuffers++;
Attachment attachment = {"", SharedTexture(), _renderBuffer}; Attachment attachment = {"", SharedTexture(), _renderBuffer};
mColorAttachments.push_back(attachment); mColorAttachments.push_back(attachment);
...@@ -124,6 +164,10 @@ public: ...@@ -124,6 +164,10 @@ public:
return false; return false;
} }
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + mDrawBuffers, _texture->getTarget(), _texture->getContext(), 0); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + mDrawBuffers, _texture->getTarget(), _texture->getContext(), 0);
if (openGLCommonErrorOccured()) {
Utils::error() << "Attaching of texture to the FBO failed" << std::endl;
return false;
}
mDrawBuffers++; mDrawBuffers++;
Attachment attachment = {"", _texture, SharedRenderBuffer()}; Attachment attachment = {"", _texture, SharedRenderBuffer()};
mColorAttachments.push_back(attachment); mColorAttachments.push_back(attachment);
...@@ -197,7 +241,7 @@ protected: ...@@ -197,7 +241,7 @@ protected:
GLsizei mHeight; GLsizei mHeight;
GLsizei mDrawBuffers; GLsizei mDrawBuffers;
AttachmentVec mColorAttachments; AttachmentVec mColorAttachments;
Attachment mDepthAttachment; Attachment mDepthAttachment; // depth and stencil are combined
}; };
} // Resource } // Resource
......
...@@ -7,6 +7,8 @@ ...@@ -7,6 +7,8 @@
#define ACGL_RESOURCE_RENDERBUFFER_HH #define ACGL_RESOURCE_RENDERBUFFER_HH
#include <ACGL/GL.hh> #include <ACGL/GL.hh>
#include <ACGL/Utils/Log.hh>
#include <ACGL/GLUtils/Tools.hh>
namespace ACGL{ namespace ACGL{
namespace Resource{ namespace Resource{
...@@ -27,6 +29,11 @@ public: ...@@ -27,6 +29,11 @@ public:
mHeight(_height) mHeight(_height)
{ {
glGenRenderbuffers(1, &mContext); glGenRenderbuffers(1, &mContext);
if (openGLCriticalErrorOccured() ) {
ACGL::Utils::error() << "could not generate renderbuffer!" << std::endl;
return;
}
glBindRenderbuffer(GL_RENDERBUFFER, mContext); glBindRenderbuffer(GL_RENDERBUFFER, mContext);
glRenderbufferStorage(GL_RENDERBUFFER, mInternalFormat, mWidth, mHeight); glRenderbufferStorage(GL_RENDERBUFFER, mInternalFormat, mWidth, mHeight);
...@@ -34,8 +41,8 @@ public: ...@@ -34,8 +41,8 @@ public:
virtual ~RenderBuffer(void) virtual ~RenderBuffer(void)
{ {
if(mContext != 0) // buffer 0 will get ignored by OpenGL
glDeleteRenderbuffers(1, &mContext); glDeleteRenderbuffers(1, &mContext);
} }
// ==================================================================================================== \/ // ==================================================================================================== \/
......
...@@ -29,11 +29,12 @@ public: ...@@ -29,11 +29,12 @@ public:
{ {
ShaderTypeInvalid = 0, ShaderTypeInvalid = 0,
ShaderTypeVertex = GL_VERTEX_SHADER, ShaderTypeVertex = GL_VERTEX_SHADER,
ShaderTypeFragment = GL_FRAGMENT_SHADER, ShaderTypeFragment = GL_FRAGMENT_SHADER
#ifndef OPENGL_ES #ifndef OPENGL_ES
,
ShaderTypeGeometry = GL_GEOMETRY_SHADER, ShaderTypeGeometry = GL_GEOMETRY_SHADER,
ShaderTypeControl = GL_TESS_CONTROL_SHADER, ShaderTypeControl = GL_TESS_CONTROL_SHADER,
ShaderTypeEvaluation = GL_TESS_EVALUATION_SHADER, ShaderTypeEvaluation = GL_TESS_EVALUATION_SHADER
#endif #endif
}; };
......
...@@ -8,6 +8,8 @@ ...@@ -8,6 +8,8 @@
#include <ACGL/Math/Math.hh> #include <ACGL/Math/Math.hh>
#include <ACGL/GL.hh> #include <ACGL/GL.hh>
#include <ACGL/Utils/Log.hh>
#include <ACGL/GLUtils/Tools.hh>
#include <vector> #include <vector>
...@@ -41,13 +43,16 @@ public: ...@@ -41,13 +43,16 @@ public:
mType(_type) mType(_type)
{ {
glGenTextures(1, &mContext); glGenTextures(1, &mContext);
if (openGLCriticalErrorOccured() ) {
ACGL::Utils::error() << "could not generate texture!" << std::endl;
}
} }
virtual ~Texture(void) virtual ~Texture(void)
{ {
// context 0 will get ignored by OpenGL // context 0 will get ignored by OpenGL
glDeleteTextures(1, &mContext); glDeleteTextures(1, &mContext);
mContext = 0;
} }
// ==================================================================================================== \/ // ==================================================================================================== \/
...@@ -93,6 +98,7 @@ public: ...@@ -93,6 +98,7 @@ public:
return; return;
glActiveTexture(GL_TEXTURE0 + _textureUnit); glActiveTexture(GL_TEXTURE0 + _textureUnit);
glBindTexture(mTarget, mContext); glBindTexture(mTarget, mContext);
openGLRareError();
sTextureContext = mContext; sTextureContext = mContext;
} }
...@@ -102,6 +108,7 @@ public: ...@@ -102,6 +108,7 @@ public:
if(sTextureContext == mContext) if(sTextureContext == mContext)
return; return;
glBindTexture(mTarget, mContext); glBindTexture(mTarget, mContext);
openGLRareError();
sTextureContext = mContext; sTextureContext = mContext;
} }
...@@ -109,12 +116,14 @@ public: ...@@ -109,12 +116,14 @@ public:
{ {
bind(); bind();
glTexParameteri(mTarget, _parameter, _value); glTexParameteri(mTarget, _parameter, _value);
openGLRareError();
} }
inline void setParameter(GLenum _parameter, GLfloat _value) inline void setParameter(GLenum _parameter, GLfloat _value)
{ {
bind(); bind();
glTexParameterf(mTarget, _parameter, _value); glTexParameterf(mTarget, _parameter, _value);
openGLRareError();
} }
//! Set texture size for 1D, 2D or 3D textures and NULL data //! Set texture size for 1D, 2D or 3D textures and NULL data
...@@ -219,6 +228,7 @@ public: ...@@ -219,6 +228,7 @@ public:
bind(); bind();
glEnable(mTarget); glEnable(mTarget);
glGenerateMipmap(mTarget); glGenerateMipmap(mTarget);
openGLRareError();
} }
// =================================================================================================== \/ // =================================================================================================== \/
......
...@@ -117,6 +117,8 @@ public: ...@@ -117,6 +117,8 @@ public:
mpElementArrayBuffer->draw(); mpElementArrayBuffer->draw();
else else
glDrawArrays(mMode, 0, mElements); glDrawArrays(mMode, 0, mElements);
openGLRareError();
} }
// =================================================================================================== \/ // =================================================================================================== \/
......
...@@ -10,23 +10,23 @@ namespace ACGL{ ...@@ -10,23 +10,23 @@ namespace ACGL{
namespace GLUtils{ namespace GLUtils{
namespace Tools{ namespace Tools{
const GLubyte* acglErrorString( GLenum err ) const GLubyte* acglErrorString( GLenum _errorCode )
{ {
#ifdef PLATFORM_IOS #ifdef PLATFORM_IOS
// no gluErrorString on iOS // no gluErrorString on iOS
// this should only get used on OpenGL ES plattforms, so error strings from the compatibility profile // this should only get used on OpenGL ES plattforms, so error strings from the compatibility profile
// are ignored. Only 3.2+ Core and ES 2.0+ errors belong here: // are ignored. Only 3.2+ Core and ES 2.0+ errors belong here:
if (err == GL_INVALID_ENUM) { return "GL_INVALID_ENUM"; } if (_errorCode == GL_INVALID_ENUM) { return (GLubyte*) "GL_INVALID_ENUM"; }
else if (err == GL_INVALID_VALUE) { return "GL_INVALID_VALUE"; } else if (_errorCode == GL_INVALID_VALUE) { return (GLubyte*) "GL_INVALID_VALUE"; }
else if (err == GL_INVALID_OPERATION) { return "GL_INVALID_OPERATION"l; } else if (_errorCode == GL_INVALID_OPERATION) { return (GLubyte*) "GL_INVALID_OPERATION"l; }
else if (err == GL_INVALID_FRAMEBUFFER_OPERATION) { return "GL_INVALID_FRAMEBUFFER_OPERATION"; } else if (_errorCode == GL_INVALID_FRAMEBUFFER_OPERATION) { return (GLubyte*) "GL_INVALID_FRAMEBUFFER_OPERATION"; }
else if (err == GL_OUT_OF_MEMORY) { return "GL_OUT_OF_MEMORY" }; else if (_errorCode == GL_OUT_OF_MEMORY) { return (GLubyte*) "GL_OUT_OF_MEMORY" };
else if (err == GL_NO_ERROR) { return "GL_NO_ERROR"; } else if (_errorCode == GL_NO_ERROR) { return (GLubyte*) "GL_NO_ERROR"; }
else { else {
return "unknown error"; return (GLubyte*) "unknown error";
} }
#else #else
return gluErrorString( err ); return gluErrorString( _errorCode );
#endif #endif
} }
...@@ -34,18 +34,18 @@ const GLubyte* acglErrorString( GLenum err ) ...@@ -34,18 +34,18 @@ const GLubyte* acglErrorString( GLenum err )
GLenum openGLError_( const char *_fileName, const unsigned long _lineNumber ) GLenum openGLError_( const char *_fileName, const unsigned long _lineNumber )
{ {
GLenum err = glGetError(); GLenum currentError = glGetError();
GLenum lastError = currentError;
if (err == GL_NO_ERROR) return GL_NO_ERROR;
// OpenGL does not forbit the implementation to stack up more than one error code
GLenum lastError = err; // so we have to check those in a loop:
while ( err != GL_NO_ERROR) { while ( currentError != GL_NO_ERROR ) {
ACGL::Utils::error() << "GL error in file " << _fileName << ":" << _lineNumber << " - " << acglErrorString( err ) << std::endl; ACGL::Utils::error() << "GL error in file " << _fileName << ":" << _lineNumber << " - " << acglErrorString( currentError ) << std::endl;
lastError = err; lastError = currentError;
err = glGetError(); currentError = glGetError();
} }
return lastError; return lastError; // returns the last real error (in case there was at least one!)
} }
......
...@@ -23,9 +23,13 @@ void ArrayBuffer::render(void) const ...@@ -23,9 +23,13 @@ void ArrayBuffer::render(void) const
{ {
setPointer(i, i); setPointer(i, i);
glEnableVertexAttribArray(i); glEnableVertexAttribArray(i);
openGLRareError();
} }
draw(); draw();
for(AttributeVec::size_type i = 0; i < mAttributes.size(); ++i) for(AttributeVec::size_type i = 0; i < mAttributes.size(); ++i)
{
glDisableVertexAttribArray(i); glDisableVertexAttribArray(i);
openGLRareError();
}
glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ARRAY_BUFFER, 0);
} }
...@@ -7,12 +7,18 @@ ...@@ -7,12 +7,18 @@
using namespace ACGL::Resource; using namespace ACGL::Resource;
GLuint FrameBuffer::msBuffers[8] = { /*
* We can't use the constants GL_COLOR_ATTACHMENT1 to GL_COLOR_ATTACHMENT7 here
* because OpenGL ES does not know these yet.
*/
GLuint FrameBuffer::msBuffers[8] = {
GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT0,
GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT0+1,
GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT0+2,
GL_COLOR_ATTACHMENT3, GL_COLOR_ATTACHMENT0+3,
GL_COLOR_ATTACHMENT4, GL_COLOR_ATTACHMENT0+4,
GL_COLOR_ATTACHMENT5, GL_COLOR_ATTACHMENT0+5,
GL_COLOR_ATTACHMENT6, GL_COLOR_ATTACHMENT0+6,
GL_COLOR_ATTACHMENT7}; GL_COLOR_ATTACHMENT0+7};
...@@ -69,12 +69,16 @@ bool Shader::setSource(const std::string& _source) ...@@ -69,12 +69,16 @@ bool Shader::setSource(const std::string& _source)