diff --git a/Source/Core/Memory.cpp b/Source/Core/Memory.cpp index 20b21b747..2d0bf3a3f 100644 --- a/Source/Core/Memory.cpp +++ b/Source/Core/Memory.cpp @@ -698,7 +698,7 @@ void MemoryUpdateSPStatus( u32 flags ) } else if (stop_rsp) { - RSP_HLE_Reset(); + //RSP_HLE_Reset(); } } diff --git a/Source/Core/RSP_HLE.cpp b/Source/Core/RSP_HLE.cpp index a2eb54c6c..fd02b6927 100644 --- a/Source/Core/RSP_HLE.cpp +++ b/Source/Core/RSP_HLE.cpp @@ -26,6 +26,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "Core/Interrupt.h" #include "Core/Memory.h" +#include "Core/ROM.h" #include "Debug/DBGConsole.h" #include "Debug/DebugLog.h" #include "Debug/Dump.h" // For Dump_GetDumpDirectory() @@ -43,34 +44,34 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. static const bool gGraphicsEnabled = true; static const bool gAudioEnabled = true; +/* JpegTask.cpp */ extern void jpeg_decode_PS(OSTask *task); extern void jpeg_decode_PS0(OSTask *task); extern void jpeg_decode_OB(OSTask *task); - /* RE2Task.cpp + HqvmTask.cpp */ extern "C" { - //extern void resize_bilinear_task(OSTask *task); - //extern void decode_video_frame_task(OSTask *task); - //extern void fill_video_double_buffer_task(OSTask *task); - extern void hvqm2_decode_sp1_task(OSTask *task); + extern void resize_bilinear_task(OSTask *task); + extern void decode_video_frame_task(OSTask *task); + extern void fill_video_double_buffer_task(OSTask *task); + extern void hvqm2_decode_task(OSTask *task, int is32); }; #ifdef DAEDALUS_DEBUG_CONSOLE #if 0 static void RDP_DumpRSPCode(char * name, u32 crc, u32 * mem_base, u32 pc_base, u32 len) { - std::string filename = std::format("task_dump_{}_crc_0x{}.txt", name, crc); - // snprintf(filename, sizeof(filename), "task_dump_%s_crc_0x%08x.txt", name, crc); + char filename[100]; + sprintf(filename, "task_dump_%s_crc_0x%08x.txt", name, crc); - std::filesystem::path filepath = setBasePath("rsp_dumps"); - std::filesystem::create_directory(filepath); - filepath /= filename; + IO::Filename filepath; + Dump_GetDumpDirectory(filepath, "rsp_dumps"); + IO::Path::Append(filepath, filename); - std::fstream fp(filepath, std::ios::in); + FILE * fp = fopen(filepath, "w"); + if (fp == nullptr) + return; - if (fp.is_open()) - { for (u32 i = 0; i < len; i+=4) { OpCode op; @@ -79,13 +80,44 @@ static void RDP_DumpRSPCode(char * name, u32 crc, u32 * mem_base, u32 pc_base, u char opinfo[400]; SprintRSPOpCodeInfo( opinfo, pc + pc_base, op ); - fp << std::format("0x{:08x}: <0x{:08x}> {}\n", pc + pc_base, op._u32, opinfo); + + fprintf(fp, "0x%08x: <0x%08x> %s\n", pc + pc_base, op._u32, opinfo); + //fprintf(fp, "<0x%08x>\n", dwOpCode); } + + fclose(fp); +} +#endif + +#if 0 +static void RDP_DumpRSPData(char * name, u32 crc, u32 * mem_base, u32 pc_base, u32 len) +{ + char filename[100]; + sprintf(filename, "task_data_dump_%s_crc_0x%08x.txt", name, crc); + + IO::Filename filepath; + Dump_GetDumpDirectory(filepath, "rsp_dumps"); + IO::Path::Append(filepath, filename); + + FILE * fp = fopen(filepath, "w"); + if (fp == nullptr) + return; + + for (u32 i = 0; i < len; i+=4) + { + u32 pc = i & 0x0FFF; + u32 data = mem_base[i/4]; + + fprintf(fp, "0x%08x: 0x%08x\n", pc + pc_base, data); } + + fclose(fp); } #endif +// + #if 0 static void RSP_HLE_DumpTaskInfo( const OSTask * pTask ) { @@ -114,7 +146,7 @@ void RSP_HLE_Finished(u32 setbits) // // Set the SP flags appropriately. The RSP is not running anyway, no need to stop it // - u32 status = Memory_SP_SetRegisterBits(SP_STATUS_REG, setbits); + u32 status( Memory_SP_SetRegisterBits(SP_STATUS_REG, setbits) ); // // We've set the SP_STATUS_BROKE flag - better check if it causes an interrupt @@ -155,9 +187,6 @@ static EProcessResult RSP_HLE_Graphics() return PR_COMPLETED; } - -// - static EProcessResult RSP_HLE_Audio() { DAEDALUS_PROFILE( "HLE: Audio" ); @@ -169,19 +198,18 @@ static EProcessResult RSP_HLE_Audio() return PR_COMPLETED; } -// RSP_HLE_Jpeg and RSP_HLE_CICX105 were borrowed from Mupen64plus static u32 sum_bytes(const u8 *bytes, u32 size) { - u32 sum = 0; - const u8 * const bytes_end = bytes + size; + u32 sum = 0; + const u8 * const bytes_end = bytes + size; - while (bytes != bytes_end) - sum += *bytes++; + while (bytes != bytes_end) + sum += *bytes++; - return sum; + return sum; } -EProcessResult RSP_HLE_Jpeg(OSTask * task) +EProcessResult RSP_HLE_Normal(OSTask * task) { // most ucode_boot procedure copy 0xf80 bytes of ucode whatever the ucode_size is. // For practical purpose we use a ucode_size = min(0xf80, task->ucode_size) @@ -191,113 +219,121 @@ EProcessResult RSP_HLE_Jpeg(OSTask * task) switch(sum) { case 0x2c85a: // Pokemon Stadium Jap Exclusive jpg decompression + //printf("jpeg_decode_PS0 task\n"); jpeg_decode_PS0(task); - break; + return PR_COMPLETED; case 0x2caa6: // Zelda OOT, Pokemon Stadium {1,2} jpg decompression + //printf("jpeg_decode_PS task\n"); jpeg_decode_PS(task); - break; - case 0x130de: // Ogre Battle & Buttom of the 9th background decompression + return PR_COMPLETED; + case 0x130de: // Ogre Battle & Bottom of the 9th background decompression case 0x278b0: - jpeg_decode_OB(task); + //printf("jpeg_decode_OB task\n"); + jpeg_decode_OB(task); + return PR_COMPLETED; + case 0x278: // StoreVe12: found in Zelda Ocarina of Time [misleading task->type == 4] + //printf("StoreVe12 task\n"); + return PR_COMPLETED; + case 0x212ee: // GFX: Twintris [misleading task->type == 0] + //printf("GFX (Twintris) task\n"); + return RSP_HLE_Graphics(); + } + + // Resident Evil 2 + sum = sum_bytes(g_pu8RamBase + (u32)task->t.ucode, 256); + switch(sum) + { + case 0x450f: + //printf("resize_bilinear task\n"); + resize_bilinear_task(task); + return PR_COMPLETED; + case 0x3b44: + //printf("decode_video_frame task\n"); + decode_video_frame_task(task); + return PR_COMPLETED; + case 0x3d84: + //printf("fill_video_double_buffer task\n"); + fill_video_double_buffer_task(task); + return PR_COMPLETED; + } + + // HVQM + sum = sum_bytes(g_pu8RamBase + (u32)task->t.ucode, 1488); + switch (sum) { + case 0x19495: + //printf("HVQM SP1 task\n"); + hvqm2_decode_task(task, 0); + return PR_COMPLETED; + case 0x19728: + //printf("HVQM SP2 task\n"); + hvqm2_decode_task(task, 1); break; } - return PR_COMPLETED; + return PR_NOT_STARTED; } -EProcessResult RSP_HLE_CICX105(OSTask * task [[maybe_unused]]) +EProcessResult RSP_HLE_CICX105(OSTask * task) { - const u32 sum {sum_bytes(g_pu8SpImemBase, 0x1000 >> 1)}; - - switch(sum) - { - /* CIC x105 ucode (used during boot of CIC x105 games) */ - case 0x9e2: /* CIC 6105 */ - case 0x9f2: /* CIC 7105 */ - { - u32 i; - u8 * dst {g_pu8RamBase + 0x2fb1f0}; - u8 * src {g_pu8SpImemBase + 0x120}; - - /* dma_read(0x1120, 0x1e8, 0x1e8) */ - memcpy(g_pu8SpImemBase + 0x120, g_pu8RamBase + 0x1e8, 0x1f0); - - /* dma_write(0x1120, 0x2fb1f0, 0xfe817000) */ - for (i = 0; i < 24; ++i) - { - memcpy(dst, src, 8); - dst += 0xff0; - src += 0x8; - - } - } - break; - - } - - return PR_COMPLETED; -} + const u32 sum = sum_bytes(g_pu8SpImemBase, 44); + + if (sum == 0x9e2) { + //printf("CICX105\n"); + u32 i; + u8 * dst = g_pu8RamBase + 0x2fb1f0; + u8 * src = g_pu8SpImemBase + 0x120; + + /* dma_read(0x1120, 0x1e8, 0x1e8) */ + memcpy(g_pu8SpImemBase + 0x120, g_pu8RamBase + 0x1e8, 0x1f0); + + /* dma_write(0x1120, 0x2fb1f0, 0xfe817000) */ + for (i = 0; i < 24; ++i) + { + memcpy(dst, src, 8); + dst += 0xff0; + src += 0x8; + + } + + return PR_COMPLETED; + } -// Pokemon Puzzle League uses this -EProcessResult RSP_HLE_Hvqm(OSTask * task) -{ - hvqm2_decode_sp1_task(task); - return PR_COMPLETED; + return PR_NOT_STARTED; } -void RSP_HLE_Reset() -{} - void RSP_HLE_ProcessTask() -{ +{ OSTask * pTask = (OSTask *)(g_pu8SpMemBase + 0x0FC0); - EProcessResult result( PR_NOT_STARTED ); - - // non task + + EProcessResult result = PR_NOT_STARTED; + + // Non task if(pTask->t.ucode_boot_size > 0x1000) { - RSP_HLE_CICX105(pTask); + result = RSP_HLE_CICX105(pTask); RSP_HLE_Finished(SP_STATUS_BROKE|SP_STATUS_HALT); return; } - - switch ( pTask->t.type ) - { - case M_GFXTASK: - // frozen task + + //printf("RSP Task: Type: %ld, Ptr: 0x%08X, Size: 0x%04X\n", pTask->t.type, (u32*)(pTask->t.data_ptr), pTask->t.ucode_boot_size); + + if (pTask->t.type == M_AUDTASK) { + result = RSP_HLE_Audio(); + } + + if (result == PR_NOT_STARTED) { + result = RSP_HLE_Normal(pTask); + + if (result == PR_NOT_STARTED && pTask->t.type == M_GFXTASK) { if(Memory_DPC_GetRegister(DPC_STATUS_REG) & DPC_STATUS_FREEZE) - { return; - } result = RSP_HLE_Graphics(); - break; - - case M_AUDTASK: - result = RSP_HLE_Audio(); - break; - - case M_VIDTASK: - // Can't handle - break; - - case M_FBTASK: - result = RSP_HLE_Hvqm(pTask); - break; - - case M_JPGTASK: - result = RSP_HLE_Jpeg(pTask); - break; - default: - // Can't handle - DBGConsole_Msg(0, "Unknown task: %08x", pTask->t.type ); - // RSP_HLE_DumpTaskInfo( pTask ); - // RDP_DumpRSPCode("boot", 0xDEAFF00D, (u32*)(g_pu8RamBase + (((u32)pTask->t.ucode_boot)&0x00FFFFFF)), 0x04001000, pTask->t.ucode_boot_size); - // RDP_DumpRSPCode("unkcode", 0xDEAFF00D, (u32*)(g_pu8RamBase + (((u32)pTask->t.ucode)&0x00FFFFFF)), 0x04001080, 0x1000 - 0x80);//pTask->t.ucode_size); - - break; + } } // Started and completed. No need to change cores. [synchronously] - if( result == PR_COMPLETED ) + if (result == PR_COMPLETED) RSP_HLE_Finished(SP_STATUS_TASKDONE|SP_STATUS_BROKE|SP_STATUS_HALT); -} + //else + //printf("Unknown ucode\n"); +} \ No newline at end of file diff --git a/Source/Core/RSP_HLE.h b/Source/Core/RSP_HLE.h index 1ef50e7b4..d0028b158 100644 --- a/Source/Core/RSP_HLE.h +++ b/Source/Core/RSP_HLE.h @@ -34,7 +34,7 @@ enum EProcessResult PR_COMPLETED, // Was processed synchronously, completed }; -void RSP_HLE_Reset(); +//void RSP_HLE_Reset(); void RSP_HLE_ProcessTask(); #endif // CORE_RSP_HLE_H_ diff --git a/Source/Graphics/CMakeLists.txt b/Source/Graphics/CMakeLists.txt index e6e22d78f..d5a495e18 100644 --- a/Source/Graphics/CMakeLists.txt +++ b/Source/Graphics/CMakeLists.txt @@ -1,6 +1,7 @@ add_library(Graphics OBJECT ColourValue.cpp HvqmTask.cpp + RE2TASK.cpp JpegTask.cpp PngUtil.cpp TextureTransform.cpp diff --git a/Source/Graphics/HvqmTask.cpp b/Source/Graphics/HvqmTask.cpp index 8652aece6..2f16b9358 100644 --- a/Source/Graphics/HvqmTask.cpp +++ b/Source/Graphics/HvqmTask.cpp @@ -226,7 +226,32 @@ static uint16_t YCbCr_to_BGRA5551(int16_t Y, int16_t Cb, int16_t Cr, uint8_t alp return (b << 11) | (g << 6) | (r << 1) | (alpha & 1); } -void hvqm2_decode_sp1_task(OSTask *task) +struct RGBA { + uint8_t r; + uint8_t g; + uint8_t b; + uint8_t a; +}; + +#define SATURATE8(x) ((unsigned int) x <= 255 ? x : (x < 0 ? 0: 255)) +static uint32_t YCbCr_to_RGBA(int16_t Y, int16_t Cb, int16_t Cr, uint8_t alpha) +{ + struct RGBA color; + + //Format S10.6 + int r = (int)(((double)Y + 0.5) + (1.765625 * (double)(Cr - 128))); + int g = (int)(((double)Y + 0.5) - (0.34375 * (double)(Cr - 128)) - (0.71875 * (double)(Cb - 128))); + int b = (int)(((double)Y + 0.5) + (1.40625 * (double)(Cb - 128))); + + color.r = SATURATE8(r); + color.g = SATURATE8(g); + color.b = SATURATE8(b); + color.a = alpha; + + return (color.b << 24) | (color.g << 16) | (color.r << 8) | color.a; +} + +void hvqm2_decode_task(OSTask *task, int is32) { uint32_t data_ptr = (u32)task->t.data_ptr; @@ -249,22 +274,26 @@ void hvqm2_decode_sp1_task(OSTask *task) data_ptr += 1; rdram_read_many_u8(arg.nest, data_ptr, HVQM2_NESTSIZE); - //int length = 0x10; - //int count = arg.chroma_step_v << 2; - int skip = arg.buf_width << 1; - - if ((arg.chroma_step_v - 1) != 0) - { - arg.buf_width <<= 3; + int length, skip; + if (is32) { + length = 0x20; + skip = arg.buf_width << 2; + arg.buf_width <<= 4; + } else { + length = 0x10; + skip = arg.buf_width << 1; + arg.buf_width <<= 3; + } + + if (arg.chroma_step_v == 2) arg.buf_width += arg.buf_width; - } for (int i = arg.vmcus; i != 0; i--) { uint32_t out; int j; - for (j = arg.hmcus, out = arg.buf; j != 0; j--, out += 0x10) + for (j = arg.hmcus, out = arg.buf; j != 0; j--, out += length) { uint8_t base = 0x80; int16_t Cb[16], Cr[16], Y1[32], Y2[32]; @@ -304,15 +333,27 @@ void hvqm2_decode_sp1_task(OSTask *task) uint32_t addr = out_buf; for (int l = 0; l < 4; l++) { - uint16_t pixel = YCbCr_to_BGRA5551(pY1[l], pCb[l >> 1], pCr[l >> 1], arg.alpha); - rdram_write_many_u16(&pixel, addr, 1); - addr += 2; + if (is32) { + uint32_t pixel = YCbCr_to_RGBA(pY1[l], pCb[l >> 1], pCr[l >> 1], arg.alpha); + rdram_write_many_u32(&pixel, addr, 1); + addr += 4; + } else { + uint16_t pixel = YCbCr_to_BGRA5551(pY1[l], pCb[l >> 1], pCr[l >> 1], arg.alpha); + rdram_write_many_u16(&pixel, addr, 1); + addr += 2; + } } for (int l = 0; l < 4; l++) { - uint16_t pixel = YCbCr_to_BGRA5551(pY2[l], pCb[(l + 4) >> 1], pCr[(l + 4) >> 1], arg.alpha); - rdram_write_many_u16(&pixel, addr, 1); - addr += 2; + if (is32) { + uint32_t pixel = YCbCr_to_RGBA(pY2[l], pCb[(l + 4) >> 1], pCr[(l + 4) >> 1], arg.alpha); + rdram_write_many_u32(&pixel, addr, 1); + addr += 4; + } else { + uint16_t pixel = YCbCr_to_BGRA5551(pY2[l], pCb[(l + 4) >> 1], pCr[(l + 4) >> 1], arg.alpha); + rdram_write_many_u16(&pixel, addr, 1); + addr += 2; + } } out_buf += skip; pY1 += 4; @@ -326,4 +367,4 @@ void hvqm2_decode_sp1_task(OSTask *task) } } -} +} \ No newline at end of file diff --git a/Source/Graphics/RE2TASK.cpp b/Source/Graphics/RE2TASK.cpp new file mode 100644 index 000000000..d4047123b --- /dev/null +++ b/Source/Graphics/RE2TASK.cpp @@ -0,0 +1,215 @@ +/** +* Daedalus X64 - RE2Task.cpp +* Copyright (C) 2020 Rinnegatamante +* +* If you want to contribute to the project please contact +* me first (maybe someone is already making what you are +* planning to do). +* +* +* This program is free software; you can redistribute it and/ +* or modify it under the terms of the GNU General Public Li- +* cence as published by the Free Software Foundation; either +* version 2 of the Licence, or any later version. +* +* This program is distributed in the hope that it will be use- +* ful, but WITHOUT ANY WARRANTY; without even the implied war- +* ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public Licence for more details. +* +* You should have received a copy of the GNU General Public +* Licence along with this program; if not, write to the Free +* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, +* USA. +* +**/ + +// +// N.B. This source code is derived from Mupen64Plus's source +// and modified by Rinnegatamante to work with Daedalus X64. +// + +//#include + +#include +#include + +#include "Debug/DBGConsole.h" +#include "Core/Memory.h" +#include "Core/RDRam.h" +#include "Ultra/ultra_sptask.h" + +#define SATURATE8(x) ((unsigned int) x <= 255 ? x : (x < 0 ? 0: 255)) + +extern "C" { + +void resize_bilinear_task(OSTask *task) +{ + int data_ptr = (u32)task->t.ucode; + + int src_addr = *(u32*)(g_pu8RamBase + data_ptr); + int dst_addr = *(u32*)(g_pu8RamBase + data_ptr + 4); + int dst_width = *(u32*)(g_pu8RamBase + data_ptr + 8); + int dst_height = *(u32*)(g_pu8RamBase + data_ptr + 12); + int x_ratio = *(u32*)(g_pu8RamBase + data_ptr + 16); + int y_ratio = *(u32*)(g_pu8RamBase + data_ptr + 20); + int src_offset = *(u32*)(g_pu8RamBase + data_ptr + 36); + + int a, b, c ,d, index, y_index, xr, yr, blue, green, red, addr, i, j; + long long x, y, x_diff, y_diff, one_min_x_diff, one_min_y_diff; + unsigned short pixel; + + src_addr += (src_offset >> 16) * (320 * 3); + x = y = 0; + + for(i = 0; i < dst_height; i++) + { + yr = (int)(y >> 16); + y_diff = y - (yr << 16); + one_min_y_diff = 65536 - y_diff; + y_index = yr * 320; + x = 0; + + for(j = 0; j < dst_width; j++) + { + xr = (int)(x >> 16); + x_diff = x - (xr << 16); + one_min_x_diff = 65536 - x_diff; + index = y_index + xr; + addr = src_addr + (index * 3); + + rdram_read_many_u8((uint8_t*)&a, addr, 3); + rdram_read_many_u8((uint8_t*)&b, (addr + 3), 3); + rdram_read_many_u8((uint8_t*)&c, (addr + (320 * 3)), 3); + rdram_read_many_u8((uint8_t*)&d, (addr + (320 * 3) + 3), 3); + + blue = (int)(((a&0xff)*one_min_x_diff*one_min_y_diff + (b&0xff)*x_diff*one_min_y_diff + + (c&0xff)*y_diff*one_min_x_diff + (d&0xff)*x_diff*y_diff) >> 32); + + green = (int)((((a>>8)&0xff)*one_min_x_diff*one_min_y_diff + ((b>>8)&0xff)*x_diff*one_min_y_diff + + ((c>>8)&0xff)*y_diff*one_min_x_diff + ((d>>8)&0xff)*x_diff*y_diff) >> 32); + + red = (int)((((a>>16)&0xff)*one_min_x_diff*one_min_y_diff + ((b>>16)&0xff)*x_diff*one_min_y_diff + + ((c>>16)&0xff)*y_diff*one_min_x_diff + ((d>>16)&0xff)*x_diff*y_diff) >> 32); + + blue = (blue >> 3) & 0x001f; + green = (green >> 3) & 0x001f; + red = (red >> 3) & 0x001f; + pixel = (red << 11) | (green << 6) | (blue << 1) | 1; + + rdram_write_many_u16(&pixel, dst_addr, 1); + dst_addr += 2; + + x += x_ratio; + } + y += y_ratio; + } +} + +static uint32_t YCbCr_to_RGBA(uint8_t Y, uint8_t Cb, uint8_t Cr) +{ + int r, g, b; + + r = (int)(((double)Y * 0.582199097) + (0.701004028 * (double)(Cr - 128))); + g = (int)(((double)Y * 0.582199097) - (0.357070923 * (double)(Cr - 128)) - (0.172073364 * (double)(Cb - 128))); + b = (int)(((double)Y * 0.582199097) + (0.886001587 * (double)(Cb - 128))); + + r = SATURATE8(r); + g = SATURATE8(g); + b = SATURATE8(b); + + return (r << 24) | (g << 16) | (b << 8) | 0; +} + +void decode_video_frame_task(OSTask *task) +{ + int data_ptr = (u32)task->t.ucode; + + int pLuminance = *(u32*)(g_pu8RamBase + data_ptr); + int pCb = *(u32*)(g_pu8RamBase + data_ptr + 4); + int pCr = *(u32*)(g_pu8RamBase + data_ptr + 8); + int pDestination = *(u32*)(g_pu8RamBase + data_ptr + 12); + int nMovieWidth = *(u32*)(g_pu8RamBase + data_ptr + 16); + int nMovieHeight = *(u32*)(g_pu8RamBase + data_ptr + 20); + int nScreenDMAIncrement = *(u32*)(g_pu8RamBase + data_ptr + 36); + + int i, j; + uint8_t Y, Cb, Cr; + uint32_t pixel; + int pY_1st_row, pY_2nd_row, pDest_1st_row, pDest_2nd_row; + + for (i = 0; i < nMovieHeight; i += 2) + { + pY_1st_row = pLuminance; + pY_2nd_row = pLuminance + nMovieWidth; + pDest_1st_row = pDestination; + pDest_2nd_row = pDestination + (nScreenDMAIncrement >> 1); + + for (j = 0; j < nMovieWidth; j += 2) + { + rdram_read_many_u8((uint8_t*)&Cb, pCb++, 1); + rdram_read_many_u8((uint8_t*)&Cr, pCr++, 1); + + /*1st row*/ + rdram_read_many_u8((uint8_t*)&Y, pY_1st_row++, 1); + pixel = YCbCr_to_RGBA(Y, Cb, Cr); + rdram_write_many_u32(&pixel, pDest_1st_row, 1); + pDest_1st_row += 4; + + rdram_read_many_u8((uint8_t*)&Y, pY_1st_row++, 1); + pixel = YCbCr_to_RGBA(Y, Cb, Cr); + rdram_write_many_u32(&pixel, pDest_1st_row, 1); + pDest_1st_row += 4; + + /*2nd row*/ + rdram_read_many_u8((uint8_t*)&Y, pY_2nd_row++, 1); + pixel = YCbCr_to_RGBA(Y, Cb, Cr); + rdram_write_many_u32(&pixel, pDest_2nd_row, 1); + pDest_2nd_row += 4; + + rdram_read_many_u8((uint8_t*)&Y, pY_2nd_row++, 1); + pixel = YCbCr_to_RGBA(Y, Cb, Cr); + rdram_write_many_u32(&pixel, pDest_2nd_row, 1); + pDest_2nd_row += 4; + } + + pLuminance += (nMovieWidth << 1); + pDestination += nScreenDMAIncrement; + } +} + +void fill_video_double_buffer_task(OSTask *task) +{ + int data_ptr = (u32)task->t.ucode; + + int pSrc = *(u32*)(g_pu8RamBase + data_ptr); + int pDest = *(u32*)(g_pu8RamBase + data_ptr + 0x4); + int width = *(u32*)(g_pu8RamBase + data_ptr + 0x8) >> 1; + int height = *(u32*)(g_pu8RamBase + data_ptr + 0x10) << 1; + int stride = *(u32*)(g_pu8RamBase + data_ptr + 0x1c) >> 1; + + int i, j; + int r, g, b; + uint32_t pixel, pixel1, pixel2; + + for(i = 0; i < height; i++) + { + for(j = 0; j < width; j=j+4) + { + pixel1 = *(u32*)(g_pu8RamBase + (pSrc+j)); + pixel2 = *(u32*)(g_pu8RamBase + (pDest+j)); + + r = (((pixel1 >> 24) & 0xff) + ((pixel2 >> 24) & 0xff)) >> 1; + g = (((pixel1 >> 16) & 0xff) + ((pixel2 >> 16) & 0xff)) >> 1; + b = (((pixel1 >> 8) & 0xff) + ((pixel2 >> 8) & 0xff)) >> 1; + + pixel = (r << 24) | (g << 16) | (b << 8) | 0; + + rdram_write_many_u32(&pixel, pDest+j, 1); + } + pSrc += stride; + pDest += stride; + } +} + +}; \ No newline at end of file diff --git a/Source/HLEAudio/AudioBuffer.cpp b/Source/HLEAudio/AudioBuffer.cpp index 3c019d284..e4ff1121f 100644 --- a/Source/HLEAudio/AudioBuffer.cpp +++ b/Source/HLEAudio/AudioBuffer.cpp @@ -18,8 +18,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "Base/Types.h" - - #include "Interface/ConfigOptions.h" #include "Debug/DBGConsole.h" #include "HLEAudio/AudioBuffer.h" @@ -39,11 +37,6 @@ CAudioBuffer::CAudioBuffer(u32 buffer_size) CAudioBuffer::~CAudioBuffer() { delete[] mBufferBegin; } u32 CAudioBuffer::GetNumBufferedSamples() const { - // Todo: Check Cache Routines - // #ifdef DAEDALUS_PSP - // dcache_wbinv_all(); - // #endif - // Safe? What if we read mWrite, and then mRead moves to start of buffer? s32 diff = mWritePtr - mReadPtr; @@ -61,30 +54,20 @@ void CAudioBuffer::AddSamples(const Sample *samples, u32 num_samples, #endif #ifdef DAEDALUS_DEBUG_AUDIO -std::ofstream fh; - - if (!fh.is_open()) - { - fh.open("audio_in.raw", std::ios::binary); -fh.write(reinterpret_cast(samples), sizeof(Sample) * num_samples); -fh.flush(); - } + std::ofstream fh; + if (!fh.is_open()) { + fh.open("audio_in.raw", std::ios::binary); + fh.write(reinterpret_cast(samples), sizeof(Sample) * num_samples); + fh.flush(); + } #endif -// clear the Cache + #ifdef DAEDALUS_PSP -// sceKernelDcacheWritebackInvalidateAll(); +// Cache routines for PSP if needed #endif - const Sample *read_ptr( - mReadPtr); // No need to invalidate, as this is uncached/volatile - Sample *write_ptr(mWritePtr); - // - // 'r' is the number of input samples we progress through for each output - //sample. 's' keeps track of how far between the current two input samples we - //are. We increment it by 'r' for each output sample we generate. When it - //reaches 1.0, we know we've hit the next sample, so we increment in_idx and - //reduce s by 1.0 (to keep it in the range 0.0 .. 1.0) Principle is the same - //but rewritten to integer mode (faster & less ASM) //Corn + const Sample *read_ptr(mReadPtr); // No need to invalidate, as this is uncached/volatile + Sample *write_ptr(mWritePtr); const s32 r = (frequency << 12) / output_freq; s32 s = 0; @@ -97,111 +80,74 @@ fh.flush(); "Input index out of range - %d / %d", in_idx + 1, num_samples); #endif - //#if 0 // 1->Sine tone, 0->Normal - // static float c= 0.0f; - // c += 100.0f / 44100.0f; - // if( c >= 1.0f ) - // c-=1.f; - // s16 v( s16( SHRT_MAX * sinf( c * 3.141f*2 ) ) ); - // Sample out; - // s16 v = WriteCounter++; - // if( WriteCounter >= MAX_COUNTER ) - // { - // printf( "Loop write\n" ); - // WriteCounter = 0; - // } - // out.L = out.R = v; - // - // #else - // Resample in integer mode (faster & less ASM code) //Corn - Sample out; - out.L = samples[in_idx].L + - (((samples[in_idx + 1].L - samples[in_idx].L) * s) >> 12); - out.R = samples[in_idx].R + - (((samples[in_idx + 1].R - samples[in_idx].R) * s) >> 12); + Sample out; + out.L = samples[in_idx].L + (((samples[in_idx + 1].L - samples[in_idx].L) * s) >> 12); + out.R = samples[in_idx].R + (((samples[in_idx + 1].R - samples[in_idx].R) * s) >> 12); s += r; in_idx += s >> 12; s &= 4095; - // #endif + // Circular buffer write logic + *write_ptr = out; write_ptr++; - if (write_ptr >= mBufferEnd) - write_ptr = mBufferBegin; - while (write_ptr == read_ptr) { - // The buffer is full - spin until the read pointer advances. - // Note - spends a lot of time here if program is running - // fast. This loop locks the speed to the playback rate - // as the program winds up waiting for the buffer to empty. - // ToDo: Adjust Audio Frequency/ Look at Turok in this regard. - // We might want to put a Sleep in when executing on the SC? - // Give time to other threads when using SYNC mode. - // ThreadYield(); + if (write_ptr >= mBufferEnd) { + write_ptr = mBufferBegin; + } + // Handle buffer full condition + if (write_ptr == read_ptr) { + // The buffer is full, so move read pointer to the next sample read_ptr = mReadPtr; + // Optionally, sleep or yield the thread here if needed } - - *write_ptr = out; } - // Todo: Check Cache Routines - // Ensure samples array is written back before mWritePtr - // dcache_wbinv_range_unaligned( mBufferBegin, mBufferEnd ); - - mWritePtr = write_ptr; // Needs cache wbinv + mWritePtr = write_ptr; } u32 CAudioBuffer::Drain(Sample *samples, u32 num_samples) { -// Todo: Check Cache Routines -// Ideally we could just invalidate this range? -// clear the Cache #ifdef DAEDALUS_PSP -// sceKernelDcacheWritebackInvalidateAll(); +// Cache routines for PSP if needed #endif const Sample *read_ptr(mReadPtr); // No need to invalidate, as this is uncached/volatile - const Sample *write_ptr(mWritePtr); // - Sample *out_ptr(samples); u32 samples_required(num_samples); while (samples_required > 0) { - // Check if empty - if (read_ptr == write_ptr) - break; + // Check if the buffer is empty + if (read_ptr == mWritePtr) { + break; // Buffer is empty + } *out_ptr++ = *read_ptr++; - - if (read_ptr >= mBufferEnd) - read_ptr = mBufferBegin; + if (read_ptr >= mBufferEnd) { + read_ptr = mBufferBegin; // Circular buffer logic + } samples_required--; } #ifdef DAEDALUS_DEBUG_AUDIO -std::ofstream fh; - - if (!fh.is_open()) - { - fh.open("audio_out.raw", std::ios::binary); - fh.write(reinterpret_cast(samples), sizeof(Sample) * num_samples - samples_required); - fh.flush(); - } + std::ofstream fh; + if (!fh.is_open()) { + fh.open("audio_out.raw", std::ios::binary); + fh.write(reinterpret_cast(samples), sizeof(Sample) * num_samples - samples_required); + fh.flush(); + } #endif - mReadPtr = read_ptr; // No need to invalidate, as this is uncached -// clear the Cache + + mReadPtr = read_ptr; // Update read pointer + #ifdef DAEDALUS_PSP -// sceKernelDcacheWritebackInvalidateAll(); +// Cache routines for PSP if needed #endif - // - // If there weren't enough samples, zero out the buffer - // FIXME(strmnnrmn): Unnecessary on OSX... - // + + // If there weren't enough samples, zero out the buffer if (samples_required > 0) { - // DBGConsole_Msg( 0, "Buffer underflow (%d samples)\n", samples_required ); - // printf( "Buffer underflow (%d samples)\n", samples_required ); memset(out_ptr, 0, samples_required * sizeof(Sample)); } diff --git a/Source/HLEAudio/Plugin/PSP/AudioPluginPSP.cpp b/Source/HLEAudio/Plugin/PSP/AudioPluginPSP.cpp index 39d8df46b..eb8a7a3f7 100644 --- a/Source/HLEAudio/Plugin/PSP/AudioPluginPSP.cpp +++ b/Source/HLEAudio/Plugin/PSP/AudioPluginPSP.cpp @@ -134,19 +134,53 @@ class AudioPluginPSP : public CAudioPlugin bool mExitAudioThread; u32 mFrequency; s32 mAudioThread; - s32 mSemaphore; // u32 mBufferLenMs; }; static AudioPluginPSP * ac; + +s32 mSemaphoretwo = sceKernelCreateSema( "pspMEaudio", 0, 1, 1, nullptr ); + +s32 mSemaphore = sceKernelCreateSema( "AudioPluginPSP", 0, 1, 1, nullptr ); + +bool audiothreadactive = false; + +static int audioOutput(SceSize args, void *argp) +{ + while(audiothreadactive == true){ + + sceKernelWaitSema( mSemaphoretwo, 1, nullptr ); + + sceKernelDcacheWritebackInvalidateAll(); + asm("sync"); + + BeginME( mei, (int)&Audio_Ucode, (int)NULL, -1, NULL, -1, NULL); + + while (CheckME(mei)) { + sceKernelDelayThread(100); // Yield to other threads to avoid 100% CPU usage + } + + + } + + return 0; + + +} + +int audioThid = sceKernelCreateThread("audioOutput", audioOutput, 0x15, 0x1800, PSP_THREAD_ATTR_USER, NULL); + void AudioPluginPSP::FillBuffer(Sample * buffer, u32 num_samples) { + sceKernelWaitSema( mSemaphore, 1, nullptr ); mAudioBufferUncached->Drain( buffer, num_samples ); sceKernelSignalSema( mSemaphore, 1 ); + + } @@ -157,7 +191,6 @@ AudioPluginPSP::AudioPluginPSP() :mKeepRunning (false) //: mAudioBuffer( kAudioBufferSize ) , mFrequency( 44100 ) -, mSemaphore( sceKernelCreateSema( "AudioPluginPSP", 0, 1, 1, nullptr ) ) //, mAudioThread ( kInvalidThreadHandle ) //, mKeepRunning( false ) //, mBufferLenMs ( 0 ) @@ -241,23 +274,17 @@ EProcessResult AudioPluginPSP::ProcessAList() result = PR_COMPLETED; break; case APM_ENABLED_ASYNC: - { -#ifdef DAEDALUS_PSP_USE_ME - sceKernelDcacheWritebackInvalidateAll(); - if(BeginME( mei, (int)&Audio_Ucode, (int)NULL, -1, NULL, -1, NULL) < 0){ - Audio_Ucode(); - result = PR_COMPLETED; - break; - } -#else - DAEDALUS_ERROR("Async audio is unimplemented"); - Audio_Ucode(); + { + //signal the audio thread to kick off a audioucode HLE task. + sceKernelSignalSema( mSemaphoretwo, 1 ); + if(audiothreadactive == false){ + audiothreadactive = true; + sceKernelStartThread(audioThid, 0, NULL); + } result = PR_COMPLETED; break; -#endif + } - result = PR_COMPLETED; - break; case APM_ENABLED_SYNC: Audio_Ucode(); result = PR_COMPLETED; diff --git a/Source/Ultra/ultra_mbi.h b/Source/Ultra/ultra_mbi.h index fdceedb44..282cba667 100644 --- a/Source/Ultra/ultra_mbi.h +++ b/Source/Ultra/ultra_mbi.h @@ -23,7 +23,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define M_GFXTASK 1 #define M_AUDTASK 2 #define M_VIDTASK 3 -#define M_JPGTASK 4 +#define M_NORTASK 4 #define M_FBTASK 7 #define NUM_SEGMENTS (16)