Exemple #1
0
void CvSIFT::onNewImage() {
	LOG(LTRACE)<< "CvSIFT::onNewImage\n";
	try {
		// Input: a grayscale image.
		cv::Mat input = in_img.read();
		std::ofstream feature_calc_time;

		if(!string(prop_calc_path).empty()) {
			feature_calc_time.open((string(prop_calc_path)+string("czas_wyznaczenia_cech_sift.txt")).c_str(), ios::out|ios::app);
		}
		Common::Timer timer;

		timer.restart();
		//-- Step 1: Detect the keypoints.
		cv::SiftFeatureDetector detector(0,4);
		std::vector<cv::KeyPoint> keypoints;
		detector.detect(input, keypoints);

		//-- Step 2: Calculate descriptors (feature vectors).
		cv::SiftDescriptorExtractor extractor;
		Mat descriptors;
		extractor.compute( input, keypoints, descriptors);

		if(!string(prop_calc_path).empty()) {
			feature_calc_time << timer.elapsed() << endl;
		}
		// Write results to outputs.
		Types::Features features(keypoints);
		features.type = "SIFT";
		out_features.write(features);
		out_descriptors.write(descriptors);
	} catch (...) {
		LOG(LERROR) << "CvSIFT::onNewImage failed\n";
	}
}
Exemple #2
0
// Apply Frame Limit and Display FPS info
// This should only be called from VI
void VideoThrottle()
{
	u32 TargetVPS = (SConfig::GetInstance().m_Framelimit > 2) ?
		(SConfig::GetInstance().m_Framelimit - 1) * 5 : VideoInterface::TargetRefreshRate;

	// Disable the frame-limiter when the throttle (Tab) key is held down. Audio throttle: m_Framelimit = 2
	if (SConfig::GetInstance().m_Framelimit && SConfig::GetInstance().m_Framelimit != 2 && !Host_GetKeyState('\t'))
	{
		u32 frametime = ((SConfig::GetInstance().b_UseFPS)? Common::AtomicLoad(DrawnFrame) : DrawnVideo) * 1000 / TargetVPS;

		u32 timeDifference = (u32)Timer.GetTimeDifference();
		if (timeDifference < frametime) {
			Common::SleepCurrentThread(frametime - timeDifference - 1);
		}

		while ((u32)Timer.GetTimeDifference() < frametime)
			Common::YieldCPU();
			//Common::SleepCurrentThread(1);
	}

	// Update info per second
	u32 ElapseTime = (u32)Timer.GetTimeDifference();
	if ((ElapseTime >= 1000 && DrawnVideo > 0) || g_requestRefreshInfo)
	{
		UpdateTitle();

		// Reset counter
		Timer.Update();
		Common::AtomicStore(DrawnFrame, 0);
		DrawnVideo = 0;
	}

	DrawnVideo++;
}
Exemple #3
0
void BVHTest()
{
    Common::Timer timer;

    Random rand = Random(1);

#define NUM_INSERTIONS 100000
    Box* pBoxes = (Box*)_aligned_malloc(NUM_INSERTIONS * sizeof(Box), 16);
    for (int i = 0; i < NUM_INSERTIONS; i++)
    {
        Vector pos = rand.GetFloat3();
        pos *= 100.0f;
        pBoxes[i] = Box(pos - Vector(0.5f, 0.5f, 0.5), pos + Vector(0.5f, 0.5f, 0.5));
    }


    Util::BVH bvh;
    timer.Start();
    for (int i = 0; i < NUM_INSERTIONS; i++)
    {
        bvh.Insert(pBoxes[i], (void*)i);
    }
    double buildTime = timer.Stop();

    Box testBox = Box(Vector(50, 50, 50), Vector(60, 60, 60));

    //__asm int 3;
}
Exemple #4
0
// Display FPS info
// This should only be called from VI
void VideoThrottle()
{
	// Update info per second
	u32 ElapseTime = (u32)s_timer.GetTimeDifference();
	if ((ElapseTime >= 1000 && s_drawn_video.load() > 0) || s_request_refresh_info)
	{
		UpdateTitle();

		// Reset counter
		s_timer.Update();
		s_drawn_frame.store(0);
		s_drawn_video.store(0);
	}

	s_drawn_video++;
	bool update_ss_speed = true;
	if (SConfig::GetInstance().bDoubleVideoRate)
	{
		update_ss_speed = s_drawn_video & 1;
	}
	// Update the audio timestretcher with the current speed
	if (g_sound_stream && update_ss_speed)
	{
		float Speed = (float)(s_drawn_video.load() * 1000.0 / (VideoInterface::GetTargetRefreshRate() * ElapseTime));
		g_sound_stream->GetMixer()->UpdateSpeed((float)Speed);
	}
}
Exemple #5
0
// Write to the status bar
void WriteStatus()
{
	std::string TmpStr = "Time: " + ReRecTimer.GetTimeElapsedFormatted();
	TmpStr += StringFromFormat("  Frame: %s", ThousandSeparate(g_FrameCounter).c_str());
	// The FPS is the total average since the game was booted
	TmpStr += StringFromFormat("  FPS: %i", (g_FrameCounter * 1000) / ReRecTimer.GetTimeElapsed());
	TmpStr += StringFromFormat("  FrameStep: %s", g_FrameStep ? "On" : "Off");
	Host_UpdateStatusBar(TmpStr.c_str(), 1);	
}
void BlobExtractor_Processor::onNewImage() {
	LOG(LTRACE) << "BlobExtractor_Processor::onNewImage() called!\n";

	Common::Timer timer;
	timer.restart();

	cv::Mat in = in_img.read();
	in.convertTo(img_uchar, CV_8UC1);
	IplImage ipl_img = IplImage(img_uchar);
//  cv::Mat mat_img = img_uchar;
//	cv::Mat out = cv::Mat::zeros(in.size(), CV_8UC3);

	Types::Blobs::Blob_vector res;
	bool success;

	try
	{
		success = ComponentLabeling( &ipl_img, NULL, props.bkg_color, res );
	}
	catch(...)
	{
		success = false;
		LOG(LWARNING) << "blob find error\n";
	}

		try {
		if( !success ) {
			LOG(LERROR) << "Blob find error\n";
		} else {
			LOG(LTRACE) << "blobs found";
			Types::Blobs::BlobResult result(res);

			result.Filter( result, B_EXCLUDE, Types::Blobs::BlobGetArea(), B_LESS, min_size );

			out_blobs.write(result);
			LOG(LTRACE) << "blobs written";
			newBlobs->raise();
			LOG(LTRACE) << "blobs sent";
		//	result.draw(out, CV_RGB(255, 0, 0), 0, 0);
		//	out_img.write(in);
		//	newImage->raise();
		}

		LOG(LINFO) << "Blobing took " << timer.elapsed() << " seconds\n";
	}
	catch(...)
	{
		LOG(LERROR) << "BlobExtractor onNewImage failure";
	}
}
// Apply Frame Limit and Display FPS info
// This should only be called from VI
void VideoThrottle()
{
	// Update info per second
	u32 ElapseTime = (u32)s_timer.GetTimeDifference();
	if ((ElapseTime >= 1000 && s_drawn_video > 0) || s_request_refresh_info)
	{
		UpdateTitle();

		// Reset counter
		s_timer.Update();
		Common::AtomicStore(s_drawn_frame, 0);
		s_drawn_video = 0;
	}

	s_drawn_video++;
}
Exemple #8
0
// Display FPS info
// This should only be called from VI
void VideoThrottle()
{
  // Update info per second
  u32 ElapseTime = (u32)s_timer.GetTimeDifference();
  if ((ElapseTime >= 1000 && s_drawn_video.load() > 0) || s_request_refresh_info)
  {
    UpdateTitle();

    // Reset counter
    s_timer.Update();
    s_drawn_frame.store(0);
    s_drawn_video.store(0);
  }

  s_drawn_video++;
}
Exemple #9
0
// Apply Frame Limit and Display FPS info
// This should only be called from VI
void VideoThrottle()
{
	// Update info per second
	u32 ElapseTime = (u32)Timer.GetTimeDifference();
	if ((ElapseTime >= 1000 && DrawnVideo > 0) || g_requestRefreshInfo)
	{
		UpdateTitle();

		// Reset counter
		Timer.Update();
		Common::AtomicStore(DrawnFrame, 0);
		DrawnVideo = 0;
	}

	DrawnVideo++;
}
Exemple #10
0
// Start the timer when a game is booted
void RerecordingStart()
{
	g_FrameCounter = 0;
	ReRecTimer.Start();

	// Logging
	//DEBUG_LOG(CONSOLE, "RerecordingStart: %i\n", g_FrameCounter);
}
Exemple #11
0
// Reset the frame counter
void RerecordingStop()
{
	// Write the final time and Stop the timer
	ReRecTimer.Stop();

	// Update status bar
	WriteStatus();
}
Exemple #12
0
void UpdateTitle()
{
	u32 ElapseTime = (u32)s_timer.GetTimeDifference();
	s_request_refresh_info = false;
	SConfig& _CoreParameter = SConfig::GetInstance();

	if (ElapseTime == 0)
		ElapseTime = 1;

	float FPS   = (float)(s_drawn_frame.load() * 1000.0 / ElapseTime);
	float VPS   = (float)(s_drawn_video.load() * 1000.0 / ElapseTime);
	float Speed = (float)(s_drawn_video.load() * (100 * 1000.0) / (VideoInterface::GetTargetRefreshRate() * ElapseTime));

	// Settings are shown the same for both extended and summary info
	std::string SSettings = StringFromFormat("%s %s | %s | %s", cpu_core_base->GetName(), _CoreParameter.bCPUThread ? "DC" : "SC",
		g_video_backend->GetDisplayName().c_str(), _CoreParameter.bDSPHLE ? "HLE" : "LLE");

	std::string SFPS;

	if (Movie::IsPlayingInput())
		SFPS = StringFromFormat("VI: %u/%u - Input: %u/%u - FPS: %.0f - VPS: %.0f - %.0f%%", (u32)Movie::g_currentFrame, (u32)Movie::g_totalFrames, (u32)Movie::g_currentInputCount, (u32)Movie::g_totalInputCount, FPS, VPS, Speed);
	else if (Movie::IsRecordingInput())
		SFPS = StringFromFormat("VI: %u - Input: %u - FPS: %.0f - VPS: %.0f - %.0f%%", (u32)Movie::g_currentFrame, (u32)Movie::g_currentInputCount, FPS, VPS, Speed);
	else
	{
		SFPS = StringFromFormat("FPS: %.0f - VPS: %.0f - %.0f%%", FPS, VPS, Speed);
		if (SConfig::GetInstance().m_InterfaceExtendedFPSInfo)
		{
			// Use extended or summary information. The summary information does not print the ticks data,
			// that's more of a debugging interest, it can always be optional of course if someone is interested.
			static u64 ticks = 0;
			static u64 idleTicks = 0;
			u64 newTicks = CoreTiming::GetTicks();
			u64 newIdleTicks = CoreTiming::GetIdleTicks();

			u64 diff = (newTicks - ticks) / 1000000;
			u64 idleDiff = (newIdleTicks - idleTicks) / 1000000;

			ticks = newTicks;
			idleTicks = newIdleTicks;

			float TicksPercentage = (float)diff / (float)(SystemTimers::GetTicksPerSecond() / 1000000) * 100;

			SFPS += StringFromFormat(" | CPU: %s%i MHz [Real: %i + IdleSkip: %i] / %i MHz (%s%3.0f%%)",
					_CoreParameter.bSkipIdle ? "~" : "",
					(int)(diff),
					(int)(diff - idleDiff),
					(int)(idleDiff),
					SystemTimers::GetTicksPerSecond() / 1000000,
					_CoreParameter.bSkipIdle ? "~" : "",
					TicksPercentage);
		}
	}
	// This is our final "frame counter" string
	std::string SMessage = StringFromFormat("%s | %s", SSettings.c_str(), SFPS.c_str());
	Host_UpdateTitle(SMessage);
}
// Executed from GPU thread
// reports if a frame should be skipped or not
// depending on the framelimit set
bool ShouldSkipFrame(int skipped)
{
	const u32 TargetFPS = (SConfig::GetInstance().m_Framelimit > 1)
		? (SConfig::GetInstance().m_Framelimit - 1) * 5
		: VideoInterface::TargetRefreshRate;
	const u32 frames = Common::AtomicLoad(s_drawn_frame);
	const bool fps_slow = !(s_timer.GetTimeDifference() < (frames + skipped) * 1000 / TargetFPS);

	return fps_slow;
}
Exemple #14
0
// Executed from GPU thread
// reports if a frame should be skipped or not
// depending on the emulation speed set
bool ShouldSkipFrame(int skipped)
{
  u32 TargetFPS = VideoInterface::GetTargetRefreshRate();
  if (SConfig::GetInstance().m_EmulationSpeed > 0.0f)
    TargetFPS = u32(TargetFPS * SConfig::GetInstance().m_EmulationSpeed);
  const u32 frames = s_drawn_frame.load();
  const bool fps_slow = !(s_timer.GetTimeDifference() < (frames + skipped) * 1000 / TargetFPS);

  return fps_slow;
}
Exemple #15
0
/* Wind back the frame counter when a save state is loaded. Currently we don't know what that means in
   time so we just guess that the time is proportional the the number of frames
   
   Todo: There are many assumptions here: We probably want to replace the time here by the actual time
   that we save together with the save state or the input recording for example. And have it adjusted
   for full speed playback (whether it's 30 fps or 60 fps or some other speed that the game is natively
   capped at). Also the input interrupts do not occur as often as the frame renderings, they occur more
   often. So we may want to move the input recording to fram updates, or perhaps sync the input interrupts
   to frame updates.
   */
