void hidWaitForEvent(HID_Event id, bool nextEvent) { if(id>=HIDEVENT_MAX)return; if (nextEvent) svcClearEvent(hidEvents[id]); svcWaitSynchronization(hidEvents[id], U64_MAX); if (!nextEvent) svcClearEvent(hidEvents[id]); }
void aptAppletClosed(void) { aptAppletUtility_Exit_RetToApp(1); GSPGPU_AcquireRight(0x0); GSPGPU_RestoreVramSysArea(); svcClearEvent(aptStatusEvent); aptSetStatus(APP_RUNNING); svcClearEvent(aptStatusEvent); }
bool udsWaitConnectionStatusEvent(bool nextEvent, bool wait) { bool ret = true; u64 delayvalue = U64_MAX; if(!wait)delayvalue = 0; if(nextEvent)svcClearEvent(__uds_connectionstatus_event); if(svcWaitSynchronization(__uds_connectionstatus_event, delayvalue)!=0 && !wait)ret = false; if(!nextEvent)svcClearEvent(__uds_connectionstatus_event); return ret; }
bool udsWaitDataAvailable(const udsBindContext *bindcontext, bool nextEvent, bool wait) { bool ret = true; u64 delayvalue = U64_MAX; if(!wait)delayvalue = 0; if(nextEvent)svcClearEvent(bindcontext->event); if(svcWaitSynchronization(bindcontext->event, delayvalue)!=0 && !wait)ret = false; if(!nextEvent)svcClearEvent(bindcontext->event); return ret; }
static inline void ndspWaitForIrq(void) { LightLock_Lock(&ndspMutex); svcWaitSynchronization(irqEvent, U64_MAX); svcClearEvent(irqEvent); LightLock_Unlock(&ndspMutex); }
void gspEventThreadMain(void *arg) { while (gspRunEvents) { svcWaitSynchronization(gspEvent, U64_MAX); svcClearEvent(gspEvent); while (true) { int curEvt = popInterrupt(); if (curEvt == -1) break; if (curEvt < GSPGPU_EVENT_MAX) { if (gspEventCb[curEvt]) { ThreadFunc func = gspEventCb[curEvt]; if (gspEventCbOneShot[curEvt]) gspEventCb[curEvt] = NULL; func(gspEventCbData[curEvt]); } LightEvent_Signal(&gspEvents[curEvt]); do __ldrex(&gspLastEvent); while (__strex(&gspLastEvent, curEvt)); svcArbitrateAddress(__sync_get_arbiter(), (u32)&gspLastEvent, ARBITRATION_SIGNAL, 1, 0); gspEventCounts[curEvt]++; } } } }
void aptEventHandler(void *arg) { bool runThread = true; while(runThread) { s32 syncedID = 0; svcWaitSynchronizationN(&syncedID, aptEvents, 3, 0, U64_MAX); svcClearEvent(aptEvents[syncedID]); switch(syncedID) { // Event 0 means we got a signal from NS (home button, power button etc). case 0x0: __handle_notification(); break; // Event 1 means we got an incoming parameter. case 0x1: runThread = __handle_incoming_parameter(); break; // Event 2 means we should exit the thread. case 0x2: runThread = false; break; } } }
static void ndspSync(void) { if (bSleeping) { svcWaitSynchronization(sleepEvent, U64_MAX); svcClearEvent(sleepEvent); } ndspWaitForIrq(); if (bDspReady) { int counter = ndspGetCounter(~ndspFrameId & 1); if (counter) { int next = (counter + 1) & 0xFFFF; ndspFrameId = next ? next : 2; ndspBufferId = ndspFrameId & 1; ndspiReadChnState(); //memcpy(dspVar9Backup, dspVars[9][ndspBufferId], sizeof(dspVar9Backup)); ndspUpdateCapture((s16*)ndspVars[6][ndspBufferId], 160); droppedFrames += *((u16*)ndspVars[5][ndspBufferId] + 1); } bNeedsSync = false; } }
void aptAppStarted(void) { u8 buf1[4], buf2[4]; aptSetStatus(APP_RUNNING); svcClearEvent(aptStatusEvent); if(!aptIsCrippled()) { memset(buf1, 0, 4); buf1[0] = 0x10; aptOpenSession(); APT_AppletUtility(NULL, 0x7, 0x4, buf1, 0x1, buf2); aptCloseSession(); buf1[0] = 0x00; aptOpenSession(); APT_AppletUtility(NULL, 0x4, 0x1, buf1, 0x1, buf2); aptCloseSession(); aptOpenSession(); APT_AppletUtility(NULL, 0x4, 0x1, buf1, 0x1, buf2); aptCloseSession(); } }
void LuaThread(void *arg) { // Run Lua interpreter // Load the boot.lua file onto the stack as a chunk luaL_loadfile(L, "lua/bios.lua"); // Continuously resume the chunk until it finishes or errors int args = 0; while(LuaBox_Running) { int state = lua_resume(L, NULL, args); args = 0; if(state == LUA_OK) break; // Execution complete if(state != LUA_YIELD) { // Error of some kind printf("# Uncaught lua error (code %i)\nTraceback:", state); luaL_dostring(L, "print(debug.traceback())"); break; } // Handle yield below svcWaitSynchronization(LuaBox_EventMutex, U64_MAX); // Attempt to lock event list if(LuaBox_EventList == NULL) { // Release the event lock and wait for a signal svcReleaseMutex(LuaBox_EventMutex); svcWaitSynchronization(LuaBox_EventSignal, U64_MAX); // Wait for another thread to signal us an event svcClearEvent(LuaBox_EventSignal); // Clear the event svcWaitSynchronization(LuaBox_EventMutex, U64_MAX); // Attempt to lock event list } struct LuaBox_Event * ev = LuaBox_EventList; // Grab end of list if(ev != NULL) { switch(ev->type) { case LUABOX_EVENT_CHAR: lua_pushstring(L, "char"); // Push string 'char' onto stack char *charPressed = malloc(2); charPressed[0] = (char)ev->value; charPressed[1] = 0x0; lua_pushstring(L, charPressed); free(charPressed); args = 2; break; default: break; } struct LuaBox_Event * next = ev->next; free(ev); LuaBox_EventList = next; } // Release the event lock svcReleaseMutex(LuaBox_EventMutex); } // Execution complete past this point printf("# bios.lua execution complete\n"); while (1) { svcSleepThread(10000000ULL);} }
bool hidTryWaitForEvent(HID_Event id, s64 nanoseconds){ if(R_DESCRIPTION(svcWaitSynchronization(hidEvents[id], nanoseconds))==RD_TIMEOUT){ return false; } else{ svcClearEvent(hidEvents[id]); return true; } }
void threadMain(void *arg) { while(1) { svcWaitSynchronization(threadRequest, U64_MAX); svcClearEvent(threadRequest); if(threadExit) svcExitThread(); threadcount++; } }
void conn_main() { APP_STATUS status; u32 it = 0; int ret = 0; int first = 1; int exiting = 0; while((status = aptGetStatus()) != APP_EXITING) { hidScanInput(); consoleClear(&bot); print(&bot, "frame: %08x\n", it); print(&bot, "ret: %08x\n", ret); print(&bot, "last_cmd: %02x\n", last_cmd & 0xFF); if(!first) { u32 bytes_read = 0; while(1) { ret = recv(sock, &cmd, sizeof(cmd), 0); if(ret < 0) { if(ret == -EWOULDBLOCK) continue; break; } bytes_read += ret; if(bytes_read == sizeof(cmd)) { svcSignalEvent(new_cmd_event); svcWaitSynchronization(cmd_done_event, U64_MAX); svcClearEvent(cmd_done_event); send(sock, &resp, sizeof(resp), 0); if(last_cmd_result == 0xDEAD) exiting = 1; break; } } } first = 0; it++; if(enable_draw) renderFrame(); u32 keys = hidKeysUp(); if(keys & KEY_A || exiting) break; } }
void cmd_thread_func() { while(1) { svcWaitSynchronization(new_cmd_event, U64_MAX); svcClearEvent(new_cmd_event); if(thread_exit) svcExitThread(); last_cmd = cmd.type; last_cmd_result = execute_cmd(sock, &cmd); svcSignalEvent(cmd_done_event); } }
void threadMain(void *arg) { ThreadArgs *const args = arg; while (1) { svcWaitSynchronization(*args->threadRequest, U64_MAX); svcClearEvent(*args->threadRequest); if (*args->shouldExit) svcExitThread(); (*args->count)++; } }
static void svchax_gspwn(u32 dst, u32 src, u32 size, u8* flush_buffer) { extern Handle gspEvents[GSPEVENT_MAX]; memcpy(flush_buffer, flush_buffer + 0x4000, 0x4000); GSPGPU_InvalidateDataCache(dst, size); GSPGPU_FlushDataCache(src, size); memcpy(flush_buffer, flush_buffer + 0x4000, 0x4000); svcClearEvent(gspEvents[GSPEVENT_PPF]); GX_TextureCopy(src, 0, dst, 0, size, 8); svcWaitSynchronization(gspEvents[GSPEVENT_PPF], U64_MAX); memcpy(flush_buffer, flush_buffer + 0x4000, 0x4000); }
// Mic thread void threadMic(){ while(1) { svcWaitSynchronization(threadRequest, U64_MAX); svcClearEvent(threadRequest); if(threadExit) svcExitThread(); touchPosition touch; hidTouchRead(&touch); u32 kDown = hidKeysDown(); if((touchInCircle(touch, 85, 120, 35) || kDown & KEY_A) && recording == 0) { audiobuf_pos = 0; MIC_SetRecording(1); recording = 1; } if((recording == 1) && (audiobuf_pos < audiobuf_size)) { audiobuf_pos+= MIC_ReadAudioData(&audiobuf[audiobuf_pos], audiobuf_size-audiobuf_pos, 0); if(audiobuf_pos > audiobuf_size)audiobuf_pos = audiobuf_size; if(audiobuf_pos >= 32704 && print == 0){ print = 1; } } if((touchInCircle(touch, 165, 120, 35) || kDown & KEY_B) && recording == 1) { print = 0; MIC_SetRecording(0); recording = 2; //Prevent first mute second to be allocated in wav struct if(audiobuf_pos >= 32704){ nomute_audiobuf = (u8*)linearAlloc(audiobuf_pos - 32704); memcpy(nomute_audiobuf,&audiobuf[32704],audiobuf_pos - 32704); buf_size = (audiobuf_pos - 32704) / 2; write_wav("audio.wav", buf_size, (short int *)nomute_audiobuf, S_RATE); } GSPGPU_FlushDataCache(NULL, nomute_audiobuf, audiobuf_pos); recording = 0; } } }
void Handler::run() { lock(); running = true; while (running) { // TODO: volatile bool for running state if (!handleMessageUnsafe()) { // If there is a message on the queue, find the reason why it didn't execute auto message = peek(); u64 time = osGetTime(); if (message && message->when > time) { u64 when = message->when; unlock(); svcWaitSynchronization(eventHandle, (when-time)*1000000LL); } else { unlock(); svcWaitSynchronization(eventHandle, UINT64_MAX); } lock(); } svcClearEvent(eventHandle); } unlock(); }
void aptAppletStarted(void) { u8 buf1[4], buf2[4]; memset(buf1, 0, 4); // Set status to SUSPENDED. svcClearEvent(aptStatusEvent); aptSetStatus(APP_SUSPENDED); aptOpenSession(); APT_SendCaptureBufferInfo(0x20, __ns_capinfo); aptCloseSession(); aptOpenSession(); APT_ReplySleepQuery(currentAppId, 0x0); aptCloseSession(); aptOpenSession(); APT_StartLibraryApplet(__apt_launchapplet_appID, __apt_launchapplet_inhandle, __apt_launchapplet_parambuf, __apt_launchapplet_parambufsize); aptCloseSession(); buf1[0]=0x00; aptOpenSession(); APT_AppletUtility(NULL, 0x4, 0x1, buf1, 0x1, buf2); aptCloseSession(); aptOpenSession(); APT_NotifyToWait(currentAppId); aptCloseSession(); buf1[0]=0x00; aptOpenSession(); APT_AppletUtility(NULL, 0x4, 0x1, buf1, 0x1, buf2); aptCloseSession(); }
Result APT_LaunchLibraryApplet(NS_APPID appID, Handle inhandle, u32 *parambuf, u32 parambufsize) { Result ret=0; u8 tmp=0; u8 buf1[4]; u8 buf2[4]; aptOpenSession(); APT_ReplySleepQuery(currentAppId, 0); aptCloseSession(); aptOpenSession(); ret=APT_PrepareToStartLibraryApplet(appID); aptCloseSession(); if(R_FAILED(ret))return ret; memset(buf1, 0, 4); aptOpenSession(); APT_AppletUtility(NULL, 0x4, 0x1, buf1, 0x1, buf2); aptCloseSession(); while(1) { aptOpenSession(); ret=APT_IsRegistered(appID, &tmp); aptCloseSession(); if(R_FAILED(ret))return ret; if(tmp!=0)break; } aptCallHook(APTHOOK_ONSUSPEND); __apt_launchapplet_appID = appID; __apt_launchapplet_inhandle = inhandle; __apt_launchapplet_parambuf = parambuf; __apt_launchapplet_parambufsize = parambufsize; // Set status to SUSPENDED. svcClearEvent(aptStatusEvent); aptSetStatus(APP_SUSPENDED); // Save Vram GSPGPU_SaveVramSysArea(); // Capture screen. memset(__ns_capinfo, 0, 0x20); aptInitCaptureInfo(__ns_capinfo); // Send capture-screen info to the library applet. aptOpenSession(); APT_SendParameter(currentAppId, appID, 0x20, __ns_capinfo, 0x0, 0x2); aptCloseSession(); // Release GSP module. GSPGPU_ReleaseRight(); return 0; }
void conn_main() { APP_STATUS status; u32 it = 0; int ret = 0; int first = 1; int exiting = 0; while((status = aptGetStatus()) != APP_EXITING) { hidScanInput(); consoleClear(&bot); print(&bot, "frame: %08x\n", it); print(&bot, "ret: %08x\n", ret); print(&bot, "last_cmd: %02x\n", last_cmd & 0xFF); int i;for(i=0;i<GSPEVENT_MAX;i++)print(&bot, "%d : %08X\n", i, gspEventCounts[i]); if(!first) { u32 bytes_read = 0; while(1) { ret = recv(sock, &cmd, 4, 0); if(ret < 0) { if(ret == -EWOULDBLOCK) continue; break; } if(!cmd.numarg)cmd.numarg=7; u32 size=cmd.numarg*4; ret = recv(sock, &cmd.args, size, 0); if(ret < 0) { if(ret == -EWOULDBLOCK) continue; break; } bytes_read += ret; if(bytes_read == size) { svcSignalEvent(new_cmd_event); svcWaitSynchronization(cmd_done_event, U64_MAX); svcClearEvent(cmd_done_event); size=4+4*resp.numarg; send(sock, &resp, size, 0); if(last_cmd_result == 0xDEAD) exiting = 1; break; } } } first = 0; it++; if(enable_draw) renderFrame(); u32 keys = hidKeysUp(); if(keys & KEY_A || exiting) break; } }
static bool ctr_frame(void* data, const void* frame, unsigned width, unsigned height, unsigned pitch, const char* msg) { ctr_video_t* ctr = (ctr_video_t*)data; settings_t* settings = config_get_ptr(); static uint64_t currentTick,lastTick; static float fps = 0.0; static int total_frames = 0; static int frames = 0; extern bool select_pressed; if (!width || !height) { gspWaitForEvent(GSPEVENT_VBlank0, true); return true; } if(!aptMainLoop()) { event_command(EVENT_CMD_QUIT); return true; } if (select_pressed) { event_command(EVENT_CMD_QUIT); return true; } svcWaitSynchronization(gspEvents[GSPEVENT_P3D], 20000000); svcClearEvent(gspEvents[GSPEVENT_P3D]); svcWaitSynchronization(gspEvents[GSPEVENT_PPF], 20000000); svcClearEvent(gspEvents[GSPEVENT_PPF]); gfxSwapBuffersGpu(); frames++; if (ctr->vsync) svcWaitSynchronization(gspEvents[GSPEVENT_VBlank0], U64_MAX); svcClearEvent(gspEvents[GSPEVENT_VBlank0]); currentTick = svcGetSystemTick(); uint32_t diff = currentTick - lastTick; if(diff > CTR_CPU_TICKS_PER_SECOND) { fps = (float)frames * ((float) CTR_CPU_TICKS_PER_SECOND / (float) diff); lastTick = currentTick; frames = 0; } printf("fps: %8.4f frames: %i\r", fps, total_frames++); fflush(stdout); ctrGuSetMemoryFill(true, (u32*)CTR_GPU_FRAMEBUFFER, 0x00000000, (u32*)(CTR_GPU_FRAMEBUFFER + CTR_TOP_FRAMEBUFFER_WIDTH * CTR_TOP_FRAMEBUFFER_HEIGHT * sizeof(uint32_t)), 0x201, (u32*)CTR_GPU_DEPTHBUFFER, 0x00000000, (u32*)(CTR_GPU_DEPTHBUFFER + CTR_TOP_FRAMEBUFFER_WIDTH * CTR_TOP_FRAMEBUFFER_HEIGHT * sizeof(uint32_t)), 0x201); GPUCMD_SetBufferOffset(0); if (width > ctr->texture_width) width = ctr->texture_width; if (height > ctr->texture_height) height = ctr->texture_height; if(frame) { if(((((u32)(frame)) >= 0x14000000 && ((u32)(frame)) < 0x1c000000)) /* frame in linear memory */ && !((u32)frame & 0x7F) /* 128-byte aligned */ && !((pitch) & 0xF)) /* 16-byte aligned */ { /* can copy the buffer directly with the GPU */ ctrGuCopyImage(false, frame, pitch / 2, height, CTRGU_RGB565, false, ctr->texture_swizzled, ctr->texture_width, CTRGU_RGB565, true); } else { int i; uint16_t* dst = (uint16_t*)ctr->texture_linear; const uint8_t* src = frame; for (i = 0; i < height; i++) { memcpy(dst, src, width * sizeof(uint16_t)); dst += ctr->texture_width; src += pitch; } GSPGPU_FlushDataCache(NULL, ctr->texture_linear, ctr->texture_width * ctr->texture_height * sizeof(uint16_t)); ctrGuCopyImage(false, ctr->texture_linear, ctr->texture_width, ctr->menu.texture_height, CTRGU_RGB565, false, ctr->texture_swizzled, ctr->texture_width, CTRGU_RGB565, true); } } ctrGuSetTexture(GPU_TEXUNIT0, VIRT_TO_PHYS(ctr->texture_swizzled), ctr->texture_width, ctr->texture_height, GPU_TEXTURE_MAG_FILTER(GPU_LINEAR) | GPU_TEXTURE_MIN_FILTER(GPU_LINEAR) | GPU_TEXTURE_WRAP_S(GPU_CLAMP_TO_EDGE) | GPU_TEXTURE_WRAP_T(GPU_CLAMP_TO_EDGE), GPU_RGB565); ctr->frame_coords->u = width; ctr->frame_coords->v = height; GSPGPU_FlushDataCache(NULL, (u8*)ctr->frame_coords, sizeof(ctr_vertex_t)); ctrGuSetAttributeBuffersAddress(VIRT_TO_PHYS(ctr->frame_coords)); ctrGuSetVertexShaderFloatUniform(0, (float*)&ctr->scale_vector, 1); GPU_DrawArray(GPU_UNKPRIM, 1); if (ctr->menu_texture_enable) { GSPGPU_FlushDataCache(NULL, ctr->menu.texture_linear, ctr->menu.texture_width * ctr->menu.texture_height * sizeof(uint16_t)); ctrGuCopyImage(false, ctr->menu.texture_linear, ctr->menu.texture_width, ctr->menu.texture_height, CTRGU_RGBA4444,false, ctr->menu.texture_swizzled, ctr->menu.texture_width, CTRGU_RGBA4444, true); ctrGuSetTexture(GPU_TEXUNIT0, VIRT_TO_PHYS(ctr->menu.texture_swizzled), ctr->menu.texture_width, ctr->menu.texture_height, GPU_TEXTURE_MAG_FILTER(GPU_LINEAR) | GPU_TEXTURE_MIN_FILTER(GPU_LINEAR) | GPU_TEXTURE_WRAP_S(GPU_CLAMP_TO_EDGE) | GPU_TEXTURE_WRAP_T(GPU_CLAMP_TO_EDGE), GPU_RGBA4); ctrGuSetAttributeBuffersAddress(VIRT_TO_PHYS(ctr->menu.frame_coords)); ctrGuSetVertexShaderFloatUniform(1, (float*)&ctr->menu.scale_vector, 1); GPU_DrawArray(GPU_UNKPRIM, 1); } GPU_FinishDrawing(); GPUCMD_Finalize(); ctrGuFlushAndRun(true); ctrGuDisplayTransfer(true, CTR_GPU_FRAMEBUFFER, 240,400, CTRGU_RGBA8, gfxGetFramebuffer(GFX_TOP, GFX_LEFT, NULL, NULL), 240,400,CTRGU_RGB8, CTRGU_MULTISAMPLE_NONE); ctr->frame_count++; return true; }
static void __handle_notification(void) { APT_Signal type; Result ret=0; // Get notification type. aptOpenSession(); ret = APT_InquireNotification(currentAppId, &type); aptCloseSession(); if(R_FAILED(ret)) return; _aptDebug(1, type); switch(type) { case APTSIGNAL_HOMEBUTTON: case APTSIGNAL_POWERBUTTON: // The main thread should call aptReturnToMenu() when the status gets set to this. if(aptGetStatus() == APP_RUNNING) { aptOpenSession(); APT_ReplySleepQuery(currentAppId, 0x0); aptCloseSession(); if(type == APTSIGNAL_HOMEBUTTON) aptSetStatusPower(0); if(type == APTSIGNAL_POWERBUTTON) aptSetStatusPower(1); aptSetStatus(APP_SUSPENDING); } break; case APTSIGNAL_PREPARESLEEP: // Reply to sleep-request. aptStatusBeforeSleep = aptGetStatus(); aptSetStatus(APP_PREPARE_SLEEPMODE); svcWaitSynchronization(aptSleepSync, U64_MAX); svcClearEvent(aptSleepSync); aptOpenSession(); APT_ReplySleepQuery(currentAppId, 0x1); aptCloseSession(); break; case APTSIGNAL_ENTERSLEEP: if(aptGetStatus() == APP_PREPARE_SLEEPMODE) { // Report into sleep-mode. aptSetStatus(APP_SLEEPMODE); aptOpenSession(); APT_ReplySleepNotificationComplete(currentAppId); aptCloseSession(); } break; // Leaving sleep-mode. case APTSIGNAL_WAKEUP: if(aptGetStatus() == APP_SLEEPMODE) { if(aptStatusBeforeSleep == APP_RUNNING)GSPGPU_SetLcdForceBlack(0); // Restore old aptStatus. aptSetStatus(aptStatusBeforeSleep); } break; default: break; } }
static bool ctr_frame(void* data, const void* frame, unsigned width, unsigned height, uint64_t frame_count, unsigned pitch, const char* msg) { uint32_t diff; static uint64_t currentTick,lastTick; ctr_video_t *ctr = (ctr_video_t*)data; settings_t *settings = config_get_ptr(); static float fps = 0.0; static int total_frames = 0; static int frames = 0; static struct retro_perf_counter ctrframe_f = {0}; uint32_t state_tmp; touchPosition state_tmp_touch; extern bool select_pressed; if (!width || !height) { gspWaitForEvent(GSPEVENT_VBlank0, true); return true; } if(!aptMainLoop()) { event_command(EVENT_CMD_QUIT); return true; } if (select_pressed) { event_command(EVENT_CMD_QUIT); return true; } state_tmp = hidKeysDown(); hidTouchRead(&state_tmp_touch); if((state_tmp & KEY_TOUCH) && (state_tmp_touch.py < 120)) { Handle lcd_handle; u8 not_2DS; extern PrintConsole* currentConsole; gfxBottomFramebuffers[0] = ctr->lcd_buttom_on ? (u8*)ctr->empty_framebuffer: (u8*)currentConsole->frameBuffer; CFGU_GetModelNintendo2DS(¬_2DS); if(not_2DS && srvGetServiceHandle(&lcd_handle, "gsp::Lcd") >= 0) { u32 *cmdbuf = getThreadCommandBuffer(); cmdbuf[0] = ctr->lcd_buttom_on? 0x00120040: 0x00110040; cmdbuf[1] = 2; svcSendSyncRequest(lcd_handle); svcCloseHandle(lcd_handle); } ctr->lcd_buttom_on = !ctr->lcd_buttom_on; } svcWaitSynchronization(gspEvents[GSPEVENT_P3D], 20000000); svcClearEvent(gspEvents[GSPEVENT_P3D]); svcWaitSynchronization(gspEvents[GSPEVENT_PPF], 20000000); svcClearEvent(gspEvents[GSPEVENT_PPF]); frames++; if (ctr->vsync) svcWaitSynchronization(gspEvents[GSPEVENT_VBlank0], U64_MAX); svcClearEvent(gspEvents[GSPEVENT_VBlank0]); currentTick = svcGetSystemTick(); diff = currentTick - lastTick; if(diff > CTR_CPU_TICKS_PER_SECOND) { fps = (float)frames * ((float) CTR_CPU_TICKS_PER_SECOND / (float) diff); lastTick = currentTick; frames = 0; } // extern u32 __linear_heap_size; // extern u32 gpuCmdBufOffset; // extern u32 __heap_size; // printf("0x%08X 0x%08X 0x%08X\r", __heap_size, gpuCmdBufOffset, (__linear_heap_size - linearSpaceFree() +0x3FF) & ~0x3FF); // printf("fps: %8.4f frames: %i (%X)\r", fps, total_frames++, (__linear_heap_size - linearSpaceFree())); printf("fps: %8.4f frames: %i\r", fps, total_frames++); fflush(stdout); rarch_perf_init(&ctrframe_f, "ctrframe_f"); retro_perf_start(&ctrframe_f); if (ctr->should_resize) ctr_update_viewport(ctr); ctrGuSetMemoryFill(true, (u32*)CTR_GPU_FRAMEBUFFER, 0x00000000, (u32*)(CTR_GPU_FRAMEBUFFER + CTR_TOP_FRAMEBUFFER_WIDTH * CTR_TOP_FRAMEBUFFER_HEIGHT * sizeof(uint32_t)), 0x201, (u32*)CTR_GPU_DEPTHBUFFER, 0x00000000, (u32*)(CTR_GPU_DEPTHBUFFER + CTR_TOP_FRAMEBUFFER_WIDTH * CTR_TOP_FRAMEBUFFER_HEIGHT * sizeof(uint32_t)), 0x201); GPUCMD_SetBufferOffset(0); if (width > ctr->texture_width) width = ctr->texture_width; if (height > ctr->texture_height) height = ctr->texture_height; if(frame) { if(((((u32)(frame)) >= 0x14000000 && ((u32)(frame)) < 0x40000000)) /* frame in linear memory */ && !((u32)frame & 0x7F) /* 128-byte aligned */ && !((pitch) & 0xF)) /* 16-byte aligned */ { /* can copy the buffer directly with the GPU */ ctrGuCopyImage(false, frame, pitch / (ctr->rgb32? 4: 2), height, ctr->rgb32 ? CTRGU_RGBA8: CTRGU_RGB565, false, ctr->texture_swizzled, ctr->texture_width, ctr->rgb32 ? CTRGU_RGBA8: CTRGU_RGB565, true); } else { int i; uint8_t *dst = (uint8_t*)ctr->texture_linear; const uint8_t *src = frame; for (i = 0; i < height; i++) { memcpy(dst, src, width * (ctr->rgb32? 4: 2)); dst += ctr->texture_width * (ctr->rgb32? 4: 2); src += pitch; } GSPGPU_FlushDataCache(ctr->texture_linear, ctr->texture_width * ctr->texture_height * (ctr->rgb32? 4: 2)); ctrGuCopyImage(false, ctr->texture_linear, ctr->texture_width, ctr->texture_height, ctr->rgb32 ? CTRGU_RGBA8: CTRGU_RGB565, false, ctr->texture_swizzled, ctr->texture_width, ctr->rgb32 ? CTRGU_RGBA8: CTRGU_RGB565, true); } } ctrGuSetTexture(GPU_TEXUNIT0, VIRT_TO_PHYS(ctr->texture_swizzled), ctr->texture_width, ctr->texture_height, (ctr->smooth? GPU_TEXTURE_MAG_FILTER(GPU_LINEAR) | GPU_TEXTURE_MIN_FILTER(GPU_LINEAR) : GPU_TEXTURE_MAG_FILTER(GPU_NEAREST) | GPU_TEXTURE_MIN_FILTER(GPU_NEAREST)) | GPU_TEXTURE_WRAP_S(GPU_CLAMP_TO_EDGE) | GPU_TEXTURE_WRAP_T(GPU_CLAMP_TO_EDGE), ctr->rgb32 ? GPU_RGBA8: GPU_RGB565); ctr->frame_coords->u = width; ctr->frame_coords->v = height; GSPGPU_FlushDataCache(ctr->frame_coords, sizeof(ctr_vertex_t)); ctrGuSetAttributeBuffersAddress(VIRT_TO_PHYS(ctr->frame_coords)); ctrGuSetVertexShaderFloatUniform(0, (float*)&ctr->scale_vector, 1); /* ARGB --> RGBA */ if (ctr->rgb32) { GPU_SetTexEnv(0, GPU_TEVSOURCES(GPU_TEXTURE0, GPU_CONSTANT, 0), GPU_TEVSOURCES(GPU_PRIMARY_COLOR, GPU_PRIMARY_COLOR, 0), GPU_TEVOPERANDS(GPU_TEVOP_RGB_SRC_G, 0, 0), GPU_TEVOPERANDS(0, 0, 0), GPU_MODULATE, GPU_MODULATE, 0x0000FF); GPU_SetTexEnv(1, GPU_TEVSOURCES(GPU_TEXTURE0, GPU_CONSTANT, GPU_PREVIOUS), GPU_TEVSOURCES(GPU_PREVIOUS, GPU_PREVIOUS, 0), GPU_TEVOPERANDS(GPU_TEVOP_RGB_SRC_B, 0, 0), GPU_TEVOPERANDS(0, 0, 0), GPU_MULTIPLY_ADD, GPU_MODULATE, 0x00FF00); GPU_SetTexEnv(2, GPU_TEVSOURCES(GPU_TEXTURE0, GPU_CONSTANT, GPU_PREVIOUS), GPU_TEVSOURCES(GPU_PREVIOUS, GPU_PREVIOUS, 0), GPU_TEVOPERANDS(GPU_TEVOP_RGB_SRC_ALPHA, 0, 0), GPU_TEVOPERANDS(0, 0, 0), GPU_MULTIPLY_ADD, GPU_MODULATE, 0xFF0000); } GPU_DrawArray(GPU_GEOMETRY_PRIM, 0, 1); /* restore */ if (ctr->rgb32) { GPU_SetTexEnv(0, GPU_TEVSOURCES(GPU_TEXTURE0, GPU_PRIMARY_COLOR, 0), GPU_TEVSOURCES(GPU_TEXTURE0, GPU_PRIMARY_COLOR, 0), GPU_TEVOPERANDS(0, 0, 0), GPU_TEVOPERANDS(0, 0, 0), GPU_MODULATE, GPU_MODULATE, 0xFFFFFFFF); GPU_SetTexEnv(1, GPU_PREVIOUS,GPU_PREVIOUS, 0, 0, 0, 0, 0); GPU_SetTexEnv(2, GPU_PREVIOUS,GPU_PREVIOUS, 0, 0, 0, 0, 0); } if (ctr->menu_texture_enable) { GSPGPU_FlushDataCache(ctr->menu.texture_linear, ctr->menu.texture_width * ctr->menu.texture_height * sizeof(uint16_t)); ctrGuCopyImage(false, ctr->menu.texture_linear, ctr->menu.texture_width, ctr->menu.texture_height, CTRGU_RGBA4444,false, ctr->menu.texture_swizzled, ctr->menu.texture_width, CTRGU_RGBA4444, true); ctrGuSetTexture(GPU_TEXUNIT0, VIRT_TO_PHYS(ctr->menu.texture_swizzled), ctr->menu.texture_width, ctr->menu.texture_height, GPU_TEXTURE_MAG_FILTER(GPU_LINEAR) | GPU_TEXTURE_MIN_FILTER(GPU_LINEAR) | GPU_TEXTURE_WRAP_S(GPU_CLAMP_TO_EDGE) | GPU_TEXTURE_WRAP_T(GPU_CLAMP_TO_EDGE), GPU_RGBA4); ctrGuSetAttributeBuffersAddress(VIRT_TO_PHYS(ctr->menu.frame_coords)); ctrGuSetVertexShaderFloatUniform(0, (float*)&ctr->menu.scale_vector, 1); GPU_DrawArray(GPU_GEOMETRY_PRIM, 0, 1); } GPU_FinishDrawing(); GPUCMD_Finalize(); ctrGuFlushAndRun(true); ctrGuDisplayTransfer(true, CTR_GPU_FRAMEBUFFER, 240,400, CTRGU_RGBA8, gfxGetFramebuffer(GFX_TOP, GFX_LEFT, NULL, NULL), 240,400,CTRGU_RGB8, CTRGU_MULTISAMPLE_NONE); gfxSwapBuffersGpu(); retro_perf_stop(&ctrframe_f); return true; }
void aptReturnToMenu(void) { NS_APPID menu_appid; u32 tmp0 = 1, tmp1 = 0; if(aptIsCrippled()) { svcClearEvent(aptStatusEvent); aptSetStatus(APP_EXITING); return; } // This is only executed when ret-to-menu was triggered via the home-button, not the power-button. if(aptGetStatusPower() == 0) { aptOpenSession(); APT_AppletUtility(NULL, 0x6, 0x4, (u8*)&tmp0, 0x1, (u8*)&tmp1); aptCloseSession(); } // Set status to SUSPENDED. __apt_launchapplet_appID = 0; svcClearEvent(aptStatusEvent); aptSetStatus(APP_SUSPENDED); // Prepare for return to menu aptOpenSession(); APT_PrepareToJumpToHomeMenu(); aptCloseSession(); // Save Vram GSPGPU_SaveVramSysArea(); // Capture screen. memset(__ns_capinfo, 0, 0x20); aptInitCaptureInfo(__ns_capinfo); menu_appid = aptGetMenuAppID(); // Send capture-screen info to menu. aptOpenSession(); APT_SendParameter(currentAppId, menu_appid, 0x20, __ns_capinfo, 0x0, 0x10); aptCloseSession(); aptOpenSession(); APT_SendCaptureBufferInfo(0x20, __ns_capinfo); aptCloseSession(); // Release GSP module. GSPGPU_ReleaseRight(); // Jump to menu! aptOpenSession(); APT_JumpToHomeMenu(0x0, 0x0, 0x0); aptCloseSession(); // Wait for return to application. aptOpenSession(); APT_NotifyToWait(currentAppId); aptCloseSession(); // This is only executed when ret-to-menu was triggered via the home-button, not the power-button. if(aptGetStatusPower() == 0) { tmp0 = 0; aptOpenSession(); APT_AppletUtility(NULL, 0x4, 0x1, (u8*)&tmp0, 0x1, (u8*)&tmp1); aptCloseSession(); } aptWaitStatusEvent(); }
void streamWAV(void* arg){ // Fetching cachePackage struct from main thread cachePackage* pack = (cachePackage*)arg; while(1) { // Waiting for updateStream event svcWaitSynchronization(updateStream, U64_MAX); svcClearEvent(updateStream); // Close the thread if closeStream event received if(closeStream){ closeStream = false; svcExitThread(); } // Check if the current stream is paused or not Music* src = pack->song; Socket* Client = pack->client; if (src->isPlaying){ // Check if a free buffer is available if (src->wavebuf2 == NULL){ // Check if file reached EOF if (src->audio_pointer >= src->size){ // Check if playback ended if (!ndspChnIsPlaying(src->ch)){ src->isPlaying = false; src->tick = (osGetTime()-src->tick); } continue; } // Swap audiobuffers u8* tmp = src->audiobuf; src->audiobuf = src->audiobuf2; src->audiobuf2 = tmp; // Create a new block for DSP service u32 bytesRead; src->wavebuf2 = (ndspWaveBuf*)calloc(1,sizeof(ndspWaveBuf)); createDspBlock(src->wavebuf2, src->bytepersample, src->mem_size, 0, (u32*)src->audiobuf); populatePurgeTable(src, src->wavebuf2); ndspChnWaveBufAdd(src->ch, src->wavebuf2); socketSend(Client, "exec2:0000"); u32 processedBytes = 0; netSize = 0; while (netSize <= 0) heapRecv(Client, 2048); while (processedBytes < (src->mem_size / 2)){ if (netSize <= 0){ heapRecv(Client, 2048); continue; } if (strncmp((char*)netBuffer, "EOF", 3) == 0) break; memcpy(&streamCache[songPointer + processedBytes], netBuffer, netSize); processedBytes = processedBytes + netSize; heapRecv(Client, 2048); } memcpy(src->audiobuf, &streamCache[songPointer], src->mem_size); if (songPointer == 0) songPointer = src->mem_size / 2; else songPointer = 0; src->audio_pointer = src->audio_pointer + src->mem_size; // Changing endianess if Big Endian if (src->big_endian){ u64 i = 0; while (i < src->mem_size){ u8 tmp = src->audiobuf[i]; src->audiobuf[i] = src->audiobuf[i+1]; src->audiobuf[i+1] = tmp; i=i+2; } } } // Check if a block playback is finished u32 curSample = ndspChnGetSamplePos(src->ch); if (src->lastCheck > curSample){ // Prepare next block src->wavebuf = src->wavebuf2; src->wavebuf2 = NULL; } // Update sample position tick src->lastCheck = curSample; } } }
void streamMusic(void* arg) { clearBottomScreen(); debug("play_buffer start\n"); stream_filename* strm_file = static_cast<stream_filename*>(arg); VGMSTREAM* vgmstream = strm_file->stream; if (!vgmstream) return; int channel = 0; ndspSetOutputMode(NDSP_OUTPUT_STEREO); for (int i = 0; i < vgmstream->channels; i++) { ndspChnReset(channel + i); ndspChnSetInterp(channel + i, NDSP_INTERP_LINEAR); ndspChnSetRate(channel + i, vgmstream->sample_rate / vgmstream->channels); ndspChnSetFormat(channel + i, NDSP_FORMAT_STEREO_PCM16); } std::vector<ndspWaveBuf> waveBufs1(vgmstream->channels); std::vector<ndspWaveBuf> waveBufs2(vgmstream->channels); for (auto& waveBuf : waveBufs1) memset(&waveBuf, 0, sizeof(ndspWaveBuf)); for (auto& waveBuf : waveBufs2) memset(&waveBuf, 0, sizeof(ndspWaveBuf)); debug("play_buffer signal produce\n"); svcSignalEvent(bufferReadyProduceRequest); // Wait for 2 buffers to play debug("play_buffer wait data 1\n"); svcWaitSynchronization(bufferReadyConsumeRequest, U64_MAX); svcClearEvent(bufferReadyConsumeRequest); debug("play_buffer signal produce\n"); svcSignalEvent(bufferReadyProduceRequest); debug("play_buffer wait data 2\n"); svcWaitSynchronization(bufferReadyConsumeRequest, U64_MAX); svcClearEvent(bufferReadyConsumeRequest); // Play it debug("play_buffer play\n"); playSoundChannels(channel, playBuffer1.samples, false, playBuffer1.channels, waveBufs1); playSoundChannels(channel, playBuffer2.samples, false, playBuffer2.channels, waveBufs2); stream_buffer* buffer = &playBuffer2; stream_buffer* playingBuf = &playBuffer1; std::vector<ndspWaveBuf>* waveBuf = &waveBufs2; std::vector<ndspWaveBuf>* playingWaveBuf = &waveBufs1; debug("play_buffer signal produce\n"); svcSignalEvent(bufferReadyProduceRequest); while (runThreads) { if (playingWaveBuf->at(0).status == NDSP_WBUF_DONE) { debug("play_buffer wait data\n"); // Wait for sound data here svcWaitSynchronization(bufferReadyConsumeRequest, U64_MAX); svcClearEvent(bufferReadyConsumeRequest); // Flip buffers if (buffer == &playBuffer1) { buffer = &playBuffer2; playingBuf = &playBuffer1; waveBuf = &waveBufs2; playingWaveBuf = &waveBufs1; } else { buffer = &playBuffer1; playingBuf = &playBuffer2; waveBuf = &waveBufs1; playingWaveBuf = &waveBufs2; } debug("play_buffer play\n"); playSoundChannels(channel, buffer->samples, false, buffer->channels, *waveBuf); debug("play_buffer signal produce\n"); svcSignalEvent(bufferReadyProduceRequest); } } for (int i = 0; i < vgmstream->channels; i++) { ndspChnWaveBufClear(channel + i); } debug("play_buffer done\n"); }
bool stream_file(const std::string& filename) { if (filename.empty()) { print("No file selected\n"); return true; } VGMSTREAM* vgmstream = init_vgmstream(filename.c_str()); if (!vgmstream) { print("Bad file %s\n", filename.c_str()); return true; } const int channels = vgmstream->channels; u32 buffer_size = max_samples * vgmstream->channels * sizeof(sample); rawSampleBuffer = static_cast<sample*>(linearAlloc(buffer_size)); sample* buffer = static_cast<sample*>(linearAlloc(buffer_size)); sample* buffer2 = static_cast<sample*>(linearAlloc(buffer_size)); playBuffer1.samples = max_samples; playBuffer2.samples = max_samples; for (int i = 0; i < channels; i++) { playBuffer1.channels.push_back(buffer + i * max_samples); playBuffer2.channels.push_back(buffer2 + i * max_samples); } stream_filename strm_file; strm_file.filename = filename; strm_file.stream = vgmstream; runThreads = true; s32 prio = 0; Thread musicThread; Thread produceThread; svcGetThreadPriority(&prio, CUR_THREAD_HANDLE); musicThread = threadCreate(streamMusic, &strm_file, 4 * 1024, prio-1, -2, false); produceThread = threadCreate(decodeThread, &strm_file, 4 * 1024, prio-1, -2, false); bool ret = false; while (aptMainLoop()) { hidScanInput(); u32 kDown = hidKeysDown(); if (kDown & KEY_START || kDown & KEY_B) { ret = kDown & KEY_START; break; } gfxFlushBuffers(); gfxSwapBuffers(); gspWaitForVBlank(); } runThreads = false; svcSignalEvent(bufferReadyProduceRequest); svcSignalEvent(bufferReadyConsumeRequest); threadJoin(musicThread, U64_MAX); threadJoin(produceThread, U64_MAX); threadFree(musicThread); threadFree(produceThread); svcClearEvent(bufferReadyConsumeRequest); svcClearEvent(bufferReadyProduceRequest); linearFree(rawSampleBuffer); linearFree(buffer); linearFree(buffer2); playBuffer1.channels.clear(); playBuffer2.channels.clear(); close_vgmstream(vgmstream); return ret; }
void decodeThread(void* arg) { debug("decode_buffer start\n"); stream_filename* strm_file = static_cast<stream_filename*>(arg); VGMSTREAM* vgmstream = strm_file->stream; std::string& filename = strm_file->filename; if (!vgmstream) return; const int channels = vgmstream->channels; const u32 stream_samples_amount = get_vgmstream_play_samples(1, 0, 0, vgmstream); u32 current_sample_pos = 0; stream_buffer* buffer = &playBuffer1; while (runThreads) { debug("decode_buffer wait produce\n"); // Wait for signal to make another stream svcWaitSynchronization(bufferReadyProduceRequest, U64_MAX); svcClearEvent(bufferReadyProduceRequest); u32 toget = max_samples; if (!vgmstream->loop_flag) { if (current_sample_pos >= stream_samples_amount) break; if (current_sample_pos + toget > stream_samples_amount) toget = stream_samples_amount - current_sample_pos; } debug("decode_buffer decode %d\n", toget); // TODO modify render_vgmstream to return not decode channel data sequentially in the buffer passed in. render_vgmstream(rawSampleBuffer, toget, vgmstream); debug("decode_buffer detangle\n"); // Detangle audio data... buffer->samples = toget; for (u32 i = 0; i < max_samples; i++) { for (int j = 0; j < channels; j++) { buffer->channels[j][i] = rawSampleBuffer[i * channels + j]; } } debug("decode_buffer signal consume\n"); // Ready to play svcSignalEvent(bufferReadyConsumeRequest); clearTopScreen(); print("\x1b[1;0HCurrently playing %s\nPress B to choose another song\nPress Start to exit", filename.c_str()); print("\x1b[29;0HPLAYING %.4lf %.4lf\n", (float)current_sample_pos / vgmstream->sample_rate, (float)stream_samples_amount / vgmstream->sample_rate); current_sample_pos += toget; // Flip buffers if (buffer == &playBuffer1) buffer = &playBuffer2; else buffer = &playBuffer1; debug("decode_buffer decode more\n"); } debug("decode_buffer done\n"); }
void aptWaitStatusEvent(void) { svcWaitSynchronization(aptStatusEvent, U64_MAX); svcClearEvent(aptStatusEvent); }