summaryrefslogtreecommitdiff
path: root/indra/llimagej2coj
diff options
context:
space:
mode:
authorJonathan "Geenz" Goodman <geenz@lindenlab.com>2026-05-22 13:13:30 -0400
committerGitHub <noreply@github.com>2026-05-22 13:13:30 -0400
commit6b4e3f3288ec1e9917cecd862a7a52945e5b4db2 (patch)
treeeb7f6952eaa5e78326308882db39500a4f149271 /indra/llimagej2coj
parent99ab6316b4ae9058f22d9f57d21e795ca45797fd (diff)
parentdad44ba5d67d04a73708a9a25bbe1ddec29a6a9a (diff)
Merge pull request #5829 from secondlife/geenz/texture-quality
Texture streaming rework
Diffstat (limited to 'indra/llimagej2coj')
-rw-r--r--indra/llimagej2coj/llimagej2coj.cpp29
-rw-r--r--indra/llimagej2coj/llimagej2coj.h19
2 files changed, 41 insertions, 7 deletions
diff --git a/indra/llimagej2coj/llimagej2coj.cpp b/indra/llimagej2coj/llimagej2coj.cpp
index 7cfadb889d..488c07e1c9 100644
--- a/indra/llimagej2coj/llimagej2coj.cpp
+++ b/indra/llimagej2coj/llimagej2coj.cpp
@@ -919,3 +919,32 @@ bool LLImageJ2COJ::getMetadata(LLImageJ2C &base)
base.setSize(width, height, components);
return true;
}
+
+
+// OpenJPEG-tuned byte estimator. Conservative pyramid walk that accounts for
+// OJ's whole-code-block decode behavior (even with strict mode off). Larger
+// images get a per-resolution multiplier so the byte range lands inside the
+// last needed code-block boundary.
+S32 LLImageJ2COJ::estimateDataSize(S32 w, S32 h, S32 comp, S32 discard_level, F32 rate) const
+{
+ constexpr S32 precision = 8;
+ constexpr S32 max_components = 4;
+ S32 width = (w > 0) ? w : 2048;
+ S32 height = (h > 0) ? h : 2048;
+ S32 max_dimension = llmax(width, height);
+ S32 block_area = MAX_BLOCK_SIZE * MAX_BLOCK_SIZE;
+ S32 max_layers = (S32)llmax(llround(log2f((float)max_dimension) - log2f((float)MAX_BLOCK_SIZE)), 4);
+ block_area *= llmax(max_layers, 1);
+ S32 totalbytes = (S32)(MIN_LAYER_SIZE * max_components * precision);
+ S32 block_layers = 0;
+ while (block_layers <= max_layers)
+ {
+ if (block_layers <= (5 - discard_level))
+ totalbytes += (S32)(block_area * max_components * precision * rate);
+ block_layers++;
+ block_area *= 4;
+ }
+ totalbytes /= 8;
+ totalbytes += LLImageJ2C::calcHeaderSizeJ2C();
+ return totalbytes;
+}
diff --git a/indra/llimagej2coj/llimagej2coj.h b/indra/llimagej2coj/llimagej2coj.h
index da49597302..0cc8d5c34c 100644
--- a/indra/llimagej2coj/llimagej2coj.h
+++ b/indra/llimagej2coj/llimagej2coj.h
@@ -35,15 +35,20 @@ class LLImageJ2COJ : public LLImageJ2CImpl
{
public:
LLImageJ2COJ();
- virtual ~LLImageJ2COJ();
+ virtual ~LLImageJ2COJ() override;
protected:
- virtual bool getMetadata(LLImageJ2C &base);
- virtual bool decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, S32 first_channel, S32 max_channel_count);
+ virtual bool getMetadata(LLImageJ2C &base) override;
+ virtual bool decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, S32 first_channel, S32 max_channel_count) override;
virtual bool encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, const char* comment_text, F32 encode_time=0.0,
- bool reversible = false);
- virtual bool initDecode(LLImageJ2C &base, LLImageRaw &raw_image, int discard_level = -1, int* region = NULL);
- virtual bool initEncode(LLImageJ2C &base, LLImageRaw &raw_image, int blocks_size = -1, int precincts_size = -1, int levels = 0);
- virtual std::string getEngineInfo() const;
+ bool reversible = false) override;
+ virtual bool initDecode(LLImageJ2C &base, LLImageRaw &raw_image, int discard_level = -1, int* region = NULL) override;
+ virtual bool initEncode(LLImageJ2C &base, LLImageRaw &raw_image, int blocks_size = -1, int precincts_size = -1, int levels = 0) override;
+ virtual std::string getEngineInfo() const override;
+public:
+ // OpenJPEG decodes whole code-blocks even with strict mode off, so the
+ // lean packet-walk under-allocates and clips quality. Keep the older
+ // conservative pyramid-with-multiplier estimate here.
+ virtual S32 estimateDataSize(S32 w, S32 h, S32 comp, S32 discard_level, F32 rate) const override;
};
#endif