Match JPEG Decoder

This commit is contained in:
Diamond Lewis 2026-07-29 19:56:56 -05:00
parent dac7dad9ef
commit 29db87408b
10 changed files with 287 additions and 282 deletions

View File

@ -564,6 +564,11 @@ D_30CD490 = 0x30CD490;
D_30CD510 = 0x30CD510;
D_8250A288 = 0x8250A288; // size:0xA
D_800A62E0 = 0x800A62E0; // defined:true size:0xA40
sJpegBitStreamPtr = 0x800A82D0; // defined:true size:0x4
sJpegBitStreamByteIdx = 0x800A82D4; // defined:true size:0x4
sJpegBitStreamBitIdx = 0x800A82D8; // defined:true size:0x1
sJpegBitStreamDontSkip = 0x800A82D9; // defined:true size:0x1
sJpegBitStreamCurWord = 0x800A82DC; // defined:true size:0x4
D_800A8320 = 0x800A8320; // size:0x74
D_800AA688 = 0x800AA688;
D_80072B00 = 0x80072B00; // size:0x3DE

View File

@ -310,13 +310,13 @@ JpegUtils_ParseHuffmanCodesLengths = 0x8000BDD8; // type:func
JpegUtils_GetHuffmanCodes = 0x8000BE5C; // type:func
JpegUtils_SetHuffmanTable = 0x8000BEC8; // type:func
JpegUtils_ProcessHuffmanTableImpl = 0x8000BF70; // type:func
func_8000C02C = 0x8000C02C; // type:func
JpegUtils_ProcessHuffmanTable = 0x8000C02C; // type:func
JpegUtils_SetHuffmanTableOld = 0x8000C104; // type:func
JpegUtils_ProcessHuffmanTableImplOld = 0x8000C1AC; // type:func
func_8000C280 = 0x8000C280; // type:func
func_8000C4A8 = 0x8000C4A8; // type:func
func_8000C644 = 0x8000C644; // type:func
func_8000C780 = 0x8000C780; // type:func
JpegDecoder_Decode = 0x8000C280; // type:func
JpegDecoder_ProcessMcu = 0x8000C4A8; // type:func
JpegDecoder_ParseNextSymbol = 0x8000C644; // type:func
JpegDecoder_ReadBits = 0x8000C780; // type:func
func_8000C870 = 0x8000C870; // type:func
func_8000C8F8 = 0x8000C8F8; // type:func
func_8000CA4C = 0x8000CA4C; // type:func

View File