void WindBack(int Counter)
{
	/* Counter should be smaller than g_FrameCounter, however it currently updates faster than the
	   frames so currently it may not be the same. Therefore I use the abs() function. */
	int AbsoluteFrameDifference = abs(g_FrameCounter - Counter);
	float FractionalFrameDifference = (float) AbsoluteFrameDifference / (float) g_FrameCounter;

	// Update the frame counter
	g_FrameCounter = Counter;

	// Approximate a time to wind back the clock to
	// Get the current time
	u64 CurrentTimeMs = ReRecTimer.GetTimeElapsed();
	// Save the current time in seconds in a new double
	double CurrentTimeSeconds = (double) (CurrentTimeMs / 1000);
	// Reduce it by the same proportion as the counter was wound back
	CurrentTimeSeconds = CurrentTimeSeconds * FractionalFrameDifference;
	// Update the clock
	ReRecTimer.WindBackStartingTime((u64)CurrentTimeSeconds * 1000);

	// Logging
	DEBUG_LOG(CONSOLE, "WindBack: %i %u\n", Counter, (u64)CurrentTimeSeconds);
}
Exemple #16
0
void UDPWiimote::mainThread()
{
	std::unique_lock<std::mutex> lk(d->termLock);

	Common::Timer time;
	fd_set fds;
	struct timeval timeout;
	timeout.tv_sec=0;
	timeout.tv_usec=0;
	time.Update();
	do
	{
		int maxfd=0;
		FD_ZERO(&fds);
		for (auto& fd : d->sockfds)
		{
			FD_SET(fd,&fds);
#ifndef _WIN32
			if (fd>=maxfd)
				maxfd=(fd)+1;
#endif
		}

		u64 tleft=timeout.tv_sec*1000+timeout.tv_usec/1000;
		u64 telapsed=time.GetTimeDifference();
		time.Update();
		if (tleft<=telapsed)
		{
			timeout.tv_sec=1;
			timeout.tv_usec=500000;
			broadcastPresence();
		}
		else
		{
			tleft-=telapsed;
			timeout.tv_sec=(long)(tleft/1000);
			timeout.tv_usec=(tleft%1000)*1000;
		}

		lk.unlock(); //VERY hacky. don't like it
		if (d->exit) return;
		int rt=select(maxfd,&fds,NULL,NULL,&timeout);
		if (d->exit) return;
		lk.lock();
		if (d->exit) return;

		if (rt)
		{
			for (sock_t fd : d->sockfds)
			{
				if (FD_ISSET(fd,&fds))
				{
					u8 bf[64];
					int size=60;
					size_t addr_len;
					struct sockaddr_storage their_addr;
					addr_len = sizeof their_addr;
					if ((size = recvfrom(fd,
										 (dataz)bf,
										 size , 0,(struct sockaddr *)&their_addr, (socklen_t*)&addr_len)) == -1)
					{
						ERROR_LOG(WIIMOTE,"UDPWii Packet error");
					}
					else
					{
						std::lock_guard<std::mutex> lkm(d->mutex);
						if (pharsePacket(bf,size)==0)
						{
							//NOTICE_LOG(WIIMOTE,"UDPWII New pack");
						}
						else
						{
							//NOTICE_LOG(WIIMOTE,"UDPWII Wrong pack format... ignoring");
						}
					}
				}
			}
		}
	} while (!(d->exit));
}
namespace Core
{

bool g_want_determinism;

// Declarations and definitions
static Common::Timer s_timer;
static volatile u32 s_drawn_frame = 0;
static u32 s_drawn_video = 0;

// Function forwarding
void Callback_WiimoteInterruptChannel(int _number, u16 _channelID, const void* _pData, u32 _Size);

// Function declarations
void EmuThread();

static bool s_is_stopping = false;
static bool s_hardware_initialized = false;
static bool s_is_started = false;
static void* s_window_handle = nullptr;
static std::string s_state_filename;
static std::thread s_emu_thread;
static StoppedCallbackFunc s_on_stopped_callback = nullptr;

static std::thread s_cpu_thread;
static bool s_request_refresh_info = false;
static int s_pause_and_lock_depth = 0;
static bool s_is_framelimiter_temp_disabled = false;

bool GetIsFramelimiterTempDisabled()
{
	return s_is_framelimiter_temp_disabled;
}

void SetIsFramelimiterTempDisabled(bool disable)
{
	s_is_framelimiter_temp_disabled = disable;
}

std::string GetStateFileName() { return s_state_filename; }
void SetStateFileName(std::string val) { s_state_filename = val; }

// Display messages and return values

// Formatted stop message
std::string StopMessage(bool bMainThread, std::string Message)
{
	return StringFromFormat("Stop [%s %i]\t%s\t%s",
		bMainThread ? "Main Thread" : "Video Thread", Common::CurrentThreadId(), MemUsage().c_str(), Message.c_str());
}

void DisplayMessage(const std::string& message, int time_in_ms)
{
	// Actually displaying non-ASCII could cause things to go pear-shaped
	for (const char& c : message)
	{
		if (!std::isprint(c))
			return;
	}

	g_video_backend->Video_AddMessage(message, time_in_ms);
	Host_UpdateTitle(message);
}

bool IsRunning()
{
	return (GetState() != CORE_UNINITIALIZED) || s_hardware_initialized;
}

bool IsRunningAndStarted()
{
	return s_is_started && !s_is_stopping;
}

bool IsRunningInCurrentThread()
{
	return IsRunning() && IsCPUThread();
}

bool IsCPUThread()
{
	return (s_cpu_thread.joinable() ? (s_cpu_thread.get_id() == std::this_thread::get_id()) : !s_is_started);
}

bool IsGPUThread()
{
	const SCoreStartupParameter& _CoreParameter =
		SConfig::GetInstance().m_LocalCoreStartupParameter;
	if (_CoreParameter.bCPUThread)
	{
		return (s_emu_thread.joinable() && (s_emu_thread.get_id() == std::this_thread::get_id()));
	}
	else
	{
		return IsCPUThread();
	}
}

// This is called from the GUI thread. See the booting call schedule in
// BootManager.cpp
bool Init()
{
	const SCoreStartupParameter& _CoreParameter =
		SConfig::GetInstance().m_LocalCoreStartupParameter;

	if (s_emu_thread.joinable())
	{
		if (IsRunning())
		{
			PanicAlertT("Emu Thread already running");
			return false;
		}

		// The Emu Thread was stopped, synchronize with it.
		s_emu_thread.join();
	}

	Core::UpdateWantDeterminism(/*initial*/ true);

	INFO_LOG(OSREPORT, "Starting core = %s mode",
		_CoreParameter.bWii ? "Wii" : "GameCube");
	INFO_LOG(OSREPORT, "CPU Thread separate = %s",
		_CoreParameter.bCPUThread ? "Yes" : "No");

	Host_UpdateMainFrame(); // Disable any menus or buttons at boot

	g_aspect_wide = _CoreParameter.bWii;
	if (g_aspect_wide)
	{
		IniFile gameIni = _CoreParameter.LoadGameIni();
		gameIni.GetOrCreateSection("Wii")->Get("Widescreen", &g_aspect_wide,
		     !!SConfig::GetInstance().m_SYSCONF->GetData<u8>("IPL.AR"));
	}

	s_window_handle = Host_GetRenderHandle();

	// Start the emu thread
	s_emu_thread = std::thread(EmuThread);

	return true;
}

// Called from GUI thread
void Stop()  // - Hammertime!
{
	if (GetState() == CORE_STOPPING)
		return;

	const SCoreStartupParameter& _CoreParameter =
		SConfig::GetInstance().m_LocalCoreStartupParameter;

	s_is_stopping = true;

	g_video_backend->EmuStateChange(EMUSTATE_CHANGE_STOP);

	INFO_LOG(CONSOLE, "Stop [Main Thread]\t\t---- Shutting down ----");

	// Stop the CPU
	INFO_LOG(CONSOLE, "%s", StopMessage(true, "Stop CPU").c_str());
	PowerPC::Stop();

	// Kick it if it's waiting (code stepping wait loop)
	CCPU::StepOpcode();

	if (_CoreParameter.bCPUThread)
	{
		// Video_EnterLoop() should now exit so that EmuThread()
		// will continue concurrently with the rest of the commands
		// in this function. We no longer rely on Postmessage.
		INFO_LOG(CONSOLE, "%s", StopMessage(true, "Wait for Video Loop to exit ...").c_str());

		g_video_backend->Video_ExitLoop();
	}
}

// Create the CPU thread, which is a CPU + Video thread in Single Core mode.
static void CpuThread()
{
	const SCoreStartupParameter& _CoreParameter =
		SConfig::GetInstance().m_LocalCoreStartupParameter;

	if (_CoreParameter.bCPUThread)
	{
		Common::SetCurrentThreadName("CPU thread");
	}
	else
	{
		Common::SetCurrentThreadName("CPU-GPU thread");
		g_video_backend->Video_Prepare();
	}

	if (_CoreParameter.bFastmem)
		EMM::InstallExceptionHandler(); // Let's run under memory watch

	if (!s_state_filename.empty())
		State::LoadAs(s_state_filename);

	s_is_started = true;


	#ifdef USE_GDBSTUB
	if (_CoreParameter.iGDBPort > 0)
	{
		gdb_init(_CoreParameter.iGDBPort);
		// break at next instruction (the first instruction)
		gdb_break();
	}
	#endif

	// Enter CPU run loop. When we leave it - we are done.
	CCPU::Run();

	s_is_started = false;

	if (!_CoreParameter.bCPUThread)
		g_video_backend->Video_Cleanup();

	EMM::UninstallExceptionHandler();

	return;
}

static void FifoPlayerThread()
{
	const SCoreStartupParameter& _CoreParameter = SConfig::GetInstance().m_LocalCoreStartupParameter;

	if (_CoreParameter.bCPUThread)
	{
		Common::SetCurrentThreadName("FIFO player thread");
	}
	else
	{
		g_video_backend->Video_Prepare();
		Common::SetCurrentThreadName("FIFO-GPU thread");
	}

	s_is_started = true;

	// Enter CPU run loop. When we leave it - we are done.
	if (FifoPlayer::GetInstance().Open(_CoreParameter.m_strFilename))
	{
		FifoPlayer::GetInstance().Play();
		FifoPlayer::GetInstance().Close();
	}

	s_is_started = false;

	if (!_CoreParameter.bCPUThread)
		g_video_backend->Video_Cleanup();

	return;
}

// Initialize and create emulation thread
// Call browser: Init():s_emu_thread().
// See the BootManager.cpp file description for a complete call schedule.
void EmuThread()
{
	const SCoreStartupParameter& core_parameter =
		SConfig::GetInstance().m_LocalCoreStartupParameter;

	Common::SetCurrentThreadName("Emuthread - Starting");

	if (SConfig::GetInstance().m_OCEnable)
		DisplayMessage("WARNING: running at non-native CPU clock! Game may not be stable.", 8000);
	DisplayMessage(cpu_info.brand_string, 8000);
	DisplayMessage(cpu_info.Summarize(), 8000);
	DisplayMessage(core_parameter.m_strFilename, 3000);

	Movie::Init();

	HW::Init();

	if (!g_video_backend->Initialize(s_window_handle))
	{
		PanicAlert("Failed to initialize video backend!");
		Host_Message(WM_USER_STOP);
		return;
	}

	OSD::AddMessage("Dolphin " + g_video_backend->GetName() + " Video Backend.", 5000);

	if (cpu_info.HTT)
		SConfig::GetInstance().m_LocalCoreStartupParameter.bDSPThread = cpu_info.num_cores > 4;
	else
		SConfig::GetInstance().m_LocalCoreStartupParameter.bDSPThread = cpu_info.num_cores > 2;

	if (!DSP::GetDSPEmulator()->Initialize(core_parameter.bWii, core_parameter.bDSPThread))
	{
		HW::Shutdown();
		g_video_backend->Shutdown();
		PanicAlert("Failed to initialize DSP emulator!");
		Host_Message(WM_USER_STOP);
		return;
	}

	Keyboard::Initialize(s_window_handle);
	Pad::Initialize(s_window_handle);

	// Load and Init Wiimotes - only if we are booting in Wii mode
	if (core_parameter.bWii)
	{
		Wiimote::Initialize(s_window_handle, !s_state_filename.empty());

		// Activate Wiimotes which don't have source set to "None"
		for (unsigned int i = 0; i != MAX_BBMOTES; ++i)
			if (g_wiimote_sources[i])
				GetUsbPointer()->AccessWiiMote(i | 0x100)->Activate(true);

	}

	AudioCommon::InitSoundStream();

	// The hardware is initialized.
	s_hardware_initialized = true;

	// Boot to pause or not
	Core::SetState(core_parameter.bBootToPause ? Core::CORE_PAUSE : Core::CORE_RUN);

	// Load GCM/DOL/ELF whatever ... we boot with the interpreter core
	PowerPC::SetMode(PowerPC::MODE_INTERPRETER);

	CBoot::BootUp();

	// Setup our core, but can't use dynarec if we are compare server
	if (core_parameter.iCPUCore != SCoreStartupParameter::CORE_INTERPRETER
	    && (!core_parameter.bRunCompareServer || core_parameter.bRunCompareClient))
	{
		PowerPC::SetMode(PowerPC::MODE_JIT);
	}
	else
	{
		PowerPC::SetMode(PowerPC::MODE_INTERPRETER);
	}

	// Update the window again because all stuff is initialized
	Host_UpdateDisasmDialog();
	Host_UpdateMainFrame();

	// Determine the CPU thread function
	void (*cpuThreadFunc)(void);
	if (core_parameter.m_BootType == SCoreStartupParameter::BOOT_DFF)
		cpuThreadFunc = FifoPlayerThread;
	else
		cpuThreadFunc = CpuThread;

	// ENTER THE VIDEO THREAD LOOP
	if (core_parameter.bCPUThread)
	{
		// This thread, after creating the EmuWindow, spawns a CPU
		// thread, and then takes over and becomes the video thread
		Common::SetCurrentThreadName("Video thread");

		g_video_backend->Video_Prepare();

		// Spawn the CPU thread
		s_cpu_thread = std::thread(cpuThreadFunc);

		// become the GPU thread
		g_video_backend->Video_EnterLoop();

		// We have now exited the Video Loop
		INFO_LOG(CONSOLE, "%s", StopMessage(false, "Video Loop Ended").c_str());
	}
	else // SingleCore mode
	{
		// The spawned CPU Thread also does the graphics.
		// The EmuThread is thus an idle thread, which sleeps while
		// waiting for the program to terminate. Without this extra
		// thread, the video backend window hangs in single core mode
		// because no one is pumping messages.
		Common::SetCurrentThreadName("Emuthread - Idle");

		// Spawn the CPU+GPU thread
		s_cpu_thread = std::thread(cpuThreadFunc);

		while (PowerPC::GetState() != PowerPC::CPU_POWERDOWN)
		{
			g_video_backend->PeekMessages();
			Common::SleepCurrentThread(20);
		}
	}

	INFO_LOG(CONSOLE, "%s", StopMessage(true, "Stopping Emu thread ...").c_str());

	// Wait for s_cpu_thread to exit
	INFO_LOG(CONSOLE, "%s", StopMessage(true, "Stopping CPU-GPU thread ...").c_str());

	#ifdef USE_GDBSTUB
	INFO_LOG(CONSOLE, "%s", StopMessage(true, "Stopping GDB ...").c_str());
	gdb_deinit();
	INFO_LOG(CONSOLE, "%s", StopMessage(true, "GDB stopped.").c_str());
	#endif

	s_cpu_thread.join();

	INFO_LOG(CONSOLE, "%s", StopMessage(true, "CPU thread stopped.").c_str());

	if (core_parameter.bCPUThread)
		g_video_backend->Video_Cleanup();

	VolumeHandler::EjectVolume();
	FileMon::Close();

	// Stop audio thread - Actually this does nothing when using HLE
	// emulation, but stops the DSP Interpreter when using LLE emulation.
	DSP::GetDSPEmulator()->DSP_StopSoundStream();

	// We must set up this flag before executing HW::Shutdown()
	s_hardware_initialized = false;
	INFO_LOG(CONSOLE, "%s", StopMessage(false, "Shutting down HW").c_str());
	HW::Shutdown();
	INFO_LOG(CONSOLE, "%s", StopMessage(false, "HW shutdown").c_str());

	Wiimote::Shutdown();

	Keyboard::Shutdown();
	Pad::Shutdown();

	g_video_backend->Shutdown();
	AudioCommon::ShutdownSoundStream();

	INFO_LOG(CONSOLE, "%s", StopMessage(true, "Main Emu thread stopped").c_str());

	// Clear on screen messages that haven't expired
	g_video_backend->Video_ClearMessages();

	// Reload sysconf file in order to see changes committed during emulation
	if (core_parameter.bWii)
		SConfig::GetInstance().m_SYSCONF->Reload();

	INFO_LOG(CONSOLE, "Stop [Video Thread]\t\t---- Shutdown complete ----");
	Movie::Shutdown();
	PatchEngine::Shutdown();

	s_is_stopping = false;

	if (s_on_stopped_callback)
		s_on_stopped_callback();
}

// Set or get the running state

void SetState(EState _State)
{
	switch (_State)
	{
	case CORE_PAUSE:
		CCPU::EnableStepping(true);  // Break
		Wiimote::Pause();
		break;
	case CORE_RUN:
		CCPU::EnableStepping(false);
		Wiimote::Resume();
		break;
	default:
		PanicAlertT("Invalid state");
		break;
	}
}

EState GetState()
{
	if (s_is_stopping)
		return CORE_STOPPING;

	if (s_hardware_initialized)
	{
		if (CCPU::IsStepping())
			return CORE_PAUSE;
		else
			return CORE_RUN;
	}

	return CORE_UNINITIALIZED;
}

static std::string GenerateScreenshotName()
{
	const std::string& gameId = SConfig::GetInstance().m_LocalCoreStartupParameter.GetUniqueID();
	std::string path = File::GetUserPath(D_SCREENSHOTS_IDX) + gameId + DIR_SEP_CHR;

	if (!File::CreateFullPath(path))
	{
		// fallback to old-style screenshots, without folder.
		path = File::GetUserPath(D_SCREENSHOTS_IDX);
	}

	//append gameId, path only contains the folder here.
	path += gameId;

	std::string name;
	for (int i = 1; File::Exists(name = StringFromFormat("%s-%d.png", path.c_str(), i)); ++i)
	{
		// TODO?
	}

	return name;
}

void SaveScreenShot()
{
	const bool bPaused = (GetState() == CORE_PAUSE);

	SetState(CORE_PAUSE);

	g_video_backend->Video_Screenshot(GenerateScreenshotName());

	if (!bPaused)
		SetState(CORE_RUN);
}

void RequestRefreshInfo()
{
	s_request_refresh_info = true;
}

bool PauseAndLock(bool doLock, bool unpauseOnUnlock)
{
	if (!IsRunning())
		return true;

	// let's support recursive locking to simplify things on the caller's side,
	// and let's do it at this outer level in case the individual systems don't support it.
	if (doLock ? s_pause_and_lock_depth++ : --s_pause_and_lock_depth)
		return true;

	// first pause or unpause the CPU
	bool wasUnpaused = CCPU::PauseAndLock(doLock, unpauseOnUnlock);
	ExpansionInterface::PauseAndLock(doLock, unpauseOnUnlock);

	// audio has to come after CPU, because CPU thread can wait for audio thread (m_throttle).
	AudioCommon::PauseAndLock(doLock, unpauseOnUnlock);
	DSP::GetDSPEmulator()->PauseAndLock(doLock, unpauseOnUnlock);

	// video has to come after CPU, because CPU thread can wait for video thread (s_efbAccessRequested).
	g_video_backend->PauseAndLock(doLock, unpauseOnUnlock);
	return wasUnpaused;
}

// Apply Frame Limit and Display FPS info
// This should only be called from VI
void VideoThrottle()
{
	// Update info per second
	u32 ElapseTime = (u32)s_timer.GetTimeDifference();
	if ((ElapseTime >= 1000 && s_drawn_video > 0) || s_request_refresh_info)
	{
		UpdateTitle();

		// Reset counter
		s_timer.Update();
		Common::AtomicStore(s_drawn_frame, 0);
		s_drawn_video = 0;
	}

	s_drawn_video++;
}

// Executed from GPU thread
// reports if a frame should be skipped or not
// depending on the framelimit set
bool ShouldSkipFrame(int skipped)
{
	const u32 TargetFPS = (SConfig::GetInstance().m_Framelimit > 1)
		? (SConfig::GetInstance().m_Framelimit - 1) * 5
		: VideoInterface::TargetRefreshRate;
	const u32 frames = Common::AtomicLoad(s_drawn_frame);
	const bool fps_slow = !(s_timer.GetTimeDifference() < (frames + skipped) * 1000 / TargetFPS);

	return fps_slow;
}

// --- Callbacks for backends / engine ---

// Should be called from GPU thread when a frame is drawn
void Callback_VideoCopiedToXFB(bool video_update)
{
	if (video_update)
		Common::AtomicIncrement(s_drawn_frame);
	Movie::FrameUpdate();

	//Dragonbane
	if (Movie::updateMainFrame)
	{
		Movie::updateMainFrame = false;
		Host_UpdateMainFrame();
	}
}

void UpdateTitle()
{
	u32 ElapseTime = (u32)s_timer.GetTimeDifference();
	s_request_refresh_info = false;
	SCoreStartupParameter& _CoreParameter = SConfig::GetInstance().m_LocalCoreStartupParameter;

	if (ElapseTime == 0)
		ElapseTime = 1;

	float FPS = (float) (Common::AtomicLoad(s_drawn_frame) * 1000.0 / ElapseTime);
	float VPS = (float) (s_drawn_video * 1000.0 / ElapseTime);
	float Speed = (float) (s_drawn_video * (100 * 1000.0) / (VideoInterface::TargetRefreshRate * ElapseTime));

	// Settings are shown the same for both extended and summary info
	std::string SSettings = StringFromFormat("%s %s | %s | %s", cpu_core_base->GetName(), _CoreParameter.bCPUThread ? "DC" : "SC",
		g_video_backend->GetDisplayName().c_str(), _CoreParameter.bDSPHLE ? "HLE" : "LLE");

	std::string SFPS;

	if (Movie::IsPlayingInput())
		SFPS = StringFromFormat("VI: %u/%u - Input: %u/%u - FPS: %.0f - VPS: %.0f - %.0f%%", (u32)Movie::g_currentFrame, (u32)Movie::g_totalFrames, (u32)Movie::g_currentInputCount, (u32)Movie::g_totalInputCount, FPS, VPS, Speed);
	else if (Movie::IsRecordingInput())
		SFPS = StringFromFormat("VI: %u - Input: %u - FPS: %.0f - VPS: %.0f - %.0f%%", (u32)Movie::g_currentFrame, (u32)Movie::g_currentInputCount, FPS, VPS, Speed);
	else
	{
		SFPS = StringFromFormat("FPS: %.0f - VPS: %.0f - %.0f%%", FPS, VPS, Speed);
		if (SConfig::GetInstance().m_InterfaceExtendedFPSInfo)
		{
			// Use extended or summary information. The summary information does not print the ticks data,
			// that's more of a debugging interest, it can always be optional of course if someone is interested.
			static u64 ticks = 0;
			static u64 idleTicks = 0;
			u64 newTicks = CoreTiming::GetTicks();
			u64 newIdleTicks = CoreTiming::GetIdleTicks();

			u64 diff = (newTicks - ticks) / 1000000;
			u64 idleDiff = (newIdleTicks - idleTicks) / 1000000;

			ticks = newTicks;
			idleTicks = newIdleTicks;

			float TicksPercentage = (float)diff / (float)(SystemTimers::GetTicksPerSecond() / 1000000) * 100;

			SFPS += StringFromFormat(" | CPU: %s%i MHz [Real: %i + IdleSkip: %i] / %i MHz (%s%3.0f%%)",
					_CoreParameter.bSkipIdle ? "~" : "",
					(int)(diff),
					(int)(diff - idleDiff),
					(int)(idleDiff),
					SystemTimers::GetTicksPerSecond() / 1000000,
					_CoreParameter.bSkipIdle ? "~" : "",
					TicksPercentage);
		}
	}
	// This is our final "frame counter" string
	std::string SMessage = StringFromFormat("%s | %s", SSettings.c_str(), SFPS.c_str());

	// Update the audio timestretcher with the current speed
	if (g_sound_stream)
	{
		CMixer* pMixer = g_sound_stream->GetMixer();
		pMixer->UpdateSpeed((float)Speed / 100);
	}

	Host_UpdateTitle(SMessage);
}

void Shutdown()
{
	if (s_emu_thread.joinable())
		s_emu_thread.join();
}

void SetOnStoppedCallback(StoppedCallbackFunc callback)
{
	s_on_stopped_callback = callback;
}

void UpdateWantDeterminism(bool initial)
{
	// For now, this value is not itself configurable.  Instead, individual
	// settings that depend on it, such as GPU determinism mode. should have
	// override options for testing,
	bool new_want_determinism =
		Movie::IsPlayingInput() ||
		Movie::IsRecordingInput() ||
		NetPlay::IsNetPlayRunning();
	if (new_want_determinism != g_want_determinism || initial)
	{
		WARN_LOG(COMMON, "Want determinism <- %s", new_want_determinism ? "true" : "false");

		bool was_unpaused = Core::PauseAndLock(true);

		g_want_determinism = new_want_determinism;
		WiiSockMan::GetInstance().UpdateWantDeterminism(new_want_determinism);
		g_video_backend->UpdateWantDeterminism(new_want_determinism);
		// We need to clear the cache because some parts of the JIT depend on want_determinism, e.g. use of FMA.
		JitInterface::ClearCache();

		Core::PauseAndLock(false, was_unpaused);
	}
}

} // Core
Exemple #18
0
namespace Core
{



// Declarations and definitions
// ---------------
int g_FrameCounter = 0;
bool g_FrameStep = false;
Common::Timer ReRecTimer;




// Control Run, Pause, Stop and the Timer.
// ---------------

// Subtract the paused time when we run again
void Run()
{
	ReRecTimer.AddTimeDifference();
}
// Update the time
void Pause()
{
	ReRecTimer.Update();
}

// Start the timer when a game is booted
void RerecordingStart()
{
	g_FrameCounter = 0;
	ReRecTimer.Start();

	// Logging
	//DEBUG_LOG(CONSOLE, "RerecordingStart: %i\n", g_FrameCounter);
}

// Reset the frame counter
void RerecordingStop()
{
	// Write the final time and Stop the timer
	ReRecTimer.Stop();

	// Update status bar
	WriteStatus();
}

/* Wind back the frame counter when a save state is loaded. Currently we don't know what that means in
   time so we just guess that the time is proportional the the number of frames
   
   Todo: There are many assumptions here: We probably want to replace the time here by the actual time
   that we save together with the save state or the input recording for example. And have it adjusted
   for full speed playback (whether it's 30 fps or 60 fps or some other speed that the game is natively
   capped at). Also the input interrupts do not occur as often as the frame renderings, they occur more
   often. So we may want to move the input recording to fram updates, or perhaps sync the input interrupts
   to frame updates.
   */
void WindBack(int Counter)
{
	/* Counter should be smaller than g_FrameCounter, however it currently updates faster than the
	   frames so currently it may not be the same. Therefore I use the abs() function. */
	int AbsoluteFrameDifference = abs(g_FrameCounter - Counter);
	float FractionalFrameDifference = (float) AbsoluteFrameDifference / (float) g_FrameCounter;

	// Update the frame counter
	g_FrameCounter = Counter;

	// Approximate a time to wind back the clock to
	// Get the current time
	u64 CurrentTimeMs = ReRecTimer.GetTimeElapsed();
	// Save the current time in seconds in a new double
	double CurrentTimeSeconds = (double) (CurrentTimeMs / 1000);
	// Reduce it by the same proportion as the counter was wound back
	CurrentTimeSeconds = CurrentTimeSeconds * FractionalFrameDifference;
	// Update the clock
	ReRecTimer.WindBackStartingTime((u64)CurrentTimeSeconds * 1000);

	// Logging
	DEBUG_LOG(CONSOLE, "WindBack: %i %u\n", Counter, (u64)CurrentTimeSeconds);
}




// Frame advance
// ---------------
void FrameAdvance()
{
	// Update status bar
	WriteStatus();	

	// If a game is not started, return
	if (Core::GetState() == Core::CORE_UNINITIALIZED) return;

	// Play to the next frame
	if (g_FrameStep)
	{
		Run();
		Core::SetState(Core::CORE_RUN);	
	}
}

// Turn on frame stepping
void FrameStepOnOff()
{
	/* Turn frame step on or off. If a game is running and we turn this on it means that the game
	   will pause after the next frame update */
	g_FrameStep = !g_FrameStep;

	// Update status bar
	WriteStatus();

	// If a game is not started, return
	if(Core::GetState() == Core::CORE_UNINITIALIZED) return;

	// Run the emulation if we turned off framestepping
	if (!g_FrameStep)
	{
		Run();
		Core::SetState(Core::CORE_RUN);
	}
}




// General functions
// ---------------

// Write to the status bar
void WriteStatus()
{
	std::string TmpStr = "Time: " + ReRecTimer.GetTimeElapsedFormatted();
	TmpStr += StringFromFormat("  Frame: %s", ThousandSeparate(g_FrameCounter).c_str());
	// The FPS is the total average since the game was booted
	TmpStr += StringFromFormat("  FPS: %i", (g_FrameCounter * 1000) / ReRecTimer.GetTimeElapsed());
	TmpStr += StringFromFormat("  FrameStep: %s", g_FrameStep ? "On" : "Off");
	Host_UpdateStatusBar(TmpStr.c_str(), 1);	
}


// When a new frame is drawn
void FrameUpdate()
{
	// Write to the status bar
	WriteStatus();
	/* I don't think the frequent update has any material speed inpact at all, but should it
	   have you can controls the update speed by changing the "% 10" in this line */
	//if (g_FrameCounter % 10 == 0) WriteStatus();

	// Pause if frame stepping is on
	if(g_FrameStep)
	{
		Pause();
		Core::SetState(Core::CORE_PAUSE);
	}

	// Count one frame
	g_FrameCounter++;
}



} // Core
Exemple #19
0
namespace Core
{
// TODO: ugly, remove
bool g_aspect_wide;

bool g_want_determinism;

// Declarations and definitions
static Common::Timer s_timer;
static std::atomic<u32> s_drawn_frame;
static std::atomic<u32> s_drawn_video;

// Function forwarding
void Callback_WiimoteInterruptChannel(int _number, u16 _channelID, const void* _pData, u32 _Size);

// Function declarations
void EmuThread();

static bool s_is_stopping = false;
static bool s_hardware_initialized = false;
static bool s_is_started = false;
static std::atomic<bool> s_is_booting{false};
static void* s_window_handle = nullptr;
static std::string s_state_filename;
static std::thread s_emu_thread;
static StoppedCallbackFunc s_on_stopped_callback = nullptr;

static std::thread s_cpu_thread;
static bool s_request_refresh_info = false;
static int s_pause_and_lock_depth = 0;
static bool s_is_throttler_temp_disabled = false;

struct HostJob
{
  std::function<void()> job;
  bool run_after_stop;
};
static std::mutex s_host_jobs_lock;
static std::queue<HostJob> s_host_jobs_queue;

#ifdef ThreadLocalStorage
static ThreadLocalStorage bool tls_is_cpu_thread = false;
#else
static pthread_key_t s_tls_is_cpu_key;
static pthread_once_t s_cpu_key_is_init = PTHREAD_ONCE_INIT;
static void InitIsCPUKey()
{
  pthread_key_create(&s_tls_is_cpu_key, nullptr);
}
#endif

bool GetIsThrottlerTempDisabled()
{
  return s_is_throttler_temp_disabled;
}

void SetIsThrottlerTempDisabled(bool disable)
{
  s_is_throttler_temp_disabled = disable;
}

std::string GetStateFileName()
{
  return s_state_filename;
}
void SetStateFileName(const std::string& val)
{
  s_state_filename = val;
}

void FrameUpdateOnCPUThread()
{
  if (NetPlay::IsNetPlayRunning())
    NetPlayClient::SendTimeBase();
}

// Display messages and return values

// Formatted stop message
std::string StopMessage(bool main_thread, const std::string& message)
{
  return StringFromFormat("Stop [%s %i]\t%s\t%s", main_thread ? "Main Thread" : "Video Thread",
                          Common::CurrentThreadId(), MemUsage().c_str(), message.c_str());
}

void DisplayMessage(const std::string& message, int time_in_ms)
{
  if (!IsRunning())
    return;

  // Actually displaying non-ASCII could cause things to go pear-shaped
  for (const char& c : message)
  {
    if (!std::isprint(c))
      return;
  }

  OSD::AddMessage(message, time_in_ms);
  Host_UpdateTitle(message);
}

bool IsRunning()
{
  return (GetState() != CORE_UNINITIALIZED || s_hardware_initialized) && !s_is_stopping;
}

bool IsRunningAndStarted()
{
  return s_is_started && !s_is_stopping;
}

bool IsRunningInCurrentThread()
{
  return IsRunning() && IsCPUThread();
}

bool IsCPUThread()
{
#ifdef ThreadLocalStorage
  return tls_is_cpu_thread;
#else
  // Use pthread implementation for Android and Mac
  // Make sure that s_tls_is_cpu_key is initialized
  pthread_once(&s_cpu_key_is_init, InitIsCPUKey);
  return pthread_getspecific(s_tls_is_cpu_key);
#endif
}

bool IsGPUThread()
{
  const SConfig& _CoreParameter = SConfig::GetInstance();
  if (_CoreParameter.bCPUThread)
  {
    return (s_emu_thread.joinable() && (s_emu_thread.get_id() == std::this_thread::get_id()));
  }
  else
  {
    return IsCPUThread();
  }
}

// This is called from the GUI thread. See the booting call schedule in
// BootManager.cpp
bool Init()
{
  const SConfig& _CoreParameter = SConfig::GetInstance();

  if (s_emu_thread.joinable())
  {
    if (IsRunning())
    {
      PanicAlertT("Emu Thread already running");
      return false;
    }

    // The Emu Thread was stopped, synchronize with it.
    s_emu_thread.join();
  }

  // Drain any left over jobs
  HostDispatchJobs();

  Core::UpdateWantDeterminism(/*initial*/ true);

  INFO_LOG(OSREPORT, "Starting core = %s mode", _CoreParameter.bWii ? "Wii" : "GameCube");
  INFO_LOG(OSREPORT, "CPU Thread separate = %s", _CoreParameter.bCPUThread ? "Yes" : "No");

  Host_UpdateMainFrame();  // Disable any menus or buttons at boot

  g_aspect_wide = _CoreParameter.bWii;
  if (g_aspect_wide)
  {
    IniFile gameIni = _CoreParameter.LoadGameIni();
    gameIni.GetOrCreateSection("Wii")->Get(
        "Widescreen", &g_aspect_wide, !!SConfig::GetInstance().m_SYSCONF->GetData<u8>("IPL.AR"));
  }

  s_window_handle = Host_GetRenderHandle();

  // Start the emu thread
  s_emu_thread = std::thread(EmuThread);

  return true;
}

// Called from GUI thread
void Stop()  // - Hammertime!
{
  if (GetState() == CORE_STOPPING)
    return;

  const SConfig& _CoreParameter = SConfig::GetInstance();

  s_is_stopping = true;

  // Dump left over jobs
  HostDispatchJobs();

  Fifo::EmulatorState(false);

  INFO_LOG(CONSOLE, "Stop [Main Thread]\t\t---- Shutting down ----");

  // Stop the CPU
  INFO_LOG(CONSOLE, "%s", StopMessage(true, "Stop CPU").c_str());
  CPU::Stop();

  if (_CoreParameter.bCPUThread)
  {
    // Video_EnterLoop() should now exit so that EmuThread()
    // will continue concurrently with the rest of the commands
    // in this function. We no longer rely on Postmessage.
    INFO_LOG(CONSOLE, "%s", StopMessage(true, "Wait for Video Loop to exit ...").c_str());

    g_video_backend->Video_ExitLoop();
  }
#if defined(__LIBUSB__) || defined(_WIN32)
  GCAdapter::ResetRumble();
#endif

#ifdef USE_MEMORYWATCHER
  MemoryWatcher::Shutdown();
#endif
}

void DeclareAsCPUThread()
{
#ifdef ThreadLocalStorage
  tls_is_cpu_thread = true;
#else
  // Use pthread implementation for Android and Mac
  // Make sure that s_tls_is_cpu_key is initialized
  pthread_once(&s_cpu_key_is_init, InitIsCPUKey);
  pthread_setspecific(s_tls_is_cpu_key, (void*)true);
#endif
}

void UndeclareAsCPUThread()
{
#ifdef ThreadLocalStorage
  tls_is_cpu_thread = false;
#else
  // Use pthread implementation for Android and Mac
  // Make sure that s_tls_is_cpu_key is initialized
  pthread_once(&s_cpu_key_is_init, InitIsCPUKey);
  pthread_setspecific(s_tls_is_cpu_key, (void*)false);
#endif
}

// For the CPU Thread only.
static void CPUSetInitialExecutionState()
{
  QueueHostJob([] {
    SetState(SConfig::GetInstance().bBootToPause ? CORE_PAUSE : CORE_RUN);
    Host_UpdateMainFrame();
  });
}

// Create the CPU thread, which is a CPU + Video thread in Single Core mode.
static void CpuThread()
{
  DeclareAsCPUThread();

  const SConfig& _CoreParameter = SConfig::GetInstance();

  if (_CoreParameter.bCPUThread)
  {
    Common::SetCurrentThreadName("CPU thread");
  }
  else
  {
    Common::SetCurrentThreadName("CPU-GPU thread");
    g_video_backend->Video_Prepare();
  }

  // This needs to be delayed until after the video backend is ready.
  DolphinAnalytics::Instance()->ReportGameStart();

  if (_CoreParameter.bFastmem)
    EMM::InstallExceptionHandler();  // Let's run under memory watch

  if (!s_state_filename.empty())
  {
    // Needs to PauseAndLock the Core
    // NOTE: EmuThread should have left us in CPU_STEPPING so nothing will happen
    //   until after the job is serviced.
    QueueHostJob([] {
      // Recheck in case Movie cleared it since.
      if (!s_state_filename.empty())
        State::LoadAs(s_state_filename);
    });
  }

  s_is_started = true;
  CPUSetInitialExecutionState();

#ifdef USE_GDBSTUB
#ifndef _WIN32
  if (!_CoreParameter.gdb_socket.empty())
  {
    gdb_init_local(_CoreParameter.gdb_socket.data());
    gdb_break();
  }
  else
#endif
      if (_CoreParameter.iGDBPort > 0)
  {
    gdb_init(_CoreParameter.iGDBPort);
    // break at next instruction (the first instruction)
    gdb_break();
  }
#endif

#ifdef USE_MEMORYWATCHER
  MemoryWatcher::Init();
#endif

  // Enter CPU run loop. When we leave it - we are done.
  CPU::Run();

  s_is_started = false;

  if (!_CoreParameter.bCPUThread)
    g_video_backend->Video_Cleanup();

  if (_CoreParameter.bFastmem)
    EMM::UninstallExceptionHandler();

  return;
}

static void FifoPlayerThread()
{
  DeclareAsCPUThread();
  const SConfig& _CoreParameter = SConfig::GetInstance();

  if (_CoreParameter.bCPUThread)
  {
    Common::SetCurrentThreadName("FIFO player thread");
  }
  else
  {
    g_video_backend->Video_Prepare();
    Common::SetCurrentThreadName("FIFO-GPU thread");
  }

  // Enter CPU run loop. When we leave it - we are done.
  if (FifoPlayer::GetInstance().Open(_CoreParameter.m_strFilename))
  {
    if (auto cpu_core = FifoPlayer::GetInstance().GetCPUCore())
    {
      PowerPC::InjectExternalCPUCore(cpu_core.get());
      s_is_started = true;

      CPUSetInitialExecutionState();
      CPU::Run();

      s_is_started = false;
      PowerPC::InjectExternalCPUCore(nullptr);
    }
    FifoPlayer::GetInstance().Close();
  }

  // If we did not enter the CPU Run Loop above then run a fake one instead.
  // We need to be IsRunningAndStarted() for DolphinWX to stop us.
  if (CPU::GetState() != CPU::CPU_POWERDOWN)
  {
    s_is_started = true;
    Host_Message(WM_USER_STOP);
    while (CPU::GetState() != CPU::CPU_POWERDOWN)
    {
      if (!_CoreParameter.bCPUThread)
        g_video_backend->PeekMessages();
      std::this_thread::sleep_for(std::chrono::milliseconds(20));
    }
    s_is_started = false;
  }

  if (!_CoreParameter.bCPUThread)
    g_video_backend->Video_Cleanup();

  return;
}

// Initialize and create emulation thread
// Call browser: Init():s_emu_thread().
// See the BootManager.cpp file description for a complete call schedule.
void EmuThread()
{
  const SConfig& core_parameter = SConfig::GetInstance();
  s_is_booting.store(true);

  Common::SetCurrentThreadName("Emuthread - Starting");

  if (SConfig::GetInstance().m_OCEnable)
    DisplayMessage("WARNING: running at non-native CPU clock! Game may not be stable.", 8000);
  DisplayMessage(cpu_info.brand_string, 8000);
  DisplayMessage(cpu_info.Summarize(), 8000);
  DisplayMessage(core_parameter.m_strFilename, 3000);

  // For a time this acts as the CPU thread...
  DeclareAsCPUThread();

  Movie::Init();

  HW::Init();

  if (!g_video_backend->Initialize(s_window_handle))
  {
    s_is_booting.store(false);
    PanicAlert("Failed to initialize video backend!");
    Host_Message(WM_USER_STOP);
    return;
  }

  OSD::AddMessage("Dolphin " + g_video_backend->GetName() + " Video Backend.", 5000);

  if (cpu_info.HTT)
    SConfig::GetInstance().bDSPThread = cpu_info.num_cores > 4;
  else
    SConfig::GetInstance().bDSPThread = cpu_info.num_cores > 2;

  if (!DSP::GetDSPEmulator()->Initialize(core_parameter.bWii, core_parameter.bDSPThread))
  {
    s_is_booting.store(false);
    HW::Shutdown();
    g_video_backend->Shutdown();
    PanicAlert("Failed to initialize DSP emulation!");
    Host_Message(WM_USER_STOP);
    return;
  }

  bool init_controllers = false;
  if (!g_controller_interface.IsInit())
  {
    Pad::Initialize(s_window_handle);
    Keyboard::Initialize(s_window_handle);
    init_controllers = true;
  }
  else
  {
    // Update references in case controllers were refreshed
    Pad::LoadConfig();
    Keyboard::LoadConfig();
  }

  // Load and Init Wiimotes - only if we are booting in Wii mode
  if (core_parameter.bWii)
  {
    if (init_controllers)
      Wiimote::Initialize(s_window_handle, !s_state_filename.empty());
    else
      Wiimote::LoadConfig();

    // Activate Wiimotes which don't have source set to "None"
    for (unsigned int i = 0; i != MAX_BBMOTES; ++i)
      if (g_wiimote_sources[i])
        GetUsbPointer()->AccessWiiMote(i | 0x100)->Activate(true);
  }

  AudioCommon::InitSoundStream();

  // The hardware is initialized.
  s_hardware_initialized = true;
  s_is_booting.store(false);

  // Set execution state to known values (CPU/FIFO/Audio Paused)
  CPU::Break();

  // Load GCM/DOL/ELF whatever ... we boot with the interpreter core
  PowerPC::SetMode(PowerPC::MODE_INTERPRETER);

  CBoot::BootUp();

  // This adds the SyncGPU handler to CoreTiming, so now CoreTiming::Advance might block.
  Fifo::Prepare();

  // Thread is no longer acting as CPU Thread
  UndeclareAsCPUThread();

  // Setup our core, but can't use dynarec if we are compare server
  if (core_parameter.iCPUCore != PowerPC::CORE_INTERPRETER &&
      (!core_parameter.bRunCompareServer || core_parameter.bRunCompareClient))
  {
    PowerPC::SetMode(PowerPC::MODE_JIT);
  }
  else
  {
    PowerPC::SetMode(PowerPC::MODE_INTERPRETER);
  }

  // Update the window again because all stuff is initialized
  Host_UpdateDisasmDialog();
  Host_UpdateMainFrame();

  // Determine the CPU thread function
  void (*cpuThreadFunc)(void);
  if (core_parameter.m_BootType == SConfig::BOOT_DFF)
    cpuThreadFunc = FifoPlayerThread;
  else
    cpuThreadFunc = CpuThread;

  // ENTER THE VIDEO THREAD LOOP
  if (core_parameter.bCPUThread)
  {
    // This thread, after creating the EmuWindow, spawns a CPU
    // thread, and then takes over and becomes the video thread
    Common::SetCurrentThreadName("Video thread");

    g_video_backend->Video_Prepare();

    // Spawn the CPU thread
    s_cpu_thread = std::thread(cpuThreadFunc);

    // become the GPU thread
    Fifo::RunGpuLoop();

    // We have now exited the Video Loop
    INFO_LOG(CONSOLE, "%s", StopMessage(false, "Video Loop Ended").c_str());
  }
  else  // SingleCore mode
  {
    // The spawned CPU Thread also does the graphics.
    // The EmuThread is thus an idle thread, which sleeps while
    // waiting for the program to terminate. Without this extra
    // thread, the video backend window hangs in single core mode
    // because no one is pumping messages.
    Common::SetCurrentThreadName("Emuthread - Idle");

    // Spawn the CPU+GPU thread
    s_cpu_thread = std::thread(cpuThreadFunc);

    while (CPU::GetState() != CPU::CPU_POWERDOWN)
    {
      g_video_backend->PeekMessages();
      Common::SleepCurrentThread(20);
    }
  }

  INFO_LOG(CONSOLE, "%s", StopMessage(true, "Stopping Emu thread ...").c_str());

  // Wait for s_cpu_thread to exit
  INFO_LOG(CONSOLE, "%s", StopMessage(true, "Stopping CPU-GPU thread ...").c_str());

#ifdef USE_GDBSTUB
  INFO_LOG(CONSOLE, "%s", StopMessage(true, "Stopping GDB ...").c_str());
  gdb_deinit();
  INFO_LOG(CONSOLE, "%s", StopMessage(true, "GDB stopped.").c_str());
#endif

  s_cpu_thread.join();

  INFO_LOG(CONSOLE, "%s", StopMessage(true, "CPU thread stopped.").c_str());

  if (core_parameter.bCPUThread)
    g_video_backend->Video_Cleanup();

  FileMon::Close();

  // Stop audio thread - Actually this does nothing when using HLE
  // emulation, but stops the DSP Interpreter when using LLE emulation.
  DSP::GetDSPEmulator()->DSP_StopSoundStream();

  // We must set up this flag before executing HW::Shutdown()
  s_hardware_initialized = false;
  INFO_LOG(CONSOLE, "%s", StopMessage(false, "Shutting down HW").c_str());
  HW::Shutdown();
  INFO_LOG(CONSOLE, "%s", StopMessage(false, "HW shutdown").c_str());

  if (init_controllers)
  {
    Wiimote::Shutdown();
    Keyboard::Shutdown();
    Pad::Shutdown();
    init_controllers = false;
  }

  g_video_backend->Shutdown();
  AudioCommon::ShutdownSoundStream();

  INFO_LOG(CONSOLE, "%s", StopMessage(true, "Main Emu thread stopped").c_str());

  // Clear on screen messages that haven't expired
  OSD::ClearMessages();

  // Reload sysconf file in order to see changes committed during emulation
  if (core_parameter.bWii)
    SConfig::GetInstance().m_SYSCONF->Reload();

  INFO_LOG(CONSOLE, "Stop [Video Thread]\t\t---- Shutdown complete ----");
  Movie::Shutdown();
  PatchEngine::Shutdown();

  s_is_stopping = false;

  if (s_on_stopped_callback)
    s_on_stopped_callback();
}

// Set or get the running state

void SetState(EState state)
{
  // State cannot be controlled until the CPU Thread is operational
  if (!IsRunningAndStarted())
    return;

  switch (state)
  {
  case CORE_PAUSE:
    // NOTE: GetState() will return CORE_PAUSE immediately, even before anything has
    //   stopped (including the CPU).
    CPU::EnableStepping(true);  // Break
    Wiimote::Pause();
#if defined(__LIBUSB__) || defined(_WIN32)
    GCAdapter::ResetRumble();
#endif
    break;
  case CORE_RUN:
    CPU::EnableStepping(false);
    Wiimote::Resume();
    break;
  default:
    PanicAlert("Invalid state");
    break;
  }
}

EState GetState()
{
  if (s_is_stopping)
    return CORE_STOPPING;

  if (s_hardware_initialized)
  {
    if (CPU::IsStepping())
      return CORE_PAUSE;

    return CORE_RUN;
  }

  return CORE_UNINITIALIZED;
}

static std::string GenerateScreenshotFolderPath()
{
  const std::string& gameId = SConfig::GetInstance().GetUniqueID();
  std::string path = File::GetUserPath(D_SCREENSHOTS_IDX) + gameId + DIR_SEP_CHR;

  if (!File::CreateFullPath(path))
  {
    // fallback to old-style screenshots, without folder.
    path = File::GetUserPath(D_SCREENSHOTS_IDX);
  }

  return path;
}

static std::string GenerateScreenshotName()
{
  std::string path = GenerateScreenshotFolderPath();

  // append gameId, path only contains the folder here.
  path += SConfig::GetInstance().GetUniqueID();

  std::string name;
  for (int i = 1; File::Exists(name = StringFromFormat("%s-%d.png", path.c_str(), i)); ++i)
  {
    // TODO?
  }

  return name;
}

void SaveScreenShot()
{
  const bool bPaused = (GetState() == CORE_PAUSE);

  SetState(CORE_PAUSE);

  Renderer::SetScreenshot(GenerateScreenshotName());

  if (!bPaused)
    SetState(CORE_RUN);
}

void SaveScreenShot(const std::string& name)
{
  const bool bPaused = (GetState() == CORE_PAUSE);

  SetState(CORE_PAUSE);

  std::string filePath = GenerateScreenshotFolderPath() + name + ".png";

  Renderer::SetScreenshot(filePath);

  if (!bPaused)
    SetState(CORE_RUN);
}

void RequestRefreshInfo()
{
  s_request_refresh_info = true;
}

bool PauseAndLock(bool do_lock, bool unpause_on_unlock)
{
  // WARNING: PauseAndLock is not fully threadsafe so is only valid on the Host Thread
  if (!IsRunning())
    return true;

  // let's support recursive locking to simplify things on the caller's side,
  // and let's do it at this outer level in case the individual systems don't support it.
  if (do_lock ? s_pause_and_lock_depth++ : --s_pause_and_lock_depth)
    return true;

  bool was_unpaused = true;
  if (do_lock)
  {
    // first pause the CPU
    // This acquires a wrapper mutex and converts the current thread into
    // a temporary replacement CPU Thread.
    was_unpaused = CPU::PauseAndLock(true);
  }

  ExpansionInterface::PauseAndLock(do_lock, false);

  // audio has to come after CPU, because CPU thread can wait for audio thread (m_throttle).
  DSP::GetDSPEmulator()->PauseAndLock(do_lock, false);

  // video has to come after CPU, because CPU thread can wait for video thread
  // (s_efbAccessRequested).
  Fifo::PauseAndLock(do_lock, false);

#if defined(__LIBUSB__) || defined(_WIN32)
  GCAdapter::ResetRumble();
#endif

  // CPU is unlocked last because CPU::PauseAndLock contains the synchronization
  // mechanism that prevents CPU::Break from racing.
  if (!do_lock)
  {
    // The CPU is responsible for managing the Audio and FIFO state so we use its
    // mechanism to unpause them. If we unpaused the systems above when releasing
    // the locks then they could call CPU::Break which would require detecting it
    // and re-pausing with CPU::EnableStepping.
    was_unpaused = CPU::PauseAndLock(false, unpause_on_unlock, true);
  }

  return was_unpaused;
}

// Display FPS info
// This should only be called from VI
void VideoThrottle()
{
  // Update info per second
  u32 ElapseTime = (u32)s_timer.GetTimeDifference();
  if ((ElapseTime >= 1000 && s_drawn_video.load() > 0) || s_request_refresh_info)
  {
    UpdateTitle();

    // Reset counter
    s_timer.Update();
    s_drawn_frame.store(0);
    s_drawn_video.store(0);
  }

  s_drawn_video++;
}

// Executed from GPU thread
// reports if a frame should be skipped or not
// depending on the emulation speed set
bool ShouldSkipFrame(int skipped)
{
  u32 TargetFPS = VideoInterface::GetTargetRefreshRate();
  if (SConfig::GetInstance().m_EmulationSpeed > 0.0f)
    TargetFPS = u32(TargetFPS * SConfig::GetInstance().m_EmulationSpeed);
  const u32 frames = s_drawn_frame.load();
  const bool fps_slow = !(s_timer.GetTimeDifference() < (frames + skipped) * 1000 / TargetFPS);

  return fps_slow;
}

// --- Callbacks for backends / engine ---

// Should be called from GPU thread when a frame is drawn
void Callback_VideoCopiedToXFB(bool video_update)
{
  if (video_update)
    s_drawn_frame++;

  Movie::FrameUpdate();
}

void UpdateTitle()
{
  u32 ElapseTime = (u32)s_timer.GetTimeDifference();
  s_request_refresh_info = false;
  SConfig& _CoreParameter = SConfig::GetInstance();

  if (ElapseTime == 0)
    ElapseTime = 1;

  float FPS = (float)(s_drawn_frame.load() * 1000.0 / ElapseTime);
  float VPS = (float)(s_drawn_video.load() * 1000.0 / ElapseTime);
  float Speed = (float)(s_drawn_video.load() * (100 * 1000.0) /
                        (VideoInterface::GetTargetRefreshRate() * ElapseTime));

  // Settings are shown the same for both extended and summary info
  std::string SSettings = StringFromFormat(
      "%s %s | %s | %s", PowerPC::GetCPUName(), _CoreParameter.bCPUThread ? "DC" : "SC",
      g_video_backend->GetDisplayName().c_str(), _CoreParameter.bDSPHLE ? "HLE" : "LLE");

  std::string SFPS;

  if (Movie::IsPlayingInput())
    SFPS = StringFromFormat("VI: %u/%u - Input: %u/%u - FPS: %.0f - VPS: %.0f - %.0f%%",
                            (u32)Movie::g_currentFrame, (u32)Movie::g_totalFrames,
                            (u32)Movie::g_currentInputCount, (u32)Movie::g_totalInputCount, FPS,
                            VPS, Speed);
  else if (Movie::IsRecordingInput())
    SFPS = StringFromFormat("VI: %u - Input: %u - FPS: %.0f - VPS: %.0f - %.0f%%",
                            (u32)Movie::g_currentFrame, (u32)Movie::g_currentInputCount, FPS, VPS,
                            Speed);
  else
  {
    SFPS = StringFromFormat("FPS: %.0f - VPS: %.0f - %.0f%%", FPS, VPS, Speed);
    if (SConfig::GetInstance().m_InterfaceExtendedFPSInfo)
    {
      // Use extended or summary information. The summary information does not print the ticks data,
      // that's more of a debugging interest, it can always be optional of course if someone is
      // interested.
      static u64 ticks = 0;
      static u64 idleTicks = 0;
      u64 newTicks = CoreTiming::GetTicks();
      u64 newIdleTicks = CoreTiming::GetIdleTicks();

      u64 diff = (newTicks - ticks) / 1000000;
      u64 idleDiff = (newIdleTicks - idleTicks) / 1000000;

      ticks = newTicks;
      idleTicks = newIdleTicks;

      float TicksPercentage =
          (float)diff / (float)(SystemTimers::GetTicksPerSecond() / 1000000) * 100;

      SFPS +=
          StringFromFormat(" | CPU: %s%i MHz [Real: %i + IdleSkip: %i] / %i MHz (%s%3.0f%%)",
                           _CoreParameter.bSkipIdle ? "~" : "", (int)(diff), (int)(diff - idleDiff),
                           (int)(idleDiff), SystemTimers::GetTicksPerSecond() / 1000000,
                           _CoreParameter.bSkipIdle ? "~" : "", TicksPercentage);
    }
  }
  // This is our final "frame counter" string
  std::string SMessage = StringFromFormat("%s | %s", SSettings.c_str(), SFPS.c_str());

  // Update the audio timestretcher with the current speed
  if (g_sound_stream)
  {
    CMixer* pMixer = g_sound_stream->GetMixer();
    pMixer->UpdateSpeed((float)Speed / 100);
  }

  Host_UpdateTitle(SMessage);
}

void Shutdown()
{
  // During shutdown DXGI expects us to handle some messages on the UI thread.
  // Therefore we can't immediately block and wait for the emu thread to shut
  // down, so we join the emu thread as late as possible when the UI has already
  // shut down.
  // For more info read "DirectX Graphics Infrastructure (DXGI): Best Practices"
  // on MSDN.
  if (s_emu_thread.joinable())
    s_emu_thread.join();

  // Make sure there's nothing left over in case we're about to exit.
  HostDispatchJobs();
}

void SetOnStoppedCallback(StoppedCallbackFunc callback)
{
  s_on_stopped_callback = callback;
}

void UpdateWantDeterminism(bool initial)
{
  // For now, this value is not itself configurable.  Instead, individual
  // settings that depend on it, such as GPU determinism mode. should have
  // override options for testing,
  bool new_want_determinism =
      Movie::IsPlayingInput() || Movie::IsRecordingInput() || NetPlay::IsNetPlayRunning();
  if (new_want_determinism != g_want_determinism || initial)
  {
    WARN_LOG(COMMON, "Want determinism <- %s", new_want_determinism ? "true" : "false");

    bool was_unpaused = Core::PauseAndLock(true);

    g_want_determinism = new_want_determinism;
    WiiSockMan::GetInstance().UpdateWantDeterminism(new_want_determinism);
    Fifo::UpdateWantDeterminism(new_want_determinism);
    // We need to clear the cache because some parts of the JIT depend on want_determinism, e.g. use
    // of FMA.
    JitInterface::ClearCache();
    Common::InitializeWiiRoot(g_want_determinism);

    Core::PauseAndLock(false, was_unpaused);
  }
}

void QueueHostJob(std::function<void()> job, bool run_during_stop)
{
  if (!job)
    return;

  bool send_message = false;
  {
    std::lock_guard<std::mutex> guard(s_host_jobs_lock);
    send_message = s_host_jobs_queue.empty();
    s_host_jobs_queue.emplace(HostJob{std::move(job), run_during_stop});
  }
  // If the the queue was empty then kick the Host to come and get this job.
  if (send_message)
    Host_Message(WM_USER_JOB_DISPATCH);
}

void HostDispatchJobs()
{
  // WARNING: This should only run on the Host Thread.
  // NOTE: This function is potentially re-entrant. If a job calls
  //   Core::Stop for instance then we'll enter this a second time.
  std::unique_lock<std::mutex> guard(s_host_jobs_lock);
  while (!s_host_jobs_queue.empty())
  {
    HostJob job = std::move(s_host_jobs_queue.front());
    s_host_jobs_queue.pop();

    // NOTE: Memory ordering is important. The booting flag needs to be
    //   checked first because the state transition is:
    //   CORE_UNINITIALIZED: s_is_booting -> s_hardware_initialized
    //   We need to check variables in the same order as the state
    //   transition, otherwise we race and get transient failures.
    if (!job.run_after_stop && !s_is_booting.load() && !IsRunning())
      continue;

    guard.unlock();
    job.job();
    guard.lock();
  }
}

}  // Core
Exemple #20
0
// Subtract the paused time when we run again
void Run()
{
	ReRecTimer.AddTimeDifference();
}
Exemple #21
0
/*
    TODO: Font rendering MUST be redesigned.
*/
Font* GuiRendererD3D11::MakeFont(const char* pPath, int height)
{
    Common::Timer timer;
    timer.Start();

    FT_Face face;
    int texWidth = 4096;
    int texHeight = 4096;

    //create pixels array
    unsigned char* pTexData = (unsigned char*)malloc(texWidth * texHeight);
    ZeroMemory(pTexData, texWidth * texHeight);

    if (FT_New_Face(mFreeTypeLibrary, pPath, 0, &face) != 0)
    {
        free(pTexData);
        // TODO
        // LOG_ERROR("Failed to load font '%s'.", pPath);
        return 0;
    }

    //FT_Set_Pixel_Sizes(face, 2*height, 2*height);
    FT_Set_Char_Size(face, 0, height * 64, 96, 96);


    Font* pFont = new Font;

    /*
    FT_Matrix Transform;
    Transform.xx = (FT_Fixed)(1.0f * 0x10000L);
    Transform.xy = (FT_Fixed)(0.0f * 0x10000L);
    Transform.yx = (FT_Fixed)(0.0f * 0x10000L);
    Transform.yy = (FT_Fixed)(1.0f * 0x10000L);
    FT_Set_Transform(face, &Transform, 0);
    */

    int Width;
    int Height;
    int OffsetX = 0;
    int OffsetY = 0;

    pFont->height = height;
    pFont->charCount = 65536;
    pFont->characters = (CharacterInfo*)malloc(sizeof(CharacterInfo) * pFont->charCount);

    int Index = 0;
    for (int ChrId = 0; ChrId < (65536); ChrId++)
    {
        // Load The Glyph For Our Character.
        unsigned int GlyphIndex = FT_Get_Char_Index(face, ChrId);
        if (GlyphIndex == 0)
        {
            pFont->characters[ChrId].exists = false;
            continue;
        }

        FT_Load_Glyph(face, GlyphIndex, FT_LOAD_DEFAULT);


        // Move The Face's Glyph Into A Glyph Object.
        FT_Glyph glyph;
        FT_Get_Glyph(face->glyph, &glyph);


        // Convert The Glyph To A Bitmap.
        FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, 0, 1);
        FT_BitmapGlyph bitmap_glyph = (FT_BitmapGlyph)glyph;

        // This Reference Will Make Accessing The Bitmap Easier.
        FT_Bitmap& bitmap = bitmap_glyph->bitmap;


        Width = bitmap.width;
        Height = bitmap.rows;

        //char won't fit to texture
        if (OffsetX + Width + 2 > texWidth)
        {
            OffsetX = 0;
            OffsetY += 2 * height;
        }

        for (int y = 0; y < Height; y++)
        {
            for (int x = 0; x < Width; x++)
            {
                unsigned char Value = bitmap.buffer[x + Width * y];

                int PxOffset = (y + OffsetY) * texWidth + x + OffsetX;
                pTexData[PxOffset] = Value;
            }
        }


        pFont->characters[ChrId].exists = true;
        pFont->characters[ChrId].top = (short)bitmap_glyph->top;
        pFont->characters[ChrId].left = (short)bitmap_glyph->left;
        pFont->characters[ChrId].height = (short)Height;
        pFont->characters[ChrId].width = (short)Width;
        pFont->characters[ChrId].u = (short)OffsetX;
        pFont->characters[ChrId].v = (short)OffsetY;
        pFont->characters[ChrId].spacing = (short)(face->glyph->advance.x >> 6) + 1;
        FT_Done_Glyph(glyph);

        OffsetX += pFont->characters[ChrId].width + 1;
        Index++;
    }

    //close font
    FT_Done_Face(face);

    OffsetY += 2 * height; // Used texture height
    texHeight = CeilToPowerOf2(OffsetY);


    Common::Image fontImage;
    fontImage.SetData(pTexData, texWidth, texHeight, Common::ImageFormat::A_UBYTE);
