mirror of
				https://github.com/dolphin-emu/dolphin.git
				synced 2025-10-25 17:39:09 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			256 lines
		
	
	
	
		
			6.4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			256 lines
		
	
	
	
		
			6.4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| // Copyright 2010 Dolphin Emulator Project
 | |
| // Licensed under GPLv2+
 | |
| // Refer to the license.txt file included.
 | |
| 
 | |
| #include <cstring>
 | |
| 
 | |
| #include "Common/ChunkFile.h"
 | |
| #include "Common/CommonTypes.h"
 | |
| #include "Common/Event.h"
 | |
| #include "Common/Flag.h"
 | |
| #include "Common/Logging/Log.h"
 | |
| #include "Core/Host.h"
 | |
| #include "VideoCommon/AsyncRequests.h"
 | |
| #include "VideoCommon/BPStructs.h"
 | |
| #include "VideoCommon/CPMemory.h"
 | |
| #include "VideoCommon/CommandProcessor.h"
 | |
| #include "VideoCommon/Fifo.h"
 | |
| #include "VideoCommon/GeometryShaderManager.h"
 | |
| #include "VideoCommon/IndexGenerator.h"
 | |
| #include "VideoCommon/OnScreenDisplay.h"
 | |
| #include "VideoCommon/OpcodeDecoding.h"
 | |
| #include "VideoCommon/PixelEngine.h"
 | |
| #include "VideoCommon/PixelShaderManager.h"
 | |
| #include "VideoCommon/RenderBase.h"
 | |
| #include "VideoCommon/TextureCacheBase.h"
 | |
| #include "VideoCommon/VertexLoaderManager.h"
 | |
| #include "VideoCommon/VertexShaderManager.h"
 | |
| #include "VideoCommon/VideoBackendBase.h"
 | |
| #include "VideoCommon/VideoConfig.h"
 | |
| #include "VideoCommon/VideoState.h"
 | |
| 
 | |
| static Common::Flag s_FifoShuttingDown;
 | |
| 
 | |
| static volatile struct
 | |
| {
 | |
|   u32 xfbAddr;
 | |
|   u32 fbWidth;
 | |
|   u32 fbStride;
 | |
|   u32 fbHeight;
 | |
| } s_beginFieldArgs;
 | |
| 
 | |
| void VideoBackendBase::Video_ExitLoop()
 | |
| {
 | |
|   Fifo::ExitGpuLoop();
 | |
|   s_FifoShuttingDown.Set();
 | |
| }
 | |
| 
 | |
| // Run from the CPU thread (from VideoInterface.cpp)
 | |
| void VideoBackendBase::Video_BeginField(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight,
 | |
|                                         u64 ticks)
 | |
| {
 | |
|   if (m_initialized && g_ActiveConfig.bUseXFB && g_renderer)
 | |
|   {
 | |
|     Fifo::SyncGPU(Fifo::SyncGPUReason::Swap);
 | |
| 
 | |
|     AsyncRequests::Event e;
 | |
|     e.time = ticks;
 | |
|     e.type = AsyncRequests::Event::SWAP_EVENT;
 | |
| 
 | |
|     e.swap_event.xfbAddr = xfbAddr;
 | |
|     e.swap_event.fbWidth = fbWidth;
 | |
|     e.swap_event.fbStride = fbStride;
 | |
|     e.swap_event.fbHeight = fbHeight;
 | |
|     AsyncRequests::GetInstance()->PushEvent(e, false);
 | |
|   }
 | |
| }
 | |
| 
 | |
| u32 VideoBackendBase::Video_AccessEFB(EFBAccessType type, u32 x, u32 y, u32 InputData)
 | |
