Skip to content

Commit 84dff83

Browse files
libretroadminLibretroAdmin
authored andcommitted
ropus: move the frame-decode buffers off the decode stack
ropus_decode_frame_f carried pcm_silk (11,520 bytes), bl/br (3,840) and the redundancy buffer (1,920) as locals -- a 15,680-byte frame by -fstack-usage, nested directly above ropus_celt_decode's own (still larger) frame on the audio/task thread. The s16 twin carried bl/br and its redundancy buffer the same way, inlined into ropus_decode_s16 for a 4,832-byte frame. Move them into a ropus_frame_scratch embedded in ropus_t, one per decoder context, passed into both decode-frame functions. Per context and not static for the reason the sub_q/sub_f comment in the struct already gives: the mixer runs several voices at once. One scratch per context is enough for any stream count because the substream loop decodes sequentially, so multistream contexts do not multiply the cost. ropus_t is heap-allocated (calloc in ropus_open), so the storage moves from a thread stack to the heap where it belongs; ropus_dec_f/ropus_dec_q themselves are unchanged. Frame sizes after: ropus_decode_f32 992 bytes, ropus_decode_s16 976 (the decode-frame layer now inlines into them entirely). Worst-case decode stack depth drops from ~20.5 KB + the CELT frame to ~1 KB + the CELT frame; ropus_celt_decode's 28,256/18,688-byte frames remain and are the larger half of the problem, left for a dedicated change. Decoded output verified bit-identical against the previous code over both pipelines for three stream shapes: a CELT-mode music encode, a pure-SILK 8 kb/s speech encode (151 SILK packets -- the mode that actually exercises pcm_silk/bl/br), and a hybrid-mode 24 kb/s encode (151 hybrid packets, covering the SILK+CELT redundancy path). FNV-1a over all decoded PCM, six checksum pairs, all exact matches.
1 parent a52f6c7 commit 84dff83

1 file changed

Lines changed: 34 additions & 9 deletions

File tree

  • libretro-common/formats/opus