//  pFont->texture = pRenderer->CreateTexture(&fontImage, false);
    pFont->texture = new RendererTextureD3D11;
    pFont->texture->FromImage(fontImage);


    pFont->texHeight = texHeight;
    pFont->texWidth = texWidth;

    free(pTexData);

    // TODO
    // LOG_SUCCESS("Font '%s', size %i loaded in %.3lf seconds.", pPath, height, timer.Stop());
    return pFont;
}
Exemple #22
0
void UpdateTitle()
{
	u32 ElapseTime = (u32)Timer.GetTimeDifference();
	g_requestRefreshInfo = false;
	SCoreStartupParameter& _CoreParameter = SConfig::GetInstance().m_LocalCoreStartupParameter;

	if (ElapseTime == 0)
		ElapseTime = 1;

	float FPS = (float) (Common::AtomicLoad(DrawnFrame) * 1000.0 / ElapseTime);
	float VPS = (float) (DrawnVideo * 1000.0 / ElapseTime);
	float Speed = (float) (DrawnVideo * (100 * 1000.0) / (VideoInterface::TargetRefreshRate * ElapseTime));

	// Settings are shown the same for both extended and summary info
	std::string SSettings = StringFromFormat("%s %s | %s | %s", cpu_core_base->GetName(), _CoreParameter.bCPUThread ? "DC" : "SC",
		g_video_backend->GetDisplayName().c_str(), _CoreParameter.bDSPHLE ? "HLE" : "LLE");

	std::string SFPS;

	if (Movie::IsPlayingInput())
		SFPS = StringFromFormat("VI: %u/%u - Frame: %u/%u - FPS: %.0f - VPS: %.0f - %.0f%%", (u32)Movie::g_currentFrame, (u32)Movie::g_totalFrames, (u32)Movie::g_currentInputCount, (u32)Movie::g_totalInputCount, FPS, VPS, Speed);
	else if (Movie::IsRecordingInput())
		SFPS = StringFromFormat("VI: %u - Frame: %u - FPS: %.0f - VPS: %.0f - %.0f%%", (u32)Movie::g_currentFrame, (u32)Movie::g_currentInputCount, FPS, VPS, Speed);
	else
	{
		SFPS = StringFromFormat("FPS: %.0f - VPS: %.0f - %.0f%%", FPS, VPS, Speed);
		if (SConfig::GetInstance().m_InterfaceExtendedFPSInfo)
		{
			// Use extended or summary information. The summary information does not print the ticks data,
			// that's more of a debugging interest, it can always be optional of course if someone is interested.
			static u64 ticks = 0;
			static u64 idleTicks = 0;
			u64 newTicks = CoreTiming::GetTicks();
			u64 newIdleTicks = CoreTiming::GetIdleTicks();

			u64 diff = (newTicks - ticks) / 1000000;
			u64 idleDiff = (newIdleTicks - idleTicks) / 1000000;

			ticks = newTicks;
			idleTicks = newIdleTicks;

			float TicksPercentage = (float)diff / (float)(SystemTimers::GetTicksPerSecond() / 1000000) * 100;

			SFPS += StringFromFormat(" | CPU: %s%i MHz [Real: %i + IdleSkip: %i] / %i MHz (%s%3.0f%%)",
					_CoreParameter.bSkipIdle ? "~" : "",
					(int)(diff),
					(int)(diff - idleDiff),
					(int)(idleDiff),
					SystemTimers::GetTicksPerSecond() / 1000000,
					_CoreParameter.bSkipIdle ? "~" : "",
					TicksPercentage);
		}
	}
	// This is our final "frame counter" string
	std::string SMessage = StringFromFormat("%s | %s", SSettings.c_str(), SFPS.c_str());
	std::string TMessage = StringFromFormat("%s | %s", scm_rev_str, SMessage.c_str());

	// Show message
	g_video_backend->UpdateFPSDisplay(SMessage);

	// Update the audio timestretcher with the current speed
	if (soundStream)
	{
		CMixer* pMixer = soundStream->GetMixer();
		pMixer->UpdateSpeed((float)Speed / 100);
	}

	if (_CoreParameter.bRenderToMain &&
		SConfig::GetInstance().m_InterfaceStatusbar)
	{
		Host_UpdateStatusBar(SMessage);
		Host_UpdateTitle(scm_rev_str);
	}
	else
	{
		Host_UpdateTitle(TMessage);
	}
}
Exemple #23
0
namespace Core
{

// Declarations and definitions
Common::Timer Timer;
volatile u32 DrawnFrame = 0;
u32 DrawnVideo = 0;

// Function forwarding
const char *Callback_ISOName(void);
void Callback_WiimoteInterruptChannel(int _number, u16 _channelID, const void* _pData, u32 _Size);

// Function declarations
void EmuThread();

void Stop();

bool g_bStopping = false;
bool g_bHwInit = false;
bool g_bStarted = false;
bool g_bRealWiimote = false;
void *g_pWindowHandle = NULL;
std::string g_stateFileName;
std::thread g_EmuThread;

static std::thread g_cpu_thread;
static bool g_requestRefreshInfo = false;
static int g_pauseAndLockDepth = 0;

SCoreStartupParameter g_CoreStartupParameter;

std::string GetStateFileName() { return g_stateFileName; }
void SetStateFileName(std::string val) { g_stateFileName = val; }

// Display messages and return values

// Formatted stop message
std::string StopMessage(bool bMainThread, std::string Message)
{
	return StringFromFormat("Stop [%s %i]\t%s\t%s",
		bMainThread ? "Main Thread" : "Video Thread", Common::CurrentThreadId(), MemUsage().c_str(), Message.c_str());
}

// 
bool PanicAlertToVideo(const char* text, bool yes_no)
{
	DisplayMessage(text, 3000);
	return true;
}

void DisplayMessage(const char *message, int time_in_ms)
{
	SCoreStartupParameter& _CoreParameter =
		SConfig::GetInstance().m_LocalCoreStartupParameter;

	// Actually displaying non-ASCII could cause things to go pear-shaped
	for (const char *c = message; *c != '\0'; ++c)
		if (*c < ' ')
			return;

	g_video_backend->Video_AddMessage(message, time_in_ms);
	
	if (_CoreParameter.bRenderToMain &&
		SConfig::GetInstance().m_InterfaceStatusbar)
	{
		Host_UpdateStatusBar(message);
	}
	else
		Host_UpdateTitle(message);
}

void Callback_DebuggerBreak()
{
	CCPU::Break();
}

void *GetWindowHandle()
{
	return g_pWindowHandle;
}

bool IsRunning()
{
	return (GetState() != CORE_UNINITIALIZED) || g_bHwInit;
}

bool IsRunningAndStarted()
{
	return g_bStarted;
}

bool IsRunningInCurrentThread()
{
	return IsRunning() && IsCPUThread();
}

bool IsCPUThread()
{
	return (g_cpu_thread.joinable() ? (g_cpu_thread.get_id() == std::this_thread::get_id()) : !g_bStarted);
}

bool IsGPUThread()
{
	const SCoreStartupParameter& _CoreParameter =
		SConfig::GetInstance().m_LocalCoreStartupParameter;
	if (_CoreParameter.bCPUThread)
	{
		return (g_EmuThread.joinable() && (g_EmuThread.get_id() == std::this_thread::get_id()));
	}
	else
	{
		return IsCPUThread();
	}
}
	
// This is called from the GUI thread. See the booting call schedule in
// BootManager.cpp
bool Init()
{
	const SCoreStartupParameter& _CoreParameter =
		SConfig::GetInstance().m_LocalCoreStartupParameter;

	if (g_EmuThread.joinable())
	{
		PanicAlertT("Emu Thread already running");
		return false;
	}

	g_CoreStartupParameter = _CoreParameter;

	INFO_LOG(OSREPORT, "Starting core = %s mode",
		g_CoreStartupParameter.bWii ? "Wii" : "Gamecube");
	INFO_LOG(OSREPORT, "CPU Thread separate = %s",
		g_CoreStartupParameter.bCPUThread ? "Yes" : "No");

	Host_UpdateMainFrame(); // Disable any menus or buttons at boot

	g_aspect_wide = _CoreParameter.bWii;
	if (g_aspect_wide) 
	{
		IniFile gameIni;
		gameIni.Load(_CoreParameter.m_strGameIni.c_str());
		gameIni.Get("Wii", "Widescreen", &g_aspect_wide,
			!!SConfig::GetInstance().m_SYSCONF->
				GetData<u8>("IPL.AR"));
	}

	// g_pWindowHandle is first the m_Panel handle,
	// then it is updated to the render window handle,
	// within g_video_backend->Initialize()
	g_pWindowHandle = Host_GetRenderHandle();

	// Start the emu thread 
	g_EmuThread = std::thread(EmuThread);

	return true;
}

// Called from GUI thread
void Stop()  // - Hammertime!
{
	if (PowerPC::GetState() == PowerPC::CPU_POWERDOWN)
	{
		if (g_EmuThread.joinable())
			g_EmuThread.join();
		return;
	}

	const SCoreStartupParameter& _CoreParameter =
		SConfig::GetInstance().m_LocalCoreStartupParameter;

	g_bStopping = true;

	g_video_backend->EmuStateChange(EMUSTATE_CHANGE_STOP);

	INFO_LOG(CONSOLE, "Stop [Main Thread]\t\t---- Shutting down ----");

	// Stop the CPU
	INFO_LOG(CONSOLE, "%s", StopMessage(true, "Stop CPU").c_str());
	PowerPC::Stop();

	// Kick it if it's waiting (code stepping wait loop)
	CCPU::StepOpcode();

	if (_CoreParameter.bCPUThread)
	{
		// Video_EnterLoop() should now exit so that EmuThread()
		// will continue concurrently with the rest of the commands
		// in this function. We no longer rely on Postmessage.
		INFO_LOG(CONSOLE, "%s", StopMessage(true, "Wait for Video Loop to exit ...").c_str());
		
		g_video_backend->Video_ExitLoop();
	}

	INFO_LOG(CONSOLE, "%s", StopMessage(true, "Stopping Emu thread ...").c_str());
	
	g_EmuThread.join();	// Wait for emuthread to close.

	INFO_LOG(CONSOLE, "%s", StopMessage(true, "Main Emu thread stopped").c_str());

#ifdef _WIN32
	EmuWindow::Close();
#endif

	// Clear on screen messages that haven't expired
	g_video_backend->Video_ClearMessages();

	// Close the trace file
	Core::StopTrace();
	
	// Reload sysconf file in order to see changes committed during emulation
	if (_CoreParameter.bWii)
		SConfig::GetInstance().m_SYSCONF->Reload();

	INFO_LOG(CONSOLE, "Stop [Main Thread]\t\t---- Shutdown complete ----");
	Movie::Shutdown();
	g_bStopping = false;
}

// Create the CPU thread, which is a CPU + Video thread in Single Core mode.
void CpuThread()
{
	const SCoreStartupParameter& _CoreParameter =
		SConfig::GetInstance().m_LocalCoreStartupParameter;

	if (_CoreParameter.bCPUThread)
	{
		Common::SetCurrentThreadName("CPU thread");
	}
	else
	{
		Common::SetCurrentThreadName("CPU-GPU thread");
		g_video_backend->Video_Prepare();
	}

	#if defined(_M_X64)
		EMM::InstallExceptionHandler(); // Let's run under memory watch
	#endif

	if (!g_stateFileName.empty())
		State::LoadAs(g_stateFileName);

	g_bStarted = true;

	// Enter CPU run loop. When we leave it - we are done.
	CCPU::Run();

	g_bStarted = false;

	return;
}

void FifoPlayerThread()
{
	const SCoreStartupParameter& _CoreParameter = SConfig::GetInstance().m_LocalCoreStartupParameter;

	if (_CoreParameter.bCPUThread)
	{
		Common::SetCurrentThreadName("FIFO player thread");
	}
	else
	{
		g_video_backend->Video_Prepare();
		Common::SetCurrentThreadName("FIFO-GPU thread");
	}

	g_bStarted = true;

	// Enter CPU run loop. When we leave it - we are done.
	if (FifoPlayer::GetInstance().Open(_CoreParameter.m_strFilename))
	{
		FifoPlayer::GetInstance().Play();
		FifoPlayer::GetInstance().Close();
	}

	g_bStarted = false;

	return;
}

// Initalize and create emulation thread
// Call browser: Init():g_EmuThread().
// See the BootManager.cpp file description for a complete call schedule.
void EmuThread()
{
	const SCoreStartupParameter& _CoreParameter =
		SConfig::GetInstance().m_LocalCoreStartupParameter;

	Common::SetCurrentThreadName("Emuthread - Starting");

	DisplayMessage(cpu_info.brand_string, 8000);
	DisplayMessage(cpu_info.Summarize(), 8000);
	DisplayMessage(_CoreParameter.m_strFilename, 3000);

	Movie::Init();

	HW::Init();	

	if (!g_video_backend->Initialize(g_pWindowHandle))
	{
		PanicAlert("Failed to initialize video backend!");
		Host_Message(WM_USER_STOP);
		return;
	}

	OSD::AddMessage(("Dolphin " + g_video_backend->GetName() + " Video Backend.").c_str(), 5000);

	if (!DSP::GetDSPEmulator()->Initialize(g_pWindowHandle,
				_CoreParameter.bWii, _CoreParameter.bDSPThread))
	{
		HW::Shutdown();
		g_video_backend->Shutdown();
		PanicAlert("Failed to initialize DSP emulator!");
		Host_Message(WM_USER_STOP);
		return;
	}

	Pad::Initialize(g_pWindowHandle);
	// Load and Init Wiimotes - only if we are booting in wii mode	
	if (g_CoreStartupParameter.bWii)
	{
		Wiimote::Initialize(g_pWindowHandle);

		// Activate wiimotes which don't have source set to "None"
		for (unsigned int i = 0; i != MAX_WIIMOTES; ++i)
			if (g_wiimote_sources[i])
				GetUsbPointer()->AccessWiiMote(i | 0x100)->
					Activate(true);
	}

	// The hardware is initialized.
	g_bHwInit = true;

	// Boot to pause or not
	Core::SetState(_CoreParameter.bBootToPause ? Core::CORE_PAUSE : Core::CORE_RUN);

	// Load GCM/DOL/ELF whatever ... we boot with the interpreter core
	PowerPC::SetMode(PowerPC::MODE_INTERPRETER);

	CBoot::BootUp();

	// Setup our core, but can't use dynarec if we are compare server
	if (_CoreParameter.iCPUCore && (!_CoreParameter.bRunCompareServer ||
					_CoreParameter.bRunCompareClient))
		PowerPC::SetMode(PowerPC::MODE_JIT);
	else
		PowerPC::SetMode(PowerPC::MODE_INTERPRETER);

	// Update the window again because all stuff is initialized
	Host_UpdateDisasmDialog();
	Host_UpdateMainFrame();

	// Determine the cpu thread function
	void (*cpuThreadFunc)(void);
	if (_CoreParameter.m_BootType == SCoreStartupParameter::BOOT_DFF)
		cpuThreadFunc = FifoPlayerThread;
	else
		cpuThreadFunc = CpuThread;

	// ENTER THE VIDEO THREAD LOOP
	if (_CoreParameter.bCPUThread)
	{
		// This thread, after creating the EmuWindow, spawns a CPU
		// thread, and then takes over and becomes the video thread
		Common::SetCurrentThreadName("Video thread");

		g_video_backend->Video_Prepare();

		// Spawn the CPU thread
		g_cpu_thread = std::thread(cpuThreadFunc);

		// become the GPU thread
		g_video_backend->Video_EnterLoop();

		// We have now exited the Video Loop
		INFO_LOG(CONSOLE, "%s", StopMessage(false, "Video Loop Ended").c_str());
	}
	else // SingleCore mode
	{
		// The spawned CPU Thread also does the graphics.
		// The EmuThread is thus an idle thread, which sleeps while
		// waiting for the program to terminate. Without this extra
		// thread, the video backend window hangs in single core mode
		// because noone is pumping messages.
		Common::SetCurrentThreadName("Emuthread - Idle");

		// Spawn the CPU+GPU thread
		g_cpu_thread = std::thread(cpuThreadFunc);

		while (PowerPC::GetState() != PowerPC::CPU_POWERDOWN)
		{
			g_video_backend->PeekMessages();
			Common::SleepCurrentThread(20);
		}
	}

	// Wait for g_cpu_thread to exit
	INFO_LOG(CONSOLE, "%s", StopMessage(true, "Stopping CPU-GPU thread ...").c_str());

	g_cpu_thread.join();

	INFO_LOG(CONSOLE, "%s", StopMessage(true, "CPU thread stopped.").c_str());

	VolumeHandler::EjectVolume();
	FileMon::Close();

	// Stop audio thread - Actually this does nothing when using HLE
	// emulation, but stops the DSP Interpreter when using LLE emulation.
	DSP::GetDSPEmulator()->DSP_StopSoundStream();
	
	// We must set up this flag before executing HW::Shutdown()
	g_bHwInit = false;
	INFO_LOG(CONSOLE, "%s", StopMessage(false, "Shutting down HW").c_str());
	HW::Shutdown();
	INFO_LOG(CONSOLE, "%s", StopMessage(false, "HW shutdown").c_str());
	Pad::Shutdown();
	Wiimote::Shutdown();
	g_video_backend->Shutdown();
}

// Set or get the running state

void SetState(EState _State)
{
	switch (_State)
	{
	case CORE_UNINITIALIZED:
		Stop();
		break;
	case CORE_PAUSE:
		CCPU::EnableStepping(true);  // Break
		break;
	case CORE_RUN:
		CCPU::EnableStepping(false);
		break;
	default:
		PanicAlertT("Invalid state");
		break;
	}
}

EState GetState()
{
	if (g_bHwInit)
	{
		if (CCPU::IsStepping())
			return CORE_PAUSE;
		else if (g_bStopping)
			return CORE_STOPPING;
		else
			return CORE_RUN;
	}
	return CORE_UNINITIALIZED;
}

static std::string GenerateScreenshotName()
{
	const std::string& gameId = SConfig::GetInstance().m_LocalCoreStartupParameter.GetUniqueID();
	std::string path = File::GetUserPath(D_SCREENSHOTS_IDX) + gameId + DIR_SEP_CHR;

	if (!File::CreateFullPath(path))
	{
		// fallback to old-style screenshots, without folder.
		path = File::GetUserPath(D_SCREENSHOTS_IDX);
	}

	//append gameId, path only contains the folder here.
	path += gameId;

	std::string name;
	for (int i = 1; File::Exists(name = StringFromFormat("%s-%d.png", path.c_str(), i)); ++i)
	{}

	return name;
}

void SaveScreenShot()
{
	const bool bPaused = (GetState() == CORE_PAUSE);

	SetState(CORE_PAUSE);

	g_video_backend->Video_Screenshot(GenerateScreenshotName().c_str());
	
	if (!bPaused)
		SetState(CORE_RUN);
}

void RequestRefreshInfo()
{
	g_requestRefreshInfo = true;
}

bool PauseAndLock(bool doLock, bool unpauseOnUnlock)
{
	// let's support recursive locking to simplify things on the caller's side,
	// and let's do it at this outer level in case the individual systems don't support it.
	if (doLock ? g_pauseAndLockDepth++ : --g_pauseAndLockDepth)
		return true;

	// first pause or unpause the cpu
	bool wasUnpaused = CCPU::PauseAndLock(doLock, unpauseOnUnlock);
	ExpansionInterface::PauseAndLock(doLock, unpauseOnUnlock);

	// audio has to come after cpu, because cpu thread can wait for audio thread (m_throttle).
	AudioCommon::PauseAndLock(doLock, unpauseOnUnlock);
	DSP::GetDSPEmulator()->PauseAndLock(doLock, unpauseOnUnlock);

	// video has to come after cpu, because cpu thread can wait for video thread (s_efbAccessRequested).
	g_video_backend->PauseAndLock(doLock, unpauseOnUnlock);
	return wasUnpaused;
}

// Apply Frame Limit and Display FPS info
// This should only be called from VI
void VideoThrottle()
{
	u32 TargetVPS = (SConfig::GetInstance().m_Framelimit > 2) ?
		(SConfig::GetInstance().m_Framelimit - 1) * 5 : VideoInterface::TargetRefreshRate;

	// Disable the frame-limiter when the throttle (Tab) key is held down. Audio throttle: m_Framelimit = 2
	if (SConfig::GetInstance().m_Framelimit && SConfig::GetInstance().m_Framelimit != 2 && !Host_GetKeyState('\t'))
	{
		u32 frametime = ((SConfig::GetInstance().b_UseFPS)? Common::AtomicLoad(DrawnFrame) : DrawnVideo) * 1000 / TargetVPS;

		u32 timeDifference = (u32)Timer.GetTimeDifference();
		if (timeDifference < frametime) {
			Common::SleepCurrentThread(frametime - timeDifference - 1);
		}

		while ((u32)Timer.GetTimeDifference() < frametime)
			Common::YieldCPU();
			//Common::SleepCurrentThread(1);
	}

	// Update info per second
	u32 ElapseTime = (u32)Timer.GetTimeDifference();
	if ((ElapseTime >= 1000 && DrawnVideo > 0) || g_requestRefreshInfo)
	{
		UpdateTitle();

		// Reset counter
		Timer.Update();
		Common::AtomicStore(DrawnFrame, 0);
		DrawnVideo = 0;
	}

	DrawnVideo++;
}

// Executed from GPU thread
// reports if a frame should be skipped or not
// depending on the framelimit set
bool ShouldSkipFrame(int skipped)
{
	const u32 TargetFPS = (SConfig::GetInstance().m_Framelimit > 1)
		? SConfig::GetInstance().m_Framelimit * 5
		: VideoInterface::TargetRefreshRate;
	const u32 frames = Common::AtomicLoad(DrawnFrame);
	const bool fps_slow = !(Timer.GetTimeDifference() < (frames + skipped) * 1000 / TargetFPS);

	return fps_slow;
}

// --- Callbacks for backends / engine ---

// Should be called from GPU thread when a frame is drawn
void Callback_VideoCopiedToXFB(bool video_update)
{
	if(video_update)
		Common::AtomicIncrement(DrawnFrame);
	Movie::FrameUpdate();
}

// Callback_ISOName: Let the DSP emulator get the game name
//
const char *Callback_ISOName()
{
	SCoreStartupParameter& params =
		SConfig::GetInstance().m_LocalCoreStartupParameter;
	if (params.m_strName.length() > 0)
		return params.m_strName.c_str();
	else	
		return "";
}

void UpdateTitle()
{
	u32 ElapseTime = (u32)Timer.GetTimeDifference();
	g_requestRefreshInfo = false;
	SCoreStartupParameter& _CoreParameter = SConfig::GetInstance().m_LocalCoreStartupParameter;

	if (ElapseTime == 0)
		ElapseTime = 1;

	u32 FPS = Common::AtomicLoad(DrawnFrame) * 1000 / ElapseTime;
	u32 VPS = DrawnVideo * 1000 / ElapseTime;
	u32 Speed = DrawnVideo * (100 * 1000) / (VideoInterface::TargetRefreshRate * ElapseTime);

	// Settings are shown the same for both extended and summary info
	std::string SSettings = StringFromFormat("%s %s", cpu_core_base->GetName(),	_CoreParameter.bCPUThread ? "DC" : "SC");

	// Use extended or summary information. The summary information does not print the ticks data,
	// that's more of a debugging interest, it can always be optional of course if someone is interested.
	//#define EXTENDED_INFO
	#ifdef EXTENDED_INFO
		u64 newTicks = CoreTiming::GetTicks();
		u64 newIdleTicks = CoreTiming::GetIdleTicks();

		u64 diff = (newTicks - ticks) / 1000000;
		u64 idleDiff = (newIdleTicks - idleTicks) / 1000000;

		ticks = newTicks;
		idleTicks = newIdleTicks;

		float TicksPercentage = (float)diff / (float)(SystemTimers::GetTicksPerSecond() / 1000000) * 100;

		std::string SFPS = StringFromFormat("FPS: %u - VPS: %u - SPEED: %u%%", FPS, VPS, Speed);
		SFPS += StringFromFormat(" | CPU: %s%i MHz [Real: %i + IdleSkip: %i] / %i MHz (%s%3.0f%%)",
				_CoreParameter.bSkipIdle ? "~" : "",
				(int)(diff),
				(int)(diff - idleDiff),
				(int)(idleDiff),
				SystemTimers::GetTicksPerSecond() / 1000000,
				_CoreParameter.bSkipIdle ? "~" : "",
				TicksPercentage);

	#else	// Summary information
	std::string SFPS;
	if (Movie::IsPlayingInput())
		SFPS = StringFromFormat("VI: %u/%u - Frame: %u/%u - FPS: %u - VPS: %u - SPEED: %u%%", (u32)Movie::g_currentFrame, (u32)Movie::g_totalFrames, (u32)Movie::g_currentInputCount, (u32)Movie::g_totalInputCount, FPS, VPS, Speed);
	else if (Movie::IsRecordingInput())
		SFPS = StringFromFormat("VI: %u - Frame: %u - FPS: %u - VPS: %u - SPEED: %u%%", (u32)Movie::g_currentFrame, (u32)Movie::g_currentInputCount, FPS, VPS, Speed);
	else
		SFPS = StringFromFormat("FPS: %u - VPS: %u - SPEED: %u%%", FPS, VPS, Speed);
	#endif

	// This is our final "frame counter" string
	std::string SMessage = StringFromFormat("%s | %s",
		SSettings.c_str(), SFPS.c_str());
	std::string TMessage = StringFromFormat("%s | ", scm_rev_str) +
		SMessage;

	// Show message
	g_video_backend->UpdateFPSDisplay(SMessage.c_str());

	// Update the audio timestretcher with the current speed
	if (soundStream)
	{
		CMixer* pMixer = soundStream->GetMixer();
		pMixer->UpdateSpeed((float)Speed / 100);
	}

	if (_CoreParameter.bRenderToMain &&
		SConfig::GetInstance().m_InterfaceStatusbar) {
		Host_UpdateStatusBar(SMessage.c_str());
		Host_UpdateTitle(scm_rev_str);
	} else
		Host_UpdateTitle(TMessage.c_str());
	}

} // Core
Exemple #24
0
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    SetUpCurrentDirectory();

    //create window
    CustomWindow* pWindow = new CustomWindow;
    pWindow->setSize(800, 600);
    pWindow->setTitle(L"NFEngine Demo - Initializing engine...");
    pWindow->open();

    //initialize engine
    if (EngineInit() != Result::OK)
        return 1;

    Demo_InitEditorBar();

    //create scene and camera
    g_pScene = EngineCreateScene();

    // --------------------------------
    // Build scene
    // --------------------------------

#ifdef DEMO_SEC_CAMERA_ON
    InitSecondaryCamera();
#endif

    //set ambient & background color
    EnviromentDesc envDesc;
    envDesc.ambientLight = Vector(0.02f, 0.03f, 0.04f, 0.0f);
    //envDesc.m_BackgroundColor = Vector(0.04f, 0.05f, 0.07f, 0.03f);
    envDesc.backgroundColor = Vector(0.02f, 0.03f, 0.04f, 0.01f);
    g_pScene->SetEnvironment(&envDesc);

    CollisionShape* pFloorShape = ENGINE_GET_COLLISION_SHAPE("shape_floor");
    pFloorShape->SetCallbacks(OnLoadCustomShapeResource, NULL);
    pFloorShape->Load();
    pFloorShape->AddRef();

    CollisionShape* pFrameShape = ENGINE_GET_COLLISION_SHAPE("shape_frame");
    pFrameShape->SetCallbacks(OnLoadCustomShapeResource, NULL);
    pFrameShape->Load();
    pFrameShape->AddRef();

    CollisionShape* pBoxShape = ENGINE_GET_COLLISION_SHAPE("shape_box");
    pBoxShape->SetCallbacks(OnLoadCustomShapeResource, NULL);
    pBoxShape->Load();
    pBoxShape->AddRef();

    CollisionShape* pBarrelShape = ENGINE_GET_COLLISION_SHAPE("shape_barrel");
    pBarrelShape->SetCallbacks(OnLoadCustomShapeResource, NULL);
    pBarrelShape->Load();
    pBarrelShape->AddRef();

    CollisionShape* pChamberShape = ENGINE_GET_COLLISION_SHAPE("chamber_collision_shape.nfcs");
    pChamberShape->Load();
    pChamberShape->AddRef();


    pWindow->InitCamera();
    pWindow->setTitle(L"NFEngine Demo");


