libreoffice-online/kit/Delta.hpp

557 lines
18 KiB
C++
Raw Normal View History

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include <vector>
#include <assert.h>
#include <zlib.h>
deltas: track, transmit and cache deltas (disabled for now) Squashed from feature/deltas-expanded. TileCache changes: + add montonic sequence (wid) numbers to TileData + account for sizes of TileData with multiple blobs + simplify saving and notifying of tiles Sends updates (via appendChanges) based on the sequence the right mix of keyframes and/or deltas required as a single message, and parse and apply those on the JS side. We continue to use PNG for slide previews and dialogs, but remove PngCache - used by document tiles only. Annotates delta: properly as a binary package for the websocket. Distinguishes between deltas and keyframes we get from the Kit based on an initial un-compressed prefix character which we then discard. kit can be forced to render a keyframe by oldWid=0 Track invalidity on tiles themselves - to keep the keyframe around. We need to be able to track that a tile is invalid, and so subscribe to the updated version as/when it is ready - but we also want to store the keyframe underneath any deltas. force rendering of a keyframe for an empty slot in the TileCache. force tile sequence to be zero for combinedtiles - so the client can always request standalone tiles with explicit combinedtiles, or tile requests. move Blob to Common.hpp use zero size for un-changed tiles. remove obsolete render-id, and color deltas in debug mode. cleanup unit tests for non-png tile results. Change-Id: I987f84ac4e58004758a243c233b19a6f0d60f8c2 Signed-off-by: Michael Meeks <michael.meeks@collabora.com>
2022-03-25 13:32:01 -05:00
#include <Log.hpp>
#include <Common.hpp>
#define ENABLE_DELTAS 1
#ifndef TILE_WIRE_ID
# define TILE_WIRE_ID
typedef uint32_t TileWireId;
#endif
/// A quick and dirty delta generator for last tile changes
class DeltaGenerator {
/// Bitmap row with a CRC for quick vertical shift detection
struct DeltaBitmapRow {
// FIXME: add "whole row the same" flag.
uint64_t _crc;
const uint32_t *_pixels; // FIXME: remove me.
size_t _pixSize;
bool identical(const DeltaBitmapRow &other) const
{
if (_crc != other._crc)
return false;
return !std::memcmp(_pixels, other._pixels, _pixSize * 4);
2018-11-08 02:16:50 -06:00
}
};
/// A bitmap tile with annotated rows and details on its location
struct DeltaData {
DeltaData (TileWireId wid,
unsigned char* pixmap, size_t startX, size_t startY,
int width, int height,
int tileLeft, int tileTop, int tileSize, int tilePart,
int bufferWidth, int bufferHeight
) :
deltas: track, transmit and cache deltas (disabled for now) Squashed from feature/deltas-expanded. TileCache changes: + add montonic sequence (wid) numbers to TileData + account for sizes of TileData with multiple blobs + simplify saving and notifying of tiles Sends updates (via appendChanges) based on the sequence the right mix of keyframes and/or deltas required as a single message, and parse and apply those on the JS side. We continue to use PNG for slide previews and dialogs, but remove PngCache - used by document tiles only. Annotates delta: properly as a binary package for the websocket. Distinguishes between deltas and keyframes we get from the Kit based on an initial un-compressed prefix character which we then discard. kit can be forced to render a keyframe by oldWid=0 Track invalidity on tiles themselves - to keep the keyframe around. We need to be able to track that a tile is invalid, and so subscribe to the updated version as/when it is ready - but we also want to store the keyframe underneath any deltas. force rendering of a keyframe for an empty slot in the TileCache. force tile sequence to be zero for combinedtiles - so the client can always request standalone tiles with explicit combinedtiles, or tile requests. move Blob to Common.hpp use zero size for un-changed tiles. remove obsolete render-id, and color deltas in debug mode. cleanup unit tests for non-png tile results. Change-Id: I987f84ac4e58004758a243c233b19a6f0d60f8c2 Signed-off-by: Michael Meeks <michael.meeks@collabora.com>
2022-03-25 13:32:01 -05:00
// in TWIPS
_left(tileLeft),
_top(tileTop),
deltas: track, transmit and cache deltas (disabled for now) Squashed from feature/deltas-expanded. TileCache changes: + add montonic sequence (wid) numbers to TileData + account for sizes of TileData with multiple blobs + simplify saving and notifying of tiles Sends updates (via appendChanges) based on the sequence the right mix of keyframes and/or deltas required as a single message, and parse and apply those on the JS side. We continue to use PNG for slide previews and dialogs, but remove PngCache - used by document tiles only. Annotates delta: properly as a binary package for the websocket. Distinguishes between deltas and keyframes we get from the Kit based on an initial un-compressed prefix character which we then discard. kit can be forced to render a keyframe by oldWid=0 Track invalidity on tiles themselves - to keep the keyframe around. We need to be able to track that a tile is invalid, and so subscribe to the updated version as/when it is ready - but we also want to store the keyframe underneath any deltas. force rendering of a keyframe for an empty slot in the TileCache. force tile sequence to be zero for combinedtiles - so the client can always request standalone tiles with explicit combinedtiles, or tile requests. move Blob to Common.hpp use zero size for un-changed tiles. remove obsolete render-id, and color deltas in debug mode. cleanup unit tests for non-png tile results. Change-Id: I987f84ac4e58004758a243c233b19a6f0d60f8c2 Signed-off-by: Michael Meeks <michael.meeks@collabora.com>
2022-03-25 13:32:01 -05:00
_size(tileSize),
_part(tilePart),
_wid(wid),
deltas: track, transmit and cache deltas (disabled for now) Squashed from feature/deltas-expanded. TileCache changes: + add montonic sequence (wid) numbers to TileData + account for sizes of TileData with multiple blobs + simplify saving and notifying of tiles Sends updates (via appendChanges) based on the sequence the right mix of keyframes and/or deltas required as a single message, and parse and apply those on the JS side. We continue to use PNG for slide previews and dialogs, but remove PngCache - used by document tiles only. Annotates delta: properly as a binary package for the websocket. Distinguishes between deltas and keyframes we get from the Kit based on an initial un-compressed prefix character which we then discard. kit can be forced to render a keyframe by oldWid=0 Track invalidity on tiles themselves - to keep the keyframe around. We need to be able to track that a tile is invalid, and so subscribe to the updated version as/when it is ready - but we also want to store the keyframe underneath any deltas. force rendering of a keyframe for an empty slot in the TileCache. force tile sequence to be zero for combinedtiles - so the client can always request standalone tiles with explicit combinedtiles, or tile requests. move Blob to Common.hpp use zero size for un-changed tiles. remove obsolete render-id, and color deltas in debug mode. cleanup unit tests for non-png tile results. Change-Id: I987f84ac4e58004758a243c233b19a6f0d60f8c2 Signed-off-by: Michael Meeks <michael.meeks@collabora.com>
2022-03-25 13:32:01 -05:00
// in Pixels
_width(width),
_height(height),
_rows(new DeltaBitmapRow[height])
{
assert (startX + width <= (size_t)bufferWidth);
assert (startY + height <= (size_t)bufferHeight);
(void)bufferHeight;
LOG_TRC("Converting pixel data to delta data of size "
<< (width * height * 4) << " width " << width
<< " height " << height);
_pixels = (uint32_t *)malloc((size_t)width * height * 4);
for (int y = 0; y < height; ++y)
{
DeltaBitmapRow &row = _rows[y];
size_t position = ((startY + y) * bufferWidth * 4) + (startX * 4);
uint32_t *src = reinterpret_cast<uint32_t *>(pixmap + position);
uint32_t *dest = _pixels + width * y;
// We get the hash ~for free as we copy - with a cheap hash.
uint64_t crc = 0x7fffffff - 1;
row._pixels = dest;
row._pixSize = width;
for (int x = 0; x < width; ++x)
{
crc = (crc << 7) + crc + src[x];
dest[x] = src[x];
}
row._crc = crc;
}
}
~DeltaData()
{
delete[] _rows;
if (_pixels)
free (_pixels);
}
2018-11-07 02:09:01 -06:00
void setWid(TileWireId wid)
{
_wid = wid;
}
TileWireId getWid() const
{
return _wid;
}
void setWidth(int width)
{
_width = width;
}
int getWidth() const
{
return _width;
}
void setHeight(int height)
{
_height = height;
}
int getHeight() const
{
return _height;
}
void setTilePos(int left, int top, int part)
{
_left = left;
_top = top;
_part = part;
}
const DeltaBitmapRow& getRow(int y) const
2018-11-07 02:09:01 -06:00
{
return _rows[y];
2018-11-07 02:09:01 -06:00
}
void replaceAndFree(std::shared_ptr<DeltaData> &repl)
{
deltas: track, transmit and cache deltas (disabled for now) Squashed from feature/deltas-expanded. TileCache changes: + add montonic sequence (wid) numbers to TileData + account for sizes of TileData with multiple blobs + simplify saving and notifying of tiles Sends updates (via appendChanges) based on the sequence the right mix of keyframes and/or deltas required as a single message, and parse and apply those on the JS side. We continue to use PNG for slide previews and dialogs, but remove PngCache - used by document tiles only. Annotates delta: properly as a binary package for the websocket. Distinguishes between deltas and keyframes we get from the Kit based on an initial un-compressed prefix character which we then discard. kit can be forced to render a keyframe by oldWid=0 Track invalidity on tiles themselves - to keep the keyframe around. We need to be able to track that a tile is invalid, and so subscribe to the updated version as/when it is ready - but we also want to store the keyframe underneath any deltas. force rendering of a keyframe for an empty slot in the TileCache. force tile sequence to be zero for combinedtiles - so the client can always request standalone tiles with explicit combinedtiles, or tile requests. move Blob to Common.hpp use zero size for un-changed tiles. remove obsolete render-id, and color deltas in debug mode. cleanup unit tests for non-png tile results. Change-Id: I987f84ac4e58004758a243c233b19a6f0d60f8c2 Signed-off-by: Michael Meeks <michael.meeks@collabora.com>
2022-03-25 13:32:01 -05:00
assert (_left == repl->_left && _top == repl->_top &&
_size == repl->_size && _part == repl->_part);
_wid = repl->_wid;
_width = repl->_width;
_height = repl->_height;
delete[] _rows;
_rows = repl->_rows;
repl->_rows = nullptr;
free (_pixels);
_pixels = repl->_pixels;
repl->_pixels = nullptr;
repl.reset();
}
int _left;
int _top;
deltas: track, transmit and cache deltas (disabled for now) Squashed from feature/deltas-expanded. TileCache changes: + add montonic sequence (wid) numbers to TileData + account for sizes of TileData with multiple blobs + simplify saving and notifying of tiles Sends updates (via appendChanges) based on the sequence the right mix of keyframes and/or deltas required as a single message, and parse and apply those on the JS side. We continue to use PNG for slide previews and dialogs, but remove PngCache - used by document tiles only. Annotates delta: properly as a binary package for the websocket. Distinguishes between deltas and keyframes we get from the Kit based on an initial un-compressed prefix character which we then discard. kit can be forced to render a keyframe by oldWid=0 Track invalidity on tiles themselves - to keep the keyframe around. We need to be able to track that a tile is invalid, and so subscribe to the updated version as/when it is ready - but we also want to store the keyframe underneath any deltas. force rendering of a keyframe for an empty slot in the TileCache. force tile sequence to be zero for combinedtiles - so the client can always request standalone tiles with explicit combinedtiles, or tile requests. move Blob to Common.hpp use zero size for un-changed tiles. remove obsolete render-id, and color deltas in debug mode. cleanup unit tests for non-png tile results. Change-Id: I987f84ac4e58004758a243c233b19a6f0d60f8c2 Signed-off-by: Michael Meeks <michael.meeks@collabora.com>
2022-03-25 13:32:01 -05:00
int _size;
int _part;
2018-11-07 02:09:01 -06:00
private:
TileWireId _wid;
int _width;
int _height;
uint32_t *_pixels;
DeltaBitmapRow *_rows;
};
/// The last several bitmap entries as a cache
std::vector<std::shared_ptr<DeltaData>> _deltaEntries;
// Unpremultiplies data and converts native endian ARGB => RGBA bytes
static void
unpremult_copy (unsigned char *dest, const unsigned char *srcBytes, unsigned int count)
{
const uint32_t *src = reinterpret_cast<const uint32_t *>(srcBytes);
for (unsigned int i = 0; i < count; ++i)
{
// Profile me: avoid math for runs of duplicate pixels
// possibly we should RLE earlier ?
if (i > 0 && src[i-1] == src[i])
{
dest[0] = dest[-4];
dest[1] = dest[-3];
dest[2] = dest[-2];
dest[3] = dest[-1];
dest += 4;
continue;
}
uint32_t pix;
uint8_t alpha;
std::memcpy (&pix, src + i, sizeof (uint32_t));
alpha = (pix & 0xff000000) >> 24;
if (alpha == 255)
{
dest[0] = ((pix & 0xff0000) >> 16);
dest[1] = ((pix & 0x00ff00) >> 8);
dest[2] = ((pix & 0x0000ff) >> 0);
dest[3] = 255;
}
else if (alpha == 0)
dest[0] = dest[1] = dest[2] = dest[3] = 0;
else
{
dest[0] = (((pix & 0xff0000) >> 16) * 255 + alpha / 2) / alpha;
dest[1] = (((pix & 0x00ff00) >> 8) * 255 + alpha / 2) / alpha;
dest[2] = (((pix & 0x0000ff) >> 0) * 255 + alpha / 2) / alpha;
dest[3] = alpha;
}
dest += 4;
}
}
bool makeDelta(
const DeltaData &prev,
const DeltaData &cur,
std::vector<char>& outStream)
{
// TODO: should we split and compress alpha separately ?
2018-11-07 02:09:01 -06:00
if (prev.getWidth() != cur.getWidth() || prev.getHeight() != cur.getHeight())
{
LOG_ERR("mis-sized delta: " << prev.getWidth() << 'x' << prev.getHeight() << " vs "
<< cur.getWidth() << 'x' << cur.getHeight());
return false;
}
deltas: track, transmit and cache deltas (disabled for now) Squashed from feature/deltas-expanded. TileCache changes: + add montonic sequence (wid) numbers to TileData + account for sizes of TileData with multiple blobs + simplify saving and notifying of tiles Sends updates (via appendChanges) based on the sequence the right mix of keyframes and/or deltas required as a single message, and parse and apply those on the JS side. We continue to use PNG for slide previews and dialogs, but remove PngCache - used by document tiles only. Annotates delta: properly as a binary package for the websocket. Distinguishes between deltas and keyframes we get from the Kit based on an initial un-compressed prefix character which we then discard. kit can be forced to render a keyframe by oldWid=0 Track invalidity on tiles themselves - to keep the keyframe around. We need to be able to track that a tile is invalid, and so subscribe to the updated version as/when it is ready - but we also want to store the keyframe underneath any deltas. force rendering of a keyframe for an empty slot in the TileCache. force tile sequence to be zero for combinedtiles - so the client can always request standalone tiles with explicit combinedtiles, or tile requests. move Blob to Common.hpp use zero size for un-changed tiles. remove obsolete render-id, and color deltas in debug mode. cleanup unit tests for non-png tile results. Change-Id: I987f84ac4e58004758a243c233b19a6f0d60f8c2 Signed-off-by: Michael Meeks <michael.meeks@collabora.com>
2022-03-25 13:32:01 -05:00
LOG_TRC("building delta of a " << cur.getWidth() << 'x' << cur.getHeight() << " bitmap " <<
"between old wid " << prev.getWid() << " and " << cur.getWid());
std::vector<char> output;
// guestimated upper-bound delta size
output.reserve(cur.getWidth() * (cur.getHeight() + 4) * 4);
// row move/copy src/dest is a byte.
2018-11-07 02:09:01 -06:00
assert (prev.getHeight() <= 256);
// column position is a byte.
2018-11-07 02:09:01 -06:00
assert (prev.getWidth() <= 256);
// How do the rows look against each other ?
size_t lastMatchOffset = 0;
size_t lastCopy = 0;
2018-11-07 02:09:01 -06:00
for (int y = 0; y < prev.getHeight(); ++y)
{
// Life is good where rows match:
if (prev.getRow(y).identical(cur.getRow(y)))
continue;
// Hunt for other rows
bool matched = false;
2018-11-07 02:09:01 -06:00
for (int yn = 0; yn < prev.getHeight() && !matched; ++yn)
{
2018-11-07 02:09:01 -06:00
size_t match = (y + lastMatchOffset + yn) % prev.getHeight();
if (prev.getRow(match).identical(cur.getRow(y)))
{
// TODO: if offsets are >256 - use 16bits?
if (lastCopy > 0)
{
char cnt = output[lastCopy];
if (output[lastCopy + 1] + cnt == (char)(match) &&
output[lastCopy + 2] + cnt == (char)(y))
{
output[lastCopy]++;
matched = true;
continue;
}
}
lastMatchOffset = match - y;
output.push_back('c'); // copy-row
lastCopy = output.size();
output.push_back(1); // count
output.push_back(match); // src
output.push_back(y); // dest
matched = true;
continue;
}
}
if (matched)
continue;
// Our row is just that different:
const DeltaBitmapRow &curRow = cur.getRow(y);
const DeltaBitmapRow &prevRow = prev.getRow(y);
2018-11-07 02:09:01 -06:00
for (int x = 0; x < prev.getWidth();)
{
int same;
2018-11-07 02:09:01 -06:00
for (same = 0; same + x < prev.getWidth() &&
prevRow._pixels[x+same] == curRow._pixels[x+same];)
++same;
x += same;
int diff;
2018-11-07 02:09:01 -06:00
for (diff = 0; diff + x < prev.getWidth() &&
(prevRow._pixels[x+diff] != curRow._pixels[x+diff] || diff < 3) &&
diff < 254;)
++diff;
if (diff > 0)
{
output.push_back('d');
output.push_back(y);
output.push_back(x);
output.push_back(diff);
size_t dest = output.size();
output.resize(dest + diff * 4);
unpremult_copy(reinterpret_cast<unsigned char *>(&output[dest]),
(const unsigned char *)(curRow._pixels + x),
diff);
deltas: track, transmit and cache deltas (disabled for now) Squashed from feature/deltas-expanded. TileCache changes: + add montonic sequence (wid) numbers to TileData + account for sizes of TileData with multiple blobs + simplify saving and notifying of tiles Sends updates (via appendChanges) based on the sequence the right mix of keyframes and/or deltas required as a single message, and parse and apply those on the JS side. We continue to use PNG for slide previews and dialogs, but remove PngCache - used by document tiles only. Annotates delta: properly as a binary package for the websocket. Distinguishes between deltas and keyframes we get from the Kit based on an initial un-compressed prefix character which we then discard. kit can be forced to render a keyframe by oldWid=0 Track invalidity on tiles themselves - to keep the keyframe around. We need to be able to track that a tile is invalid, and so subscribe to the updated version as/when it is ready - but we also want to store the keyframe underneath any deltas. force rendering of a keyframe for an empty slot in the TileCache. force tile sequence to be zero for combinedtiles - so the client can always request standalone tiles with explicit combinedtiles, or tile requests. move Blob to Common.hpp use zero size for un-changed tiles. remove obsolete render-id, and color deltas in debug mode. cleanup unit tests for non-png tile results. Change-Id: I987f84ac4e58004758a243c233b19a6f0d60f8c2 Signed-off-by: Michael Meeks <michael.meeks@collabora.com>
2022-03-25 13:32:01 -05:00
LOG_TRC("row " << y << " different " << diff << "pixels");
x += diff;
}
}
}
LOG_TRC("Created delta of size " << output.size());
deltas: track, transmit and cache deltas (disabled for now) Squashed from feature/deltas-expanded. TileCache changes: + add montonic sequence (wid) numbers to TileData + account for sizes of TileData with multiple blobs + simplify saving and notifying of tiles Sends updates (via appendChanges) based on the sequence the right mix of keyframes and/or deltas required as a single message, and parse and apply those on the JS side. We continue to use PNG for slide previews and dialogs, but remove PngCache - used by document tiles only. Annotates delta: properly as a binary package for the websocket. Distinguishes between deltas and keyframes we get from the Kit based on an initial un-compressed prefix character which we then discard. kit can be forced to render a keyframe by oldWid=0 Track invalidity on tiles themselves - to keep the keyframe around. We need to be able to track that a tile is invalid, and so subscribe to the updated version as/when it is ready - but we also want to store the keyframe underneath any deltas. force rendering of a keyframe for an empty slot in the TileCache. force tile sequence to be zero for combinedtiles - so the client can always request standalone tiles with explicit combinedtiles, or tile requests. move Blob to Common.hpp use zero size for un-changed tiles. remove obsolete render-id, and color deltas in debug mode. cleanup unit tests for non-png tile results. Change-Id: I987f84ac4e58004758a243c233b19a6f0d60f8c2 Signed-off-by: Michael Meeks <michael.meeks@collabora.com>
2022-03-25 13:32:01 -05:00
if (output.size() == 0)
{
// The tile content is identical to what the client already has, so skip it
LOG_TRC("Identical / un-changed tile");
// Return a zero byte image to inform WSD we didn't need that.
// This allows WSD side TileCache to free up waiting subscribers.
return true;
}
#if !ENABLE_DELTAS
return false; // Disable transmission for now; just send keyframes.
#endif
z_stream zstr;
memset((void *)&zstr, 0, sizeof (zstr));
if (deflateInit2 (&zstr, Z_DEFAULT_COMPRESSION, Z_DEFLATED,
-MAX_WBITS, 8, Z_DEFAULT_STRATEGY) != Z_OK) {
LOG_ERR("Failed to init deflate");
return false;
}
// FIXME: avoid allocation & make this more efficient.
uLong maxCompressed = compressBound(output.size());
Bytef *compressed = (Bytef *)malloc(maxCompressed);
zstr.next_in = (Bytef *)output.data();
zstr.avail_in = output.size();
zstr.next_out = compressed;
zstr.avail_out = maxCompressed;
if (!compressed || deflate(&zstr, Z_FINISH) != Z_STREAM_END) {
LOG_ERR("Failed to compress delta of size " << output.size());
return false;
}
deflateEnd(&zstr);
uLong compSize = maxCompressed - zstr.avail_out;
LOG_TRC("Compressed delta of size " << output.size() << " to size " << compSize);
// << Util::dumpHex(std::string((char *)compressed, compSize)));
// FIXME: should get zlib to drop it directly in really.
outStream.push_back('D');
size_t oldSize = outStream.size();
outStream.resize(oldSize + compSize);
memcpy(&outStream[oldSize], compressed, compSize);
free (compressed);
return true;
}
public:
DeltaGenerator() {}
/**
deltas: track, transmit and cache deltas (disabled for now) Squashed from feature/deltas-expanded. TileCache changes: + add montonic sequence (wid) numbers to TileData + account for sizes of TileData with multiple blobs + simplify saving and notifying of tiles Sends updates (via appendChanges) based on the sequence the right mix of keyframes and/or deltas required as a single message, and parse and apply those on the JS side. We continue to use PNG for slide previews and dialogs, but remove PngCache - used by document tiles only. Annotates delta: properly as a binary package for the websocket. Distinguishes between deltas and keyframes we get from the Kit based on an initial un-compressed prefix character which we then discard. kit can be forced to render a keyframe by oldWid=0 Track invalidity on tiles themselves - to keep the keyframe around. We need to be able to track that a tile is invalid, and so subscribe to the updated version as/when it is ready - but we also want to store the keyframe underneath any deltas. force rendering of a keyframe for an empty slot in the TileCache. force tile sequence to be zero for combinedtiles - so the client can always request standalone tiles with explicit combinedtiles, or tile requests. move Blob to Common.hpp use zero size for un-changed tiles. remove obsolete render-id, and color deltas in debug mode. cleanup unit tests for non-png tile results. Change-Id: I987f84ac4e58004758a243c233b19a6f0d60f8c2 Signed-off-by: Michael Meeks <michael.meeks@collabora.com>
2022-03-25 13:32:01 -05:00
* Creates a delta if possible:
* if so - returns @true and appends the delta to @output
* stores @pixmap, and other data to accelerate delta
* creation in a limited size cache.
*/
bool createDelta(
unsigned char* pixmap, size_t startX, size_t startY,
int width, int height,
int bufferWidth, int bufferHeight,
deltas: track, transmit and cache deltas (disabled for now) Squashed from feature/deltas-expanded. TileCache changes: + add montonic sequence (wid) numbers to TileData + account for sizes of TileData with multiple blobs + simplify saving and notifying of tiles Sends updates (via appendChanges) based on the sequence the right mix of keyframes and/or deltas required as a single message, and parse and apply those on the JS side. We continue to use PNG for slide previews and dialogs, but remove PngCache - used by document tiles only. Annotates delta: properly as a binary package for the websocket. Distinguishes between deltas and keyframes we get from the Kit based on an initial un-compressed prefix character which we then discard. kit can be forced to render a keyframe by oldWid=0 Track invalidity on tiles themselves - to keep the keyframe around. We need to be able to track that a tile is invalid, and so subscribe to the updated version as/when it is ready - but we also want to store the keyframe underneath any deltas. force rendering of a keyframe for an empty slot in the TileCache. force tile sequence to be zero for combinedtiles - so the client can always request standalone tiles with explicit combinedtiles, or tile requests. move Blob to Common.hpp use zero size for un-changed tiles. remove obsolete render-id, and color deltas in debug mode. cleanup unit tests for non-png tile results. Change-Id: I987f84ac4e58004758a243c233b19a6f0d60f8c2 Signed-off-by: Michael Meeks <michael.meeks@collabora.com>
2022-03-25 13:32:01 -05:00
int tileLeft, int tileTop, int tileSize, int tilePart,
std::vector<char>& output,
deltas: track, transmit and cache deltas (disabled for now) Squashed from feature/deltas-expanded. TileCache changes: + add montonic sequence (wid) numbers to TileData + account for sizes of TileData with multiple blobs + simplify saving and notifying of tiles Sends updates (via appendChanges) based on the sequence the right mix of keyframes and/or deltas required as a single message, and parse and apply those on the JS side. We continue to use PNG for slide previews and dialogs, but remove PngCache - used by document tiles only. Annotates delta: properly as a binary package for the websocket. Distinguishes between deltas and keyframes we get from the Kit based on an initial un-compressed prefix character which we then discard. kit can be forced to render a keyframe by oldWid=0 Track invalidity on tiles themselves - to keep the keyframe around. We need to be able to track that a tile is invalid, and so subscribe to the updated version as/when it is ready - but we also want to store the keyframe underneath any deltas. force rendering of a keyframe for an empty slot in the TileCache. force tile sequence to be zero for combinedtiles - so the client can always request standalone tiles with explicit combinedtiles, or tile requests. move Blob to Common.hpp use zero size for un-changed tiles. remove obsolete render-id, and color deltas in debug mode. cleanup unit tests for non-png tile results. Change-Id: I987f84ac4e58004758a243c233b19a6f0d60f8c2 Signed-off-by: Michael Meeks <michael.meeks@collabora.com>
2022-03-25 13:32:01 -05:00
TileWireId wid, bool forceKeyframe,
std::mutex &pngMutex)
{
if ((width & 0x1) != 0) // power of two - RGBA
{
LOG_TRC("Bad width to create deltas " << width);
return false;
}
// FIXME: why duplicate this ? we could overwrite
// as we make the delta into an existing cache entry,
// and just do this as/when there is no entry.
std::shared_ptr<DeltaData> update(
new DeltaData(
wid, pixmap, startX, startY, width, height,
tileLeft, tileTop, tileSize, tilePart,
bufferWidth, bufferHeight));
std::shared_ptr<DeltaData> cacheEntry;
{
// protect _deltaEntries
std::unique_lock<std::mutex> pngLock(pngMutex);
if (_deltaEntries.size() > 16) // FIXME: hard-coded & not per-view
_deltaEntries.erase(_deltaEntries.begin());
for (auto &old : _deltaEntries)
{
deltas: track, transmit and cache deltas (disabled for now) Squashed from feature/deltas-expanded. TileCache changes: + add montonic sequence (wid) numbers to TileData + account for sizes of TileData with multiple blobs + simplify saving and notifying of tiles Sends updates (via appendChanges) based on the sequence the right mix of keyframes and/or deltas required as a single message, and parse and apply those on the JS side. We continue to use PNG for slide previews and dialogs, but remove PngCache - used by document tiles only. Annotates delta: properly as a binary package for the websocket. Distinguishes between deltas and keyframes we get from the Kit based on an initial un-compressed prefix character which we then discard. kit can be forced to render a keyframe by oldWid=0 Track invalidity on tiles themselves - to keep the keyframe around. We need to be able to track that a tile is invalid, and so subscribe to the updated version as/when it is ready - but we also want to store the keyframe underneath any deltas. force rendering of a keyframe for an empty slot in the TileCache. force tile sequence to be zero for combinedtiles - so the client can always request standalone tiles with explicit combinedtiles, or tile requests. move Blob to Common.hpp use zero size for un-changed tiles. remove obsolete render-id, and color deltas in debug mode. cleanup unit tests for non-png tile results. Change-Id: I987f84ac4e58004758a243c233b19a6f0d60f8c2 Signed-off-by: Michael Meeks <michael.meeks@collabora.com>
2022-03-25 13:32:01 -05:00
if (old->_left == tileLeft && old->_top == tileTop &&
old->_size == tileSize && old->_part == tilePart)
{
cacheEntry = old;
break;
}
}
deltas: track, transmit and cache deltas (disabled for now) Squashed from feature/deltas-expanded. TileCache changes: + add montonic sequence (wid) numbers to TileData + account for sizes of TileData with multiple blobs + simplify saving and notifying of tiles Sends updates (via appendChanges) based on the sequence the right mix of keyframes and/or deltas required as a single message, and parse and apply those on the JS side. We continue to use PNG for slide previews and dialogs, but remove PngCache - used by document tiles only. Annotates delta: properly as a binary package for the websocket. Distinguishes between deltas and keyframes we get from the Kit based on an initial un-compressed prefix character which we then discard. kit can be forced to render a keyframe by oldWid=0 Track invalidity on tiles themselves - to keep the keyframe around. We need to be able to track that a tile is invalid, and so subscribe to the updated version as/when it is ready - but we also want to store the keyframe underneath any deltas. force rendering of a keyframe for an empty slot in the TileCache. force tile sequence to be zero for combinedtiles - so the client can always request standalone tiles with explicit combinedtiles, or tile requests. move Blob to Common.hpp use zero size for un-changed tiles. remove obsolete render-id, and color deltas in debug mode. cleanup unit tests for non-png tile results. Change-Id: I987f84ac4e58004758a243c233b19a6f0d60f8c2 Signed-off-by: Michael Meeks <michael.meeks@collabora.com>
2022-03-25 13:32:01 -05:00
if (!cacheEntry)
{
deltas: track, transmit and cache deltas (disabled for now) Squashed from feature/deltas-expanded. TileCache changes: + add montonic sequence (wid) numbers to TileData + account for sizes of TileData with multiple blobs + simplify saving and notifying of tiles Sends updates (via appendChanges) based on the sequence the right mix of keyframes and/or deltas required as a single message, and parse and apply those on the JS side. We continue to use PNG for slide previews and dialogs, but remove PngCache - used by document tiles only. Annotates delta: properly as a binary package for the websocket. Distinguishes between deltas and keyframes we get from the Kit based on an initial un-compressed prefix character which we then discard. kit can be forced to render a keyframe by oldWid=0 Track invalidity on tiles themselves - to keep the keyframe around. We need to be able to track that a tile is invalid, and so subscribe to the updated version as/when it is ready - but we also want to store the keyframe underneath any deltas. force rendering of a keyframe for an empty slot in the TileCache. force tile sequence to be zero for combinedtiles - so the client can always request standalone tiles with explicit combinedtiles, or tile requests. move Blob to Common.hpp use zero size for un-changed tiles. remove obsolete render-id, and color deltas in debug mode. cleanup unit tests for non-png tile results. Change-Id: I987f84ac4e58004758a243c233b19a6f0d60f8c2 Signed-off-by: Michael Meeks <michael.meeks@collabora.com>
2022-03-25 13:32:01 -05:00
_deltaEntries.push_back(update);
return false;
}
}
deltas: track, transmit and cache deltas (disabled for now) Squashed from feature/deltas-expanded. TileCache changes: + add montonic sequence (wid) numbers to TileData + account for sizes of TileData with multiple blobs + simplify saving and notifying of tiles Sends updates (via appendChanges) based on the sequence the right mix of keyframes and/or deltas required as a single message, and parse and apply those on the JS side. We continue to use PNG for slide previews and dialogs, but remove PngCache - used by document tiles only. Annotates delta: properly as a binary package for the websocket. Distinguishes between deltas and keyframes we get from the Kit based on an initial un-compressed prefix character which we then discard. kit can be forced to render a keyframe by oldWid=0 Track invalidity on tiles themselves - to keep the keyframe around. We need to be able to track that a tile is invalid, and so subscribe to the updated version as/when it is ready - but we also want to store the keyframe underneath any deltas. force rendering of a keyframe for an empty slot in the TileCache. force tile sequence to be zero for combinedtiles - so the client can always request standalone tiles with explicit combinedtiles, or tile requests. move Blob to Common.hpp use zero size for un-changed tiles. remove obsolete render-id, and color deltas in debug mode. cleanup unit tests for non-png tile results. Change-Id: I987f84ac4e58004758a243c233b19a6f0d60f8c2 Signed-off-by: Michael Meeks <michael.meeks@collabora.com>
2022-03-25 13:32:01 -05:00
// interestingly cacheEntry may no longer be in the cache by here.
// but no other thread can touch the same tile at the same time.
assert (cacheEntry);
bool delta = false;
if (!forceKeyframe)
delta = makeDelta(*cacheEntry, *update, output);
// no two threads can be working on the same DeltaData.
cacheEntry->replaceAndFree(update);
deltas: track, transmit and cache deltas (disabled for now) Squashed from feature/deltas-expanded. TileCache changes: + add montonic sequence (wid) numbers to TileData + account for sizes of TileData with multiple blobs + simplify saving and notifying of tiles Sends updates (via appendChanges) based on the sequence the right mix of keyframes and/or deltas required as a single message, and parse and apply those on the JS side. We continue to use PNG for slide previews and dialogs, but remove PngCache - used by document tiles only. Annotates delta: properly as a binary package for the websocket. Distinguishes between deltas and keyframes we get from the Kit based on an initial un-compressed prefix character which we then discard. kit can be forced to render a keyframe by oldWid=0 Track invalidity on tiles themselves - to keep the keyframe around. We need to be able to track that a tile is invalid, and so subscribe to the updated version as/when it is ready - but we also want to store the keyframe underneath any deltas. force rendering of a keyframe for an empty slot in the TileCache. force tile sequence to be zero for combinedtiles - so the client can always request standalone tiles with explicit combinedtiles, or tile requests. move Blob to Common.hpp use zero size for un-changed tiles. remove obsolete render-id, and color deltas in debug mode. cleanup unit tests for non-png tile results. Change-Id: I987f84ac4e58004758a243c233b19a6f0d60f8c2 Signed-off-by: Michael Meeks <michael.meeks@collabora.com>
2022-03-25 13:32:01 -05:00
return delta;
}
/**
* Compress the relevant pixmap data either to a delta if we can
* or a plain deflated stream if we cannot.
*/
size_t compressOrDelta(
unsigned char* pixmap, size_t startX, size_t startY,
int width, int height,
int bufferWidth, int bufferHeight,
deltas: track, transmit and cache deltas (disabled for now) Squashed from feature/deltas-expanded. TileCache changes: + add montonic sequence (wid) numbers to TileData + account for sizes of TileData with multiple blobs + simplify saving and notifying of tiles Sends updates (via appendChanges) based on the sequence the right mix of keyframes and/or deltas required as a single message, and parse and apply those on the JS side. We continue to use PNG for slide previews and dialogs, but remove PngCache - used by document tiles only. Annotates delta: properly as a binary package for the websocket. Distinguishes between deltas and keyframes we get from the Kit based on an initial un-compressed prefix character which we then discard. kit can be forced to render a keyframe by oldWid=0 Track invalidity on tiles themselves - to keep the keyframe around. We need to be able to track that a tile is invalid, and so subscribe to the updated version as/when it is ready - but we also want to store the keyframe underneath any deltas. force rendering of a keyframe for an empty slot in the TileCache. force tile sequence to be zero for combinedtiles - so the client can always request standalone tiles with explicit combinedtiles, or tile requests. move Blob to Common.hpp use zero size for un-changed tiles. remove obsolete render-id, and color deltas in debug mode. cleanup unit tests for non-png tile results. Change-Id: I987f84ac4e58004758a243c233b19a6f0d60f8c2 Signed-off-by: Michael Meeks <michael.meeks@collabora.com>
2022-03-25 13:32:01 -05:00
int tileLeft, int tileTop, int tileSize, int tilePart,
std::vector<char>& output,
deltas: track, transmit and cache deltas (disabled for now) Squashed from feature/deltas-expanded. TileCache changes: + add montonic sequence (wid) numbers to TileData + account for sizes of TileData with multiple blobs + simplify saving and notifying of tiles Sends updates (via appendChanges) based on the sequence the right mix of keyframes and/or deltas required as a single message, and parse and apply those on the JS side. We continue to use PNG for slide previews and dialogs, but remove PngCache - used by document tiles only. Annotates delta: properly as a binary package for the websocket. Distinguishes between deltas and keyframes we get from the Kit based on an initial un-compressed prefix character which we then discard. kit can be forced to render a keyframe by oldWid=0 Track invalidity on tiles themselves - to keep the keyframe around. We need to be able to track that a tile is invalid, and so subscribe to the updated version as/when it is ready - but we also want to store the keyframe underneath any deltas. force rendering of a keyframe for an empty slot in the TileCache. force tile sequence to be zero for combinedtiles - so the client can always request standalone tiles with explicit combinedtiles, or tile requests. move Blob to Common.hpp use zero size for un-changed tiles. remove obsolete render-id, and color deltas in debug mode. cleanup unit tests for non-png tile results. Change-Id: I987f84ac4e58004758a243c233b19a6f0d60f8c2 Signed-off-by: Michael Meeks <michael.meeks@collabora.com>
2022-03-25 13:32:01 -05:00
TileWireId wid, bool forceKeyframe,
std::mutex &pngMutex)
{
if (!createDelta(pixmap, startX, startY, width, height, bufferWidth, bufferHeight,
deltas: track, transmit and cache deltas (disabled for now) Squashed from feature/deltas-expanded. TileCache changes: + add montonic sequence (wid) numbers to TileData + account for sizes of TileData with multiple blobs + simplify saving and notifying of tiles Sends updates (via appendChanges) based on the sequence the right mix of keyframes and/or deltas required as a single message, and parse and apply those on the JS side. We continue to use PNG for slide previews and dialogs, but remove PngCache - used by document tiles only. Annotates delta: properly as a binary package for the websocket. Distinguishes between deltas and keyframes we get from the Kit based on an initial un-compressed prefix character which we then discard. kit can be forced to render a keyframe by oldWid=0 Track invalidity on tiles themselves - to keep the keyframe around. We need to be able to track that a tile is invalid, and so subscribe to the updated version as/when it is ready - but we also want to store the keyframe underneath any deltas. force rendering of a keyframe for an empty slot in the TileCache. force tile sequence to be zero for combinedtiles - so the client can always request standalone tiles with explicit combinedtiles, or tile requests. move Blob to Common.hpp use zero size for un-changed tiles. remove obsolete render-id, and color deltas in debug mode. cleanup unit tests for non-png tile results. Change-Id: I987f84ac4e58004758a243c233b19a6f0d60f8c2 Signed-off-by: Michael Meeks <michael.meeks@collabora.com>
2022-03-25 13:32:01 -05:00
tileLeft, tileTop, tileSize, tilePart, output, wid, forceKeyframe, pngMutex))
{
// FIXME: should stream it in =)
// FIXME: get sizes right [!] ...
z_stream zstr;
memset((void *)&zstr, 0, sizeof (zstr));
if (deflateInit2 (&zstr, Z_BEST_SPEED + 1, Z_DEFLATED,
-MAX_WBITS, 8, Z_DEFAULT_STRATEGY) != Z_OK)
{
LOG_ERR("Failed to init deflate");
return 0;
}
uLong maxCompressed = compressBound((uLong)width * height * 4);
Bytef *compressed = (Bytef *)malloc(maxCompressed);
if (!compressed)
{
LOG_ERR("Failed to allocate buffer of size " << maxCompressed << " to compress into");
return 0;
}
zstr.next_out = compressed;
zstr.avail_out = maxCompressed;
unsigned char fixedupLine[width * 4];
// FIXME: should we RLE in pixels first ?
for (int y = 0; y < height; ++y)
{
unpremult_copy(fixedupLine, (Bytef *)pixmap + ((startY + y) * bufferWidth * 4) + (startX * 4), width);
zstr.next_in = fixedupLine;
zstr.avail_in = width * 4;
bool lastRow = (y == height - 1);
int flushFlag = lastRow ? Z_FINISH : Z_NO_FLUSH;
int expected = lastRow ? Z_STREAM_END : Z_OK;
if (deflate(&zstr, flushFlag) != expected)
{
LOG_ERR("failed to compress image ");
return 0;
}
}
deflateEnd(&zstr);
uLong compSize = maxCompressed - zstr.avail_out;
deltas: track, transmit and cache deltas (disabled for now) Squashed from feature/deltas-expanded. TileCache changes: + add montonic sequence (wid) numbers to TileData + account for sizes of TileData with multiple blobs + simplify saving and notifying of tiles Sends updates (via appendChanges) based on the sequence the right mix of keyframes and/or deltas required as a single message, and parse and apply those on the JS side. We continue to use PNG for slide previews and dialogs, but remove PngCache - used by document tiles only. Annotates delta: properly as a binary package for the websocket. Distinguishes between deltas and keyframes we get from the Kit based on an initial un-compressed prefix character which we then discard. kit can be forced to render a keyframe by oldWid=0 Track invalidity on tiles themselves - to keep the keyframe around. We need to be able to track that a tile is invalid, and so subscribe to the updated version as/when it is ready - but we also want to store the keyframe underneath any deltas. force rendering of a keyframe for an empty slot in the TileCache. force tile sequence to be zero for combinedtiles - so the client can always request standalone tiles with explicit combinedtiles, or tile requests. move Blob to Common.hpp use zero size for un-changed tiles. remove obsolete render-id, and color deltas in debug mode. cleanup unit tests for non-png tile results. Change-Id: I987f84ac4e58004758a243c233b19a6f0d60f8c2 Signed-off-by: Michael Meeks <michael.meeks@collabora.com>
2022-03-25 13:32:01 -05:00
LOG_TRC("Compressed image of size " << (width * height * 4) << " to size " << compSize);
// << Util::dumpHex(std::string((char *)compressed, compSize)));
// FIXME: get zlib to drop it directly into this buffer really.
output.push_back('Z');
size_t oldSize = output.size();
output.resize(oldSize + compSize);
memcpy(&output[oldSize], compressed, compSize);
free (compressed);
}
return output.size();
}
deltas: track, transmit and cache deltas (disabled for now) Squashed from feature/deltas-expanded. TileCache changes: + add montonic sequence (wid) numbers to TileData + account for sizes of TileData with multiple blobs + simplify saving and notifying of tiles Sends updates (via appendChanges) based on the sequence the right mix of keyframes and/or deltas required as a single message, and parse and apply those on the JS side. We continue to use PNG for slide previews and dialogs, but remove PngCache - used by document tiles only. Annotates delta: properly as a binary package for the websocket. Distinguishes between deltas and keyframes we get from the Kit based on an initial un-compressed prefix character which we then discard. kit can be forced to render a keyframe by oldWid=0 Track invalidity on tiles themselves - to keep the keyframe around. We need to be able to track that a tile is invalid, and so subscribe to the updated version as/when it is ready - but we also want to store the keyframe underneath any deltas. force rendering of a keyframe for an empty slot in the TileCache. force tile sequence to be zero for combinedtiles - so the client can always request standalone tiles with explicit combinedtiles, or tile requests. move Blob to Common.hpp use zero size for un-changed tiles. remove obsolete render-id, and color deltas in debug mode. cleanup unit tests for non-png tile results. Change-Id: I987f84ac4e58004758a243c233b19a6f0d60f8c2 Signed-off-by: Michael Meeks <michael.meeks@collabora.com>
2022-03-25 13:32:01 -05:00
static Blob expand(const Blob &blob)
{
Blob img = std::make_shared<BlobData>();
img->resize(1024*1024*4); // lots of extra space.
z_stream zstr;
memset((void *)&zstr, 0, sizeof (zstr));
zstr.next_in = (Bytef *)blob->data();
zstr.avail_in = blob->size();
zstr.next_out = (Bytef *)img->data();
zstr.avail_out = img->size();
if (inflateInit2 (&zstr, -MAX_WBITS) != Z_OK)
{
LOG_ERR("Failed to expand zimage");
return Blob();
}
if (inflate (&zstr, Z_SYNC_FLUSH) != Z_STREAM_END)
{
LOG_ERR("Failed to inflate zimage");
return Blob();
}
if (inflateEnd(&zstr) != Z_OK)
return Blob();
img->resize(img->size() - zstr.avail_out);
return img;
}
};
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */