1 // Copyright (C) 2003 Dolphin Project.
3 // This program is free software: you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License as published by
5 // the Free Software Foundation, version 2.0.
7 // This program is distributed in the hope that it will be useful,
8 // but WITHOUT ANY WARRANTY; without even the implied warranty of
9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 // GNU General Public License 2.0 for more details.
12 // A copy of the GPL 2.0 should have been included with the program.
13 // If not, see http://www.gnu.org/licenses/
15 // Official SVN repository and contact information can be found at
16 // http://code.google.com/p/dolphin-emu/
20 // OpenGL Plugin Documentation
25 Internal and fullscreen resolution: Since the only internal resolutions allowed
26 are also fullscreen resolution allowed by the system there is only need for one
27 resolution setting that applies to both the internal resolution and the
28 fullscreen resolution. - Apparently no, someone else doesn't agree
30 Todo: Make the internal resolution option apply instantly, currently only the
31 native and 2x option applies instantly. To do this we need to be able to change
32 the reinitialize FramebufferManager:Init() while a game is running.
37 The screenshots should be taken from the internal representation of the picture
38 regardless of what the current window size is. Since AA and wireframe is
39 applied together with the picture resizing this rule is not currently applied
40 to AA or wireframe pictures, they are instead taken from whatever the window
43 Todo: Render AA and wireframe to a separate picture used for the screenshot in
44 addition to the one for display.
48 Make AA apply instantly during gameplay if possible
53 #include "LogManager.h"
63 #if defined(HAVE_WX) && HAVE_WX
64 #include "GUI/ConfigDlg.h"
65 GFXConfigDialogOGL
*m_ConfigFrame
= NULL
;
66 #include "Debugger/Debugger.h"
67 GFXDebuggerOGL
*m_DebuggerFrame
= NULL
;
70 #include "VideoConfig.h"
71 #include "LookUpTables.h"
72 #include "ImageWrite.h"
76 #include "OpcodeDecoding.h"
77 #include "TextureMngr.h"
78 #include "BPStructs.h"
79 #include "VertexLoader.h"
80 #include "VertexLoaderManager.h"
81 #include "VertexManager.h"
82 #include "PixelShaderCache.h"
83 #include "PixelShaderManager.h"
84 #include "VertexShaderCache.h"
85 #include "VertexShaderManager.h"
87 #include "XFBConvert.h"
88 #include "CommandProcessor.h"
89 #include "PixelEngine.h"
90 #include "TextureConverter.h"
91 #include "PostProcessing.h"
92 #include "OnScreenDisplay.h"
96 #include "VideoState.h"
98 #if defined(HAVE_COCOA) && HAVE_COCOA
99 #include <Cocoa/Cocoa.h>
102 SVideoInitialize g_VideoInitialize
;
103 PLUGIN_GLOBALS
* globals
= NULL
;
106 int GLScissorX
, GLScissorY
, GLScissorW
, GLScissorH
;
108 static bool s_PluginInitialized
= false;
110 volatile u32 s_swapRequested
= FALSE
;
111 static u32 s_efbAccessRequested
= FALSE
;
112 static volatile u32 s_FifoShuttingDown
= FALSE
;
113 static bool ForceSwap
= true;
120 void GetDllInfo (PLUGIN_INFO
* _PluginInfo
)
122 _PluginInfo
->Version
= 0x0100;
123 _PluginInfo
->Type
= PLUGIN_TYPE_VIDEO
;
125 sprintf(_PluginInfo
->Name
, "Dolphin OpenGL (DebugFast)");
127 sprintf(_PluginInfo
->Name
, "Dolphin OpenGL (Debug)");
129 sprintf(_PluginInfo
->Name
, "Dolphin OpenGL");
133 void SetDllGlobals(PLUGIN_GLOBALS
* _pPluginGlobals
)
135 globals
= _pPluginGlobals
;
136 LogManager::SetInstance((LogManager
*)globals
->logManager
);
139 // This is used for the functions right below here which use wxwidgets
140 #if defined(HAVE_WX) && HAVE_WX
142 WXDLLIMPEXP_BASE
void wxSetInstance(HINSTANCE hInst
);
143 extern HINSTANCE g_hInstance
;
146 wxWindow
* GetParentedWxWindow(HWND Parent
)
149 wxSetInstance((HINSTANCE
)g_hInstance
);
151 wxWindow
*win
= new wxWindow();
153 win
->SetHWND((WXHWND
)Parent
);
154 win
->AdoptAttributesFromHWND();
160 void DllDebugger(HWND _hParent
, bool Show
)
162 #if defined(HAVE_WX) && HAVE_WX
164 if (!m_DebuggerFrame
)
165 m_DebuggerFrame
= new GFXDebuggerOGL(NULL
);
166 m_DebuggerFrame
->Show();
168 if (m_DebuggerFrame
) m_DebuggerFrame
->Hide();
173 void DllConfig(HWND _hParent
)
175 g_Config
.Load((std::string(File::GetUserPath(D_CONFIG_IDX
)) + "gfx_opengl.ini").c_str());
176 g_Config
.GameIniLoad(globals
->game_ini
);
177 g_Config
.UpdateProjectionHack();
178 UpdateActiveConfig();
179 #if defined(HAVE_WX) && HAVE_WX
180 wxWindow
*frame
= GetParentedWxWindow(_hParent
);
181 m_ConfigFrame
= new GFXConfigDialogOGL(frame
);
183 // Prevent user to show more than 1 config window at same time
186 m_ConfigFrame
->CreateGUIControls();
187 m_ConfigFrame
->ShowModal();
190 m_ConfigFrame
->CreateGUIControls();
191 m_ConfigFrame
->ShowModal();
196 frame
->SetHWND(NULL
);
199 m_ConfigFrame
->Destroy();
200 m_ConfigFrame
= NULL
;
205 void Initialize(void *init
)
208 SVideoInitialize
*_pVideoInitialize
= (SVideoInitialize
*)init
;
209 // Create a shortcut to _pVideoInitialize that can also update it
210 g_VideoInitialize
= *(_pVideoInitialize
);
213 g_Config
.Load((std::string(File::GetUserPath(D_CONFIG_IDX
)) + "gfx_opengl.ini").c_str());
214 g_Config
.GameIniLoad(globals
->game_ini
);
216 g_Config
.UpdateProjectionHack();
217 #if defined(HAVE_WX) && HAVE_WX
218 //Enable support for PNG screenshots.
219 wxImage::AddHandler( new wxPNGHandler
);
221 UpdateActiveConfig();
223 if (!OpenGL_Create(g_VideoInitialize
, 640, 480))
225 g_VideoInitialize
.pLog("Renderer::Create failed\n", TRUE
);
229 _pVideoInitialize
->pPeekMessages
= g_VideoInitialize
.pPeekMessages
;
230 _pVideoInitialize
->pUpdateFPSDisplay
= g_VideoInitialize
.pUpdateFPSDisplay
;
232 // Now the window handle is written
233 _pVideoInitialize
->pWindowHandle
= g_VideoInitialize
.pWindowHandle
;
234 #if defined(HAVE_X11) && HAVE_X11
235 _pVideoInitialize
->pXWindow
= g_VideoInitialize
.pXWindow
;
238 OSD::AddMessage("Dolphin OpenGL Video Plugin" ,5000);
241 void DoState(unsigned char **ptr
, int mode
) {
242 #if defined(HAVE_X11) && HAVE_X11
243 OpenGL_MakeCurrent();
245 // Clear all caches that touch RAM
246 TextureMngr::Invalidate(false);
247 VertexLoaderManager::MarkAllDirty();
249 PointerWrap
p(ptr
, mode
);
250 VideoCommon_DoState(p
);
253 if (mode
== PointerWrap::MODE_READ
)
256 RecomputeCachedArraybases();
260 void EmuStateChange(PLUGIN_EMUSTATE newState
)
262 Fifo_RunLoop((newState
== PLUGIN_EMUSTATE_PLAY
) ? true : false);
265 // This is called after Video_Initialize() from the Core
266 void Video_Prepare(void)
268 OpenGL_MakeCurrent();
269 if (!Renderer::Init()) {
270 g_VideoInitialize
.pLog("Renderer::Create failed\n", TRUE
);
271 PanicAlert("Can't create opengl renderer. You might be missing some required opengl extensions, check the logs for more info");
275 s_swapRequested
= FALSE
;
276 s_efbAccessRequested
= FALSE
;
277 s_FifoShuttingDown
= FALSE
;
279 CommandProcessor::Init();
285 VertexManager::Init();
286 Fifo_Init(); // must be done before OpcodeDecoder_Init()
287 OpcodeDecoder_Init();
288 VertexShaderCache::Init();
289 VertexShaderManager::Init();
290 PixelShaderCache::Init();
291 PixelShaderManager::Init();
292 PostProcessing::Init();
294 VertexLoaderManager::Init();
295 TextureConverter::Init();
298 // Notify the core that the video plugin is ready
299 g_VideoInitialize
.pCoreMessage(WM_USER_CREATE
);
301 s_PluginInitialized
= true;
302 INFO_LOG(VIDEO
, "Video plugin initialized.");
307 s_PluginInitialized
= false;
310 s_efbAccessRequested
= FALSE
;
311 s_swapRequested
= FALSE
;
312 s_FifoShuttingDown
= FALSE
;
316 PostProcessing::Shutdown();
318 // The following calls are NOT Thread Safe
319 // And need to be called from the video thread
320 TextureConverter::Shutdown();
321 VertexLoaderManager::Shutdown();
322 VertexShaderCache::Shutdown();
323 VertexShaderManager::Shutdown();
324 PixelShaderManager::Shutdown();
325 PixelShaderCache::Shutdown();
326 VertexManager::Shutdown();
327 TextureMngr::Shutdown();
328 OpcodeDecoder_Shutdown();
329 Renderer::Shutdown();
333 // Enter and exit the video loop
334 void Video_EnterLoop()
336 Fifo_EnterLoop(g_VideoInitialize
);
339 void Video_ExitLoop()
343 s_FifoShuttingDown
= TRUE
;
346 // Screenshot and screen message
348 void Video_Screenshot(const char *_szFilename
)
350 Renderer::SetScreenshot(_szFilename
);
353 void Video_AddMessage(const char* pstr
, u32 milliseconds
)
355 OSD::AddMessage(pstr
, milliseconds
);
358 void Video_SetRendering(bool bEnabled
) {
359 Fifo_SetRendering(bEnabled
);
362 static volatile struct
370 // Run from the graphics thread (from Fifo.cpp)
371 void VideoFifo_CheckSwapRequest()
373 if (Common::AtomicLoadAcquire(s_swapRequested
))
375 if (ForceSwap
|| g_ActiveConfig
.bUseXFB
)
377 Renderer::Swap(s_beginFieldArgs
.xfbAddr
, s_beginFieldArgs
.field
, s_beginFieldArgs
.fbWidth
, s_beginFieldArgs
.fbHeight
);
380 Common::AtomicStoreRelease(s_swapRequested
, FALSE
);
384 inline bool addrRangesOverlap(u32 aLower
, u32 aUpper
, u32 bLower
, u32 bUpper
)
386 return !((aLower
>= bUpper
) || (bLower
>= aUpper
));
389 // Run from the graphics thread (from Fifo.cpp)
390 void VideoFifo_CheckSwapRequestAt(u32 xfbAddr
, u32 fbWidth
, u32 fbHeight
)
392 if (Common::AtomicLoadAcquire(s_swapRequested
) && g_ActiveConfig
.bUseXFB
)
394 u32 aLower
= xfbAddr
;
395 u32 aUpper
= xfbAddr
+ 2 * fbWidth
* fbHeight
;
396 u32 bLower
= s_beginFieldArgs
.xfbAddr
;
397 u32 bUpper
= s_beginFieldArgs
.xfbAddr
+ 2 * s_beginFieldArgs
.fbWidth
* s_beginFieldArgs
.fbHeight
;
399 if (addrRangesOverlap(aLower
, aUpper
, bLower
, bUpper
))
400 VideoFifo_CheckSwapRequest();
406 // Run from the CPU thread (from VideoInterface.cpp)
407 void Video_BeginField(u32 xfbAddr
, FieldType field
, u32 fbWidth
, u32 fbHeight
)
409 if (s_PluginInitialized
&& g_ActiveConfig
.bUseXFB
)
411 s_beginFieldArgs
.xfbAddr
= xfbAddr
;
412 s_beginFieldArgs
.field
= field
;
413 s_beginFieldArgs
.fbWidth
= fbWidth
;
414 s_beginFieldArgs
.fbHeight
= fbHeight
;
416 Common::AtomicStoreRelease(s_swapRequested
, TRUE
);
417 if (g_VideoInitialize
.bOnThread
)
419 while (Common::AtomicLoadAcquire(s_swapRequested
) && !s_FifoShuttingDown
)
420 //Common::SleepCurrentThread(1);
424 VideoFifo_CheckSwapRequest();
428 // Run from the CPU thread (from VideoInterface.cpp)
429 void Video_EndField()
440 static u32 s_AccessEFBResult
= 0;
442 void VideoFifo_CheckEFBAccess()
444 if (Common::AtomicLoadAcquire(s_efbAccessRequested
))
446 s_AccessEFBResult
= Renderer::AccessEFB(s_accessEFBArgs
.type
, s_accessEFBArgs
.x
, s_accessEFBArgs
.y
);
448 Common::AtomicStoreRelease(s_efbAccessRequested
, FALSE
);
452 u32
Video_AccessEFB(EFBAccessType type
, u32 x
, u32 y
)
454 if (s_PluginInitialized
)
456 s_accessEFBArgs
.type
= type
;
457 s_accessEFBArgs
.x
= x
;
458 s_accessEFBArgs
.y
= y
;
460 Common::AtomicStoreRelease(s_efbAccessRequested
, TRUE
);
462 if (g_VideoInitialize
.bOnThread
)
464 while (Common::AtomicLoadAcquire(s_efbAccessRequested
) && !s_FifoShuttingDown
)
465 //Common::SleepCurrentThread(1);
469 VideoFifo_CheckEFBAccess();
471 return s_AccessEFBResult
;
477 void Video_CommandProcessorRead16(u16
& _rReturnValue
, const u32 _Address
)
479 CommandProcessor::Read16(_rReturnValue
, _Address
);
482 void Video_CommandProcessorWrite16(const u16 _Data
, const u32 _Address
)
484 CommandProcessor::Write16(_Data
, _Address
);
487 void Video_PixelEngineRead16(u16
& _rReturnValue
, const u32 _Address
)
489 PixelEngine::Read16(_rReturnValue
, _Address
);
492 void Video_PixelEngineWrite16(const u16 _Data
, const u32 _Address
)
494 PixelEngine::Write16(_Data
, _Address
);
497 void Video_PixelEngineWrite32(const u32 _Data
, const u32 _Address
)
499 PixelEngine::Write32(_Data
, _Address
);
502 void Video_GatherPipeBursted(void)
504 CommandProcessor::GatherPipeBursted();
507 void Video_WaitForFrameFinish(void)
509 CommandProcessor::WaitForFrameFinish();