init: 自 zomaintain/backend/rdplib 平移独立成库; module path 从上游 github.com/nakagami/grdp 改为 git.zeroonesoft.cn/golib/rdplib

This commit is contained in:
w11
2026-09-19 18:55:43 +08:00
commit 1096fbce9d
94 changed files with 36790 additions and 0 deletions
+221
View File
@@ -0,0 +1,221 @@
package rdpgfx
// Standard RemoteFX (MS-RDPRFX) codec helpers shared with rfx.go.
// Extracted from the progressive decoder rewrite; algorithms unchanged.
func rfxGetQuant(quants []rfxQuant, idx int) rfxQuant {
if idx < len(quants) {
return quants[idx]
}
return rfxQuant{6, 6, 6, 6, 6, 6, 6, 6, 6, 6}
}
// rfxDecodeComponent decodes one color component (Y, Cb, or Cr) for a 64×64 tile.
// The returned slice is backed by a *coeffArr from coeffPool; the caller must
// return it via coeffPool.Put((*coeffArr)(result)) when done.
func rfxDecodeComponent(data []byte, quant rfxQuant, rlgrMode int) []int16 {
const tilePixels = rfxTileSize * rfxTileSize // 4096
// Get a pooled coefficient buffer. The pool stores *coeffArr (pointer to a
// fixed-size array) so the any interface stores a single pointer word with no
// heap-boxing allocation.
arr := coeffPool.Get().(*coeffArr)
coeffs := arr[:]
if data == nil {
clear(coeffs)
return coeffs
}
// 1. RLGR entropy decode → 4096 coefficients
if rlgrMode == 3 {
coeffs = rlgr3Decode(data, tilePixels, coeffs)
} else {
coeffs = rlgr1Decode(data, tilePixels, coeffs)
}
// 2. Differential decode LL3 and dequantize LL3 in a single pass.
// Mathematical identity: cumsum(x) * 2^s == cumsum_of(x * 2^s)
// so we can left-shift each element before accumulating.
if quant.LL3 > 1 {
shift := quant.LL3 - 1
coeffs[4032] <<= shift
for i := 4033; i < 4096; i++ {
coeffs[i] = coeffs[i-1] + coeffs[i]<<shift
}
} else {
for i := 4033; i < 4096; i++ {
coeffs[i] += coeffs[i-1]
}
}
// 3. Dequantize all subbands except LL3 (handled above)
rfxDequantizeSkipLL3(coeffs, quant)
// 4. Inverse DWT (3 levels)
rfxInverseDWT2D(coeffs)
return coeffs
}
// rfxDequantizeSkipLL3 applies dequantization per subband, skipping LL3
// (which is handled together with differential decode in rfxDecodeComponent).
func rfxDequantizeSkipLL3(coeffs []int16, q rfxQuant) {
rfxShiftSubband(coeffs[0:1024], q.HL1) // HL1
rfxShiftSubband(coeffs[1024:2048], q.LH1) // LH1
rfxShiftSubband(coeffs[2048:3072], q.HH1) // HH1
rfxShiftSubband(coeffs[3072:3328], q.HL2) // HL2
rfxShiftSubband(coeffs[3328:3584], q.LH2) // LH2
rfxShiftSubband(coeffs[3584:3840], q.HH2) // HH2
rfxShiftSubband(coeffs[3840:3904], q.HL3) // HL3
rfxShiftSubband(coeffs[3904:3968], q.LH3) // LH3
rfxShiftSubband(coeffs[3968:4032], q.HH3) // HH3
}
// rfxInverseDWT2D performs 3-level inverse 2D discrete wavelet transform in-place.
// Buffer layout: [HL1(1024)|LH1(1024)|HH1(1024)|HL2(256)|LH2(256)|HH2(256)|HL3(64)|LH3(64)|HH3(64)|LL3(64)]
// A single temporary buffer is obtained from the pool and reused across all three
// levels, reducing pool pressure from 9 Get/Put calls (3 levels × 3 components) to 3.
func rfxInverseDWT2D(coeffs []int16) {
bufs := idwtBufPool.Get().(*idwtBufs)
// Level 3: 8×8 subbands → 16×16 output (needs 16×16 = 256 elements)
rfxIDWT2DLevel(coeffs[3840:], bufs.tmp[:256], 8)
// Level 2: 16×16 subbands → 32×32 output (needs 32×32 = 1024 elements)
rfxIDWT2DLevel(coeffs[3072:], bufs.tmp[:1024], 16)
// Level 1: 32×32 subbands → 64×64 output (needs 64×64 = 4096 elements)
rfxIDWT2DLevel(coeffs[0:], bufs.tmp[:4096], 32)
idwtBufPool.Put(bufs)
}
// rfxIDWT2DLevel performs one level of inverse 2D DWT.
// buf contains [HL(n²)|LH(n²)|HH(n²)|LL(n²)] and is replaced with the (2n)×(2n) result.
// tmp is a caller-supplied scratch buffer of length (2n)² (must be ≥ 4n² elements).
// Uses the MS-RDPRFX lifting scheme. Order: horizontal IDWT first, then vertical.
func rfxIDWT2DLevel(buf, tmp []int16, n int) {
nn := n * n
size := 2 * n
// Read subbands directly from buf — no copy needed because the horizontal
// pass only reads from them and writes exclusively to tmp.
hl := buf[0:nn]
lh := buf[nn : 2*nn]
hh := buf[2*nn : 3*nn]
ll := buf[3*nn : 4*nn]
// Step 1: Horizontal IDWT on each row (fused even+odd passes).
// Instead of two separate loops — even pass writing to tmp, then odd pass
// re-reading those values — we keep the last even value in a register and
// compute the preceding odd value in the same iteration. This eliminates
// 2*(n-1) reads of tmp per row (one even[col-1] and one even[col] per odd
// position), replacing them with register references.
// Valid sizes in practice: n = 8, 16, 32.
for row := range n {
rowOff := row * n
lDstOff := row * size
hDstOff := (row + n) * size
// col=0: even boundary (no left neighbour, hl[-1] = hl[0]).
prevEvenL := ll[rowOff] - int16((int32(hl[rowOff])*2+1)>>1)
prevEvenH := lh[rowOff] - int16((int32(hh[rowOff])*2+1)>>1)
tmp[lDstOff] = prevEvenL
tmp[hDstOff] = prevEvenH
// col=1..n-1: compute even[col], then immediately compute odd[col-1]
// using prevEven (=even[col-1], still in register) and the just-computed
// even[col] — no re-read of tmp required.
for col := 1; col < n; col++ {
x := col << 1
evenL := ll[rowOff+col] - int16((int32(hl[rowOff+col-1])+int32(hl[rowOff+col])+1)>>1)
evenH := lh[rowOff+col] - int16((int32(hh[rowOff+col-1])+int32(hh[rowOff+col])+1)>>1)
tmp[lDstOff+x-1] = int16((int32(hl[rowOff+col-1])<<1) + ((int32(prevEvenL)+int32(evenL))>>1))
tmp[hDstOff+x-1] = int16((int32(hh[rowOff+col-1])<<1) + ((int32(prevEvenH)+int32(evenH))>>1))
tmp[lDstOff+x] = evenL
tmp[hDstOff+x] = evenH
prevEvenL = evenL
prevEvenH = evenH
}
// last odd[n-1]: right boundary, even[n] = even[n-1].
x := (n - 1) << 1
tmp[lDstOff+x+1] = int16((int32(hl[rowOff+n-1])<<1) + int32(prevEvenL))
tmp[hDstOff+x+1] = int16((int32(hh[rowOff+n-1])<<1) + int32(prevEvenH))
}
// Step 2: Vertical IDWT on each column.
// Process 8 columns at a time to improve cache utilisation — a cache line
// holds 32 int16 values; 8 columns keeps the working set within one or two
// lines per row access. All valid sizes (16, 32, 64) divide evenly by 8,
// so the scalar tail loop is never reached in practice.
const blk = 8
col := 0
for ; col+blk <= size; col += blk {
// Row 0: first even output (no previous odd)
l0 := tmp[col : col+blk]
h0 := tmp[n*size+col : n*size+col+blk]
out0 := buf[col : col+blk]
for b := range blk {
out0[b] = int16(int32(l0[b]) - ((int32(h0[b])*2 + 1) >> 1))
}
// Rows 1..n-1: interleaved even/odd outputs
for row := 1; row < n; row++ {
lBase := row*size + col
hBase := (row+n)*size + col
hPrevBase := (row-1+n)*size + col
evenBase := 2*row*size + col
prevEvenBase := (2*row-2)*size + col
oddBase := (2*row-1)*size + col
l := tmp[lBase : lBase+blk]
h := tmp[hBase : hBase+blk]
hPrev := tmp[hPrevBase : hPrevBase+blk]
evenOut := buf[evenBase : evenBase+blk]
prevEvenIn := buf[prevEvenBase : prevEvenBase+blk]
oddOut := buf[oddBase : oddBase+blk]
for b := range blk {
hPrevV := int32(hPrev[b])
even := int32(l[b]) - ((hPrevV + int32(h[b]) + 1) >> 1)
evenOut[b] = int16(even)
oddOut[b] = int16((hPrevV << 1) + ((int32(prevEvenIn[b]) + even) >> 1))
}
}
// Last odd row
lastEvenBase := (2*n-2)*size + col
lastHBase := (2*n-1)*size + col
lastEvenSlice := buf[lastEvenBase : lastEvenBase+blk]
lastHSlice := tmp[lastHBase : lastHBase+blk]
lastOddOut := buf[lastHBase : lastHBase+blk]
for b := range blk {
lastOddOut[b] = int16((int32(lastHSlice[b]) << 1) + int32(lastEvenSlice[b]))
}
}
for ; col < size; col++ {
lVal := int32(tmp[col])
hVal := int32(tmp[n*size+col])
buf[col] = int16(lVal - ((hVal*2 + 1) >> 1))
for row := 1; row < n; row++ {
lIdx := row*size + col
hIdx := (row+n)*size + col
hPrevIdx := (row-1+n)*size + col
even := int32(tmp[lIdx]) - ((int32(tmp[hPrevIdx]) + int32(tmp[hIdx]) + 1) >> 1)
buf[2*row*size+col] = int16(even)
prevEven := int32(buf[(2*row-2)*size+col])
odd := (int32(tmp[hPrevIdx]) << 1) + ((prevEven + even) >> 1)
buf[(2*row-1)*size+col] = int16(odd)
}
lastEven := int32(buf[(2*n-2)*size+col])
lastH := int32(tmp[(2*n-1)*size+col])
buf[(2*n-1)*size+col] = int16((lastH << 1) + lastEven)
}
}
func rfxShiftSubband(data []int16, factor uint8) {
if factor <= 1 {
return
}
shift := factor - 1
for i := range data {
data[i] <<= shift
}
}