Merge pull request #13 from audetto/threads

Threads
This commit is contained in:
Andrea 2020-11-14 20:36:14 +00:00 committed by GitHub
commit 0511128fea
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 404 additions and 116 deletions

View file

@ -5,6 +5,7 @@ add_library(common2 STATIC
configuration.cpp
programoptions.cpp
utils.cpp
timer.cpp
)
find_package(Boost REQUIRED

View file

@ -13,29 +13,33 @@ bool getEmulatorOptions(int argc, const char * argv [], const std::string & vers
desc.add_options()
("help,h", "Print this help message")
("conf", "Save configuration on exit")
("qt-ini", "Use Qt ini file (read only)");
("multi-threaded,m", "Multi threaded")
("loose-mutex,l", "Loose mutex")
("sdl-driver", po::value<int>()->default_value(options.sdlDriver), "SDL driver")
("timer-interval,i", po::value<int>()->default_value(options.timerInterval), "Timer interval in ms")
("qt-ini,q", "Use Qt ini file (read only)");
po::options_description diskDesc("Disk");
diskDesc.add_options()
("d1,1", po::value<std::string>(), "Mount disk image in first drive")
("d2,2", po::value<std::string>(), "Mount disk image in second drive")
("d1,1", po::value<std::string>(), "Disk in 1st drive")
("d2,2", po::value<std::string>(), "Disk in 2nd drive")
("create,c", "Create missing disks");
desc.add(diskDesc);
po::options_description snapshotDesc("Snapshot");
snapshotDesc.add_options()
("load-state,ls", po::value<std::string>(), "Load snapshot from file");
("load-state,s", po::value<std::string>(), "Load snapshot from file");
desc.add(snapshotDesc);
po::options_description memoryDesc("Memory");
memoryDesc.add_options()
("memclear,m", po::value<int>(), "Memory initialization pattern [0..7]");
("memclear", po::value<int>()->default_value(options.memclear), "Memory initialization pattern [0..7]");
desc.add(memoryDesc);
po::options_description emulatorDesc("Emulator");
emulatorDesc.add_options()
("log", "Log to AppleWin.log")
("headless,hl", "Headless: disable video")
("headless", "Headless: disable video")
("ntsc,nt", "NTSC: execute NTSC code")
("benchmark,b", "Benchmark emulator")
("no-squaring", "Gamepad range is (already) a square");
@ -54,6 +58,10 @@ bool getEmulatorOptions(int argc, const char * argv [], const std::string & vers
options.saveConfigurationOnExit = vm.count("conf");
options.useQtIni = vm.count("qt-ini");
options.multiThreaded = vm.count("multi-threaded");
options.looseMutex = vm.count("loose-mutex");
options.timerInterval = vm["timer-interval"].as<int>();
options.sdlDriver = vm["sdl-driver"].as<int>();
if (vm.count("d1"))
{
@ -72,12 +80,9 @@ bool getEmulatorOptions(int argc, const char * argv [], const std::string & vers
options.snapshot = vm["load-state"].as<std::string>();
}
if (vm.count("memclear"))
{
const int memclear = vm["memclear"].as<int>();
if (memclear >=0 && memclear < NUM_MIP)
options.memclear = memclear;
}
const int memclear = vm["memclear"].as<int>();
if (memclear >=0 && memclear < NUM_MIP)
options.memclear = memclear;
options.benchmark = vm.count("benchmark") > 0;
options.headless = vm.count("headless") > 0;

View file

@ -7,24 +7,30 @@ struct EmulatorOptions
{
std::string disk1;
std::string disk2;
bool createMissingDisks;
bool createMissingDisks = false;
std::string snapshot;
int memclear;
int memclear = 0;
bool log;
bool log = false;
bool benchmark;
bool headless;
bool ntsc;
bool benchmark = false;
bool headless = false;
bool ntsc = false; // only for applen
bool squaring; // turn the x/y range to a square
bool squaring = true; // turn the x/y range to a square
bool saveConfigurationOnExit;
bool useQtIni; // use Qt .ini file (read only)
bool saveConfigurationOnExit = false;
bool useQtIni = false; // use Qt .ini file (read only)
bool run; // false if options include "-h"
bool run = true; // false if options include "-h"
bool multiThreaded = false;
bool looseMutex = false; // whether SDL_UpdateTexture is mutex protected (from CPU)
int timerInterval = 16; // only when multithreaded
int sdlDriver = -1; // default = -1 to let SDL choose
};
bool getEmulatorOptions(int argc, const char * argv [], const std::string & version, EmulatorOptions & options);

View file

@ -0,0 +1,48 @@
#include "frontends/common2/timer.h"
#include <ostream>
#include <cmath>
#include <iomanip>
Timer::Timer()
: mySum(0)
, mySum2(0)
, myN(0)
{
tic();
}
void Timer::tic()
{
myT0 = std::chrono::steady_clock::now();
}
void Timer::toc()
{
const auto now = std::chrono::steady_clock::now();
const auto micros = std::chrono::duration_cast<std::chrono::microseconds>(now - myT0).count();
const double s = micros * 0.000001;
mySum += s;
mySum2 += s * s;
++myN;
myT0 = now;
}
double Timer::getTimeInSeconds() const
{
return mySum;
}
std::ostream& operator<<(std::ostream& os, const Timer & timer)
{
const int width = 10;
const double m1 = timer.mySum / timer.myN;
const double m2 = timer.mySum2 / timer.myN;
const double std = std::sqrt(std::max(0.0, m2 - m1 * m1));
const double scale = 1000;
os << "total = " << std::setw(width) << timer.mySum * scale << " ms";
os << ", average = " << std::setw(width) << m1 * scale << " ms";
os << ", std = " << std::setw(width) << std * scale << " ms";
os << ", n = " << std::setw(6) << timer.myN;
return os;
}

View file

@ -0,0 +1,24 @@
#include <chrono>
#include <iosfwd>
class Timer
{
public:
Timer();
void tic();
void toc();
double getTimeInSeconds() const;
friend std::ostream& operator<<(std::ostream& os, const Timer & timer);
private:
std::chrono::time_point<std::chrono::steady_clock> myT0;
double mySum;
double mySum2;
int myN;
};
std::ostream& operator<<(std::ostream& os, const Timer & timer);

View file

@ -90,10 +90,9 @@ namespace
void DirectSoundGenerator::setVolume()
{
LONG dwVolume = 0;
myBuffer->GetVolume(&dwVolume);
const qreal volume = - qreal(dwVolume) / DSBVOLUME_MIN + 1.0;
myAudioOutput->setVolume(volume);
const qreal logVolume = myBuffer->GetLogarithmicVolume();
const qreal linVolume = QAudio::convertVolume(logVolume, QAudio::LogarithmicVolumeScale, QAudio::LinearVolumeScale);
myAudioOutput->setVolume(linVolume);
}
void DirectSoundGenerator::start()

View file

@ -6,6 +6,7 @@ add_executable(sa2
emulator.cpp
gamepad.cpp
sdirectsound.cpp
utils.cpp
)
find_package(Boost REQUIRED

View file

@ -21,32 +21,6 @@
namespace
{
SDL_Rect refreshTexture(const std::shared_ptr<SDL_Texture> & tex)
{
uint8_t * data;
int width;
int height;
int sx, sy;
int sw, sh;
getScreenData(data, width, height, sx, sy, sw, sh);
SDL_UpdateTexture(tex.get(), nullptr, data, width * 4);
SDL_Rect srect;
srect.x = sx;
srect.y = sy;
srect.w = sw;
srect.h = sh;
return srect;
}
void renderScreen(const std::shared_ptr<SDL_Renderer> & ren, const std::shared_ptr<SDL_Texture> & tex, const SDL_Rect & srect)
{
SDL_RenderCopyEx(ren.get(), tex.get(), &srect, nullptr, 0.0, nullptr, SDL_FLIP_VERTICAL);
SDL_RenderPresent(ren.get());
}
void cycleVideoType(const std::shared_ptr<SDL_Window> & win)
{
g_eVideoType++;
@ -76,20 +50,6 @@ namespace
VideoRedrawScreen();
}
int getFPS()
{
SDL_DisplayMode current;
int should_be_zero = SDL_GetCurrentDisplayMode(0, &current);
if (should_be_zero)
{
throw std::runtime_error(SDL_GetError());
}
return current.refresh_rate;
}
void processAppleKey(const SDL_KeyboardEvent & key)
{
// using keycode (or scan code) one takes a physical view of the keyboard
@ -164,7 +124,7 @@ namespace
if (ch)
{
addKeyToBuffer(ch);
std::cerr << "Apple Key Down: " << std::hex << (int)ch << std::dec << std::endl;
std::cerr << "SDL KeyboardEvent: " << std::hex << (int)ch << std::dec << std::endl;
}
}
@ -179,27 +139,51 @@ Emulator::Emulator(
: myWindow(window)
, myRenderer(renderer)
, myTexture(texture)
, myFPS(getFPS())
, myMultiplier(1)
, myFullscreen(false)
, myExtraCycles(0)
{
}
void Emulator::executeOneFrame()
void Emulator::executeCycles(const int targetCycles)
{
const DWORD uCyclesToExecute = int(g_fCurrentCLK6502 / myFPS);
const UINT dwClksPerFrame = NTSC_GetCyclesPerFrame();
const bool bVideoUpdate = true;
const DWORD uActualCyclesExecuted = CpuExecute(uCyclesToExecute, bVideoUpdate);
g_dwCyclesThisFrame = (g_dwCyclesThisFrame + uActualCyclesExecuted) % dwClksPerFrame;
const UINT dwClksPerFrame = NTSC_GetCyclesPerFrame();
GetCardMgr().GetDisk2CardMgr().UpdateDriveState(uActualCyclesExecuted);
MB_PeriodicUpdate(uActualCyclesExecuted);
SpkrUpdate(uActualCyclesExecuted);
const DWORD executedCycles = CpuExecute(targetCycles + myExtraCycles, bVideoUpdate);
// SDL2 seems to synch with screen refresh rate so we do not need to worry about timers
const SDL_Rect srect = refreshTexture(myTexture);
renderScreen(myRenderer, myTexture, srect);
g_dwCyclesThisFrame = (g_dwCyclesThisFrame + executedCycles) % dwClksPerFrame;
GetCardMgr().GetDisk2CardMgr().UpdateDriveState(executedCycles);
MB_PeriodicUpdate(executedCycles);
SpkrUpdate(executedCycles);
myExtraCycles = targetCycles - executedCycles;
}
SDL_Rect Emulator::updateTexture()
{
uint8_t * data;
int width;
int height;
int sx, sy;
int sw, sh;
getScreenData(data, width, height, sx, sy, sw, sh);
SDL_UpdateTexture(myTexture.get(), nullptr, data, width * 4);
SDL_Rect srect;
srect.x = sx;
srect.y = sy;
srect.w = sw;
srect.h = sh;
return srect;
}
void Emulator::refreshVideo(const SDL_Rect & rect)
{
SDL_RenderCopyEx(myRenderer.get(), myTexture.get(), &rect, nullptr, 0.0, nullptr, SDL_FLIP_VERTICAL);
SDL_RenderPresent(myRenderer.get());
}
void Emulator::processEvents(bool & quit)
@ -297,7 +281,9 @@ void Emulator::processKeyDown(const SDL_KeyboardEvent & key, bool & quit)
processAppleKey(key);
#if LOGGING_VERBOSE
std::cerr << "KEY DOWN: " << key.keysym.scancode << "," << key.keysym.sym << "," << key.keysym.mod << "," << bool(key.repeat) << std::endl;
#endif
}
@ -316,7 +302,11 @@ void Emulator::processKeyUp(const SDL_KeyboardEvent & key)
break;
}
}
#if LOGGING_VERBOSE
std::cerr << "KEY UP: " << key.keysym.scancode << "," << key.keysym.sym << "," << key.keysym.mod << "," << bool(key.repeat) << std::endl;
#endif
}
void Emulator::processText(const SDL_TextInputEvent & text)
@ -332,7 +322,7 @@ void Emulator::processText(const SDL_TextInputEvent & text)
// not the letters
// this is very simple, but one cannot handle CRTL-key combination.
addKeyToBuffer(key);
std::cerr << "Apple Text: " << std::hex << (int)key << std::dec << std::endl;
std::cerr << "SDL TextInputEvent: " << std::hex << (int)key << std::dec << std::endl;
break;
}
}

View file

@ -12,7 +12,11 @@ public:
const std::shared_ptr<SDL_Texture> & texture
);
void executeOneFrame();
void executeCycles(const int cycles);
void refreshVideo();
SDL_Rect updateTexture();
void refreshVideo(const SDL_Rect & rect);
void processEvents(bool & quit);
private:
@ -23,8 +27,8 @@ private:
const std::shared_ptr<SDL_Window> myWindow;
const std::shared_ptr<SDL_Renderer> myRenderer;
const std::shared_ptr<SDL_Texture> myTexture;
const int myFPS;
int myMultiplier;
bool myFullscreen;
int myExtraCycles;
};

