diff --git a/loolwsd/DocumentBroker.cpp b/loolwsd/DocumentBroker.cpp index 989e05698..f8266a7dc 100644 --- a/loolwsd/DocumentBroker.cpp +++ b/loolwsd/DocumentBroker.cpp @@ -526,6 +526,7 @@ void DocumentBroker::handleTileCombinedRequest(TileCombined& tileCombined, Log::trace() << "TileCombined request for " << tileCombined.serialize() << Log::end; // Satisfy as many tiles from the cache. + std::vector tiles; for (auto& tile : tileCombined.getTiles()) { std::unique_ptr cachedTile = _tileCache->lookupTile(tile); @@ -559,14 +560,20 @@ void DocumentBroker::handleTileCombinedRequest(TileCombined& tileCombined, // Not cached, needs rendering. tile.setVersion(++_tileVersion); tileCache().subscribeToTileRendering(tile, session); - - // Forward to child to render. - Log::debug() << "Sending render request for tile (" << tile.getPart() << ',' << tile.getTilePosX() << ',' << tile.getTilePosY() << ")." << Log::end; - const auto req = tile.serialize("tile"); - Log::debug() << "Tile request: " << req << Log::end; - _childProcess->getWebSocket()->sendFrame(req.data(), req.size()); + tiles.push_back(tile); } } + + if (!tiles.empty()) + { + auto newTileCombined = TileCombined::create(tiles); + newTileCombined.setVersion(++_tileVersion); + + // Forward to child to render. + const auto req = newTileCombined.serialize("tilecombine"); + Log::debug() << "Sending residual tilecombine: " << req << Log::end; + _childProcess->getWebSocket()->sendFrame(req.data(), req.size()); + } } void DocumentBroker::cancelTileRequests(const std::shared_ptr& session) diff --git a/loolwsd/MessageQueue.cpp b/loolwsd/MessageQueue.cpp index da1bfbacb..e84580003 100644 --- a/loolwsd/MessageQueue.cpp +++ b/loolwsd/MessageQueue.cpp @@ -106,17 +106,22 @@ void TileQueue::put_impl(const Payload& value) Log::trace() << "After canceltiles have " << _queue.size() << " in queue." << Log::end; return; } - - // TODO because we are doing tile combining ourselves in the get_impl(), - // we could split the "tilecombine" messages into separate tiles here; - // could lead to some improvements in case we are getting subsequent - // tilecombines with overlapping, but not completely same areas. + else if (msg.compare(0, 10, "tilecombine") == 0) + { + // Breakup tilecombine and deduplicate. + const auto tileCombined = TileCombined::parse(msg); + for (auto& tile : tileCombined.getTiles()) + { + const auto newMsg = tile.serialize("tile"); + _queue.push_back(Payload(newMsg.data(), newMsg.data() + newMsg.size())); + } + } if (!_queue.empty()) { // TODO probably we could do the same with the invalidation callbacks // (later one wins). - if (msg.compare(0, 4, "tile") == 0 || msg.compare(0, 10, "tilecombine") == 0) + if (msg.compare(0, 4, "tile") == 0) { const auto newMsg = msg.substr(0, msg.find(" ver")); diff --git a/loolwsd/TileCache.cpp b/loolwsd/TileCache.cpp index ce749453d..232ca2b65 100644 --- a/loolwsd/TileCache.cpp +++ b/loolwsd/TileCache.cpp @@ -433,6 +433,7 @@ void TileCache::subscribeToTileRendering(const TileDesc& tile, const std::shared { Log::debug("Redundant request to subscribe on tile " + name); tileBeingRendered->setVersion(tile.getVersion()); + return; } }