summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan "Geenz" Goodman <geenz@geenzo.com>2026-05-20 10:20:54 -0400
committerJonathan "Geenz" Goodman <geenz@geenzo.com>2026-05-20 10:20:54 -0400
commit57048769db20f5e84834c8c6dd15466083bd7585 (patch)
tree685d5d7d88aaea6064b49561537bdaeae550db89
parenta4fdf69c2dae9ed5fafe4d292bfb4cd1ce881441 (diff)
Move the KDU data size estimate into j2ckdu, make the base pure virtual.
-rw-r--r--indra/llimage/llimagej2c.cpp26
-rw-r--r--indra/llimage/llimagej2c.h7
-rw-r--r--indra/llkdu/llimagej2ckdu.cpp30
-rw-r--r--indra/llkdu/llimagej2ckdu.h2
-rw-r--r--indra/llkdu/tests/llimagej2ckdu_test.cpp1
5 files changed, 35 insertions, 31 deletions
diff --git a/indra/llimage/llimagej2c.cpp b/indra/llimage/llimagej2c.cpp
index 512b370bae..8099a18045 100644
--- a/indra/llimage/llimagej2c.cpp
+++ b/indra/llimage/llimagej2c.cpp
@@ -265,32 +265,6 @@ S32 LLImageJ2C::calcHeaderSizeJ2C()
return FIRST_PACKET_SIZE; // Hack. just needs to be >= actual header size...
}
-// Lean pyramid-walk byte estimator suited to packet-by-packet decoders (KDU).
-// Starts at one max-block, walks resolutions by doubling area, sums each
-// layer's compressed-bytes contribution.
-// Reference: https://wiki.lindenlab.com/wiki/THX1138_KDU_Improvements#Byte_Range_Study
-S32 LLImageJ2CImpl::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;
- const S32 surface = width * height;
- S32 nb_layers = 1;
- S32 s = MAX_BLOCK_SIZE * MAX_BLOCK_SIZE;
- S32 totalbytes = (S32)(s * max_components * precision * rate);
- while (surface > s)
- {
- if (nb_layers <= (5 - discard_level))
- totalbytes += (S32)(s * max_components * precision * rate);
- nb_layers++;
- s *= 4;
- }
- totalbytes /= 8;
- totalbytes += LLImageJ2C::calcHeaderSizeJ2C();
- return totalbytes;
-}
-
//static
S32 LLImageJ2C::calcDataSizeJ2C(S32 w, S32 h, S32 comp, S32 discard_level, F32 rate)
{
diff --git a/indra/llimage/llimagej2c.h b/indra/llimage/llimagej2c.h
index 5173eed33b..81b24cc0b3 100644
--- a/indra/llimage/llimagej2c.h
+++ b/indra/llimage/llimagej2c.h
@@ -108,10 +108,9 @@ public:
virtual ~LLImageJ2CImpl();
// Estimate the byte size of a J2C codestream sufficient to decode the
- // given discard level. KDU streams packet-by-packet and uses the lean
- // pyramid-walk default. OpenJPEG needs over-allocation to land on
- // code-block boundaries even with strict mode off, so it overrides.
- virtual S32 estimateDataSize(S32 w, S32 h, S32 comp, S32 discard_level, F32 rate) const;
+ // given discard level. KDU uses a packet-by-packet impl; OpenJPEG
+ // overrides with a more conservative block-aligned estimate.
+ virtual S32 estimateDataSize(S32 w, S32 h, S32 comp, S32 discard_level, F32 rate) const = 0;
protected:
// Find out the image size and number of channels.
// Return value:
diff --git a/indra/llkdu/llimagej2ckdu.cpp b/indra/llkdu/llimagej2ckdu.cpp
index e7ac6bdb31..4330b1e5b1 100644
--- a/indra/llkdu/llimagej2ckdu.cpp
+++ b/indra/llkdu/llimagej2ckdu.cpp
@@ -1513,3 +1513,33 @@ void kdc_flow_control::process_components()
}
}
}
+
+// Layer-factored byte estimator. Walks the resolution pyramid to count
+// layers, weights by layer_factor, then picks between a sqrt-based "new"
+// estimate and a raw-dimensions "old" estimate per TextureNewByteRange.
+// Reference: https://wiki.lindenlab.com/wiki/THX1138_KDU_Improvements#Byte_Range_Study
+S32 LLImageJ2CKDU::estimateDataSize(S32 w, S32 h, S32 comp, S32 discard_level, F32 rate) const
+{
+ S32 width = (w > 0) ? w : 2048;
+ S32 height = (h > 0) ? h : 2048;
+ S32 nb_layers = 1;
+ S32 surface = width * height;
+ S32 s = MAX_BLOCK_SIZE * MAX_BLOCK_SIZE;
+ while (surface > s)
+ {
+ nb_layers++;
+ s *= 4;
+ }
+ F32 layer_factor = 3.0f * (7 - llclamp(nb_layers, 1, 6));
+
+ width >>= discard_level;
+ height >>= discard_level;
+ width = llmax(width, 1);
+ height = llmax(height, 1);
+
+ S32 new_bytes = (S32)(sqrtf((F32)(width * height)) * (F32)comp * rate * 1000.f / layer_factor);
+ S32 old_bytes = (S32)((F32)(width * height * comp) * rate);
+ S32 bytes = (LLImage::useNewByteRange() && (new_bytes < old_bytes)) ? new_bytes : old_bytes;
+ bytes = llmax(bytes, LLImageJ2C::calcHeaderSizeJ2C());
+ return bytes;
+}
diff --git a/indra/llkdu/llimagej2ckdu.h b/indra/llkdu/llimagej2ckdu.h
index c9aa0c5250..6079585948 100644
--- a/indra/llkdu/llimagej2ckdu.h
+++ b/indra/llkdu/llimagej2ckdu.h
@@ -67,6 +67,8 @@ protected:
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;
+public:
+ virtual S32 estimateDataSize(S32 w, S32 h, S32 comp, S32 discard_level, F32 rate) const;
private:
bool initDecode(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, ECodeStreamMode mode, S32 first_channel, S32 max_channel_count, int discard_level = -1, int* region = NULL);
diff --git a/indra/llkdu/tests/llimagej2ckdu_test.cpp b/indra/llkdu/tests/llimagej2ckdu_test.cpp
index a016865fcd..bc52a15c4a 100644
--- a/indra/llkdu/tests/llimagej2ckdu_test.cpp
+++ b/indra/llkdu/tests/llimagej2ckdu_test.cpp
@@ -83,7 +83,6 @@ void LLImageBase::setSize(S32 , S32 , S32 ) { }
bool LLImageBase::isBufferInvalid() const { return false; }
LLImageJ2CImpl::~LLImageJ2CImpl() { }
-S32 LLImageJ2CImpl::estimateDataSize(S32, S32, S32, S32, F32) const { return 0; }
LLImageFormatted::LLImageFormatted(S8 ) { }
LLImageFormatted::~LLImageFormatted() { }