diff options
| author | Vijfhoek <me@vijf.life> | 2021-05-26 20:46:07 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-05-26 20:46:07 +0200 |
| commit | 36fead60a061e0566d2cdf1c247c5c4cd5110826 (patch) | |
| tree | aa858d1631fedaf1484fa13f1762f418bb08a749 /src/code | |
| parent | aebf11b8bedab56273d53261e8c7e82a58f50d12 (diff) | |
Improve z_jpeg documentation (#825)
* Improve z_jpeg documentation
* JpegWork::data is probably better than address
* Rename Jpeg_SendTask to Jpeg_ScheduleDecoderTask
* Rename njpegUCode to gJpegUCode
* Rename GetU16 to GetUnalignedU16 and improve docs
Diffstat (limited to 'src/code')
| -rw-r--r-- | src/code/z_jpeg.c | 146 |
1 files changed, 88 insertions, 58 deletions
diff --git a/src/code/z_jpeg.c b/src/code/z_jpeg.c index 775151487..cd789e20f 100644 --- a/src/code/z_jpeg.c +++ b/src/code/z_jpeg.c @@ -1,6 +1,7 @@ #include "global.h" #include "vt.h" +#define MARKER_ESCAPE 0x00 #define MARKER_SOI 0xD8 #define MARKER_SOF 0xC0 #define MARKER_DHT 0xC4 @@ -13,32 +14,33 @@ #define MARKER_COM 0xFE #define MARKER_EOI 0xD9 -u32 Jpeg_SendTask(JpegContext* ctx) { - // clang-format off +/** + * Configures and schedules a JPEG decoder task and waits for it to finish. + */ +u32 Jpeg_ScheduleDecoderTask(JpegContext* ctx) { static OSTask_t sJpegTask = { - M_NJPEGTASK, // type - 0, //flags - NULL, // ucode_boot - 0, // ucode_boot_size - D_80114930, // ucode - 0x1000, // ucode_size - D_80157D30, // ucode_data - 0x800, // ucode_data_size - NULL, // dram_stack - 0, // dram_stack_size - NULL, // output_buff - 0, // output_buff_size - NULL, // data_ptr + M_NJPEGTASK, // type + 0, // flags + NULL, // ucode_boot + 0, // ucode_boot_size + gJpegUCode, // ucode + 0x1000, // ucode_size + gJpegUCodeData, // ucode_data + 0x800, // ucode_data_size + NULL, // dram_stack + 0, // dram_stack_size + NULL, // output_buff + NULL, // output_buff_size + NULL, // data_ptr sizeof(JpegTaskData), // data_size - NULL, // yield_data_ptr - 0x200, // yield_data_size + NULL, // yield_data_ptr + 0x200, // yield_data_size }; - // clang-format on JpegWork* workBuf = ctx->workBuf; s32 pad[2]; - workBuf->taskData.address = PHYSICAL_TO_VIRTUAL(&workBuf->unk_6C0); + workBuf->taskData.address = PHYSICAL_TO_VIRTUAL(&workBuf->data); workBuf->taskData.mode = ctx->mode; workBuf->taskData.mbCount = 4; workBuf->taskData.qTableYPtr = PHYSICAL_TO_VIRTUAL(&workBuf->qTableY); @@ -63,6 +65,9 @@ u32 Jpeg_SendTask(JpegContext* ctx) { osRecvMesg(&ctx->mq, NULL, OS_MESG_BLOCK); } +/** + * Copies a 16x16 block of decoded image data to the Z-buffer. + */ void Jpeg_CopyToZbuffer(u16* src, u16* zbuffer, s32 x, s32 y) { u16* dst = zbuffer + (((y * SCREEN_WIDTH) + x) * 16); s32 i; @@ -90,14 +95,26 @@ void Jpeg_CopyToZbuffer(u16* src, u16* zbuffer, s32 x, s32 y) { } } -u16 Jpeg_GetU16(u8* ptr) { - if (((u32)ptr & 1) == 0) { // if the address is aligned to 2 +/** + * Reads an u16 from a possibly unaligned address in memory. + * + * Replaces unaligned 16-bit reads with a pair of aligned reads, allowing for reading the possibly + * unaligned values in JPEG header files. + */ +u16 Jpeg_GetUnalignedU16(u8* ptr) { + if (((u32)ptr & 1) == 0) { + // Read the value normally if it's aligned to a 16-bit address. return *(u16*)ptr; } else { - return *(u16*)(ptr - 1) << 8 | (*(u16*)(ptr + 1) >> 8); // lhu crashes with unaligned addresses + // Read unaligned values using two separate aligned memory accesses when it's not. + return *(u16*)(ptr - 1) << 8 | (*(u16*)(ptr + 1) >> 8); } } +/** + * Parses the markers in the JPEG file, storing information such as the pointer to the image data + * in `ctx` for later processing. + */ void Jpeg_ParseMarkers(u8* ptr, JpegContext* ctx) { u32 exit = false; @@ -109,47 +126,58 @@ void Jpeg_ParseMarkers(u8* ptr, JpegContext* ctx) { break; } + // 0xFF indicates the start of a JPEG marker, so look for the next. if (*ptr++ == 0xFF) { switch (*ptr++) { - case 0: + case MARKER_ESCAPE: { + // Compressed value 0xFF is stored as 0xFF00 to escape it, so ignore it. break; + } case MARKER_SOI: { + // Start of Image osSyncPrintf("MARKER_SOI\n"); break; } case MARKER_APP0: { - osSyncPrintf("MARKER_APP0 %d\n", Jpeg_GetU16(ptr)); - ptr += Jpeg_GetU16(ptr); + // Application marker for JFIF + osSyncPrintf("MARKER_APP0 %d\n", Jpeg_GetUnalignedU16(ptr)); + ptr += Jpeg_GetUnalignedU16(ptr); break; } case MARKER_APP1: { - osSyncPrintf("MARKER_APP1 %d\n", Jpeg_GetU16(ptr)); - ptr += Jpeg_GetU16(ptr); + // Application marker for EXIF + osSyncPrintf("MARKER_APP1 %d\n", Jpeg_GetUnalignedU16(ptr)); + ptr += Jpeg_GetUnalignedU16(ptr); break; } case MARKER_APP2: { - osSyncPrintf("MARKER_APP2 %d\n", Jpeg_GetU16(ptr)); - ptr += Jpeg_GetU16(ptr); + osSyncPrintf("MARKER_APP2 %d\n", Jpeg_GetUnalignedU16(ptr)); + ptr += Jpeg_GetUnalignedU16(ptr); break; } case MARKER_DQT: { - osSyncPrintf("MARKER_DQT %d %d %02x\n", ctx->dqtCount, Jpeg_GetU16(ptr), ptr[2]); + // Define Quantization Table, stored for later processing + osSyncPrintf("MARKER_DQT %d %d %02x\n", ctx->dqtCount, Jpeg_GetUnalignedU16(ptr), ptr[2]); ctx->dqtPtr[ctx->dqtCount++] = ptr + 2; - ptr += Jpeg_GetU16(ptr); + ptr += Jpeg_GetUnalignedU16(ptr); break; } case MARKER_DHT: { - osSyncPrintf("MARKER_DHT %d %d %02x\n", ctx->dhtCount, Jpeg_GetU16(ptr), ptr[2]); + // Define Huffman Table, stored for later processing + osSyncPrintf("MARKER_DHT %d %d %02x\n", ctx->dhtCount, Jpeg_GetUnalignedU16(ptr), ptr[2]); ctx->dhtPtr[ctx->dhtCount++] = ptr + 2; - ptr += Jpeg_GetU16(ptr); + ptr += Jpeg_GetUnalignedU16(ptr); break; } case MARKER_DRI: { - osSyncPrintf("MARKER_DRI %d\n", Jpeg_GetU16(ptr)); - ptr += Jpeg_GetU16(ptr); + // Define Restart Interval + osSyncPrintf("MARKER_DRI %d\n", Jpeg_GetUnalignedU16(ptr)); + ptr += Jpeg_GetUnalignedU16(ptr); break; } case MARKER_SOF: { + // Start of Frame, stores important metadata of the image. + // Only used for extracting the sampling factors (ctx->mode). osSyncPrintf("MARKER_SOF %d " "精度%02x " // accuracy "垂直%d " // vertical @@ -158,33 +186,35 @@ void Jpeg_ParseMarkers(u8* ptr, JpegContext* ctx) { "(1:Y)%d (H0=2,V0=1(422) or 2(420))%02x (量子化テーブル)%02x " "(2:Cb)%d (H1=1,V1=1)%02x (量子化テーブル)%02x " "(3:Cr)%d (H2=1,V2=1)%02x (量子化テーブル)%02x\n", - Jpeg_GetU16(ptr), - ptr[2], // precision - Jpeg_GetU16(ptr + 3), // height - Jpeg_GetU16(ptr + 5), // width - ptr[7], // component count - ptr[8], ptr[9], ptr[10], // Y - ptr[11], ptr[12], ptr[13], // Cb - ptr[14], ptr[15], ptr[16] // Cr + Jpeg_GetUnalignedU16(ptr), + ptr[2], // precision + Jpeg_GetUnalignedU16(ptr + 3), // height + Jpeg_GetUnalignedU16(ptr + 5), // width + ptr[7], // component count (assumed to be 3) + ptr[8], ptr[9], ptr[10], // Y component + ptr[11], ptr[12], ptr[13], // Cb component + ptr[14], ptr[15], ptr[16] // Cr component ); - if (ptr[9] == 0x21) // component Y : V0 == 1 - { + if (ptr[9] == 0x21) { + // component Y : V0 == 1 ctx->mode = 0; - } else if (ptr[9] == 0x22) // component Y : V0 == 2 - { + } else if (ptr[9] == 0x22) { + // component Y : V0 == 2 ctx->mode = 2; } - ptr += Jpeg_GetU16(ptr); + ptr += Jpeg_GetUnalignedU16(ptr); break; } case MARKER_SOS: { - osSyncPrintf("MARKER_SOS %d\n", Jpeg_GetU16(ptr)); - ptr += Jpeg_GetU16(ptr); + // Start of Scan marker, indicates the start of the image data. + osSyncPrintf("MARKER_SOS %d\n", Jpeg_GetUnalignedU16(ptr)); + ptr += Jpeg_GetUnalignedU16(ptr); ctx->imageData = ptr; break; } case MARKER_EOI: { + // End of Image osSyncPrintf("MARKER_EOI\n"); exit = true; break; @@ -192,7 +222,7 @@ void Jpeg_ParseMarkers(u8* ptr, JpegContext* ctx) { default: { // Unknown marker osSyncPrintf("マーカー不明 %02x\n", ptr[-1]); - ptr += Jpeg_GetU16(ptr); + ptr += Jpeg_GetUnalignedU16(ptr); break; } } @@ -201,7 +231,7 @@ void Jpeg_ParseMarkers(u8* ptr, JpegContext* ctx) { } #ifdef NON_MATCHING -// the time diff isn't correct, workBuff->unk_6C0 is kept in a temp register instead of being stored in the stack and +// the time diff isn't correct, workBuff->data is kept in a temp register instead of being stored in the stack and // regalloc differences s32 Jpeg_Decode(void* data, u16* zbuffer, JpegWork* workBuff, u32 workSize) { s32 y; @@ -218,7 +248,7 @@ s32 Jpeg_Decode(void* data, u16* zbuffer, JpegWork* workBuff, u32 workSize) { OSTime time2; time = osGetTime(); - // (?) I guess MB_SIZE=0x180, PROC_OF_MBS=5 which means unk_6C0 is not a part of JpegWork + // (?) I guess MB_SIZE=0x180, PROC_OF_MBS=5 which means data is not a part of JpegWork ASSERT(workSize >= sizeof(JpegWork), "worksize >= sizeof(JPEGWork) + MB_SIZE * (PROC_OF_MBS - 1)", "../z_jpeg.c", 527); @@ -312,16 +342,16 @@ s32 Jpeg_Decode(void* data, u16* zbuffer, JpegWork* workBuff, u32 workSize) { y = 0; x = 0; for (i = 0; i < 300; i += 4) { - if (JpegDecoder_Decode(&decoder, (u16*)workBuff->unk_6C0, 4, i != 0, &state)) { + if (JpegDecoder_Decode(&decoder, (u16*)workBuff->data, 4, i != 0, &state)) { osSyncPrintf(VT_FGCOL(RED)); osSyncPrintf("Error : Can't decode jpeg\n"); osSyncPrintf(VT_RST); } else { - Jpeg_SendTask(&ctx); - osInvalDCache(&workBuff->unk_6C0, sizeof(workBuff->unk_6C0[0])); + Jpeg_ScheduleDecoderTask(&ctx); + osInvalDCache(&workBuff->data, sizeof(workBuff->data[0])); - src = workBuff->unk_6C0; - for (j = 0; j < ARRAY_COUNT(workBuff->unk_6C0); j++) { + src = workBuff->data; + for (j = 0; j < ARRAY_COUNT(workBuff->data); j++) { Jpeg_CopyToZbuffer(src[j], zbuffer, x, y); x++; |