#ifdef SCENE_MINECRAFT
    // SUNLIGHT
    Entity* pDirLightEnt = g_pScene->CreateEntity();
    XOrientation orient;
    orient.x = Vector(0.0f, -0.0f, -0.0f, 0.0f);
    orient.z = Vector(-1.5f, -1.0f, 0.5f, 0.0f);
    orient.y = Vector(0.0f, 1.0f, 0.0f, 0.0f);
    pDirLightEnt->SetOrientation(&orient);
    DirLightDesc dirLight;
    dirLight.m_Far = 100.0f;
    dirLight.m_Splits = 4;
    dirLight.m_LightDist = 1000.0f;

    LightComponent* pDirLight = new LightComponent(pDirLightEnt);
    pDirLight->SetDirLight(&dirLight);
    pDirLight->SetColor(Float3(2.2, 2, 1.8));
    pDirLight->SetShadowMap(1024);

    // MINECRAFT
    Entity* pEnt = g_pScene->CreateEntity();
    pEnt->SetPosition(Vector(0, -70.0f, 0));

    MeshComponent* pMesh = new MeshComponent(pEnt);
    pMesh->SetMeshResource("minecraft.nfm");
#endif

#ifdef SCENE_SPONZA
    // SPONZA
    Entity* pEnt = g_pScene->CreateEntity();
    pEnt->SetPosition(Vector(0, 0, 0));

    MeshComponent* pMesh = new MeshComponent(pEnt);
    pMesh->SetMeshResource("sponza.nfm");

    CollisionShape* pSponzaShape = ENGINE_GET_COLLISION_SHAPE("sponza_collision_shape.nfcs");
    //pSponzaShape->Load();

    BodyComponent* pFloorBody = new BodyComponent(pEnt);
    pFloorBody->EnablePhysics(pSponzaShape);
    pFloorBody->SetMass(0.0);

    pEnt = g_pScene->CreateEntity();
    pEnt->SetPosition(Vector(0.0f, 3.5f, 0.0f));
    LightComponent* pLight = new LightComponent(pEnt);
    OmniLightDesc omni;
    omni.m_ShadowFadeStart = 12.0f;
    omni.m_ShadowFadeEnd = 120.0f;
    omni.m_Radius = 90.0f;
    pLight->SetOmniLight(&omni);
    pLight->SetColor(Float3(50, 50, 50));
    pLight->SetShadowMap(512);
    /*
    // SUNLIGHT
    Entity* pDirLightEnt = g_pScene->CreateEntity();
    XOrientation orient;
    orient.x = Vector(0.0f, -0.0f, -0.0f, 0.0f);
    orient.z = Vector(0.1, -2.3f, 1.05, 0.0f);
    orient.y = Vector(0.0f, 1.0f, 0.0f, 0.0f);
    pDirLightEnt->SetOrientation(&orient);
    DirLightDesc dirLight;
    dirLight.m_Far = 100.0f;
    dirLight.m_Splits = 4;
    dirLight.m_LightDist = 1000.0;

    LightComponent* pDirLight = new LightComponent(pDirLightEnt);
    pDirLight->SetDirLight(&dirLight);
    pDirLight->SetColor(Float3(2.2, 1.3, 0.8));
    pDirLight->SetShadowMap(2048);
    */
