Browse Source

Support for ARB_robustness.

Robust *Framebuffer::read() access, ability to query robust buffer
access behavior in Context::flags(), ability to check graphics reset
status and reset notification policy in Renderer.
pull/278/head
Vladimír Vondruš 13 years ago
parent
commit
11b3150a31
  1. 52
      src/AbstractFramebuffer.cpp
  2. 19
      src/AbstractFramebuffer.h
  3. 2
      src/Context.cpp
  4. 13
      src/Context.h
  5. 2
      src/Extensions.h
  6. 45
      src/Implementation/RendererState.h
  7. 3
      src/Implementation/State.cpp
  8. 2
      src/Implementation/State.h
  9. 1
      src/Platform/AbstractXApplication.h
  10. 54
      src/Renderer.cpp
  11. 96
      src/Renderer.h

52
src/AbstractFramebuffer.cpp

@ -34,6 +34,8 @@
namespace Magnum {
AbstractFramebuffer::ReadImplementation AbstractFramebuffer::readImplementation = &AbstractFramebuffer::readImplementationDefault;
AbstractFramebuffer::DrawBuffersImplementation AbstractFramebuffer::drawBuffersImplementation = &AbstractFramebuffer::drawBuffersImplementationDefault;
AbstractFramebuffer::DrawBufferImplementation AbstractFramebuffer::drawBufferImplementation = &AbstractFramebuffer::drawBufferImplementationDefault;
AbstractFramebuffer::ReadBufferImplementation AbstractFramebuffer::readBufferImplementation = &AbstractFramebuffer::readBufferImplementationDefault;
@ -128,8 +130,9 @@ void AbstractFramebuffer::clear(ClearMask mask) {
void AbstractFramebuffer::read(const Vector2i& offset, const Vector2i& size, AbstractImage::Format format, AbstractImage::Type type, Image2D* image) {
bindInternal(readTarget);
char* data = new char[AbstractImage::pixelSize(format, type)*size.product()];
glReadPixels(offset.x(), offset.y(), size.x(), size.y(), static_cast<GLenum>(format), static_cast<GLenum>(type), data);
const std::size_t dataSize = AbstractImage::pixelSize(format, type)*size.product();
char* const data = new char[dataSize];
readImplementation(offset, size, format, type, dataSize, data);
image->setData(size, format, type, data);
}
@ -142,7 +145,8 @@ void AbstractFramebuffer::read(const Vector2i& offset, const Vector2i& size, Abs
image->setData(size, format, type, nullptr, usage);
image->buffer()->bind(Buffer::Target::PixelPack);
glReadPixels(offset.x(), offset.y(), size.x(), size.y(), static_cast<GLenum>(format), static_cast<GLenum>(type), nullptr);
/** @todo De-duplicate buffer size computation */
readImplementation(offset, size, format, type, AbstractImage::pixelSize(format, type)*size.product(), nullptr);
}
#endif
@ -185,6 +189,26 @@ void AbstractFramebuffer::initializeContextBasedFunctionality(Context* context)
drawBufferImplementation = &AbstractFramebuffer::drawBufferImplementationDSA;
readBufferImplementation = &AbstractFramebuffer::readBufferImplementationDSA;
}
#endif
#ifndef MAGNUM_TARGET_GLES3
#ifndef MAGNUM_TARGET_GLES
if(context->isExtensionSupported<Extensions::GL::ARB::robustness>())
#else
if(context->isExtensionSupported<Extensions::GL::EXT::robustness>())
#endif
{
#ifndef MAGNUM_TARGET_GLES
Debug() << "AbstractFramebuffer: using" << Extensions::GL::ARB::robustness::string() << "features";
#else
//Debug() << "AbstractFramebuffer: using" << Extensions::GL::EXT::robustness::string() << "features";
#endif
/** @todo Enable when extension wrangler for ES is available */
#ifndef MAGNUM_TARGET_GLES
readImplementation = &AbstractFramebuffer::readImplementationRobustness;
#endif
}
#else
static_cast<void>(context);
#endif
@ -243,4 +267,26 @@ void AbstractFramebuffer::readBufferImplementationDSA(GLenum buffer) {
}
#endif
void AbstractFramebuffer::readImplementationDefault(const Vector2i& offset, const Vector2i& size, const AbstractImage::Format format, const AbstractImage::Type type, const std::size_t, GLvoid* const data) {
glReadPixels(offset.x(), offset.y(), size.x(), size.y(), static_cast<GLenum>(format), static_cast<GLenum>(type), data);
}
#ifndef MAGNUM_TARGET_GLES3
void AbstractFramebuffer::readImplementationRobustness(const Vector2i& offset, const Vector2i& size, const AbstractImage::Format format, const AbstractImage::Type type, const std::size_t dataSize, GLvoid* const data) {
/** @todo Enable when extension wrangler for ES is available */
#ifndef MAGNUM_TARGET_GLES
glReadnPixelsARB(offset.x(), offset.y(), size.x(), size.y(), static_cast<GLenum>(format), static_cast<GLenum>(type), dataSize, data);
#else
CORRADE_INTERNAL_ASSERT(false);
//glReadnPixelsEXT(offset.x(), offset.y(), size.x(), size.y(), static_cast<GLenum>(format), static_cast<GLenum>(type), data);
static_cast<void>(offset);
static_cast<void>(size);
static_cast<void>(format);
static_cast<void>(type);
static_cast<void>(dataSize);
static_cast<void>(data);
#endif
}
#endif
}