| {
 | |
|   if (!g_ActiveConfig.bEFBAccessEnable)
 | |
|   {
 | |
|     return 0;
 | |
|   }
 | |
| 
 | |
|   if (type == EFBAccessType::PokeColor || type == EFBAccessType::PokeZ)
 | |
|   {
 | |
|     AsyncRequests::Event e;
 | |
|     e.type = type == EFBAccessType::PokeColor ? AsyncRequests::Event::EFB_POKE_COLOR :
 | |
|                                                 AsyncRequests::Event::EFB_POKE_Z;
 | |
|     e.time = 0;
 | |
|     e.efb_poke.data = InputData;
 | |
|     e.efb_poke.x = x;
 | |
|     e.efb_poke.y = y;
 | |
|     AsyncRequests::GetInstance()->PushEvent(e, false);
 | |
|     return 0;
 | |
|   }
 | |
|   else
 | |
|   {
 | |
|     AsyncRequests::Event e;
 | |
|     u32 result;
 | |
|     e.type = type == EFBAccessType::PeekColor ? AsyncRequests::Event::EFB_PEEK_COLOR :
 | |
|                                                 AsyncRequests::Event::EFB_PEEK_Z;
 | |
|     e.time = 0;
 | |
|     e.efb_peek.x = x;
 | |
|     e.efb_peek.y = y;
 | |
|     e.efb_peek.data = &result;
 | |
|     AsyncRequests::GetInstance()->PushEvent(e, true);
 | |
|     return result;
 | |
|   }
 | |
| }
 | |
| 
 | |
| u32 VideoBackendBase::Video_GetQueryResult(PerfQueryType type)
 | |
| {
 | |
|   if (!g_perf_query->ShouldEmulate())
 | |
|   {
 | |
|     return 0;
 | |
|   }
 | |
| 
 | |
|   Fifo::SyncGPU(Fifo::SyncGPUReason::PerfQuery);
 | |
| 
 | |
|   AsyncRequests::Event e;
 | |
|   e.time = 0;
 | |
|   e.type = AsyncRequests::Event::PERF_QUERY;
 | |
| 
 | |
|   if (!g_perf_query->IsFlushed())
 | |
|     AsyncRequests::GetInstance()->PushEvent(e, true);
 | |
| 
 | |
|   return g_perf_query->GetQueryResult(type);
 | |
| }
 | |
| 
 | |
| u16 VideoBackendBase::Video_GetBoundingBox(int index)
 | |
| {
 | |
|   if (!g_ActiveConfig.bBBoxEnable)
 | |
|   {
 | |
|     static bool warn_once = true;
 | |
|     if (warn_once)
 | |
|       ERROR_LOG(VIDEO, "BBox shall be used but it is disabled. Please use a gameini to enable it "
 | |
|                        "for this game.");
 | |
|     warn_once = false;
 | |
|     return 0;
 | |
|   }
 | |
| 
 | |
|   if (!g_ActiveConfig.backend_info.bSupportsBBox)
 | |
|   {
 | |
|     static bool warn_once = true;
 | |
|     if (warn_once)
 | |
|       PanicAlertT("This game requires bounding box emulation to run properly but your graphics "
 | |
|                   "card or its drivers do not support it. As a result you will experience bugs or "
 | |
|                   "freezes while running this game.");
 | |
|     warn_once = false;
 | |
|     return 0;
 | |
|   }
 | |
| 
 | |
|   Fifo::SyncGPU(Fifo::SyncGPUReason::BBox);
 | |
| 
 | |
|   AsyncRequests::Event e;
 | |
|   u16 result;
 | |
|   e.time = 0;
 | |
|   e.type = AsyncRequests::Event::BBOX_READ;
 | |
|   e.bbox.index = index;
 | |
|   e.bbox.data = &result;
 | |
|   AsyncRequests::GetInstance()->PushEvent(e, true);
 | |
| 
 | |
|   return result;
 | |
| }
 | |
| 
 | |
| void VideoBackendBase::ShowConfig(void* parent_handle)
 | |
| {
 | |
|   if (!m_initialized)
 | |
|     InitBackendInfo();
 | |
| 
 | |
|   Host_ShowVideoConfig(parent_handle, GetDisplayName());
 | |
| }
 | |