@ -119,15 +119,15 @@ void func_80003558(UnkStruct80001380* arg0, unk_func_80003680_sp90* arg1) {
osCreateMesgQueue(&arg0->queue, &arg0->mesg, 1);
}
void func_80003608(unk_func_80003680_sp27* arg0, JpegHuffmanTable* arg1, unk_func_80003680_sp300* arg2) {
arg0->unk_00 = arg2->start_of_scan;
arg0->unk_04 = arg2->unk_00;
arg0->unk_05 = 2;
arg0->unk_08 = &arg1[0];
arg0->unk_0C = &arg1[2];
arg0->unk_10 = &arg1[1];
arg0->unk_14 = &arg1[3];
arg0->unk_18 = arg2->unk_01;
void func_80003608(JpegDecoder* decoder, JpegHuffmanTable* hTable, unk_func_80003680_sp300* arg2) {
decoder->imageData = arg2->start_of_scan;
decoder->mode = arg2->unk_00;
decoder->unk_05 = 2;
decoder->hTablePtrs[0] = &hTable[0];
decoder->hTablePtrs[1] = &hTable[2];
decoder->hTablePtrs[2] = &hTable[1];
decoder->hTablePtrs[3] = &hTable[3];
decoder->unk_18 = arg2->unk_01;
}
void func_80003648(unk_func_80003680_sp90* arg0, u8(arg1)[2][0x80], unk_func_80003680_sp300* arg2) {
@ -147,8 +147,8 @@ s32 func_80003680(u32 addr, s32 arg1, u8* arg2) {
u16* temp_s0;
u8* temp_s3;
unk_func_80003680_sp90 sp90;
unk_func_80003680_sp27 sp74;
unk_func_80003680_sp60 sp60;
JpegDecoder sp74;
JpegDecoderState sp60;
u32 var_s1;
s32 i;
s32 j;
@ -177,7 +177,7 @@ s32 func_80003680(u32 addr, s32 arg1, u8* arg2) {
return 0;
}
if (func_8000C280(&sp74, addr, 1, var_s4, &sp60) != 0) {
if (JpegDecoder_Decode(&sp74, addr, 1, var_s4, &sp60) != 0) {
return 0;
}

View File

@ -4,7 +4,7 @@
#include "global.h"
#include "5580.h"
#include "jpegutils.h"
#include "CE80.h"
#include "jpeg_decoder.h"
#include "src/memmap.h"
#include "src/memory.h"
@ -62,7 +62,7 @@ typedef struct unk_func_800041C0 {
} unk_func_800041C0; // size >= 0x8
typedef struct unk_func_80003680_sp300 {
/* 0x00 */ u8 unk_00;
/* 0x00 */ u8 unk_00; // mode
/* 0x01 */ u8 unk_01;
/* 0x02 */ char unk02[0x2];
/* 0x04 */ s16 width;
@ -87,7 +87,7 @@ typedef void (*ret_func_80004454)(void);
s32 func_800033B0(u8* arg0);
void func_800033C8(unk_func_80003680_sp300* arg0, u8* arg1);
void func_80003558(UnkStruct80001380* arg0, unk_func_80003680_sp90* arg1);
void func_80003608(unk_func_80003680_sp27* arg0, JpegHuffmanTable* arg1, unk_func_80003680_sp300* arg2);
void func_80003608(JpegDecoder* arg0, JpegHuffmanTable* arg1, unk_func_80003680_sp300* arg2);
void func_80003648(unk_func_80003680_sp90* arg0, u8(arg1)[2][0x80], unk_func_80003680_sp300* arg2);
s32 func_80003680(u32 addr, s32 arg1, u8* arg2);
void func_80003860(void);

View File

@ -1,226 +0,0 @@
#include "CE80.h"
extern u8* D_800A82D0;
extern s32 D_800A82D4;
extern u8 D_800A82D8;
extern u8 D_800A82D9;
extern u32 D_800A82DC;
#ifdef NON_MATCHING
s32 func_8000C280(unk_func_80003680_sp27* arg0, u32 arg1, u32 arg2, u8 arg3, unk_func_80003680_sp60* arg4) {
u16 var_v0;
s16 sp64;
s16 sp62;
s16 sp60;
u32 i;
s32 sp58;
JpegHuffmanTable* temp_fp;
JpegHuffmanTable* temp_s4;
JpegHuffmanTable* temp_s5;
JpegHuffmanTable* temp_s7;
sp58 = 0;
D_800A82D0 = arg0->unk_00;
if (arg0->unk_04 == 0) {
var_v0 = 2;
} else {
var_v0 = 4;
if (arg0->unk_05 == 1) {
sp58 = 0x80;
}
}
temp_s4 = arg0->unk_08;
temp_s5 = arg0->unk_0C;
temp_s7 = arg0->unk_10;
temp_fp = arg0->unk_14;
if (arg3 == 0) {
D_800A82D4 = 0;
D_800A82D8 = 0x20;
D_800A82DC = 0;
D_800A82D9 = 0;
sp64 = 0;
sp62 = 0;
sp60 = 0;
} else {
D_800A82D4 = arg4->unk_00;
D_800A82D8 = arg4->unk_04;
D_800A82DC = arg4->unk_08;
D_800A82D9 = arg4->unk_05;
sp64 = arg4->unk_0C;
sp62 = arg4->unk_0E;
sp60 = arg4->unk_10;
}
while (arg2) {
for (i = 0; i < var_v0; i++) {
if (func_8000C4A8(temp_s4, temp_s5, arg1, &sp64) != 0) {
return 2;
}
arg1 += 0x80;
}
if (func_8000C4A8(temp_s7, temp_fp, arg1, &sp62) != 0) {
return 2;
}
arg1 += 0x80;
if (func_8000C4A8(temp_s7, temp_fp, arg1, &sp60) != 0) {
return 2;
}
arg2--;
arg1 += 0x80;
arg1 += (sp58 * 2);
}
arg4->unk_00 = D_800A82D4;
arg4->unk_04 = D_800A82D8;
arg4->unk_08 = D_800A82DC;
arg4->unk_05 = D_800A82D9;
arg4->unk_0C = sp64;
arg4->unk_0E = sp62;
arg4->unk_10 = sp60;
return 0;
}
#else
#pragma GLOBAL_ASM("asm/us/nonmatchings/CE80/func_8000C280.s")
#endif
#ifdef NON_MATCHING
s32 func_8000C4A8(JpegHuffmanTable* arg0, JpegHuffmanTable* arg1, s16* arg2, s16* arg3) {
s8 i;
s8 sp36;
s16 sp34;
u32 test;
if (func_8000C644(arg0, &sp34, &sp36) != 0) {
return 1;
}
*arg3 += sp34;
*arg2 = *arg3;
i = 1;
while (i < 0x40) {
if (func_8000C644(arg1, &sp34, &sp36) != 0) {
return 1;
}
if (sp34 == 0) {
if (sp36 == 0xF) {
while (sp36 >= 0) {
sp36--;
arg2[i++] = 0;
}
continue;
}
while (i < 0x40) {
arg2[i++] = 0;
}
break;
}
while (sp36-- > 0) {
arg2[i++] = 0;
}
arg2[i++] = sp34;
}
return 0;
}
#else
#pragma GLOBAL_ASM("asm/us/nonmatchings/CE80/func_8000C4A8.s")
#endif
typedef struct sp24_func_8000C644 {
u16 unk_00;
u8 unk_02;
} sp24_func_8000C644;
#ifdef NON_MATCHING
s32 func_8000C644(JpegHuffmanTable* arg0, s16* arg1, s8* arg2) {
u8 i;
sp24_func_8000C644 sp24;
s16 temp_v0;
sp24.unk_00 = 0;
temp_v0 = func_8000C780(0x10);
for (i = 0; i < 16; i++) {
sp24.unk_00 = temp_v0 >> (0xF - i);
if ((arg0->codesB[i] != 0xFFFF) && !(arg0->codesB[i] < sp24.unk_00)) {
break;
}
}
if (i >= 16) {
return 1;
}
sp24.unk_02 = *(u8*)(((arg0->codeOffs[i] + sp24.unk_00) - arg0->codesA[i]) + arg0->symbols);
*arg2 = sp24.unk_02 >> 4;
D_800A82D8 = (D_800A82D8 + i) - 0xF;
*arg1 = 0;
if ((sp24.unk_02 & 0xF) != 0) {
sp24.unk_02 &= 0xF;
*arg1 = func_8000C780(sp24.unk_02);
if (*arg1 < (1 << (sp24.unk_02 + 0x1F))) {
*arg1 += (-1 << sp24.unk_02) + 1;
}
}
return 0;
}
#else
#pragma GLOBAL_ASM("asm/us/nonmatchings/CE80/func_8000C644.s")
#endif
#ifdef NON_MATCHING
u16 func_8000C780(u8 arg0) {
u8 var_v0;
u8 var_v1;
u32 ret;
var_v0 = D_800A82D8 >> 3;
while (var_v0 > 0) {
var_v1 = D_800A82D0[D_800A82D4++];
if ((D_800A82D9 != 0) && (var_v1 == 0)) {
var_v1 = D_800A82D0[D_800A82D4++];
}
if (var_v1 == 0xFF) {
D_800A82D9 = 1;
} else {
D_800A82D9 = 0;
}
D_800A82DC <<= 8;
D_800A82DC |= var_v1;
D_800A82D8 -= 8;
var_v0--;
}
ret = (D_800A82DC << D_800A82D8);
D_800A82D8 += arg0;
ret >>= -arg0;
return ret;
}
#else
#pragma GLOBAL_ASM("asm/us/nonmatchings/CE80/func_8000C780.s")
#endif

View File

@ -1,33 +0,0 @@
#ifndef _CE80_H_
#define _CE80_H_
#include "global.h"
#include "jpegutils.h"
typedef struct unk_func_80003680_sp27 {
/* 0x00 */ s32 unk_00;
/* 0x04 */ u8 unk_04;
/* 0x05 */ u8 unk_05;
/* 0x08 */ JpegHuffmanTable* unk_08;
/* 0x0C */ JpegHuffmanTable* unk_0C;
/* 0x10 */ JpegHuffmanTable* unk_10;
/* 0x14 */ JpegHuffmanTable* unk_14;
/* 0x18 */ s8 unk_18;
} unk_func_80003680_sp27; // size == 0x1C
typedef struct unk_func_80003680_sp60 {
/* 0x00 */ s32 unk_00;
/* 0x04 */ u8 unk_04;
/* 0x05 */ u8 unk_05;
/* 0x08 */ s32 unk_08;
/* 0x0C */ s16 unk_0C;
/* 0x0E */ s16 unk_0E;
/* 0x10 */ s16 unk_10;
} unk_func_80003680_sp60; // size = 0x14
s32 func_8000C280(unk_func_80003680_sp27*, u32, u32, u8, unk_func_80003680_sp60*);
s32 func_8000C4A8(JpegHuffmanTable*, JpegHuffmanTable*, s16*, s16*);
s32 func_8000C644(JpegHuffmanTable*, s16*, s8*);
u16 func_8000C780(u8);
#endif // _CE80_H_

191
src/jpeg_decoder.c Normal file
View File

@ -0,0 +1,191 @@
#include "jpegutils.h"
#include "jpeg_decoder.h"
u8* sJpegBitStreamPtr;
u32 sJpegBitStreamByteIdx;
u8 sJpegBitStreamBitIdx;
u8 sJpegBitStreamDontSkip;
u32 sJpegBitStreamCurWord;
s32 JpegDecoder_Decode(JpegDecoder* decoder, u16* mcuBuff, s32 count, u8 isFollowing, JpegDecoderState* state) {
s16 pad;
s16 unk0;
s16 unk1;
s16 unk2;
u32 idx;
s32 inc;
u16 unkCount;
JpegHuffmanTable* hTable0;
JpegHuffmanTable* hTable1;
JpegHuffmanTable* hTable2;
JpegHuffmanTable* hTable3;
inc = 0;
sJpegBitStreamPtr = decoder->imageData;
if (decoder->mode == 0) {
unkCount = 2;
} else {
unkCount = 4;
if (decoder->unk_05 == 1) {
inc = 8 * 8 * 2;
}
}
hTable0 = decoder->hTablePtrs[0];
hTable1 = decoder->hTablePtrs[1];
hTable2 = decoder->hTablePtrs[2];
hTable3 = decoder->hTablePtrs[3];
if (!isFollowing) {
sJpegBitStreamByteIdx = 0;
sJpegBitStreamBitIdx = 32;
sJpegBitStreamCurWord = 0;
sJpegBitStreamDontSkip = 0;
unk0 = 0;
unk1 = 0;
unk2 = 0;
} else {
sJpegBitStreamByteIdx = state->byteIdx;
sJpegBitStreamBitIdx = state->bitIdx;
sJpegBitStreamCurWord = state->curWord;
sJpegBitStreamDontSkip = state->dontSkip;
unk0 = state->unk_0C;
unk1 = state->unk_0E;
unk2 = state->unk_10;
}
while (count != 0) {
for (idx = 0; idx < unkCount; idx++) {
if (JpegDecoder_ProcessMcu(hTable0, hTable1, mcuBuff, &unk0)) {
return 2;
}
mcuBuff += 8 * 8;
}
if (JpegDecoder_ProcessMcu(hTable2, hTable3, mcuBuff, &unk1)) {
return 2;
}
mcuBuff += 8 * 8;
if (JpegDecoder_ProcessMcu(hTable2, hTable3, mcuBuff, &unk2)) {
return 2;
}
count--;
mcuBuff += 8 * 8;
mcuBuff += inc;
}
state->byteIdx = sJpegBitStreamByteIdx;
state->bitIdx = sJpegBitStreamBitIdx;
state->curWord = sJpegBitStreamCurWord;
state->dontSkip = sJpegBitStreamDontSkip;
state->unk_0C = unk0;
state->unk_0E = unk1;
state->unk_10 = unk2;
return 0;
}
s32 JpegDecoder_ProcessMcu(JpegHuffmanTable* hTable0, JpegHuffmanTable* hTable1, u16* mcu, s16* unk) {
s8 i = 0;
s8 zeroCount;
s16 coeff;
if (JpegDecoder_ParseNextSymbol(hTable0, &coeff, &zeroCount)) {
return 1;
}
*unk += coeff;
mcu[i++] = *unk;
while (i < 8 * 8) {
if (JpegDecoder_ParseNextSymbol(hTable1, &coeff, &zeroCount) != 0) {
return 1;
}
if (coeff == 0) {
if (zeroCount == 0xF) {
while (zeroCount-- >= 0) {
mcu[i++] = 0;
}
} else {
while (i < 8 * 8) {
mcu[i++] = 0;
}
break;
}
} else {
while (0 < zeroCount--) {
mcu[i++] = 0;
}
mcu[i++] = coeff;
}
}
return 0;
}
s32 JpegDecoder_ParseNextSymbol(JpegHuffmanTable* hTable, s16* outCoeff, s8* outZeroCount) {
u8 codeIdx;
u8 sym;
u16 codeOff = 0;
u16 buff = JpegDecoder_ReadBits(16);
for (codeIdx = 0; codeIdx < 16; codeIdx++) {
if (hTable->codesB[codeIdx] == 0xFFFF) {
continue;
}
codeOff = buff >> (15 - codeIdx);
if (codeOff <= hTable->codesB[codeIdx]) {
break;
}
}
if (codeIdx >= 16) {
return 1;
}
sym = hTable->symbols[hTable->codeOffs[codeIdx] + codeOff - hTable->codesA[codeIdx]];
*outZeroCount = sym >> 4;
sym &= 0xF;
sJpegBitStreamBitIdx += codeIdx - 15;
*outCoeff = 0;
if (sym) {
*outCoeff = JpegDecoder_ReadBits(sym);
if (*outCoeff < (1 << (sym - 1))) {
*outCoeff += (-1U << sym) + 1;
}
}
return 0;
}
u16 JpegDecoder_ReadBits(u8 len) {
u8 byteCount;
u8 data;
s32 ret = 0;
u32 temp;
for (byteCount = sJpegBitStreamBitIdx >> 3; byteCount > 0; byteCount--) {
data = sJpegBitStreamPtr[sJpegBitStreamByteIdx++];
if (sJpegBitStreamDontSkip) {
if (data == 0) {
data = sJpegBitStreamPtr[sJpegBitStreamByteIdx++];
}
}
sJpegBitStreamDontSkip = (data == 0xFF) ? 1 : 0;
sJpegBitStreamCurWord <<= 8;
sJpegBitStreamCurWord |= data;
sJpegBitStreamBitIdx -= 8;
}
ret = sJpegBitStreamCurWord << sJpegBitStreamBitIdx;
temp = ret;
ret = temp >> -len;
sJpegBitStreamBitIdx += len;
return ret;
}

67
src/jpeg_decoder.h Normal file
View File

@ -0,0 +1,67 @@
#ifndef JPEG_DECODER_H
#define JPEG_DECODER_H
#include "global.h"
#include "jpegutils.h"
typedef union JpegTaskData {
struct {
/* 0x00 */ u32 address;
/* 0x04 */ u32 mbCount;
/* 0x08 */ u32 mode;
/* 0x0C */ u32 qTableYPtr;
/* 0x10 */ u32 qTableUPtr;
/* 0x14 */ u32 qTableVPtr;
/* 0x18 */ u32 mbSize; // This field is used by the microcode to save the macroblock size during a yield
};
long long int force_structure_alignment;
} JpegTaskData; // size = 0x20
typedef struct JpegWork {
/* 0x000 */ JpegTaskData taskData;
/* 0x020 */ u64 yieldData[0x200 / sizeof(u64)];
/* 0x220 */ JpegQuantizationTable qTableY;
/* 0x2A0 */ JpegQuantizationTable qTableU;
/* 0x320 */ JpegQuantizationTable qTableV;
/* 0x3A0 */ u8 codesLengths[0x110];
/* 0x4B0 */ u16 codes[0x108];
/* 0x6C0 */ u16 data[4][0x180];
} JpegWork; // size = 0x12C0
typedef struct JpegDecoder {
/* 0x00 */ void* imageData;
/* 0x04 */ u8 mode;
/* 0x05 */ u8 unk_05;
/* 0x08 */ JpegHuffmanTable* hTablePtrs[4];
/* 0x18 */ u8 unk_18;
} JpegDecoder; // size = 0x1C
typedef struct JpegContext {
/* 0x00 */ u8 dqtCount;
/* 0x04 */ u8* dqtPtr[3];
/* 0x10 */ u8 dhtCount;
/* 0x14 */ u8* dhtPtr[4];
/* 0x24 */ void* imageData;
/* 0x28 */ u32 mode; // 0 if Y V0 is 1 and 2 if Y V0 is 2
/* 0x30 */ OSScTask scTask;
/* 0x98 */ OSMesgQueue mq;
/* 0xB0 */ OSMesg msg;
/* 0xB4 */ JpegWork* workBuf;
} JpegContext; // size = 0xB8
typedef struct JpegDecoderState {
/* 0x00 */ u32 byteIdx;
/* 0x04 */ u8 bitIdx;
/* 0x05 */ u8 dontSkip;
/* 0x08 */ u32 curWord;
/* 0x0C */ s16 unk_0C;
/* 0x0E */ s16 unk_0E;
/* 0x10 */ s16 unk_10;
} JpegDecoderState; // size = 0x14
s32 JpegDecoder_Decode(JpegDecoder*, u16*, s32, u8, JpegDecoderState*);
s32 JpegDecoder_ProcessMcu(JpegHuffmanTable*, JpegHuffmanTable*, u16*, s16*);
s32 JpegDecoder_ParseNextSymbol(JpegHuffmanTable*, s16*, s8*);
u16 JpegDecoder_ReadBits(u8);
#endif // JPEG_DECODER_H

View File

@ -156,4 +156,4 @@ u32 JpegUtils_ProcessHuffmanTableImplOld(u8* dht, JpegHuffmanTableOld* ht, u8* c
JpegUtils_SetHuffmanTableOld(dht + 0x10, ht, codesLengths, codes, count2, isAc);
return 0;
}
}

View File

@ -48,7 +48,7 @@
- [0xC4B0, c, libleo/bootdisk]
- [0xC910, hasm, ../../src/libleo/bootstrap]
- [0xC970, c, jpegutils]
- [0xCE80, c] #
- [0xCE80, c, jpeg_decoder]
- [0xD470, c] #
- [0xDDC0, c]
- [0xE1C0, c] # load gb emulator (fragment 1)
@ -505,7 +505,8 @@
- {vram: 0x800A7450, type: .bss, name: stage_loader}
- {vram: 0x800A74C0, type: .bss, name: crash_screen}
- {vram: 0x800A7EA0, type: .bss, name: profiler}
- {vram: 0x800A8100, type: bss, name: unk_bss_2}
- {vram: 0x800A8100, type: bss, name: unk_bss_2}
- {vram: 0x800A82D0, type: .bss, name: jpeg_decoder}
- {vram: 0x800A82E0, type: .bss, name: D470}
- {vram: 0x800A83A0, type: bss, name: unk_bss_17}
- {vram: 0x800AA680, type: .bss, name: E890}