bool LoadWork(ref LibRetro.retro_game_info gi)
        {
            //defer this until loading because during the LibRetroEmulator constructor, we dont have access to the game name and so paths can't be selected
            //this cannot be done until set_environment is complete
            if (CoreComm.CoreFileProvider == null)
            {
                SaveDirectory = SystemDirectory = "";
            }
            else
            {
                SystemDirectory     = CoreComm.CoreFileProvider.GetRetroSystemPath();
                SaveDirectory       = CoreComm.CoreFileProvider.GetRetroSaveRAMDirectory();
                SystemDirectoryAtom = unmanagedResources.StringToHGlobalAnsi(SystemDirectory);
                SaveDirectoryAtom   = unmanagedResources.StringToHGlobalAnsi(SaveDirectory);
            }

            //defer this until loading because it triggers the core to read save and system paths
            //if any cores did that from set_environment then i'm assured we can call set_environment again here before retro_init and it should work
            //--alcaro says any cores that can't handle that should be considered a bug
            //UPDATE: dosbox does that, so lets try it
            retro.retro_set_environment(retro_environment_cb);
            retro.retro_init();

            if (!retro.retro_load_game(ref gi))
            {
                Console.WriteLine("retro_load_game() failed");
                return(false);
            }

            //TODO - libretro cores can return a varying serialize size over time. I tried to get them to write it in the docs...
            savebuff  = new byte[retro.retro_serialize_size()];
            savebuff2 = new byte[savebuff.Length + 13];

            LibRetro.retro_system_av_info av = new LibRetro.retro_system_av_info();
            retro.retro_get_system_av_info(ref av);

            BufferWidth  = (int)av.geometry.base_width;
            BufferHeight = (int)av.geometry.base_height;
            vidbuff      = new int[av.geometry.max_width * av.geometry.max_height];
            dar          = av.geometry.aspect_ratio;

            // TODO: more precise
            CoreComm.VsyncNum = (int)(10000000 * av.timing.fps);
            CoreComm.VsyncDen = 10000000;

            SetupResampler(av.timing.fps, av.timing.sample_rate);
            (ServiceProvider as BasicServiceProvider).Register <ISoundProvider>(resampler);

            ControllerDefinition = CreateControllerDefinition(_SyncSettings);

            return(true);
        }
        public LibRetroEmulator(CoreComm nextComm, string modulename)
        {
            ServiceProvider = new BasicServiceProvider(this);

            retro_environment_cb        = new LibRetro.retro_environment_t(retro_environment);
            retro_video_refresh_cb      = new LibRetro.retro_video_refresh_t(retro_video_refresh);
            retro_audio_sample_cb       = new LibRetro.retro_audio_sample_t(retro_audio_sample);
            retro_audio_sample_batch_cb = new LibRetro.retro_audio_sample_batch_t(retro_audio_sample_batch);
            retro_input_poll_cb         = new LibRetro.retro_input_poll_t(retro_input_poll);
            retro_input_state_cb        = new LibRetro.retro_input_state_t(retro_input_state);

            retro = new LibRetro(modulename);
            try
            {
                CoreComm = nextComm;

                LibRetro.retro_system_info sys = new LibRetro.retro_system_info();
                retro.retro_get_system_info(ref sys);

                if (sys.need_fullpath)
                {
                    throw new ArgumentException("This libretro core needs filepaths");
                }
                if (sys.block_extract)
                {
                    throw new ArgumentException("This libretro needs non-blocked extract");
                }

                retro.retro_set_environment(retro_environment_cb);
                retro.retro_init();
                retro.retro_set_video_refresh(retro_video_refresh_cb);
                retro.retro_set_audio_sample(retro_audio_sample_cb);
                retro.retro_set_audio_sample_batch(retro_audio_sample_batch_cb);
                retro.retro_set_input_poll(retro_input_poll_cb);
                retro.retro_set_input_state(retro_input_state_cb);
            }
            catch
            {
                retro.Dispose();
                throw;
            }
        }
        public LibRetroEmulator(CoreComm nextComm, string modulename)
        {
            ServiceProvider = new BasicServiceProvider(this);

            retro_environment_cb = new LibRetro.retro_environment_t(retro_environment);
            retro_video_refresh_cb = new LibRetro.retro_video_refresh_t(retro_video_refresh);
            retro_audio_sample_cb = new LibRetro.retro_audio_sample_t(retro_audio_sample);
            retro_audio_sample_batch_cb = new LibRetro.retro_audio_sample_batch_t(retro_audio_sample_batch);
            retro_input_poll_cb = new LibRetro.retro_input_poll_t(retro_input_poll);
            retro_input_state_cb = new LibRetro.retro_input_state_t(retro_input_state);

            retro = new LibRetro(modulename);
            try
            {
                CoreComm = nextComm;

                LibRetro.retro_system_info sys = new LibRetro.retro_system_info();
                retro.retro_get_system_info(ref sys);

                if (sys.need_fullpath)
                    throw new ArgumentException("This libretro core needs filepaths");
                if (sys.block_extract)
                    throw new ArgumentException("This libretro needs non-blocked extract");

                retro.retro_set_environment(retro_environment_cb);
                retro.retro_init();
                retro.retro_set_video_refresh(retro_video_refresh_cb);
                retro.retro_set_audio_sample(retro_audio_sample_cb);
                retro.retro_set_audio_sample_batch(retro_audio_sample_batch_cb);
                retro.retro_set_input_poll(retro_input_poll_cb);
                retro.retro_set_input_state(retro_input_state_cb);
            }
            catch
            {
                retro.Dispose();
                throw;
            }
        }