Skip to content

Commit 946524c

Browse files
author
Grok Compression
committed
memory back presssure: fix for grk_decompress decompress to disk
1 parent 61ec9f9 commit 946524c

5 files changed

Lines changed: 96 additions & 8 deletions

File tree

.vscode/launch.json

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -139,15 +139,15 @@
139139
"name": "SPOT6",
140140
"type": "cppdbg",
141141
"request": "launch",
142-
//"program": "/usr/bin/time",
143-
"program": "${workspaceFolder}/build/bin/core_decompress",
142+
"program": "/usr/bin/time",
143+
//"program": "${workspaceFolder}/build/bin/grk_decompress",
144144
"args": [
145-
// "-v",
146-
// "${workspaceFolder}/build/bin/core_decompress",
145+
"-v",
146+
"${workspaceFolder}/build/bin/grk_decompress",
147147
"-i",
148148
"$HOME/temp/IMG_SPOT6_PMS_201305251604372_ORT_816009101_R1C1.JP2",
149-
// "-o",
150-
// "$HOME/temp/spot6.tif"
149+
"-o",
150+
"$HOME/temp/spot6.tif"
151151
],
152152
"cwd": "${workspaceFolder}",
153153
"environment": [

src/lib/core/codestream/decompress/CodeStreamDecompress.cpp

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
*
1616
*/
1717

18+
#include <chrono>
1819
#include <functional>
1920

2021
#include "TFSingleton.h"
@@ -258,7 +259,15 @@ bool CodeStreamDecompress::decompress(grk_plugin_tile* tile)
258259
uint32_t yBegin = 0;
259260
uint32_t yEnd = std::min(tileGlobalYEnd, regionY1) - std::max(tileGlobalYBegin, regionY0);
260261
if(yEnd <= yBegin)
262+
{
263+
// Empty tile row (e.g. zero pixels after resolution reduction).
264+
// Still advance nextBandTileY_ so backpressure unblocks.
265+
std::lock_guard<std::mutex> lock(bandOrderMutex_);
266+
if(tileY == nextBandTileY_)
267+
nextBandTileY_ = tileY + 1;
268+
bandDrainCV_.notify_one();
261269
return;
270+
}
262271

263272
uint16_t tileX0 = tileIndexBegin % numTileCols;
264273
uint16_t numSlatedCols = (uint16_t)tilesToDecompress_.getSlatedTileRect().width();
@@ -288,6 +297,16 @@ bool CodeStreamDecompress::decompress(grk_plugin_tile* tile)
288297

289298
if(!ioBandCallback_(band.yBegin, band.yEnd, scratchImage_.get(), ioBandUserData_))
290299
success_ = false;
300+
301+
// Release tile processors for this completed row — compositing is done,
302+
// so tile image data is no longer needed.
303+
for(uint16_t col = 0; col < band.numCols; col++)
304+
{
305+
uint16_t tileIndex = nextBandTileY_ * numTileCols + (band.tileX0 + col);
306+
tileCache_->releaseForSwath(tileIndex);
307+
}
308+
MemoryManager::releaseFreedPages();
309+
291310
pendingBands_.erase(nextBandTileY_);
292311

293312
// Advance strip buffer for the next tile row
@@ -310,6 +329,8 @@ bool CodeStreamDecompress::decompress(grk_plugin_tile* tile)
310329

311330
nextBandTileY_ = nextTileY;
312331
}
332+
// Wake the parser thread so it can schedule more tiles
333+
bandDrainCV_.notify_one();
313334
},
314335
nullptr, tilesToDecompress_.getSlatedTileRect());
315336
}
@@ -825,6 +846,20 @@ bool CodeStreamDecompress::sequentialParseAndSchedule(bool multiTile)
825846
return true;
826847
}
827848

