1 #pragma once 2 #include "stdafx.h" 3 #include "../Core/IRenderingDevice.h" 4 #include "../Core/VideoRenderer.h" 5 #include "../Core/EmulationSettings.h" 6 #include "../Core/Console.h" 7 #include "../Utilities/nes_ntsc.h" 8 #include "libretro.h" 9 10 class LibretroRenderer : public IRenderingDevice 11 { 12 private: 13 shared_ptr<Console> _console; 14 retro_video_refresh_t _sendFrame = nullptr; 15 retro_environment_t _retroEnv = nullptr; 16 bool _skipMode = false; 17 int32_t _previousHeight = -1; 18 int32_t _previousWidth = -1; 19 20 public: LibretroRenderer(shared_ptr<Console> console,retro_environment_t retroEnv)21 LibretroRenderer(shared_ptr<Console> console, retro_environment_t retroEnv) 22 { 23 _console = console; 24 _retroEnv = retroEnv; 25 _console->GetVideoRenderer()->RegisterRenderingDevice(this); 26 } 27 ~LibretroRenderer()28 ~LibretroRenderer() 29 { 30 _console->GetVideoRenderer()->UnregisterRenderingDevice(this); 31 } 32 33 // Inherited via IRenderingDevice UpdateFrame(void * frameBuffer,uint32_t width,uint32_t height)34 virtual void UpdateFrame(void *frameBuffer, uint32_t width, uint32_t height) override 35 { 36 if(!_skipMode && _sendFrame) { 37 //Use Blargg's NTSC filter's max size as a minimum resolution, to prevent changing resolution too often 38 int32_t newWidth = std::max<int32_t>(width, NES_NTSC_OUT_WIDTH(256)); 39 int32_t newHeight = std::max<int32_t>(height, 240); 40 if(_retroEnv != nullptr && (_previousWidth != newWidth || _previousHeight != newHeight)) { 41 //Resolution change is needed 42 retro_system_av_info avInfo = {}; 43 GetSystemAudioVideoInfo(avInfo, newWidth, newHeight); 44 _retroEnv(RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO, &avInfo); 45 46 _previousWidth = newWidth; 47 _previousHeight = newHeight; 48 } 49 50 _sendFrame(frameBuffer, width, height, sizeof(uint32_t) * width); 51 } 52 } 53 54 void GetSystemAudioVideoInfo(retro_system_av_info &info, int32_t maxWidth = 0, int32_t maxHeight = 0) 55 { 56 info.timing.fps = _console->GetModel() == NesModel::NTSC ? 60.098811862348404716732985230828 : 50.006977968268290848936010226333; 57 info.timing.sample_rate = _console->GetSettings()->GetSampleRate(); 58 59 float ratio = (float)_console->GetSettings()->GetAspectRatio(_console); 60 if(ratio == 0.0f) { 61 ratio = (float)256 / 240; 62 } 63 ratio *= (float)_console->GetSettings()->GetOverscanDimensions().GetScreenWidth() / _console->GetSettings()->GetOverscanDimensions().GetScreenHeight() / 256 * 240; 64 65 if(_console->GetSettings()->GetScreenRotation() % 180) { 66 info.geometry.aspect_ratio = ratio == 0.0f ? 0.0f : 1.0f / ratio; 67 } else { 68 info.geometry.aspect_ratio = ratio; 69 } 70 71 info.geometry.base_width = _console->GetSettings()->GetOverscanDimensions().GetScreenWidth(); 72 info.geometry.base_height = _console->GetSettings()->GetOverscanDimensions().GetScreenHeight(); 73 74 info.geometry.max_width = maxWidth; 75 info.geometry.max_height = maxHeight; 76 77 if(maxHeight > 0 && maxWidth > 0) { 78 _previousWidth = maxWidth; 79 _previousHeight = maxHeight; 80 } 81 } 82 SetVideoCallback(retro_video_refresh_t sendFrame)83 void SetVideoCallback(retro_video_refresh_t sendFrame) 84 { 85 _sendFrame = sendFrame; 86 } 87 SetSkipMode(bool skip)88 void SetSkipMode(bool skip) 89 { 90 _skipMode = skip; 91 } 92 Render()93 virtual void Render() override 94 { 95 } 96 Reset()97 virtual void Reset() override 98 { 99 } 100 SetFullscreenMode(bool fullscreen,void * windowHandle,uint32_t monitorWidth,uint32_t monitorHeight)101 virtual void SetFullscreenMode(bool fullscreen, void *windowHandle, uint32_t monitorWidth, uint32_t monitorHeight) override 102 { 103 } 104 };