2020-07-10 06:59:59 -05:00
|
|
|
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
|
|
|
|
/*
|
|
|
|
* 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 <cassert>
|
2020-07-12 05:35:54 -05:00
|
|
|
#include <memory>
|
|
|
|
#include <queue>
|
2020-07-10 06:59:59 -05:00
|
|
|
#include <thread>
|
2020-07-12 05:35:54 -05:00
|
|
|
#include <unordered_map>
|
|
|
|
#include <vector>
|
2022-03-29 15:25:40 -05:00
|
|
|
#include <common/SpookyV2.h>
|
2020-07-10 06:59:59 -05:00
|
|
|
|
|
|
|
#include "Png.hpp"
|
2021-11-06 10:20:35 -05:00
|
|
|
#include "Delta.hpp"
|
2020-07-12 05:35:54 -05:00
|
|
|
#include "Rectangle.hpp"
|
2020-07-10 06:59:59 -05:00
|
|
|
#include "TileDesc.hpp"
|
|
|
|
|
|
|
|
class ThreadPool {
|
|
|
|
std::mutex _mutex;
|
|
|
|
std::condition_variable _cond;
|
|
|
|
std::condition_variable _complete;
|
|
|
|
typedef std::function<void()> ThreadFn;
|
|
|
|
std::queue<ThreadFn> _work;
|
|
|
|
std::vector<std::thread> _threads;
|
|
|
|
size_t _working;
|
|
|
|
bool _shutdown;
|
|
|
|
public:
|
|
|
|
ThreadPool()
|
|
|
|
: _working(0),
|
|
|
|
_shutdown(false)
|
|
|
|
{
|
|
|
|
int maxConcurrency = 2;
|
|
|
|
#if MOBILEAPP && !defined(GTKAPP)
|
|
|
|
maxConcurrency = std::max<int>(std::thread::hardware_concurrency(), 2);
|
|
|
|
#else
|
|
|
|
const char *max = getenv("MAX_CONCURRENCY");
|
|
|
|
if (max)
|
|
|
|
maxConcurrency = atoi(max);
|
|
|
|
#endif
|
|
|
|
LOG_TRC("PNG compression thread pool size " << maxConcurrency);
|
|
|
|
for (int i = 1; i < maxConcurrency; ++i)
|
|
|
|
_threads.push_back(std::thread(&ThreadPool::work, this));
|
|
|
|
}
|
|
|
|
~ThreadPool()
|
|
|
|
{
|
|
|
|
{
|
|
|
|
std::unique_lock< std::mutex > lock(_mutex);
|
|
|
|
assert(_working == 0);
|
|
|
|
_shutdown = true;
|
|
|
|
}
|
|
|
|
_cond.notify_all();
|
|
|
|
for (auto &it : _threads)
|
|
|
|
it.join();
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t count() const
|
|
|
|
{
|
|
|
|
return _work.size();
|
|
|
|
}
|
|
|
|
|
Always lock the work queue.
The worker threads can be running and have not yet responded
to the last _cond.wait() by the time we start compressing again
- at least under valgrind:
loolforkit-nocaps: ./common/RenderTiles.hpp:304: void ThreadPool::run(): Assertion `_working == 0' failed.
==240379== Process terminating with default action of signal 6 (SIGABRT): dumping core
==240379== at 0x5505322: raise (raise.c:50)
==240379== by 0x54EE863: abort (abort.c:79)
==240379== by 0x54EE748: __assert_fail_base.cold (assert.c:92)
==240379== by 0x54FD9D5: __assert_fail (assert.c:101)
==240379== by 0x5886BB: ThreadPool::run() (RenderTiles.hpp:304)
==240379== by 0x56DC02: RenderTiles::doRender(std::shared_ptr<lok::Document>, TileCombined&, PngCache&, ThreadPool&, bool, std::function<void (unsigned char*, int, int, unsigned long, unsigned long, int, int, LibreOfficeKitTileMode)> const&, std::function<void (char const*, unsigned long)> const&) (RenderTiles.hpp:711)
==240379== by 0x5A0104: Document::renderTiles(TileCombined&, bool) (Kit.cpp:762)
==240379== by 0x59CF1A: Document::renderCombinedTiles(StringVector const&) (Kit.cpp:719)
==240379== by 0x59AEC8: Document::drainQueue(std::chrono::time_point<std::chrono::_V2::steady_clock, std::chrono::duration<long, std::ratio<1l, 1000000000l> > > const&) (Kit.cpp:1570)
That means our queue starts processing work as we do the unlocked
queue push - causing some potential badness.
Change-Id: Ib0578dac009376c0676da73a8c1d8960304dc072
Signed-off-by: Michael Meeks <michael.meeks@collabora.com>
2021-08-21 13:40:46 -05:00
|
|
|
void pushWork(const ThreadFn &fn)
|
2020-07-10 06:59:59 -05:00
|
|
|
{
|
Always lock the work queue.
The worker threads can be running and have not yet responded
to the last _cond.wait() by the time we start compressing again
- at least under valgrind:
loolforkit-nocaps: ./common/RenderTiles.hpp:304: void ThreadPool::run(): Assertion `_working == 0' failed.
==240379== Process terminating with default action of signal 6 (SIGABRT): dumping core
==240379== at 0x5505322: raise (raise.c:50)
==240379== by 0x54EE863: abort (abort.c:79)
==240379== by 0x54EE748: __assert_fail_base.cold (assert.c:92)
==240379== by 0x54FD9D5: __assert_fail (assert.c:101)
==240379== by 0x5886BB: ThreadPool::run() (RenderTiles.hpp:304)
==240379== by 0x56DC02: RenderTiles::doRender(std::shared_ptr<lok::Document>, TileCombined&, PngCache&, ThreadPool&, bool, std::function<void (unsigned char*, int, int, unsigned long, unsigned long, int, int, LibreOfficeKitTileMode)> const&, std::function<void (char const*, unsigned long)> const&) (RenderTiles.hpp:711)
==240379== by 0x5A0104: Document::renderTiles(TileCombined&, bool) (Kit.cpp:762)
==240379== by 0x59CF1A: Document::renderCombinedTiles(StringVector const&) (Kit.cpp:719)
==240379== by 0x59AEC8: Document::drainQueue(std::chrono::time_point<std::chrono::_V2::steady_clock, std::chrono::duration<long, std::ratio<1l, 1000000000l> > > const&) (Kit.cpp:1570)
That means our queue starts processing work as we do the unlocked
queue push - causing some potential badness.
Change-Id: Ib0578dac009376c0676da73a8c1d8960304dc072
Signed-off-by: Michael Meeks <michael.meeks@collabora.com>
2021-08-21 13:40:46 -05:00
|
|
|
std::unique_lock< std::mutex > lock(_mutex);
|
|
|
|
assert(_working == 0);
|
2020-07-10 06:59:59 -05:00
|
|
|
_work.push(fn);
|
|
|
|
}
|
|
|
|
|
|
|
|
void runOne(std::unique_lock< std::mutex >& lock)
|
|
|
|
{
|
|
|
|
assert(!_work.empty());
|
|
|
|
|
|
|
|
ThreadFn fn = _work.front();
|
|
|
|
_work.pop();
|
|
|
|
_working++;
|
|
|
|
lock.unlock();
|
|
|
|
|
Always lock the work queue.
The worker threads can be running and have not yet responded
to the last _cond.wait() by the time we start compressing again
- at least under valgrind:
loolforkit-nocaps: ./common/RenderTiles.hpp:304: void ThreadPool::run(): Assertion `_working == 0' failed.
==240379== Process terminating with default action of signal 6 (SIGABRT): dumping core
==240379== at 0x5505322: raise (raise.c:50)
==240379== by 0x54EE863: abort (abort.c:79)
==240379== by 0x54EE748: __assert_fail_base.cold (assert.c:92)
==240379== by 0x54FD9D5: __assert_fail (assert.c:101)
==240379== by 0x5886BB: ThreadPool::run() (RenderTiles.hpp:304)
==240379== by 0x56DC02: RenderTiles::doRender(std::shared_ptr<lok::Document>, TileCombined&, PngCache&, ThreadPool&, bool, std::function<void (unsigned char*, int, int, unsigned long, unsigned long, int, int, LibreOfficeKitTileMode)> const&, std::function<void (char const*, unsigned long)> const&) (RenderTiles.hpp:711)
==240379== by 0x5A0104: Document::renderTiles(TileCombined&, bool) (Kit.cpp:762)
==240379== by 0x59CF1A: Document::renderCombinedTiles(StringVector const&) (Kit.cpp:719)
==240379== by 0x59AEC8: Document::drainQueue(std::chrono::time_point<std::chrono::_V2::steady_clock, std::chrono::duration<long, std::ratio<1l, 1000000000l> > > const&) (Kit.cpp:1570)
That means our queue starts processing work as we do the unlocked
queue push - causing some potential badness.
Change-Id: Ib0578dac009376c0676da73a8c1d8960304dc072
Signed-off-by: Michael Meeks <michael.meeks@collabora.com>
2021-08-21 13:40:46 -05:00
|
|
|
try {
|
|
|
|
fn();
|
|
|
|
} catch(...) {
|
|
|
|
LOG_ERR("Exception in thread pool execution.");
|
|
|
|
}
|
2020-07-10 06:59:59 -05:00
|
|
|
|
|
|
|
lock.lock();
|
|
|
|
_working--;
|
|
|
|
if (_work.empty() && _working == 0)
|
|
|
|
_complete.notify_all();
|
|
|
|
}
|
|
|
|
|
|
|
|
void run()
|
|
|
|
{
|
|
|
|
std::unique_lock< std::mutex > lock(_mutex);
|
|
|
|
assert(_working == 0);
|
|
|
|
|
|
|
|
// Avoid notifying threads if we don't need to.
|
|
|
|
bool useThreads = _threads.size() > 1 && _work.size() > 1;
|
|
|
|
if (useThreads)
|
|
|
|
_cond.notify_all();
|
|
|
|
|
|
|
|
while(!_work.empty())
|
|
|
|
runOne(lock);
|
|
|
|
|
|
|
|
if (useThreads && (_working > 0 || !_work.empty()))
|
|
|
|
_complete.wait(lock, [this]() { return _working == 0 && _work.empty(); } );
|
|
|
|
|
|
|
|
assert(_working==0);
|
|
|
|
assert(_work.empty());
|
|
|
|
}
|
|
|
|
|
|
|
|
void work()
|
|
|
|
{
|
|
|
|
std::unique_lock< std::mutex > lock(_mutex);
|
|
|
|
while (!_shutdown)
|
|
|
|
{
|
|
|
|
_cond.wait(lock);
|
|
|
|
if (!_shutdown && !_work.empty())
|
|
|
|
runOne(lock);
|
|
|
|
}
|
|
|
|
}
|
2021-05-12 11:55:16 -05:00
|
|
|
|
|
|
|
void dumpState(std::ostream& oss)
|
|
|
|
{
|
|
|
|
oss << "\tthreadPool:"
|
|
|
|
<< "\n\t\tshutdown: " << _shutdown
|
|
|
|
<< "\n\t\tworking: " << _working
|
|
|
|
<< "\n\t\twork count: " << count()
|
|
|
|
<< "\n\t\tthread count " << _threads.size()
|
|
|
|
<< "\n";
|
|
|
|
}
|
2020-07-10 06:59:59 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
namespace RenderTiles
|
|
|
|
{
|
|
|
|
struct Buffer {
|
|
|
|
unsigned char *_data;
|
|
|
|
Buffer()
|
|
|
|
{
|
|
|
|
_data = nullptr;
|
|
|
|
}
|
|
|
|
Buffer(size_t x, size_t y) :
|
|
|
|
Buffer()
|
|
|
|
{
|
|
|
|
allocate(x, y);
|
|
|
|
}
|
|
|
|
void allocate(size_t x, size_t y)
|
|
|
|
{
|
|
|
|
assert(!_data);
|
|
|
|
_data = static_cast<unsigned char *>(calloc(x * y, 4));
|
|
|
|
}
|
|
|
|
~Buffer()
|
|
|
|
{
|
|
|
|
if (_data)
|
|
|
|
free (_data);
|
|
|
|
}
|
|
|
|
unsigned char *data() { return _data; }
|
|
|
|
};
|
|
|
|
|
|
|
|
static void pushRendered(std::vector<TileDesc> &renderedTiles,
|
|
|
|
const TileDesc &desc, TileWireId wireId, size_t imgSize)
|
|
|
|
{
|
|
|
|
renderedTiles.push_back(desc);
|
|
|
|
renderedTiles.back().setWireId(wireId);
|
|
|
|
renderedTiles.back().setImgSize(imgSize);
|
|
|
|
}
|
2020-07-13 15:00:44 -05:00
|
|
|
|
2020-07-10 06:59:59 -05:00
|
|
|
bool doRender(std::shared_ptr<lok::Document> document,
|
2022-06-15 12:34:11 -05:00
|
|
|
DeltaGenerator &deltaGen,
|
2020-07-10 06:59:59 -05:00
|
|
|
TileCombined &tileCombined,
|
|
|
|
ThreadPool &pngPool,
|
2020-07-12 16:43:51 -05:00
|
|
|
bool combined,
|
|
|
|
const std::function<void (unsigned char *data,
|
|
|
|
int offsetX, int offsetY,
|
|
|
|
size_t pixmapWidth, size_t pixmapHeight,
|
|
|
|
int pixelWidth, int pixelHeight,
|
|
|
|
LibreOfficeKitTileMode mode)>& blendWatermark,
|
2021-09-01 03:11:55 -05:00
|
|
|
const std::function<void (const char *buffer, size_t length)>& outputMessage,
|
2022-06-20 13:52:10 -05:00
|
|
|
unsigned mobileAppDocId,
|
|
|
|
int canonicalViewId)
|
2020-07-10 06:59:59 -05:00
|
|
|
{
|
2022-02-19 07:51:38 -06:00
|
|
|
const auto& tiles = tileCombined.getTiles();
|
2020-07-10 06:59:59 -05:00
|
|
|
|
2022-06-09 07:29:02 -05:00
|
|
|
// Otherwise our delta-building & threading goes badly wrong
|
2022-06-15 10:37:16 -05:00
|
|
|
// external sources of tilecombine are checked at the perimeter
|
2022-06-09 07:29:02 -05:00
|
|
|
assert(!tileCombined.hasDuplicates());
|
|
|
|
|
2020-07-10 06:59:59 -05:00
|
|
|
// Calculate the area we cover
|
|
|
|
Util::Rectangle renderArea;
|
|
|
|
std::vector<Util::Rectangle> tileRecs;
|
|
|
|
tileRecs.reserve(tiles.size());
|
|
|
|
|
2022-02-19 07:51:38 -06:00
|
|
|
for (const auto& tile : tiles)
|
2020-07-10 06:59:59 -05:00
|
|
|
{
|
|
|
|
Util::Rectangle rectangle(tile.getTilePosX(), tile.getTilePosY(),
|
|
|
|
tileCombined.getTileWidth(), tileCombined.getTileHeight());
|
|
|
|
|
|
|
|
if (tileRecs.empty())
|
|
|
|
{
|
|
|
|
renderArea = rectangle;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
renderArea.extend(rectangle);
|
|
|
|
}
|
|
|
|
|
|
|
|
tileRecs.push_back(rectangle);
|
|
|
|
}
|
|
|
|
|
2020-07-13 15:00:44 -05:00
|
|
|
assert(tiles.size() == tileRecs.size());
|
|
|
|
|
2020-07-10 06:59:59 -05:00
|
|
|
const size_t tilesByX = renderArea.getWidth() / tileCombined.getTileWidth();
|
|
|
|
const size_t tilesByY = renderArea.getHeight() / tileCombined.getTileHeight();
|
2020-07-13 15:00:44 -05:00
|
|
|
const int pixelWidth = tileCombined.getWidth();
|
|
|
|
const int pixelHeight = tileCombined.getHeight();
|
2022-06-09 07:29:02 -05:00
|
|
|
assert (pixelWidth > 0 && pixelHeight > 0);
|
2020-07-13 15:00:44 -05:00
|
|
|
const size_t pixmapWidth = tilesByX * pixelWidth;
|
|
|
|
const size_t pixmapHeight = tilesByY * pixelHeight;
|
2020-07-10 06:59:59 -05:00
|
|
|
|
|
|
|
if (pixmapWidth > 4096 || pixmapHeight > 4096)
|
|
|
|
LOG_WRN("Unusual extremely large tile combine of size " << pixmapWidth << 'x' << pixmapHeight);
|
|
|
|
|
|
|
|
RenderTiles::Buffer pixmap(pixmapWidth, pixmapHeight);
|
|
|
|
|
|
|
|
// Render the whole area
|
|
|
|
const double area = pixmapWidth * pixmapHeight;
|
2020-12-06 13:51:54 -06:00
|
|
|
const auto start = std::chrono::steady_clock::now();
|
2020-07-10 06:59:59 -05:00
|
|
|
LOG_TRC("Calling paintPartTile(" << (void*)pixmap.data() << ')');
|
|
|
|
document->paintPartTile(pixmap.data(),
|
|
|
|
tileCombined.getPart(),
|
|
|
|
pixmapWidth, pixmapHeight,
|
|
|
|
renderArea.getLeft(), renderArea.getTop(),
|
|
|
|
renderArea.getWidth(), renderArea.getHeight());
|
2020-12-06 13:51:54 -06:00
|
|
|
auto duration = std::chrono::steady_clock::now() - start;
|
2020-12-06 21:45:46 -06:00
|
|
|
const auto elapsedMs = std::chrono::duration_cast<std::chrono::milliseconds>(duration);
|
|
|
|
const double elapsedMics = elapsedMs.count() * 1000.; // Need MPixels/sec, use Pixels/mics.
|
|
|
|
LOG_DBG("paintPartTile at ("
|
|
|
|
<< renderArea.getLeft() << ", " << renderArea.getTop() << "), ("
|
|
|
|
<< renderArea.getWidth() << ", " << renderArea.getHeight() << ") "
|
|
|
|
<< " rendered in " << elapsedMs << " (" << area / elapsedMics << " MP/s).");
|
2020-07-10 06:59:59 -05:00
|
|
|
|
2021-09-01 03:11:55 -05:00
|
|
|
(void) mobileAppDocId;
|
2020-07-13 15:00:44 -05:00
|
|
|
|
2020-07-10 06:59:59 -05:00
|
|
|
const auto mode = static_cast<LibreOfficeKitTileMode>(document->getTileMode());
|
|
|
|
|
2020-07-15 03:52:15 -05:00
|
|
|
const size_t pixmapSize = 4 * pixmapWidth * pixmapHeight;
|
2020-07-10 06:59:59 -05:00
|
|
|
std::vector<char> output;
|
|
|
|
output.reserve(pixmapSize);
|
|
|
|
|
|
|
|
// Compress the area as tiles
|
|
|
|
std::vector<TileDesc> renderedTiles;
|
|
|
|
std::vector<TileWireId> renderingIds;
|
|
|
|
|
|
|
|
size_t tileIndex = 0;
|
|
|
|
|
|
|
|
std::mutex pngMutex;
|
|
|
|
|
2022-02-19 07:51:38 -06:00
|
|
|
for (const Util::Rectangle& tileRect : tileRecs)
|
2020-07-10 06:59:59 -05:00
|
|
|
{
|
|
|
|
const size_t positionX = (tileRect.getLeft() - renderArea.getLeft()) / tileCombined.getTileWidth();
|
|
|
|
const size_t positionY = (tileRect.getTop() - renderArea.getTop()) / tileCombined.getTileHeight();
|
|
|
|
|
|
|
|
const int offsetX = positionX * pixelWidth;
|
|
|
|
const int offsetY = positionY * pixelHeight;
|
2022-06-09 07:29:02 -05:00
|
|
|
|
|
|
|
// FIXME: should this be in the delta / compression thread ?
|
2020-07-12 16:43:51 -05:00
|
|
|
blendWatermark(pixmap.data(), offsetX, offsetY,
|
|
|
|
pixmapWidth, pixmapHeight,
|
|
|
|
pixelWidth, pixelHeight,
|
|
|
|
mode);
|
2020-07-10 06:59:59 -05:00
|
|
|
|
2022-03-25 13:32:01 -05:00
|
|
|
// FIXME: prettify this.
|
|
|
|
bool forceKeyframe = tiles[tileIndex].getOldWireId() == 0;
|
2020-07-10 06:59:59 -05:00
|
|
|
|
2022-03-25 13:32:01 -05:00
|
|
|
// FIXME: we should perhaps increment only on a plausible edit
|
|
|
|
static TileWireId nextId = 0;
|
2021-12-31 13:37:10 -06:00
|
|
|
TileWireId wireId = ++nextId;
|
2020-07-10 06:59:59 -05:00
|
|
|
|
|
|
|
bool skipCompress = false;
|
|
|
|
if (!skipCompress)
|
|
|
|
{
|
|
|
|
renderingIds.push_back(wireId);
|
|
|
|
|
2022-03-25 13:32:01 -05:00
|
|
|
LOG_TRC("Queued encoding of tile #" << tileIndex << " at (" << positionX << ',' << positionY << ") with " <<
|
|
|
|
(forceKeyframe?"force keyframe" : "allow delta") << ", wireId: " << wireId);
|
2022-04-27 04:21:21 -05:00
|
|
|
|
2020-07-10 06:59:59 -05:00
|
|
|
// Queue to be executed later in parallel inside 'run'
|
2022-03-17 14:52:45 -05:00
|
|
|
pngPool.pushWork([=,&output,&pixmap,&tiles,&renderedTiles,
|
2022-06-15 12:34:11 -05:00
|
|
|
&pngMutex,&deltaGen]()
|
|
|
|
{
|
|
|
|
auto data = std::shared_ptr<std::vector< char >>(new std::vector< char >());
|
|
|
|
data->reserve(pixmapWidth * pixmapHeight * 1);
|
2022-01-05 08:24:18 -06:00
|
|
|
|
2022-06-09 07:29:02 -05:00
|
|
|
// FIXME: don't try to store & create deltas for read-only documents.
|
2022-03-25 13:32:01 -05:00
|
|
|
if (tiles[tileIndex].getId() < 0) // not a preview
|
2020-07-10 06:59:59 -05:00
|
|
|
{
|
2022-03-25 13:32:01 -05:00
|
|
|
// Can we create a delta ?
|
|
|
|
LOG_TRC("Compress new tile #" << tileIndex);
|
|
|
|
deltaGen.compressOrDelta(pixmap.data(), offsetX, offsetY,
|
|
|
|
pixelWidth, pixelHeight,
|
|
|
|
pixmapWidth, pixmapHeight,
|
2022-06-20 13:36:27 -05:00
|
|
|
TileLocation(
|
|
|
|
tileRect.getLeft(),
|
|
|
|
tileRect.getTop(),
|
|
|
|
tileRect.getWidth(),
|
2022-06-20 13:52:10 -05:00
|
|
|
tileCombined.getPart(),
|
|
|
|
canonicalViewId
|
|
|
|
),
|
2022-06-15 12:34:11 -05:00
|
|
|
*data, wireId, forceKeyframe);
|
2022-03-25 13:32:01 -05:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// FIXME: write our own trivial PNG encoding code using deflate.
|
|
|
|
LOG_TRC("Encode a new png for tile #" << tileIndex);
|
|
|
|
if (!Png::encodeSubBufferToPNG(pixmap.data(), offsetX, offsetY, pixelWidth, pixelHeight,
|
|
|
|
pixmapWidth, pixmapHeight, *data, mode))
|
|
|
|
{
|
|
|
|
// FIXME: Return error.
|
|
|
|
// sendTextFrameAndLogError("error: cmd=tile kind=failure");
|
|
|
|
LOG_ERR("Failed to encode tile into PNG.");
|
|
|
|
return;
|
|
|
|
}
|
2020-07-10 06:59:59 -05:00
|
|
|
}
|
|
|
|
|
wsd: reduce debug and generally redundant logs
In 'debug' log-level we expect a detailed, but
still readable output. Having one area with
disproportionately large number of logs reduces
the overall utility of the log output.
This patch reduces a number of redundant log
entries, including errors that are already
logged. It also reduces the level of some
others from 'information' to 'debug' and
from 'debug' to 'trace'.
The goal is to make 'debug' level as useful as
possible to read the progress and be able to
understand what was going on, such that one is
able to decide which area to dig deeper into.
Then, trace level could be used to get more
insight into that area, if necessary. For
example, when investigating a test failure,
one first enables 'debug' logs and reads through.
Once a section between two debug entries is
identified as being of interest, enabling 'trace'
level logs becomes more productive as it's
now possible to easily reach the first DBG
entry and read through until the second one.
It's unfortunate that we don't have per-area
control for enabling/disabling logs, so it
is common to see more and more 'debug' log
entries added all around, making logs
less and less readable.
It is also a limitation of the levels we have
that we really only have 3 usable levels:
one, two, many. That is, 'information' for
the most important events, 'debug' for
technical details needed to investigate issues,
and 'trace' for everything else. ('warning'
and 'error' aren't really 'levels'; they have
semantics that makes them special-cases.)
So we have to avoid degrading one into the
other, or have differences without distinction.
If any of these entries are needed to be
displayed more frequently, changing them
back to 'debug' or even 'information' should
be done. Though for me they seem special
cases that don't benefit most log readings.
Change-Id: Id2c6a9dc027483b81a066b0b4b50a298c5eff449
Signed-off-by: Ashod Nakashian <ashod.nakashian@collabora.co.uk>
2022-02-19 07:30:26 -06:00
|
|
|
LOG_TRC("Tile " << tileIndex << " is " << data->size() << " bytes.");
|
2020-07-10 06:59:59 -05:00
|
|
|
std::unique_lock<std::mutex> pngLock(pngMutex);
|
|
|
|
output.insert(output.end(), data->begin(), data->end());
|
|
|
|
pushRendered(renderedTiles, tiles[tileIndex], wireId, data->size());
|
|
|
|
});
|
|
|
|
}
|
|
|
|
tileIndex++;
|
|
|
|
}
|
|
|
|
|
|
|
|
pngPool.run();
|
|
|
|
|
2020-12-06 13:51:54 -06:00
|
|
|
duration = std::chrono::steady_clock::now() - start;
|
2020-12-06 21:45:46 -06:00
|
|
|
const auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(duration);
|
|
|
|
LOG_DBG("rendering tiles at (" << renderArea.getLeft() << ", " << renderArea.getTop()
|
|
|
|
<< "), (" << renderArea.getWidth() << ", "
|
|
|
|
<< renderArea.getHeight() << ") "
|
|
|
|
<< " took " << elapsed << " (including the paintPartTile).");
|
2020-07-10 06:59:59 -05:00
|
|
|
|
|
|
|
if (tileIndex == 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
std::string tileMsg;
|
|
|
|
if (combined)
|
2020-07-12 16:43:51 -05:00
|
|
|
{
|
2022-03-25 13:32:01 -05:00
|
|
|
tileMsg = tileCombined.serialize("tilecombine:", "\n", renderedTiles);
|
2020-07-10 06:59:59 -05:00
|
|
|
|
2020-07-12 16:43:51 -05:00
|
|
|
LOG_TRC("Sending back painted tiles for " << tileMsg << " of size " << output.size() << " bytes) for: " << tileMsg);
|
2020-07-10 06:59:59 -05:00
|
|
|
|
2020-07-12 16:43:51 -05:00
|
|
|
std::unique_ptr<char[]> response;
|
|
|
|
const size_t responseSize = tileMsg.size() + output.size();
|
|
|
|
response.reset(new char[responseSize]);
|
|
|
|
std::copy(tileMsg.begin(), tileMsg.end(), response.get());
|
|
|
|
std::copy(output.begin(), output.end(), response.get() + tileMsg.size());
|
|
|
|
outputMessage(response.get(), responseSize);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
size_t outputOffset = 0;
|
|
|
|
for (auto &i : renderedTiles)
|
|
|
|
{
|
2022-03-25 13:32:01 -05:00
|
|
|
tileMsg = i.serialize("tile:", "\n");
|
2020-07-12 16:43:51 -05:00
|
|
|
const size_t responseSize = tileMsg.size() + i.getImgSize();
|
|
|
|
std::unique_ptr<char[]> response;
|
|
|
|
response.reset(new char[responseSize]);
|
|
|
|
std::copy(tileMsg.begin(), tileMsg.end(), response.get());
|
|
|
|
std::copy(output.begin() + outputOffset, output.begin() + outputOffset + i.getImgSize(), response.get() + tileMsg.size());
|
|
|
|
outputMessage(response.get(), responseSize);
|
|
|
|
outputOffset += i.getImgSize();
|
|
|
|
}
|
|
|
|
}
|
2022-06-15 12:34:11 -05:00
|
|
|
|
|
|
|
// Should we do this more frequently? and/orshould we defer it?
|
|
|
|
deltaGen.rebalanceDeltas();
|
2020-07-10 06:59:59 -05:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|