View file

@ -1,6 +1,7 @@
#include <iostream>
#include <SDL.h>
#include <memory>
#include <iomanip>
#include "linux/interface.h"
#include "linux/windows/misc.h"
@ -10,9 +11,11 @@
#include "frontends/common2/configuration.h"
#include "frontends/common2/utils.h"
#include "frontends/common2/programoptions.h"
#include "frontends/common2/timer.h"
#include "frontends/sa2/emulator.h"
#include "frontends/sa2/gamepad.h"
#include "frontends/sa2/sdirectsound.h"
#include "frontends/sa2/utils.h"
#include "StdAfx.h"
#include "Common.h"
@ -122,6 +125,41 @@ namespace
RiffFinishWriteFile();
}
int getRefreshRate()
{
SDL_DisplayMode current;
const int should_be_zero = SDL_GetCurrentDisplayMode(0, &current);
if (should_be_zero)
{
throw std::runtime_error(SDL_GetError());
}
return current.refresh_rate;
}
struct Data
{
Emulator * emulator;
SDL_mutex * mutex;
Timer * timer;
};
Uint32 emulator_callback(Uint32 interval, void *param)
{
Data * data = static_cast<Data *>(param);
SDL_LockMutex(data->mutex);
data->timer->tic();
const int uCyclesToExecute = int(g_fCurrentCLK6502 * interval * 0.001);
data->emulator->executeCycles(uCyclesToExecute);
data->timer->toc();
SDL_UnlockMutex(data->mutex);
return interval;
}
}
int MessageBox(HWND, const char * text, const char * caption, UINT type)
@ -151,7 +189,6 @@ void run_sdl(int argc, const char * argv [])
if (!run)
return;
if (options.log)
{
LogInit();
@ -180,6 +217,8 @@ void run_sdl(int argc, const char * argv [])
const int sw = GetFrameBufferBorderlessWidth();
const int sh = GetFrameBufferBorderlessHeight();
std::cerr << std::fixed << std::setprecision(2);
std::shared_ptr<SDL_Window> win(SDL_CreateWindow(g_pAppTitle.c_str(), SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, sw, sh, SDL_WINDOW_SHOWN), SDL_DestroyWindow);
if (!win)
{
@ -187,36 +226,141 @@ void run_sdl(int argc, const char * argv [])
return;
}
std::shared_ptr<SDL_Renderer> ren(SDL_CreateRenderer(win.get(), -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC), SDL_DestroyRenderer);
std::shared_ptr<SDL_Renderer> ren(SDL_CreateRenderer(win.get(), options.sdlDriver, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC), SDL_DestroyRenderer);
if (!ren)
{
std::cout << "SDL_CreateRenderer Error: " << SDL_GetError() << std::endl;
return;
}
SDL_RendererInfo info;
SDL_GetRendererInfo(ren.get(), &info);
std::cerr << "SDL Renderer:" << info.name << std::endl;
for (size_t i = 0; i < info.num_texture_formats; ++i)
{
std::cerr << SDL_GetPixelFormatName(info.texture_formats[i]) << std::endl;
}
const Uint32 format = SDL_PIXELFORMAT_ARGB8888;
std::cerr << "Selected format: " << SDL_GetPixelFormatName(format) << std::endl;
printRendererInfo(std::cerr, ren, format, options.sdlDriver);
std::shared_ptr<SDL_Texture> tex(SDL_CreateTexture(ren.get(), format, SDL_TEXTUREACCESS_STATIC, width, height), SDL_DestroyTexture);
const int fps = getRefreshRate();
std::cerr << "Video refresh rate: " << fps << " Hz, " << 1000.0 / fps << " ms" << std::endl;
Emulator emulator(win, ren, tex);
bool quit = false;
do
Timer global;
Timer updateTextureTimer;
Timer refreshScreenTimer;
Timer cpuTimer;
Timer eventTimer;
const std::string globalTag = ". .";
std::string updateTextureTimerTag, refreshScreenTimerTag, cpuTimerTag, eventTimerTag;
if (options.multiThreaded)
{
SDirectSound::writeAudio();
emulator.processEvents(quit);
emulator.executeOneFrame();
} while (!quit);
refreshScreenTimerTag = "0 .";
cpuTimerTag = "1 M";
eventTimerTag = "0 M";
if (options.looseMutex)
{
updateTextureTimerTag = "0 .";
}
else
{
updateTextureTimerTag = "0 M";
}
std::shared_ptr<SDL_mutex> mutex(SDL_CreateMutex(), SDL_DestroyMutex);
Data data;
data.mutex = mutex.get();
data.emulator = &emulator;
data.timer = &cpuTimer;
const SDL_TimerID timer = SDL_AddTimer(options.timerInterval, emulator_callback, &data);
bool quit = false;
do
{
SDL_LockMutex(data.mutex);
eventTimer.tic();
SDirectSound::writeAudio();
emulator.processEvents(quit);
eventTimer.toc();
if (options.looseMutex)
{
// loose mutex
// unlock early and let CPU run again in the timer callback
SDL_UnlockMutex(data.mutex);
// but the texture will be updated concurrently with the CPU updating the video buffer
// pixels are not atomic, so a pixel error could happen (if pixel changes while being read)
// on the positive side this will release pressure from CPU and allow for more parallelism
}
updateTextureTimer.tic();
const SDL_Rect rect = emulator.updateTexture();
updateTextureTimer.toc();
if (!options.looseMutex)
{
// safe mutex, only unlock after texture has been updated
// this will stop the CPU for longer
SDL_UnlockMutex(data.mutex);
}
refreshScreenTimer.tic();
emulator.refreshVideo(rect);
refreshScreenTimer.toc();
} while (!quit);
SDL_RemoveTimer(timer);
// if the following enough to make sure the timer has finished
// and wont be called again?
SDL_LockMutex(data.mutex);
SDL_UnlockMutex(data.mutex);
}
else
{
refreshScreenTimerTag = "0 .";
cpuTimerTag = "0 .";
eventTimerTag = "0 .";
updateTextureTimerTag = "0 .";
bool quit = false;
const int uCyclesToExecute = int(g_fCurrentCLK6502 / fps);
do
{
eventTimer.tic();
SDirectSound::writeAudio();
emulator.processEvents(quit);
eventTimer.toc();
cpuTimer.tic();
emulator.executeCycles(uCyclesToExecute);
cpuTimer.toc();
updateTextureTimer.tic();
const SDL_Rect rect = emulator.updateTexture();
updateTextureTimer.toc();
refreshScreenTimer.tic();
emulator.refreshVideo(rect);
refreshScreenTimer.toc();
} while (!quit);
}
global.toc();
const char sep[] = "], ";
std::cerr << "Global: [" << globalTag << sep << global << std::endl;
std::cerr << "Events: [" << eventTimerTag << sep << eventTimer << std::endl;
std::cerr << "Texture: [" << updateTextureTimerTag << sep << updateTextureTimer << std::endl;
std::cerr << "Screen: [" << refreshScreenTimerTag << sep << refreshScreenTimer << std::endl;
std::cerr << "CPU: [" << cpuTimerTag << sep << cpuTimer << std::endl;
const double timeInSeconds = global.getTimeInSeconds();
const double averageClock = g_nCumulativeCycles / timeInSeconds;
std::cerr << "Expected clock: " << g_fCurrentCLK6502 << " Hz, " << timeInSeconds << " s" << std::endl;
std::cerr << "Average clock: " << averageClock << " Hz, " << g_nCumulativeCycles / g_fCurrentCLK6502 << " s" << std::endl;
SDirectSound::stop();
stopEmulator();
@ -226,7 +370,8 @@ void run_sdl(int argc, const char * argv [])
int main(int argc, const char * argv [])
{
//First we need to start up SDL, and make sure it went ok
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMECONTROLLER | SDL_INIT_AUDIO) != 0)
const Uint32 flags = SDL_INIT_VIDEO | SDL_INIT_GAMECONTROLLER | SDL_INIT_AUDIO | SDL_INIT_TIMER;
if (SDL_Init(flags) != 0)
{
std::cerr << "SDL_Init Error: " << SDL_GetError() << std::endl;
return 1;

View file

@ -22,6 +22,8 @@ namespace
private:
IDirectSoundBuffer * myBuffer;
std::vector<Uint8> myMixerBuffer;
SDL_AudioDeviceID myAudioDevice;
SDL_AudioSpec myAudioSpec;
@ -29,9 +31,10 @@ namespace
int myInitialSilence;
void close();
void setVolume();
bool isRunning();
void writeEnoughSilence(const int ms);
void mixBuffer(const void * ptr, const size_t size);
};
@ -95,14 +98,6 @@ namespace
myInitialSilence = std::max(0, initialSilence);
}
void DirectSoundGenerator::setVolume()
{
LONG dwVolume = 0;
myBuffer->GetVolume(&dwVolume);
const double volume = - double(dwVolume) / DSBVOLUME_MIN + 1.0;
// myAudioOutput->setVolume(volume);
}
void DirectSoundGenerator::stop()
{
if (myAudioDevice)
@ -124,6 +119,21 @@ namespace
SDL_QueueAudio(myAudioDevice, silence.data(), silence.size());
}
void DirectSoundGenerator::mixBuffer(const void * ptr, const size_t size)
{
const double logVolume = myBuffer->GetLogarithmicVolume();
// same formula as QAudio::convertVolume()
const double linVolume = logVolume > 0.99 ? 1.0 : -std::log(1.0 - logVolume) / std::log(100.0);
const Uint8 svolume = Uint8(linVolume * SDL_MIX_MAXVOLUME);
// this is a bit of a waste copy-time, but it reuses SDL to do it properly
myMixerBuffer.resize(size);
memset(myMixerBuffer.data(), 0, size);
SDL_MixAudioFormat(myMixerBuffer.data(), (const Uint8*)ptr, myAudioSpec.format, size, svolume);
SDL_QueueAudio(myAudioDevice, myMixerBuffer.data(), size);
}
void DirectSoundGenerator::writeAudio()
{
// this is autostart as we only do for the palying buffers
@ -152,11 +162,11 @@ namespace
if (lpvAudioPtr1 && dwAudioBytes1)
{
SDL_QueueAudio(myAudioDevice, lpvAudioPtr1, dwAudioBytes1);
mixBuffer(lpvAudioPtr1, dwAudioBytes1);
}
if (lpvAudioPtr2 && dwAudioBytes2)
{
SDL_QueueAudio(myAudioDevice, lpvAudioPtr2, dwAudioBytes2);
mixBuffer(lpvAudioPtr2, dwAudioBytes2);
}
}
}

