mirror of https://github.com/mosra/magnum.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
488 lines
19 KiB
488 lines
19 KiB
#ifndef Magnum_PixelStorage_h |
|
#define Magnum_PixelStorage_h |
|
/* |
|
This file is part of Magnum. |
|
|
|
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017 |
|
Vladimír Vondruš <mosra@centrum.cz> |
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a |
|
copy of this software and associated documentation files (the "Software"), |
|
to deal in the Software without restriction, including without limitation |
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
|
and/or sell copies of the Software, and to permit persons to whom the |
|
Software is furnished to do so, subject to the following conditions: |
|
|
|
The above copyright notice and this permission notice shall be included |
|
in all copies or substantial portions of the Software. |
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
|
DEALINGS IN THE SOFTWARE. |
|
*/ |
|
|
|
/** @file |
|
* @brief Class @ref Magnum::PixelStorage, @ref Magnum::CompressedPixelStorage |
|
*/ |
|
|
|
#include <cstddef> |
|
#include <tuple> |
|
|
|
#include "Magnum/Magnum.h" |
|
#include "Magnum/visibility.h" |
|
#include "Magnum/Math/Vector3.h" |
|
|
|
namespace Magnum { |
|
|
|
namespace Implementation { struct RendererState; } |
|
|
|
/** |
|
@brief Pixel storage parameters |
|
|
|
Descibes how to interpret data which are read from or stored into @ref Image, |
|
@ref ImageView, @ref BufferImage and @ref Trade::ImageData using |
|
@ref Texture::setImage() "*Texture::setImage()", @ref Texture::setSubImage() "*Texture::setSubImage()", |
|
@ref Texture::image() "*Texture::image()", @ref Texture::subImage() "*Texture::subImage()" |
|
and @ref AbstractFramebuffer::read() "*Framebuffer::read()". |
|
|
|
## Performance optimizations |
|
|
|
The storage mode is applied either right before doing image upload using |
|
@fn_gl{PixelStore} with @def_gl{UNPACK_*} parameters or right before doing |
|
image download using @fn_gl{PixelStore} with @def_gl{PACK_*}. The engine tracks |
|
currently used pixel pack/unpack parameters to avoid unnecessary calls to |
|
@fn_gl{PixelStore}. See also @ref Context::resetState() and |
|
@ref Context::State::PixelStorage. |
|
|
|
@see @ref CompressedPixelStorage |
|
*/ |
|
class MAGNUM_EXPORT PixelStorage { |
|
friend AbstractFramebuffer; |
|
friend AbstractTexture; |
|
friend CubeMapTexture; |
|
|
|
public: |
|
/** |
|
* @brief Pixel size for given format/type combination (in bytes) |
|
* |
|
* @see @ref dataProperties() |
|
*/ |
|
static std::size_t pixelSize(PixelFormat format, PixelType type); |
|
|
|
/** |
|
* @brief Default constructor |
|
* |
|
* Sets all parameters to default values, i.e. all values set to |
|
* `false`/`0` except for alignment, which is `4`. |
|
*/ |
|
constexpr /*implicit*/ PixelStorage() noexcept; |
|
|
|
/** @brief Equality comparison */ |
|
bool operator==(const PixelStorage& other) const; |
|
|
|
/** @brief Non-equality comparison */ |
|
bool operator!=(const PixelStorage& other) const { |
|
return !operator==(other); |
|
} |
|
|
|
#ifndef MAGNUM_TARGET_GLES |
|
/** |
|
* @brief Whether to reverse byte order |
|
* |
|
* @requires_gl Not available in OpenGL ES or WebGL. |
|
*/ |
|
constexpr bool swapBytes() const { return _swapBytes; } |
|
|
|
/** |
|
* @brief Enable or disable byte order reversion |
|
* |
|
* Not applicable for @ref CompressedPixelStorage. Default is `false`. |
|
* @see @fn_gl{PixelStore} with @def_gl{PACK_SWAP_BYTES}/ |
|
* @def_gl{UNPACK_SWAP_BYTES} |
|
* @requires_gl Not available in OpenGL ES or WebGL. |
|
*/ |
|
PixelStorage& setSwapBytes(bool enabled) { |
|
_swapBytes = enabled; |
|
return *this; |
|
} |
|
#endif |
|
|
|
/** @brief Row alignment */ |
|
constexpr Int alignment() const { return _alignment; } |
|
|
|
/** |
|
* @brief Set row alignment |
|
* |
|
* Not applicable for @ref CompressedPixelStorage. Valid values are |
|
* `1`, `2`, `4` and `8`. Default is `4`. |
|
* @see @fn_gl{PixelStore} with @def_gl{PACK_ALIGNMENT}/ |
|
* @def_gl{UNPACK_ALIGNMENT} |
|
*/ |
|
PixelStorage& setAlignment(Int alignment) { |
|
_alignment = alignment; |
|
return *this; |
|
} |
|
|
|
#if !(defined(MAGNUM_TARGET_GLES2) && defined(MAGNUM_TARGET_WEBGL)) |
|
/** |
|
* @brief Row length |
|
* |
|
* @requires_gles30 Extension @extension{EXT,unpack_subimage}/ |
|
* @extension{NV,pack_subimage} in OpenGL ES 2.0. |
|
* @requires_webgl20 Row length specification is not available in WebGL |
|
* 1.0. |
|
*/ |
|
constexpr Int rowLength() const { return _rowLength; } |
|
|
|
/** |
|
* @brief Set row length |
|
* |
|
* Used only on 2D and 3D images. If set to `0`, size information from |
|
* actual image is used. Default is `0`. |
|
* @see @fn_gl{PixelStore} with @def_gl{UNPACK_ROW_LENGTH}/ |
|
* @def_gl{PACK_ROW_LENGTH} |
|
* @requires_gles30 Extension @extension{EXT,unpack_subimage}/ |
|
* @extension{NV,pack_subimage} in OpenGL ES 2.0. |
|
* @requires_webgl20 Row length specification is not available in WebGL |
|
* 1.0. |
|
*/ |
|
PixelStorage& setRowLength(Int length) { |
|
_rowLength = length; |
|
return *this; |
|
} |
|
#endif |
|
|
|
#ifndef MAGNUM_TARGET_GLES2 |
|
/** |
|
* @brief Image height |
|
* |
|
* @requires_gles30 Image height specification is not available in |
|
* OpenGL ES 2.0 |
|
* @requires_webgl20 Image height specification is not available in |
|
* WebGL 1.0. |
|
*/ |
|
constexpr Int imageHeight() const { return _imageHeight; } |
|
|
|
/** |
|
* @brief Set image height |
|
* |
|
* Used only on 3D images. If set to `0`, size information from actual |
|
* image is used. Default is `0`. |
|
* @see @fn_gl{PixelStore} with @def_gl{UNPACK_IMAGE_HEIGHT}/ |
|
* @def_gl{PACK_IMAGE_HEIGHT} |
|
* @requires_gles30 Image height specification is not available in |
|
* OpenGL ES 2.0 |
|
* @requires_webgl20 Image height specification is not available in |
|
* WebGL 1.0. |
|
* @requires_gl Image height specification is available only for unpack |
|
* in OpenGL ES and WebGL. |
|
*/ |
|
PixelStorage& setImageHeight(Int height) { |
|
_imageHeight = height; |
|
return *this; |
|
} |
|
#endif |
|
|
|
/** @brief Pixel, row and image skipping */ |
|
constexpr Vector3i skip() const { return _skip; } |
|
|
|
/** |
|
* @brief Set pixel, row and image skipping |
|
* |
|
* The Y value is used only for 2D and 3D images, the Z value is used |
|
* only for 3D images. Default is `0`. On OpenGL ES 2.0 and WebGL 1.0 |
|
* the functionality is emulated by increasing the data pointer. |
|
* @see @fn_gl{PixelStore} with @def_gl{UNPACK_SKIP_PIXELS}/ |
|
* @def_gl{PACK_SKIP_PIXELS}, @def_gl{UNPACK_SKIP_ROWS}/ |
|
* @def_gl{PACK_SKIP_ROWS}, @def_gl{UNPACK_SKIP_IMAGES}/ |
|
* @def_gl{PACK_SKIP_IMAGES} |
|
* @requires_gl Image skip specification is available only for unpack |
|
* in OpenGL ES and WebGL. |
|
*/ |
|
PixelStorage& setSkip(const Vector3i& skip) { |
|
_skip = skip; |
|
return *this; |
|
} |
|
|
|
/** |
|
* @brief Data properties for given parameters |
|
* |
|
* Returns byte offset in each direction, (row length, row count, layer |
|
* count) and pixel size for image of given @p size with current pixel |
|
* storage parameters, @p format and @p type. The offset reflects the |
|
* @ref skip() parameter. Sum of the byte offset vector gives the |
|
* byte offset of first pixel in the data array. |
|
* @see @ref pixelSize() |
|
*/ |
|
std::tuple<Math::Vector3<std::size_t>, Math::Vector3<std::size_t>, std::size_t> dataProperties(PixelFormat format, PixelType type, const Vector3i& size) const; |
|
|
|
#ifndef DOXYGEN_GENERATING_OUTPUT |
|
protected: |
|
#else |
|
private: |
|
#endif |
|
/* Bool parameter is ugly, but this is implementation detail of |
|
internal API so who cares */ |
|
void MAGNUM_LOCAL applyInternal(bool isUnpack); |
|
|
|
#if !(defined(MAGNUM_TARGET_GLES2) && defined(MAGNUM_TARGET_WEBGL)) |
|
Int _rowLength; |
|
#endif |
|
#ifndef MAGNUM_TARGET_GLES2 |
|
Int _imageHeight; |
|
#endif |
|
Vector3i _skip; |
|
|
|
private: |
|
/* Used internally in *Texture::image(), *Texture::subImage(), |
|
*Texture::setImage(), *Texture::setSubImage() and |
|
*Framebuffer::read() */ |
|
void MAGNUM_LOCAL applyUnpack(); |
|
void MAGNUM_LOCAL applyPack() { applyInternal(false); } |
|
|
|
#ifndef MAGNUM_TARGET_GLES |
|
bool _swapBytes; |
|
#endif |
|
Int _alignment; |
|
}; |
|
|
|
#ifndef MAGNUM_TARGET_GLES |
|
/** |
|
@brief Compressed pixel storage parameters |
|
|
|
Descibes how to interpret data which are read from or stored into |
|
@ref CompressedImage, @ref CompressedImageView, @ref CompressedBufferImage and |
|
@ref Trade::ImageData using @ref Texture::setCompressedImage() "*Texture::setCompressedImage(), |
|
@ref Texture::setCompressedSubImage() "*Texture::setCompressedSubImage()", |
|
@ref Texture::compressedImage() "*Texture::compressedImage()" and |
|
@ref Texture::compressedSubImage() "*Texture::compressedSubImage()". |
|
|
|
Includes all parameters from @ref PixelStorage, except for @ref swapBytes() and |
|
@ref alignment(), which are ignored for compressed images. |
|
|
|
@requires_gl42 Extension @extension{ARB,compressed_texture_pixel_storage} |
|
@requires_gl Compressed pixel storage is hardcoded in OpenGL ES and WebGL. |
|
*/ |
|
class MAGNUM_EXPORT CompressedPixelStorage: public PixelStorage { |
|
friend AbstractTexture; |
|
friend CubeMapTexture; |
|
|
|
public: |
|
/** |
|
* @brief Default constructor |
|
* |
|
* Sets all parameters to default values, i.e. all values set to |
|
* `false`/`0` except for alignment, which is `4`. |
|
*/ |
|
#ifndef CORRADE_MSVC2015_COMPATIBILITY /* What am I doing wrong? */ |
|
constexpr |
|
#endif |
|
/*implicit*/ CompressedPixelStorage() noexcept: _blockSize{0}, _blockDataSize{0} {} |
|
|
|
/** @brief Equality comparison */ |
|
bool operator==(const CompressedPixelStorage& other) const; |
|
|
|
/** @brief Non-equality comparison */ |
|
bool operator!=(const CompressedPixelStorage& other) const { |
|
return !operator==(other); |
|
} |
|
|
|
/** @brief Compressed block size */ |
|
constexpr Vector3i compressedBlockSize() const { return _blockSize; } |
|
|
|
/** |
|
* @brief Set compressed block size |
|
* |
|
* If set to `0` for given dimension, size information from particular |
|
* compressed format is used. Default is `0` in all dimensions. |
|
*/ |
|
CompressedPixelStorage& setCompressedBlockSize(const Vector3i& size) { |
|
_blockSize = size; |
|
return *this; |
|
} |
|
|
|
/** @brief Compressed block data size (in bytes) */ |
|
constexpr Int compressedBlockDataSize() const { return _blockDataSize; } |
|
|
|
/** |
|
* @brief Set compressed block data size (in bytes) |
|
* |
|
* If set to `0`, size information from particular compressed format is |
|
* used. Default is `0` in all dimensions. |
|
*/ |
|
CompressedPixelStorage& setCompressedBlockDataSize(Int size) { |
|
_blockDataSize = size; |
|
return *this; |
|
} |
|
|
|
/** |
|
* @brief Data properties for given parameters |
|
* |
|
* Returns byte offset in each dimension, count of blocks in each |
|
* dimension and block data size for image of given @p size with |
|
* current pixel storage parameters. Adding byte offset and product of |
|
* the vector multiplied with block data size gives minimal byte count |
|
* to store given data. |
|
* |
|
* Expects @ref compressedBlockSize() and @ref compressedBlockDataSize() |
|
* to be non-zero. |
|
*/ |
|
std::tuple<Math::Vector3<std::size_t>, Math::Vector3<std::size_t>, std::size_t> dataProperties(const Vector3i& size) const; |
|
|
|
/* Overloads to remove WTF-factor from method chaining order */ |
|
#ifndef DOXYGEN_GENERATING_OUTPUT |
|
CompressedPixelStorage& setRowLength(Int length) { |
|
PixelStorage::setRowLength(length); |
|
return *this; |
|
} |
|
CompressedPixelStorage& setImageHeight(Int height) { |
|
PixelStorage::setImageHeight(height); |
|
return *this; |
|
} |
|
CompressedPixelStorage& setSkip(const Vector3i& skip) { |
|
PixelStorage::setSkip(skip); |
|
return *this; |
|
} |
|
#endif |
|
|
|
private: |
|
#ifndef MAGNUM_TARGET_GLES |
|
using PixelStorage::swapBytes; |
|
using PixelStorage::setSwapBytes; |
|
#endif |
|
using PixelStorage::alignment; |
|
using PixelStorage::setAlignment; |
|
|
|
/* Bool parameter is ugly, but this is implementation detail of |
|
internal API so who cares */ |
|
void MAGNUM_LOCAL applyInternal(bool isUnpack); |
|
|
|
/* Used internally in *Texture::compressedImage(), *Texture::compressedSubImage(), |
|
*Texture::setCompressedImage() and *Texture::setCompressedSubImage() */ |
|
void MAGNUM_LOCAL applyUnpack() { applyInternal(true); } |
|
void MAGNUM_LOCAL applyPack() { applyInternal(false); } |
|
|
|
Vector3i _blockSize; |
|
Int _blockDataSize; |
|
}; |
|
#endif |
|
|
|
constexpr PixelStorage::PixelStorage() noexcept: |
|
#if !(defined(MAGNUM_TARGET_GLES2) && defined(MAGNUM_TARGET_WEBGL)) |
|
_rowLength{0}, |
|
#endif |
|
#ifndef MAGNUM_TARGET_GLES2 |
|
_imageHeight{0}, |
|
#endif |
|
_skip{0}, |
|
#ifndef MAGNUM_TARGET_GLES |
|
_swapBytes{false}, |
|
#endif |
|
_alignment{4} {} |
|
|
|
namespace Implementation { |
|
/* Used in *Image::dataProperties() */ |
|
template<std::size_t dimensions, class T> std::tuple<Math::Vector<dimensions, std::size_t>, Math::Vector<dimensions, std::size_t>, std::size_t> imageDataProperties(const T& image) { |
|
Math::Vector3<std::size_t> offset, dataSize; |
|
std::size_t pixelSize; |
|
std::tie(offset, dataSize, pixelSize) = image.storage().dataProperties(image.format(), image.type(), Vector3i::pad(image.size(), 1)); |
|
return std::make_tuple(Math::Vector<dimensions, std::size_t>::pad(offset), Math::Vector<dimensions, std::size_t>::pad(dataSize), pixelSize); |
|
} |
|
|
|
#ifndef MAGNUM_TARGET_GLES2 |
|
/* Used in Compressed*Image::dataProperties() */ |
|
template<std::size_t dimensions, class T> std::tuple<Math::Vector<dimensions, std::size_t>, Math::Vector<dimensions, std::size_t>, std::size_t> compressedImageDataProperties(const T& image) { |
|
Math::Vector3<std::size_t> offset, blockCount; |
|
std::size_t blockSize; |
|
std::tie(offset, blockCount, blockSize) = image.storage().dataProperties(Vector3i::pad(image.size(), 1)); |
|
return std::make_tuple(Math::Vector<dimensions, std::size_t>::pad(offset), Math::Vector<dimensions, std::size_t>::pad(blockCount), blockSize); |
|
} |
|
#endif |
|
|
|
/* Used in image query functions */ |
|
template<std::size_t dimensions, class T> std::size_t imageDataSizeFor(const T& image, const Math::Vector<dimensions, Int>& size) { |
|
Math::Vector3<std::size_t> offset, dataSize; |
|
std::size_t pixelSize; |
|
std::tie(offset, dataSize, pixelSize) = image.storage().dataProperties(image.format(), image.type(), Vector3i::pad(size, 1)); |
|
|
|
/* Smallest line/rectangle/cube that covers the area */ |
|
std::size_t dataOffset = 0; |
|
if(offset.z()) |
|
dataOffset += offset.z(); |
|
else if(offset.y()) { |
|
#ifndef MAGNUM_TARGET_GLES2 |
|
if(!image.storage().imageHeight()) |
|
#endif |
|
{ |
|
dataOffset += offset.y(); |
|
} |
|
} else if(offset.x()) { |
|
#if !(defined(MAGNUM_TARGET_GLES2) && defined(MAGNUM_TARGET_WEBGL)) |
|
if(!image.storage().rowLength()) |
|
#endif |
|
{ |
|
dataOffset += offset.x(); |
|
} |
|
} |
|
return dataOffset + dataSize.product(); |
|
} |
|
|
|
/* Used in data size assertions */ |
|
template<class T> inline std::size_t imageDataSize(const T& image) { |
|
return imageDataSizeFor(image, image.size()); |
|
} |
|
|
|
#ifdef MAGNUM_BUILD_DEPRECATED |
|
/* Uses default pixel storage */ |
|
template<std::size_t dimensions> std::size_t imageDataSizeFor(PixelFormat format, PixelType type, const Math::Vector<dimensions, Int>& size) { |
|
return std::get<1>(PixelStorage{}.dataProperties(format, type, Vector3i::pad(size, 1))).product(); |
|
} |
|
#endif |
|
|
|
#ifndef MAGNUM_TARGET_GLES |
|
template<std::size_t dimensions, class T> std::pair<std::size_t, std::size_t> compressedImageDataOffsetSizeFor(const T& image, const Math::Vector<dimensions, Int>& size) { |
|
CORRADE_INTERNAL_ASSERT(image.storage().compressedBlockSize().product() && image.storage().compressedBlockDataSize()); |
|
|
|
Math::Vector3<std::size_t> offset, blockCount; |
|
std::size_t blockDataSize; |
|
std::tie(offset, blockCount, blockDataSize) = image.storage().dataProperties(Vector3i::pad(size, 1)); |
|
|
|
const auto realBlockCount = Math::Vector3<std::size_t>{(Vector3i::pad(size, 1) + image.storage().compressedBlockSize() - Vector3i{1})/image.storage().compressedBlockSize()}; |
|
|
|
return {offset.sum(), (blockCount.product() - (blockCount.x() - realBlockCount.x()) - (blockCount.y() - realBlockCount.y())*blockCount.x())*blockDataSize}; |
|
} |
|
|
|
/* Used in image query functions */ |
|
template<std::size_t dimensions, class T> std::size_t compressedImageDataSizeFor(const T& image, const Math::Vector<dimensions, Int>& size) { |
|
auto r = compressedImageDataOffsetSizeFor(image, size); |
|
return r.first + r.second; |
|
} |
|
|
|
/* Use in compressed image upload functions */ |
|
template<class T> std::size_t occupiedCompressedImageDataSize(const T& image, std::size_t dataSize) { |
|
return image.storage().compressedBlockSize().product() && image.storage().compressedBlockDataSize() |
|
? compressedImageDataOffsetSizeFor(image, image.size()).second : dataSize; |
|
} |
|
#else |
|
template<class T> std::size_t occupiedCompressedImageDataSize(const T&, std::size_t dataSize) { |
|
return dataSize; |
|
} |
|
#endif |
|
|
|
#ifdef MAGNUM_TARGET_GLES2 |
|
template<std::size_t dimensions, class T> std::ptrdiff_t pixelStorageSkipOffsetFor(const T& image, const Math::Vector<dimensions, Int>& size) { |
|
return std::get<0>(image.storage().dataProperties(image.format(), image.type(), Vector3i::pad(size, 1))).sum(); |
|
} |
|
template<class T> std::ptrdiff_t pixelStorageSkipOffset(const T& image) { |
|
return pixelStorageSkipOffsetFor(image, image.size()); |
|
} |
|
#endif |
|
} |
|
|
|
} |
|
|
|
#endif
|
|
|