#endif

//performance test (many objects and shadowmaps)
#ifdef SCENE_SEGMENTS_PERF_TEST
    for (int x = -4; x < 5; x++)
    {
        for (int z = -4; z < 5; z++)
        {
            Entity* pEntity = g_pScene->CreateEntity();
            pEntity->SetPosition(12.0f * Vector((float)x, 0, (float)z));
            MeshComponent* pMesh = new MeshComponent(pEntity);
            pMesh->SetMeshResource("chamber.nfm");
            BodyComponent* pBody = new BodyComponent(pEntity);
            pBody->EnablePhysics(pChamberShape);


            LightComponent* pLight;
            OmniLightDesc omni;
            pEntity = g_pScene->CreateEntity();
            pEntity->SetPosition(12.0f * Vector(x, 0, z) + Vector(0.0f, 3.5f, 0.0f));
            pLight = new LightComponent(pEntity);

            omni.shadowFadeStart = 80.0f;
            omni.shadowFadeEnd = 120.0f;
            omni.radius = 8.0f;
            pLight->SetOmniLight(&omni);
            pLight->SetColor(Float3(50, 50, 50));
            pLight->SetShadowMap(32);


            pEntity = g_pScene->CreateEntity();
            pEntity->SetPosition(12.0f * Vector(x, 0, z) + Vector(6.0f, 1.8f, 0.0f));
            pLight = new LightComponent(pEntity);
            omni.radius = 3.0f;
            pLight->SetOmniLight(&omni);
            pLight->SetColor(Float3(5.0f, 0.5f, 0.25f));

            pEntity = g_pScene->CreateEntity();
            pEntity->SetPosition(12.0f * Vector(x, 0, z) + Vector(0.0f, 1.8f, 6.0f));
            pLight = new LightComponent(pEntity);
            omni.radius = 3.0f;
            pLight->SetOmniLight(&omni);
            pLight->SetColor(Float3(5.0f, 0.5f, 0.25f));


            /*
            for (int i = -3; i<=3; i++)
            {
            for (int j = 0; j<4; j++)
            {
                for (int k = -3; k<=3; k++)
                {
                    Entity* pCube = g_pScene->CreateEntity();
                    pCube->SetPosition(12.0f * Vector(x,0,z) + 0.6f * Vector(i,j,k) + Vector(0.0f, 0.25f, 0.0f));

                    MeshComponent* pMesh = new MeshComponent(pCube);
                    pMesh->SetMeshResource("cube.nfm");

                    BodyComponent* pBody = new BodyComponent(pCube);
                    pBody->SetMass(0.0f);
                    pBody->EnablePhysics((CollisionShape*)Engine_GetResource(Mesh::COLLISION_SHAPE, "shape_box"));
                }
            }
            }*/
        }
    }