19
src/AbstractFramebuffer.h

@ -41,12 +41,14 @@ namespace Magnum {
See DefaultFramebuffer and Framebuffer for more information.
@section AbstractFramebuffer-performance-optimization Performance optimizations
@section AbstractFramebuffer-performance-optimization Performance optimizations and security
The engine tracks currently bound framebuffer and current viewport to avoid
unnecessary calls to @fn_gl{BindFramebuffer} and @fn_gl{Viewport} when
switching framebuffers.
If @extension{ARB,robustness} is available, read() operations are protected
from buffer overflow.
@todo @extension{ARB,viewport_array}
*/
class MAGNUM_EXPORT AbstractFramebuffer {
@ -238,7 +240,10 @@ class MAGNUM_EXPORT AbstractFramebuffer {
* @param type Data type of pixel data
* @param image %Image where to put the data
*
* @see @fn_gl{BindFramebuffer}, @fn_gl{ReadPixels}
* If @extension{ARB,robustness} is available, the operation is
* protected from buffer overflow.
* @see @fn_gl{BindFramebuffer}, @fn_gl{ReadPixels} or
* @fn_gl_extension{ReadnPixels,ARB,robustness}
* @todo Read size, format & type from image?
*/
void read(const Vector2i& offset, const Vector2i& size, AbstractImage::Format format, AbstractImage::Type type, Image2D* image);
@ -253,7 +258,8 @@ class MAGNUM_EXPORT AbstractFramebuffer {
* @param image %Buffer image where to put the data
* @param usage %Buffer usage
*
* @see @fn_gl{BindFramebuffer}, @fn_gl{ReadPixels}
* See read(const Vector2i&, const Vector2i&, Image2D*) for more
* information.
* @requires_gles30 Pixel buffer objects are not available in OpenGL ES 2.0.
* @todo Read size, format & type from image?
*/
@ -304,6 +310,13 @@ class MAGNUM_EXPORT AbstractFramebuffer {
#ifndef MAGNUM_TARGET_GLES
void MAGNUM_LOCAL readBufferImplementationDSA(GLenum buffer);
#endif
typedef void(*ReadImplementation)(const Vector2i&, const Vector2i&, AbstractImage::Format, AbstractImage::Type, std::size_t, GLvoid*);
static void MAGNUM_LOCAL readImplementationDefault(const Vector2i& offset, const Vector2i& size, AbstractImage::Format format, AbstractImage::Type type, std::size_t dataSize, GLvoid* data);
#ifndef MAGNUM_TARGET_GLES3
static void MAGNUM_LOCAL readImplementationRobustness(const Vector2i& offset, const Vector2i& size, AbstractImage::Format format, AbstractImage::Type type, std::size_t dataSize, GLvoid* data);
#endif
static ReadImplementation MAGNUM_LOCAL readImplementation;
};
inline AbstractFramebuffer::~AbstractFramebuffer() {}

2
src/Context.cpp

@ -80,6 +80,7 @@ const std::vector<Extension>& Extension::extensions(Version version) {
static const std::vector<Extension> extensions{
_extension(GL,AMD,vertex_shader_layer), // done
_extension(GL,AMD,shader_trinary_minmax), // done
_extension(GL,ARB,robustness),
_extension(GL,EXT,texture_filter_anisotropic), // done
_extension(GL,EXT,direct_state_access),
_extension(GL,GREMEDY,string_marker)}; // done
@ -211,6 +212,7 @@ const std::vector<Extension>& Extension::extensions(Version version) {
_extension(GL,EXT,debug_marker),
_extension(GL,EXT,separate_shader_objects),
_extension(GL,EXT,sRGB),
_extension(GL,EXT,robustness),
_extension(GL,NV,read_buffer_front),
_extension(GL,NV,read_stencil),
_extension(GL,NV,texture_border_clamp), // done

13
src/Context.h

@ -157,7 +157,18 @@ class MAGNUM_EXPORT Context {
* @requires_gl43 %Extension @es_extension{KHR,debug}
* @requires_es_extension %Extension @es_extension{KHR,debug}
*/
Debug = GL_CONTEXT_FLAG_DEBUG_BIT
Debug = GL_CONTEXT_FLAG_DEBUG_BIT,
#endif
#ifndef MAGNUM_TARGET_GLES
/**
* Context with robust buffer access
* @requires_extension %Extension @extension{EXT,robustness}
* @requires_es_extension %Extension @es_extension{EXT,robustness}
* @todo In ES available under glGetIntegerv(CONTEXT_ROBUST_ACCESS_EXT),
* how to make it compatible?
*/
Robustness = GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT_ARB
#endif
};

2
src/Extensions.h

@ -120,6 +120,7 @@ namespace GL {
_extension(GL,ARB,shader_precision, GL400, GL410) // #98
_extension(GL,ARB,vertex_attrib_64bit, GL300, GL410) // #99
_extension(GL,ARB,viewport_array, GL210, GL410) // #100
_extension(GL,ARB,robustness, GL210, None) // #105
_extension(GL,ARB,base_instance, GL210, GL420) // #107
_extension(GL,ARB,shading_language_420pack, GL300, GL420) // #108
_extension(GL,ARB,transform_feedback_instanced, GL210, GL420) // #109
@ -204,6 +205,7 @@ namespace GL {
_extension(GL,EXT,separate_shader_objects, GLES200, None) // #101
_extension(GL,EXT,texture_rg, GLES200, GLES300) // #103
_extension(GL,EXT,sRGB, GLES200, None) // #105
_extension(GL,EXT,robustness, GLES200, None) // #105
_extension(GL,EXT,texture_storage, GLES200, GLES300) // #108
_extension(GL,EXT,map_buffer_range, GLES200, GLES300) // #121
} namespace NV {

45
src/Implementation/RendererState.h

@ -0,0 +1,45 @@
#ifndef Magnum_Implementation_RendererState_h
#define Magnum_Implementation_RendererState_h
/*
This file is part of Magnum.
Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš <mosra@centrum.cz>
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#include "Renderer.h"
namespace Magnum { namespace Implementation {
struct RendererState {
inline constexpr RendererState()
#ifndef MAGNUM_TARGET_GLES3
: resetNotificationStrategy()
#endif
{}
#ifndef MAGNUM_TARGET_GLES3
Renderer::ResetNotificationStrategy resetNotificationStrategy;
#endif
};
}}
#endif

3
src/Implementation/State.cpp

@ -27,6 +27,7 @@
#include "BufferState.h"
#include "FramebufferState.h"
#include "MeshState.h"
#include "RendererState.h"
#include "ShaderProgramState.h"
#include "TextureState.h"
@ -36,12 +37,14 @@ State::State():
buffer(new BufferState),
framebuffer(new FramebufferState),
mesh(new MeshState),
renderer(new RendererState),
shaderProgram(new ShaderProgramState),
texture(new TextureState) {}
State::~State() {
delete texture;
delete shaderProgram;
delete renderer;
delete mesh;
delete framebuffer;
delete buffer;

2
src/Implementation/State.h

@ -29,6 +29,7 @@ namespace Magnum { namespace Implementation {
struct BufferState;
struct FramebufferState;
struct MeshState;
struct RendererState;
struct ShaderProgramState;
struct TextureState;
@ -39,6 +40,7 @@ struct State {
BufferState* const buffer;
FramebufferState* const framebuffer;
MeshState* const mesh;
RendererState* const renderer;
ShaderProgramState* const shaderProgram;
TextureState* const texture;
};

1
src/Platform/AbstractXApplication.h

@ -178,6 +178,7 @@ CORRADE_ENUMSET_OPERATORS(AbstractXApplication::Flags)
Double-buffered OpenGL context.
@see AbstractXApplication(), createContext()
@todo GLX_ARB_create_context_robustness/EGL_EXT_create_context_robustness
*/
class AbstractXApplication::Configuration {
Configuration(const Configuration&) = delete;

54
src/Renderer.cpp

@ -28,6 +28,8 @@
#include "Math/Geometry/Rectangle.h"
#include "Context.h"
#include "Extensions.h"
#include "Implementation/State.h"
#include "Implementation/RendererState.h"
namespace Magnum {
@ -36,6 +38,9 @@ Renderer::ClearDepthfImplementation Renderer::clearDepthfImplementation = &Rende
#else
Renderer::ClearDepthfImplementation Renderer::clearDepthfImplementation = &Renderer::clearDepthfImplementationES;
#endif
#ifndef MAGNUM_TARGET_GLES3
Renderer::GraphicsResetStatusImplementation Renderer::graphicsResetStatusImplementation = &Renderer::graphicsResetStatusImplementationDefault;
#endif
void Renderer::setFeature(const Feature feature, const bool enabled) {
enabled ? glEnable(GLenum(feature)) : glDisable(GLenum(feature));
@ -153,6 +158,22 @@ void Renderer::setLogicOperation(const LogicOperation operation) {
}
#endif
#ifndef MAGNUM_TARGET_GLES3
Renderer::ResetNotificationStrategy Renderer::resetNotificationStrategy() {
ResetNotificationStrategy& strategy = Context::current()->state()->renderer->resetNotificationStrategy;
if(strategy == ResetNotificationStrategy()) {
#ifndef MAGNUM_TARGET_GLES
glGetIntegerv(GL_RESET_NOTIFICATION_STRATEGY_ARB, reinterpret_cast<GLint*>(&strategy));
#else
glGetIntegerv(GL_RESET_NOTIFICATION_STRATEGY_EXT, reinterpret_cast<GLint*>(&strategy));
#endif
}
return strategy;
}
#endif
void Renderer::initializeContextBasedFunctionality(Context* context) {
#ifndef MAGNUM_TARGET_GLES
if(context->isExtensionSupported<Extensions::GL::ARB::ES2_compatibility>()) {
@ -160,6 +181,23 @@ void Renderer::initializeContextBasedFunctionality(Context* context) {
clearDepthfImplementation = &Renderer::clearDepthfImplementationES;
}
#endif
#ifndef MAGNUM_TARGET_GLES3
#ifndef MAGNUM_TARGET_GLES
if(context->isExtensionSupported<Extensions::GL::ARB::robustness>())
#else
if(context->isExtensionSupported<Extensions::GL::EXT::robustness>())
#endif
{
#ifndef MAGNUM_TARGET_GLES
Debug() << "Renderer: using" << Extensions::GL::ARB::robustness::string() << "features";
#else
Debug() << "Renderer: using" << Extensions::GL::EXT::robustness::string() << "features";
#endif
graphicsResetStatusImplementation = &Renderer::graphicsResetStatusImplementationRobustness;
}
#else
static_cast<void>(context);
#endif
@ -175,4 +213,20 @@ void Renderer::clearDepthfImplementationES(const GLfloat depth) {
glClearDepthf(depth);
}
#ifndef MAGNUM_TARGET_GLES3
Renderer::GraphicsResetStatus Renderer::graphicsResetStatusImplementationDefault() {
return GraphicsResetStatus::NoError;
}
Renderer::GraphicsResetStatus Renderer::graphicsResetStatusImplementationRobustness() {
/** @todo Enable when extension wrangler for ES is available */
#ifndef MAGNUM_TARGET_GLES
return GraphicsResetStatus(glGetGraphicsResetStatusARB());
#else
//return GraphicsResetStatus(glGetGraphicsResetStatusEXT());
CORRADE_INTERNAL_ASSERT(false);
#endif
}
#endif
}

96
src/Renderer.h

@ -838,6 +838,95 @@ class MAGNUM_EXPORT Renderer {
glFinish();
}
#ifndef MAGNUM_TARGET_GLES3
/**
* @brief Graphics reset notification strategy
*
* @see resetNotificationStrategy()
* @requires_extension %Extension @extension{ARB,robustness}
* @requires_es_extension %Extension @es_extension{EXT,robustness}
*/
enum class ResetNotificationStrategy: GLint {
/**
* No reset notification, thus graphicsResetStatus() will always
* return @ref GraphicsResetStatus "GraphicsResetStatus::NoError".
* However this doesn't mean that the context cannot be lost.
*/
#ifndef MAGNUM_TARGET_GLES
NoResetNotification = GL_NO_RESET_NOTIFICATION_ARB,
#else
NoResetNotification = GL_NO_RESET_NOTIFICATION_EXT,
#endif
/**
* Graphics reset will result in context loss, cause of the reset
* can be queried with graphicsResetStatus().
*/
#ifndef MAGNUM_TARGET_GLES
LoseContextOnReset = GL_LOSE_CONTEXT_ON_RESET_ARB
#else
LoseContextOnReset = GL_LOSE_CONTEXT_ON_RESET_EXT
#endif
};
/**
* @brief Graphics reset notification strategy
*
* The result is cached, repeated queries don't result in repeated
* OpenGL calls. If OpenGL extension @extension{ARB,robustness} or ES
* extension @es_extension{EXT,robustness} is not available, this
* function always returns @ref ResetNotificationStrategy "ResetNotificationStrategy::NoResetNotification".
* @see graphicsResetStatus(), @fn_gl{Get} with @def_gl{RESET_NOTIFICATION_STRATEGY_ARB}
*/
static ResetNotificationStrategy resetNotificationStrategy();
/**
* @brief Graphics reset status
*
* @see resetNotificationStrategy(), graphicsResetStatus()
* @requires_extension %Extension @extension{ARB,robustness}
* @requires_es_extension %Extension @es_extension{EXT,robustness}
*/
enum class GraphicsResetStatus: GLenum {
/** No reset occured since last call. */
NoError = GL_NO_ERROR,
/** Reset attributable to the current context has been detected. */
#ifndef MAGNUM_TARGET_GLES
GuiltyContextReset = GL_GUILTY_CONTEXT_RESET_ARB,
#else
GuiltyContextReset = GL_GUILTY_CONTEXT_RESET_EXT,
#endif
/** Reset not attributable to the current context has been detected. */
#ifndef MAGNUM_TARGET_GLES
InnocentContextReset = GL_INNOCENT_CONTEXT_RESET_ARB,
#else
InnocentContextReset = GL_INNOCENT_CONTEXT_RESET_EXT,
#endif
/** Reset with unknown cause has been detected. */
#ifndef MAGNUM_TARGET_GLES
UnknownContextReset = GL_UNKNOWN_CONTEXT_RESET_ARB
#else
UnknownContextReset = GL_UNKNOWN_CONTEXT_RESET_EXT
#endif
};
/**
* @brief Check graphics reset status
*
* Reset causes all context state to be lost. If OpenGL extension
* @extension{ARB,robustness} or ES extension @es_extension{EXT,robustness}
* is not available, this function always returns
* @ref GraphicsResetStatus "GraphicsResetStatus::NoError".
* @see resetNotificationStrategy(), @fn_gl_extension{GetGraphicsResetStatus,ARB,robustness}
*/
inline static GraphicsResetStatus graphicsResetStatus() {
return graphicsResetStatusImplementation();
}
#endif
/*@}*/
private:
@ -849,6 +938,13 @@ class MAGNUM_EXPORT Renderer {
#endif
static void MAGNUM_LOCAL clearDepthfImplementationES(GLfloat depth);
static ClearDepthfImplementation clearDepthfImplementation;
#ifndef MAGNUM_TARGET_GLES3
typedef GraphicsResetStatus(*GraphicsResetStatusImplementation)();
static GraphicsResetStatus MAGNUM_LOCAL graphicsResetStatusImplementationDefault();
static GraphicsResetStatus MAGNUM_LOCAL graphicsResetStatusImplementationRobustness();
static GraphicsResetStatusImplementation graphicsResetStatusImplementation;
#endif
};
}

Loading…
Cancel
Save