Пример #1
0
void __CtrlTimerUpdate(u64 userdata, int cyclesLate)
{
	// This only runs in timer mode (ctrlCycle > 0.)
	_dbg_assert_msg_(SCECTRL, ctrlCycle > 0, "Ctrl: sampling cycle should be > 0");

	__CtrlDoSample();
	CoreTiming::ScheduleEvent(usToCycles(ctrlCycle), ctrlTimer, 0);
}
Пример #2
0
ResultCode Applet::Start(const Service::APT::AppletStartupParameter& parameter) {
    ResultCode result = StartImpl(parameter);
    if (result.IsError())
        return result;
    // Schedule the update event
    CoreTiming::ScheduleEvent(usToCycles(applet_update_interval_us), applet_update_event, static_cast<u64>(id));
    return result;
}
Пример #3
0
void __KernelScheduleVTimer(VTimer *vt, u64 schedule) {
	CoreTiming::UnscheduleEvent(vtimerTimer, vt->GetUID());

	vt->nvt.schedule = schedule;

	if (vt->nvt.active == 1 && vt->nvt.handlerAddr != 0)
		CoreTiming::ScheduleEvent(usToCycles(vt->nvt.schedule), vtimerTimer, vt->GetUID());
}
Пример #4
0
void EmuScreen::render() {
	if (invalid_)
		return;

	// Reapply the graphics state of the PSP
	ReapplyGfxState();

	// We just run the CPU until we get to vblank. This will quickly sync up pretty nicely.
	// The actual number of cycles doesn't matter so much here as we will break due to CORE_NEXTFRAME, most of the time hopefully...
	int blockTicks = usToCycles(1000000 / 10);

	// Run until CORE_NEXTFRAME
	while (coreState == CORE_RUNNING) {
		u64 nowTicks = CoreTiming::GetTicks();
		mipsr4k.RunLoopUntil(nowTicks + blockTicks);
	}
	// Hopefully coreState is now CORE_NEXTFRAME
	if (coreState == CORE_NEXTFRAME) {
		// set back to running for the next frame
		coreState = CORE_RUNNING;
	} else if (coreState == CORE_POWERDOWN)	{
		ILOG("SELF-POWERDOWN!");
		screenManager()->switchScreen(new MenuScreen());
	}

	if (invalid_)
		return;

	if (g_Config.bBufferedRendering)
		fbo_unbind();

	UIShader_Prepare();

	uiTexture->Bind(0);

	glstate.viewport.set(0, 0, pixel_xres, pixel_yres);
	glstate.viewport.restore();

	ui_draw2d.Begin(UIShader_Get(), DBMODE_NORMAL);

	if (g_Config.bShowTouchControls)
		DrawGamepad(ui_draw2d);

	DrawWatermark();

	glsl_bind(UIShader_Get());
	ui_draw2d.End();
	ui_draw2d.Flush();


	// Tiled renderers like PowerVR should benefit greatly from this. However - seems I can't call it?
#if defined(USING_GLES2)
	bool hasDiscard = false;  // TODO
	if (hasDiscard) {
		//glDiscardFramebuffer(GL_COLOR_EXT | GL_DEPTH_EXT | GL_STENCIL_EXT);
	}
#endif
}
Пример #5
0
void __KernelSetSemaTimeout(Semaphore *s, u32 timeoutPtr)
{
	if (timeoutPtr == 0 || semaWaitTimer == 0)
		return;

	// This should call __KernelMutexTimeout() later, unless we cancel it.
	int micro = (int) Memory::Read_U32(timeoutPtr);
	CoreTiming::ScheduleEvent(usToCycles(micro), semaWaitTimer, __KernelGetCurThread());
}
Пример #6
0
void __KernelScheduleVTimer(VTimer *vt, u64 schedule) {
	CoreTiming::UnscheduleEvent(vtimerTimer, vt->GetUID());

	vt->nvt.schedule = schedule;

	if (vt->nvt.active == 1)
		// this delay makes the test pass, not sure if it's right
		CoreTiming::ScheduleEvent(usToCycles(vt->nvt.schedule + 372), vtimerTimer, vt->GetUID());
}
Пример #7
0
	virtual void handleResult(int result)
	{
		// A non-zero result means to reschedule.
		// TODO: Do sysclock alarms return a different value unit?
		if (result > 0)
			__KernelScheduleAlarm(alarm, usToCycles(result));
		else if (result < 0)
			WARN_LOG(HLE, "Alarm requested reschedule for negative value %u, ignoring", (unsigned) result);
	}