#endif

// infinite looped scene
#ifdef SCENE_SEGMENTS
    BufferOutputStream segmentDesc;

    Matrix mat = MatrixRotationNormal(Vector(0, 1, 0), NFE_MATH_PI / 4.0f);

    // create segments description buffer
    {
        OmniLightDesc omni;
        LightComponent* pLight;
        Entity entity;
        entity.SetPosition(Vector());
        //pEntity->SetMatrix(mat);
        MeshComponent* pMesh = new MeshComponent(&entity);
        pMesh->SetMeshResource("chamber.nfm");
        BodyComponent* pBody = new BodyComponent(&entity);
        pBody->EnablePhysics(pChamberShape);
        entity.Serialize(&segmentDesc, Vector());

        entity.RemoveAllComponents();
        entity.SetPosition(Vector(0.0f, 3.5f, 0.0f));
        /*
            pLight = new LightComponent(&entity);
            omni.m_ShadowFadeEnd = 12.0f;
            omni.m_ShadowFadeStart = 8.0f;
            omni.m_Radius = 9.0f;
            pLight->SetOmniLight(&omni);
            pLight->SetColor(Float3(50, 50, 50));
            pLight->SetShadowMap(512);
                entity.Serialize(&segmentDesc, Vector());
                */
        entity.RemoveAllComponents();
        entity.SetPosition(Vector(6.0f, 1.8f, 0.0f));
        pLight = new LightComponent(&entity);
        omni.m_Radius = 3.0f;
        pLight->SetOmniLight(&omni);
        pLight->SetColor(Float3(5.0f, 0.5f, 0.25f));
        entity.Serialize(&segmentDesc, Vector());

        entity.RemoveAllComponents();
        entity.SetPosition(Vector(0.0f, 1.8f, 6.0f));
        pLight = new LightComponent(&entity);
        omni.m_Radius = 3.0f;
        pLight->SetOmniLight(&omni);
        pLight->SetColor(Float3(5.0f, 0.5f, 0.25f));
        entity.Serialize(&segmentDesc, Vector());
    }