| 
 | |
| void VideoBackendBase::InitializeShared()
 | |
| {
 | |
|   memset(&g_main_cp_state, 0, sizeof(g_main_cp_state));
 | |
|   memset(&g_preprocess_cp_state, 0, sizeof(g_preprocess_cp_state));
 | |
|   memset(texMem, 0, TMEM_SIZE);
 | |
| 
 | |
|   // Do our OSD callbacks
 | |
|   OSD::DoCallbacks(OSD::CallbackType::Initialization);
 | |
| 
 | |
|   // do not initialize again for the config window
 | |
|   m_initialized = true;
 | |
| 
 | |
|   s_FifoShuttingDown.Clear();
 | |
|   memset((void*)&s_beginFieldArgs, 0, sizeof(s_beginFieldArgs));
 | |
|   m_invalid = false;
 | |
|   frameCount = 0;
 | |
| 
 | |
|   CommandProcessor::Init();
 | |
|   Fifo::Init();
 | |
|   OpcodeDecoder::Init();
 | |
|   PixelEngine::Init();
 | |
|   BPInit();
 | |
|   VertexLoaderManager::Init();
 | |
|   IndexGenerator::Init();
 | |
|   VertexShaderManager::Init();
 | |
|   GeometryShaderManager::Init();
 | |
|   PixelShaderManager::Init();
 | |
| 
 | |
|   g_Config.Load(File::GetUserPath(D_CONFIG_IDX) + "GFX.ini");
 | |
|   g_Config.GameIniLoad();
 | |
|   g_Config.UpdateProjectionHack();
 | |
|   g_Config.VerifyValidity();
 | |
|   UpdateActiveConfig();
 | |
| 
 | |
|   // Notify the core that the video backend is ready
 | |
|   Host_Message(WM_USER_CREATE);
 | |
| }
 | |
| 
 | |
| void VideoBackendBase::ShutdownShared()
 | |
| {
 | |
|   // Do our OSD callbacks
 | |
|   OSD::DoCallbacks(OSD::CallbackType::Shutdown);
 | |
| 
 | |
|   m_initialized = false;
 | |
| 
 | |
|   Fifo::Shutdown();
 | |
| }
 | |
| 
 | |
| void VideoBackendBase::CleanupShared()
 | |
| {
 | |
|   VertexLoaderManager::Clear();
 | |
| }
 | |
| 
 | |
| // Run from the CPU thread
 | |
| void VideoBackendBase::DoState(PointerWrap& p)
 | |
| {
 | |
|   bool software = false;
 | |
|   p.Do(software);
 | |
| 
 | |
|   if (p.GetMode() == PointerWrap::MODE_READ && software == true)
 | |
|   {
 | |
|     // change mode to abort load of incompatible save state.
 | |
|     p.SetMode(PointerWrap::MODE_VERIFY);
 | |
|   }
 | |
| 
 | |
|   VideoCommon_DoState(p);
 | |
|   p.DoMarker("VideoCommon");
 | |
| 
 | |
|   p.Do(s_beginFieldArgs);
 | |
|   p.DoMarker("VideoBackendBase");
 | |
| 
 | |
|   // Refresh state.
 | |
|   if (p.GetMode() == PointerWrap::MODE_READ)
 | |
|   {
 | |
|     m_invalid = true;
 | |
| 
 | |
|     // Clear all caches that touch RAM
 | |
|     // (? these don't appear to touch any emulation state that gets saved. moved to on load only.)
 | |
|     VertexLoaderManager::MarkAllDirty();
 | |
|   }
 | |
| }
 | |
| 
 | |
| void VideoBackendBase::CheckInvalidState()
 | |
| {
 | |
|   if (m_invalid)
 | |
|   {
 | |
|     m_invalid = false;
 | |
| 
 | |
|     BPReload();
 | |
|     g_texture_cache->Invalidate();
 | |
|   }
 | |
| }
 |