Пример #8
0
void __KernelWaitLwMutex(LwMutex *mutex, u32 timeoutPtr)
{
	if (timeoutPtr == 0 || lwMutexWaitTimer == 0)
		return;

	// This should call __KernelMutexTimeout() later, unless we cancel it.
	int micro = (int) Memory::Read_U32(timeoutPtr);
	CoreTiming::ScheduleEvent(usToCycles(micro), lwMutexWaitTimer, __KernelGetCurThread());
}
Пример #9
0
void __KernelUmdActivate()
{
	u32 notifyArg = PSP_UMD_PRESENT | PSP_UMD_READABLE;
	__KernelNotifyCallbackType(THREAD_CALLBACK_UMD, -1, notifyArg);

	// Don't activate immediately, take time to "spin up."
	CoreTiming::RemoveAllEvents(umdStatChangeEvent);
	CoreTiming::ScheduleEvent(usToCycles(MICRO_DELAY_ACTIVATE), umdStatChangeEvent, 1);
}
Пример #10
0
void __UmdWaitStat(u32 timeout)
{
	// This happens to be how the hardware seems to time things.
	if (timeout <= 4)
		timeout = 15;
	else if (timeout <= 215)
		timeout = 250;

	CoreTiming::ScheduleEvent(usToCycles((int) timeout), umdStatTimeoutEvent, __KernelGetCurThread());
}
Пример #11
0
void Timer::Set(s64 initial, s64 interval) {
    // Ensure we get rid of any previous scheduled event
    Cancel();

    initial_delay = initial;
    interval_delay = interval;

    u64 initial_microseconds = initial / 1000;
    CoreTiming::ScheduleEvent(usToCycles(initial_microseconds), timer_callback_event_type,
                              callback_handle);
}
Пример #12
0
u32 hleDelayResult(u32 result, const char *reason, int usec)
{
	if (__KernelIsDispatchEnabled())
	{
		CoreTiming::ScheduleEvent(usToCycles(usec), delayedResultEvent, __KernelGetCurThread());
		__KernelWaitCurThread(WAITTYPE_HLEDELAY, 1, result, 0, false, reason);
	}
	else
		WARN_LOG(HLE, "Dispatch disabled, not delaying HLE result (right thing to do?)");
	return result;
}
Пример #13
0
SceUID sceKernelSetSysClockAlarm(u32 microPtr, u32 handlerPtr, u32 commonPtr)
{
	u64 micro;

	if (Memory::IsValidAddress(microPtr))
		micro = Memory::Read_U64(microPtr);
	else
		return -1;

	DEBUG_LOG(HLE, "sceKernelSetSysClockAlarm(%lld, %08x, %08x)", micro, handlerPtr, commonPtr);
	return __KernelSetAlarm(usToCycles(micro), handlerPtr, commonPtr);
}
Пример #14
0
void __UmdWaitStat(u32 timeout)
{
	if (umdStatTimer == 0)
		umdStatTimer = CoreTiming::RegisterEvent("MutexTimeout", &__UmdStatTimeout);

	// This happens to be how the hardware seems to time things.
	if (timeout <= 4)
		timeout = 15;
	else if (timeout <= 215)
		timeout = 250;

	CoreTiming::ScheduleEvent(usToCycles((int) timeout), umdStatTimer, __KernelGetCurThread());
}
Пример #15
0
static void __KernelUmdActivate()
{
	u32 notifyArg = PSP_UMD_PRESENT | PSP_UMD_READABLE;
	// PSP_UMD_READY will be returned when sceKernelGetCompiledSdkVersion() != 0
	if (sceKernelGetCompiledSdkVersion() != 0) {
		notifyArg |= PSP_UMD_READY;
	}
	if (driveCBId != 0)
		__KernelNotifyCallback(driveCBId, notifyArg);

	// Don't activate immediately, take time to "spin up."
	CoreTiming::RemoveAllEvents(umdStatChangeEvent);
	CoreTiming::ScheduleEvent(usToCycles(MICRO_DELAY_ACTIVATE), umdStatChangeEvent, 1);
}
Пример #16
0
void Timer::Signal(int cycles_late) {
    LOG_TRACE(Kernel, "Timer %u fired", GetObjectId());

    signaled = true;

    // Resume all waiting threads
    WakeupAllWaitingThreads();

    if (interval_delay != 0) {
        // Reschedule the timer with the interval delay
        u64 interval_microseconds = interval_delay / 1000;
        CoreTiming::ScheduleEvent(usToCycles(interval_microseconds) - cycles_late,
                                  timer_callback_event_type, callback_handle);
    }
}
Пример #17
0
static int DisplayWaitForVblanks(const char *reason, int vblanks, bool callbacks = false) {
	const s64 ticksIntoFrame = CoreTiming::GetTicks() - frameStartTicks;
	const s64 cyclesToNextVblank = msToCycles(frameMs) - ticksIntoFrame;

	// These syscalls take about 115 us, so if the next vblank is before then, we're waiting extra.
	// At least, on real firmware a wait >= 16500 into the frame will wait two.
	if (cyclesToNextVblank <= usToCycles(115)) {
		++vblanks;
	}

	vblankWaitingThreads.push_back(WaitVBlankInfo(__KernelGetCurThread(), vblanks));
	__KernelWaitCurThread(WAITTYPE_VBLANK, 1, 0, 0, callbacks, reason);

	return hleLogSuccessVerboseI(SCEDISPLAY, 0, "waiting for %d vblanks", vblanks);
}
Пример #18
0
void Timer::Set(s64 initial, s64 interval) {
    // Ensure we get rid of any previous scheduled event
    Cancel();

    initial_delay = initial;
    interval_delay = interval;

    if (initial == 0) {
        // Immediately invoke the callback
        Signal(0);
    } else {
        u64 initial_microseconds = initial / 1000;
        CoreTiming::ScheduleEvent(usToCycles(initial_microseconds), timer_callback_event_type,
                                  callback_handle);
    }
}
Пример #19
0
void __KernelSetEventFlagTimeout(EventFlag *e, u32 timeoutPtr)
{
	if (timeoutPtr == 0 || eventFlagWaitTimer == 0)
		return;

	int micro = (int) Memory::Read_U32(timeoutPtr);

	// This seems like the actual timing of timeouts on hardware.
	if (micro <= 1)
		micro = 5;
	else if (micro <= 209)
		micro = 240;

	// This should call __KernelEventFlagTimeout() later, unless we cancel it.
	CoreTiming::ScheduleEvent(usToCycles(micro), eventFlagWaitTimer, __KernelGetCurThread());
}
Пример #20
0
/// Handles updating the current Applet every time it's called.
static void AppletUpdateEvent(u64 applet_id, int cycles_late) {
    Service::APT::AppletId id = static_cast<Service::APT::AppletId>(applet_id);
    std::shared_ptr<Applet> applet = Applet::Get(id);
    ASSERT_MSG(applet != nullptr, "Applet doesn't exist! applet_id=%08X", id);

    applet->Update();

    // If the applet is still running after the last update, reschedule the event
    if (applet->IsRunning()) {
        CoreTiming::ScheduleEvent(usToCycles(applet_update_interval_us) - cycles_late,
            applet_update_event, applet_id);
    } else {
        // Otherwise the applet has terminated, in which case we should clean it up
        applets[id] = nullptr;
    }
}
Пример #21
0
void __KernelWaitMbx(Mbx *m, u32 timeoutPtr)
{
	if (timeoutPtr == 0 || mbxWaitTimer == -1)
		return;

	int micro = (int) Memory::Read_U32(timeoutPtr);

	// This seems to match the actual timing.
	if (micro <= 2)
		micro = 10;
	else if (micro <= 209)
		micro = 250;

	// This should call __KernelMbxTimeout() later, unless we cancel it.
	CoreTiming::ScheduleEvent(usToCycles(micro), mbxWaitTimer, __KernelGetCurThread());
}
Пример #22
0
void __KernelSetSemaTimeout(Semaphore *s, u32 timeoutPtr)
{
	if (timeoutPtr == 0 || semaWaitTimer == -1)
		return;

	int micro = (int) Memory::Read_U32(timeoutPtr);

	// This happens to be how the hardware seems to time things.
	if (micro <= 3)
		micro = 15;
	else if (micro <= 249)
		micro = 250;

	// This should call __KernelSemaTimeout() later, unless we cancel it.
	CoreTiming::ScheduleEvent(usToCycles(micro), semaWaitTimer, __KernelGetCurThread());
}
Пример #23
0
static bool __KernelSetMsgPipeTimeout(u32 timeoutPtr)
{
	if (timeoutPtr == 0 || waitTimer == -1)
		return true;

	int micro = (int) Memory::Read_U32(timeoutPtr);
	if (micro <= 2)
	{
		// Don't wait or reschedule, just timeout immediately.
		return false;
	}

	if (micro <= 210)
		micro = 250;
	CoreTiming::ScheduleEvent(usToCycles(micro), waitTimer, __KernelGetCurThread());
	return true;
}
Пример #24
0
int __DmacMemcpy(u32 dst, u32 src, u32 size) {
	Memory::Memcpy(dst, Memory::GetPointer(src), size);

	src &= ~0x40000000;
	dst &= ~0x40000000;
	if (Memory::IsVRAMAddress(src) || Memory::IsVRAMAddress(dst)) {
		gpu->UpdateMemory(dst, src, size);
	}

	// This number seems strangely reproducible.
	if (size >= 272) {
		// Approx. 225 MiB/s or 235929600 B/s, so let's go with 236 B/us.
		int delayUs = size / 236;
		dmacMemcpyDeadline = CoreTiming::GetTicks() + usToCycles(delayUs);
		return hleDelayResult(0, "dmac copy", delayUs);
	}
	return 0;
}
Пример #25
0
void __KernelSetVplTimeout(u32 timeoutPtr)
{
	if (timeoutPtr == 0 || vplWaitTimer == -1)
		return;

	int micro = (int) Memory::Read_U32(timeoutPtr);

	// This happens to be how the hardware seems to time things.
	if (micro <= 5)
		micro = 10;
	// Yes, this 7 is reproducible.  6 is (a lot) longer than 7.
	else if (micro == 7)
		micro = 15;
	else if (micro <= 215)
		micro = 250;

	CoreTiming::ScheduleEvent(usToCycles(micro), vplWaitTimer, __KernelGetCurThread());
}
Пример #26
0
void __GeInit()
{
	memset(&ge_used_callbacks, 0, sizeof(ge_used_callbacks));
	ge_pending_cb.clear();
	__RegisterIntrHandler(PSP_GE_INTR, new GeIntrHandler());

	geSyncEvent = CoreTiming::RegisterEvent("GeSyncEvent", &__GeExecuteSync);
	geInterruptEvent = CoreTiming::RegisterEvent("GeInterruptEvent", &__GeExecuteInterrupt);
	geCycleEvent = CoreTiming::RegisterEvent("GeCycleEvent", &__GeCheckCycles);

	listWaitingThreads.clear();
	drawWaitingThreads.clear();

	// When we're using separate CPU/GPU threads, we need to keep them in sync.
	if (IsOnSeparateCPUThread()) {
		CoreTiming::ScheduleEvent(usToCycles(geIntervalUs), geCycleEvent, 0);
	}
}
Пример #27
0
void NativeRender()
{
	glstate.Restore();

    ReapplyGfxState();

    s64 blockTicks = usToCycles(1000000 / 10);
    while(coreState == CORE_RUNNING)
    {
		PSP_RunLoopFor((int)blockTicks);
	}

	// Hopefully coreState is now CORE_NEXTFRAME
	if(coreState == CORE_NEXTFRAME)
    {
		// set back to running for the next frame
		coreState = CORE_RUNNING;
    }
}
Пример #28
0
void NativeRender()
{
	glstate.Restore();

    ReapplyGfxState();

    s64 blockTicks = usToCycles(1000000 / 10);
    while(coreState == CORE_RUNNING)
    {
		u64 nowTicks = CoreTiming::GetTicks();
		mipsr4k.RunLoopUntil(nowTicks + blockTicks);
	}
	// Hopefully coreState is now CORE_NEXTFRAME
	if(coreState == CORE_NEXTFRAME)
    {
		// set back to running for the next frame
		coreState = CORE_RUNNING;
    }
}
Пример #29
0
	virtual void handleResult(int result)
	{
		// A non-zero result means to reschedule.
		if (result > 0)
		{
			u32 error;
			Alarm *alarm = kernelObjects.Get<Alarm>(alarmID, error);
			__KernelScheduleAlarm(alarm, (u64) usToCycles(result));
		}
		else
		{
			if (result < 0)
				WARN_LOG(HLE, "Alarm requested reschedule for negative value %u, ignoring", (unsigned) result);

			// Delete the alarm if it's not rescheduled.
			kernelObjects.Destroy<Alarm>(alarmID);
			__ReleaseSubIntrHandler(PSP_SYSTIMER0_INTR, alarmID);
		}
	}
Пример #30
0
u32 sceCtrlSetSamplingCycle(u32 cycle)
{
	DEBUG_LOG(SCECTRL, "sceCtrlSetSamplingCycle(%u)", cycle);

	if ((cycle > 0 && cycle < 5555) || cycle > 20000)
	{
		WARN_LOG(SCECTRL, "SCE_KERNEL_ERROR_INVALID_VALUE=sceCtrlSetSamplingCycle(%u)", cycle);
		return SCE_KERNEL_ERROR_INVALID_VALUE;
	}

	u32 prev = ctrlCycle;
	ctrlCycle = cycle;

	if (prev > 0)
		CoreTiming::UnscheduleEvent(ctrlTimer, 0);
	if (cycle > 0)
		CoreTiming::ScheduleEvent(usToCycles(ctrlCycle), ctrlTimer, 0);

	return prev;
}