--- previous/src/dimension/nd_sdl.c 2018/04/24 19:30:01 1.1 +++ previous/src/dimension/nd_sdl.c 2018/04/24 19:31:37 1.1.1.2 @@ -3,49 +3,49 @@ #include "configuration.h" #include "dimension.h" #include "screen.h" +#include "host.h" +#include "cycInt.h" /* Because of SDL time (in)accuracy, timing is very approximative */ const int DISPLAY_VBL_MS = 1000 / 68; // main display at 68Hz, actually this is 71.42 Hz because (int)1000/(int)68Hz=14ms const int VIDEO_VBL_MS = 1000 / 60; // NTSC display at 60Hz, actually this is 62.5 Hz because (int)1000/(int)60Hz=16ms const int BLANK_MS = 2; // Give some blank time for both -extern Uint32 nd_display_blank_start(); -extern Uint32 nd_display_blank_end(); -extern Uint32 nd_video_vbl(Uint32 interval, void* param); - -static SDL_TimerID videoVBL = NULL; static volatile bool doRepaint = true; static SDL_Thread* repaintThread = NULL; static SDL_Window* ndWindow = NULL; +static SDL_Renderer* ndRenderer = NULL; + +SDL_atomic_t blitNDFB; -extern void blitDimension(SDL_Texture* tex); +void blitDimension(SDL_Texture* tex); static int repainter(void* unused) { + SDL_SetThreadPriority(SDL_THREAD_PRIORITY_NORMAL); + SDL_Texture* ndTexture = NULL; - SDL_Renderer* ndRenderer = NULL; + + SDL_Rect r = {0,0,1120,832}; ndRenderer = SDL_CreateRenderer(ndWindow, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); - if (!ndWindow || !ndRenderer) { + + if (!ndRenderer) { fprintf(stderr,"[ND] Failed to create renderer!\n"); exit(-1); } - SDL_Rect r = {0,0,1120,832}; + SDL_RenderSetLogicalSize(ndRenderer, r.w, r.h); ndTexture = SDL_CreateTexture(ndRenderer, SDL_PIXELFORMAT_UNKNOWN, SDL_TEXTUREACCESS_STREAMING, r.w, r.h); + SDL_AtomicSet(&blitNDFB, 1); + while(doRepaint) { - if(ConfigureParams.Screen.nMonitorType == MONITOR_TYPE_DUAL) { + if (SDL_AtomicGet(&blitNDFB)) { blitDimension(ndTexture); SDL_RenderCopy(ndRenderer, ndTexture, NULL, NULL); SDL_RenderPresent(ndRenderer); } else { - SDL_Delay(VIDEO_VBL_MS - BLANK_MS); - } - // if this is a cube, then do ND blank emulation. - if(ConfigureParams.System.nMachineType == NEXT_CUBE030 || ConfigureParams.System.nMachineType == NEXT_CUBE040) { - nd_display_blank_start(); - SDL_Delay(BLANK_MS); - nd_display_blank_end(); + host_sleep_ms(100); } } @@ -56,17 +56,38 @@ static int repainter(void* unused) { return 0; } +static bool ndVBLtoggle; +void nd_vbl_handler() { + CycInt_AcknowledgeInterrupt(); + + host_blank(ND_SLOT, ND_DISPLAY, ndVBLtoggle); + ndVBLtoggle = !ndVBLtoggle; + + CycInt_AddRelativeInterruptUs((1000*1000)/136, 0, INTERRUPT_ND_VBL); // 136Hz with toggle gives 68Hz, blank time is 1/2 frame time +} + +bool ndVideoVBLtoggle; +void nd_video_vbl_handler() { + CycInt_AcknowledgeInterrupt(); + + host_blank(ND_SLOT, ND_VIDEO, ndVideoVBLtoggle); + ndVideoVBLtoggle = !ndVideoVBLtoggle; + + CycInt_AddRelativeInterruptUs((1000*1000)/120, 0, INTERRUPT_ND_VIDEO_VBL); // 120Hz with toggle gives 60Hz NTSC, blank time is 1/2 frame time +} + void nd_sdl_init() { if(!(repaintThread)) { int x, y, w, h; SDL_GetWindowPosition(sdlWindow, &x, &y); SDL_GetWindowSize(sdlWindow, &w, &h); - ndWindow = SDL_CreateWindow("NeXT Dimension",(x-w)+1, y, 1120, 832, SDL_WINDOW_HIDDEN); - repaintThread = SDL_CreateThread(repainter, "[ND] repainter", NULL); + ndWindow = SDL_CreateWindow("NeXTdimension",(x-w)+1, y, 1120, 832, SDL_WINDOW_HIDDEN); + + if (!ndWindow) { + fprintf(stderr,"[ND] Failed to create window!\n"); + exit(-1); + } } - if(videoVBL) SDL_RemoveTimer(videoVBL); - // NTSC video at 60Hz - videoVBL = SDL_AddTimer(VIDEO_VBL_MS, nd_video_vbl, NULL); if(ConfigureParams.Screen.nMonitorType == MONITOR_TYPE_DUAL) { SDL_ShowWindow(ndWindow); @@ -75,14 +96,29 @@ void nd_sdl_init() { } } -void nd_sdl_uninit() { - if(videoVBL) { - SDL_RemoveTimer(videoVBL); - videoVBL = NULL; +void nd_start_interrupts() { + if(!(repaintThread) && ConfigureParams.Screen.nMonitorType == MONITOR_TYPE_DUAL) + repaintThread = SDL_CreateThread(repainter, "[ND] repainter", NULL); + + // if this is a cube and we have an ND configured, install ND VBL handlers + if (ConfigureParams.Dimension.bEnabled && (ConfigureParams.System.nMachineType == NEXT_CUBE030 || ConfigureParams.System.nMachineType == NEXT_CUBE040)) { + CycInt_AddRelativeInterruptUs(1000, 0, INTERRUPT_ND_VBL); + CycInt_AddRelativeInterruptUs(1000, 0, INTERRUPT_ND_VIDEO_VBL); } +} + +void nd_sdl_uninit() { SDL_HideWindow(ndWindow); } +void nd_sdl_pause(bool pause) { + if (pause) { + SDL_AtomicSet(&blitNDFB, 0); + } else { + SDL_AtomicSet(&blitNDFB, 1); + } +} + void nd_sdl_destroy() { doRepaint = false; // stop repaint thread int s; @@ -90,39 +126,3 @@ void nd_sdl_destroy() { nd_sdl_uninit(); } -//----- SDL abstractions for ND implementation - -void lock(lock_t* lock) { - SDL_AtomicLock(lock); -} - -int trylock(lock_t* lock) { - return SDL_AtomicTryLock(lock); -} - -void unlock(lock_t* lock) { - SDL_AtomicUnlock(lock); -} - -void checklock(lock_t* lock) { - SDL_AtomicLock(lock); - SDL_AtomicUnlock(lock); -} - -Uint32 time_ms() { - return SDL_GetTicks(); -} - -void sleep_ms(Uint32 ms) { - SDL_Delay(ms); -} - -thread_t* thread_create(thread_func_t func, void* data) { - return SDL_CreateThread(func, "[ND] Thread", data); -} - -int thread_wait(thread_t* thread) { - int status; - SDL_WaitThread(thread, &status); - return status; -} \ No newline at end of file