#define SEG_AXIS_NUM 12

    Segment* pSegments[SEG_AXIS_NUM][SEG_AXIS_NUM];

    // create segments array
    for (int i = 0; i < SEG_AXIS_NUM; i++)
    {
        for (int j = 0; j < SEG_AXIS_NUM; j++)
        {
            char segName[32];
            sprintf_s(segName, "seg_%i_%i", i, j);
            pSegments[i][j] = g_pScene->CreateSegment(segName, Vector(5.99f, 1000.0f, 5.99f));
            pSegments[i][j]->AddEntityFromRawBuffer(segmentDesc.GetData(), segmentDesc.GetSize());
        }
    }

    // create links
    for (int x = 0; x < SEG_AXIS_NUM; x++)
    {
        for (int z = 0; z < SEG_AXIS_NUM; z++)
        {
            //make inifinite loop
            for (int depth = 1; depth <= 5; depth++)
            {
                g_pScene->CreateLink(pSegments[x][z], pSegments[(x + depth) % SEG_AXIS_NUM][z],
                                     Vector(depth * 12.0f, 0.0f, 0.0f));
                g_pScene->CreateLink(pSegments[x][z], pSegments[x][(z + depth) % SEG_AXIS_NUM], Vector(0.0, 0.0f,
                                     depth * 12.0f));
            }
        }
    }

    // Set focus
    g_pScene->SetFocusSegment(pSegments[0][0]);
#endif

    /*
    for (int i = -4; i<4; i++)
    {
        for (int j = -10; j<10; j++)
        {
            for (int k = -4; k<4; k++)
            {
                Entity* pCube = g_pScene->CreateEntity();
                pCube->SetPosition(0.75f * Vector(i,j,k));

                MeshComponent* pMesh = new MeshComponent(pCube);
                pMesh->SetMeshResource("cube.nfm");

                BodyComponent* pBody = new BodyComponent(pCube);
                pBody->SetMass(1.0f);
                pBody->EnablePhysics((CollisionShape*)Engine_GetResource(Mesh::COLLISION_SHAPE, "shape_box"));
            }
        }
    }

    //set ambient & background color
    envDesc.m_AmbientLight = Vector(0.001f, 0.001f, 0.001f, 0.0f);
    envDesc.m_BackgroundColor = Vector(0.0f, 0.0f, 0.0f, 0.0f);
    g_pScene->SetEnvironment(&envDesc);

    // SUNLIGHT
    Entity* pDirLightEnt = g_pScene->CreateEntity();
    XOrientation orient;
    orient.x = Vector(0.0f, -0.0f, -0.0f, 0.0f);
    orient.z = Vector(-0.5f, -1.1f, 1.2f, 0.0f);
    orient.y = Vector(0.0f, 1.0f, 0.0f, 0.0f);
    pDirLightEnt->SetOrientation(&orient);
    DirLightDesc dirLight;
    dirLight.m_Far = 100.0f;
    dirLight.m_Splits = 4;
    dirLight.m_LightDist = 1000.0f;

    LightComponent* pDirLight = new LightComponent(pDirLightEnt);
    pDirLight->SetDirLight(&dirLight);
    pDirLight->SetColor(Float3(2.2, 2, 1.8));
    pDirLight->SetShadowMap(1024);

    pFirstWindow->cameraEntity->SetPosition(Vector(0.0f, 1.6f, -20.0f, 0.0f));
    */

    // message loop

    DrawRequest drawRequests[2];

    Common::Timer timer;
    timer.Start();
    while (!pWindow->isClosed())
    {
        //measure delta time
        g_DeltaTime = (float)timer.Stop();
        timer.Start();

        UpdateRequest updateReq;
        updateReq.pScene = g_pScene;
        updateReq.deltaTime = g_DeltaTime;


        pWindow->processMessages();
        pWindow->UpdateCamera();

        drawRequests[0].deltaTime = g_DeltaTime;
        drawRequests[0].pView = pWindow->view;
        drawRequests[1].deltaTime = g_DeltaTime;
        drawRequests[1].pView = g_pSecondaryCameraView;
        EngineAdvance(drawRequests, 2, &updateReq, 1);

        ProcessSceneEvents();

        // print focus segment name
        wchar_t str[128];
        Segment* pFocus = g_pScene->GetFocusSegment();
        swprintf(str, L"NFEngine Demo (%S) - focus: %S", PLATFORM_STR,
                 (pFocus != 0) ? pFocus->GetName() : "NONE");
        pWindow->setTitle(str);
    }

    // for testing purposes
    Common::FileOutputStream test_stream("test.xml");
    g_pScene->Serialize(&test_stream, SerializationFormat::Xml, false);

    EngineDeleteScene(g_pScene);
    delete pWindow;
    EngineRelease();

//detect memory leaks
#ifdef _DEBUG
    _CrtDumpMemoryLeaks();
#endif

    return 0;
}
Exemple #25
0
// Apply Frame Limit and Display FPS info
// This should only be called from VI
void VideoThrottle()
{
	u32 TargetVPS = (SConfig::GetInstance().m_Framelimit > 2) ?
		(SConfig::GetInstance().m_Framelimit - 1) * 5 : VideoInterface::TargetRefreshRate;

	// Disable the frame-limiter when the throttle (Tab) key is held down. Audio throttle: m_Framelimit = 2
	if (SConfig::GetInstance().m_Framelimit && SConfig::GetInstance().m_Framelimit != 2 && !Host_GetKeyState('\t'))
	{
		u32 frametime = ((SConfig::GetInstance().b_UseFPS)? Common::AtomicLoad(DrawnFrame) : DrawnVideo) * 1000 / TargetVPS;

		u32 timeDifference = (u32)Timer.GetTimeDifference();
		if (timeDifference < frametime) {
			Common::SleepCurrentThread(frametime - timeDifference - 1);
		}

		while ((u32)Timer.GetTimeDifference() < frametime)
			Common::YieldCPU();
			//Common::SleepCurrentThread(1);
	}

	// Update info per second
	u32 ElapseTime = (u32)Timer.GetTimeDifference();
	if ((ElapseTime >= 1000 && DrawnVideo > 0) || g_requestRefreshInfo)
	{
		g_requestRefreshInfo = false;
		SCoreStartupParameter& _CoreParameter = SConfig::GetInstance().m_LocalCoreStartupParameter;

		if (ElapseTime == 0)
			ElapseTime = 1;

		u32 FPS = Common::AtomicLoad(DrawnFrame) * 1000 / ElapseTime;
		u32 VPS = DrawnVideo * 1000 / ElapseTime;
		u32 Speed = DrawnVideo * (100 * 1000) / (VideoInterface::TargetRefreshRate * ElapseTime);
		
		// Settings are shown the same for both extended and summary info
		std::string SSettings = StringFromFormat("%s %s", cpu_core_base->GetName(),	_CoreParameter.bCPUThread ? "DC" : "SC");

		// Use extended or summary information. The summary information does not print the ticks data,
		// that's more of a debugging interest, it can always be optional of course if someone is interested.
		//#define EXTENDED_INFO
		#ifdef EXTENDED_INFO
			u64 newTicks = CoreTiming::GetTicks();
			u64 newIdleTicks = CoreTiming::GetIdleTicks();
	 
			u64 diff = (newTicks - ticks) / 1000000;
			u64 idleDiff = (newIdleTicks - idleTicks) / 1000000;
	 
			ticks = newTicks;
			idleTicks = newIdleTicks;	 
			
			float TicksPercentage = (float)diff / (float)(SystemTimers::GetTicksPerSecond() / 1000000) * 100;

			std::string SFPS = StringFromFormat("FPS: %u - VPS: %u - SPEED: %u%%", FPS, VPS, Speed);
			SFPS += StringFromFormat(" | CPU: %s%i MHz [Real: %i + IdleSkip: %i] / %i MHz (%s%3.0f%%)",
					_CoreParameter.bSkipIdle ? "~" : "",
					(int)(diff),
					(int)(diff - idleDiff),
					(int)(idleDiff),
					SystemTimers::GetTicksPerSecond() / 1000000,
					_CoreParameter.bSkipIdle ? "~" : "",
					TicksPercentage);

		#else	// Summary information
		std::string SFPS;
		if (Movie::IsPlayingInput())
			SFPS = StringFromFormat("VI: %u/%u - Frame: %u/%u - FPS: %u - VPS: %u - SPEED: %u%%", (u32)Movie::g_currentFrame, (u32)Movie::g_totalFrames, (u32)Movie::g_currentInputCount, (u32)Movie::g_totalInputCount, FPS, VPS, Speed);
		else if (Movie::IsRecordingInput())
			SFPS = StringFromFormat("VI: %u - Frame: %u - FPS: %u - VPS: %u - SPEED: %u%%", (u32)Movie::g_currentFrame, (u32)Movie::g_currentInputCount, FPS, VPS, Speed);
		else
			SFPS = StringFromFormat("FPS: %u - VPS: %u - SPEED: %u%%", FPS, VPS, Speed);
		#endif

		// This is our final "frame counter" string
		std::string SMessage = StringFromFormat("%s | %s",
			SSettings.c_str(), SFPS.c_str());
		std::string TMessage = StringFromFormat("%s | ", scm_rev_str) +
			SMessage;

		// Show message
		g_video_backend->UpdateFPSDisplay(SMessage.c_str()); 

		if (_CoreParameter.bRenderToMain &&
			SConfig::GetInstance().m_InterfaceStatusbar) {
			Host_UpdateStatusBar(SMessage.c_str());
			Host_UpdateTitle(scm_rev_str);
		} else
			Host_UpdateTitle(TMessage.c_str());
		

		// Reset counter
		Timer.Update();
		Common::AtomicStore(DrawnFrame, 0);
		DrawnVideo = 0;
	}

	DrawnVideo++;
}
Exemple #26
0
// Update the time
void Pause()
{
	ReRecTimer.Update();
}