libretro-common/formats/opus/ropus.c

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10056,7 +10056,28 @@ static void ropus_smooth_fade_q(const int16_t *in1, const int16_t *in2,
1005610056
/* Decode one frame of an Opus packet. data/len cover the frame's
1005710057
* bytes; toc_* give the packet TOC properties. pcm receives
1005810058
* frame_size48 interleaved s16 samples at 48 kHz. */
10059-
static int ropus_decode_frame_q(ropus_dec_q *st, const uint8_t *data,
10059+
/* Frame-decode scratch, one per decoder context (embedded in ropus_t
10060+
* below). These lived on the decode-frame stacks: pcm_silk alone is
10061+
* 11.5 KB, and with bl/br and the redundancy buffer the float frame
10062+
* measured 15,680 bytes by -fstack-usage -- nested above
10063+
* ropus_celt_decode's own (still larger) frame on the audio thread.
10064+
* Per context and not static for the same reason as sub_q/sub_f:
10065+
* the mixer runs several voices at once. The substream loop is
10066+
* sequential, so one scratch per context serves every substream. */
10067+
typedef struct
10068+
{
10069+
int16_t pcm_silk[2880 * 2];
10070+
int16_t bl[960];
10071+
int16_t br[960];
10072+
union
10073+
{
10074+
float f[240 * 2];
10075+
int16_t q[240 * 2];
10076+
} redundant;
10077+
} ropus_frame_scratch;
10078+
10079+
static int ropus_decode_frame_q(ropus_dec_q *st,
10080+
ropus_frame_scratch *scr, const uint8_t *data,
1006010081
int32_t len, int16_t *pcm, int frame_size48, int mode,
1006110082
int bandwidth, int stream_channels, int nfp, int newPacket)
1006210083
{
@@ -10066,7 +10087,7 @@ static int ropus_decode_frame_q(ropus_dec_q *st, const uint8_t *data,
1006610087
int start_band = 0;
1006710088
int F2_5 = 120, F5 = 240, F20 = 960;
1006810089
int celt_accum;
10069-
int16_t redundant_audio[240 * 2];
10090+
int16_t *redundant_audio = scr->redundant.q;
1007010091
int celt_ret = 0;
1007110092

1007210093
st->stream_channels = stream_channels;
@@ -10090,7 +10111,8 @@ static int ropus_decode_frame_q(ropus_dec_q *st, const uint8_t *data,
1009010111
/* unsupported (never emitted)*/
1009110112
memset(pcm, 0, audiosize * st->channels * sizeof(int16_t));
1009210113
{
10093-
int16_t bl[960], br[960];
10114+
int16_t *bl = scr->bl;
10115+
int16_t *br = scr->br;
1009410116
int fr, done = 0;
1009510117
for (fr = 0; fr < nfp; fr++)
1009610118
{
@@ -10275,7 +10297,8 @@ static void ropus_smooth_fade(const float *in1, const float *in2,
1027510297
}
1027610298
}
1027710299

10278-
static int ropus_decode_frame_f(ropus_dec_f *st, const uint8_t *data,
10300+
static int ropus_decode_frame_f(ropus_dec_f *st,
10301+
ropus_frame_scratch *scr, const uint8_t *data,
1027910302
int32_t len, float *pcm, int frame_size48, int mode,
1028010303
int bandwidth, int stream_channels, int nfp, int newPacket)
1028110304
{
@@ -10284,8 +10307,8 @@ static int ropus_decode_frame_f(ropus_dec_f *st, const uint8_t *data,
1028410307
int redundancy = 0, redundancy_bytes = 0, celt_to_silk = 0;
1028510308
int start_band = 0;
1028610309
int F2_5 = 120, F5 = 240, F20 = 960;
10287-
float redundant_audio[240 * 2];
10288-
int16_t pcm_silk[2880 * 2];
10310+
float *redundant_audio = scr->redundant.f;
10311+
int16_t *pcm_silk = scr->pcm_silk;
1028910312
int have_silk = 0, silk_n = 0;
1029010313
int celt_ret = 0;
1029110314

@@ -10295,7 +10318,8 @@ static int ropus_decode_frame_f(ropus_dec_f *st, const uint8_t *data,
1029510318
if (mode != ROPUS_MODE_CELT)
1029610319
{
1029710320
int fs_khz, nb_subfr;
10298-
int16_t bl[960], br[960];
10321+
int16_t *bl = scr->bl;
10322+
int16_t *br = scr->br;
1029910323
int fr;
1030010324
if (st->prev_mode == ROPUS_MODE_CELT)
1030110325
ropus_silk2_init(&st->silk);
@@ -10470,6 +10494,7 @@ struct ropus
1047010494
* caller's buffer, as it always did. */
1047110495
int16_t *sub_q; /* 5760 * 2, or NULL */
1047210496
float *sub_f;
10497+
ropus_frame_scratch fscr;
1047310498
};
1047410499

1047510500
/* Where a substream's channels land in the decoded (pre-mapping)
@@ -10671,7 +10696,7 @@ int ropus_decode_s16(ropus_t *o, const void *pkt, size_t len,
1067110696
ropus_toc_props(d[0], &mode, &bw, &nfp);
1067210697
for (fr = 0; fr < pk.nframes; fr++)
1067310698
{
10674-
int r = ropus_decode_frame_q(&o->q[s], pk.frames[fr],
10699+
int r = ropus_decode_frame_q(&o->q[s], &o->fscr, pk.frames[fr],
1067510700
pk.sizes[fr], sub + got * sch, pk.frame_size, mode, bw,
1067610701
(d[0] & 4) ? 2 : 1, nfp, 1);
1067710702
if (r <= 0)
@@ -10751,7 +10776,7 @@ int ropus_decode_f32(ropus_t *o, const void *pkt, size_t len,
1075110776
ropus_toc_props(d[0], &mode, &bw, &nfp);
1075210777
for (fr = 0; fr < pk.nframes; fr++)
1075310778
{
10754-
int r = ropus_decode_frame_f(&o->f[s], pk.frames[fr],
10779+
int r = ropus_decode_frame_f(&o->f[s], &o->fscr, pk.frames[fr],
1075510780
pk.sizes[fr], sub + got * sch, pk.frame_size, mode, bw,
1075610781
(d[0] & 4) ? 2 : 1, nfp, 1);
1075710782
if (r <= 0)

0 commit comments

Comments
 (0)