View file

@ -0,0 +1,37 @@
#include "frontends/sa2/utils.h"
#include <ostream>
void printRendererInfo(std::ostream & os, std::shared_ptr<SDL_Renderer> & ren, const Uint32 pixelFormat, const int selectedDriver)
{
SDL_RendererInfo info;
SDL_GetRendererInfo(ren.get(), &info);
const size_t n = SDL_GetNumRenderDrivers();
os << "SDL: " << n << " drivers" << std::endl;
for(size_t i = 0; i < n; ++i)
{
SDL_RendererInfo info;
SDL_GetRenderDriverInfo(i, &info);
os << " " << i << ": " << info.name << std::endl;
}
if (SDL_GetRendererInfo(ren.get(), &info) == 0)
{
os << "Active driver (" << selectedDriver << "): " << info.name << std::endl;
os << " SDL_RENDERER_SOFTWARE: " << ((info.flags & SDL_RENDERER_SOFTWARE) > 0) << std::endl;
os << " SDL_RENDERER_ACCELERATED: " << ((info.flags & SDL_RENDERER_ACCELERATED) > 0) << std::endl;
os << " SDL_RENDERER_PRESENTVSYNC: " << ((info.flags & SDL_RENDERER_PRESENTVSYNC) > 0) << std::endl;
os << " SDL_RENDERER_TARGETTEXTURE: " << ((info.flags & SDL_RENDERER_TARGETTEXTURE) > 0) << std::endl;
os << "Supported pixel formats:" << std::endl;
for (size_t i = 0; i < info.num_texture_formats; ++i)
{
os << " " << SDL_GetPixelFormatName(info.texture_formats[i]) << std::endl;
}
os << "Selected format: " << SDL_GetPixelFormatName(pixelFormat) << std::endl;
}
else
{
os << "No Renderinfo" << std::endl;
}
}

