From baa03a7b3062d3c846172f7aeb7e96af3dfb415d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Sat, 5 Sep 2015 22:28:09 +0200 Subject: [PATCH] Pixel storage support, part 8: functions to apply storage state. Not yet tested/used anywhere. --- src/Magnum/PixelStorage.cpp | 111 ++++++++++++++++++++++++++++++++++++ src/Magnum/PixelStorage.h | 51 +++++++++++++++++ 2 files changed, 162 insertions(+) diff --git a/src/Magnum/PixelStorage.cpp b/src/Magnum/PixelStorage.cpp index 9618fc368..da9d3a89b 100644 --- a/src/Magnum/PixelStorage.cpp +++ b/src/Magnum/PixelStorage.cpp @@ -27,9 +27,14 @@ #include +#include "Magnum/Context.h" +#include "Magnum/Extensions.h" #include "Magnum/PixelFormat.h" #include "Magnum/Math/Vector4.h" +#include "Implementation/RendererState.h" +#include "Implementation/State.h" + namespace Magnum { std::size_t PixelStorage::pixelSize(PixelFormat format, PixelType type) { @@ -187,4 +192,110 @@ std::tuple, std::size_t> CompressedPixel } #endif +void PixelStorage::applyInternal(const bool isUnpack) { + Implementation::RendererState::PixelStorage& state = isUnpack ? + Context::current()->state().renderer->unpackPixelStorage : + Context::current()->state().renderer->packPixelStorage; + + #ifndef MAGNUM_TARGET_GLES + /* Byte swap */ + if(state.swapBytes == std::nullopt || state.swapBytes != _swapBytes) + glPixelStorei(isUnpack ? GL_UNPACK_SWAP_BYTES : GL_PACK_SWAP_BYTES, + *(state.swapBytes = _swapBytes)); + #endif + + /* Alignment */ + if(state.alignment == Implementation::RendererState::PixelStorage::DisengagedValue || state.alignment != _alignment) + glPixelStorei(isUnpack ? GL_UNPACK_ALIGNMENT : GL_PACK_ALIGNMENT, + state.alignment = _alignment); + + /* Row length */ + #if !(defined(MAGNUM_TARGET_GLES2) && defined(MAGNUM_TARGET_WEBGL)) + if(state.rowLength == Implementation::RendererState::PixelStorage::DisengagedValue || state.rowLength != _rowLength) + { + /** @todo Use real value for GL_PACK_ROW_LENGTH_NV when it is in headers */ + #ifndef MAGNUM_TARGET_GLES2 + glPixelStorei(isUnpack ? GL_UNPACK_ROW_LENGTH : GL_PACK_ROW_LENGTH, + state.rowLength = _rowLength); + #elif !defined(MAGNUM_TARGET_WEBGL) + glPixelStorei(isUnpack ? GL_UNPACK_ROW_LENGTH_EXT : 0xD02 /*GL_PACK_ROW_LENGTH_NV*/, + state.rowLength = _rowLength); + #endif + } + #endif + + #ifndef MAGNUM_TARGET_GLES + /* Image height (on ES for unpack only, taken care of below) */ + if(state.imageHeight == Implementation::RendererState::PixelStorage::DisengagedValue || state.imageHeight != _imageHeight) + glPixelStorei(isUnpack ? GL_UNPACK_IMAGE_HEIGHT : GL_PACK_IMAGE_HEIGHT, + state.imageHeight = _imageHeight); + #endif + + /* On ES2 done by modifying data pointer */ + #ifndef MAGNUM_TARGET_GLES2 + /* Skip pixels */ + if(state.skip.x() == Implementation::RendererState::PixelStorage::DisengagedValue || state.skip.x() != _skip.x()) + glPixelStorei(isUnpack ? GL_UNPACK_SKIP_PIXELS : GL_PACK_SKIP_PIXELS, + state.skip.x() = _skip.x()); + + /* Skip rows */ + if(state.skip.y() == Implementation::RendererState::PixelStorage::DisengagedValue || state.skip.y() != _skip.y()) + glPixelStorei(isUnpack ? GL_UNPACK_SKIP_ROWS : GL_PACK_SKIP_ROWS, + state.skip.y() = _skip.y()); + + #ifndef MAGNUM_TARGET_GLES + /* Skip images (on ES for unpack only, taken care of below) */ + if(state.skip.z() == Implementation::RendererState::PixelStorage::DisengagedValue || state.skip.z() != _skip.z()) + glPixelStorei(isUnpack ? GL_UNPACK_SKIP_IMAGES : GL_PACK_SKIP_IMAGES, + state.skip.z() = _skip.z()); + #endif + #endif +} + +void PixelStorage::applyUnpack() { + applyInternal(true); + + #if defined(MAGNUM_TARGET_GLES) && !defined(MAGNUM_TARGET_GLES2) + Implementation::RendererState::PixelStorage& state = Context::current()->state().renderer->unpackPixelStorage; + + /* Image height (on ES for unpack only) */ + if(state.imageHeight == Implementation::RendererState::PixelStorage::DisengagedValue || state.imageHeight != _imageHeight) + glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, state.imageHeight = _imageHeight); + + /* Skip images (on ES for unpack only) */ + if(state.skip.z() == Implementation::RendererState::PixelStorage::DisengagedValue || state.skip.z() != _skip.z()) + glPixelStorei(GL_UNPACK_SKIP_IMAGES, state.skip.z() = _skip.z()); + #endif +} + +#ifndef MAGNUM_TARGET_GLES +void CompressedPixelStorage::applyInternal(const bool isUnpack) { + PixelStorage::applyInternal(isUnpack); + + Implementation::RendererState::PixelStorage& state = isUnpack ? + Context::current()->state().renderer->unpackPixelStorage : + Context::current()->state().renderer->packPixelStorage; + + /* Compressed block width */ + if(state.compressedBlockSize.x() == Implementation::RendererState::PixelStorage::DisengagedValue || state.compressedBlockSize.x() != _blockSize.x()) + glPixelStorei(isUnpack ? GL_UNPACK_COMPRESSED_BLOCK_WIDTH : GL_PACK_COMPRESSED_BLOCK_WIDTH, + state.compressedBlockSize.x() = _blockSize.x()); + + /* Compressed block height */ + if(state.compressedBlockSize.y() == Implementation::RendererState::PixelStorage::DisengagedValue || state.compressedBlockSize.y() != _blockSize.y()) + glPixelStorei(isUnpack ? GL_UNPACK_COMPRESSED_BLOCK_HEIGHT : GL_PACK_COMPRESSED_BLOCK_HEIGHT, + state.compressedBlockSize.y() = _blockSize.y()); + + /* Compressed block depth */ + if(state.compressedBlockSize.z() == Implementation::RendererState::PixelStorage::DisengagedValue || state.compressedBlockSize.z() != _blockSize.z()) + glPixelStorei(isUnpack ? GL_UNPACK_COMPRESSED_BLOCK_DEPTH : GL_PACK_COMPRESSED_BLOCK_DEPTH, + state.compressedBlockSize.z() = _blockSize.z()); + + /* Compressed block size */ + if(state.compressedBlockDataSize == Implementation::RendererState::PixelStorage::DisengagedValue || state.compressedBlockDataSize != _blockDataSize) + glPixelStorei(isUnpack ? GL_UNPACK_COMPRESSED_BLOCK_SIZE : GL_PACK_COMPRESSED_BLOCK_SIZE, + state.compressedBlockDataSize = _blockDataSize); +} +#endif + } diff --git a/src/Magnum/PixelStorage.h b/src/Magnum/PixelStorage.h index 9e2d1c0c5..b75bb9195 100644 --- a/src/Magnum/PixelStorage.h +++ b/src/Magnum/PixelStorage.h @@ -38,6 +38,8 @@ namespace Magnum { +namespace Implementation { struct RendererState; } + /** @brief Pixel storage parameters @@ -59,6 +61,10 @@ currently used pixel pack/unpack parameters to avoid unnecessary calls to @see @ref CompressedPixelStorage */ class MAGNUM_EXPORT PixelStorage { + friend AbstractFramebuffer; + friend AbstractTexture; + friend CubeMapTexture; + public: /** * @brief Pixel size for given format/type combination (in bytes) @@ -211,6 +217,10 @@ class MAGNUM_EXPORT PixelStorage { #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 @@ -220,6 +230,12 @@ class MAGNUM_EXPORT PixelStorage { 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 @@ -244,6 +260,9 @@ Includes all parameters from @ref PixelStorage, except for @ref swapBytes() and @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 @@ -318,6 +337,15 @@ class MAGNUM_EXPORT CompressedPixelStorage: public PixelStorage { 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; }; @@ -383,6 +411,20 @@ namespace Implementation { } #endif + /* Use in compressed image upload functions */ + #ifndef MAGNUM_TARGET_GLES + template std::size_t occupiedCompressedImageDataSize(const T& image, std::size_t dataSize) { + if(!image.storage().compressedBlockSize().product() || !image.storage().compressedBlockDataSize()) + return dataSize; + + return ((Vector3i::pad(image.size(), 1) + image.storage().compressedBlockSize() - Vector3i{1})/image.storage().compressedBlockSize()).product()*image.storage().compressedBlockDataSize(); + } + #else + template std::size_t occupiedCompressedImageDataSize(const T&, std::size_t dataSize) { + return dataSize; + } + #endif + #ifndef MAGNUM_TARGET_GLES /* Used in image query functions */ template std::size_t compressedImageDataSizeFor(const T& image, const Math::Vector& size, std::size_t dataSize) { @@ -399,6 +441,15 @@ namespace Implementation { return offset + (blockCount.product() - (blockCount.x() - realBlockCount.x()) - (blockCount.y() - realBlockCount.y())*blockCount.x())*blockDataSize; } #endif + + #ifdef MAGNUM_TARGET_GLES2 + template std::ptrdiff_t pixelStorageSkipOffsetFor(const T& image, const Math::Vector& size) { + return std::get<0>(image.storage().dataProperties(image.format(), image.type(), Vector3i::pad(size, 1))); + } + template std::ptrdiff_t pixelStorageSkipOffset(const T& image) { + return pixelStorageSkipOffsetFor(image, image.size()); + } + #endif } }