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