View file

@ -0,0 +1,7 @@
#pragma once
#include <SDL.h>
#include <memory>
#include <iosfwd>
void printRendererInfo(std::ostream & os, std::shared_ptr<SDL_Renderer> & ren, const Uint32 pixelFormat, const int selectedDriver);

View file

@ -286,11 +286,14 @@ void LoadConfiguration(void)
if(REGLOAD(TEXT(REGVALUE_THE_FREEZES_F8_ROM), &dwTmp))
sg_PropertySheet.SetTheFreezesF8Rom(dwTmp);
if(REGLOAD(TEXT(REGVALUE_SPKR_VOLUME), &dwTmp))
SpkrSetVolume(dwTmp, 99);
// if missing set volume low to avoid annoying beeps
dwTmp = 70;
REGLOAD(TEXT(REGVALUE_SPKR_VOLUME), &dwTmp);
SpkrSetVolume(dwTmp, 99);
if(REGLOAD(TEXT(REGVALUE_MB_VOLUME), &dwTmp))
MB_SetVolume(dwTmp, 99);
dwTmp = 60;
REGLOAD(TEXT(REGVALUE_MB_VOLUME), &dwTmp);
MB_SetVolume(dwTmp, 99);
if(REGLOAD(TEXT(REGVALUE_SAVE_STATE_ON_EXIT), &dwTmp))
g_bSaveStateOnExit = dwTmp ? true : false;

View file

@ -173,6 +173,12 @@ HRESULT IDirectSoundBuffer::GetVolume( LONG * lplVolume )
return DS_OK;
}
double IDirectSoundBuffer::GetLogarithmicVolume() const
{
const double volume = (double(myVolume) - DSBVOLUME_MIN) / (0.0 - DSBVOLUME_MIN);
return volume;
}
HRESULT WINAPI DirectSoundCreate(LPGUID lpGuid, LPDIRECTSOUND* ppDS, LPUNKNOWN pUnkOuter)
{
*ppDS = new IDirectSound();

View file

@ -111,6 +111,8 @@ class IDirectSoundBuffer : public IUnknown
HRESULT SetVolume( LONG lVolume );
HRESULT GetVolume( LONG * lplVolume );
double GetLogarithmicVolume() const; // in [0, 1]
HRESULT GetStatus( LPDWORD lpdwStatus );
HRESULT Restore();
};