+
+#include "Magnum.h"
+#include "OpenGL.h"
+#include "magnumVisibility.h"
+
+namespace Magnum {
+
+namespace Implementation { struct DebugState; }
+
+/**
+@brief Debug message
+
+Allows retrieving and inserting debug messages from and to OpenGL command
+stream, for example with conjunction with various debuggers, such as Apitrace
+or gDEBugger.
+
+@section DebugMessage-usage Basic usage
+
+To retrieve debug messages from either the GL or your application you need to
+have OpenGL 4.3 or @extension{KHR,debug} desktop/ES extension. You need to
+enable @ref Renderer::Feature::DebugOutput and possibly also
+@ref Renderer::Feature::DebugOutputSynchronous. Then set up message callback
+using @ref setCallback() or use the default one provided in
+@ref setDefaultCallback():
+
+@code
+Renderer::setFeature(Renderer::Feature::DebugOutput, true);
+Renderer::setFeature(Renderer::Feature::DebugOutputSynchronous, true);
+
+DebugMessage::setDefaultCallback();
+DebugMessage::insert(DebugMessage::Source::Application, DebugMessage::Type::Marker,
+ 1337, DebugMessage::Severity::Notification, "Hello from OpenGL command stream!");
+@endcode
+
+With default callback the messages will be printed on standard output:
+
+ DebugMessage::Source::Application DebugMessage::Type::Marker -1 DebugMessage::Severity::Notification
+ Hello from OpenGL command stream!
+*/
+class MAGNUM_EXPORT DebugMessage {
+ friend struct Implementation::DebugState;
+
+ public:
+ /**
+ * @brief Message source
+ *
+ * @see @ref insert(), @ref setCallback()
+ */
+ enum class Source: GLenum {
+ /** OpenGL */
+ #ifndef MAGNUM_TARGET_GLES
+ Api = GL_DEBUG_SOURCE_API,
+ #else
+ Api = GL_DEBUG_SOURCE_API_KHR,
+ #endif
+
+ /** Window system (GLX, WGL) */
+ #ifndef MAGNUM_TARGET_GLES
+ WindowSystem = GL_DEBUG_SOURCE_WINDOW_SYSTEM,
+ #else
+ WindowSystem = GL_DEBUG_SOURCE_WINDOW_SYSTEM_KHR,
+ #endif
+
+ /** %Shader compiler */
+ #ifndef MAGNUM_TARGET_GLES
+ ShaderCompiler = GL_DEBUG_SOURCE_SHADER_COMPILER,
+ #else
+ ShaderCompiler = GL_DEBUG_SOURCE_SHADER_COMPILER_KHR,
+ #endif
+
+ /** External debugger or third-party middleware */
+ #ifndef MAGNUM_TARGET_GLES
+ ThirdParty = GL_DEBUG_SOURCE_THIRD_PARTY,
+ #else
+ ThirdParty = GL_DEBUG_SOURCE_THIRD_PARTY_KHR,
+ #endif
+
+ /** The application */
+ #ifndef MAGNUM_TARGET_GLES
+ Application = GL_DEBUG_SOURCE_APPLICATION,
+ #else
+ Application = GL_DEBUG_SOURCE_APPLICATION_KHR,
+ #endif
+
+ /** Any other source */
+ #ifndef MAGNUM_TARGET_GLES
+ Other = GL_DEBUG_SOURCE_OTHER
+ #else
+ Other = GL_DEBUG_SOURCE_OTHER_KHR
+ #endif
+ };
+
+ /**
+ * @brief Message type
+ *
+ * @see @ref insert(), @ref setCallback()
+ */
+ enum class Type: GLenum {
+ /** OpenGL error */
+ #ifndef MAGNUM_TARGET_GLES
+ Error = GL_DEBUG_TYPE_ERROR,
+ #else
+ Error = GL_DEBUG_TYPE_ERROR_KHR,
+ #endif
+
+ /** Behavior that has been marked for deprecation */
+ #ifndef MAGNUM_TARGET_GLES
+ DeprecatedBehavior = GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR,
+ #else
+ DeprecatedBehavior = GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_KHR,
+ #endif
+
+ /** Behavior that is undefined according to the specification */
+ #ifndef MAGNUM_TARGET_GLES
+ UndefinedBehavior = GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR,
+ #else
+ UndefinedBehavior = GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_KHR,
+ #endif
+
+ /** Non-portable usage of extensions or shaders */
+ #ifndef MAGNUM_TARGET_GLES
+ Portability = GL_DEBUG_TYPE_PORTABILITY,
+ #else
+ Portability = GL_DEBUG_TYPE_PORTABILITY_KHR,
+ #endif
+
+ /** Implementation-dependent performance warning */
+ #ifndef MAGNUM_TARGET_GLES
+ Performance = GL_DEBUG_TYPE_PERFORMANCE,
+ #else
+ Performance = GL_DEBUG_TYPE_PERFORMANCE_KHR,
+ #endif
+
+ /** Any other type */
+ #ifndef MAGNUM_TARGET_GLES
+ Other = GL_DEBUG_TYPE_OTHER,
+ #else
+ Other = GL_DEBUG_TYPE_OTHER_KHR,
+ #endif
+
+ /** Annotation of the command stream */
+ #ifndef MAGNUM_TARGET_GLES
+ Marker = GL_DEBUG_TYPE_MARKER
+ #else
+ Marker = GL_DEBUG_TYPE_MARKER_KHR
+ #endif
+ };
+
+ /**
+ * @brief Message severity
+ *
+ * @see @ref insert(), @ref setCallback()
+ */
+ enum class Severity: GLenum {
+ /**
+ * Any OpenGL error, dangerous undefined behavior, shader
+ * compilation errors.
+ */
+ #ifndef MAGNUM_TARGET_GLES
+ High = GL_DEBUG_SEVERITY_HIGH,
+ #else
+ High = GL_DEBUG_SEVERITY_HIGH_KHR,
+ #endif
+
+ /**
+ * Severe performance warnings, shader compilation warnings, use of
+ * deprecated behavior.
+ */
+ #ifndef MAGNUM_TARGET_GLES
+ Medium = GL_DEBUG_SEVERITY_MEDIUM,
+ #else
+ Medium = GL_DEBUG_SEVERITY_MEDIUM_KHR,
+ #endif
+
+ /** Minor performance warnings, trivial undefined behavior. */
+ #ifndef MAGNUM_TARGET_GLES
+ Low = GL_DEBUG_SEVERITY_LOW,
+ #else
+ Low = GL_DEBUG_SEVERITY_LOW_KHR,
+ #endif
+
+ /** Any message other than error or performance warning. */
+ #ifndef MAGNUM_TARGET_GLES
+ Notification = GL_DEBUG_SEVERITY_NOTIFICATION
+ #else
+ Notification = GL_DEBUG_SEVERITY_NOTIFICATION_KHR
+ #endif
+ };
+
+ /**
+ * @brief Debug callback
+ *
+ * @see @ref setCallback()
+ */
+ typedef void(*Callback)(Source, Type, UnsignedInt, Severity, const std::string&, const void*);
+
+ /**
+ * @brief Max count of debug messages in log
+ *
+ * The result is cached, repeated queries don't result in repeated
+ * OpenGL calls. If OpenGL 4.3 is not supported and @extension{KHR,debug}
+ * desktop or ES extension is not available, returns `0`.
+ * @see @fn_gl{Get} with @def_gl{MAX_DEBUG_LOGGED_MESSAGES}
+ */
+ static Int maxLoggedMessages();
+
+ /**
+ * @brief Max debug message length
+ *
+ * The result is cached, repeated queries don't result in repeated
+ * OpenGL calls. If OpenGL 4.3 is not supported and @extension{KHR,debug}
+ * desktop or ES extension is not available, returns `0`.
+ * @see @fn_gl{Get} with @def_gl{MAX_DEBUG_MESSAGE_LENGTH}
+ */
+ static Int maxMessageLength();
+
+ /**
+ * @brief Insert message
+ * @param source Message source. Allowed values are
+ * @ref Source::ThirdParty or @ref Source::Application.
+ * @param type Message type
+ * @param id Message-specific ID
+ * @param severity Message severity
+ * @param string The actual message
+ *
+ * If OpenGL 4.3 is not supported and none of @extension{KHR,debug},
+ * @extension2{EXT,debug_marker} or @extension{GREMEDY,string_marker}
+ * is available, this function does nothing.
+ *
+ * If @extension{KHR,debug} is not available and only @extension2{EXT,debug_marker}
+ * or @extension{GREMEDY,string_marker} are available, only @p string
+ * is used and all other parameters are ignored. The call is then
+ * equivalent to the following:
+ * @code
+ * DebugMessage::insert(DebugMessage::Source::Application,
+ * DebugMessage::Type::Marker, 0, DebugMessage::Severity::Notification, string);
+ * @endcode
+ *
+ * @see @ref maxMessageLength(), @fn_gl{DebugMessageInsert},
+ * @fn_gl_extension2{InsertEventMarker,EXT,debug_marker} or
+ * @fn_gl_extension{StringMarker,GREMEDY,string_marker}
+ */
+ static void insert(Source source, Type type, UnsignedInt id, Severity severity, const std::string& string);
+
+ /**
+ * @brief Set debug message callback
+ *
+ * The messages are sent to the callback only if
+ * @ref Renderer::Feature::DebugOutput is enabled. If OpenGL 4.3 is not
+ * supported and @extension{KHR,debug} is not available, this function
+ * does nothing.
+ * @see @ref setDefaultCallback(),
+ * @ref Renderer::Feature::DebugOutputSynchronous
+ */
+ static void setCallback(Callback callback, const void* userParam = nullptr);
+
+ /**
+ * @brief Set default debug message callback
+ *
+ * See @ref setCallback() for more information. The message is printed
+ * to either @ref Corrade::Utility::Error "Error", @ref Corrade::Utility::Warning "Warning"
+ * or @ref Corrade::Utility::Debug "Debug" in the following format:
+ * @code
+ * DebugMessage::insert(DebugMessage::Source::Application,
+ * DebugMessage::Type::Marker, 1337, DebugMessage::Severity::Notification, "Hello from OpenGL command stream!");
+ * @endcode
+ *
+ * %DebugMessage::Source::Application %DebugMessage::Type::Marker -1 %DebugMessage::Severity::Notification
+ * Hello from OpenGL command stream!
+ */
+ static void setDefaultCallback();
+
+ DebugMessage() = delete;
+
+ private:
+ static MAGNUM_LOCAL void insertImplementationNoOp(Source, Type, UnsignedInt, Severity, const std::string&);
+ static MAGNUM_LOCAL void insertImplementationKhr(Source source, Type type, UnsignedInt id, Severity severity, const std::string& string);
+ static MAGNUM_LOCAL void insertImplementationExt(Source, Type, UnsignedInt, Severity, const std::string& string);
+ #ifndef MAGNUM_TARGET_GLES
+ static MAGNUM_LOCAL void insertImplementationGremedy(Source, Type, UnsignedInt, Severity, const std::string& string);
+ #endif
+
+ static MAGNUM_LOCAL void callbackImplementationNoOp(Callback, const void*);
+ static MAGNUM_LOCAL void callbackImplementationKhr(Callback callback, const void* userParam);
+};
+
+/** @debugoperator{Magnum::DebugMessage} */
+Debug MAGNUM_EXPORT operator<<(Debug debug, DebugMessage::Source value);
+
+/** @debugoperator{Magnum::DebugMessage} */
+Debug MAGNUM_EXPORT operator<<(Debug debug, DebugMessage::Type value);
+
+/** @debugoperator{Magnum::DebugMessage} */
+Debug MAGNUM_EXPORT operator<<(Debug debug, DebugMessage::Severity value);
+
+}
+
+#endif
diff --git a/src/DebugTools/ResourceManager.cpp b/src/DebugTools/ResourceManager.cpp
index 8a8491f55..94d9f29a4 100644
--- a/src/DebugTools/ResourceManager.cpp
+++ b/src/DebugTools/ResourceManager.cpp
@@ -35,11 +35,11 @@
namespace Magnum {
-#ifndef _WIN32
-template class ResourceManager;
-#else
-template class MAGNUM_DEBUGTOOLS_EXPORT ResourceManager;
+template class
+#if defined(CORRADE_TARGET_WINDOWS) && _MSC_VER
+MAGNUM_DEBUGTOOLS_EXPORT
#endif
+ResourceManager;
namespace DebugTools {
diff --git a/src/DebugTools/ResourceManager.h b/src/DebugTools/ResourceManager.h
index d075c51aa..ae10d147f 100644
--- a/src/DebugTools/ResourceManager.h
+++ b/src/DebugTools/ResourceManager.h
@@ -55,7 +55,7 @@ namespace Magnum {
/** @todo Do the listing in one place, not five thousand! */
-#ifndef _WIN32
+#ifndef CORRADE_TARGET_WINDOWS
extern template ResourceManager MAGNUM_DEBUGTOOLS_EXPORT *& ResourceManager::internalInstance();
#else
extern template class MAGNUM_DEBUGTOOLS_EXPORT ResourceManager;
diff --git a/src/DefaultFramebuffer.h b/src/DefaultFramebuffer.h
index 245fc4998..eb8706cbd 100644
--- a/src/DefaultFramebuffer.h
+++ b/src/DefaultFramebuffer.h
@@ -92,7 +92,7 @@ class MAGNUM_EXPORT DefaultFramebuffer: public AbstractFramebuffer {
/**
* The default framebuffer does not exist.
- * @requires_es_extension %Extension @es_extension{OES,surfaceless_context}
+ * @requires_gles30 %Extension @es_extension{OES,surfaceless_context}
*/
#ifndef MAGNUM_TARGET_GLES2
Undefined = GL_FRAMEBUFFER_UNDEFINED
@@ -291,6 +291,18 @@ class MAGNUM_EXPORT DefaultFramebuffer: public AbstractFramebuffer {
explicit MAGNUM_LOCAL DefaultFramebuffer();
+ /** @brief Copying is not allowed */
+ DefaultFramebuffer(const DefaultFramebuffer&) = delete;
+
+ /** @brief Moving is not allowed */
+ DefaultFramebuffer(DefaultFramebuffer&&) = delete;
+
+ /** @brief Copying is not allowed */
+ DefaultFramebuffer& operator=(const DefaultFramebuffer&) = delete;
+
+ /** @brief Moving is not allowed */
+ DefaultFramebuffer& operator=(DefaultFramebuffer&& other) = delete;
+
/**
* @brief Check framebuffer status
* @param target Target for which to check the status
diff --git a/src/Extensions.h b/src/Extensions.h
index beef67726..4ae0faf3e 100644
--- a/src/Extensions.h
+++ b/src/Extensions.h
@@ -181,6 +181,8 @@ namespace GL {
_extension(GL,EXT,transform_feedback, GL210, GL300) // #352
_extension(GL,EXT,direct_state_access, GL210, None) // #353
_extension(GL,EXT,texture_snorm, GL300, GL310) // #365
+ _extension(GL,EXT,debug_label, GL210, None) // #439
+ _extension(GL,EXT,debug_marker, GL210, None) // #440
} namespace GREMEDY {
_extension(GL,GREMEDY,string_marker, GL210, None) // #311
} namespace INTEL {
@@ -215,6 +217,7 @@ namespace GL {
_extension(GL,EXT,discard_framebuffer, GLES200, GLES300) // #64
_extension(GL,EXT,blend_minmax, GLES200, GLES300) // #65
_extension(GL,EXT,read_format_bgra, GLES200, None) // #66
+ _extension(GL,EXT,debug_label, GLES200, None) // #98
_extension(GL,EXT,debug_marker, GLES200, None) // #99
_extension(GL,EXT,occlusion_query_boolean, GLES200, GLES300) // #100
_extension(GL,EXT,separate_shader_objects, GLES200, None) // #101
@@ -232,9 +235,9 @@ namespace GL {
_extension(GL,NV,fbo_color_attachments, GLES200, GLES300) // #92
_extension(GL,NV,read_buffer, GLES200, GLES300) // #93
_extension(GL,NV,read_buffer_front, GLES200, None) // #93
- _extension(GL,NV,read_depth, GLES200, GLES300) // #94
+ _extension(GL,NV,read_depth, GLES200, None) // #94
_extension(GL,NV,read_stencil, GLES200, None) // #94
- _extension(GL,NV,read_depth_stencil, GLES200, GLES300) // #94
+ _extension(GL,NV,read_depth_stencil, GLES200, None) // #94
_extension(GL,NV,framebuffer_blit, GLES200, GLES300) // #142
_extension(GL,NV,framebuffer_multisample, GLES200, GLES300) // #143
_extension(GL,NV,texture_border_clamp, GLES200, None) // #149
diff --git a/src/Framebuffer.cpp b/src/Framebuffer.cpp
index 89636c57b..39d50211b 100644
--- a/src/Framebuffer.cpp
+++ b/src/Framebuffer.cpp
@@ -31,6 +31,7 @@
#include "Renderbuffer.h"
#include "Texture.h"
+#include "Implementation/DebugState.h"
#include "Implementation/State.h"
#include "Implementation/FramebufferState.h"
@@ -78,6 +79,9 @@ Framebuffer::Framebuffer(const Range2Di& viewport) {
}
Framebuffer::~Framebuffer() {
+ /* Moved out, nothing to do */
+ if(!_id) return;
+
/* If bound, remove itself from state */
Implementation::FramebufferState* state = Context::current()->state().framebuffer;
if(state->readBinding == _id) state->readBinding = 0;
@@ -86,6 +90,15 @@ Framebuffer::~Framebuffer() {
glDeleteFramebuffers(1, &_id);
}
+std::string Framebuffer::label() const {
+ return Context::current()->state().debug->getLabelImplementation(GL_FRAMEBUFFER, _id);
+}
+
+Framebuffer& Framebuffer::setLabel(const std::string& label) {
+ Context::current()->state().debug->labelImplementation(GL_FRAMEBUFFER, _id, label);
+ return *this;
+}
+
Framebuffer& Framebuffer::mapForDraw(std::initializer_list> attachments) {
/* Max attachment location */
std::size_t max = 0;
@@ -172,7 +185,7 @@ void Framebuffer::texture2DImplementationDSA(BufferAttachment attachment, GLenum
void Framebuffer::texture3DImplementationDefault(BufferAttachment attachment, Texture3D& texture, GLint mipLevel, GLint layer) {
/** @todo Check for texture target compatibility */
- /** @todo Get some extension wrangler for glFramebufferTexture3D() (extension only) */
+ /** @todo Re-enable when extension loader is available for ES */
#ifndef MAGNUM_TARGET_GLES
glFramebufferTexture3D(GLenum(bindInternal()), GLenum(attachment), GLenum(texture.target()), texture.id(), mipLevel, layer);
#else
@@ -180,6 +193,8 @@ void Framebuffer::texture3DImplementationDefault(BufferAttachment attachment, Te
static_cast(texture);
static_cast(mipLevel);
static_cast(layer);
+ CORRADE_INTERNAL_ASSERT(false);
+ //glFramebufferTexture3DOES(GLenum(bindInternal()), GLenum(attachment), GLenum(texture.target()), texture.id(), mipLevel, layer);
#endif
}
diff --git a/src/Framebuffer.h b/src/Framebuffer.h
index 3f2ab2115..fdf5f3e86 100644
--- a/src/Framebuffer.h
+++ b/src/Framebuffer.h
@@ -31,6 +31,10 @@
#include "AbstractFramebuffer.h"
#include "CubeMapTexture.h"
+#ifdef _X11_XLIB_H_ /* Xlib.h, I hate you sincerely */
+#undef Status
+#endif
+
namespace Magnum {
/**
@@ -95,8 +99,9 @@ to avoid unnecessary calls to @fn_gl{BindFramebuffer}. See their respective
documentation for more information.
@requires_gl30 %Extension @extension{ARB,framebuffer_object}
+@todo `MAX_COLOR_ATTACHMENTS`
*/
-class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer {
+class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer, public AbstractObject {
friend class Context;
public:
@@ -113,6 +118,9 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer {
/**
* @brief Constructor
* @param id Color attachment id
+ *
+ * @requires_gles30 %Extension @es_extension{NV,fbo_color_attachments}
+ * is required for @p id greater than 0.
*/
constexpr explicit ColorAttachment(UnsignedInt id): attachment(GL_COLOR_ATTACHMENT0 + id) {}
@@ -308,6 +316,12 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer {
*/
explicit Framebuffer(const Range2Di& viewport);
+ /** @brief Copying is not allowed */
+ Framebuffer(const Framebuffer&) = delete;
+
+ /** @brief Move constructor */
+ Framebuffer(Framebuffer&& other) noexcept;
+
/**
* @brief Destructor
*
@@ -316,6 +330,41 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer {
*/
~Framebuffer();
+ /** @brief Copying is not allowed */
+ Framebuffer& operator=(const Framebuffer&) = delete;
+
+ /** @brief Move assignment */
+ Framebuffer& operator=(Framebuffer&& other) noexcept;
+
+ /** @brief OpenGL framebuffer ID */
+ GLuint id() const { return _id; }
+
+ /**
+ * @brief %Framebuffer label
+ *
+ * The result is *not* cached, repeated queries will result in repeated
+ * OpenGL calls. If neither @extension{KHR,debug} nor
+ * @extension2{EXT,debug_label} desktop or ES extension is available,
+ * this function returns empty string.
+ * @see @fn_gl{GetObjectLabel} or
+ * @fn_gl_extension2{GetObjectLabel,EXT,debug_label} with
+ * @def_gl{FRAMEBUFFER}
+ */
+ std::string label() const;
+
+ /**
+ * @brief Set framebuffer label
+ * @return Reference to self (for method chaining)
+ *
+ * Default is empty string. If neither @extension{KHR,debug} nor
+ * @extension2{EXT,debug_label} desktop or ES extension is available,
+ * this function does nothing.
+ * @see @ref maxLabelLength(), @fn_gl{ObjectLabel} or
+ * @fn_gl_extension2{LabelObject,EXT,debug_label} with
+ * @def_gl{FRAMEBUFFER}
+ */
+ Framebuffer& setLabel(const std::string& label);
+
/**
* @brief Check framebuffer status
* @param target Target for which check the status
@@ -560,6 +609,19 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer {
/** @debugoperator{DefaultFramebuffer} */
Debug MAGNUM_EXPORT operator<<(Debug debug, Framebuffer::Status value);
+inline Framebuffer::Framebuffer(Framebuffer&& other) noexcept {
+ _id = other._id;
+ _viewport = other._viewport;
+ other._id = 0;
+ other._viewport = {};
+}
+
+inline Framebuffer& Framebuffer::operator=(Framebuffer&& other) noexcept {
+ std::swap(_id, other._id);
+ std::swap(_viewport, other._viewport);
+ return *this;
+}
+
}
#endif
diff --git a/src/Implementation/DebugState.cpp b/src/Implementation/DebugState.cpp
new file mode 100644
index 000000000..e00b1bb62
--- /dev/null
+++ b/src/Implementation/DebugState.cpp
@@ -0,0 +1,62 @@
+/*
+ This file is part of Magnum.
+
+ Copyright © 2010, 2011, 2012, 2013 VladimÃr VondruÅ¡
+
+ 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 "DebugState.h"
+
+#include "AbstractObject.h"
+#include "Context.h"
+#include "Extensions.h"
+
+namespace Magnum { namespace Implementation {
+
+DebugState::DebugState(Context& context): maxLabelLength(0), maxLoggedMessages(0), maxMessageLength(0), messageCallback(nullptr) {
+ if(context.isExtensionSupported()) {
+ getLabelImplementation = &AbstractObject::getLabelImplementationKhr;
+ labelImplementation = &AbstractObject::labelImplementationKhr;
+ messageInsertImplementation = &DebugMessage::insertImplementationKhr;
+ messageCallbackImplementation = &DebugMessage::callbackImplementationKhr;
+
+ } else {
+ if(context.isExtensionSupported()) {
+ getLabelImplementation = &AbstractObject::getLabelImplementationExt;
+ labelImplementation = &AbstractObject::labelImplementationExt;
+ } else {
+ getLabelImplementation = &AbstractObject::getLabelImplementationNoOp;
+ labelImplementation = &AbstractObject::labelImplementationNoOp;
+ }
+
+ if(context.isExtensionSupported())
+ messageInsertImplementation = &DebugMessage::insertImplementationExt;
+ #ifndef MAGNUM_TARGET_GLES
+ else if(context.isExtensionSupported())
+ messageInsertImplementation = &DebugMessage::insertImplementationGremedy;
+ #endif
+ else
+ messageInsertImplementation = &DebugMessage::insertImplementationNoOp;
+
+ messageCallbackImplementation = &DebugMessage::callbackImplementationNoOp;
+ }
+}
+
+}}
diff --git a/src/Implementation/DebugState.h b/src/Implementation/DebugState.h
new file mode 100644
index 000000000..0b3ec18f1
--- /dev/null
+++ b/src/Implementation/DebugState.h
@@ -0,0 +1,48 @@
+#ifndef Magnum_Implementation_DebugState_h
+#define Magnum_Implementation_DebugState_h
+/*
+ This file is part of Magnum.
+
+ Copyright © 2010, 2011, 2012, 2013 VladimÃr VondruÅ¡
+
+ 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
+
+#include "DebugMessage.h"
+
+namespace Magnum { namespace Implementation {
+
+struct DebugState {
+ DebugState(Context& context);
+
+ std::string(*getLabelImplementation)(GLenum, GLuint);
+ void(*labelImplementation)(GLenum, GLuint, const std::string&);
+
+ void(*messageInsertImplementation)(DebugMessage::Source, DebugMessage::Type, UnsignedInt, DebugMessage::Severity, const std::string&);
+ void(*messageCallbackImplementation)(DebugMessage::Callback, const void*);
+
+ GLint maxLabelLength, maxLoggedMessages, maxMessageLength;
+ DebugMessage::Callback messageCallback;
+};
+
+}}
+
+#endif
diff --git a/src/Implementation/State.cpp b/src/Implementation/State.cpp
index 7fd1619f8..ff35e3c64 100644
--- a/src/Implementation/State.cpp
+++ b/src/Implementation/State.cpp
@@ -24,7 +24,10 @@
#include "State.h"
+#include "Context.h"
+#include "Extensions.h"
#include "Implementation/BufferState.h"
+#include "Implementation/DebugState.h"
#include "Implementation/FramebufferState.h"
#include "Implementation/MeshState.h"
#include "Implementation/RendererState.h"
@@ -34,14 +37,33 @@
namespace Magnum { namespace Implementation {
-State::State():
+State::State(Context& context):
buffer(new BufferState),
+ debug(new DebugState(context)),
framebuffer(new FramebufferState),
mesh(new MeshState),
renderer(new RendererState),
shader(new ShaderState),
shaderProgram(new ShaderProgramState),
- texture(new TextureState) {}
+ texture(new TextureState)
+{
+
+ Debug() << "Using optional features:";
+
+ if(context.isExtensionSupported())
+ Debug() << " " << Extensions::GL::KHR::debug::string();
+ else {
+ if(context.isExtensionSupported())
+ Debug() << " " << Extensions::GL::EXT::debug_label::string();
+
+ if(context.isExtensionSupported())
+ Debug() << " " << Extensions::GL::EXT::debug_marker::string();
+ #ifndef MAGNUM_TARGET_GLES
+ else if(context.isExtensionSupported())
+ Debug() << " " << Extensions::GL::GREMEDY::string_marker::string();
+ #endif
+ }
+}
State::~State() {
delete texture;
@@ -50,6 +72,7 @@ State::~State() {
delete renderer;
delete mesh;
delete framebuffer;
+ delete debug;
delete buffer;
}
diff --git a/src/Implementation/State.h b/src/Implementation/State.h
index 79b322d76..36570baa3 100644
--- a/src/Implementation/State.h
+++ b/src/Implementation/State.h
@@ -24,9 +24,12 @@
DEALINGS IN THE SOFTWARE.
*/
+#include "Magnum.h"
+
namespace Magnum { namespace Implementation {
struct BufferState;
+struct DebugState;
struct FramebufferState;
struct MeshState;
struct RendererState;
@@ -35,10 +38,13 @@ struct ShaderProgramState;
struct TextureState;
struct State {
- State();
+ /* Initializes context-based functionality */
+ State(Context& context);
+
~State();
BufferState* const buffer;
+ DebugState* const debug;
FramebufferState* const framebuffer;
MeshState* const mesh;
RendererState* const renderer;
diff --git a/src/Implementation/TextureState.cpp b/src/Implementation/TextureState.cpp
index 7c08ebceb..689b7aa40 100644
--- a/src/Implementation/TextureState.cpp
+++ b/src/Implementation/TextureState.cpp
@@ -26,9 +26,9 @@
namespace Magnum { namespace Implementation {
-TextureState::TextureState(): maxAnisotropy(0.0f), currentLayer(0)
+TextureState::TextureState(): maxMaxAnisotropy(0.0f), currentLayer(0)
#ifndef MAGNUM_TARGET_GLES
- , maxColorSamples(0), maxDepthSamples(0), maxIntegerSamples(0)
+ , maxColorSamples(0), maxDepthSamples(0), maxIntegerSamples(0), bufferOffsetAlignment(0)
#endif
{}
diff --git a/src/Implementation/TextureState.h b/src/Implementation/TextureState.h
index 91875bc9e..ab5d237fa 100644
--- a/src/Implementation/TextureState.h
+++ b/src/Implementation/TextureState.h
@@ -34,12 +34,13 @@ struct TextureState {
explicit TextureState();
~TextureState();
- GLfloat maxAnisotropy;
+ GLfloat maxMaxAnisotropy;
GLint currentLayer;
#ifndef MAGNUM_TARGET_GLES
GLint maxColorSamples,
maxDepthSamples,
- maxIntegerSamples;
+ maxIntegerSamples,
+ bufferOffsetAlignment;
#endif
std::vector bindings;
diff --git a/src/Magnum.h b/src/Magnum.h
index e5fb3e8ab..1206eb0f9 100644
--- a/src/Magnum.h
+++ b/src/Magnum.h
@@ -572,7 +572,7 @@ class CubeMapTexture;
class CubeMapTextureArray;
#endif
-/* DebugMarker forward declaration is not needed */
+/* DebugMessage used only statically */
/* DefaultFramebuffer is available only through global instance */
/* DimensionTraits forward declaration is not needed */
diff --git a/src/Math/Matrix4.h b/src/Math/Matrix4.h
index 145105b57..2a7abdf1c 100644
--- a/src/Math/Matrix4.h
+++ b/src/Math/Matrix4.h
@@ -31,7 +31,7 @@
#include "Math/Matrix.h"
#include "Math/Vector4.h"
-#ifdef _WIN32 /* I so HATE windef.h */
+#ifdef CORRADE_TARGET_WINDOWS /* I so HATE windef.h */
#undef near
#undef far
#endif
diff --git a/src/Mesh.cpp b/src/Mesh.cpp
index bb2235e17..533796605 100644
--- a/src/Mesh.cpp
+++ b/src/Mesh.cpp
@@ -29,6 +29,7 @@
#include "Buffer.h"
#include "Context.h"
#include "Extensions.h"
+#include "Implementation/DebugState.h"
#include "Implementation/BufferState.h"
#include "Implementation/MeshState.h"
#include "Implementation/State.h"
@@ -92,6 +93,9 @@ Mesh::Mesh(MeshPrimitive primitive): _primitive(primitive), _vertexCount(0), _in
}
Mesh::~Mesh() {
+ /* Moved out, nothing to do */
+ if(!_id) return;
+
/* Remove current vao from the state */
GLuint& current = Context::current()->state().mesh->currentVAO;
if(current == _id) current = 0;
@@ -137,6 +141,23 @@ Mesh& Mesh::operator=(Mesh&& other) noexcept {
return *this;
}
+std::string Mesh::label() const {
+ #ifndef MAGNUM_TARGET_GLES
+ return Context::current()->state().debug->getLabelImplementation(GL_VERTEX_ARRAY, _id);
+ #else
+ return Context::current()->state().debug->getLabelImplementation(GL_VERTEX_ARRAY_KHR, _id);
+ #endif
+}
+
+Mesh& Mesh::setLabel(const std::string& label) {
+ #ifndef MAGNUM_TARGET_GLES
+ Context::current()->state().debug->labelImplementation(GL_VERTEX_ARRAY, _id, label);
+ #else
+ Context::current()->state().debug->labelImplementation(GL_VERTEX_ARRAY_KHR, _id, label);
+ #endif
+ return *this;
+}
+
Mesh& Mesh::setIndexBuffer(Buffer& buffer, GLintptr offset, IndexType type, UnsignedInt start, UnsignedInt end) {
#if defined(CORRADE_TARGET_NACL) || defined(CORRADE_TARGET_EMSCRIPTEN)
CORRADE_ASSERT(buffer.targetHint() == Buffer::Target::ElementArray,
@@ -185,13 +206,16 @@ void Mesh::drawInternal(Int firstVertex, Int vertexCount, GLintptr indexOffset,
}
void Mesh::bindVAO(GLuint vao) {
- /** @todo Get some extension wrangler instead to avoid linker errors to glBindVertexArray() on ES2 */
- #ifndef MAGNUM_TARGET_GLES2
+ /** @todo Re-enable when extension loader is available for ES */
GLuint& current = Context::current()->state().mesh->currentVAO;
- if(current != vao) glBindVertexArray(current = vao);
- #else
- static_cast(vao);
- #endif
+ if(current != vao) {
+ #ifndef MAGNUM_TARGET_GLES2
+ glBindVertexArray(current = vao);
+ #else
+ CORRADE_INTERNAL_ASSERT(false);
+ //glBindVertexArrayOES(current = vao);
+ #endif
+ }
}
void Mesh::vertexAttribPointer(const Attribute& attribute) {
@@ -246,7 +270,7 @@ void Mesh::initializeContextBasedFunctionality(Context& context) {
#endif
}
-void Mesh::createImplementationDefault() {}
+void Mesh::createImplementationDefault() { _id = 0; }
void Mesh::createImplementationVAO() {
/** @todo Get some extension wrangler instead to avoid linker errors to glGenVertexArrays() on ES2 */
@@ -260,7 +284,7 @@ void Mesh::destroyImplementationDefault() {}
void Mesh::destroyImplementationVAO() {
/** @todo Get some extension wrangler instead to avoid linker errors to glDeleteVertexArrays() on ES2 */
#ifndef MAGNUM_TARGET_GLES2
- if(_id) glDeleteVertexArrays(1, &_id);
+ glDeleteVertexArrays(1, &_id);
#endif
}
diff --git a/src/Mesh.h b/src/Mesh.h
index 57af67504..893615125 100644
--- a/src/Mesh.h
+++ b/src/Mesh.h
@@ -307,7 +307,7 @@ drawing commands are used on desktop OpenGL and OpenGL ES 3.0. See also
@todo test vertex specification & drawing
@todo How to glDrawElementsBaseVertex()/vertex offset -- in draw()?
*/
-class MAGNUM_EXPORT Mesh {
+class MAGNUM_EXPORT Mesh: public AbstractObject {
friend class Context;
friend class MeshView;
@@ -407,6 +407,40 @@ class MAGNUM_EXPORT Mesh {
/** @brief Move assignment */
Mesh& operator=(Mesh&& other) noexcept;
+ /**
+ * @brief OpenGL mesh ID
+ *
+ * If @extension{APPLE,vertex_array_object} is not available, returns
+ * `0`.
+ */
+ GLuint id() const { return _id; }
+
+ /**
+ * @brief %Mesh label
+ *
+ * The result is *not* cached, repeated queries will result in repeated
+ * OpenGL calls. If neither @extension{KHR,debug} nor
+ * @extension2{EXT,debug_label} desktop or ES extension is available,
+ * this function returns empty string.
+ * @see @fn_gl{GetObjectLabel} with @def_gl{VERTEX_ARRAY} or
+ * @fn_gl_extension2{GetObjectLabel,EXT,debug_label} with
+ * @def_gl{VERTEX_ARRAY_OBJECT_EXT}
+ */
+ std::string label() const;
+
+ /**
+ * @brief Set mesh label
+ * @return Reference to self (for method chaining)
+ *
+ * Default is empty string. If neither @extension{KHR,debug} nor
+ * @extension2{EXT,debug_label} desktop or ES extension is available,
+ * this function does nothing.
+ * @see @ref maxLabelLength(), @fn_gl{ObjectLabel} with
+ * @def_gl{VERTEX_ARRAY} or @fn_gl_extension2{LabelObject,EXT,debug_label}
+ * with @def_gl{VERTEX_ARRAY_OBJECT_EXT}
+ */
+ Mesh& setLabel(const std::string& label);
+
/**
* @brief Index size
*
diff --git a/src/Platform/Sdl2Application.cpp b/src/Platform/Sdl2Application.cpp
index a28f6a4e9..1999c7ee7 100644
--- a/src/Platform/Sdl2Application.cpp
+++ b/src/Platform/Sdl2Application.cpp
@@ -117,6 +117,46 @@ bool Sdl2Application::tryCreateContext(const Configuration& configuration) {
/** @todo Remove when Emscripten has proper SDL2 support */
#ifndef CORRADE_TARGET_EMSCRIPTEN
+
+ #ifdef __APPLE__
+
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
+
+ if(!(window = SDL_CreateWindow(configuration.title().data(),
+ SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
+ configuration.size().x(), configuration.size().y(),
+ SDL_WINDOW_OPENGL|flags))){
+ Error() << "Platform::Sdl2Application::tryCreateContext(): cannot create core window:" << SDL_GetError();
+ return false;
+ }
+
+ if(!(context = SDL_GL_CreateContext(window))){
+ Error() << "Platform::Sdl2Application::tryCreateContext(): cannot create core context:" << SDL_GetError() << " falling back to compatibility context.";
+ SDL_DestroyWindow(window);
+
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY);
+
+ if(!(window = SDL_CreateWindow(configuration.title().data(),
+ SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
+ configuration.size().x(), configuration.size().y(),
+ SDL_WINDOW_OPENGL|flags))){
+ Error() << "Platform::Sdl2Application::tryCreateContext(): cannot create window:" << SDL_GetError();
+ return false;
+ }
+
+ if(!(context = SDL_GL_CreateContext(window))){
+ Error() << "Platform::Sdl2Application::tryCreateContext(): cannot create compatibility context:" << SDL_GetError();
+ SDL_DestroyWindow(window);
+ window = nullptr;
+ return false;
+ }
+ }
+
+ #else
if(!(window = SDL_CreateWindow(configuration.title().data(),
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
configuration.size().x(), configuration.size().y(),
@@ -131,6 +171,7 @@ bool Sdl2Application::tryCreateContext(const Configuration& configuration) {
window = nullptr;
return false;
}
+ #endif
#else
context = SDL_SetVideoMode(configuration.size().x(), configuration.size().y(), 24, SDL_OPENGL|SDL_HWSURFACE|SDL_DOUBLEBUF);
#endif
diff --git a/src/Platform/Sdl2Application.h b/src/Platform/Sdl2Application.h
index 616f0a4a4..0b839c18c 100644
--- a/src/Platform/Sdl2Application.h
+++ b/src/Platform/Sdl2Application.h
@@ -34,7 +34,7 @@
#include "Math/Vector2.h"
#include "Magnum.h"
-#ifdef _WIN32 /* Windows version of SDL2 redefines main(), we don't want that */
+#ifdef CORRADE_TARGET_WINDOWS /* Windows version of SDL2 redefines main(), we don't want that */
#define SDL_MAIN_HANDLED
#endif
#include
diff --git a/src/Platform/magnum-info.cpp b/src/Platform/magnum-info.cpp
index 5d79d35f1..deb10c8a7 100644
--- a/src/Platform/magnum-info.cpp
+++ b/src/Platform/magnum-info.cpp
@@ -31,7 +31,9 @@
#include "AbstractShaderProgram.h"
#include "Buffer.h"
+#include "BufferTexture.h"
#include "Context.h"
+#include "DebugMessage.h"
#include "Extensions.h"
#include "Framebuffer.h"
#include "Mesh.h"
@@ -322,6 +324,12 @@ MagnumInfo::MagnumInfo(const Arguments& arguments): Platform::WindowlessApplicat
_l(Shader::maxTessellationEvaluationInputComponents())
_l(Shader::maxTessellationEvaluationOutputComponents())
}
+
+ if(c->isExtensionSupported()) {
+ _h(ARB::texture_buffer_range)
+
+ _l(BufferTexture::offsetAlignment())
+ }
#endif
#ifndef MAGNUM_TARGET_GLES2
@@ -356,7 +364,15 @@ MagnumInfo::MagnumInfo(const Arguments& arguments): Platform::WindowlessApplicat
if(c->isExtensionSupported()) {
_h(EXT::texture_filter_anisotropic)
- _l(Sampler::maxAnisotropy())
+ _l(Sampler::maxMaxAnisotropy())
+ }
+
+ if(c->isExtensionSupported()) {
+ _h(KHR::debug)
+
+ _l(AbstractObject::maxLabelLength())
+ _l(DebugMessage::maxLoggedMessages())
+ _l(DebugMessage::maxMessageLength())
}
#undef _l
diff --git a/src/Query.cpp b/src/Query.cpp
index 79203c0d7..1e3adfa56 100644
--- a/src/Query.cpp
+++ b/src/Query.cpp
@@ -26,38 +26,65 @@
#include
+#include "Context.h"
+#include "Implementation/DebugState.h"
+#include "Implementation/State.h"
+
namespace Magnum {
AbstractQuery::AbstractQuery(): target() {
- /** @todo Get some extension wrangler instead to avoid undeclared glGenQueries() on ES2 */
+ /** @todo Re-enable when extension loader is available for ES */
#ifndef MAGNUM_TARGET_GLES2
glGenQueries(1, &_id);
+ #elif defined(CORRADE_TARGET_NACL)
+ glGenQueriesEXT(1, &_id);
#else
CORRADE_INTERNAL_ASSERT(false);
- //glGenQueriesEXT(1, &_id);
#endif
}
AbstractQuery::~AbstractQuery() {
- /** @todo Get some extension wrangler instead to avoid undeclared glGenQueries() on ES2 */
+ /* Moved out, nothing to do */
+ if(!_id) return;
+
+ /** @todo Re-enable when extension loader is available for ES */
#ifndef MAGNUM_TARGET_GLES2
glDeleteQueries(1, &_id);
+ #elif defined(CORRADE_TARGET_NACL)
+ glDeleteQueriesEXT(1, &_id);
#else
CORRADE_INTERNAL_ASSERT(false);
- //glDeleteQueriesEXT(1, &_id);
#endif
}
+std::string AbstractQuery::label() const {
+ #ifndef MAGNUM_TARGET_GLES
+ return Context::current()->state().debug->getLabelImplementation(GL_QUERY, _id);
+ #else
+ return Context::current()->state().debug->getLabelImplementation(GL_QUERY_KHR, _id);
+ #endif
+}
+
+AbstractQuery& AbstractQuery::setLabel(const std::string& label) {
+ #ifndef MAGNUM_TARGET_GLES
+ Context::current()->state().debug->labelImplementation(GL_QUERY, _id, label);
+ #else
+ Context::current()->state().debug->labelImplementation(GL_QUERY_KHR, _id, label);
+ #endif
+ return *this;
+}
+
bool AbstractQuery::resultAvailable() {
CORRADE_ASSERT(!target, "AbstractQuery::resultAvailable(): the query is currently running", false);
- /** @todo Re-enable when extension wrangler is available for ES */
+ /** @todo Re-enable when extension loader is available for ES */
GLuint result;
#ifndef MAGNUM_TARGET_GLES2
glGetQueryObjectuiv(_id, GL_QUERY_RESULT_AVAILABLE, &result);
+ #elif defined(CORRADE_TARGET_NACL)
+ glGetQueryObjectuivEXT(_id, GL_QUERY_RESULT_AVAILABLE, &result);
#else
CORRADE_INTERNAL_ASSERT(false);
- //glGetQueryObjectuivEXT(_id, GL_QUERY_RESULT_AVAILABLE, &result);
#endif
return result == GL_TRUE;
}
@@ -66,13 +93,14 @@ bool AbstractQuery::resultAvailable() {
template<> bool AbstractQuery::result() {
CORRADE_ASSERT(!target, "AbstractQuery::result(): the query is currently running", {});
- /** @todo Re-enable when extension wrangler is available for ES */
+ /** @todo Re-enable when extension loader is available for ES */
GLuint result;
#ifndef MAGNUM_TARGET_GLES2
glGetQueryObjectuiv(_id, GL_QUERY_RESULT, &result);
+ #elif defined(CORRADE_TARGET_NACL)
+ glGetQueryObjectuivEXT(_id, GL_QUERY_RESULT, &result);
#else
CORRADE_INTERNAL_ASSERT(false);
- //glGetQueryObjectuivEXT(_id, GL_QUERY_RESULT, &result);
#endif
return result == GL_TRUE;
}
@@ -80,13 +108,14 @@ template<> bool AbstractQuery::result() {
template<> UnsignedInt AbstractQuery::result() {
CORRADE_ASSERT(!target, "AbstractQuery::result(): the query is currently running", {});
- /** @todo Re-enable when extension wrangler is available for ES */
+ /** @todo Re-enable when extension loader is available for ES */
UnsignedInt result;
#ifndef MAGNUM_TARGET_GLES2
glGetQueryObjectuiv(_id, GL_QUERY_RESULT, &result);
+ #elif defined(CORRADE_TARGET_NACL)
+ glGetQueryObjectuivEXT(_id, GL_QUERY_RESULT, &result);
#else
CORRADE_INTERNAL_ASSERT(false);
- //glGetQueryObjectuivEXT(_id, GL_QUERY_RESULT, &result);
#endif
return result;
}
@@ -94,13 +123,14 @@ template<> UnsignedInt AbstractQuery::result() {
template<> Int AbstractQuery::result() {
CORRADE_ASSERT(!target, "AbstractQuery::result(): the query is currently running", {});
- /** @todo Re-enable when extension wrangler is available for ES */
+ /** @todo Re-enable when extension loader is available for ES */
Int result;
#ifndef MAGNUM_TARGET_GLES
glGetQueryObjectiv(_id, GL_QUERY_RESULT, &result);
+ #elif defined(CORRADE_TARGET_NACL)
+ glGetQueryObjectivEXT(_id, GL_QUERY_RESULT, &result);
#else
CORRADE_INTERNAL_ASSERT(false);
- //glGetQueryObjectivEXT(_id, GL_QUERY_RESULT, &result);
#endif
return result;
}
@@ -108,7 +138,7 @@ template<> Int AbstractQuery::result() {
template<> UnsignedLong AbstractQuery::result() {
CORRADE_ASSERT(!target, "AbstractQuery::result(): the query is currently running", {});
- /** @todo Re-enable when extension wrangler is available for ES */
+ /** @todo Re-enable when extension loader is available for ES */
UnsignedLong result;
#ifndef MAGNUM_TARGET_GLES
glGetQueryObjectui64v(_id, GL_QUERY_RESULT, &result);
@@ -122,7 +152,7 @@ template<> UnsignedLong AbstractQuery::result() {
template<> Long AbstractQuery::result() {
CORRADE_ASSERT(!target, "AbstractQuery::result(): the query is currently running", {});
- /** @todo Re-enable when extension wrangler is available for ES */
+ /** @todo Re-enable when extension loader is available for ES */
Long result;
#ifndef MAGNUM_TARGET_GLES
glGetQueryObjecti64v(_id, GL_QUERY_RESULT, &result);
@@ -137,25 +167,27 @@ template<> Long AbstractQuery::result() {
void AbstractQuery::begin(GLenum target) {
CORRADE_ASSERT(!this->target, "AbstractQuery::begin(): the query is already running", );
- /** @todo Re-enable when extension wrangler is available for ES */
+ /** @todo Re-enable when extension loader is available for ES */
#ifndef MAGNUM_TARGET_GLES2
glBeginQuery(this->target = target, id());
+ #elif defined(CORRADE_TARGET_NACL)
+ glBeginQueryEXT(this->target = target, id());
#else
- CORRADE_INTERNAL_ASSERT(false);
static_cast(target);
- //glBeginQueryEXT(this->target = target, id());
+ CORRADE_INTERNAL_ASSERT(false);
#endif
}
void AbstractQuery::end() {
CORRADE_ASSERT(target, "AbstractQuery::end(): the query is not running", );
- /** @todo Re-enable when extension wrangler is available for ES */
+ /** @todo Re-enable when extension loader is available for ES */
#ifndef MAGNUM_TARGET_GLES2
glEndQuery(target);
+ #elif defined(CORRADE_TARGET_NACL)
+ glEndQueryEXT(target);
#else
CORRADE_INTERNAL_ASSERT(false);
- //glEndQueryEXT(target);
#endif
target = {};
}
diff --git a/src/Query.h b/src/Query.h
index 9e4f8fad0..8becdf1ec 100644
--- a/src/Query.h
+++ b/src/Query.h
@@ -30,10 +30,8 @@
#include
-#include "OpenGL.h"
-#include "Types.h"
+#include "AbstractObject.h"
#include "magnumConfigure.h"
-#include "magnumVisibility.h"
namespace Magnum {
@@ -45,11 +43,49 @@ information.
@todo Support for AMD's query buffer (@extension{AMD,query_buffer_object})
@requires_gles30 %Extension @es_extension{EXT,occlusion_query_boolean}
*/
-class MAGNUM_EXPORT AbstractQuery {
+class MAGNUM_EXPORT AbstractQuery: public AbstractObject {
public:
+ /** @brief Copying is not allowed */
+ AbstractQuery(const AbstractQuery&) = delete;
+
+ /** @brief Move constructor */
+ AbstractQuery(AbstractQuery&& other) noexcept;
+
+ /** @brief Copying is not allowed */
+ AbstractQuery& operator=(const AbstractQuery&) = delete;
+
+ /** @brief Move assignment */
+ AbstractQuery& operator=(AbstractQuery&& other) noexcept;
+
/** @brief OpenGL query ID */
GLuint id() const { return _id; }
+ /**
+ * @brief %Query label
+ *
+ * The result is *not* cached, repeated queries will result in repeated
+ * OpenGL calls. If neither @extension{KHR,debug} nor
+ * @extension2{EXT,debug_label} desktop or ES extension is available,
+ * this function returns empty string.
+ * @see @fn_gl{GetObjectLabel} with @def_gl{QUERY} or
+ * @fn_gl_extension2{GetObjectLabel,EXT,debug_label} with
+ * @def_gl{QUERY_OBJECT_EXT}
+ */
+ std::string label() const;
+
+ /**
+ * @brief Set query label
+ * @return Reference to self (for method chaining)
+ *
+ * Default is empty string. If neither @extension{KHR,debug} nor
+ * @extension2{EXT,debug_label} desktop or ES extension is available,
+ * this function does nothing.
+ * @see @ref maxLabelLength(), @fn_gl{ObjectLabel} with
+ * @def_gl{QUERY} or @fn_gl_extension2{LabelObject,EXT,debug_label}
+ * with @def_gl{QUERY_OBJECT_EXT}
+ */
+ AbstractQuery& setLabel(const std::string& label);
+
/**
* @brief Whether the result is available
*
@@ -157,6 +193,8 @@ class PrimitiveQuery: public AbstractQuery {
TransformFeedbackPrimitivesWritten = GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN
};
+ explicit PrimitiveQuery() {}
+
/**
* @brief Begin query
*
@@ -166,6 +204,14 @@ class PrimitiveQuery: public AbstractQuery {
void begin(Target target) {
AbstractQuery::begin(GLenum(target));
}
+
+ /* Overloads to remove WTF-factor from method chaining order */
+ #ifndef DOXYGEN_GENERATING_OUTPUT
+ PrimitiveQuery& setLabel(const std::string& label) {
+ AbstractQuery::setLabel(label);
+ return *this;
+ }
+ #endif
};
#endif
@@ -275,6 +321,8 @@ class SampleQuery: public AbstractQuery {
};
#endif
+ explicit SampleQuery() {}
+
/** @copydoc PrimitiveQuery::begin() */
void begin(Target target) {
AbstractQuery::begin(GLenum(target));
@@ -303,6 +351,14 @@ class SampleQuery: public AbstractQuery {
glEndConditionalRender();
}
#endif
+
+ /* Overloads to remove WTF-factor from method chaining order */
+ #ifndef DOXYGEN_GENERATING_OUTPUT
+ SampleQuery& setLabel(const std::string& label) {
+ AbstractQuery::setLabel(label);
+ return *this;
+ }
+ #endif
};
/**
@@ -351,6 +407,8 @@ class TimeQuery: public AbstractQuery {
#endif
};
+ explicit TimeQuery() {}
+
/**
* @brief Query timestamp
*
@@ -370,8 +428,27 @@ class TimeQuery: public AbstractQuery {
void begin(Target target) {
AbstractQuery::begin(GLenum(target));
}
+
+ /* Overloads to remove WTF-factor from method chaining order */
+ #ifndef DOXYGEN_GENERATING_OUTPUT
+ TimeQuery& setLabel(const std::string& label) {
+ AbstractQuery::setLabel(label);
+ return *this;
+ }
+ #endif
};
+
+inline AbstractQuery::AbstractQuery(AbstractQuery&& other) noexcept: _id(other._id), target(other.target) {
+ other._id = 0;
+}
+
+inline AbstractQuery& AbstractQuery::operator=(AbstractQuery&& other) noexcept {
+ std::swap(_id, other._id);
+ std::swap(target, other.target);
+ return *this;
+}
+
}
#endif
diff --git a/src/Renderbuffer.cpp b/src/Renderbuffer.cpp
index b97d860e0..2ec609d99 100644
--- a/src/Renderbuffer.cpp
+++ b/src/Renderbuffer.cpp
@@ -27,8 +27,9 @@
#include "Context.h"
#include "Extensions.h"
-#include "Implementation/State.h"
+#include "Implementation/DebugState.h"
#include "Implementation/FramebufferState.h"
+#include "Implementation/State.h"
namespace Magnum {
@@ -70,7 +71,12 @@ Int Renderbuffer::maxSamples() {
return value;
}
+Renderbuffer::Renderbuffer() { glGenRenderbuffers(1, &_id); }
+
Renderbuffer::~Renderbuffer() {
+ /* Moved out, nothing to do */
+ if(!_id) return;
+
/* If bound, remove itself from state */
GLuint& binding = Context::current()->state().framebuffer->renderbufferBinding;
if(binding == _id) binding = 0;
@@ -78,6 +84,15 @@ Renderbuffer::~Renderbuffer() {
glDeleteRenderbuffers(1, &_id);
}
+std::string Renderbuffer::label() const {
+ return Context::current()->state().debug->getLabelImplementation(GL_RENDERBUFFER, _id);
+}
+
+Renderbuffer& Renderbuffer::setLabel(const std::string& label) {
+ Context::current()->state().debug->labelImplementation(GL_RENDERBUFFER, _id, label);
+ return *this;
+}
+
void Renderbuffer::bind() {
GLuint& binding = Context::current()->state().framebuffer->renderbufferBinding;
@@ -121,7 +136,7 @@ void Renderbuffer::storageImplementationDSA(RenderbufferFormat internalFormat, c
}
#endif
-/** @todo Enable when extension wrangler for ES is done */
+/** @todo Re-enable when extension loader is available for ES */
#ifndef MAGNUM_TARGET_GLES2
void Renderbuffer::storageMultisampleImplementationDefault(const GLsizei samples, const RenderbufferFormat internalFormat, const Vector2i& size) {
diff --git a/src/Renderbuffer.h b/src/Renderbuffer.h
index 095f22d69..3807f8ffe 100644
--- a/src/Renderbuffer.h
+++ b/src/Renderbuffer.h
@@ -28,8 +28,8 @@
* @brief Class Magnum::Renderbuffer
*/
+#include "AbstractObject.h"
#include "Magnum.h"
-#include "OpenGL.h"
#include "magnumVisibility.h"
#ifdef CORRADE_GCC45_COMPATIBILITY
@@ -57,14 +57,9 @@ See its documentation for more information.
@requires_gl30 %Extension @extension{ARB,framebuffer_object}
*/
-class MAGNUM_EXPORT Renderbuffer {
+class MAGNUM_EXPORT Renderbuffer: public AbstractObject {
friend class Context;
- Renderbuffer(const Renderbuffer&) = delete;
- Renderbuffer(Renderbuffer&&) = delete;
- Renderbuffer& operator=(const Renderbuffer&) = delete;
- Renderbuffer& operator=(Renderbuffer&&) = delete;
-
public:
/**
* @brief Max supported renderbuffer size
@@ -93,7 +88,13 @@ class MAGNUM_EXPORT Renderbuffer {
* Generates new OpenGL renderbuffer.
* @see @fn_gl{GenRenderbuffers}
*/
- explicit Renderbuffer() { glGenRenderbuffers(1, &_id); }
+ explicit Renderbuffer();
+
+ /** @brief Copying is not allowed */
+ Renderbuffer(const Renderbuffer&) = delete;
+
+ /** @brief Move constructor */
+ Renderbuffer(Renderbuffer&& other) noexcept;
/**
* @brief Destructor
@@ -103,9 +104,41 @@ class MAGNUM_EXPORT Renderbuffer {
*/
~Renderbuffer();
+ /** @brief Copying is not allowed */
+ Renderbuffer& operator=(const Renderbuffer&) = delete;
+
+ /** @brief Move assignment */
+ Renderbuffer& operator=(Renderbuffer&& other) noexcept;
+
/** @brief OpenGL internal renderbuffer ID */
GLuint id() const { return _id; }
+ /**
+ * @brief %Renderbuffer label
+ *
+ * The result is *not* cached, repeated queries will result in repeated
+ * OpenGL calls. If neither @extension{KHR,debug} nor
+ * @extension2{EXT,debug_label} desktop or ES extension is available,
+ * this function returns empty string.
+ * @see @fn_gl{GetObjectLabel} or
+ * @fn_gl_extension2{GetObjectLabel,EXT,debug_label} with
+ * @def_gl{RENDERBUFFER}
+ */
+ std::string label() const;
+
+ /**
+ * @brief Set renderbuffer label
+ * @return Reference to self (for method chaining)
+ *
+ * Default is empty string. If neither @extension{KHR,debug} nor
+ * @extension2{EXT,debug_label} desktop or ES extension is available,
+ * this function does nothing.
+ * @see @ref maxLabelLength(), @fn_gl{ObjectLabel} or
+ * @fn_gl_extension2{LabelObject,EXT,debug_label} with
+ * @def_gl{RENDERBUFFER}
+ */
+ Renderbuffer& setLabel(const std::string& label);
+
/**
* @brief Set renderbuffer storage
* @param internalFormat Internal format
@@ -131,10 +164,11 @@ class MAGNUM_EXPORT Renderbuffer {
* framebufferbuffer is not currently bound, it is bound before the
* operation.
* @see @ref maxSize(), @ref maxSamples(), @fn_gl{BindRenderbuffer},
- * @fn_gl{RenderbufferStorage} or @fn_gl_extension{NamedRenderbufferStorage,EXT,direct_state_access}
+ * @fn_gl{RenderbufferStorageMultisample} or @fn_gl_extension{NamedRenderbufferStorageMultisample,EXT,direct_state_access}
* @requires_gles30 %Extension @es_extension{ANGLE,framebuffer_multisample}
* or @es_extension{NV,framebuffer_multisample}
* @todo How about @es_extension{APPLE,framebuffer_multisample}?
+ * @todo NaCl has @fn_gl_extension{RenderbufferStorageMultisample,EXT,multisampled_render_to_texture}
*/
void setStorageMultisample(Int samples, RenderbufferFormat internalFormat, const Vector2i& size) {
(this->*storageMultisampleImplementation)(samples, internalFormat, size);
@@ -167,6 +201,15 @@ class MAGNUM_EXPORT Renderbuffer {
GLuint _id;
};
+inline Renderbuffer::Renderbuffer(Renderbuffer&& other) noexcept: _id(other._id) {
+ other._id = 0;
+}
+
+inline Renderbuffer& Renderbuffer::operator=(Renderbuffer&& other) noexcept {
+ std::swap(_id, other._id);
+ return *this;
+}
+
}
#endif
diff --git a/src/Renderer.cpp b/src/Renderer.cpp
index 6ce26485d..55675d6dc 100644
--- a/src/Renderer.cpp
+++ b/src/Renderer.cpp
@@ -217,12 +217,12 @@ Renderer::GraphicsResetStatus Renderer::graphicsResetStatusImplementationDefault
}
Renderer::GraphicsResetStatus Renderer::graphicsResetStatusImplementationRobustness() {
- /** @todo Enable when extension wrangler for ES is available */
+ /** @todo Re-enable when extension loader is available for ES */
#ifndef MAGNUM_TARGET_GLES
return GraphicsResetStatus(glGetGraphicsResetStatusARB());
#else
- //return GraphicsResetStatus(glGetGraphicsResetStatusEXT());
CORRADE_INTERNAL_ASSERT(false);
+ //return GraphicsResetStatus(glGetGraphicsResetStatusEXT());
#endif
}
diff --git a/src/Renderer.h b/src/Renderer.h
index bdad9382d..f9254b114 100644
--- a/src/Renderer.h
+++ b/src/Renderer.h
@@ -79,6 +79,31 @@ class MAGNUM_EXPORT Renderer {
*/
Blending = GL_BLEND,
+ /**
+ * Debug output
+ * @requires_gl43 %Extension @extension{KHR,debug}
+ * @requires_es_extension %Extension @es_extension{KHR,debug}
+ * @see @ref DebugMessage, @ref Feature::DebugOutputSynchronous
+ */
+ #ifndef MAGNUM_TARGET_GLES
+ DebugOutput = GL_DEBUG_OUTPUT,
+ #else
+ DebugOutput = GL_DEBUG_OUTPUT_KHR,
+ #endif
+
+ /**
+ * Synchronous debug output. Has effect only if @ref Feature::DebugOutput
+ * is enabled.
+ * @requires_gl43 %Extension @extension{KHR,debug}
+ * @requires_es_extension %Extension @es_extension{KHR,debug}
+ * @see @ref DebugMessage
+ */
+ #ifndef MAGNUM_TARGET_GLES
+ DebugOutputSynchronous = GL_DEBUG_OUTPUT_SYNCHRONOUS,
+ #else
+ DebugOutputSynchronous = GL_DEBUG_OUTPUT_SYNCHRONOUS_KHR,
+ #endif
+
#ifndef MAGNUM_TARGET_GLES
/**
* Depth clamping. If enabled, ignores near and far clipping plane.
diff --git a/src/Sampler.cpp b/src/Sampler.cpp
index 15bfd75d0..9e6a9311e 100644
--- a/src/Sampler.cpp
+++ b/src/Sampler.cpp
@@ -29,6 +29,7 @@
#include "Context.h"
#include "Implementation/State.h"
#include "Implementation/TextureState.h"
+#include "Extensions.h"
namespace Magnum {
@@ -45,15 +46,15 @@ static_assert((filter_or(Nearest, Base) == GL_NEAREST) &&
"Unsupported constants for GL texture filtering");
#undef filter_or
-Float Sampler::maxAnisotropy() {
- GLfloat& value = Context::current()->state().texture->maxAnisotropy;
+Float Sampler::maxMaxAnisotropy() {
+ if(!Context::current()->isExtensionSupported())
+ return 0.0f;
+
+ GLfloat& value = Context::current()->state().texture->maxMaxAnisotropy;
- /** @todo Re-enable when extension header is available */
- #ifndef MAGNUM_TARGET_GLES
/* Get the value, if not already cached */
if(value == 0.0f)
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &value);
- #endif
return value;
}
diff --git a/src/Sampler.h b/src/Sampler.h
index 85360d4af..974d60c2e 100644
--- a/src/Sampler.h
+++ b/src/Sampler.h
@@ -133,23 +133,29 @@ class MAGNUM_EXPORT Sampler {
};
/**
- * @brief Max supported anisotropy
+ * @brief Max supported max anisotropy
*
* The result is cached, repeated queries don't result in repeated
- * OpenGL calls.
+ * OpenGL calls. If extension @extension{EXT,texture_filter_anisotropic}
+ * (desktop or ES) is not available, returns `0.0f`.
* @see setMaxAnisotropy(), @fn_gl{Get} with @def_gl{MAX_TEXTURE_MAX_ANISOTROPY_EXT}
- * @requires_extension %Extension @extension{EXT,texture_filter_anisotropic}
- * @requires_es_extension %Extension @es_extension2{EXT,texture_filter_anisotropic,texture_filter_anisotropic}
*/
- static Float maxAnisotropy();
+ static Float maxMaxAnisotropy();
#ifdef MAGNUM_BUILD_DEPRECATED
/**
- * @copybrief maxAnisotropy()
- * @deprecated Use @ref Magnum::Sampler::maxAnisotropy() "maxAnisotropy()"
+ * @copybrief maxMaxAnisotropy()
+ * @deprecated Use @ref Magnum::Sampler::maxMaxAnisotropy() "maxMaxAnisotropy()"
* instead.
*/
- static CORRADE_DEPRECATED("use maxAnisotropy() instead") Float maxSupportedAnisotropy() { return maxAnisotropy(); }
+ static CORRADE_DEPRECATED("use maxMaxAnisotropy() instead") Float maxAnisotropy() { return maxMaxAnisotropy(); }
+
+ /**
+ * @copybrief maxMaxAnisotropy()
+ * @deprecated Use @ref Magnum::Sampler::maxMaxAnisotropy() "maxMaxAnisotropy()"
+ * instead.
+ */
+ static CORRADE_DEPRECATED("use maxMaxAnisotropy() instead") Float maxSupportedAnisotropy() { return maxMaxAnisotropy(); }
#endif
};
diff --git a/src/SceneGraph/AbstractCamera.h b/src/SceneGraph/AbstractCamera.h
index 986769565..d9d118081 100644
--- a/src/SceneGraph/AbstractCamera.h
+++ b/src/SceneGraph/AbstractCamera.h
@@ -215,7 +215,7 @@ typedef AbstractBasicCamera3D AbstractCamera3D;
typedef AbstractCamera<3, Float> AbstractCamera3D;
#endif
-#ifdef _WIN32
+#ifdef CORRADE_TARGET_WINDOWS
extern template class MAGNUM_SCENEGRAPH_EXPORT AbstractCamera<2, Float>;
extern template class MAGNUM_SCENEGRAPH_EXPORT AbstractCamera<3, Float>;
#endif
diff --git a/src/SceneGraph/AbstractFeature.h b/src/SceneGraph/AbstractFeature.h
index 1488c056f..2502ca322 100644
--- a/src/SceneGraph/AbstractFeature.h
+++ b/src/SceneGraph/AbstractFeature.h
@@ -349,7 +349,7 @@ typedef AbstractBasicFeature3D AbstractFeature3D;
typedef AbstractFeature<3, Float> AbstractFeature3D;
#endif
-#ifdef _WIN32
+#ifdef CORRADE_TARGET_WINDOWS
extern template class MAGNUM_SCENEGRAPH_EXPORT AbstractFeature<2, Float>;
extern template class MAGNUM_SCENEGRAPH_EXPORT AbstractFeature<3, Float>;
#endif
diff --git a/src/SceneGraph/AbstractObject.h b/src/SceneGraph/AbstractObject.h
index d804f678e..e15679519 100644
--- a/src/SceneGraph/AbstractObject.h
+++ b/src/SceneGraph/AbstractObject.h
@@ -285,7 +285,7 @@ typedef AbstractBasicObject3D AbstractObject3D;
typedef AbstractObject<3, Float> AbstractObject3D;
#endif
-#ifdef _WIN32
+#ifdef CORRADE_TARGET_WINDOWS
extern template class MAGNUM_SCENEGRAPH_EXPORT AbstractObject<2, Float>;
extern template class MAGNUM_SCENEGRAPH_EXPORT AbstractObject<3, Float>;
#endif
diff --git a/src/SceneGraph/AbstractTransformation.h b/src/SceneGraph/AbstractTransformation.h
index 49a02d052..64e76a967 100644
--- a/src/SceneGraph/AbstractTransformation.h
+++ b/src/SceneGraph/AbstractTransformation.h
@@ -150,7 +150,7 @@ typedef AbstractBasicTransformation3D AbstractTransformation3D;
typedef AbstractTransformation<3, Float> AbstractTransformation3D;
#endif
-#ifdef _WIN32
+#ifdef CORRADE_TARGET_WINDOWS
extern template class MAGNUM_SCENEGRAPH_EXPORT AbstractTransformation<2, Float>;
extern template class MAGNUM_SCENEGRAPH_EXPORT AbstractTransformation<3, Float>;
#endif
diff --git a/src/SceneGraph/Animable.h b/src/SceneGraph/Animable.h
index 9516e05bf..77f2bafd6 100644
--- a/src/SceneGraph/Animable.h
+++ b/src/SceneGraph/Animable.h
@@ -388,7 +388,7 @@ typedef BasicAnimable3D Animable3D;
typedef Animable<3, Float> Animable3D;
#endif
-#ifdef _WIN32
+#ifdef CORRADE_TARGET_WINDOWS
extern template class MAGNUM_SCENEGRAPH_EXPORT Animable<2, Float>;
extern template class MAGNUM_SCENEGRAPH_EXPORT Animable<3, Float>;
#endif
diff --git a/src/SceneGraph/AnimableGroup.h b/src/SceneGraph/AnimableGroup.h
index 4b7ae52eb..531d5c820 100644
--- a/src/SceneGraph/AnimableGroup.h
+++ b/src/SceneGraph/AnimableGroup.h
@@ -126,7 +126,7 @@ typedef BasicAnimableGroup3D AnimableGroup3D;
typedef AnimableGroup<3, Float> AnimableGroup3D;
#endif
-#ifdef _WIN32
+#ifdef CORRADE_TARGET_WINDOWS
extern template class MAGNUM_SCENEGRAPH_EXPORT AnimableGroup<2, Float>;
extern template class MAGNUM_SCENEGRAPH_EXPORT AnimableGroup<3, Float>;
#endif
diff --git a/src/SceneGraph/Camera2D.h b/src/SceneGraph/Camera2D.h
index 09183c9ef..610af6419 100644
--- a/src/SceneGraph/Camera2D.h
+++ b/src/SceneGraph/Camera2D.h
@@ -105,7 +105,7 @@ template class BasicCamera2D: public AbstractCamera<2, T> {
*/
typedef BasicCamera2D Camera2D;
-#ifdef _WIN32
+#ifdef CORRADE_TARGET_WINDOWS
extern template class MAGNUM_SCENEGRAPH_EXPORT BasicCamera2D;
#endif
diff --git a/src/SceneGraph/Camera3D.h b/src/SceneGraph/Camera3D.h
index 8b126458b..d6744d953 100644
--- a/src/SceneGraph/Camera3D.h
+++ b/src/SceneGraph/Camera3D.h
@@ -30,7 +30,7 @@
#include "AbstractCamera.h"
-#ifdef _WIN32 /* I so HATE windef.h */
+#ifdef CORRADE_TARGET_WINDOWS /* I so HATE windef.h */
#undef near
#undef far
#endif
@@ -141,7 +141,7 @@ template class BasicCamera3D: public AbstractCamera<3, T> {
*/
typedef BasicCamera3D Camera3D;
-#ifdef _WIN32
+#ifdef CORRADE_TARGET_WINDOWS
extern template class MAGNUM_SCENEGRAPH_EXPORT BasicCamera3D;
#endif
diff --git a/src/SceneGraph/DualComplexTransformation.h b/src/SceneGraph/DualComplexTransformation.h
index 8d89c531a..a9a960a38 100644
--- a/src/SceneGraph/DualComplexTransformation.h
+++ b/src/SceneGraph/DualComplexTransformation.h
@@ -185,7 +185,7 @@ template struct Transformation> {
}
-#ifdef _WIN32
+#ifdef CORRADE_TARGET_WINDOWS
extern template class MAGNUM_SCENEGRAPH_EXPORT Object>;
#endif
diff --git a/src/SceneGraph/DualQuaternionTransformation.h b/src/SceneGraph/DualQuaternionTransformation.h
index 8109c40eb..d6826f4ba 100644
--- a/src/SceneGraph/DualQuaternionTransformation.h
+++ b/src/SceneGraph/DualQuaternionTransformation.h
@@ -202,7 +202,7 @@ template struct Transformation> {
}
-#ifdef _WIN32
+#ifdef CORRADE_TARGET_WINDOWS
extern template class MAGNUM_SCENEGRAPH_EXPORT Object>;
#endif
diff --git a/src/SceneGraph/FeatureGroup.h b/src/SceneGraph/FeatureGroup.h
index d3d6f2f07..2d725118f 100644
--- a/src/SceneGraph/FeatureGroup.h
+++ b/src/SceneGraph/FeatureGroup.h
@@ -193,7 +193,7 @@ template FeatureGroup;
extern template class MAGNUM_SCENEGRAPH_EXPORT AbstractFeatureGroup<3, Float>;
#endif
diff --git a/src/SceneGraph/MatrixTransformation2D.h b/src/SceneGraph/MatrixTransformation2D.h
index 78a1964b3..9be34f7ce 100644
--- a/src/SceneGraph/MatrixTransformation2D.h
+++ b/src/SceneGraph/MatrixTransformation2D.h
@@ -170,7 +170,7 @@ template struct Transformation> {
}
-#ifdef _WIN32
+#ifdef CORRADE_TARGET_WINDOWS
extern template class MAGNUM_SCENEGRAPH_EXPORT Object>;
#endif
diff --git a/src/SceneGraph/MatrixTransformation3D.h b/src/SceneGraph/MatrixTransformation3D.h
index 032a38122..b3acdb6b5 100644
--- a/src/SceneGraph/MatrixTransformation3D.h
+++ b/src/SceneGraph/MatrixTransformation3D.h
@@ -218,7 +218,7 @@ template struct Transformation> {
}
-#ifdef _WIN32
+#ifdef CORRADE_TARGET_WINDOWS
extern template class MAGNUM_SCENEGRAPH_EXPORT Object>;
#endif
diff --git a/src/SceneGraph/RigidMatrixTransformation2D.h b/src/SceneGraph/RigidMatrixTransformation2D.h
index caf05a7fe..16df48896 100644
--- a/src/SceneGraph/RigidMatrixTransformation2D.h
+++ b/src/SceneGraph/RigidMatrixTransformation2D.h
@@ -204,7 +204,7 @@ template struct Transformation> {
}
-#ifdef _WIN32
+#ifdef CORRADE_TARGET_WINDOWS
extern template class MAGNUM_SCENEGRAPH_EXPORT Object>;
#endif
diff --git a/src/SceneGraph/RigidMatrixTransformation3D.h b/src/SceneGraph/RigidMatrixTransformation3D.h
index 11b2ff1c2..37f3f275a 100644
--- a/src/SceneGraph/RigidMatrixTransformation3D.h
+++ b/src/SceneGraph/RigidMatrixTransformation3D.h
@@ -257,7 +257,7 @@ template struct Transformation> {
}
-#ifdef _WIN32
+#ifdef CORRADE_TARGET_WINDOWS
extern template class MAGNUM_SCENEGRAPH_EXPORT Object>;
#endif
diff --git a/src/SceneGraph/TranslationTransformation.h b/src/SceneGraph/TranslationTransformation.h
index bbb20e1c9..6c2423542 100644
--- a/src/SceneGraph/TranslationTransformation.h
+++ b/src/SceneGraph/TranslationTransformation.h
@@ -212,7 +212,7 @@ template struct Transfor
}
-#ifdef _WIN32
+#ifdef CORRADE_TARGET_WINDOWS
extern template class MAGNUM_SCENEGRAPH_EXPORT Object>;
extern template class MAGNUM_SCENEGRAPH_EXPORT Object>;
#endif
diff --git a/src/SceneGraph/instantiation.cpp b/src/SceneGraph/instantiation.cpp
index b04fd0964..079199ddc 100644
--- a/src/SceneGraph/instantiation.cpp
+++ b/src/SceneGraph/instantiation.cpp
@@ -39,7 +39,7 @@
namespace Magnum { namespace SceneGraph {
/* On Windows the instantiations are already marked with extern template */
-#ifndef _WIN32
+#ifndef CORRADE_TARGET_WINDOWS
#define MAGNUM_SCENEGRAPH_EXPORT_HPP MAGNUM_SCENEGRAPH_EXPORT
#else
#define MAGNUM_SCENEGRAPH_EXPORT_HPP
diff --git a/src/Shader.cpp b/src/Shader.cpp
index 8335083e9..82bfe5e54 100644
--- a/src/Shader.cpp
+++ b/src/Shader.cpp
@@ -31,6 +31,7 @@
#include
#include "Extensions.h"
+#include "Implementation/DebugState.h"
#include "Implementation/State.h"
#include "Implementation/ShaderState.h"
@@ -439,8 +440,8 @@ Int Shader::maxUniformBlocks(const Type type) {
GL_MAX_VERTEX_UNIFORM_BLOCKS,
GL_MAX_FRAGMENT_UNIFORM_BLOCKS,
#ifndef MAGNUM_TARGET_GLES
- /** @todo Fix this when glLoadGen has GL_MAX_GEOMETRY_UNIFORM_BLOCKS enum */
- 0x8A2C /*GL_MAX_GEOMETRY_UNIFORM_BLOCKS*/,
+ /** @todo Fix this when glLoadGen has `GL_MAX_GEOMETRY_UNIFORM_BLOCKS` enum */
+ 0x8A2C, //GL_MAX_GEOMETRY_UNIFORM_BLOCKS,
GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS,
GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS,
GL_MAX_COMPUTE_UNIFORM_BLOCKS
@@ -522,8 +523,8 @@ Int Shader::maxCombinedUniformComponents(const Type type) {
GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS,
GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS,
#ifndef MAGNUM_TARGET_GLES
- /** @todo Fix this when glLoadGen has GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS enum */
- 0x8A32 /*GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS*/,
+ /** @todo Fix this when glLoadGen has `GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS` enum */
+ 0x8A32, //GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS,
GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS,
GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS,
GL_MAX_COMBINED_COMPUTE_UNIFORM_COMPONENTS
@@ -541,19 +542,19 @@ Shader::Shader(const Version version, const Type type): _type(type), _id(0) {
switch(version) {
#ifndef MAGNUM_TARGET_GLES
- case Version::GL210: sources.push_back("#version 120\n"); return;
- case Version::GL300: sources.push_back("#version 130\n"); return;
- case Version::GL310: sources.push_back("#version 140\n"); return;
- case Version::GL320: sources.push_back("#version 150\n"); return;
- case Version::GL330: sources.push_back("#version 330\n"); return;
- case Version::GL400: sources.push_back("#version 400\n"); return;
- case Version::GL410: sources.push_back("#version 410\n"); return;
- case Version::GL420: sources.push_back("#version 420\n"); return;
- case Version::GL430: sources.push_back("#version 430\n"); return;
- case Version::GL440: sources.push_back("#version 440\n"); return;
+ case Version::GL210: _sources.push_back("#version 120\n"); return;
+ case Version::GL300: _sources.push_back("#version 130\n"); return;
+ case Version::GL310: _sources.push_back("#version 140\n"); return;
+ case Version::GL320: _sources.push_back("#version 150\n"); return;
+ case Version::GL330: _sources.push_back("#version 330\n"); return;
+ case Version::GL400: _sources.push_back("#version 400\n"); return;
+ case Version::GL410: _sources.push_back("#version 410\n"); return;
+ case Version::GL420: _sources.push_back("#version 420\n"); return;
+ case Version::GL430: _sources.push_back("#version 430\n"); return;
+ case Version::GL440: _sources.push_back("#version 440\n"); return;
#else
- case Version::GLES200: sources.push_back("#version 100\n"); return;
- case Version::GLES300: sources.push_back("#version 300\n"); return;
+ case Version::GLES200: _sources.push_back("#version 100\n"); return;
+ case Version::GLES300: _sources.push_back("#version 300\n"); return;
#endif
case Version::None:
@@ -563,48 +564,54 @@ Shader::Shader(const Version version, const Type type): _type(type), _id(0) {
CORRADE_ASSERT_UNREACHABLE();
}
-Shader::Shader(Shader&& other): _type(other._type), _id(other._id), sources(std::move(other.sources)) {
- other._id = 0;
-}
-
Shader::~Shader() {
- if(_id) glDeleteShader(_id);
-}
+ /* Moved out, nothing to do */
+ if(!_id) return;
-Shader& Shader::operator=(Shader&& other) {
glDeleteShader(_id);
+}
- _type = other._type;
- sources = std::move(other.sources);
- _id = other._id;
-
- other._id = 0;
+std::string Shader::label() const {
+ #ifndef MAGNUM_TARGET_GLES
+ return Context::current()->state().debug->getLabelImplementation(GL_SHADER, _id);
+ #else
+ return Context::current()->state().debug->getLabelImplementation(GL_SHADER_KHR, _id);
+ #endif
+}
+Shader& Shader::setLabel(const std::string& label) {
+ #ifndef MAGNUM_TARGET_GLES
+ Context::current()->state().debug->labelImplementation(GL_SHADER, _id, label);
+ #else
+ Context::current()->state().debug->labelImplementation(GL_SHADER_KHR, _id, label);
+ #endif
return *this;
}
+std::vector Shader::sources() const { return _sources; }
+
Shader& Shader::addSource(std::string source) {
if(!source.empty()) {
#if defined(CORRADE_TARGET_NACL_NEWLIB) || defined(__MINGW32__)
std::ostringstream converter;
- converter << (sources.size()+1)/2;
+ converter << (_sources.size()+1)/2;
#endif
/* Fix line numbers, so line 41 of third added file is marked as 3(41).
Source 0 is the #version string added in constructor. */
- sources.push_back("#line 1 " +
+ _sources.push_back("#line 1 " +
/* This shouldn't be ambiguous. But is. */
#if !defined(CORRADE_TARGET_NACL_NEWLIB) && !defined(__MINGW32__)
#ifndef CORRADE_GCC44_COMPATIBILITY
- std::to_string((sources.size()+1)/2) +
+ std::to_string((_sources.size()+1)/2) +
#else
- std::to_string(static_cast(sources.size()+1)/2) +
+ std::to_string(static_cast(_sources.size()+1)/2) +
#endif
#else
converter.str() +
#endif
'\n');
- sources.push_back(std::move(source));
+ _sources.push_back(std::move(source));
}
return *this;
@@ -619,20 +626,20 @@ Shader& Shader::addFile(const std::string& filename) {
}
bool Shader::compile() {
- CORRADE_ASSERT(sources.size() > 1, "Shader::compile(): no files added", false);
+ CORRADE_ASSERT(_sources.size() > 1, "Shader::compile(): no files added", false);
/* Array of source string pointers and their lengths */
/** @todo Use `Containers::ArrayTuple` to avoid one allocation if it ever
gets to be implemented (we need properly aligned memory too) */
- Containers::Array pointers(sources.size());
- Containers::Array sizes(sources.size());
- for(std::size_t i = 0; i != sources.size(); ++i) {
- pointers[i] = static_cast(sources[i].data());
- sizes[i] = sources[i].size();
+ Containers::Array pointers(_sources.size());
+ Containers::Array sizes(_sources.size());
+ for(std::size_t i = 0; i != _sources.size(); ++i) {
+ pointers[i] = static_cast(_sources[i].data());
+ sizes[i] = _sources[i].size();
}
/* Create shader and set its source */
- glShaderSource(_id, sources.size(), pointers, sizes);
+ glShaderSource(_id, _sources.size(), pointers, sizes);
/* Compile shader */
glCompileShader(_id);
@@ -671,4 +678,23 @@ bool Shader::compile() {
return success;
}
+#ifndef DOXYGEN_GENERATING_OUTPUT
+Debug operator<<(Debug debug, const Shader::Type value) {
+ switch(value) {
+ #define _c(value) case Shader::Type::value: return debug << "Shader::Type::" #value;
+ _c(Vertex)
+ #ifndef MAGNUM_TARGET_GLES
+ _c(TessellationControl)
+ _c(TessellationEvaluation)
+ _c(Geometry)
+ _c(Compute)
+ #endif
+ _c(Fragment)
+ #undef _c
+ }
+
+ return debug << "Shader::Type::(invalid)";
+}
+#endif
+
}
diff --git a/src/Shader.h b/src/Shader.h
index 5bfb732f3..6764fde00 100644
--- a/src/Shader.h
+++ b/src/Shader.h
@@ -31,7 +31,7 @@
#include
#include
-#include "Magnum.h"
+#include "AbstractObject.h"
#include "Context.h"
#include "magnumVisibility.h"
@@ -43,10 +43,7 @@ namespace Magnum {
See AbstractShaderProgram for more information.
*/
-class MAGNUM_EXPORT Shader {
- Shader(const Shader&) = delete;
- Shader& operator=(const Shader&) = delete;
-
+class MAGNUM_EXPORT Shader: public AbstractObject {
public:
/**
* @brief %Shader type
@@ -439,6 +436,12 @@ class MAGNUM_EXPORT Shader {
*/
explicit Shader(Version version, Type type);
+ /** @brief Copying is not allowed */
+ Shader(const Shader&) = delete;
+
+ /** @brief Move constructor */
+ Shader(Shader&& other) noexcept;
+
/**
* @brief Destructor
*
@@ -447,15 +450,47 @@ class MAGNUM_EXPORT Shader {
*/
~Shader();
- /** @brief Move constructor */
- Shader(Shader&& other);
+ /** @brief Copying is not allowed */
+ Shader& operator=(const Shader&) = delete;
- /** @brief Move assignment operator */
- Shader& operator=(Shader&& other);
+ /** @brief Move assignment */
+ Shader& operator=(Shader&& other) noexcept;
/** @brief OpenGL shader ID */
GLuint id() const { return _id; }
+ /**
+ * @brief %Shader label
+ *
+ * The result is *not* cached, repeated queries will result in repeated
+ * OpenGL calls. If neither @extension{KHR,debug} nor
+ * @extension2{EXT,debug_label} desktop or ES extension is available,
+ * this function returns empty string.
+ * @see @fn_gl{GetObjectLabel} with @def_gl{SHADER} or
+ * @fn_gl_extension2{GetObjectLabel,EXT,debug_label} with
+ * @def_gl{SHADER_OBJECT_EXT}
+ */
+ std::string label() const;
+
+ /**
+ * @brief Set shader label
+ * @return Reference to self (for method chaining)
+ *
+ * Default is empty string. If neither @extension{KHR,debug} nor
+ * @extension2{EXT,debug_label} desktop or ES extension is available,
+ * this function does nothing.
+ * @see @ref maxLabelLength(), @fn_gl{ObjectLabel} with
+ * @def_gl{SHADER} or @fn_gl_extension2{LabelObject,EXT,debug_label}
+ * with @def_gl{SHADER_OBJECT_EXT}
+ */
+ Shader& setLabel(const std::string& label);
+
+ /** @brief Shader type */
+ Type type() const { return _type; }
+
+ /** @brief Shader sources */
+ std::vector sources() const;
+
/**
* @brief Add shader source
* @param source String with shader source
@@ -493,9 +528,23 @@ class MAGNUM_EXPORT Shader {
Type _type;
GLuint _id;
- std::vector sources;
+ std::vector _sources;
};
+/** @debugoperator{Magnum::Shader} */
+Debug MAGNUM_EXPORT operator<<(Debug debug, Shader::Type value);
+
+inline Shader::Shader(Shader&& other) noexcept: _type(other._type), _id(other._id), _sources(std::move(other._sources)) {
+ other._id = 0;
+}
+
+inline Shader& Shader::operator=(Shader&& other) noexcept {
+ std::swap(_type, other._type);
+ std::swap(_id, other._id);
+ std::swap(_sources, other._sources);
+ return *this;
+}
+
}
#endif
diff --git a/src/DebugMarker.cpp b/src/Test/AbstractObjectGLTest.cpp
similarity index 52%
rename from src/DebugMarker.cpp
rename to src/Test/AbstractObjectGLTest.cpp
index 47049c742..fe27d3973 100644
--- a/src/DebugMarker.cpp
+++ b/src/Test/AbstractObjectGLTest.cpp
@@ -22,43 +22,34 @@
DEALINGS IN THE SOFTWARE.
*/
-#include "DebugMarker.h"
-
-#include
-
+#include "Buffer.h"
#include "Context.h"
#include "Extensions.h"
+#include "Test/AbstractOpenGLTester.h"
-namespace Magnum {
+namespace Magnum { namespace Test {
-DebugMarker::MarkImplementation DebugMarker::markImplementation = &DebugMarker::markImplementationDefault;
+class AbstractObjectGLTest: public AbstractOpenGLTester {
+ public:
+ explicit AbstractObjectGLTest();
-void DebugMarker::initializeContextBasedFunctionality(Context& context) {
- /** @todo Re-enable when extension wrangler is available for ES */
- #ifndef MAGNUM_TARGET_GLES
- if(context.isExtensionSupported()) {
- Debug() << "DebugMarker: using" << Extensions::GL::GREMEDY::string_marker::string() << "features";
+ void labelNoOp();
+};
- markImplementation = &DebugMarker::markImplementationDebugger;
- }
- #else
- static_cast(context);
- #endif
+AbstractObjectGLTest::AbstractObjectGLTest() {
+ addTests({&AbstractObjectGLTest::labelNoOp});
}
-void DebugMarker::markImplementationDefault(const std::string&) {}
+void AbstractObjectGLTest::labelNoOp() {
+ if(Context::current()->isExtensionSupported())
+ CORRADE_SKIP(Extensions::GL::KHR::debug::string() + std::string(" is supported."));
-void DebugMarker::markImplementationDebugger(const std::string& string) {
- /** @todo Re-enable when extension wrangler is available for ES */
- #ifndef MAGNUM_TARGET_GLES
- glStringMarkerGREMEDY(string.length(), string.c_str());
- #else
- #if 0
- glInsertEventMarkerEXT(string.length(), string.c_str());
- #else
- static_cast(string);
- #endif
- #endif
+ Buffer buffer;
+ buffer.setLabel("MyBuffer");
+ CORRADE_COMPARE(buffer.label(), "");
+ MAGNUM_VERIFY_NO_ERROR();
}
-}
+}}
+
+CORRADE_TEST_MAIN(Magnum::Test::AbstractObjectGLTest)
diff --git a/src/Test/AbstractOpenGLTester.h b/src/Test/AbstractOpenGLTester.h
index e551b4639..ef1c7c0be 100644
--- a/src/Test/AbstractOpenGLTester.h
+++ b/src/Test/AbstractOpenGLTester.h
@@ -27,6 +27,9 @@
#include
#include
+#include "Context.h"
+#include "Extensions.h"
+#include "DebugMessage.h"
#include "Renderer.h"
#if !defined(MAGNUM_TARGET_GLES) || defined(MAGNUM_TARGET_DESKTOP_GLES)
@@ -39,15 +42,23 @@ namespace Magnum { namespace Test {
class AbstractOpenGLTester: public TestSuite::Tester, public Platform::WindowlessApplication {
public:
- explicit AbstractOpenGLTester(): Platform::WindowlessApplication({zero, nullptr}) {}
+ explicit AbstractOpenGLTester();
using TestSuite::Tester::exec;
- int exec() override { return TestSuite::Tester::exec(); }
+ int exec() override final { return TestSuite::Tester::exec(); }
private:
static int zero;
};
+AbstractOpenGLTester::AbstractOpenGLTester(): Platform::WindowlessApplication({zero, nullptr}) {
+ if(Context::current()->isExtensionSupported()) {
+ Renderer::setFeature(Renderer::Feature::DebugOutput, true);
+ Renderer::setFeature(Renderer::Feature::DebugOutputSynchronous, true);
+ DebugMessage::setDefaultCallback();
+ }
+}
+
int AbstractOpenGLTester::zero = 0;
#define MAGNUM_VERIFY_NO_ERROR() CORRADE_COMPARE(Magnum::Renderer::error(), Magnum::Renderer::Error::NoError)
diff --git a/src/Test/AbstractQueryGLTest.cpp b/src/Test/AbstractQueryGLTest.cpp
new file mode 100644
index 000000000..39c00c777
--- /dev/null
+++ b/src/Test/AbstractQueryGLTest.cpp
@@ -0,0 +1,124 @@
+/*
+ This file is part of Magnum.
+
+ Copyright © 2010, 2011, 2012, 2013 VladimÃr VondruÅ¡
+
+ 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 "Context.h"
+#include "Extensions.h"
+#include "Query.h"
+#include "Test/AbstractOpenGLTester.h"
+
+namespace Magnum { namespace Test {
+
+class AbstractQueryGLTest: public AbstractOpenGLTester {
+ public:
+ explicit AbstractQueryGLTest();
+
+ void construct();
+ void constructCopy();
+ void constructMove();
+
+ void label();
+};
+
+AbstractQueryGLTest::AbstractQueryGLTest() {
+ addTests({&AbstractQueryGLTest::construct,
+ &AbstractQueryGLTest::constructCopy,
+ &AbstractQueryGLTest::constructMove,
+
+ &AbstractQueryGLTest::label});
+}
+
+void AbstractQueryGLTest::construct() {
+ #ifdef MAGNUM_TARGET_GLES2
+ if(!Context::current()->isExtensionSupported())
+ CORRADE_SKIP(Extensions::GL::EXT::occlusion_query_boolean::string() + std::string(" is not supported."));
+ #endif
+
+ {
+ const SampleQuery query;
+
+ MAGNUM_VERIFY_NO_ERROR();
+ CORRADE_VERIFY(query.id() > 0);
+ }
+
+ MAGNUM_VERIFY_NO_ERROR();
+}
+
+void AbstractQueryGLTest::constructCopy() {
+ CORRADE_VERIFY(!(std::is_constructible{}));
+ /* GCC 4.6 doesn't have std::is_assignable */
+ #ifndef CORRADE_GCC46_COMPATIBILITY
+ CORRADE_VERIFY(!(std::is_assignable{}));
+ #endif
+}
+
+void AbstractQueryGLTest::constructMove() {
+ #ifdef MAGNUM_TARGET_GLES2
+ if(!Context::current()->isExtensionSupported())
+ CORRADE_SKIP(Extensions::GL::EXT::occlusion_query_boolean::string() + std::string(" is not supported."));
+ #endif
+
+ SampleQuery a;
+ const Int id = a.id();
+
+ MAGNUM_VERIFY_NO_ERROR();
+ CORRADE_VERIFY(id > 0);
+
+ SampleQuery b(std::move(a));
+
+ CORRADE_COMPARE(a.id(), 0);
+ CORRADE_COMPARE(b.id(), id);
+
+ SampleQuery c;
+ const Int cId = c.id();
+ c = std::move(b);
+
+ MAGNUM_VERIFY_NO_ERROR();
+ CORRADE_VERIFY(cId > 0);
+ CORRADE_COMPARE(b.id(), cId);
+ CORRADE_COMPARE(c.id(), id);
+}
+
+void AbstractQueryGLTest::label() {
+ #ifdef MAGNUM_TARGET_GLES2
+ if(!Context::current()->isExtensionSupported())
+ CORRADE_SKIP(Extensions::GL::EXT::occlusion_query_boolean::string() + std::string(" is not supported."));
+ #endif
+
+ /* No-Op version is tested in AbstractObjectGLTest */
+ if(!Context::current()->isExtensionSupported() &&
+ !Context::current()->isExtensionSupported())
+ CORRADE_SKIP("Required extension is not available");
+
+ SampleQuery query;
+ CORRADE_COMPARE(query.label(), "");
+
+ query.setLabel("MyQuery");
+ CORRADE_COMPARE(query.label(), "MyQuery");
+
+ MAGNUM_VERIFY_NO_ERROR();
+}
+
+}}
+
+CORRADE_TEST_MAIN(Magnum::Test::AbstractQueryGLTest)
diff --git a/src/Test/AbstractShaderProgramGLTest.cpp b/src/Test/AbstractShaderProgramGLTest.cpp
new file mode 100644
index 000000000..2f0ac36fe
--- /dev/null
+++ b/src/Test/AbstractShaderProgramGLTest.cpp
@@ -0,0 +1,118 @@
+/*
+ This file is part of Magnum.
+
+ Copyright © 2010, 2011, 2012, 2013 VladimÃr VondruÅ¡
+
+ 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 "AbstractShaderProgram.h"
+#include "Context.h"
+#include "Extensions.h"
+#include "Test/AbstractOpenGLTester.h"
+
+namespace Magnum { namespace Test {
+
+class AbstractShaderProgramGLTest: public AbstractOpenGLTester {
+ public:
+ explicit AbstractShaderProgramGLTest();
+
+ void construct();
+ void constructCopy();
+ void constructMove();
+
+ void label();
+};
+
+AbstractShaderProgramGLTest::AbstractShaderProgramGLTest() {
+ addTests({&AbstractShaderProgramGLTest::construct,
+ &AbstractShaderProgramGLTest::constructCopy,
+ &AbstractShaderProgramGLTest::constructMove,
+
+ &AbstractShaderProgramGLTest::label});
+}
+
+namespace {
+
+class MyShader: public AbstractShaderProgram {
+ public:
+ explicit MyShader() {}
+};
+
+}
+
+void AbstractShaderProgramGLTest::construct() {
+ {
+ const MyShader shader;
+
+ MAGNUM_VERIFY_NO_ERROR();
+ CORRADE_VERIFY(shader.id() > 0);
+ }
+
+ MAGNUM_VERIFY_NO_ERROR();
+}
+
+void AbstractShaderProgramGLTest::constructCopy() {
+ CORRADE_VERIFY(!(std::is_constructible{}));
+ /* GCC 4.6 doesn't have std::is_assignable */
+ #ifndef CORRADE_GCC46_COMPATIBILITY
+ CORRADE_VERIFY(!(std::is_assignable{}));
+ #endif
+}
+
+void AbstractShaderProgramGLTest::constructMove() {
+ MyShader a;
+ const Int id = a.id();
+
+ MAGNUM_VERIFY_NO_ERROR();
+ CORRADE_VERIFY(id > 0);
+
+ MyShader b(std::move(a));
+
+ CORRADE_COMPARE(a.id(), 0);
+ CORRADE_COMPARE(b.id(), id);
+
+ MyShader c;
+ const Int cId = c.id();
+ c = std::move(b);
+
+ MAGNUM_VERIFY_NO_ERROR();
+ CORRADE_VERIFY(cId > 0);
+ CORRADE_COMPARE(b.id(), cId);
+ CORRADE_COMPARE(c.id(), id);
+}
+
+void AbstractShaderProgramGLTest::label() {
+ /* No-Op version is tested in AbstractObjectGLTest */
+ if(!Context::current()->isExtensionSupported() &&
+ !Context::current()->isExtensionSupported())
+ CORRADE_SKIP("Required extension is not available");
+
+ MyShader shader;
+ CORRADE_COMPARE(shader.label(), "");
+
+ shader.setLabel("MyShader");
+ CORRADE_COMPARE(shader.label(), "MyShader");
+
+ MAGNUM_VERIFY_NO_ERROR();
+}
+
+}}
+
+CORRADE_TEST_MAIN(Magnum::Test::AbstractShaderProgramGLTest)
diff --git a/src/Test/AbstractTextureGLTest.cpp b/src/Test/AbstractTextureGLTest.cpp
new file mode 100644
index 000000000..753d90337
--- /dev/null
+++ b/src/Test/AbstractTextureGLTest.cpp
@@ -0,0 +1,109 @@
+/*
+ This file is part of Magnum.
+
+ Copyright © 2010, 2011, 2012, 2013 VladimÃr VondruÅ¡
+
+ 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 "Context.h"
+#include "Extensions.h"
+#include "Texture.h"
+#include "Test/AbstractOpenGLTester.h"
+
+namespace Magnum { namespace Test {
+
+class AbstractTextureGLTest: public AbstractOpenGLTester {
+ public:
+ explicit AbstractTextureGLTest();
+
+ void construct();
+ void constructCopy();
+ void constructMove();
+
+ void label();
+};
+
+AbstractTextureGLTest::AbstractTextureGLTest() {
+ addTests({&AbstractTextureGLTest::construct,
+ &AbstractTextureGLTest::constructCopy,
+ &AbstractTextureGLTest::constructMove,
+
+ &AbstractTextureGLTest::label});
+}
+
+void AbstractTextureGLTest::construct() {
+ {
+ const Texture2D texture;
+
+ MAGNUM_VERIFY_NO_ERROR();
+ CORRADE_VERIFY(texture.id() > 0);
+ }
+
+ MAGNUM_VERIFY_NO_ERROR();
+}
+
+void AbstractTextureGLTest::constructCopy() {
+ CORRADE_VERIFY(!(std::is_constructible{}));
+ /* GCC 4.6 doesn't have std::is_assignable */
+ #ifndef CORRADE_GCC46_COMPATIBILITY
+ CORRADE_VERIFY(!(std::is_assignable{}));
+ #endif
+}
+
+void AbstractTextureGLTest::constructMove() {
+ Texture2D a;
+ const Int id = a.id();
+
+ MAGNUM_VERIFY_NO_ERROR();
+ CORRADE_VERIFY(id > 0);
+
+ Texture2D b(std::move(a));
+
+ CORRADE_COMPARE(a.id(), 0);
+ CORRADE_COMPARE(b.id(), id);
+
+ Texture2D c;
+ const Int cId = c.id();
+ c = std::move(b);
+
+ MAGNUM_VERIFY_NO_ERROR();
+ CORRADE_VERIFY(cId > 0);
+ CORRADE_COMPARE(b.id(), cId);
+ CORRADE_COMPARE(c.id(), id);
+}
+
+void AbstractTextureGLTest::label() {
+ /* No-Op version is tested in AbstractObjectGLTest */
+ if(!Context::current()->isExtensionSupported() &&
+ !Context::current()->isExtensionSupported())
+ CORRADE_SKIP("Required extension is not available");
+
+ Texture2D texture;
+ CORRADE_COMPARE(texture.label(), "");
+
+ texture.setLabel("MyTexture");
+ CORRADE_COMPARE(texture.label(), "MyTexture");
+
+ MAGNUM_VERIFY_NO_ERROR();
+}
+
+}}
+
+CORRADE_TEST_MAIN(Magnum::Test::AbstractTextureGLTest)
diff --git a/src/Test/BufferGLTest.cpp b/src/Test/BufferGLTest.cpp
index 48029b5a8..a5718eab2 100644
--- a/src/Test/BufferGLTest.cpp
+++ b/src/Test/BufferGLTest.cpp
@@ -38,6 +38,10 @@ class BufferGLTest: public AbstractOpenGLTester {
explicit BufferGLTest();
void construct();
+ void constructCopy();
+ void constructMove();
+
+ void label();
void data();
void map();
#ifdef MAGNUM_TARGET_GLES2
@@ -55,6 +59,7 @@ class BufferGLTest: public AbstractOpenGLTester {
BufferGLTest::BufferGLTest() {
addTests({&BufferGLTest::construct,
+ &BufferGLTest::label,
&BufferGLTest::data,
&BufferGLTest::map,
#ifdef MAGNUM_TARGET_GLES2
@@ -72,12 +77,60 @@ BufferGLTest::BufferGLTest() {
}
void BufferGLTest::construct() {
- Buffer buffer;
+ {
+ Buffer buffer;
+
+ MAGNUM_VERIFY_NO_ERROR();
+ CORRADE_VERIFY(buffer.id() > 0);
+ CORRADE_COMPARE(buffer.targetHint(), Buffer::Target::Array);
+ CORRADE_COMPARE(buffer.size(), 0);
+ }
+
+ MAGNUM_VERIFY_NO_ERROR();
+}
+
+void BufferGLTest::constructCopy() {
+ CORRADE_VERIFY(!(std::is_constructible{}));
+ /* GCC 4.6 doesn't have std::is_assignable */
+ #ifndef CORRADE_GCC46_COMPATIBILITY
+ CORRADE_VERIFY(!(std::is_assignable{}));
+ #endif
+}
+
+void BufferGLTest::constructMove() {
+ Buffer a;
+ const Int id = a.id();
+
+ MAGNUM_VERIFY_NO_ERROR();
+ CORRADE_VERIFY(id > 0);
+
+ Buffer b(std::move(a));
+
+ CORRADE_COMPARE(a.id(), 0);
+ CORRADE_COMPARE(b.id(), id);
+
+ Buffer c;
+ const Int cId = c.id();
+ c = std::move(b);
+
MAGNUM_VERIFY_NO_ERROR();
+ CORRADE_VERIFY(cId > 0);
+ CORRADE_COMPARE(b.id(), cId);
+ CORRADE_COMPARE(c.id(), id);
+}
+
+void BufferGLTest::label() {
+ /* No-Op version is tested in AbstractObjectGLTest */
+ if(!Context::current()->isExtensionSupported() &&
+ !Context::current()->isExtensionSupported())
+ CORRADE_SKIP("Required extension is not available");
+
+ Buffer buffer;
+ CORRADE_COMPARE(buffer.label(), "");
- CORRADE_COMPARE(buffer.targetHint(), Buffer::Target::Array);
+ buffer.setLabel("MyBuffer");
+ CORRADE_COMPARE(buffer.label(), "MyBuffer");
- CORRADE_COMPARE(buffer.size(), 0);
MAGNUM_VERIFY_NO_ERROR();
}
@@ -275,10 +328,10 @@ void BufferGLTest::mapRangeExplicitFlush() {
void BufferGLTest::copy() {
Buffer buffer1;
constexpr char data[] = {2, 7, 5, 13, 25};
- buffer1.setData(data, BufferUsage::StaticDraw);
+ buffer1.setData(data, BufferUsage::StaticCopy);
Buffer buffer2;
- buffer2.setData({nullptr, 5}, BufferUsage::StaticDraw);
+ buffer2.setData({nullptr, 5}, BufferUsage::StaticRead);
Buffer::copy(buffer1, buffer2, 1, 2, 3);
MAGNUM_VERIFY_NO_ERROR();
diff --git a/src/Test/BufferImageGLTest.cpp b/src/Test/BufferImageGLTest.cpp
new file mode 100644
index 000000000..ff01edf04
--- /dev/null
+++ b/src/Test/BufferImageGLTest.cpp
@@ -0,0 +1,130 @@
+/*
+ This file is part of Magnum.
+
+ Copyright © 2010, 2011, 2012, 2013 VladimÃr VondruÅ¡
+
+ 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
+
+#include "BufferImage.h"
+#include "ColorFormat.h"
+#include "Test/AbstractOpenGLTester.h"
+
+namespace Magnum { namespace Test {
+
+class BufferImageTest: public AbstractOpenGLTester {
+ public:
+ explicit BufferImageTest();
+
+ void construct();
+ void constructCopy();
+ void constructMove();
+
+ void setData();
+};
+
+BufferImageTest::BufferImageTest() {
+ addTests({&BufferImageTest::construct,
+ &BufferImageTest::constructCopy,
+ &BufferImageTest::constructMove,
+
+ &BufferImageTest::setData});
+}
+
+void BufferImageTest::construct() {
+ const unsigned char data[] = { 'a', 'b', 'c' };
+ BufferImage2D a(ColorFormat::Red, ColorType::UnsignedByte, {1, 3}, data, BufferUsage::StaticDraw);
+ const auto imageData = a.buffer().data();
+
+ MAGNUM_VERIFY_NO_ERROR();
+
+ CORRADE_COMPARE(a.format(), ColorFormat::Red);
+ CORRADE_COMPARE(a.type(), ColorType::UnsignedByte);
+ CORRADE_COMPARE(a.size(), Vector2i(1, 3));
+ CORRADE_COMPARE_AS(std::vector(imageData.begin(), imageData.end()),
+ std::vector(data, data + 3),
+ TestSuite::Compare::Container);
+}
+
+void BufferImageTest::constructCopy() {
+ CORRADE_VERIFY(!(std::is_constructible