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

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 )
// 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
// (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
......@@ -83,31 +83,34 @@ GLenum openGLError_( const char *_fileName, const unsigned long _lineNumber );
* 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
# define openGLCriticalError() openGLError_( __FILE__, __LINE__ )
# define openGLCriticalErrorOccured() (openGLError_( __FILE__, __LINE__ ) != GL_NO_ERROR)
# define openGLCriticalError() ACGL::GLUtils::Tools::openGLError_( __FILE__, __LINE__ )
# define openGLCriticalErrorOccured() (ACGL::GLUtils::Tools::openGLError_( __FILE__, __LINE__ ) != GL_NO_ERROR)
#else
inline GLenum openGLCriticalError() { return GL_NO_ERROR; }
inline bool openGLCriticalErrorOccured() { return false; }
# define openGLCriticalError() ACGL::GLUtils::Tools::openGLErrorDummy()
# define openGLCriticalErrorOccured() ACGL::GLUtils::Tools::openGLErrorOccuredDummy()
#endif
#ifdef ACGL_CHECK_COMMON_GL_ERRORS
# define openGLCommonError() openGLError_( __FILE__, __LINE__ )
# define openGLCommonErrorOccured() (openGLError_( __FILE__, __LINE__ ) != GL_NO_ERROR)
# define openGLCommonError() ACGL::GLUtils::Tools::openGLError_( __FILE__, __LINE__ )
# define openGLCommonErrorOccured() (ACGL::GLUtils::Tools::openGLError_( __FILE__, __LINE__ ) != GL_NO_ERROR)
#else
inline GLenum openGLCommonError() { return GL_NO_ERROR; }
inline bool openGLCommonErrorOccured() { return false; }
# define openGLCommonError() ACGL::GLUtils::Tools::openGLErrorDummy()
# define openGLCommonErrorOccured() ACGL::GLUtils::Tools::openGLErrorOccuredDummy()
#endif
#ifdef ACGL_CHECK_RARE_GL_ERRORS
# define openGLRareError() openGLError_( __FILE__, __LINE__ )
# define openGLRareErrorOccured() (openGLError_( __FILE__, __LINE__ ) != GL_NO_ERROR)
# define openGLRareError() ACGL::GLUtils::Tools::openGLError_( __FILE__, __LINE__ )
# define openGLRareErrorOccured() (ACGL::GLUtils::Tools::openGLError_( __FILE__, __LINE__ ) != GL_NO_ERROR)
#else
inline GLenum openGLRareError() { return GL_NO_ERROR; }
inline bool openGLRareErrorOccured() { return false; }
# define openGLRareError() ACGL::GLUtils::Tools::openGLErrorDummy()
# define openGLRareErrorOccured() ACGL::GLUtils::Tools::openGLErrorOccuredDummy()
#endif
} // Tools
} // GLUtils
} // ACGL
......
......@@ -52,12 +52,15 @@ public:
mAttributes()
{
glGenBuffers(1, &mContext);
if (openGLCriticalErrorOccured() ) {
ACGL::Utils::error() << "could not generate array buffer!" << std::endl;
}
}
virtual ~ArrayBuffer(void)
{
if(mContext != 0)
glDeleteBuffers(1, &mContext);
// buffer 0 will get ignored by OpenGL
glDeleteBuffers(1, &mContext);
}
// ==================================================================================================== \/
......
......@@ -30,12 +30,16 @@ public:
mSizeOfType(GLUtils::Tools::getGLTypeSize(_type))
{
glGenBuffers(1, &mContext);
if (openGLCriticalErrorOccured() ) {
ACGL::Utils::error() << "could not generate element array buffer!" << std::endl;
}
}
virtual ~ElementArrayBuffer(void)
{
if(mContext != 0)
glDeleteBuffers(1, &mContext);
// buffer 0 will get ignored by OpenGL
glDeleteBuffers(1, &mContext);
}
// ==================================================================================================== \/
......
......@@ -6,12 +6,30 @@
#ifndef 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/RenderBuffer.hh>
#include <ACGL/Resource/Texture.hh>
#include <ACGL/Utils/Log.hh>
#include <ACGL/Utils/StringOperations.hh>
#include <ACGL/GL.hh>
#include <ACGL/GLUtils/Tools.hh>
namespace ACGL{
namespace Resource{
......@@ -36,6 +54,14 @@ public:
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 \/
// ===================================================================================================== \/
......@@ -55,6 +81,10 @@ public:
mDepthAttachment()
{
glGenFramebuffers(1, &mContext);
if (openGLCriticalErrorOccured() ) {
ACGL::Utils::error() << "could not generate framebuffer!" << std::endl;
return;
}
mDepthAttachment.name = "";
mDepthAttachment.texture = SharedTexture();
mDepthAttachment.renderBuffer = SharedRenderBuffer();
......@@ -62,8 +92,8 @@ public:
virtual ~FrameBuffer(void)
{
if(mContext != 0)
glDeleteFramebuffers(1, &mContext);
// buffer 0 will get ignored by OpenGL
glDeleteFramebuffers(1, &mContext);
}
// ==================================================================================================== \/
......@@ -83,18 +113,24 @@ public:
public:
inline void bindAsRenderTarget(void) const
{
glBindFramebuffer(GL_FRAMEBUFFER, mContext);
glDrawBuffers(mDrawBuffers, msBuffers);
bind();
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
{
glDrawBuffers(mDrawBuffers, msBuffers);
openGLRareError();
}
inline void setViewport(void) const
......@@ -110,6 +146,10 @@ public:
return false;
}
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++;
Attachment attachment = {"", SharedTexture(), _renderBuffer};
mColorAttachments.push_back(attachment);
......@@ -124,6 +164,10 @@ public:
return false;
}
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++;
Attachment attachment = {"", _texture, SharedRenderBuffer()};
mColorAttachments.push_back(attachment);
......@@ -197,7 +241,7 @@ protected:
GLsizei mHeight;
GLsizei mDrawBuffers;
AttachmentVec mColorAttachments;
Attachment mDepthAttachment;
Attachment mDepthAttachment; // depth and stencil are combined
};
} // Resource
......
......@@ -7,6 +7,8 @@
#define ACGL_RESOURCE_RENDERBUFFER_HH
#include <ACGL/GL.hh>
#include <ACGL/Utils/Log.hh>
#include <ACGL/GLUtils/Tools.hh>
namespace ACGL{
namespace Resource{
......@@ -27,6 +29,11 @@ public:
mHeight(_height)
{
glGenRenderbuffers(1, &mContext);
if (openGLCriticalErrorOccured() ) {
ACGL::Utils::error() << "could not generate renderbuffer!" << std::endl;
return;
}
glBindRenderbuffer(GL_RENDERBUFFER, mContext);
glRenderbufferStorage(GL_RENDERBUFFER, mInternalFormat, mWidth, mHeight);
......@@ -34,8 +41,8 @@ public:
virtual ~RenderBuffer(void)
{
if(mContext != 0)
glDeleteRenderbuffers(1, &mContext);
// buffer 0 will get ignored by OpenGL
glDeleteRenderbuffers(1, &mContext);
}
// ==================================================================================================== \/
......
......@@ -29,11 +29,12 @@ public:
{
ShaderTypeInvalid = 0,
ShaderTypeVertex = GL_VERTEX_SHADER,
ShaderTypeFragment = GL_FRAGMENT_SHADER,
ShaderTypeFragment = GL_FRAGMENT_SHADER
#ifndef OPENGL_ES
,
ShaderTypeGeometry = GL_GEOMETRY_SHADER,
ShaderTypeControl = GL_TESS_CONTROL_SHADER,
ShaderTypeEvaluation = GL_TESS_EVALUATION_SHADER,
ShaderTypeEvaluation = GL_TESS_EVALUATION_SHADER
#endif
};
......
......@@ -8,6 +8,8 @@
#include <ACGL/Math/Math.hh>
#include <ACGL/GL.hh>
#include <ACGL/Utils/Log.hh>
#include <ACGL/GLUtils/Tools.hh>
#include <vector>
......@@ -41,13 +43,16 @@ public:
mType(_type)
{
glGenTextures(1, &mContext);
if (openGLCriticalErrorOccured() ) {
ACGL::Utils::error() << "could not generate texture!" << std::endl;
}
}
virtual ~Texture(void)
{
// context 0 will get ignored by OpenGL
glDeleteTextures(1, &mContext);
mContext = 0;
}
// ==================================================================================================== \/
......@@ -93,6 +98,7 @@ public:
return;
glActiveTexture(GL_TEXTURE0 + _textureUnit);
glBindTexture(mTarget, mContext);
openGLRareError();
sTextureContext = mContext;
}
......@@ -102,6 +108,7 @@ public:
if(sTextureContext == mContext)
return;
glBindTexture(mTarget, mContext);
openGLRareError();
sTextureContext = mContext;
}
......@@ -109,12 +116,14 @@ public:
{
bind();
glTexParameteri(mTarget, _parameter, _value);
openGLRareError();
}
inline void setParameter(GLenum _parameter, GLfloat _value)
{
bind();
glTexParameterf(mTarget, _parameter, _value);
openGLRareError();
}
//! Set texture size for 1D, 2D or 3D textures and NULL data
......@@ -219,6 +228,7 @@ public:
bind();
glEnable(mTarget);
glGenerateMipmap(mTarget);
openGLRareError();
}
// =================================================================================================== \/
......
......@@ -117,6 +117,8 @@ public:
mpElementArrayBuffer->draw();
else
glDrawArrays(mMode, 0, mElements);
openGLRareError();
}
// =================================================================================================== \/
......
......@@ -10,23 +10,23 @@ namespace ACGL{
namespace GLUtils{
namespace Tools{
const GLubyte* acglErrorString( GLenum err )
const GLubyte* acglErrorString( GLenum _errorCode )
{
#ifdef PLATFORM_IOS
// no gluErrorString on iOS
// 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:
if (err == GL_INVALID_ENUM) { return "GL_INVALID_ENUM"; }
else if (err == GL_INVALID_VALUE) { return "GL_INVALID_VALUE"; }
else if (err == GL_INVALID_OPERATION) { return "GL_INVALID_OPERATION"l; }
else if (err == GL_INVALID_FRAMEBUFFER_OPERATION) { return "GL_INVALID_FRAMEBUFFER_OPERATION"; }
else if (err == GL_OUT_OF_MEMORY) { return "GL_OUT_OF_MEMORY" };
else if (err == GL_NO_ERROR) { return "GL_NO_ERROR"; }
if (_errorCode == GL_INVALID_ENUM) { return (GLubyte*) "GL_INVALID_ENUM"; }
else if (_errorCode == GL_INVALID_VALUE) { return (GLubyte*) "GL_INVALID_VALUE"; }
else if (_errorCode == GL_INVALID_OPERATION) { return (GLubyte*) "GL_INVALID_OPERATION"l; }
else if (_errorCode == GL_INVALID_FRAMEBUFFER_OPERATION) { return (GLubyte*) "GL_INVALID_FRAMEBUFFER_OPERATION"; }
else if (_errorCode == GL_OUT_OF_MEMORY) { return (GLubyte*) "GL_OUT_OF_MEMORY" };
else if (_errorCode == GL_NO_ERROR) { return (GLubyte*) "GL_NO_ERROR"; }
else {
return "unknown error";
return (GLubyte*) "unknown error";
}
#else
return gluErrorString( err );
return gluErrorString( _errorCode );
#endif
}
......@@ -34,18 +34,18 @@ const GLubyte* acglErrorString( GLenum err )
GLenum openGLError_( const char *_fileName, const unsigned long _lineNumber )
{
GLenum err = glGetError();
if (err == GL_NO_ERROR) return GL_NO_ERROR;
GLenum lastError = err;
while ( err != GL_NO_ERROR) {
ACGL::Utils::error() << "GL error in file " << _fileName << ":" << _lineNumber << " - " << acglErrorString( err ) << std::endl;
lastError = err;
err = glGetError();
GLenum currentError = glGetError();
GLenum lastError = currentError;
// OpenGL does not forbit the implementation to stack up more than one error code
// so we have to check those in a loop:
while ( currentError != GL_NO_ERROR ) {
ACGL::Utils::error() << "GL error in file " << _fileName << ":" << _lineNumber << " - " << acglErrorString( currentError ) << std::endl;
lastError = currentError;
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
{
setPointer(i, i);
glEnableVertexAttribArray(i);
openGLRareError();
}
draw();
for(AttributeVec::size_type i = 0; i < mAttributes.size(); ++i)
{
glDisableVertexAttribArray(i);
openGLRareError();
}
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
......@@ -7,12 +7,18 @@
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_ATTACHMENT1,
GL_COLOR_ATTACHMENT2,
GL_COLOR_ATTACHMENT3,
GL_COLOR_ATTACHMENT4,
GL_COLOR_ATTACHMENT5,
GL_COLOR_ATTACHMENT6,
GL_COLOR_ATTACHMENT7};
GL_COLOR_ATTACHMENT0+1,
GL_COLOR_ATTACHMENT0+2,
GL_COLOR_ATTACHMENT0+3,
GL_COLOR_ATTACHMENT0+4,
GL_COLOR_ATTACHMENT0+5,
GL_COLOR_ATTACHMENT0+6,
GL_COLOR_ATTACHMENT0+7};
......@@ -69,12 +69,16 @@ bool Shader::setSource(const std::string& _source)
bool Shader::compile(const char* _pProgramText) const
{
glShaderSource(mContext, 1, &_pProgramText, NULL);
openGLRareError();
glShaderSource(mContext, 1, &_pProgramText, NULL); // can't create OpenGL errors
glCompileShader(mContext);
if ( openGLCommonErrorOccured() )
#ifdef ACGL_CHECK_CRITICAL_GL_ERRORS
// problems with the shader creation are always a bad thing...
// from here on only error checks are performed:
//
if ( openGLRareErrorOccured() )
{
error() << "glCompileShader failed, that can only mean, that the context used is not a valid shader object!" << std::endl;
return false;
}
......@@ -87,6 +91,7 @@ bool Shader::compile(const char* _pProgramText) const
error() << "Shader compile error: " << std::endl;
}
// a log gets always printed (could be warnings)
GLsizei length = 0;
glGetShaderiv(mContext, GL_INFO_LOG_LENGTH, &length);
if(length > 1)
......@@ -97,5 +102,9 @@ bool Shader::compile(const char* _pProgramText) const
error() << "Compile log: " << std::string(pInfo) << std::endl;
delete[] pInfo;
}
openGLRareError(); // glGetShader- calls normaly shoudn't create errors
return (shaderError == GL_TRUE); // return true if we encountered no errors
#else
return true; // if no error checking was done we assume it went ok
#endif
}
......@@ -30,31 +30,36 @@ bool ShaderProgram::link(void) const
glLinkProgram(mContext);
#ifdef ACGL_CHECK_CRITICAL_GL_ERRORS
if ( openGLRareErrorOccured() )
{
// it's uncommon that this fails, compile errors (the most common errors)
// are not checked here!
// it's uncommon that glLinkProgram creates errors,
// linking errors create no gl errors but a GL_LINK_STATUS of GL_FALSE
return false;
}
// check for shader compile errors:
GLint error;
glGetProgramiv(mContext, GL_LINK_STATUS, &error);
// check for program link errors:
GLint programError;
glGetProgramiv(mContext, GL_LINK_STATUS, &programError);
if (error != GL_TRUE)
if (programError != GL_TRUE)
{
// yes, errors :-(
GLsizei length = 0;
glGetProgramiv(mContext, GL_INFO_LOG_LENGTH, &length);
if (length > 1)
{
GLchar* pInfo = new char[length + 1];
glGetProgramInfoLog(mContext, length, &length, pInfo);
openGLRareError();
message() << "Linker Error: " << std::string(pInfo) << std::endl;
delete[] pInfo;
return false;
}
error() << "Program could not get linked:" << std::endl;
}
GLsizei length = 0;
glGetProgramiv(mContext, GL_INFO_LOG_LENGTH, &length);
if (length > 1)
{
// error log or warnings:
GLchar* pInfo = new char[length + 1];
glGetProgramInfoLog(mContext, length, &length, pInfo);
openGLRareError();
warning() << "Linker log: " << std::string(pInfo) << std::endl;
delete[] pInfo;
return (programError == GL_TRUE); // if the log contains only warnings we return true
}
#endif
return true;
}
......@@ -32,6 +32,7 @@ void VertexBuffer::render(void) const
}
mArrayBuffers[currentBufferID]->setPointer(mAttributes[i].attributeID, i);
glEnableVertexAttribArray(i);
openGLRareError();
}
draw();
......@@ -45,6 +46,7 @@ void VertexBuffer::render(void) const
mArrayBuffers[currentBufferID]->bind();
}
glDisableVertexAttribArray(i);
openGLRareError();
}
if(mpElementArrayBuffer)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment