[Libreoffice-commits] online.git: Branch 'libreoffice-5-3' - common/Png.hpp kit/Kit.cpp
Michael Meeks
michael.meeks at collabora.com
Tue Mar 14 17:01:34 UTC 2017
common/Png.hpp | 20 +++++++++
kit/Kit.cpp | 117 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 135 insertions(+), 2 deletions(-)
New commits:
commit 71368bfd58e00fc2c33c7dfd9651c4c838e6c1d7
Author: Michael Meeks <michael.meeks at collabora.com>
Date: Mon Nov 21 11:42:01 2016 +0000
tdf#106273 Avoid PNG compression for un-changed tiles.
Change-Id: I563ce95663929a4be83d93c06a064d5baffd603e
Reviewed-on: https://gerrit.libreoffice.org/34787
Reviewed-by: Michael Meeks <michael.meeks at collabora.com>
Reviewed-by: Thorsten Behrens <Thorsten.Behrens at CIB.de>
Tested-by: Thorsten Behrens <Thorsten.Behrens at CIB.de>
diff --git a/common/Png.hpp b/common/Png.hpp
index cb05654..eb18aa9 100644
--- a/common/Png.hpp
+++ b/common/Png.hpp
@@ -157,6 +157,26 @@ bool encodeBufferToPNG(unsigned char* pixmap, int width, int height,
return encodeSubBufferToPNG(pixmap, 0, 0, width, height, width, height, output, mode);
}
+inline
+uint64_t hashSubBuffer(unsigned char* pixmap, size_t startX, size_t startY,
+ int width, int height, int bufferWidth, int bufferHeight)
+{
+ if (bufferWidth < width || bufferHeight < height)
+ return 0; // magic invalid hash.
+
+ // assume a consistent mode - RGBA vs. BGRA for process
+ uint64_t nHash = 1073741789;
+ for (int y = 0; y < height; ++y)
+ {
+ size_t position = ((startY + y) * bufferWidth * 4) + (startX * 4);
+ uint32_t *rgba = reinterpret_cast<uint32_t *>(pixmap + position);
+ // Lameness for now.
+ for (int x = 0; x < width; ++x)
+ nHash = (nHash << 7) + rgba[x] - nHash;
+ }
+ return nHash;
+}
+
static
void readTileData(png_structp png_ptr, png_bytep data, png_size_t length)
{
diff --git a/kit/Kit.cpp b/kit/Kit.cpp
index 255e473..15fd559 100644
--- a/kit/Kit.cpp
+++ b/kit/Kit.cpp
@@ -261,6 +261,118 @@ namespace
#endif
}
+/// A quick & dirty cache of the last few PNGs
+/// and their hashes to avoid re-compression
+/// wherever possible.
+class PngCache
+{
+ typedef std::shared_ptr< std::vector< char > > CacheData;
+ struct CacheEntry {
+ size_t _hitCount;
+ CacheData _data;
+ CacheEntry(size_t defaultSize) :
+ _hitCount(0),
+ _data( new std::vector< char >() )
+ {
+ _data->reserve( defaultSize );
+ }
+ } ;
+ size_t _cacheSize;
+ std::map< uint64_t, CacheEntry > _cache;
+
+ void balanceCache()
+ {
+ // A normalish PNG image size for text in a writer document is
+ // around 4k for a content tile, and sub 1k for a background one.
+ if (_cacheSize > (1024 * 4 * 32) /* 128k of cache */)
+ {
+ size_t avgHits = 0;
+ for (auto it = _cache.begin(); it != _cache.end(); ++it)
+ avgHits += it->second._hitCount;
+
+ LOG_DBG("cache " << _cache.size() << " items total size " <<
+ _cacheSize << " total hits " << avgHits << " at balance start");
+ avgHits /= _cache.size();
+
+ for (auto it = _cache.begin(); it != _cache.end();)
+ {
+ if (it->second._hitCount <= avgHits)
+ {
+ _cacheSize -= it->second._data->size();
+ _cache.erase(it++);
+ }
+ else
+ {
+ it->second._hitCount /= 2;
+ ++it;
+ }
+ }
+
+ LOG_DBG("cache " << _cache.size() << " items total size " <<
+ _cacheSize << " after balance");
+ }
+ }
+
+ bool cacheEncodeSubBufferToPNG(unsigned char* pixmap, size_t startX, size_t startY,
+ int width, int height,
+ int bufferWidth, int bufferHeight,
+ std::vector<char>& output, LibreOfficeKitTileMode mode)
+ {
+ uint64_t hash = png::hashSubBuffer(pixmap, startX, startY, width, height,
+ bufferWidth, bufferHeight);
+ if (hash) {
+ auto it = _cache.find(hash);
+ if (it != _cache.end())
+ {
+ LOG_DBG("PNG cache with hash " << hash << " hit.");
+ output.insert(output.end(),
+ it->second._data->begin(),
+ it->second._data->end());
+ it->second._hitCount++;
+ return true;
+ }
+ }
+ LOG_DBG("PNG cache with hash " << hash << " missed.");
+ CacheEntry newEntry(bufferWidth * bufferHeight * 1);
+ if (png::encodeSubBufferToPNG(pixmap, startX, startY, width, height,
+ bufferWidth, bufferHeight,
+ *newEntry._data, mode))
+ {
+ if (hash)
+ {
+ _cache.insert(std::pair< uint64_t, CacheEntry >( hash, newEntry ));
+ _cacheSize += newEntry._data->size();
+ }
+ output.insert(output.end(),
+ newEntry._data->begin(),
+ newEntry._data->end());
+ balanceCache();
+ return true;
+ }
+ else
+ return false;
+ }
+
+public:
+ PngCache() : _cacheSize(0)
+ {
+ }
+ bool encodeBufferToPNG(unsigned char* pixmap, int width, int height,
+ std::vector<char>& output, LibreOfficeKitTileMode mode)
+ {
+ return cacheEncodeSubBufferToPNG(pixmap, 0, 0, width, height,
+ width, height, output, mode);
+ }
+ bool encodeSubBufferToPNG(unsigned char* pixmap, size_t startX, size_t startY,
+ int width, int height,
+ int bufferWidth, int bufferHeight,
+ std::vector<char>& output, LibreOfficeKitTileMode mode)
+ {
+ return cacheEncodeSubBufferToPNG(pixmap, startX, startY, width, height,
+ bufferWidth, bufferHeight, output, mode);
+ }
+};
+
/// A document container.
/// Owns LOKitDocument instance and connections.
/// Manages the lifetime of a document.
@@ -499,7 +611,7 @@ public:
" ms (" << area / elapsed << " MP/s).");
const auto mode = static_cast<LibreOfficeKitTileMode>(_loKitDocument->getTileMode());
- if (!png::encodeBufferToPNG(pixmap.data(), tile.getWidth(), tile.getHeight(), output, mode))
+ if (!_pngCache.encodeBufferToPNG(pixmap.data(), tile.getWidth(), tile.getHeight(), output, mode))
{
//FIXME: Return error.
//sendTextFrame("error: cmd=tile kind=failure");
@@ -582,7 +694,7 @@ public:
const auto oldSize = output.size();
const auto pixelWidth = tileCombined.getWidth();
const auto pixelHeight = tileCombined.getHeight();
- if (!png::encodeSubBufferToPNG(pixmap.data(), positionX * pixelWidth, positionY * pixelHeight,
+ if (!_pngCache.encodeSubBufferToPNG(pixmap.data(), positionX * pixelWidth, positionY * pixelHeight,
pixelWidth, pixelHeight, pixmapWidth, pixmapHeight, output, mode))
{
//FIXME: Return error.
@@ -1256,6 +1368,7 @@ private:
std::shared_ptr<lok::Document> _loKitDocument;
std::shared_ptr<TileQueue> _tileQueue;
std::shared_ptr<LOOLWebSocket> _ws;
+ PngCache _pngCache;
// Document password provided
std::string _docPassword;
More information about the Libreoffice-commits
mailing list