849+
// Backpressure for strip-based band callback: block the parser thread if
850+
// this tile's row is too far ahead of the row currently being drained.
851+
// Without this, all tiles decompress into memory before any row is written.
852+
// Use wait_for with a timeout so we periodically re-check success_ even if
853+
// the Taskflow task graph skips the post callback on error.
854+
if(ioBandCallback_ && tileCompletion_)
855+
{
856+
uint16_t numTileCols = tileCompletion_->getNumTileCols();
857+
uint16_t tileY = tileProcessor->getIndex() / numTileCols;
858+
std::unique_lock<std::mutex> lock(bandOrderMutex_);
859+
while(!(tileY < nextBandTileY_ + 2 || !success_))
860+
bandDrainCV_.wait_for(lock, std::chrono::milliseconds(100));
861+
}
862+
828863
// schedule
829864
return schedule(tileProcessor, multiTile);
830865
}
@@ -1113,6 +1148,10 @@ std::function<void()> CodeStreamDecompress::postMultiTile(ITileProcessor* tilePr
11131148
if(!success_)
11141149
{
11151150
releaseThrottle();
1151+
// Always mark tile as complete so row callbacks can fire and
1152+
// backpressure unblocks, even when the decompress failed.
1153+
if(tileCompletion_)
1154+
tileCompletion_->complete(tileProcessor->getIndex());
11161155
return;
11171156
}
11181157
tileProcessor->post_decompressT2T1(scratchImage_.get());

src/lib/core/codestream/decompress/CodeStreamDecompress.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,7 @@ class CodeStreamDecompress final : public CodeStream, public IDecompressor
412412

413413
// band ordering for incremental writes
414414
std::mutex bandOrderMutex_;
415+
std::condition_variable bandDrainCV_;
415416
uint16_t nextBandTileY_ = 0;
416417
struct PendingBand_
417418
{

src/lib/core/util/GrkImage.cpp

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -444,8 +444,11 @@ bool GrkImage::isOpacity(uint16_t compno) const
444444
}
445445
bool GrkImage::isPostProcessNoOp(void) const
446446
{
447-
// applyColour: palette or channel_definition requires processing
448-
if(meta && (meta->color.palette || meta->color.channel_definition))
447+
// applyColour: palette requires processing; channel_definition only blocks
448+
// if it needs component data swaps (type-only metadata is applied early)
449+
if(meta && meta->color.palette)
450+
return false;
451+
if(needsChannelDefinitionSwap())
449452
return false;
450453
// applyColourManagement: ICC profile that must be applied
451454
if(meta && meta->color.icc_profile_buf)
@@ -504,6 +507,11 @@ bool GrkImage::isPostProcessNoOp(void) const
504507
}
505508
void GrkImage::postReadHeader(CodingParams* cp)
506509
{
510+
// Apply channel definition types (e.g. alpha) early so format writers
511+
// can emit correct metadata (TIFF EXTRASAMPLES, etc.) before strip-based
512+
// decompress starts. Component data swaps are deferred to postProcess.
513+
applyChannelDefinitionTypes();
514+
507515
uint8_t prec = comps[0].prec;
508516
if(precision)
509517
prec = precision->prec;
@@ -596,6 +604,44 @@ void GrkImage::allocPalette(uint8_t num_channels, uint16_t num_entries)
596604
((GrkImageMeta*)meta)->allocPalette(num_channels, num_entries);
597605
}
598606

607+
bool GrkImage::needsChannelDefinitionSwap() const
608+
{
609+
if(!meta || !meta->color.channel_definition)
610+
return false;
611+
auto info = meta->color.channel_definition->descriptions;
612+
uint16_t n = meta->color.channel_definition->num_channel_descriptions;
613+
for(uint16_t i = 0; i < n; ++i)
614+
{
615+
if(info[i].typ != GRK_CHANNEL_TYPE_COLOUR)
616+
continue;
617+
if(info[i].asoc == GRK_CHANNEL_ASSOC_WHOLE_IMAGE)
618+
continue;
619+
uint16_t channel = info[i].channel;
620+
uint16_t asoc = info[i].asoc;
621+
if(channel >= numcomps || asoc > numcomps)
622+
continue;
623+
uint16_t asoc_index = (uint16_t)(asoc - 1);
624+
if(channel != asoc_index)
625+
return true;
626+
}
627+
return false;
628+
}
629+
630+
void GrkImage::applyChannelDefinitionTypes()
631+
{
632+
if(!meta || !meta->color.channel_definition)
633+
return;
634+
auto info = meta->color.channel_definition->descriptions;
635+
uint16_t n = meta->color.channel_definition->num_channel_descriptions;
636+
for(uint16_t i = 0; i < n; ++i)
637+
{
638+
uint16_t channel = info[i].channel;
639+
if(channel >= numcomps)
640+
continue;
641+
comps[channel].type = (GRK_CHANNEL_TYPE)info[i].typ;
642+
}
643+
}
644+
599645
void GrkImage::apply_channel_definition()
600646
{
601647
if(channel_definition_applied)

src/lib/core/util/GrkImage.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,8 @@ class GrkImage : public grk_image
123123

124124
bool check_color(uint16_t signalledNumComps);
125125
void apply_channel_definition(void);
126+
void applyChannelDefinitionTypes(void);
127+
bool needsChannelDefinitionSwap(void) const;
126128
void allocPalette(uint8_t num_channels, uint16_t num_entries);
127129
uint32_t width(void) const;
128130
uint32_t height(void) const;

0 commit comments

Comments
 (0)