From f68b40c5d9dbc6e34dcc0aba4212cf76f4bc6b72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Sun, 19 Jun 2016 20:32:28 +0200 Subject: [PATCH] Implemented *Framebuffer::copyImage() and copySubImage(). Default, ARB_DSA and EXT_DSA paths. --- doc/opengl-mapping.dox | 4 +- doc/opengl-support.dox | 1 - src/Magnum/AbstractFramebuffer.cpp | 160 +++++ src/Magnum/AbstractFramebuffer.h | 322 ++++++++++ src/Magnum/AbstractTexture.h | 1 + .../Implementation/FramebufferState.cpp | 19 + src/Magnum/Implementation/FramebufferState.h | 10 + src/Magnum/Test/FramebufferGLTest.cpp | 556 +++++++++++++++++- src/Magnum/Texture.h | 9 +- 9 files changed, 1074 insertions(+), 8 deletions(-) diff --git a/doc/opengl-mapping.dox b/doc/opengl-mapping.dox index 37dd149b3..4fd9ab6f0 100644 --- a/doc/opengl-mapping.dox +++ b/doc/opengl-mapping.dox @@ -101,8 +101,8 @@ OpenGL function | Matching API @fn_gl{CompressedTexSubImage1D}, \n `glCompressedTextureSubImage1D()`, \n @fn_gl_extension{CompressedTextureSubImage1D,EXT,direct_state_access}, \n @fn_gl{CompressedTexSubImage2D}, \n `glCompressedTextureSubImage2D()`, \n @fn_gl_extension{CompressedTextureSubImage2D,EXT,direct_state_access}, \n @fn_gl{CompressedTexSubImage3D}, \n `glCompressedTextureSubImage3D()`, \n @fn_gl_extension{CompressedTextureSubImage3D,EXT,direct_state_access} | @ref Texture::setCompressedSubImage(), \n @ref TextureArray::setCompressedSubImage(), \n @ref CubeMapTexture::setCompressedSubImage(), \n @ref CubeMapTextureArray::setCompressedSubImage(), \n @ref RectangleTexture::setCompressedSubImage() @fn_gl{CopyBufferSubData}, \n `glCopyNamedBufferSubData()`, \n @fn_gl_extension{NamedCopyBufferSubData,EXT,direct_state_access} | @ref Buffer::copy() @fn_gl{CopyImageSubData} | | -@fn_gl{CopyTexImage1D}, \n @fn_gl_extension{CopyTextureImage1D,EXT,direct_state_access}, \n @fn_gl{CopyTexImage2D}, \n @fn_gl_extension{CopyTextureImage2D,EXT,direct_state_access} | | -@fn_gl{CopyTexSubImage1D}, \n `glCopyTextureSubImage1D()`, \n @fn_gl_extension{CopyTextureSubImage1D,EXT,direct_state_access}, \n @fn_gl{CopyTexSubImage2D}, \n `glCopyTextureSubImage2D()`, \n @fn_gl_extension{CopyTextureSubImage2D,EXT,direct_state_access}, \n @fn_gl{CopyTexSubImage3D}, \n `glCopyTextureSubImage3D()`, \n @fn_gl_extension{CopyTextureSubImage3D,EXT,direct_state_access} | | +@fn_gl{CopyTexImage1D}, \n @fn_gl{CopyTexImage2D} | @ref Framebuffer::copyImage() +@fn_gl{CopyTexSubImage1D}, \n `glCopyTextureSubImage1D()`, \n @fn_gl_extension{CopyTextureSubImage1D,EXT,direct_state_access}, \n @fn_gl{CopyTexSubImage2D}, \n `glCopyTextureSubImage2D()`, \n @fn_gl_extension{CopyTextureSubImage2D,EXT,direct_state_access}, \n @fn_gl{CopyTexSubImage3D}, \n `glCopyTextureSubImage3D()`, \n @fn_gl_extension{CopyTextureSubImage3D,EXT,direct_state_access} | @ref Framebuffer::copySubImage() @fn_gl{CreateProgram}, @fn_gl{DeleteProgram} | @ref AbstractShaderProgram constructor and destructor @fn_gl{CreateShader}, @fn_gl{DeleteShader} | @ref Shader constructor and destructor @fn_gl{CreateShaderProgram} | | diff --git a/doc/opengl-support.dox b/doc/opengl-support.dox index cf33b9bb1..a9bf219f6 100644 --- a/doc/opengl-support.dox +++ b/doc/opengl-support.dox @@ -40,7 +40,6 @@ The core subset of OpenGL 2.1 should be fully implemented, except for the following: - Proxy textures -- Copying framebuffer to texture (@fn_gl{CopyTexImage2D} etc.) - Some forgotten limit queries @subsection opengl-support-30 OpenGL 3.0 diff --git a/src/Magnum/AbstractFramebuffer.cpp b/src/Magnum/AbstractFramebuffer.cpp index 03a9cc61d..f3c73c4c9 100644 --- a/src/Magnum/AbstractFramebuffer.cpp +++ b/src/Magnum/AbstractFramebuffer.cpp @@ -29,8 +29,19 @@ #include "Magnum/BufferImage.h" #endif #include "Magnum/Context.h" +#include "Magnum/CubeMapTexture.h" +#if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) +#include "Magnum/CubeMapTextureArray.h" +#endif #include "Magnum/Extensions.h" #include "Magnum/Image.h" +#ifndef MAGNUM_TARGET_GLES +#include "Magnum/RectangleTexture.h" +#endif +#include "Magnum/Texture.h" +#ifndef MAGNUM_TARGET_GLES2 +#include "Magnum/TextureArray.h" +#endif #include "Implementation/FramebufferState.h" #include "Implementation/State.h" @@ -331,6 +342,96 @@ BufferImage2D AbstractFramebuffer::read(const Range2Di& rectangle, BufferImage2D } #endif +#ifndef MAGNUM_TARGET_GLES +void AbstractFramebuffer::copyImage(const Range2Di& rectangle, Texture1D& texture, const Int level, const TextureFormat internalFormat) { + CORRADE_ASSERT(rectangle.sizeY() == 1, "AbstractFramebuffer::copyImage(): height must be 1 for 1D textures", ); + bindInternal(FramebufferTarget::Read); + texture.bindInternal(); + glCopyTexImage1D(GL_TEXTURE_1D, level, GLenum(internalFormat), rectangle.min().x(), rectangle.min().y(), rectangle.sizeX(), 0); +} +#endif + +void AbstractFramebuffer::copyImage(const Range2Di& rectangle, Texture2D& texture, const Int level, const TextureFormat internalFormat) { + bindInternal(FramebufferTarget::Read); + texture.bindInternal(); + glCopyTexImage2D(GL_TEXTURE_2D, level, GLenum(internalFormat), rectangle.min().x(), rectangle.min().y(), rectangle.sizeX(), rectangle.sizeY(), 0); +} + +#ifndef MAGNUM_TARGET_GLES +void AbstractFramebuffer::copyImage(const Range2Di& rectangle, RectangleTexture& texture, const TextureFormat internalFormat) { + bindInternal(FramebufferTarget::Read); + texture.bindInternal(); + glCopyTexImage2D(GL_TEXTURE_RECTANGLE, 0, GLenum(internalFormat), rectangle.min().x(), rectangle.min().y(), rectangle.sizeX(), rectangle.sizeY(), 0); +} +#endif + +void AbstractFramebuffer::copyImage(const Range2Di& rectangle, CubeMapTexture& texture, const CubeMapCoordinate coordinate, const Int level, const TextureFormat internalFormat) { + bindInternal(FramebufferTarget::Read); + texture.bindInternal(); + glCopyTexImage2D(GLenum(coordinate), level, GLenum(internalFormat), rectangle.min().x(), rectangle.min().y(), rectangle.sizeX(), rectangle.sizeY(), 0); +} + +#ifndef MAGNUM_TARGET_GLES +void AbstractFramebuffer::copyImage(const Range2Di& rectangle, Texture1DArray& texture, const Int level, const TextureFormat internalFormat) { + bindInternal(FramebufferTarget::Read); + texture.bindInternal(); + glCopyTexImage2D(GL_TEXTURE_1D_ARRAY, level, GLenum(internalFormat), rectangle.min().x(), rectangle.min().y(), rectangle.sizeX(), rectangle.sizeY(), 0); +} +#endif + +#ifndef MAGNUM_TARGET_GLES +void AbstractFramebuffer::copySubImage(const Range2Di& rectangle, Texture1D& texture, const Int level, const Int offset) { + CORRADE_ASSERT(rectangle.sizeY() == 1, "AbstractFramebuffer::copyImage(): height must be 1 for 1D textures", ); + bindInternal(FramebufferTarget::Read); + Context::current().state().framebuffer->copySub1DImplementation(rectangle, texture, level, offset); +} +#endif + +void AbstractFramebuffer::copySubImage(const Range2Di& rectangle, Texture2D& texture, const Int level, const Vector2i& offset) { + bindInternal(FramebufferTarget::Read); + Context::current().state().framebuffer->copySub2DImplementation(rectangle, texture, GL_TEXTURE_2D, level, offset); +} + +#ifndef MAGNUM_TARGET_GLES +void AbstractFramebuffer::copySubImage(const Range2Di& rectangle, RectangleTexture& texture, const Vector2i& offset) { + bindInternal(FramebufferTarget::Read); + Context::current().state().framebuffer->copySub2DImplementation(rectangle, texture, GL_TEXTURE_RECTANGLE, 0, offset); +} +#endif + +void AbstractFramebuffer::copySubImage(const Range2Di& rectangle, CubeMapTexture& texture, const Int level, const Vector3i& offset) { + bindInternal(FramebufferTarget::Read); + Context::current().state().framebuffer->copySubCubeMapImplementation(rectangle, texture, GL_TEXTURE_CUBE_MAP_POSITIVE_X + offset.z(), level, offset.xy()); +} + +#if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) +void AbstractFramebuffer::copySubImage(const Range2Di& rectangle, Texture3D& texture, const Int level, const Vector3i& offset) { + bindInternal(FramebufferTarget::Read); + Context::current().state().framebuffer->copySub3DImplementation(rectangle, texture, level, offset); +} +#endif + +#ifndef MAGNUM_TARGET_GLES +void AbstractFramebuffer::copySubImage(const Range2Di& rectangle, Texture1DArray& texture, const Int level, const Vector2i& offset) { + bindInternal(FramebufferTarget::Read); + Context::current().state().framebuffer->copySub2DImplementation(rectangle, texture, GL_TEXTURE_1D_ARRAY, level, offset); +} +#endif + +#ifndef MAGNUM_TARGET_GLES2 +void AbstractFramebuffer::copySubImage(const Range2Di& rectangle, Texture2DArray& texture, const Int level, const Vector3i& offset) { + bindInternal(FramebufferTarget::Read); + Context::current().state().framebuffer->copySub3DImplementation(rectangle, texture, level, offset); +} +#endif + +#if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) +void AbstractFramebuffer::copySubImage(const Range2Di& rectangle, CubeMapTextureArray& texture, const Int level, const Vector3i& offset) { + bindInternal(FramebufferTarget::Read); + Context::current().state().framebuffer->copySub3DImplementation(rectangle, texture, level, offset); +} +#endif + void AbstractFramebuffer::invalidateImplementationNoOp(GLsizei, const GLenum* const) {} void AbstractFramebuffer::invalidateImplementationDefault(const GLsizei count, const GLenum* const attachments) { @@ -497,4 +598,63 @@ void AbstractFramebuffer::readImplementationRobustness(const Range2Di& rectangle } #endif +#ifndef MAGNUM_TARGET_GLES +void AbstractFramebuffer::copySub1DImplementationDefault(const Range2Di& rectangle, AbstractTexture& texture, const Int level, const Int offset) { + texture.bindInternal(); + glCopyTexSubImage1D(texture._target, level, offset, rectangle.min().x(), rectangle.min().y(), rectangle.sizeX()); +} + +void AbstractFramebuffer::copySub1DImplementationDSA(const Range2Di& rectangle, AbstractTexture& texture, const Int level, const Int offset) { + glCopyTextureSubImage1D(texture._id, level, offset, rectangle.min().x(), rectangle.min().y(), rectangle.sizeX()); +} + +void AbstractFramebuffer::copySub1DImplementationDSAEXT(const Range2Di& rectangle, AbstractTexture& texture, const Int level, const Int offset) { + texture._flags |= ObjectFlag::Created; + glCopyTextureSubImage1DEXT(texture._id, texture._target, level, offset, rectangle.min().x(), rectangle.min().y(), rectangle.sizeX()); +} +#endif + +void AbstractFramebuffer::copySub2DImplementationDefault(const Range2Di& rectangle, AbstractTexture& texture, const GLenum target, const Int level, const Vector2i& offset) { + texture.bindInternal(); + glCopyTexSubImage2D(target, level, offset.x(), offset.y(), rectangle.min().x(), rectangle.min().y(), rectangle.sizeX(), rectangle.sizeY()); +} + +#ifndef MAGNUM_TARGET_GLES +void AbstractFramebuffer::copySub2DImplementationDSA(const Range2Di& rectangle, AbstractTexture& texture, const GLenum, const Int level, const Vector2i& offset) { + glCopyTextureSubImage2D(texture._id, level, offset.x(), offset.y(), rectangle.min().x(), rectangle.min().y(), rectangle.sizeX(), rectangle.sizeY()); +} + +void AbstractFramebuffer::copySubCubeMapImplementationDSA(const Range2Di& rectangle, AbstractTexture& texture, const GLenum target, const Int level, const Vector2i& offset) { + glCopyTextureSubImage3D(texture._id, level, offset.x(), offset.y(), target - GL_TEXTURE_CUBE_MAP_POSITIVE_X, rectangle.min().x(), rectangle.min().y(), rectangle.sizeX(), rectangle.sizeY()); +} + +void AbstractFramebuffer::copySub2DImplementationDSAEXT(const Range2Di& rectangle, AbstractTexture& texture, const GLenum target, const Int level, const Vector2i& offset) { + texture._flags |= ObjectFlag::Created; + glCopyTextureSubImage2DEXT(texture._id, target, level, offset.x(), offset.y(), rectangle.min().x(), rectangle.min().y(), rectangle.sizeX(), rectangle.sizeY()); +} +#endif + +#if !(defined(MAGNUM_TARGET_GLES2) && defined(MAGNUM_TARGET_WEBGL)) +void AbstractFramebuffer::copySub3DImplementationDefault(const Range2Di& rectangle, AbstractTexture& texture, const Int level, const Vector3i& offset) { + texture.bindInternal(); + #ifndef MAGNUM_TARGET_GLES2 + glCopyTexSubImage3D + #else + glCopyTexSubImage3DOES + #endif + (texture._target, level, offset.x(), offset.y(), offset.z(), rectangle.min().x(), rectangle.min().y(), rectangle.sizeX(), rectangle.sizeY()); +} +#endif + +#ifndef MAGNUM_TARGET_GLES +void AbstractFramebuffer::copySub3DImplementationDSA(const Range2Di& rectangle, AbstractTexture& texture, const Int level, const Vector3i& offset) { + glCopyTextureSubImage3D(texture._id, level, offset.x(), offset.y(), offset.z(), rectangle.min().x(), rectangle.min().y(), rectangle.sizeX(), rectangle.sizeY()); +} + +void AbstractFramebuffer::copySub3DImplementationDSAEXT(const Range2Di& rectangle, AbstractTexture& texture, const Int level, const Vector3i& offset) { + texture._flags |= ObjectFlag::Created; + glCopyTextureSubImage3DEXT(texture._id, texture._target, level, offset.x(), offset.y(), offset.z(), rectangle.min().x(), rectangle.min().y(), rectangle.sizeX(), rectangle.sizeY()); +} +#endif + } diff --git a/src/Magnum/AbstractFramebuffer.h b/src/Magnum/AbstractFramebuffer.h index f966dd0f8..41d048eab 100644 --- a/src/Magnum/AbstractFramebuffer.h +++ b/src/Magnum/AbstractFramebuffer.h @@ -383,6 +383,307 @@ class MAGNUM_EXPORT AbstractFramebuffer { #endif #endif + #ifndef MAGNUM_TARGET_GLES + /** + * @brief Copy block of pixels from framebuffer to 1D texture image + * @param rectangle Framebuffer rectangle to copy. Height must + * be `1`. + * @param texture Texture where to put the data + * @param level Texture mip level + * @param internalFormat Texture internal format + * + * On platforms that support it prefer to use @ref Texture1D::setStorage() + * and @ref copySubImage() instead, as it avoids unnecessary + * reallocations and has better performance characteristics. This call + * also has no equivalent in @extension{ARB,direct_state_access}, thus + * the texture needs to be bound to some texture unit before the + * operation. + * @see @ref Texture1D::maxSize(), @fn_gl{BindFramebuffer}, then + * @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and + * @fn_gl{CopyTexImage1D} + * @requires_gl 1D textures are not available in OpenGL ES or WebGL. + * @deprecated_gl Prefer to use @ref Texture1D::setStorage() and + * @ref copySubImage() instead. + */ + void copyImage(const Range2Di& rectangle, Texture1D& texture, Int level, TextureFormat internalFormat); + #endif + + /** + * @brief Copy block of pixels from framebuffer to 2D texture image + * @param rectangle Framebuffer rectangle to copy + * @param texture Texture where to put the data + * @param level Texture mip level + * @param internalFormat Texture internal format + * + * On platforms that support it prefer to use @ref Texture2D::setStorage() + * and @ref copySubImage() instead, as it avoids unnecessary + * reallocations and has better performance characteristics. This call + * also has no equivalent in @extension{ARB,direct_state_access}, thus + * the texture needs to be bound to some texture unit before the + * operation. + * @see @ref Texture2D::maxSize(), @fn_gl{BindFramebuffer}, then + * @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and + * @fn_gl{CopyTexImage2D} + * @deprecated_gl Prefer to use @ref Texture2D::setStorage() and + * @ref copySubImage() instead. + */ + void copyImage(const Range2Di& rectangle, Texture2D& texture, Int level, TextureFormat internalFormat); + + #ifndef MAGNUM_TARGET_GLES + /** + * @brief Copy block of pixels from framebuffer to rectangle texture + * @param rectangle Framebuffer rectangle to copy + * @param texture Texture where to put the data + * @param internalFormat Texture internal format + * + * On platforms that support it prefer to use @ref RectangleTexture::setStorage() + * and @ref copySubImage() instead, as it avoids unnecessary + * reallocations and has better performance characteristics. This call + * also has no equivalent in @extension{ARB,direct_state_access}, thus + * the texture needs to be bound to some texture unit before the + * operation. + * @see @ref Texture2D::maxSize(), @fn_gl{BindFramebuffer}, then + * @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and + * @fn_gl{CopyTexImage2D} + * @requires_gl31 Extension @extension{ARB,texture_rectangle} + * @requires_gl Rectangle textures are not available in OpenGL ES and + * WebGL. + * @deprecated_gl Prefer to use @ref RectangleTexture::setStorage() and + * @ref copySubImage() instead. + */ + void copyImage(const Range2Di& rectangle, RectangleTexture& texture, TextureFormat internalFormat); + #endif + + /** + * @brief Copy block of pixels from framebuffer to cube map texture image + * @param rectangle Framebuffer rectangle to copy + * @param texture Texture where to put the data + * @param level Texture mip level + * @param coordinate Cube map coordinate + * @param internalFormat Texture internal format + * + * On platforms that support it prefer to use @ref CubeMapTexture::setStorage() + * and @ref copySubImage() instead, as it avoids unnecessary + * reallocations and has better performance characteristics. This call + * also has no equivalent in @extension{ARB,direct_state_access}, thus + * the texture needs to be bound to some texture unit before the + * operation. + * @see @ref Texture2D::maxSize(), @fn_gl{BindFramebuffer}, then + * @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and + * @fn_gl{CopyTexImage2D} + * @deprecated_gl Prefer to use @ref CubeMapTexture::setStorage() and + * @ref copySubImage() instead. + */ + void copyImage(const Range2Di& rectangle, CubeMapTexture& texture, CubeMapCoordinate coordinate, Int level, TextureFormat internalFormat); + + #ifndef MAGNUM_TARGET_GLES + /** + * @brief Copy block of pixels from framebuffer to 1D texture array image + * @param rectangle Framebuffer rectangle to copy + * @param texture Texture where to put the data + * @param level Texture mip level + * @param internalFormat Texture internal format + * + * On platforms that support it prefer to use @ref Texture2D::setStorage() + * and @ref copySubImage() instead, as it avoids unnecessary + * reallocations and has better performance characteristics. This call + * also has no equivalent in @extension{ARB,direct_state_access}, thus + * the texture needs to be bound to some texture unit before the + * operation. + * @see @ref Texture2D::maxSize(), @fn_gl{BindFramebuffer}, then + * @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and + * @fn_gl{CopyTexImage2D} + * @requires_gl 1D array textures are not available in OpenGL ES or + * WebGL, only 2D ones. + * @deprecated_gl Prefer to use @ref Texture1DArray::setStorage() and + * @ref copySubImage() instead. + */ + void copyImage(const Range2Di& rectangle, Texture1DArray& texture, Int level, TextureFormat internalFormat); + #endif + + #ifndef MAGNUM_TARGET_GLES + /** + * @brief Copy block of pixels from framebuffer to 1D texture subimage + * @param rectangle Framebuffer rectangle to copy. Height must + * be `1`. + * @param texture Texture where to put the data + * @param level Texture mip level + * @param offset Offset inside the texture + * + * If neither @extension{ARB,direct_state_access} (part of OpenGL 4.5) + * nor @extension{EXT,direct_state_access} desktop extension is + * available, the texture is bound before the operation (if not + * already). + * @see @ref Texture1D::setStorage(), @fn_gl{BindFramebuffer}, then + * @fn_gl2{CopyTextureSubImage1D,CopyTexSubImage1D}, + * @fn_gl_extension{CopyTextureSubImage1D,EXT,direct_state_access}, + * eventually @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and + * @fn_gl{CopyTexSubImage1D} + * @requires_gl 1D textures are not available in OpenGL ES or WebGL. + */ + void copySubImage(const Range2Di& rectangle, Texture1D& texture, Int level, Int offset); + #endif + + /** + * @brief Copy block of pixels from framebuffer to 2D texture subimage + * @param rectangle Framebuffer rectangle to copy + * @param texture Texture where to put the data + * @param level Texture mip level + * @param offset Offset inside the texture + * + * If neither @extension{ARB,direct_state_access} (part of OpenGL 4.5) + * nor @extension{EXT,direct_state_access} desktop extension is + * available, the texture is bound before the operation (if not + * already). + * @see @ref Texture2D::setStorage(), @fn_gl{BindFramebuffer}, then + * @fn_gl2{CopyTextureSubImage2D,CopyTexSubImage2D}, + * @fn_gl_extension{CopyTextureSubImage2D,EXT,direct_state_access}, + * eventually @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and + * @fn_gl{CopyTexSubImage2D} + */ + void copySubImage(const Range2Di& rectangle, Texture2D& texture, Int level, const Vector2i& offset); + + #ifndef MAGNUM_TARGET_GLES + /** + * @brief Copy block of pixels from framebuffer to rectangle texture subimage + * @param rectangle Framebuffer rectangle to copy + * @param texture Texture where to put the data + * @param offset Offset inside the texture + * + * If neither @extension{ARB,direct_state_access} (part of OpenGL 4.5) + * nor @extension{EXT,direct_state_access} desktop extension is + * available, the texture is bound before the operation (if not + * already). + * @see @ref RectangleTexture::setStorage(), @fn_gl{BindFramebuffer}, + * then @fn_gl2{CopyTextureSubImage2D,CopyTexSubImage2D}, + * @fn_gl_extension{CopyTextureSubImage2D,EXT,direct_state_access}, + * eventually @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and + * @fn_gl{CopyTexSubImage2D} + * @requires_gl Rectangle textures are not available in OpenGL ES and + * WebGL. + */ + void copySubImage(const Range2Di& rectangle, RectangleTexture& texture, const Vector2i& offset); + #endif + + /** + * @brief Copy block of pixels from framebuffer to cube map texture subimage + * @param rectangle Framebuffer rectangle to copy + * @param texture Texture where to put the data + * @param level Texture mip level + * @param offset Offset inside the texture + * + * Z coordinate of the offset is equivalent to number of texture face, + * i.e. +X is `0` and so on, in order of (+X, -X, +Y, -Y, +Z, -Z). If + * neither @extension{ARB,direct_state_access} (part of OpenGL 4.5) nor + * @extension{EXT,direct_state_access} desktop extension is available, + * the texture is bound before the operation (if not already). + * @see @ref CubeMapTexture::setStorage(), @fn_gl{BindFramebuffer}, + * then @fn_gl2{CopyTextureSubImage3D,CopyTexSubImage3D}, + * @fn_gl_extension{CopyTextureSubImage2D,EXT,direct_state_access}, + * eventually @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and + * @fn_gl{CopyTexSubImage2D} + */ + void copySubImage(const Range2Di& rectangle, CubeMapTexture& texture, Int level, const Vector3i& offset); + + #if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) + /** + * @brief Copy block of pixels from framebuffer to 3D texture subimage + * @param rectangle Framebuffer rectangle to copy + * @param texture Texture where to put the data + * @param level Texture mip level + * @param offset Offset inside the texture + * + * If neither @extension{ARB,direct_state_access} (part of OpenGL 4.5) + * nor @extension{EXT,direct_state_access} desktop extension is + * available, the texture is bound before the operation (if not + * already). + * @see @ref Texture3D::setStorage(), @fn_gl{BindFramebuffer}, then + * @fn_gl2{CopyTextureSubImage3D,CopyTexSubImage3D}, + * @fn_gl_extension{CopyTextureSubImage3D,EXT,direct_state_access}, + * eventually @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and + * @fn_gl{CopyTexSubImage3D} + * @requires_gles30 Extension @es_extension{OES,texture_3D} in OpenGL + * ES 2.0. + * @requires_webgl20 Only 2D textures are available in WebGL 1.0. + */ + void copySubImage(const Range2Di& rectangle, Texture3D& texture, Int level, const Vector3i& offset); + #endif + + #ifndef MAGNUM_TARGET_GLES + /** + * @brief Copy block of pixels from framebuffer to 1D texture array subimage + * @param rectangle Framebuffer rectangle to copy + * @param texture Texture where to put the data + * @param level Texture mip level + * @param offset Offset inside the texture + * + * If neither @extension{ARB,direct_state_access} (part of OpenGL 4.5) + * nor @extension{EXT,direct_state_access} desktop extension is + * available, the texture is bound before the operation (if not + * already). + * @see @ref Texture1DArray::setStorage(), @fn_gl{BindFramebuffer}, + * then @fn_gl2{CopyTextureSubImage2D,CopyTexSubImage2D}, + * @fn_gl_extension{CopyTextureSubImage2D,EXT,direct_state_access}, + * eventually @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and + * @fn_gl{CopyTexSubImage2D} + * @requires_gl 1D array textures are not available in OpenGL ES or + * WebGL, only 2D ones. + */ + void copySubImage(const Range2Di& rectangle, Texture1DArray& texture, Int level, const Vector2i& offset); + #endif + + #ifndef MAGNUM_TARGET_GLES2 + /** + * @brief Copy block of pixels from framebuffer to 2D texture array subimage + * @param rectangle Framebuffer rectangle to copy + * @param texture Texture where to put the data + * @param level Texture mip level + * @param offset Offset inside the texture + * + * If neither @extension{ARB,direct_state_access} (part of OpenGL 4.5) + * nor @extension{EXT,direct_state_access} desktop extension is + * available, the texture is bound before the operation (if not + * already). + * @see @ref Texture2DArray::setStorage(), @fn_gl{BindFramebuffer}, + * then @fn_gl2{CopyTextureSubImage3D,CopyTexSubImage3D}, + * @fn_gl_extension{CopyTextureSubImage3D,EXT,direct_state_access}, + * eventually @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and + * @fn_gl{CopyTexSubImage3D} + * @requires_gl30 Extension @extension{EXT,texture_array} + * @requires_gles30 Array textures are not available in OpenGL ES 2.0. + * @requires_webgl20 Array textures are not available in WebGL 1.0. + */ + void copySubImage(const Range2Di& rectangle, Texture2DArray& texture, Int level, const Vector3i& offset); + #endif + + #if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) + /** + * @brief Copy block of pixels from framebuffer to cube map texture array subimage + * @param rectangle Framebuffer rectangle to copy + * @param texture Texture where to put the data + * @param level Texture mip level + * @param offset Offset inside the texture + * + * Z coordinate of the offset is equivalent to layer * 6 + number of + * texture face, i.e. +X is `0` and so on, in order of (+X, -X, +Y, -Y, + * +Z, -Z). If neither @extension{ARB,direct_state_access} (part of + * OpenGL 4.5) nor @extension{EXT,direct_state_access} desktop + * available, the texture is bound before the operation (if not + * already). + * @see @ref CubeMapTextureArray::setStorage(), @fn_gl{BindFramebuffer}, + * then @fn_gl2{CopyTextureSubImage3D,CopyTexSubImage3D}, + * @fn_gl_extension{CopyTextureSubImage3D,EXT,direct_state_access}, + * eventually @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and + * @fn_gl{CopyTexSubImage3D} + * @requires_gl40 Extension @extension{ARB,texture_cube_map_array} + * @requires_gles30 Not defined in OpenGL ES 2.0. + * @requires_es_extension Extension @es_extension{ANDROID,extension_pack_es31a}/ + * @es_extension{EXT,texture_cube_map_array} + * @requires_gles Cube map texture arrays are not available in WebGL. + */ + void copySubImage(const Range2Di& rectangle, CubeMapTextureArray& texture, Int level, const Vector3i& offset); + #endif + #ifdef DOXYGEN_GENERATING_OUTPUT private: #else @@ -462,6 +763,27 @@ class MAGNUM_EXPORT AbstractFramebuffer { static void MAGNUM_LOCAL readImplementationRobustness(const Range2Di& rectangle, PixelFormat format, PixelType type, std::size_t dataSize, GLvoid* data); #endif + #ifndef MAGNUM_TARGET_GLES + static void MAGNUM_LOCAL copySub1DImplementationDefault(const Range2Di& rectangle, AbstractTexture& texture, Int level, Int offset); + static void MAGNUM_LOCAL copySub1DImplementationDSA(const Range2Di& rectangle, AbstractTexture& texture, Int level, Int offset); + static void MAGNUM_LOCAL copySub1DImplementationDSAEXT(const Range2Di& rectangle, AbstractTexture& texture, Int level, Int offset); + #endif + + static void MAGNUM_LOCAL copySub2DImplementationDefault(const Range2Di& rectangle, AbstractTexture& texture, GLenum textureTarget, Int level, const Vector2i& offset); + #ifndef MAGNUM_TARGET_GLES + static void MAGNUM_LOCAL copySub2DImplementationDSA(const Range2Di& rectangle, AbstractTexture& texture, GLenum textureTarget, Int level, const Vector2i& offset); + static void MAGNUM_LOCAL copySubCubeMapImplementationDSA(const Range2Di& rectangle, AbstractTexture& texture, GLenum textureTarget, Int level, const Vector2i& offset); + static void MAGNUM_LOCAL copySub2DImplementationDSAEXT(const Range2Di& rectangle, AbstractTexture& texture, GLenum textureTarget, Int level, const Vector2i& offset); + #endif + + #if !(defined(MAGNUM_TARGET_GLES2) && defined(MAGNUM_TARGET_WEBGL)) + static void MAGNUM_LOCAL copySub3DImplementationDefault(const Range2Di& rectangle, AbstractTexture& texture, Int level, const Vector3i& offset); + #endif + #ifndef MAGNUM_TARGET_GLES + static void MAGNUM_LOCAL copySub3DImplementationDSA(const Range2Di& rectangle, AbstractTexture& texture, Int level, const Vector3i& offset); + static void MAGNUM_LOCAL copySub3DImplementationDSAEXT(const Range2Di& rectangle, AbstractTexture& texture, Int level, const Vector3i& offset); + #endif + void MAGNUM_LOCAL invalidateImplementationNoOp(GLsizei, const GLenum*); void MAGNUM_LOCAL invalidateImplementationDefault(GLsizei count, const GLenum* attachments); #ifndef MAGNUM_TARGET_GLES diff --git a/src/Magnum/AbstractTexture.h b/src/Magnum/AbstractTexture.h index 77694e01f..4d49b9540 100644 --- a/src/Magnum/AbstractTexture.h +++ b/src/Magnum/AbstractTexture.h @@ -133,6 +133,7 @@ functions do nothing. */ class MAGNUM_EXPORT AbstractTexture: public AbstractObject { friend Implementation::TextureState; + friend AbstractFramebuffer; friend CubeMapTexture; public: diff --git a/src/Magnum/Implementation/FramebufferState.cpp b/src/Magnum/Implementation/FramebufferState.cpp index 9ba1004f5..d0ebb0a57 100644 --- a/src/Magnum/Implementation/FramebufferState.cpp +++ b/src/Magnum/Implementation/FramebufferState.cpp @@ -68,6 +68,11 @@ FramebufferState::FramebufferState(Context& context, std::vector& e drawBufferImplementation = &AbstractFramebuffer::drawBufferImplementationDSA; readBufferImplementation = &AbstractFramebuffer::readBufferImplementationDSA; + copySub1DImplementation = &AbstractFramebuffer::copySub1DImplementationDSA; + copySub2DImplementation = &AbstractFramebuffer::copySub2DImplementationDSA; + copySubCubeMapImplementation = &AbstractFramebuffer::copySubCubeMapImplementationDSA; + copySub3DImplementation = &AbstractFramebuffer::copySub3DImplementationDSA; + renderbufferImplementation = &Framebuffer::renderbufferImplementationDSA; /* The 1D implementation uses the same function as the layered attachment */ texture1DImplementation = &Framebuffer::textureImplementationDSA; @@ -88,6 +93,11 @@ FramebufferState::FramebufferState(Context& context, std::vector& e drawBufferImplementation = &AbstractFramebuffer::drawBufferImplementationDSAEXT; readBufferImplementation = &AbstractFramebuffer::readBufferImplementationDSAEXT; + copySub1DImplementation = &AbstractFramebuffer::copySub1DImplementationDSAEXT; + copySub2DImplementation = &AbstractFramebuffer::copySub2DImplementationDSAEXT; + copySubCubeMapImplementation = &AbstractFramebuffer::copySub2DImplementationDSAEXT; + copySub3DImplementation = &AbstractFramebuffer::copySub3DImplementationDSAEXT; + renderbufferImplementation = &Framebuffer::renderbufferImplementationDSAEXT; texture1DImplementation = &Framebuffer::texture1DImplementationDSAEXT; /* The EXT_DSA implementation is the same for both 2D and cube map textures */ @@ -111,6 +121,15 @@ FramebufferState::FramebufferState(Context& context, std::vector& e readBufferImplementation = &AbstractFramebuffer::readBufferImplementationDefault; #endif + #ifndef MAGNUM_TARGET_GLES + copySub1DImplementation = &AbstractFramebuffer::copySub1DImplementationDefault; + #endif + copySub2DImplementation = &AbstractFramebuffer::copySub2DImplementationDefault; + copySubCubeMapImplementation = &AbstractFramebuffer::copySub2DImplementationDefault; + #if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) + copySub3DImplementation = &AbstractFramebuffer::copySub3DImplementationDefault; + #endif + renderbufferImplementation = &Framebuffer::renderbufferImplementationDefault; #ifndef MAGNUM_TARGET_GLES texture1DImplementation = &Framebuffer::texture1DImplementationDefault; diff --git a/src/Magnum/Implementation/FramebufferState.h b/src/Magnum/Implementation/FramebufferState.h index 278f87d6b..57564b103 100644 --- a/src/Magnum/Implementation/FramebufferState.h +++ b/src/Magnum/Implementation/FramebufferState.h @@ -56,6 +56,16 @@ struct FramebufferState { #endif #if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) void(AbstractFramebuffer::*readBufferImplementation)(GLenum); + #endif + #ifndef MAGNUM_TARGET_GLES + void(*copySub1DImplementation)(const Range2Di&, AbstractTexture&, Int, Int); + #endif + void(*copySub2DImplementation)(const Range2Di&, AbstractTexture&, GLenum, Int, const Vector2i&); + void(*copySubCubeMapImplementation)(const Range2Di&, AbstractTexture&, GLenum, Int, const Vector2i&); + #if !(defined(MAGNUM_TARGET_GLES2) && defined(MAGNUM_TARGET_WEBGL)) + void(*copySub3DImplementation)(const Range2Di&, AbstractTexture&, Int, const Vector3i&); + #endif + #if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) void(AbstractFramebuffer::*invalidateImplementation)(GLsizei, const GLenum*); #endif #ifndef MAGNUM_TARGET_GLES2 diff --git a/src/Magnum/Test/FramebufferGLTest.cpp b/src/Magnum/Test/FramebufferGLTest.cpp index c99f02b15..ccbf8be8a 100644 --- a/src/Magnum/Test/FramebufferGLTest.cpp +++ b/src/Magnum/Test/FramebufferGLTest.cpp @@ -23,7 +23,8 @@ DEALINGS IN THE SOFTWARE. */ -#include "Magnum/configure.h" +#include + #include "Magnum/Context.h" #include "Magnum/CubeMapTexture.h" #include "Magnum/Extensions.h" @@ -110,6 +111,35 @@ struct FramebufferGLTest: AbstractOpenGLTester { #ifndef MAGNUM_TARGET_GLES2 void readBuffer(); #endif + #ifndef MAGNUM_TARGET_GLES + void copyImageTexture1D(); + #endif + void copyImageTexture2D(); + #ifndef MAGNUM_TARGET_GLES + void copyImageTexture1DArray(); + #endif + #ifndef MAGNUM_TARGET_GLES + void copyImageRectangleTexture(); + #endif + void copyImageCubeMapTexture(); + #ifndef MAGNUM_TARGET_GLES + void copySubImageTexture1D(); + #endif + void copySubImageTexture2D(); + void copySubImageTexture3D(); + #ifndef MAGNUM_TARGET_GLES + void copySubImageTexture1DArray(); + #endif + #ifndef MAGNUM_TARGET_GLES2 + void copySubImageTexture2DArray(); + #endif + #ifndef MAGNUM_TARGET_GLES + void copySubImageRectangleTexture(); + #endif + void copySubImageCubeMapTexture(); + #if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) + void copySubImageCubeMapTextureArray(); + #endif void blit(); #ifdef MAGNUM_TARGET_GLES2 @@ -175,6 +205,35 @@ FramebufferGLTest::FramebufferGLTest() { #ifndef MAGNUM_TARGET_GLES2 &FramebufferGLTest::readBuffer, #endif + #ifndef MAGNUM_TARGET_GLES + &FramebufferGLTest::copyImageTexture1D, + #endif + &FramebufferGLTest::copyImageTexture2D, + #ifndef MAGNUM_TARGET_GLES + &FramebufferGLTest::copyImageTexture1DArray, + #endif + #ifndef MAGNUM_TARGET_GLES + &FramebufferGLTest::copyImageRectangleTexture, + #endif + &FramebufferGLTest::copyImageCubeMapTexture, + #ifndef MAGNUM_TARGET_GLES + &FramebufferGLTest::copySubImageTexture1D, + #endif + &FramebufferGLTest::copySubImageTexture2D, + &FramebufferGLTest::copySubImageTexture3D, + #ifndef MAGNUM_TARGET_GLES + &FramebufferGLTest::copySubImageTexture1DArray, + #endif + #ifndef MAGNUM_TARGET_GLES2 + &FramebufferGLTest::copySubImageTexture2DArray, + #endif + #ifndef MAGNUM_TARGET_GLES + &FramebufferGLTest::copySubImageRectangleTexture, + #endif + &FramebufferGLTest::copySubImageCubeMapTexture, + #if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) + &FramebufferGLTest::copySubImageCubeMapTextureArray, + #endif &FramebufferGLTest::blit}); #ifdef MAGNUM_TARGET_GLES2 @@ -1157,6 +1216,501 @@ void FramebufferGLTest::readBuffer() { } #endif +namespace { + constexpr char StorageData[]{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f + }; + + constexpr char ZeroStorage[4*4*4*6]{}; +} + +#ifndef MAGNUM_TARGET_GLES +void FramebufferGLTest::copyImageTexture1D() { + if(!Context::current().isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::framebuffer_object::string() + std::string(" is not available.")); + + Texture2D storage; + storage.setStorage(1, TextureFormat::RGBA8, Vector2i{4}) + .setSubImage(0, {}, ImageView2D{PixelFormat::RGBA, PixelType::UnsignedByte, Vector2i{4}, StorageData}); + + Framebuffer fb{{{}, Vector2i{4}}}; + fb.attachTexture(Framebuffer::ColorAttachment{0}, storage, 0); + + Texture1D texture; + fb.copyImage(Range2Di::fromSize(Vector2i{1}, {2, 1}), texture, 0, TextureFormat::RGBA8); + + MAGNUM_VERIFY_NO_ERROR(); + + CORRADE_COMPARE(texture.imageSize(0)[0], 2); + CORRADE_COMPARE_AS(texture.image(0, {PixelFormat::RGBA, PixelType::UnsignedByte}).release(), + Containers::Array::from(0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b), + TestSuite::Compare::Container); +} +#endif + +void FramebufferGLTest::copyImageTexture2D() { + #ifndef MAGNUM_TARGET_GLES + if(!Context::current().isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::framebuffer_object::string() + std::string(" is not available.")); + #endif + + Texture2D storage; + storage.setStorage(1, + #ifndef MAGNUM_TARGET_GLES2 + TextureFormat::RGBA8, + #else + rgbaFormatES2, + #endif + Vector2i{4}) + .setSubImage(0, {}, ImageView2D{PixelFormat::RGBA, PixelType::UnsignedByte, Vector2i{4}, StorageData}); + + Framebuffer fb{{{}, Vector2i{4}}}; + fb.attachTexture(Framebuffer::ColorAttachment{0}, storage, 0); + + Texture2D texture; + fb.copyImage(Range2Di::fromSize(Vector2i{1}, Vector2i{2}), texture, 0, + #ifndef MAGNUM_TARGET_GLES2 + TextureFormat::RGBA8 + #else + rgbaFormatES2 + #endif + ); + + MAGNUM_VERIFY_NO_ERROR(); + + #ifndef MAGNUM_TARGET_GLES + CORRADE_COMPARE(texture.imageSize(0), Vector2i{2}); + CORRADE_COMPARE_AS(texture.image(0, {PixelFormat::RGBA, PixelType::UnsignedByte}).release(), + Containers::Array::from(0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, + 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b), + TestSuite::Compare::Container); + #endif +} + +#ifndef MAGNUM_TARGET_GLES +void FramebufferGLTest::copyImageTexture1DArray() { + if(!Context::current().isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::framebuffer_object::string() + std::string(" is not available.")); + if(!Context::current().isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::EXT::texture_array::string() + std::string(" is not available.")); + + Texture2D storage; + storage.setStorage(1, TextureFormat::RGBA8, Vector2i{4}) + .setSubImage(0, {}, ImageView2D{PixelFormat::RGBA, PixelType::UnsignedByte, Vector2i{4}, StorageData}); + + Framebuffer fb{{{}, Vector2i{4}}}; + fb.attachTexture(Framebuffer::ColorAttachment{0}, storage, 0); + + Texture1DArray texture; + fb.copyImage(Range2Di::fromSize(Vector2i{1}, Vector2i{2}), texture, 0, TextureFormat::RGBA8); + + MAGNUM_VERIFY_NO_ERROR(); + + CORRADE_COMPARE(texture.imageSize(0), Vector2i{2}); + CORRADE_COMPARE_AS(texture.image(0, {PixelFormat::RGBA, PixelType::UnsignedByte}).release(), + Containers::Array::from(0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, + 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b), + TestSuite::Compare::Container); +} + +void FramebufferGLTest::copyImageRectangleTexture() { + if(!Context::current().isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::framebuffer_object::string() + std::string(" is not available.")); + if(!Context::current().isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::texture_rectangle::string() + std::string(" is not available.")); + + Texture2D storage; + storage.setStorage(1, TextureFormat::RGBA8, Vector2i{4}) + .setSubImage(0, {}, ImageView2D{PixelFormat::RGBA, PixelType::UnsignedByte, Vector2i{4}, StorageData}); + + Framebuffer fb{{{}, Vector2i{4}}}; + fb.attachTexture(Framebuffer::ColorAttachment{0}, storage, 0); + + RectangleTexture texture; + fb.copyImage(Range2Di::fromSize(Vector2i{1}, Vector2i{2}), texture, TextureFormat::RGBA8); + + MAGNUM_VERIFY_NO_ERROR(); + + CORRADE_COMPARE(texture.imageSize(), Vector2i{2}); + CORRADE_COMPARE_AS(texture.image({PixelFormat::RGBA, PixelType::UnsignedByte}).release(), + Containers::Array::from(0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, + 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b), + TestSuite::Compare::Container); +} +#endif + +void FramebufferGLTest::copyImageCubeMapTexture() { + #ifndef MAGNUM_TARGET_GLES + if(!Context::current().isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::framebuffer_object::string() + std::string(" is not available.")); + #endif + + Texture2D storage; + storage.setStorage(1, + #ifndef MAGNUM_TARGET_GLES2 + TextureFormat::RGBA8, + #else + rgbaFormatES2, + #endif + Vector2i{4}) + .setSubImage(0, {}, ImageView2D{PixelFormat::RGBA, PixelType::UnsignedByte, Vector2i{4}, StorageData}); + + Framebuffer fb{{{}, Vector2i{4}}}; + fb.attachTexture(Framebuffer::ColorAttachment{0}, storage, 0); + + CubeMapTexture texture; + fb.copyImage(Range2Di::fromSize(Vector2i{1}, Vector2i{2}), texture, CubeMapCoordinate::PositiveX, 0, + #ifndef MAGNUM_TARGET_GLES2 + TextureFormat::RGBA8 + #else + rgbaFormatES2 + #endif + ); + + MAGNUM_VERIFY_NO_ERROR(); + + #ifndef MAGNUM_TARGET_GLES + CORRADE_COMPARE(texture.imageSize(0), Vector2i{2}); + CORRADE_COMPARE_AS(texture.image(CubeMapCoordinate::PositiveX, 0, {PixelFormat::RGBA, PixelType::UnsignedByte}).release(), + Containers::Array::from(0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, + 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b), + TestSuite::Compare::Container); + #endif +} + +#ifndef MAGNUM_TARGET_GLES +void FramebufferGLTest::copySubImageTexture1D() { + if(!Context::current().isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::framebuffer_object::string() + std::string(" is not available.")); + + Texture2D storage; + storage.setStorage(1, TextureFormat::RGBA8, Vector2i{4}) + .setSubImage(0, {}, ImageView2D{PixelFormat::RGBA, PixelType::UnsignedByte, Vector2i{4}, StorageData}); + + Framebuffer fb{{{}, Vector2i{4}}}; + fb.attachTexture(Framebuffer::ColorAttachment{0}, storage, 0); + + Texture1D texture; + texture.setStorage(1, TextureFormat::RGBA8, 4) + .setSubImage(0, {}, ImageView1D{PixelFormat::RGBA, PixelType::UnsignedByte, 4, ZeroStorage}); + fb.copySubImage(Range2Di::fromSize(Vector2i{1}, {2, 1}), texture, 0, 1); + + MAGNUM_VERIFY_NO_ERROR(); + + CORRADE_COMPARE_AS(texture.image(0, {PixelFormat::RGBA, PixelType::UnsignedByte}).release(), + Containers::Array::from( + 0x00, 0x00, 0x00, 0x00, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x00, 0x00, 0x00, 0x00), + TestSuite::Compare::Container); +} +#endif + +void FramebufferGLTest::copySubImageTexture2D() { + #ifndef MAGNUM_TARGET_GLES + if(!Context::current().isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::framebuffer_object::string() + std::string(" is not available.")); + #endif + + Texture2D storage; + storage.setStorage(1, + #ifndef MAGNUM_TARGET_GLES2 + TextureFormat::RGBA8, + #else + rgbaFormatES2, + #endif + Vector2i{4}) + .setSubImage(0, {}, ImageView2D{PixelFormat::RGBA, PixelType::UnsignedByte, Vector2i{4}, StorageData}); + + Framebuffer fb{{{}, Vector2i{4}}}; + fb.attachTexture(Framebuffer::ColorAttachment{0}, storage, 0); + + Texture2D texture; + texture.setStorage(1, + #ifndef MAGNUM_TARGET_GLES2 + TextureFormat::RGBA8, + #else + rgbaFormatES2, + #endif + Vector2i{4}) + .setSubImage(0, {}, ImageView2D{PixelFormat::RGBA, PixelType::UnsignedByte, Vector2i{4}, ZeroStorage}); + fb.copySubImage(Range2Di::fromSize(Vector2i{1}, Vector2i{2}), texture, 0, Vector2i{1}); + + MAGNUM_VERIFY_NO_ERROR(); + + #ifndef MAGNUM_TARGET_GLES + CORRADE_COMPARE_AS(texture.image(0, {PixelFormat::RGBA, PixelType::UnsignedByte}).release(), + Containers::Array::from( + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), + TestSuite::Compare::Container); + #endif +} + +#if !(defined(MAGNUM_TARGET_GLES2) && defined(MAGNUM_TARGET_WEBGL)) +void FramebufferGLTest::copySubImageTexture3D() { + #ifndef MAGNUM_TARGET_GLES + if(!Context::current().isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::framebuffer_object::string() + std::string(" is not available.")); + #elif defined(MAGNUM_TARGET_GLES2) + if(!Context::current().isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::OES::texture_3D::string() + std::string(" is not available.")); + #endif + + Texture2D storage; + storage.setStorage(1, + #ifndef MAGNUM_TARGET_GLES2 + TextureFormat::RGBA8, + #else + rgbaFormatES2, + #endif + Vector2i{4}) + .setSubImage(0, {}, ImageView2D{PixelFormat::RGBA, PixelType::UnsignedByte, Vector2i{4}, StorageData}); + + Framebuffer fb{{{}, Vector2i{4}}}; + fb.attachTexture(Framebuffer::ColorAttachment{0}, storage, 0); + + Texture3D texture; + texture.setStorage(1, + #ifndef MAGNUM_TARGET_GLES2 + TextureFormat::RGBA8, + #else + rgbaFormatES2, + #endif + {4, 4, 2}) + .setSubImage(0, {}, ImageView3D{PixelFormat::RGBA, PixelType::UnsignedByte, {4, 4, 2}, ZeroStorage}); + fb.copySubImage(Range2Di::fromSize(Vector2i{1}, Vector2i{2}), texture, 0, Vector3i{1}); + + MAGNUM_VERIFY_NO_ERROR(); + + #ifndef MAGNUM_TARGET_GLES + CORRADE_COMPARE_AS(texture.image(0, {PixelFormat::RGBA, PixelType::UnsignedByte}).release(), + Containers::Array::from( + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), + TestSuite::Compare::Container); + #endif +} +#endif + +#ifndef MAGNUM_TARGET_GLES +void FramebufferGLTest::copySubImageTexture1DArray() { + if(!Context::current().isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::framebuffer_object::string() + std::string(" is not available.")); + if(!Context::current().isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::EXT::texture_array::string() + std::string(" is not available.")); + + Texture2D storage; + storage.setStorage(1, TextureFormat::RGBA8, Vector2i{4}) + .setSubImage(0, {}, ImageView2D{PixelFormat::RGBA, PixelType::UnsignedByte, Vector2i{4}, StorageData}); + + Framebuffer fb{{{}, Vector2i{4}}}; + fb.attachTexture(Framebuffer::ColorAttachment{0}, storage, 0); + + Texture1DArray texture; + texture.setStorage(1, TextureFormat::RGBA8, Vector2i{4}) + .setSubImage(0, {}, ImageView2D{PixelFormat::RGBA, PixelType::UnsignedByte, Vector2i{4}, ZeroStorage}); + fb.copySubImage(Range2Di::fromSize(Vector2i{1}, Vector2i{2}), texture, 0, Vector2i{1}); + + MAGNUM_VERIFY_NO_ERROR(); + + CORRADE_COMPARE_AS(texture.image(0, {PixelFormat::RGBA, PixelType::UnsignedByte}).release(), + Containers::Array::from( + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), + TestSuite::Compare::Container); +} +#endif + +#ifndef MAGNUM_TARGET_GLES2 +void FramebufferGLTest::copySubImageTexture2DArray() { + #ifndef MAGNUM_TARGET_GLES + if(!Context::current().isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::framebuffer_object::string() + std::string(" is not available.")); + if(!Context::current().isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::EXT::texture_array::string() + std::string(" is not available.")); + #endif + + Texture2D storage; + storage.setStorage(1, TextureFormat::RGBA8, Vector2i{4}) + .setSubImage(0, {}, ImageView2D{PixelFormat::RGBA, PixelType::UnsignedByte, Vector2i{4}, StorageData}); + + Framebuffer fb{{{}, Vector2i{4}}}; + fb.attachTexture(Framebuffer::ColorAttachment{0}, storage, 0); + + Texture2DArray texture; + texture.setStorage(1, TextureFormat::RGBA8, {4, 4, 2}) + .setSubImage(0, {}, ImageView3D{PixelFormat::RGBA, PixelType::UnsignedByte, {4, 4, 2}, ZeroStorage}); + fb.copySubImage(Range2Di::fromSize(Vector2i{1}, Vector2i{2}), texture, 0, Vector3i{1}); + + MAGNUM_VERIFY_NO_ERROR(); + + #ifndef MAGNUM_TARGET_GLES + CORRADE_COMPARE_AS(texture.image(0, {PixelFormat::RGBA, PixelType::UnsignedByte}).release(), + Containers::Array::from( + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), + TestSuite::Compare::Container); + #endif +} +#endif + +#ifndef MAGNUM_TARGET_GLES +void FramebufferGLTest::copySubImageRectangleTexture() { + if(!Context::current().isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::framebuffer_object::string() + std::string(" is not available.")); + if(!Context::current().isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::texture_rectangle::string() + std::string(" is not available.")); + + Texture2D storage; + storage.setStorage(1, TextureFormat::RGBA8, Vector2i{4}) + .setSubImage(0, {}, ImageView2D{PixelFormat::RGBA, PixelType::UnsignedByte, Vector2i{4}, StorageData}); + + Framebuffer fb{{{}, Vector2i{4}}}; + fb.attachTexture(Framebuffer::ColorAttachment{0}, storage, 0); + + RectangleTexture texture; + texture.setStorage(TextureFormat::RGBA8, Vector2i{4}) + .setSubImage({}, ImageView2D{PixelFormat::RGBA, PixelType::UnsignedByte, Vector2i{4}, ZeroStorage}); + fb.copySubImage(Range2Di::fromSize(Vector2i{1}, Vector2i{2}), texture, Vector2i{1}); + + MAGNUM_VERIFY_NO_ERROR(); + + CORRADE_COMPARE_AS(texture.image({PixelFormat::RGBA, PixelType::UnsignedByte}).release(), + Containers::Array::from( + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), + TestSuite::Compare::Container); +} +#endif + +void FramebufferGLTest::copySubImageCubeMapTexture() { + #ifndef MAGNUM_TARGET_GLES + if(!Context::current().isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::framebuffer_object::string() + std::string(" is not available.")); + #endif + + Texture2D storage; + storage.setStorage(1, + #ifndef MAGNUM_TARGET_GLES2 + TextureFormat::RGBA8, + #else + rgbaFormatES2, + #endif + Vector2i{4}) + .setSubImage(0, {}, ImageView2D{PixelFormat::RGBA, PixelType::UnsignedByte, Vector2i{4}, StorageData}); + + Framebuffer fb{{{}, Vector2i{4}}}; + fb.attachTexture(Framebuffer::ColorAttachment{0}, storage, 0); + + CubeMapTexture texture; + texture.setStorage(1, + #ifndef MAGNUM_TARGET_GLES2 + TextureFormat::RGBA8, + #else + rgbaFormatES2, + #endif + Vector2i{4}) + .setSubImage(CubeMapCoordinate::NegativeY, 0, {}, ImageView2D{PixelFormat::RGBA, PixelType::UnsignedByte, Vector2i{4}, ZeroStorage}); + fb.copySubImage(Range2Di::fromSize(Vector2i{1}, Vector2i{2}), texture, 0, {1, 1, 3}); + + MAGNUM_VERIFY_NO_ERROR(); + + #ifndef MAGNUM_TARGET_GLES + CORRADE_COMPARE_AS(texture.image(CubeMapCoordinate::NegativeY, 0, {PixelFormat::RGBA, PixelType::UnsignedByte}).release(), + Containers::Array::from( + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), + TestSuite::Compare::Container); + #endif +} + +#if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) +void FramebufferGLTest::copySubImageCubeMapTextureArray() { + #ifndef MAGNUM_TARGET_GLES + if(!Context::current().isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::framebuffer_object::string() + std::string(" is not available.")); + if(!Context::current().isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::texture_cube_map_array::string() + std::string(" is not available.")); + #else + if(!Context::current().isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::EXT::texture_cube_map_array::string() + std::string(" is not available.")); + #endif + + Texture2D storage; + storage.setStorage(1, TextureFormat::RGBA8, Vector2i{4}) + .setSubImage(0, {}, ImageView2D{PixelFormat::RGBA, PixelType::UnsignedByte, Vector2i{4}, StorageData}); + + Framebuffer fb{{{}, Vector2i{4}}}; + fb.attachTexture(Framebuffer::ColorAttachment{0}, storage, 0); + + CubeMapTextureArray texture; + texture.setStorage(1, TextureFormat::RGBA8, {4, 4, 6}) + .setSubImage(0, {}, ImageView3D{PixelFormat::RGBA, PixelType::UnsignedByte, {4, 4, 6}, ZeroStorage}); + fb.copySubImage(Range2Di::fromSize(Vector2i{1}, Vector2i{2}), texture, 0, {1, 1, 3}); + + MAGNUM_VERIFY_NO_ERROR(); + + #ifndef MAGNUM_TARGET_GLES + CORRADE_COMPARE_AS(texture.image(0, {PixelFormat::RGBA, PixelType::UnsignedByte}).release(), + Containers::Array::from( + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), + TestSuite::Compare::Container); + #endif +} +#endif + void FramebufferGLTest::blit() { #ifndef MAGNUM_TARGET_GLES if(!Context::current().isExtensionSupported()) diff --git a/src/Magnum/Texture.h b/src/Magnum/Texture.h index d33498c42..60fceade3 100644 --- a/src/Magnum/Texture.h +++ b/src/Magnum/Texture.h @@ -1014,9 +1014,9 @@ template class Texture: public AbstractTexture { * and has better performance characteristics. This call also has no * equivalent in @extension{ARB,direct_state_access}, thus the texture * needs to be bound to some texture unit before the operation. - * @see @ref maxSize(), @fn_gl{PixelStore}, then @fn_gl{ActiveTexture}, - * @fn_gl{BindTexture} and @fn_gl{TexImage1D} / @fn_gl{TexImage2D} - * / @fn_gl{TexImage3D} + * @see @ref maxSize(), @ref Framebuffer::copyImage(), @fn_gl{PixelStore}, + * then @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and @fn_gl{TexImage1D} + * / @fn_gl{TexImage2D} / @fn_gl{TexImage3D} * @deprecated_gl Prefer to use @ref setStorage() and @ref setSubImage() * instead. */ @@ -1115,7 +1115,8 @@ template class Texture: public AbstractTexture { * nor @extension{EXT,direct_state_access} desktop extension is * available, the texture is bound before the operation (if not * already). - * @see @ref setStorage(), @fn_gl{PixelStore}, @fn_gl2{TextureSubImage1D,TexSubImage1D} / + * @see @ref setStorage(), @ref Framebuffer::copySubImage(), + * @fn_gl{PixelStore}, @fn_gl2{TextureSubImage1D,TexSubImage1D} / * @fn_gl2{TextureSubImage2D,TexSubImage2D} / @fn_gl2{TextureSubImage3D,TexSubImage3D}, * @fn_gl_extension{TextureSubImage1D,EXT,direct_state_access} / * @fn_gl_extension{TextureSubImage2D,EXT,direct_state_access} /