Some attempts to speedup Rice when using FB
[mupen64plus-pandora.git] / source / gles2rice / src / Video.cpp
CommitLineData
292f9317 1/*
2Copyright (C) 2002 Rice1964
3Copyright (C) 2009-2011 Richard Goedeken
4
5This program is free software; you can redistribute it and/or
6modify it under the terms of the GNU General Public License
7as published by the Free Software Foundation; either version 2
8of the License, or (at your option) any later version.
9
10This program is distributed in the hope that it will be useful,
11but WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20
21#include <vector>
22
23#include <stdarg.h>
24
25#include "osal_opengl.h"
26
27#define M64P_PLUGIN_PROTOTYPES 1
28#include "m64p_types.h"
29#include "m64p_common.h"
30#include "m64p_plugin.h"
31#include "osal_dynamiclib.h"
32
33#include "Config.h"
34#include "Debugger.h"
35#include "DeviceBuilder.h"
36#include "FrameBuffer.h"
37#include "GraphicsContext.h"
38#include "Render.h"
39#include "RSP_Parser.h"
40#include "TextureFilters.h"
41#include "TextureManager.h"
42#include "Video.h"
43#include "version.h"
44
45//=======================================================
46// local variables
47
48static void (*l_DebugCallback)(void *, int, const char *) = NULL;
49static void *l_DebugCallContext = NULL;
50static int l_PluginInit = 0;
51
52//=======================================================
53// global variables
54
55PluginStatus status;
56GFX_INFO g_GraphicsInfo;
57CCritSect g_CritialSection;
58
59unsigned int g_dwRamSize = 0x400000;
60unsigned int *g_pRDRAMu32 = NULL;
61signed char *g_pRDRAMs8 = NULL;
62unsigned char *g_pRDRAMu8 = NULL;
63
64RECT frameWriteByCPURect;
65std::vector<RECT> frameWriteByCPURects;
66RECT frameWriteByCPURectArray[20][20];
67bool frameWriteByCPURectFlag[20][20];
68std::vector<uint32> frameWriteRecord;
69
70void (*renderCallback)(int) = NULL;
71
72/* definitions of pointers to Core config functions */
73ptr_ConfigOpenSection ConfigOpenSection = NULL;
74ptr_ConfigSetParameter ConfigSetParameter = NULL;
75ptr_ConfigGetParameter ConfigGetParameter = NULL;
76ptr_ConfigGetParameterHelp ConfigGetParameterHelp = NULL;
77ptr_ConfigSetDefaultInt ConfigSetDefaultInt = NULL;
78ptr_ConfigSetDefaultFloat ConfigSetDefaultFloat = NULL;
79ptr_ConfigSetDefaultBool ConfigSetDefaultBool = NULL;
80ptr_ConfigSetDefaultString ConfigSetDefaultString = NULL;
81ptr_ConfigGetParamInt ConfigGetParamInt = NULL;
82ptr_ConfigGetParamFloat ConfigGetParamFloat = NULL;
83ptr_ConfigGetParamBool ConfigGetParamBool = NULL;
84ptr_ConfigGetParamString ConfigGetParamString = NULL;
85
86ptr_ConfigGetSharedDataFilepath ConfigGetSharedDataFilepath = NULL;
87ptr_ConfigGetUserConfigPath ConfigGetUserConfigPath = NULL;
88ptr_ConfigGetUserDataPath ConfigGetUserDataPath = NULL;
89ptr_ConfigGetUserCachePath ConfigGetUserCachePath = NULL;
90
91/* definitions of pointers to Core video extension functions */
92ptr_VidExt_Init CoreVideo_Init = NULL;
93ptr_VidExt_Quit CoreVideo_Quit = NULL;
94ptr_VidExt_ListFullscreenModes CoreVideo_ListFullscreenModes = NULL;
95ptr_VidExt_SetVideoMode CoreVideo_SetVideoMode = NULL;
96ptr_VidExt_SetCaption CoreVideo_SetCaption = NULL;
97ptr_VidExt_ToggleFullScreen CoreVideo_ToggleFullScreen = NULL;
98ptr_VidExt_ResizeWindow CoreVideo_ResizeWindow = NULL;
99ptr_VidExt_GL_GetProcAddress CoreVideo_GL_GetProcAddress = NULL;
100ptr_VidExt_GL_SetAttribute CoreVideo_GL_SetAttribute = NULL;
101ptr_VidExt_GL_GetAttribute CoreVideo_GL_GetAttribute = NULL;
102ptr_VidExt_GL_SwapBuffers CoreVideo_GL_SwapBuffers = NULL;
103
ca22e7b7 104// For Fameskip
105float mspervi = 1000.0f/60.0f; //default is shortest frame
106float numvi = 0.0f;
107bool skipping = false;
108
292f9317 109//---------------------------------------------------------------------------------------
110// Forward function declarations
111
112extern "C" EXPORT void CALL RomClosed(void);
113
114//---------------------------------------------------------------------------------------
115// Static (local) functions
116static void ChangeWindowStep2()
117{
118 status.bDisableFPS = true;
119 windowSetting.bDisplayFullscreen = !windowSetting.bDisplayFullscreen;
120 g_CritialSection.Lock();
121 windowSetting.bDisplayFullscreen = CGraphicsContext::Get()->ToggleFullscreen();
122
123 CGraphicsContext::Get()->Clear(CLEAR_COLOR_AND_DEPTH_BUFFER);
124 CGraphicsContext::Get()->UpdateFrame();
125 CGraphicsContext::Get()->Clear(CLEAR_COLOR_AND_DEPTH_BUFFER);
126 CGraphicsContext::Get()->UpdateFrame();
127 CGraphicsContext::Get()->Clear(CLEAR_COLOR_AND_DEPTH_BUFFER);
128 CGraphicsContext::Get()->UpdateFrame();
129 g_CritialSection.Unlock();
130 status.bDisableFPS = false;
131 status.ToToggleFullScreen = FALSE;
132}
133
134static void ResizeStep2(void)
135{
136 g_CritialSection.Lock();
137
138 // Delete all OpenGL textures
139 gTextureManager.CleanUp();
140 RDP_Cleanup();
141 // delete our opengl renderer
142 CDeviceBuilder::GetBuilder()->DeleteRender();
143
144 // call video extension function with updated width, height (this creates a new OpenGL context)
145 windowSetting.uDisplayWidth = status.gNewResizeWidth;
146 windowSetting.uDisplayHeight = status.gNewResizeHeight;
147 CoreVideo_ResizeWindow(windowSetting.uDisplayWidth, windowSetting.uDisplayHeight);
148
149 // re-initialize our OpenGL graphics context state
150 bool res = CGraphicsContext::Get()->ResizeInitialize(windowSetting.uDisplayWidth, windowSetting.uDisplayHeight, !windowSetting.bDisplayFullscreen);
151 if (res)
152 {
153 // re-create the OpenGL renderer
154 CDeviceBuilder::GetBuilder()->CreateRender();
155 CRender::GetRender()->Initialize();
156 DLParser_Init();
157 }
158
159 g_CritialSection.Unlock();
160 status.ToResize = false;
161}
162
163static void UpdateScreenStep2 (void)
164{
165 status.bVIOriginIsUpdated = false;
166
167 if( status.ToToggleFullScreen && status.gDlistCount > 0 )
168 {
169 ChangeWindowStep2();
170 return;
171 }
172 if (status.ToResize && status.gDlistCount > 0)
173 {
174 ResizeStep2();
175 return;
176 }
177
178 g_CritialSection.Lock();
ca22e7b7 179
180 //framskip, count vi
181 numvi++;
182
292f9317 183 if( status.bHandleN64RenderTexture )
184 g_pFrameBufferManager->CloseRenderTexture(true);
ca22e7b7 185
186 if (skipping) {
187 g_CritialSection.Unlock();
188 return;
189 }
292f9317 190
191 g_pFrameBufferManager->SetAddrBeDisplayed(*g_GraphicsInfo.VI_ORIGIN_REG);
192
ca22e7b7 193 if(status.gDlistCount == 0)
292f9317 194 {
195 // CPU frame buffer update
196 uint32 width = *g_GraphicsInfo.VI_WIDTH_REG;
197 if( (*g_GraphicsInfo.VI_ORIGIN_REG & (g_dwRamSize-1) ) > width*2 && *g_GraphicsInfo.VI_H_START_REG != 0 && width != 0 )
198 {
199 SetVIScales();
200 CRender::GetRender()->DrawFrameBuffer(true);
201 CGraphicsContext::Get()->UpdateFrame();
202 }
203 g_CritialSection.Unlock();
204 return;
205 }
206
207 TXTRBUF_DETAIL_DUMP(TRACE1("VI ORIG is updated to %08X", *g_GraphicsInfo.VI_ORIGIN_REG));
208
209 if( currentRomOptions.screenUpdateSetting == SCREEN_UPDATE_AT_VI_UPDATE )
210 {
211 CGraphicsContext::Get()->UpdateFrame();
212
213 DEBUGGER_IF_DUMP( pauseAtNext, TRACE1("Update Screen: VIORIG=%08X", *g_GraphicsInfo.VI_ORIGIN_REG));
214 DEBUGGER_PAUSE_COUNT_N_WITHOUT_UPDATE(NEXT_FRAME);
215 DEBUGGER_PAUSE_COUNT_N_WITHOUT_UPDATE(NEXT_SET_CIMG);
216 g_CritialSection.Unlock();
217 return;
218 }
219
220 TXTRBUF_DETAIL_DUMP(TRACE1("VI ORIG is updated to %08X", *g_GraphicsInfo.VI_ORIGIN_REG));
221
222 if( currentRomOptions.screenUpdateSetting == SCREEN_UPDATE_AT_VI_UPDATE_AND_DRAWN )
223 {
224 if( status.bScreenIsDrawn )
225 {
226 CGraphicsContext::Get()->UpdateFrame();
227 DEBUGGER_IF_DUMP( pauseAtNext, TRACE1("Update Screen: VIORIG=%08X", *g_GraphicsInfo.VI_ORIGIN_REG));
228 }
229 else
230 {
231 DEBUGGER_IF_DUMP( pauseAtNext, TRACE1("Skip Screen Update: VIORIG=%08X", *g_GraphicsInfo.VI_ORIGIN_REG));
232 }
233
234 DEBUGGER_PAUSE_COUNT_N_WITHOUT_UPDATE(NEXT_FRAME);
235 DEBUGGER_PAUSE_COUNT_N_WITHOUT_UPDATE(NEXT_SET_CIMG);
236 g_CritialSection.Unlock();
237 return;
238 }
239
240 if( currentRomOptions.screenUpdateSetting==SCREEN_UPDATE_AT_VI_CHANGE )
241 {
242
243 if( *g_GraphicsInfo.VI_ORIGIN_REG != status.curVIOriginReg )
244 {
245 if( *g_GraphicsInfo.VI_ORIGIN_REG < status.curDisplayBuffer || *g_GraphicsInfo.VI_ORIGIN_REG > status.curDisplayBuffer+0x2000 )
246 {
247 status.curDisplayBuffer = *g_GraphicsInfo.VI_ORIGIN_REG;
248 status.curVIOriginReg = status.curDisplayBuffer;
249 //status.curRenderBuffer = NULL;
250
251 CGraphicsContext::Get()->UpdateFrame();
252 DEBUGGER_IF_DUMP( pauseAtNext, TRACE1("Update Screen: VIORIG=%08X", *g_GraphicsInfo.VI_ORIGIN_REG));
253 DEBUGGER_PAUSE_COUNT_N_WITHOUT_UPDATE(NEXT_FRAME);
254 DEBUGGER_PAUSE_COUNT_N_WITHOUT_UPDATE(NEXT_SET_CIMG);
255 }
256 else
257 {
258 status.curDisplayBuffer = *g_GraphicsInfo.VI_ORIGIN_REG;
259 status.curVIOriginReg = status.curDisplayBuffer;
260 DEBUGGER_PAUSE_AND_DUMP_NO_UPDATE(NEXT_FRAME, {DebuggerAppendMsg("Skip Screen Update, closed to the display buffer, VIORIG=%08X", *g_GraphicsInfo.VI_ORIGIN_REG);});
261 }
262 }
263 else
264 {
265 DEBUGGER_PAUSE_AND_DUMP_NO_UPDATE(NEXT_FRAME, {DebuggerAppendMsg("Skip Screen Update, the same VIORIG=%08X", *g_GraphicsInfo.VI_ORIGIN_REG);});
266 }
267
268 g_CritialSection.Unlock();
269 return;
270 }
271
272 if( currentRomOptions.screenUpdateSetting >= SCREEN_UPDATE_AT_1ST_CI_CHANGE )
273 {
274 status.bVIOriginIsUpdated=true;
275 DEBUGGER_PAUSE_AND_DUMP_NO_UPDATE(NEXT_FRAME, {DebuggerAppendMsg("VI ORIG is updated to %08X", *g_GraphicsInfo.VI_ORIGIN_REG);});
276 g_CritialSection.Unlock();
277 return;
278 }
279
280 DEBUGGER_IF_DUMP( pauseAtNext, TRACE1("VI is updated, No screen update: VIORIG=%08X", *g_GraphicsInfo.VI_ORIGIN_REG));
281 DEBUGGER_PAUSE_COUNT_N_WITHOUT_UPDATE(NEXT_FRAME);
282 DEBUGGER_PAUSE_COUNT_N_WITHOUT_UPDATE(NEXT_SET_CIMG);
283
284 g_CritialSection.Unlock();
285}
286
287static void ProcessDListStep2(void)
288{
289 g_CritialSection.Lock();
290 if( status.toShowCFB )
291 {
292 CRender::GetRender()->DrawFrameBuffer(true);
293 status.toShowCFB = false;
294 }
295
296 try
297 {
298 DLParser_Process((OSTask *)(g_GraphicsInfo.DMEM + 0x0FC0));
299 }
300 catch (...)
301 {
302 TRACE0("Unknown Error in ProcessDList");
303 TriggerDPInterrupt();
304 TriggerSPInterrupt();
305 }
306
307 g_CritialSection.Unlock();
308}
309
310static bool StartVideo(void)
311{
312 windowSetting.dps = windowSetting.fps = -1;
313 windowSetting.lastSecDlistCount = windowSetting.lastSecFrameCount = 0xFFFFFFFF;
314
315 g_CritialSection.Lock();
316
317 memcpy(&g_curRomInfo.romheader, g_GraphicsInfo.HEADER, sizeof(ROMHeader));
318 unsigned char *puc = (unsigned char *) &g_curRomInfo.romheader;
319 unsigned int i;
320 unsigned char temp;
321 for (i = 0; i < sizeof(ROMHeader); i += 4) /* byte-swap the ROM header */
322 {
323 temp = puc[i];
324 puc[i] = puc[i+3];
325 puc[i+3] = temp;
326 temp = puc[i+1];
327 puc[i+1] = puc[i+2];
328 puc[i+2] = temp;
329 }
330
331 ROM_GetRomNameFromHeader(g_curRomInfo.szGameName, &g_curRomInfo.romheader);
332 Ini_GetRomOptions(&g_curRomInfo);
333 char *p = (char *) g_curRomInfo.szGameName + (strlen((char *) g_curRomInfo.szGameName) -1); // -1 to skip null
334 while (p >= (char *) g_curRomInfo.szGameName)
335 {
336 if( *p == ':' || *p == '\\' || *p == '/' )
337 *p = '-';
338 p--;
339 }
340
341 GenerateCurrentRomOptions();
342 status.dwTvSystem = CountryCodeToTVSystem(g_curRomInfo.romheader.nCountryID);
ca22e7b7 343 if( status.dwTvSystem == TV_SYSTEM_NTSC ) {
292f9317 344 status.fRatio = 0.75f;
ca22e7b7 345 mspervi=1000.0f/60.0f; //for framskipping
346 } else {
347 status.fRatio = 9/11.0f;
348 mspervi=1000.0f/50.0f; //for framskipping
349 }
292f9317 350
351 InitExternalTextures();
352
353 try {
354 CDeviceBuilder::GetBuilder()->CreateGraphicsContext();
355 CGraphicsContext::InitWindowInfo();
356
357 bool res = CGraphicsContext::Get()->Initialize(640, 480, !windowSetting.bDisplayFullscreen);
358 if (!res)
359 {
360 g_CritialSection.Unlock();
361 return false;
362 }
363 CDeviceBuilder::GetBuilder()->CreateRender();
364 CRender::GetRender()->Initialize();
365 DLParser_Init();
366 status.bGameIsRunning = true;
367 }
368 catch(...)
369 {
370 DebugMessage(M64MSG_ERROR, "Exception caught while starting video renderer");
371 throw 0;
372 }
373
374 g_CritialSection.Unlock();
375 return true;
376}
377
378static void StopVideo()
379{
380 g_CritialSection.Lock();
381 status.bGameIsRunning = false;
382
383 try {
384 CloseExternalTextures();
385
386 // Kill all textures?
387 gTextureManager.RecycleAllTextures();
388 gTextureManager.CleanUp();
389 RDP_Cleanup();
390
391 CDeviceBuilder::GetBuilder()->DeleteRender();
392 CGraphicsContext::Get()->CleanUp();
393 CDeviceBuilder::GetBuilder()->DeleteGraphicsContext();
394 }
395 catch(...)
396 {
397 TRACE0("Some exceptions during RomClosed");
398 }
399
400 g_CritialSection.Unlock();
401 windowSetting.dps = windowSetting.fps = -1;
402 windowSetting.lastSecDlistCount = windowSetting.lastSecFrameCount = 0xFFFFFFFF;
403 status.gDlistCount = status.gFrameCount = 0;
404
405}
406
407//---------------------------------------------------------------------------------------
408// Global functions, for use by other source files in this plugin
409
410void SetVIScales()
411{
412 if( g_curRomInfo.VIHeight>0 && g_curRomInfo.VIWidth>0 )
413 {
414 windowSetting.fViWidth = windowSetting.uViWidth = g_curRomInfo.VIWidth;
415 windowSetting.fViHeight = windowSetting.uViHeight = g_curRomInfo.VIHeight;
416 }
417 else if( g_curRomInfo.UseCIWidthAndRatio && g_CI.dwWidth )
418 {
419 windowSetting.fViWidth = windowSetting.uViWidth = g_CI.dwWidth;
420 windowSetting.fViHeight = windowSetting.uViHeight =
421 g_curRomInfo.UseCIWidthAndRatio == USE_CI_WIDTH_AND_RATIO_FOR_NTSC ? g_CI.dwWidth/4*3 : g_CI.dwWidth/11*9;
422 }
423 else
424 {
425 float xscale, yscale;
426 uint32 val = *g_GraphicsInfo.VI_X_SCALE_REG & 0xFFF;
427 xscale = (float)val / (1<<10);
428 uint32 start = *g_GraphicsInfo.VI_H_START_REG >> 16;
429 uint32 end = *g_GraphicsInfo.VI_H_START_REG&0xFFFF;
430 uint32 width = *g_GraphicsInfo.VI_WIDTH_REG;
431 windowSetting.fViWidth = (end-start)*xscale;
432 if( abs((int)(windowSetting.fViWidth - width) ) < 8 )
433 {
434 windowSetting.fViWidth = (float)width;
435 }
436 else
437 {
438 DebuggerAppendMsg("fViWidth = %f, Width Reg=%d", windowSetting.fViWidth, width);
439 }
440
441 val = (*g_GraphicsInfo.VI_Y_SCALE_REG & 0xFFF);// - ((*g_GraphicsInfo.VI_Y_SCALE_REG>>16) & 0xFFF);
442 if( val == 0x3FF ) val = 0x400;
443 yscale = (float)val / (1<<10);
444 start = *g_GraphicsInfo.VI_V_START_REG >> 16;
445 end = *g_GraphicsInfo.VI_V_START_REG&0xFFFF;
446 windowSetting.fViHeight = (end-start)/2*yscale;
447
448 if( yscale == 0 )
449 {
450 windowSetting.fViHeight = windowSetting.fViWidth*status.fRatio;
451 }
452 else
453 {
454 if( *g_GraphicsInfo.VI_WIDTH_REG > 0x300 )
455 windowSetting.fViHeight *= 2;
456
457 if( windowSetting.fViWidth*status.fRatio > windowSetting.fViHeight && (*g_GraphicsInfo.VI_X_SCALE_REG & 0xFF) != 0 )
458 {
459 if( abs(int(windowSetting.fViWidth*status.fRatio - windowSetting.fViHeight)) < 8 )
460 {
461 windowSetting.fViHeight = windowSetting.fViWidth*status.fRatio;
462 }
463 /*
464 else
465 {
466 if( abs(windowSetting.fViWidth*status.fRatio-windowSetting.fViHeight) > windowSetting.fViWidth*0.1f )
467 {
468 if( status.fRatio > 0.8 )
469 windowSetting.fViHeight = windowSetting.fViWidth*3/4;
470 //windowSetting.fViHeight = (*g_GraphicsInfo.VI_V_SYNC_REG - 0x2C)/2;
471 }
472 }
473 */
474 }
475
476 if( windowSetting.fViHeight<100 || windowSetting.fViWidth<100 )
477 {
478 //At sometime, value in VI_H_START_REG or VI_V_START_REG are 0
479 windowSetting.fViWidth = (float)*g_GraphicsInfo.VI_WIDTH_REG;
480 windowSetting.fViHeight = windowSetting.fViWidth*status.fRatio;
481 }
482 }
483
484 windowSetting.uViWidth = (unsigned short)(windowSetting.fViWidth/4);
485 windowSetting.fViWidth = windowSetting.uViWidth *= 4;
486
487 windowSetting.uViHeight = (unsigned short)(windowSetting.fViHeight/4);
488 windowSetting.fViHeight = windowSetting.uViHeight *= 4;
489 uint16 optimizeHeight = (uint16)(windowSetting.uViWidth*status.fRatio);
490 optimizeHeight &= ~3;
491
492 uint16 optimizeHeight2 = (uint16)(windowSetting.uViWidth*3/4);
493 optimizeHeight2 &= ~3;
494
495 if( windowSetting.uViHeight != optimizeHeight && windowSetting.uViHeight != optimizeHeight2 )
496 {
497 if( abs(windowSetting.uViHeight-optimizeHeight) <= 8 )
498 windowSetting.fViHeight = windowSetting.uViHeight = optimizeHeight;
499 else if( abs(windowSetting.uViHeight-optimizeHeight2) <= 8 )
500 windowSetting.fViHeight = windowSetting.uViHeight = optimizeHeight2;
501 }
502
503
504 if( gRDP.scissor.left == 0 && gRDP.scissor.top == 0 && gRDP.scissor.right != 0 )
505 {
506 if( (*g_GraphicsInfo.VI_X_SCALE_REG & 0xFF) != 0x0 && gRDP.scissor.right == windowSetting.uViWidth )
507 {
508 // Mario Tennis
509 if( abs(int( windowSetting.fViHeight - gRDP.scissor.bottom )) < 8 )
510 {
511 windowSetting.fViHeight = windowSetting.uViHeight = gRDP.scissor.bottom;
512 }
513 else if( windowSetting.fViHeight < gRDP.scissor.bottom )
514 {
515 windowSetting.fViHeight = windowSetting.uViHeight = gRDP.scissor.bottom;
516 }
517 windowSetting.fViHeight = windowSetting.uViHeight = gRDP.scissor.bottom;
518 }
519 else if( gRDP.scissor.right == windowSetting.uViWidth - 1 && gRDP.scissor.bottom != 0 )
520 {
521 if( windowSetting.uViHeight != optimizeHeight && windowSetting.uViHeight != optimizeHeight2 )
522 {
523 if( status.fRatio != 0.75 && windowSetting.fViHeight > optimizeHeight/2 )
524 {
525 windowSetting.fViHeight = windowSetting.uViHeight = gRDP.scissor.bottom + gRDP.scissor.top + 1;
526 }
527 }
528 }
529 else if( gRDP.scissor.right == windowSetting.uViWidth && gRDP.scissor.bottom != 0 && status.fRatio != 0.75 )
530 {
531 if( windowSetting.uViHeight != optimizeHeight && windowSetting.uViHeight != optimizeHeight2 )
532 {
533 if( status.fRatio != 0.75 && windowSetting.fViHeight > optimizeHeight/2 )
534 {
535 windowSetting.fViHeight = windowSetting.uViHeight = gRDP.scissor.bottom + gRDP.scissor.top + 1;
536 }
537 }
538 }
539 }
540 }
541 SetScreenMult(windowSetting.uDisplayWidth/windowSetting.fViWidth, windowSetting.uDisplayHeight/windowSetting.fViHeight);
542}
543
544void TriggerDPInterrupt(void)
545{
546 *(g_GraphicsInfo.MI_INTR_REG) |= MI_INTR_DP;
547 g_GraphicsInfo.CheckInterrupts();
548}
549
550void TriggerSPInterrupt(void)
551{
552 *(g_GraphicsInfo.MI_INTR_REG) |= MI_INTR_SP;
553 g_GraphicsInfo.CheckInterrupts();
554}
555
556void _VIDEO_DisplayTemporaryMessage(const char *Message)
557{
558}
559
560void DebugMessage(int level, const char *message, ...)
561{
562 char msgbuf[1024];
563 va_list args;
564
565 if (l_DebugCallback == NULL)
566 return;
567
568 va_start(args, message);
569 vsprintf(msgbuf, message, args);
570
571 (*l_DebugCallback)(l_DebugCallContext, level, msgbuf);
572
573 va_end(args);
574}
575
576//---------------------------------------------------------------------------------------
577// Global functions, exported for use by the core library
578
579// since these functions are exported, they need to have C-style names
580#ifdef __cplusplus
581extern "C" {
582#endif
583
584/* Mupen64Plus plugin functions */
585EXPORT m64p_error CALL PluginStartup(m64p_dynlib_handle CoreLibHandle, void *Context,
586 void (*DebugCallback)(void *, int, const char *))
587{
588 if (l_PluginInit)
589 return M64ERR_ALREADY_INIT;
590
591 /* first thing is to set the callback function for debug info */
592 l_DebugCallback = DebugCallback;
593 l_DebugCallContext = Context;
594
595 /* attach and call the CoreGetAPIVersions function, check Config and Video Extension API versions for compatibility */
596 ptr_CoreGetAPIVersions CoreAPIVersionFunc;
597 CoreAPIVersionFunc = (ptr_CoreGetAPIVersions) osal_dynlib_getproc(CoreLibHandle, "CoreGetAPIVersions");
598 if (CoreAPIVersionFunc == NULL)
599 {
600 DebugMessage(M64MSG_ERROR, "Core emulator broken; no CoreAPIVersionFunc() function found.");
601 return M64ERR_INCOMPATIBLE;
602 }
603 int ConfigAPIVersion, DebugAPIVersion, VidextAPIVersion;
604 (*CoreAPIVersionFunc)(&ConfigAPIVersion, &DebugAPIVersion, &VidextAPIVersion, NULL);
605 if ((ConfigAPIVersion & 0xffff0000) != (CONFIG_API_VERSION & 0xffff0000))
606 {
607 DebugMessage(M64MSG_ERROR, "Emulator core Config API (v%i.%i.%i) incompatible with plugin (v%i.%i.%i)",
608 VERSION_PRINTF_SPLIT(ConfigAPIVersion), VERSION_PRINTF_SPLIT(CONFIG_API_VERSION));
609 return M64ERR_INCOMPATIBLE;
610 }
611 if ((VidextAPIVersion & 0xffff0000) != (VIDEXT_API_VERSION & 0xffff0000))
612 {
613 DebugMessage(M64MSG_ERROR, "Emulator core Video Extension API (v%i.%i.%i) incompatible with plugin (v%i.%i.%i)",
614 VERSION_PRINTF_SPLIT(VidextAPIVersion), VERSION_PRINTF_SPLIT(VIDEXT_API_VERSION));
615 return M64ERR_INCOMPATIBLE;
616 }
617
618 /* Get the core config function pointers from the library handle */
619 ConfigOpenSection = (ptr_ConfigOpenSection) osal_dynlib_getproc(CoreLibHandle, "ConfigOpenSection");
620 ConfigSetParameter = (ptr_ConfigSetParameter) osal_dynlib_getproc(CoreLibHandle, "ConfigSetParameter");
621 ConfigGetParameter = (ptr_ConfigGetParameter) osal_dynlib_getproc(CoreLibHandle, "ConfigGetParameter");
622 ConfigSetDefaultInt = (ptr_ConfigSetDefaultInt) osal_dynlib_getproc(CoreLibHandle, "ConfigSetDefaultInt");
623 ConfigSetDefaultFloat = (ptr_ConfigSetDefaultFloat) osal_dynlib_getproc(CoreLibHandle, "ConfigSetDefaultFloat");
624 ConfigSetDefaultBool = (ptr_ConfigSetDefaultBool) osal_dynlib_getproc(CoreLibHandle, "ConfigSetDefaultBool");
625 ConfigSetDefaultString = (ptr_ConfigSetDefaultString) osal_dynlib_getproc(CoreLibHandle, "ConfigSetDefaultString");
626 ConfigGetParamInt = (ptr_ConfigGetParamInt) osal_dynlib_getproc(CoreLibHandle, "ConfigGetParamInt");
627 ConfigGetParamFloat = (ptr_ConfigGetParamFloat) osal_dynlib_getproc(CoreLibHandle, "ConfigGetParamFloat");
628 ConfigGetParamBool = (ptr_ConfigGetParamBool) osal_dynlib_getproc(CoreLibHandle, "ConfigGetParamBool");
629 ConfigGetParamString = (ptr_ConfigGetParamString) osal_dynlib_getproc(CoreLibHandle, "ConfigGetParamString");
630
631 ConfigGetSharedDataFilepath = (ptr_ConfigGetSharedDataFilepath) osal_dynlib_getproc(CoreLibHandle, "ConfigGetSharedDataFilepath");
632 ConfigGetUserConfigPath = (ptr_ConfigGetUserConfigPath) osal_dynlib_getproc(CoreLibHandle, "ConfigGetUserConfigPath");
633 ConfigGetUserDataPath = (ptr_ConfigGetUserDataPath) osal_dynlib_getproc(CoreLibHandle, "ConfigGetUserDataPath");
634 ConfigGetUserCachePath = (ptr_ConfigGetUserCachePath) osal_dynlib_getproc(CoreLibHandle, "ConfigGetUserCachePath");
635
636 if (!ConfigOpenSection || !ConfigSetParameter || !ConfigGetParameter ||
637 !ConfigSetDefaultInt || !ConfigSetDefaultFloat || !ConfigSetDefaultBool || !ConfigSetDefaultString ||
638 !ConfigGetParamInt || !ConfigGetParamFloat || !ConfigGetParamBool || !ConfigGetParamString ||
639 !ConfigGetSharedDataFilepath || !ConfigGetUserConfigPath || !ConfigGetUserDataPath || !ConfigGetUserCachePath)
640 {
641 DebugMessage(M64MSG_ERROR, "Couldn't connect to Core configuration functions");
642 return M64ERR_INCOMPATIBLE;
643 }
644
645 /* Get the core Video Extension function pointers from the library handle */
646 CoreVideo_Init = (ptr_VidExt_Init) osal_dynlib_getproc(CoreLibHandle, "VidExt_Init");
647 CoreVideo_Quit = (ptr_VidExt_Quit) osal_dynlib_getproc(CoreLibHandle, "VidExt_Quit");
648 CoreVideo_ListFullscreenModes = (ptr_VidExt_ListFullscreenModes) osal_dynlib_getproc(CoreLibHandle, "VidExt_ListFullscreenModes");
649 CoreVideo_SetVideoMode = (ptr_VidExt_SetVideoMode) osal_dynlib_getproc(CoreLibHandle, "VidExt_SetVideoMode");
650 CoreVideo_SetCaption = (ptr_VidExt_SetCaption) osal_dynlib_getproc(CoreLibHandle, "VidExt_SetCaption");
651 CoreVideo_ToggleFullScreen = (ptr_VidExt_ToggleFullScreen) osal_dynlib_getproc(CoreLibHandle, "VidExt_ToggleFullScreen");
652 CoreVideo_ResizeWindow = (ptr_VidExt_ResizeWindow) osal_dynlib_getproc(CoreLibHandle, "VidExt_ResizeWindow");
653 CoreVideo_GL_GetProcAddress = (ptr_VidExt_GL_GetProcAddress) osal_dynlib_getproc(CoreLibHandle, "VidExt_GL_GetProcAddress");
654 CoreVideo_GL_SetAttribute = (ptr_VidExt_GL_SetAttribute) osal_dynlib_getproc(CoreLibHandle, "VidExt_GL_SetAttribute");
655 CoreVideo_GL_GetAttribute = (ptr_VidExt_GL_GetAttribute) osal_dynlib_getproc(CoreLibHandle, "VidExt_GL_GetAttribute");
656 CoreVideo_GL_SwapBuffers = (ptr_VidExt_GL_SwapBuffers) osal_dynlib_getproc(CoreLibHandle, "VidExt_GL_SwapBuffers");
657
658 if (!CoreVideo_Init || !CoreVideo_Quit || !CoreVideo_ListFullscreenModes || !CoreVideo_SetVideoMode ||
659 !CoreVideo_ResizeWindow || !CoreVideo_SetCaption || !CoreVideo_ToggleFullScreen || !CoreVideo_GL_GetProcAddress ||
660 !CoreVideo_GL_SetAttribute || !CoreVideo_GL_GetAttribute || !CoreVideo_GL_SwapBuffers)
661 {
662 DebugMessage(M64MSG_ERROR, "Couldn't connect to Core video extension functions");
663 return M64ERR_INCOMPATIBLE;
664 }
665
666 /* open config section handles and set parameter default values */
667 if (!InitConfiguration())
668 return M64ERR_INTERNAL;
669
670 l_PluginInit = 1;
671 return M64ERR_SUCCESS;
672}
673
674EXPORT m64p_error CALL PluginShutdown(void)
675{
676 if (!l_PluginInit)
677 return M64ERR_NOT_INIT;
678
679 if( status.bGameIsRunning )
680 {
681 RomClosed();
682 }
683 if (bIniIsChanged)
684 {
685 WriteIniFile();
686 TRACE0("Write back INI file");
687 }
688
689 /* reset some local variables */
690 l_DebugCallback = NULL;
691 l_DebugCallContext = NULL;
692
693 l_PluginInit = 0;
694 return M64ERR_SUCCESS;
695}
696
697EXPORT m64p_error CALL PluginGetVersion(m64p_plugin_type *PluginType, int *PluginVersion, int *APIVersion, const char **PluginNamePtr, int *Capabilities)
698{
699 /* set version info */
700 if (PluginType != NULL)
701 *PluginType = M64PLUGIN_GFX;
702
703 if (PluginVersion != NULL)
704 *PluginVersion = PLUGIN_VERSION;
705
706 if (APIVersion != NULL)
707 *APIVersion = VIDEO_PLUGIN_API_VERSION;
708
709 if (PluginNamePtr != NULL)
710 *PluginNamePtr = PLUGIN_NAME;
711
712 if (Capabilities != NULL)
713 {
714 *Capabilities = 0;
715 }
716
717 return M64ERR_SUCCESS;
718}
719
720//-------------------------------------------------------------------------------------
721
722
723EXPORT void CALL ChangeWindow (void)
724{
725 if( status.ToToggleFullScreen )
726 status.ToToggleFullScreen = FALSE;
727 else
728 status.ToToggleFullScreen = TRUE;
729}
730
731//---------------------------------------------------------------------------------------
732
733EXPORT void CALL MoveScreen (int xpos, int ypos)
734{
735}
736
737//---------------------------------------------------------------------------------------
738EXPORT void CALL RomClosed(void)
739{
740 TRACE0("To stop video");
741 Ini_StoreRomOptions(&g_curRomInfo);
742 StopVideo();
743 TRACE0("Video is stopped");
744}
745
746EXPORT int CALL RomOpen(void)
747{
748 /* Read RiceVideoLinux.ini file, set up internal variables by reading values from core configuration API */
749 LoadConfiguration();
750
751 if( g_CritialSection.IsLocked() )
752 {
753 g_CritialSection.Unlock();
754 TRACE0("g_CritialSection is locked when game is starting, unlock it now.");
755 }
756 status.bDisableFPS=false;
757
758 g_dwRamSize = 0x800000;
759
760#ifdef DEBUGGER
761 if( debuggerPause )
762 {
763 debuggerPause = FALSE;
764 usleep(100 * 1000);
765 }
766#endif
767
768 if (!StartVideo())
769 return 0;
770
771 return 1;
772}
773
774
775//---------------------------------------------------------------------------------------
776EXPORT void CALL UpdateScreen(void)
777{
778 if(options.bShowFPS)
779 {
780 static unsigned int lastTick=0;
781 static int frames=0;
782 unsigned int nowTick = SDL_GetTicks();
783 frames++;
784 if(lastTick + 5000 <= nowTick)
785 {
786 char caption[200];
787 sprintf(caption, "%s v%i.%i.%i - %.3f VI/S", PLUGIN_NAME, VERSION_PRINTF_SPLIT(PLUGIN_VERSION), frames/5.0);
788 CoreVideo_SetCaption(caption);
789 frames = 0;
790 lastTick = nowTick;
791 }
792 }
793 UpdateScreenStep2();
794}
795
796//---------------------------------------------------------------------------------------
797
798EXPORT void CALL ViStatusChanged(void)
799{
800 g_CritialSection.Lock();
801 SetVIScales();
802 CRender::g_pRender->UpdateClipRectangle();
803 g_CritialSection.Unlock();
804}
805
806//---------------------------------------------------------------------------------------
807EXPORT void CALL ViWidthChanged(void)
808{
809 g_CritialSection.Lock();
810 SetVIScales();
811 CRender::g_pRender->UpdateClipRectangle();
812 g_CritialSection.Unlock();
813}
814
815EXPORT int CALL InitiateGFX(GFX_INFO Gfx_Info)
816{
817 memset(&status, 0, sizeof(status));
818 memcpy(&g_GraphicsInfo, &Gfx_Info, sizeof(GFX_INFO));
819
820 g_pRDRAMu8 = Gfx_Info.RDRAM;
821 g_pRDRAMu32 = (uint32*)Gfx_Info.RDRAM;
822 g_pRDRAMs8 = (signed char *)Gfx_Info.RDRAM;
823
824 windowSetting.fViWidth = 320;
825 windowSetting.fViHeight = 240;
826 status.ToToggleFullScreen = FALSE;
827 status.ToResize = false;
828 status.bDisableFPS=false;
829
830 if (!InitConfiguration())
831 {
832 DebugMessage(M64MSG_ERROR, "Failed to read configuration data");
833 return FALSE;
834 }
835
836 CGraphicsContext::InitWindowInfo();
837 CGraphicsContext::InitDeviceParameters();
838
839 return(TRUE);
840}
841
842EXPORT void CALL ResizeVideoOutput(int width, int height)
843{
844 // save the new window resolution. actual resizing operation is asynchronous (it happens later)
845 status.gNewResizeWidth = width;
846 status.gNewResizeHeight = height;
847 status.ToResize = true;
848}
849
850//---------------------------------------------------------------------------------------
851
852EXPORT void CALL ProcessRDPList(void)
853{
854 try
855 {
856 RDP_DLParser_Process();
857 }
858 catch (...)
859 {
860 TRACE0("Unknown Error in ProcessRDPList");
861 TriggerDPInterrupt();
862 TriggerSPInterrupt();
863 }
864}
865
866EXPORT void CALL ProcessDList(void)
867{
868 ProcessDListStep2();
869}
870
871//---------------------------------------------------------------------------------------
872
873/******************************************************************
874 Function: FrameBufferRead
875 Purpose: This function is called to notify the dll that the
876 frame buffer memory is beening read at the given address.
877 DLL should copy content from its render buffer to the frame buffer
878 in N64 RDRAM
879 DLL is responsible to maintain its own frame buffer memory addr list
880 DLL should copy 4KB block content back to RDRAM frame buffer.
881 Emulator should not call this function again if other memory
882 is read within the same 4KB range
883
884 Since depth buffer is also being watched, the reported addr
885 may belong to depth buffer
886 input: addr rdram address
887 val val
888 size 1 = uint8, 2 = uint16, 4 = uint32
889 output: none
890*******************************************************************/
891
892EXPORT void CALL FBRead(uint32 addr)
893{
894 g_pFrameBufferManager->FrameBufferReadByCPU(addr);
895}
896
897
898/******************************************************************
899 Function: FrameBufferWrite
900 Purpose: This function is called to notify the dll that the
901 frame buffer has been modified by CPU at the given address.
902
903 Since depth buffer is also being watched, the reported addr
904 may belong to depth buffer
905
906 input: addr rdram address
907 val val
908 size 1 = uint8, 2 = uint16, 4 = uint32
909 output: none
910*******************************************************************/
911
912EXPORT void CALL FBWrite(uint32 addr, uint32 size)
913{
914 g_pFrameBufferManager->FrameBufferWriteByCPU(addr, size);
915}
916
917/************************************************************************
918Function: FBGetFrameBufferInfo
919Purpose: This function is called by the emulator core to retrieve frame
920 buffer information from the video plugin in order to be able
921 to notify the video plugin about CPU frame buffer read/write
922 operations
923
924 size:
925 = 1 byte
926 = 2 word (16 bit) <-- this is N64 default depth buffer format
927 = 4 dword (32 bit)
928
929 when frame buffer information is not available yet, set all values
930 in the FrameBufferInfo structure to 0
931
932input: FrameBufferInfo pinfo[6]
933 pinfo is pointed to a FrameBufferInfo structure which to be
934 filled in by this function
935output: Values are return in the FrameBufferInfo structure
936 Plugin can return up to 6 frame buffer info
937 ************************************************************************/
938
939EXPORT void CALL FBGetFrameBufferInfo(void *p)
940{
941 FrameBufferInfo * pinfo = (FrameBufferInfo *)p;
942 memset(pinfo,0,sizeof(FrameBufferInfo)*6);
943
944 //if( g_ZI.dwAddr == 0 )
945 //{
946 // memset(pinfo,0,sizeof(FrameBufferInfo)*6);
947 //}
948 //else
949 {
950 for (int i=0; i<5; i++ )
951 {
952 if( status.gDlistCount-g_RecentCIInfo[i].lastUsedFrame > 30 || g_RecentCIInfo[i].lastUsedFrame == 0 )
953 {
954 //memset(&pinfo[i],0,sizeof(FrameBufferInfo));
955 }
956 else
957 {
958 pinfo[i].addr = g_RecentCIInfo[i].dwAddr;
959 pinfo[i].size = 2;
960 pinfo[i].width = g_RecentCIInfo[i].dwWidth;
961 pinfo[i].height = g_RecentCIInfo[i].dwHeight;
962 TXTRBUF_DETAIL_DUMP(TRACE3("Protect 0x%08X (%d,%d)", g_RecentCIInfo[i].dwAddr, g_RecentCIInfo[i].dwWidth, g_RecentCIInfo[i].dwHeight));
963 pinfo[5].width = g_RecentCIInfo[i].dwWidth;
964 pinfo[5].height = g_RecentCIInfo[i].dwHeight;
965 }
966 }
967
968 pinfo[5].addr = g_ZI.dwAddr;
969 //pinfo->size = g_RecentCIInfo[5].dwSize;
970 pinfo[5].size = 2;
971 TXTRBUF_DETAIL_DUMP(TRACE3("Protect 0x%08X (%d,%d)", pinfo[5].addr, pinfo[5].width, pinfo[5].height));
972 }
973}
974
975// Plugin spec 1.3 functions
976EXPORT void CALL ShowCFB(void)
977{
978 status.toShowCFB = true;
979}
980
981//void ReadScreen2( void *dest, int *width, int *height, int bFront )
982EXPORT void CALL ReadScreen2(void *dest, int *width, int *height, int bFront)
983{
984 if (width == NULL || height == NULL)
985 return;
986
987 *width = windowSetting.uDisplayWidth;
988 *height = windowSetting.uDisplayHeight;
989
990 if (dest == NULL)
991 return;
992
993#if SDL_VIDEO_OPENGL
994 GLint oldMode;
995 glGetIntegerv( GL_READ_BUFFER, &oldMode );
996 if (bFront)
997 glReadBuffer( GL_FRONT );
998 else
999 glReadBuffer( GL_BACK );
1000 glReadPixels( 0, 0, windowSetting.uDisplayWidth, windowSetting.uDisplayHeight,
1001 GL_RGB, GL_UNSIGNED_BYTE, dest );
1002 glReadBuffer( oldMode );
1003#endif
1004}
1005
1006
1007EXPORT void CALL SetRenderingCallback(void (*callback)(int))
1008{
1009 renderCallback = callback;
1010}
1011
1012#ifdef __cplusplus
1013}
1014#endif
1015