mirror of
https://github.com/libretro/gambatte-libretro.git
synced 2024-11-23 07:49:48 +00:00
Fractional bits for intermediate rate estimation averages.
Add RateEst reset method. Initialize RateEst count to 1. Less refresh rate estimation averaging. Allow more refresh rate estimation deviation. Return NULL paintEngine in windows blitters that use the PaintToScreen attribute. Add checks for things not being initialized in DirectDraw-blitter and QPainterBlitter paintEvents. Don't reparent blitters (mainly to make a bug in Qt 4.4.3 win less annoying, widgets that do internal reparenting are still affected). Check for window position less than screen top-left after mode change, before full screen, to avoid Qt moving it to the primary screen. Add rate estimation to DirectSound engine. Better underrun detection in DirectSound engine. git-svn-id: https://gambatte.svn.sourceforge.net/svnroot/gambatte@182 9dfb2916-2d38-0410-aef4-c5fe6c9ffc24
This commit is contained in:
parent
eb810eb4fe
commit
a5f83a3719
@ -24,34 +24,37 @@ static long limit(long est, const long reference) {
|
||||
est = reference + (reference >> 7);
|
||||
else if (est < reference - (reference >> 7))
|
||||
est = reference - (reference >> 7);
|
||||
|
||||
|
||||
return est;
|
||||
}
|
||||
|
||||
void RateEst::init(long srate, const long reference) {
|
||||
void RateEst::init(long srate, long reference) {
|
||||
srate <<= UPSHIFT;
|
||||
reference <<= UPSHIFT;
|
||||
|
||||
this->srate.est = limit(srate, reference);
|
||||
this->srate.var = srate >> 12;
|
||||
last = 0;
|
||||
this->reference = reference;
|
||||
samples = 0;
|
||||
count = 32;
|
||||
count = 1;
|
||||
}
|
||||
|
||||
void RateEst::feed(const long samplesIn) {
|
||||
samples += samplesIn;
|
||||
|
||||
|
||||
if (--count == 0) {
|
||||
count = 32;
|
||||
|
||||
|
||||
const usec_t now = getusecs();
|
||||
|
||||
|
||||
if (last) {
|
||||
long est = samples * 1000000.0f / (now - last) + 0.5f;
|
||||
long est = samples * (1000000.0f * UP) / (now - last) + 0.5f;
|
||||
est = limit((srate.est * 31 + est + 16) >> 5, reference);
|
||||
srate.var = (srate.var * 15 + std::abs(est - srate.est) + 8) >> 4;
|
||||
srate.est = est;
|
||||
}
|
||||
|
||||
|
||||
last = now;
|
||||
samples = 0;
|
||||
}
|
||||
|
@ -27,21 +27,25 @@ public:
|
||||
long est;
|
||||
long var;
|
||||
};
|
||||
|
||||
|
||||
private:
|
||||
enum { UPSHIFT = 5 };
|
||||
enum { UP = 1 << UPSHIFT };
|
||||
|
||||
Result srate;
|
||||
usec_t last;
|
||||
long reference;
|
||||
long samples;
|
||||
unsigned count;
|
||||
|
||||
|
||||
public:
|
||||
RateEst(long srate = 0) { init(srate); }
|
||||
RateEst(long srate, long reference) { init(srate, reference); }
|
||||
void init(long srate) { init(srate, srate); }
|
||||
void init(long srate, long reference);
|
||||
void reset() { count = 1; last = 0; }
|
||||
void feed(long samples);
|
||||
const Result& result() const { return srate; }
|
||||
const Result result() const { const Result res = { (srate.est + UP / 2) >> UPSHIFT, (srate.var + UP / 2) >> UPSHIFT }; return res; }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -1,5 +1,5 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aam<EFBFBD>s *
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
@ -26,6 +26,7 @@
|
||||
#include <QVBoxLayout>
|
||||
#include <QHBoxLayout>
|
||||
#include <QSettings>
|
||||
#include <iostream>
|
||||
|
||||
Q_DECLARE_METATYPE(GUID*)
|
||||
|
||||
@ -35,7 +36,7 @@ BOOL CALLBACK DirectSoundEngine::enumCallback(LPGUID lpGuid, const char *lpcstrD
|
||||
thisptr->deviceList.append(*lpGuid);
|
||||
thisptr->deviceSelector->addItem(lpcstrDescription, QVariant::fromValue(&thisptr->deviceList.last()));
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -46,51 +47,53 @@ DirectSoundEngine::DirectSoundEngine(HWND hwnd_in) :
|
||||
deviceSelector(new QComboBox),
|
||||
lpDS(NULL),
|
||||
lpDSB(NULL),
|
||||
lastusecs(0),
|
||||
bufSize(0),
|
||||
deviceIndex(0),
|
||||
offset(0),
|
||||
lastpc(0),
|
||||
hwnd(hwnd_in),
|
||||
useGlobalBuf(false)
|
||||
{
|
||||
DirectSoundEnumerateA(enumCallback, this);
|
||||
|
||||
|
||||
if (deviceSelector->count() < 1)
|
||||
deviceSelector->addItem(QString(), QVariant::fromValue<GUID*>(NULL));
|
||||
|
||||
|
||||
{
|
||||
QVBoxLayout *const mainLayout = new QVBoxLayout;
|
||||
mainLayout->setMargin(0);
|
||||
|
||||
|
||||
if (deviceSelector->count() > 1) {
|
||||
QHBoxLayout *const hlayout = new QHBoxLayout;
|
||||
|
||||
|
||||
hlayout->addWidget(new QLabel(QString("DirectSound device:")));
|
||||
hlayout->addWidget(deviceSelector);
|
||||
|
||||
|
||||
mainLayout->addLayout(hlayout);
|
||||
}
|
||||
|
||||
|
||||
mainLayout->addWidget(globalBufBox);
|
||||
confWidget->setLayout(mainLayout);
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
QSettings settings;
|
||||
settings.beginGroup("directsoundengine");
|
||||
useGlobalBuf = settings.value("useGlobalBuf", useGlobalBuf).toBool();
|
||||
|
||||
|
||||
if ((deviceIndex = settings.value("deviceIndex", deviceIndex).toUInt()) >= static_cast<unsigned>(deviceSelector->count()))
|
||||
deviceIndex = 0;
|
||||
|
||||
|
||||
settings.endGroup();
|
||||
}
|
||||
|
||||
|
||||
rejectSettings();
|
||||
}
|
||||
|
||||
DirectSoundEngine::~DirectSoundEngine() {
|
||||
uninit();
|
||||
|
||||
|
||||
QSettings settings;
|
||||
settings.beginGroup("directsoundengine");
|
||||
settings.setValue("useGlobalBuf", useGlobalBuf);
|
||||
@ -108,59 +111,56 @@ void DirectSoundEngine::rejectSettings() {
|
||||
deviceSelector->setCurrentIndex(deviceIndex);
|
||||
}
|
||||
|
||||
static unsigned nearestPowerOf2(const unsigned in) {
|
||||
/*static unsigned nearestPowerOf2(const unsigned in) {
|
||||
unsigned out = in;
|
||||
|
||||
|
||||
out |= out >> 1;
|
||||
out |= out >> 2;
|
||||
out |= out >> 4;
|
||||
out |= out >> 8;
|
||||
out |= out >> 16;
|
||||
++out;
|
||||
|
||||
|
||||
if (!(out >> 2 & in))
|
||||
out >>= 1;
|
||||
|
||||
|
||||
return out;
|
||||
}*/
|
||||
|
||||
static unsigned bufferMsecs(unsigned bufSz, unsigned rate) {
|
||||
return rate ? ((bufSz / 4) * 1000) / rate : 0;
|
||||
}
|
||||
|
||||
int DirectSoundEngine::doInit(const int rate, const unsigned latency) {
|
||||
if (DirectSoundCreate(deviceSelector->itemData(deviceIndex).value<GUID*>(), &lpDS, NULL) != DS_OK) {
|
||||
lpDS = NULL;
|
||||
std::cout << "DirectSoundCreate failed" << std::endl;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (lpDS->SetCooperativeLevel(hwnd, DSSCL_PRIORITY) != DS_OK)
|
||||
|
||||
if (lpDS->SetCooperativeLevel(hwnd, DSSCL_PRIORITY) != DS_OK) {
|
||||
std::cout << "SetCooperativeLevel failed" << std::endl;
|
||||
goto fail;
|
||||
|
||||
}
|
||||
|
||||
{
|
||||
DSBUFFERDESC dsbd;
|
||||
std::memset(&dsbd, 0, sizeof(dsbd));
|
||||
dsbd.dwSize = sizeof(dsbd);
|
||||
dsbd.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | (useGlobalBuf ? DSBCAPS_GLOBALFOCUS : 0);
|
||||
|
||||
|
||||
{
|
||||
/*int bufferSize = (((rate * 4389) / 262144) + 1) * 8 * 4;
|
||||
|
||||
--bufferSize;
|
||||
bufferSize |= bufferSize >> 1;
|
||||
bufferSize |= bufferSize >> 2;
|
||||
bufferSize |= bufferSize >> 4;
|
||||
bufferSize |= bufferSize >> 8;
|
||||
bufferSize |= bufferSize >> 16;
|
||||
++bufferSize;*/
|
||||
|
||||
int bufferSize = nearestPowerOf2(((rate * latency + 500) / 1000) * 4);
|
||||
|
||||
int bufferSize = /*nearestPowerOf2*/(((rate * latency + 500) / 1000) * 4);
|
||||
|
||||
if (bufferSize < DSBSIZE_MIN)
|
||||
bufferSize = DSBSIZE_MIN;
|
||||
|
||||
|
||||
if (bufferSize > DSBSIZE_MAX)
|
||||
bufferSize = DSBSIZE_MAX;
|
||||
|
||||
dsbd.dwBufferBytes = bufSize = bufferSize;
|
||||
|
||||
dsbd.dwBufferBytes = bufferSize;
|
||||
}
|
||||
|
||||
|
||||
WAVEFORMATEX wfe;
|
||||
std::memset(&wfe, 0, sizeof(wfe));
|
||||
wfe.wFormatTag = WAVE_FORMAT_PCM;
|
||||
@ -169,23 +169,35 @@ int DirectSoundEngine::doInit(const int rate, const unsigned latency) {
|
||||
wfe.wBitsPerSample = 16;
|
||||
wfe.nBlockAlign = wfe.nChannels * wfe.wBitsPerSample >> 3;
|
||||
wfe.nAvgBytesPerSec = rate * wfe.nBlockAlign;
|
||||
|
||||
|
||||
dsbd.lpwfxFormat = &wfe;
|
||||
|
||||
|
||||
{
|
||||
GUID guidNULL;
|
||||
std::memset(&guidNULL,0,sizeof(GUID));
|
||||
dsbd.guid3DAlgorithm = guidNULL;
|
||||
}
|
||||
|
||||
|
||||
if (lpDS->CreateSoundBuffer(&dsbd, &lpDSB, NULL) != DS_OK) {
|
||||
lpDSB = NULL;
|
||||
std::cout << "CreateSoundBuffer failed" << std::endl;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
DSBCAPS dsbcaps;
|
||||
std::memset(&dsbcaps, 0, sizeof(dsbcaps));
|
||||
dsbcaps.dwSize = sizeof(dsbcaps);
|
||||
|
||||
if (lpDSB->GetCaps(&dsbcaps) != DS_OK)
|
||||
goto fail;
|
||||
|
||||
bufSize = dsbcaps.dwBufferBytes;
|
||||
}
|
||||
|
||||
|
||||
est.init(rate);
|
||||
|
||||
return rate;
|
||||
|
||||
|
||||
fail:
|
||||
uninit();
|
||||
return -1;
|
||||
@ -196,87 +208,100 @@ void DirectSoundEngine::uninit() {
|
||||
lpDSB->Stop();
|
||||
lpDSB->Release();
|
||||
}
|
||||
|
||||
|
||||
lpDSB = NULL;
|
||||
|
||||
|
||||
if (lpDS)
|
||||
lpDS->Release();
|
||||
|
||||
|
||||
lpDS = NULL;
|
||||
}
|
||||
|
||||
int DirectSoundEngine::write(void *const buffer, const unsigned frames) {
|
||||
DWORD status;
|
||||
lpDSB->GetStatus(&status);
|
||||
|
||||
|
||||
if (status & DSBSTATUS_BUFFERLOST) {
|
||||
lpDSB->Restore();
|
||||
status &= ~DSBSTATUS_PLAYING;
|
||||
}
|
||||
|
||||
|
||||
if (!(status & DSBSTATUS_PLAYING)) {
|
||||
// std:: cout << "notplaying" << std::endl;
|
||||
offset = bufSize >> 1;
|
||||
lpDSB->SetCurrentPosition(0);
|
||||
} else for (DWORD pc, wc;;) {
|
||||
lpDSB->SetCurrentPosition(lastpc = lastusecs = 0);
|
||||
est.reset();
|
||||
} else {
|
||||
DWORD pc, wc;
|
||||
|
||||
if (lpDSB->GetCurrentPosition(&pc, &wc) != DS_OK)
|
||||
return -1;
|
||||
|
||||
//std::cout << "wc-pc: " << ((wc < pc ? bufSize : 0) + wc - pc) << std::endl;
|
||||
if (offset > pc && offset < wc) {
|
||||
// std::cout << "underrun" << std::endl;
|
||||
offset = wc;
|
||||
break;
|
||||
|
||||
const usec_t usecs = getusecs();
|
||||
|
||||
if (usecs - lastusecs > (bufferMsecs(bufSize, rate())) * 1000)
|
||||
est.reset();
|
||||
|
||||
est.feed(((pc >= lastpc ? 0 : bufSize) + pc - lastpc) >> 2);
|
||||
lastpc = pc;
|
||||
lastusecs = usecs;
|
||||
|
||||
for (;;) {
|
||||
if ((wc > pc ? wc : wc + bufSize) > (offset > pc ? offset : offset + bufSize)) {
|
||||
//std::cout << "underrun" << std::endl;
|
||||
offset = wc;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((pc < offset ? bufSize : 0) + pc - offset >= frames * 4)
|
||||
break;
|
||||
|
||||
Sleep(1);
|
||||
|
||||
if (lpDSB->GetCurrentPosition(&pc, &wc) != DS_OK)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((pc < offset ? bufSize : 0) + pc - offset >= frames * 4)
|
||||
break;
|
||||
|
||||
Sleep(1);
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
LPVOID ptr1;
|
||||
LPVOID ptr2;
|
||||
DWORD bytes1;
|
||||
DWORD bytes2;
|
||||
|
||||
|
||||
if (lpDSB->Lock(offset, frames * 4, &ptr1, &bytes1, &ptr2, &bytes2, 0) != DS_OK)
|
||||
return 0;
|
||||
|
||||
|
||||
std::memcpy(ptr1, buffer, bytes1);
|
||||
|
||||
if (ptr2) {
|
||||
|
||||
if (ptr2)
|
||||
std::memcpy(ptr2, static_cast<char*>(buffer) + bytes1, bytes2);
|
||||
}
|
||||
|
||||
|
||||
lpDSB->Unlock(ptr1, bytes1, ptr2, bytes2);
|
||||
}
|
||||
|
||||
|
||||
if ((offset += frames * 4) >= bufSize)
|
||||
offset -= bufSize;
|
||||
|
||||
if (!(status & DSBSTATUS_PLAYING)) {
|
||||
|
||||
if (!(status & DSBSTATUS_PLAYING))
|
||||
lpDSB->Play(0, 0, DSBPLAY_LOOPING);
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const AudioEngine::BufferState DirectSoundEngine::bufferState() const {
|
||||
BufferState s;
|
||||
DWORD pc, wc;
|
||||
|
||||
|
||||
if (lpDSB->GetCurrentPosition(&pc, &wc) != DS_OK) {
|
||||
s.fromOverflow = s.fromUnderrun = BufferState::NOT_SUPPORTED;
|
||||
} else if (offset > pc && offset < wc) {
|
||||
} else if ((wc > pc ? wc : wc + bufSize) > (offset > pc ? offset : offset + bufSize)) {
|
||||
s.fromUnderrun = 0;
|
||||
s.fromOverflow = bufSize >> 2;
|
||||
} else {
|
||||
s.fromUnderrun = (offset < wc ? bufSize : 0) + offset - wc >> 2;
|
||||
s.fromOverflow = (pc < offset ? bufSize : 0) + pc - offset >> 2;
|
||||
s.fromUnderrun = ((offset < wc ? bufSize : 0) + offset - wc) >> 2;
|
||||
s.fromOverflow = ((pc < offset ? bufSize : 0) + pc - offset) >> 2;
|
||||
}
|
||||
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
@ -26,29 +26,34 @@ class QComboBox;
|
||||
#include <QList>
|
||||
#include <memory>
|
||||
#include <dsound.h>
|
||||
#include <usec.h>
|
||||
|
||||
class DirectSoundEngine : public AudioEngine {
|
||||
RateEst est;
|
||||
const std::auto_ptr<QWidget> confWidget;
|
||||
QCheckBox *const globalBufBox;
|
||||
QComboBox *const deviceSelector;
|
||||
LPDIRECTSOUND lpDS;
|
||||
LPDIRECTSOUNDBUFFER lpDSB;
|
||||
QList<GUID> deviceList;
|
||||
usec_t lastusecs;
|
||||
unsigned bufSize;
|
||||
unsigned deviceIndex;
|
||||
DWORD offset;
|
||||
DWORD lastpc;
|
||||
HWND hwnd;
|
||||
bool useGlobalBuf;
|
||||
|
||||
|
||||
static BOOL CALLBACK enumCallback(LPGUID, const char*, const char*, LPVOID);
|
||||
|
||||
|
||||
int doInit(int rate, unsigned latency);
|
||||
|
||||
|
||||
public:
|
||||
DirectSoundEngine(HWND hwnd);
|
||||
~DirectSoundEngine();
|
||||
void uninit();
|
||||
int write(void *buffer, unsigned frames);
|
||||
const RateEst::Result rateEstimate() const { return est.result(); }
|
||||
const BufferState bufferState() const;
|
||||
void pause();
|
||||
QWidget* settingsWidget() { return confWidget.get(); }
|
||||
|
@ -42,12 +42,12 @@ BlitterContainer::~BlitterContainer()
|
||||
void BlitterContainer::doLayout(const int w, const int h) {
|
||||
if (!blitter)
|
||||
return;
|
||||
|
||||
|
||||
if (videoDialog->scalingType() == UNRESTRICTED)
|
||||
blitter->setCorrectedGeometry(w, h, w, h);
|
||||
else if (videoDialog->scalingType() == KEEP_RATIO) {
|
||||
const QSize &ar = videoDialog->aspectRatio();
|
||||
|
||||
|
||||
if (w * (ar).height() > h * ar.width()) {
|
||||
const int new_w = (h * ar.width() + (ar.height() >> 1)) / ar.height();
|
||||
blitter->setCorrectedGeometry(w, h, new_w, h);
|
||||
@ -70,13 +70,13 @@ void BlitterContainer::testExclusive() {
|
||||
}
|
||||
|
||||
void BlitterContainer::setBlitter(BlitterWidget *const blitter_in) {
|
||||
if (blitter)
|
||||
blitter->setParent(0);
|
||||
|
||||
// if (blitter)
|
||||
// blitter->setParent(0);
|
||||
|
||||
blitter = blitter_in;
|
||||
|
||||
|
||||
if (blitter) {
|
||||
blitter->setParent(this);
|
||||
// blitter->setParent(this);
|
||||
updateLayout();
|
||||
testExclusive();
|
||||
}
|
||||
|
@ -30,24 +30,24 @@ void FtEst::init(const long frameTime) {
|
||||
}
|
||||
|
||||
void FtEst::update(const usec_t t) {
|
||||
if (t - last < static_cast<unsigned long>(frameTime + (frameTime >> 2))) {
|
||||
if (t - last < static_cast<unsigned long>(frameTime + (frameTime >> 3))) {
|
||||
ft += t - last;
|
||||
|
||||
|
||||
if (--count == 0) {
|
||||
count = COUNT;
|
||||
long oldFtAvg = ftAvg;
|
||||
ftAvg = (ftAvg * 31 + ft + 16) >> 5;
|
||||
|
||||
if (ftAvg > ((frameTime + (frameTime >> 6)) << COUNT_LOG2))
|
||||
ftAvg = (frameTime + (frameTime >> 6)) << COUNT_LOG2;
|
||||
else if (ftAvg < ((frameTime - (frameTime >> 6)) << COUNT_LOG2))
|
||||
ftAvg = (frameTime - (frameTime >> 6)) << COUNT_LOG2;
|
||||
|
||||
ftAvg = (ftAvg * 15 + ft + 8) >> 4;
|
||||
|
||||
if (ftAvg > ((frameTime + (frameTime >> 5)) << COUNT_LOG2))
|
||||
ftAvg = (frameTime + (frameTime >> 5)) << COUNT_LOG2;
|
||||
else if (ftAvg < ((frameTime - (frameTime >> 5)) << COUNT_LOG2))
|
||||
ftAvg = (frameTime - (frameTime >> 5)) << COUNT_LOG2;
|
||||
|
||||
ftVar = (ftVar * 15 + std::abs(ftAvg - oldFtAvg) + 8) >> 4;
|
||||
ft = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
last = t;
|
||||
}
|
||||
|
||||
@ -58,22 +58,22 @@ void FtEst::update(const usec_t t) {
|
||||
class Timer {
|
||||
LONGLONG freq;
|
||||
bool qpf;
|
||||
|
||||
|
||||
public:
|
||||
Timer() : freq(0), qpf(false) {
|
||||
LARGE_INTEGER li;
|
||||
qpf = QueryPerformanceFrequency(&li);
|
||||
freq = qpf ? li.QuadPart : 1000;
|
||||
}
|
||||
|
||||
|
||||
usec_t get() const {
|
||||
LARGE_INTEGER li;
|
||||
|
||||
|
||||
if (qpf)
|
||||
QueryPerformanceCounter(&li);
|
||||
else
|
||||
li.QuadPart = timeGetTime();
|
||||
|
||||
|
||||
return static_cast<ULONGLONG>(li.QuadPart) * 1000000 / freq;
|
||||
}
|
||||
};
|
||||
@ -110,16 +110,16 @@ void usecsleep(const usec_t usecs) {
|
||||
class BlitterWidget::Impl {
|
||||
AdaptiveSleep asleep;
|
||||
usec_t last;
|
||||
|
||||
|
||||
public:
|
||||
Impl() : last(0) {}
|
||||
|
||||
|
||||
long sync(const long ft) {
|
||||
if (ft) {
|
||||
last += asleep.sleepUntil(last, ft);
|
||||
last += ft;
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
@ -28,16 +28,16 @@
|
||||
class QHBoxLayout;
|
||||
|
||||
class FtEst {
|
||||
enum { COUNT_LOG2 = 5 };
|
||||
enum { COUNT_LOG2 = 4 };
|
||||
enum { COUNT = 1 << COUNT_LOG2 };
|
||||
|
||||
|
||||
long frameTime;
|
||||
long ft;
|
||||
long ftAvg;
|
||||
long ftVar;
|
||||
usec_t last;
|
||||
unsigned count;
|
||||
|
||||
|
||||
public:
|
||||
FtEst(long frameTime = 0) { init(frameTime); }
|
||||
void init(long frameTime);
|
||||
@ -50,28 +50,28 @@ class BlitterWidget : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
class Impl;
|
||||
|
||||
|
||||
Impl *const impl;
|
||||
long ft;
|
||||
|
||||
|
||||
protected:
|
||||
PixelBufferSetter setPixelBuffer;
|
||||
|
||||
|
||||
public:
|
||||
struct Estimate {
|
||||
long est;
|
||||
long var;
|
||||
};
|
||||
|
||||
|
||||
const QString nameString;
|
||||
const bool integerOnlyScaler;
|
||||
|
||||
|
||||
BlitterWidget(PixelBufferSetter setPixelBuffer,
|
||||
const QString &name,
|
||||
bool integerOnlyScaler = false,
|
||||
QWidget *parent = 0);
|
||||
virtual ~BlitterWidget();
|
||||
|
||||
|
||||
virtual void init() {}
|
||||
virtual void uninit() {}
|
||||
virtual void blit() = 0;
|
||||
|
@ -31,20 +31,20 @@
|
||||
class ModeLock {
|
||||
HMONITOR monitor;
|
||||
DEVMODE originalMode;
|
||||
|
||||
|
||||
public:
|
||||
ModeLock(HMONITOR monitor) : monitor(monitor) {
|
||||
ZeroMemory(&originalMode, sizeof(DEVMODE));
|
||||
originalMode.dmSize = sizeof(DEVMODE);
|
||||
gdiSettings.enumDisplaySettings(monitor, ENUM_REGISTRY_SETTINGS, &originalMode);
|
||||
|
||||
|
||||
DEVMODE devmode;
|
||||
ZeroMemory(&devmode, sizeof(DEVMODE));
|
||||
devmode.dmSize = sizeof(DEVMODE);
|
||||
gdiSettings.enumDisplaySettings(monitor, ENUM_CURRENT_SETTINGS, &devmode);
|
||||
gdiSettings.changeDisplaySettings(monitor, &devmode, CDS_NORESET | CDS_UPDATEREGISTRY);
|
||||
}
|
||||
|
||||
|
||||
~ModeLock() {
|
||||
gdiSettings.changeDisplaySettings(monitor, &originalMode, CDS_NORESET | CDS_UPDATEREGISTRY);
|
||||
}
|
||||
@ -86,92 +86,91 @@ Direct3DBlitter::Direct3DBlitter(PixelBufferSetter setPixelBuffer, QWidget *pare
|
||||
triplebuf(true),
|
||||
bf(true)
|
||||
{
|
||||
setAttribute(Qt::WA_OpaquePaintEvent, true);
|
||||
setAttribute(Qt::WA_PaintOnScreen, true);
|
||||
|
||||
|
||||
if ((d3d9handle = LoadLibraryA("d3d9.dll")))
|
||||
direct3DCreate9 = (Direct3DCreate9Ptr)GetProcAddress(d3d9handle, "Direct3DCreate9");
|
||||
|
||||
if (direct3DCreate9) {
|
||||
|
||||
if (direct3DCreate9) {
|
||||
if ((d3d = direct3DCreate9(D3D_SDK_VERSION))) {
|
||||
const unsigned adapterCount = d3d->GetAdapterCount();
|
||||
D3DADAPTER_IDENTIFIER9 adapterId;
|
||||
|
||||
|
||||
for (unsigned i = 0; i < adapterCount; ++i) {
|
||||
if (FAILED(d3d->GetAdapterIdentifier(i, 0, &adapterId)))
|
||||
break;
|
||||
|
||||
|
||||
adapterSelector->addItem(adapterId.Description);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (adapterSelector->count() < 1)
|
||||
adapterSelector->addItem(QString());
|
||||
|
||||
|
||||
QSettings settings;
|
||||
settings.beginGroup("direct3dblitter");
|
||||
|
||||
|
||||
if ((adapterIndex = settings.value("adapterIndex", adapterIndex).toUInt()) >= static_cast<unsigned>(adapterSelector->count()))
|
||||
adapterIndex = 0;
|
||||
|
||||
|
||||
vblank = settings.value("vblank", vblank).toBool();
|
||||
flipping = settings.value("flipping", flipping).toBool();
|
||||
vblankflip = settings.value("vblankflip", vblankflip).toBool();
|
||||
triplebuf = settings.value("triplebuf", triplebuf).toBool();
|
||||
bf = settings.value("bf", bf).toBool();
|
||||
settings.endGroup();
|
||||
|
||||
|
||||
{
|
||||
QVBoxLayout *mainLayout = new QVBoxLayout;
|
||||
mainLayout->setMargin(0);
|
||||
|
||||
|
||||
if (adapterSelector->count() > 1) {
|
||||
QHBoxLayout *const hlayout = new QHBoxLayout;
|
||||
hlayout->addWidget(new QLabel(QString(tr("Direct3D adapter:"))));
|
||||
hlayout->addWidget(adapterSelector);
|
||||
mainLayout->addLayout(hlayout);
|
||||
}
|
||||
|
||||
|
||||
mainLayout->addWidget(vblankBox);
|
||||
mainLayout->addWidget(flippingBox);
|
||||
|
||||
|
||||
{
|
||||
QHBoxLayout *l = new QHBoxLayout;
|
||||
l->addSpacing(QApplication::style()->pixelMetric(QStyle::PM_LayoutLeftMargin));
|
||||
l->addWidget(vblankflipBox);
|
||||
mainLayout->addLayout(l);
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
QHBoxLayout *l = new QHBoxLayout;
|
||||
l->addSpacing(QApplication::style()->pixelMetric(QStyle::PM_LayoutLeftMargin));
|
||||
l->addWidget(triplebufBox);
|
||||
mainLayout->addLayout(l);
|
||||
}
|
||||
|
||||
|
||||
mainLayout->addWidget(bfBox);
|
||||
confWidget->setLayout(mainLayout);
|
||||
}
|
||||
|
||||
|
||||
vblankflipBox->setEnabled(false);
|
||||
triplebufBox->setEnabled(false);
|
||||
|
||||
|
||||
connect(flippingBox, SIGNAL(toggled(bool)), vblankflipBox, SLOT(setEnabled(bool)));
|
||||
connect(flippingBox, SIGNAL(toggled(bool)), triplebufBox, SLOT(setEnabled(bool)));
|
||||
|
||||
|
||||
rejectSettings();
|
||||
}
|
||||
|
||||
Direct3DBlitter::~Direct3DBlitter() {
|
||||
uninit();
|
||||
|
||||
|
||||
if (d3d)
|
||||
d3d->Release();
|
||||
|
||||
|
||||
if (d3d9handle)
|
||||
FreeLibrary(d3d9handle);
|
||||
|
||||
|
||||
QSettings settings;
|
||||
settings.beginGroup("direct3dblitter");
|
||||
settings.setValue("adapterIndex", adapterIndex);
|
||||
@ -186,17 +185,17 @@ Direct3DBlitter::~Direct3DBlitter() {
|
||||
void Direct3DBlitter::getPresentParams(D3DPRESENT_PARAMETERS *const presentParams) const {
|
||||
D3DDISPLAYMODE displayMode;
|
||||
bool excl = exclusive & flipping;
|
||||
|
||||
|
||||
if (gdiSettings.monitorFromWindow &&
|
||||
d3d->GetAdapterMonitor(adapterIndex) != gdiSettings.monitorFromWindow(parentWidget()->parentWidget()->winId(), GdiSettings::MON_DEFAULTTONEAREST))
|
||||
excl = false;
|
||||
|
||||
|
||||
if (FAILED(d3d->GetAdapterDisplayMode(adapterIndex, &displayMode))) {
|
||||
excl = false;
|
||||
displayMode.Format = D3DFMT_UNKNOWN;
|
||||
std::cout << "d3d->GetAdapterDisplayMode failed" << std::endl;
|
||||
}
|
||||
|
||||
|
||||
presentParams->BackBufferWidth = excl ? displayMode.Width : width();
|
||||
presentParams->BackBufferHeight = excl ? displayMode.Height : height();
|
||||
presentParams->BackBufferFormat = displayMode.Format;
|
||||
@ -217,51 +216,51 @@ void Direct3DBlitter::lockTexture() {
|
||||
const RECT rect = { left: 0, top: 0, right: inWidth, bottom: inHeight };
|
||||
D3DLOCKED_RECT lockedrect;
|
||||
lockedrect.pBits = NULL;
|
||||
|
||||
|
||||
if (texture)
|
||||
texture->LockRect(0, &lockedrect, &rect, D3DLOCK_NOSYSLOCK);
|
||||
|
||||
|
||||
setPixelBuffer(lockedrect.pBits, MediaSource::RGB32, lockedrect.Pitch >> 2);
|
||||
}
|
||||
|
||||
void Direct3DBlitter::setVertexBuffer() {
|
||||
if (!vertexBuffer)
|
||||
return;
|
||||
|
||||
|
||||
Vertex *vertices = NULL;
|
||||
|
||||
|
||||
if (!FAILED(vertexBuffer->Lock(0, 0, (VOID**)&vertices, 0))) {
|
||||
const unsigned xoffset = backBufferWidth > static_cast<unsigned>(width()) ? backBufferWidth - width() >> 1 : 0;
|
||||
const unsigned yoffset = backBufferHeight > static_cast<unsigned>(height()) ? backBufferHeight - height() >> 1 : 0;
|
||||
|
||||
|
||||
vertices[0].x = xoffset;
|
||||
vertices[0].y = yoffset + height();
|
||||
vertices[0].z = 0.0f;
|
||||
vertices[0].rhw = 1.0f;
|
||||
vertices[0].u = 0.0f;
|
||||
vertices[0].v = static_cast<float>(inHeight) / textRes;
|
||||
|
||||
|
||||
vertices[1].x = xoffset;
|
||||
vertices[1].y = yoffset;
|
||||
vertices[1].z = 0.0f;
|
||||
vertices[1].rhw = 1.0f;
|
||||
vertices[1].u = 0.0f;
|
||||
vertices[1].v = 0.0f;
|
||||
|
||||
|
||||
vertices[2].x = xoffset + width();
|
||||
vertices[2].y = yoffset + height();
|
||||
vertices[2].z = 0.0f;
|
||||
vertices[2].rhw = 1.0f;
|
||||
vertices[2].u = static_cast<float>(inWidth) / textRes;
|
||||
vertices[2].v = static_cast<float>(inHeight) / textRes;
|
||||
|
||||
|
||||
vertices[3].x = xoffset + width();
|
||||
vertices[3].y = yoffset;
|
||||
vertices[3].z = 0.0f;
|
||||
vertices[3].rhw = 1.0f;
|
||||
vertices[3].u = static_cast<float>(inWidth) / textRes;
|
||||
vertices[3].v = 0.0f;
|
||||
|
||||
|
||||
vertexBuffer->Unlock();
|
||||
} else
|
||||
std::cout << "vertexBuffer->Lock failed" << std::endl;
|
||||
@ -277,10 +276,10 @@ void Direct3DBlitter::setFilter() {
|
||||
void Direct3DBlitter::setDeviceState() {
|
||||
if (device) {
|
||||
device->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1);
|
||||
|
||||
|
||||
if (vertexBuffer)
|
||||
device->SetStreamSource(0, vertexBuffer, 0, sizeof(Vertex));
|
||||
|
||||
|
||||
setFilter();
|
||||
}
|
||||
}
|
||||
@ -288,26 +287,26 @@ void Direct3DBlitter::setDeviceState() {
|
||||
void Direct3DBlitter::resetDevice() {
|
||||
if (device && device->TestCooperativeLevel() != D3DERR_DEVICELOST) {
|
||||
device->SetTexture(0, NULL);
|
||||
|
||||
|
||||
D3DPRESENT_PARAMETERS presentParams;
|
||||
|
||||
|
||||
getPresentParams(&presentParams);
|
||||
|
||||
|
||||
if (FAILED(device->Reset(&presentParams)) && FAILED(device->Reset(&presentParams))) {
|
||||
if (texture) {
|
||||
setPixelBuffer(NULL, MediaSource::RGB32, 0);
|
||||
texture->Release();
|
||||
texture = NULL;
|
||||
}
|
||||
|
||||
|
||||
if (vertexBuffer) {
|
||||
vertexBuffer->Release();
|
||||
vertexBuffer = NULL;
|
||||
}
|
||||
|
||||
|
||||
device->Release();
|
||||
device = NULL;
|
||||
|
||||
|
||||
std::cout << "device->Reset failed" << std::endl;
|
||||
} else {
|
||||
backBufferWidth = presentParams.BackBufferWidth;
|
||||
@ -318,7 +317,7 @@ void Direct3DBlitter::resetDevice() {
|
||||
setVertexBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
drawn = false;
|
||||
}
|
||||
|
||||
@ -337,7 +336,7 @@ void Direct3DBlitter::exclusiveChange() {
|
||||
|
||||
void Direct3DBlitter::setSwapInterval(const unsigned hz1, const unsigned hz2) {
|
||||
const unsigned newSwapInterval = vblank ? hz == hz1 * 2 || hz == hz2 ? 2 : (hz == hz1 ? 1 : 0) : 0;
|
||||
|
||||
|
||||
if (newSwapInterval != swapInterval) {
|
||||
swapInterval = newSwapInterval;
|
||||
resetDevice();
|
||||
@ -359,51 +358,51 @@ void Direct3DBlitter::draw() {
|
||||
void Direct3DBlitter::present() {
|
||||
if (device && device->TestCooperativeLevel() == D3DERR_DEVICENOTRESET)
|
||||
resetDevice();
|
||||
|
||||
|
||||
if (!drawn)
|
||||
draw();
|
||||
|
||||
|
||||
if (device) {
|
||||
IDirect3DSwapChain9 *swapChain = NULL;
|
||||
|
||||
|
||||
device->GetSwapChain(0, &swapChain);
|
||||
|
||||
|
||||
if (swapChain) {
|
||||
swapChain->Present(NULL, NULL, 0, NULL, ~windowed & vblankflip && !swapInterval ? 1 : 0);
|
||||
swapChain->Release();
|
||||
} else
|
||||
device->Present(NULL, NULL, 0, NULL);
|
||||
}
|
||||
|
||||
|
||||
drawn = false;
|
||||
}
|
||||
|
||||
void Direct3DBlitter::init() {
|
||||
{
|
||||
D3DPRESENT_PARAMETERS presentParams;
|
||||
|
||||
|
||||
getPresentParams(&presentParams);
|
||||
|
||||
|
||||
for (unsigned n = 2; n--;) {
|
||||
if (!FAILED(d3d->CreateDevice(adapterIndex, D3DDEVTYPE_HAL,
|
||||
parentWidget()->parentWidget()->winId(), D3DCREATE_SOFTWARE_VERTEXPROCESSING, &presentParams, &device))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
backBufferWidth = presentParams.BackBufferWidth;
|
||||
backBufferHeight = presentParams.BackBufferHeight;
|
||||
windowed = presentParams.Windowed;
|
||||
}
|
||||
|
||||
|
||||
if (!device) {
|
||||
std::cout << "d3d->CreateDevice failed" << std::endl;
|
||||
} else if (FAILED(device->CreateVertexBuffer(sizeof(Vertex) * 4, 0, D3DFVF_XYZRHW | D3DFVF_TEX1, D3DPOOL_MANAGED, &vertexBuffer, NULL))) {
|
||||
std::cout << "device->CreateVertexBuffer failed" << std::endl;
|
||||
}
|
||||
|
||||
|
||||
setDeviceState();
|
||||
|
||||
|
||||
drawn = false;
|
||||
}
|
||||
|
||||
@ -412,18 +411,18 @@ void Direct3DBlitter::uninit() {
|
||||
device->SetStreamSource(0, NULL, 0, 0);
|
||||
device->SetTexture(0, NULL);
|
||||
}
|
||||
|
||||
|
||||
if (texture) {
|
||||
texture->UnlockRect(0);
|
||||
texture->Release();
|
||||
texture = NULL;
|
||||
}
|
||||
|
||||
|
||||
if (vertexBuffer) {
|
||||
vertexBuffer->Release();
|
||||
vertexBuffer = NULL;
|
||||
}
|
||||
|
||||
|
||||
if (device) {
|
||||
device->Release();
|
||||
device = NULL;
|
||||
@ -433,31 +432,31 @@ void Direct3DBlitter::uninit() {
|
||||
void Direct3DBlitter::setBufferDimensions(unsigned w, unsigned h) {
|
||||
inWidth = w;
|
||||
inHeight = h;
|
||||
|
||||
|
||||
if (device) {
|
||||
device->SetTexture(0, NULL);
|
||||
|
||||
|
||||
if (texture) {
|
||||
texture->UnlockRect(0);
|
||||
texture->Release();
|
||||
texture = NULL;
|
||||
}
|
||||
|
||||
|
||||
textRes = std::max(w, h);
|
||||
|
||||
|
||||
--textRes;
|
||||
textRes |= textRes >> 1;
|
||||
textRes |= textRes >> 2;
|
||||
textRes |= textRes >> 4;
|
||||
textRes |= textRes >> 8;
|
||||
++textRes;
|
||||
|
||||
|
||||
if (FAILED(device->CreateTexture(textRes, textRes, 1, 0, D3DFMT_X8R8G8B8, D3DPOOL_MANAGED, &texture, NULL)))
|
||||
std::cout << "device->CreateTexture failed" << std::endl;
|
||||
|
||||
|
||||
device->SetTexture(0, texture);
|
||||
}
|
||||
|
||||
|
||||
lockTexture();
|
||||
setVertexBuffer();
|
||||
}
|
||||
@ -465,10 +464,10 @@ void Direct3DBlitter::setBufferDimensions(unsigned w, unsigned h) {
|
||||
void Direct3DBlitter::blit() {
|
||||
if (texture) {
|
||||
texture->UnlockRect(0);
|
||||
|
||||
|
||||
draw();
|
||||
drawn = true;
|
||||
|
||||
|
||||
lockTexture();
|
||||
}
|
||||
}
|
||||
@ -476,33 +475,33 @@ void Direct3DBlitter::blit() {
|
||||
long Direct3DBlitter::sync(const long ft) {
|
||||
if (!swapInterval)
|
||||
BlitterWidget::sync(ft);
|
||||
|
||||
|
||||
present();
|
||||
|
||||
|
||||
if (swapInterval)
|
||||
ftEst.update(getusecs());
|
||||
|
||||
|
||||
if (!device)
|
||||
return -1;
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Direct3DBlitter::setFrameTime(const long ft) {
|
||||
BlitterWidget::setFrameTime(ft);
|
||||
|
||||
|
||||
const unsigned hz1 = (1000000 + (ft >> 1)) / ft;
|
||||
const unsigned hz2 = (1000000 * 2 + (ft >> 1)) / ft;
|
||||
|
||||
|
||||
{
|
||||
QString text("Sync to vertical blank in " + QString::number(hz1));
|
||||
|
||||
|
||||
if (hz2 != hz1 * 2)
|
||||
text += ", " + QString::number(hz2);
|
||||
|
||||
|
||||
vblankBox->setText(text + " and " + QString::number(hz1 * 2) + " Hz modes");
|
||||
}
|
||||
|
||||
|
||||
setSwapInterval(hz1, hz2);
|
||||
}
|
||||
|
||||
@ -511,14 +510,14 @@ const BlitterWidget::Estimate Direct3DBlitter::frameTimeEst() const {
|
||||
const Estimate est = { ftEst.est(), ftEst.var() };
|
||||
return est;
|
||||
}
|
||||
|
||||
|
||||
return BlitterWidget::frameTimeEst();
|
||||
}
|
||||
|
||||
/*const BlitterWidget::Rational Direct3DBlitter::frameTime() const {
|
||||
if (swapInterval)
|
||||
return Rational(swapInterval, hz);
|
||||
|
||||
|
||||
return BlitterWidget::frameTime();
|
||||
}*/
|
||||
|
||||
@ -532,7 +531,7 @@ void Direct3DBlitter::setExclusive(const bool exclusive) {
|
||||
void Direct3DBlitter::acceptSettings() {
|
||||
if (static_cast<int>(adapterIndex) != adapterSelector->currentIndex()) {
|
||||
adapterIndex = adapterSelector->currentIndex();
|
||||
|
||||
|
||||
if (isVisible()) {
|
||||
uninit();
|
||||
setPixelBuffer(NULL, MediaSource::RGB32, 0);
|
||||
@ -540,17 +539,17 @@ void Direct3DBlitter::acceptSettings() {
|
||||
setBufferDimensions(inWidth, inHeight);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (vblank != vblankBox->isChecked()) {
|
||||
vblank = vblankBox->isChecked();
|
||||
setSwapInterval();
|
||||
}
|
||||
|
||||
|
||||
if (flipping != flippingBox->isChecked()) {
|
||||
flipping = flippingBox->isChecked();
|
||||
exclusiveChange();
|
||||
}
|
||||
|
||||
|
||||
vblankflip = vblankflipBox->isChecked();
|
||||
triplebuf = triplebufBox->isChecked();
|
||||
bf = bfBox->isChecked();
|
||||
|
@ -28,7 +28,7 @@ class QComboBox;
|
||||
|
||||
class Direct3DBlitter : public BlitterWidget {
|
||||
typedef IDirect3D9* (WINAPI *Direct3DCreate9Ptr)(UINT);
|
||||
|
||||
|
||||
FtEst ftEst;
|
||||
const std::auto_ptr<QWidget> confWidget;
|
||||
QComboBox *const adapterSelector;
|
||||
@ -38,7 +38,7 @@ class Direct3DBlitter : public BlitterWidget {
|
||||
QCheckBox *const triplebufBox;
|
||||
QCheckBox *const bfBox;
|
||||
HMODULE d3d9handle;
|
||||
Direct3DCreate9Ptr direct3DCreate9;
|
||||
Direct3DCreate9Ptr direct3DCreate9;
|
||||
IDirect3D9 *d3d;
|
||||
IDirect3DDevice9* device;
|
||||
IDirect3DVertexBuffer9* vertexBuffer;
|
||||
@ -59,7 +59,7 @@ class Direct3DBlitter : public BlitterWidget {
|
||||
bool vblankflip;
|
||||
bool triplebuf;
|
||||
bool bf;
|
||||
|
||||
|
||||
void getPresentParams(D3DPRESENT_PARAMETERS *presentParams) const;
|
||||
void lockTexture();
|
||||
void setVertexBuffer();
|
||||
@ -71,11 +71,11 @@ class Direct3DBlitter : public BlitterWidget {
|
||||
void setSwapInterval();
|
||||
void draw();
|
||||
void present();
|
||||
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *e);
|
||||
void resizeEvent(QResizeEvent *e);
|
||||
|
||||
|
||||
public:
|
||||
Direct3DBlitter(PixelBufferSetter setPixelBuffer, QWidget *parent = 0);
|
||||
~Direct3DBlitter();
|
||||
@ -91,7 +91,9 @@ public:
|
||||
QWidget* settingsWidget() { return confWidget.get(); }
|
||||
void acceptSettings();
|
||||
void rejectSettings();
|
||||
|
||||
|
||||
QPaintEngine* paintEngine () const { return NULL; }
|
||||
|
||||
public slots:
|
||||
void rateChange(int hz);
|
||||
};
|
||||
|
@ -31,14 +31,14 @@ Q_DECLARE_METATYPE(GUID*)
|
||||
BOOL WINAPI DirectDrawBlitter::enumCallback(GUID FAR *lpGUID, char *lpDriverDescription, char */*lpDriverName*/, LPVOID lpContext, HMONITOR) {
|
||||
DirectDrawBlitter *const thisptr = static_cast<DirectDrawBlitter*>(lpContext);
|
||||
GUID *guidptr = NULL;
|
||||
|
||||
|
||||
if (lpGUID) {
|
||||
thisptr->deviceList.append(*lpGUID);
|
||||
guidptr = &thisptr->deviceList.last();
|
||||
}
|
||||
|
||||
|
||||
thisptr->deviceSelector->addItem(lpDriverDescription, QVariant::fromValue(guidptr));
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -62,48 +62,47 @@ DirectDrawBlitter::DirectDrawBlitter(PixelBufferSetter setPixelBuffer, QWidget *
|
||||
inHeight(1),
|
||||
exclusive(false)
|
||||
{
|
||||
setAttribute(Qt::WA_OpaquePaintEvent, true);
|
||||
setAttribute(Qt::WA_PaintOnScreen, true);
|
||||
|
||||
|
||||
DirectDrawEnumerateExA(enumCallback, this, DDENUM_ATTACHEDSECONDARYDEVICES);
|
||||
|
||||
|
||||
if (deviceSelector->count() < 1)
|
||||
deviceSelector->addItem(QString(), QVariant::fromValue<GUID*>(NULL));
|
||||
|
||||
|
||||
QSettings settings;
|
||||
settings.beginGroup("directdrawblitter");
|
||||
vblank = settings.value("vblank", false).toBool();
|
||||
flipping = settings.value("flipping", false).toBool();
|
||||
videoSurface = settings.value("videoSurface", true).toBool();
|
||||
|
||||
|
||||
if ((deviceIndex = settings.value("deviceIndex", deviceIndex).toUInt()) >= static_cast<unsigned>(deviceSelector->count()))
|
||||
deviceIndex = 0;
|
||||
|
||||
|
||||
settings.endGroup();
|
||||
|
||||
|
||||
QVBoxLayout *const mainLayout = new QVBoxLayout;
|
||||
mainLayout->setMargin(0);
|
||||
|
||||
|
||||
if (deviceSelector->count() > 2) {
|
||||
QHBoxLayout *const hlayout = new QHBoxLayout;
|
||||
|
||||
|
||||
hlayout->addWidget(new QLabel(QString(tr("DirectDraw device:"))));
|
||||
hlayout->addWidget(deviceSelector);
|
||||
|
||||
|
||||
mainLayout->addLayout(hlayout);
|
||||
}
|
||||
|
||||
|
||||
mainLayout->addWidget(vblankBox);
|
||||
mainLayout->addWidget(flippingBox);
|
||||
mainLayout->addWidget(videoSurfaceBox);
|
||||
confWidget->setLayout(mainLayout);
|
||||
|
||||
|
||||
rejectSettings();
|
||||
}
|
||||
|
||||
DirectDrawBlitter::~DirectDrawBlitter() {
|
||||
uninit();
|
||||
|
||||
|
||||
QSettings settings;
|
||||
settings.beginGroup("directdrawblitter");
|
||||
settings.setValue("vblank", vblank);
|
||||
@ -116,24 +115,24 @@ DirectDrawBlitter::~DirectDrawBlitter() {
|
||||
void DirectDrawBlitter::videoSurfaceBlit() {
|
||||
lpDDSSystem->PageLock(0);
|
||||
lpDDSVideo->PageLock(0);
|
||||
|
||||
|
||||
HRESULT ddrval;
|
||||
ddrval = lpDDSVideo->BltFast(0, 0, lpDDSSystem, NULL, DDBLTFAST_WAIT);
|
||||
|
||||
|
||||
if (ddrval == DDERR_SURFACELOST) {
|
||||
if (!restoreSurfaces())
|
||||
ddrval = lpDDSVideo->BltFast(0, 0, lpDDSSystem, NULL, DDBLTFAST_WAIT);
|
||||
}
|
||||
|
||||
|
||||
if (ddrval != DD_OK) {
|
||||
std::cout << "lpDDSVideo->BltFast(0, 0, lpDDSSystem, NULL, DDBLTFAST_WAIT) failed" << std::endl;
|
||||
|
||||
|
||||
if (lpDDSPrimary) {
|
||||
lpDDSPrimary->Release();
|
||||
lpDDSPrimary = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
lpDDSVideo->PageUnlock(0);
|
||||
lpDDSSystem->PageUnlock(0);
|
||||
}
|
||||
@ -147,20 +146,20 @@ void DirectDrawBlitter::systemSurfaceBlit() {
|
||||
void DirectDrawBlitter::blit() {
|
||||
if (!lpDDSPrimary)
|
||||
return;
|
||||
|
||||
|
||||
lpDDSSystem->Unlock(NULL);
|
||||
|
||||
|
||||
if (videoSurface)
|
||||
videoSurfaceBlit();
|
||||
else
|
||||
systemSurfaceBlit();
|
||||
|
||||
|
||||
DDSURFACEDESC2 ddsd;
|
||||
ddsd.dwSize = sizeof(ddsd);
|
||||
|
||||
ddsd.dwSize = sizeof(ddsd);
|
||||
|
||||
if (lpDDSSystem->Lock(NULL, &ddsd, DDLOCK_NOSYSLOCK, NULL) != DD_OK)
|
||||
std::cout << "lpDDSSystem->Lock(NULL, &ddsd, DDLOCK_NOSYSLOCK, NULL) failed" << std::endl;
|
||||
|
||||
|
||||
setPixelBuffer(ddsd.lpSurface, pixelFormat, pixelFormat == MediaSource::RGB16 ? ddsd.lPitch >> 1 : (ddsd.lPitch >> 2));
|
||||
}
|
||||
|
||||
@ -168,55 +167,55 @@ bool DirectDrawBlitter::initPrimarySurface() {
|
||||
{
|
||||
DDSURFACEDESC2 ddsd;
|
||||
std::memset(&ddsd, 0, sizeof(ddsd));
|
||||
ddsd.dwSize = sizeof(ddsd);
|
||||
ddsd.dwFlags = DDSD_CAPS;
|
||||
ddsd.dwSize = sizeof(ddsd);
|
||||
ddsd.dwFlags = DDSD_CAPS;
|
||||
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
|
||||
|
||||
|
||||
if (exclusive && flipping) {
|
||||
ddsd.dwFlags |= DDSD_BACKBUFFERCOUNT;
|
||||
ddsd.dwBackBufferCount = 1;
|
||||
ddsd.ddsCaps.dwCaps |= DDSCAPS_COMPLEX | DDSCAPS_FLIP;
|
||||
}
|
||||
|
||||
|
||||
HRESULT ddrval = lpDD->CreateSurface(&ddsd, &lpDDSPrimary, NULL);
|
||||
lpDDSBack = lpDDSPrimary;
|
||||
|
||||
|
||||
if (exclusive && flipping && ddrval == DD_OK) {
|
||||
ddsd.ddsCaps.dwCaps = DDSCAPS_BACKBUFFER;
|
||||
ddrval = lpDDSPrimary->GetAttachedSurface(&ddsd.ddsCaps, &lpDDSBack);
|
||||
ddrval = lpDDSPrimary->GetAttachedSurface(&ddsd.ddsCaps, &lpDDSBack);
|
||||
}
|
||||
|
||||
|
||||
if (ddrval != DD_OK) {
|
||||
std::cout << "CreateSurface failed" << std::endl;
|
||||
lpDDSPrimary = NULL;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (lpDDSPrimary->SetClipper(lpClipper) != DD_OK) {
|
||||
std::cout << "SetClipper failed" << std::endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DirectDrawBlitter::initVideoSurface() {
|
||||
DDSURFACEDESC2 ddsd;
|
||||
std::memset(&ddsd, 0, sizeof(ddsd));
|
||||
ddsd.dwSize = sizeof(ddsd);
|
||||
ddsd.dwSize = sizeof(ddsd);
|
||||
lpDDSSystem->GetSurfaceDesc(&ddsd);
|
||||
ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
|
||||
ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
|
||||
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
|
||||
|
||||
|
||||
if (!videoSurface)
|
||||
ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
|
||||
|
||||
|
||||
if (lpDD->CreateSurface(&ddsd, &lpDDSVideo, NULL) != DD_OK) {
|
||||
lpDDSVideo = NULL;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -225,27 +224,27 @@ void DirectDrawBlitter::init() {
|
||||
std::cout << "DirectDrawCreateEx failed" << std::endl;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
||||
if (lpDD->SetCooperativeLevel(parentWidget()->parentWidget()->winId(), (exclusive && flipping) ? DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN : DDSCL_NORMAL) != DD_OK) {
|
||||
std::cout << "SetCooperativeLevel failed" << std::endl;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
||||
if (lpDD->CreateClipper(0, &lpClipper, NULL) != DD_OK) {
|
||||
std::cout << "CreateClipper failed" << std::endl;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
||||
if (lpClipper->SetHWnd(0, winId()) != DD_OK) {
|
||||
std::cout << "SetHWnd failed" << std::endl;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
||||
if (initPrimarySurface())
|
||||
goto fail;
|
||||
|
||||
|
||||
return;
|
||||
|
||||
|
||||
fail:
|
||||
uninit();
|
||||
}
|
||||
@ -253,23 +252,23 @@ fail:
|
||||
bool DirectDrawBlitter::restoreSurfaces() {
|
||||
lpDDSPrimary->Restore();
|
||||
lpDDSVideo->Restore();
|
||||
|
||||
|
||||
if (lpDDSPrimary->IsLost() != DDERR_SURFACELOST && lpDDSVideo->IsLost() != DDERR_SURFACELOST)
|
||||
return false;
|
||||
|
||||
|
||||
lpDDSPrimary->Release();
|
||||
|
||||
|
||||
if (initPrimarySurface()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
if (videoSurface) {
|
||||
lpDDSVideo->Release();
|
||||
|
||||
|
||||
if (initVideoSurface())
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -277,17 +276,17 @@ static void setDdPf(DDPIXELFORMAT *const ddpf, MediaSource::PixelFormat *const p
|
||||
bool alpha = false;
|
||||
|
||||
ddpf->dwSize = sizeof(DDPIXELFORMAT);
|
||||
|
||||
|
||||
if (lpDDSPrimary && lpDDSPrimary->GetPixelFormat(ddpf) == DD_OK && (ddpf->dwFlags & DDPF_RGB) && ddpf->dwRGBBitCount == 16) {
|
||||
*pixelFormat = MediaSource::RGB16;
|
||||
} else {
|
||||
*pixelFormat = MediaSource::RGB32;
|
||||
alpha = ddpf->dwFlags & DDPF_ALPHAPIXELS;
|
||||
}
|
||||
|
||||
|
||||
std::memset(ddpf, 0, sizeof(DDPIXELFORMAT));
|
||||
ddpf->dwFlags = DDPF_RGB;
|
||||
|
||||
|
||||
if (*pixelFormat == MediaSource::RGB16) {
|
||||
ddpf->dwRGBBitCount = 16;
|
||||
ddpf->dwRBitMask = 0xF800;
|
||||
@ -298,7 +297,7 @@ static void setDdPf(DDPIXELFORMAT *const ddpf, MediaSource::PixelFormat *const p
|
||||
ddpf->dwRBitMask = 0x00FF0000;
|
||||
ddpf->dwGBitMask = 0x0000FF00;
|
||||
ddpf->dwBBitMask = 0x000000FF;
|
||||
|
||||
|
||||
if (alpha) {
|
||||
ddpf->dwFlags |= DDPF_ALPHAPIXELS;
|
||||
ddpf->dwRGBAlphaBitMask = 0xFF000000;
|
||||
@ -309,53 +308,53 @@ static void setDdPf(DDPIXELFORMAT *const ddpf, MediaSource::PixelFormat *const p
|
||||
void DirectDrawBlitter::setBufferDimensions(const unsigned int w, const unsigned int h) {
|
||||
inWidth = w;
|
||||
inHeight = h;
|
||||
|
||||
|
||||
if (lpDDSPrimary == NULL)
|
||||
return;
|
||||
|
||||
|
||||
if (lpDDSSystem) {
|
||||
lpDDSSystem->Release();
|
||||
lpDDSSystem = NULL;
|
||||
}
|
||||
|
||||
|
||||
if (lpDDSVideo) {
|
||||
lpDDSVideo->Release();
|
||||
lpDDSVideo = NULL;
|
||||
}
|
||||
|
||||
|
||||
DDPIXELFORMAT ddpf;
|
||||
setDdPf(&ddpf, &pixelFormat, lpDDSPrimary);
|
||||
|
||||
|
||||
DDSURFACEDESC2 ddsd;
|
||||
std::memset(&ddsd, 0, sizeof(ddsd));
|
||||
ddsd.dwSize = sizeof(ddsd);
|
||||
ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
|
||||
ddsd.dwSize = sizeof(ddsd);
|
||||
ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
|
||||
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
|
||||
ddsd.dwWidth = w;
|
||||
ddsd.dwHeight = h;
|
||||
ddsd.ddpfPixelFormat = ddpf;
|
||||
|
||||
|
||||
if (lpDD->CreateSurface(&ddsd, &lpDDSSystem, NULL) != DD_OK) {
|
||||
std::cout << "lpDD->CreateSurface(&ddsd, &lpDDSSystem, NULL) failed" << std::endl;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
||||
if (videoSurface)
|
||||
ddsd.ddsCaps.dwCaps &= ~DDSCAPS_SYSTEMMEMORY;
|
||||
|
||||
|
||||
if (lpDD->CreateSurface(&ddsd, &lpDDSVideo, NULL) != DD_OK) {
|
||||
std::cout << "lpDD->CreateSurface(&ddsd, &lpDDSVideo, NULL) failed" << std::endl;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
||||
if (lpDDSSystem->Lock(NULL, &ddsd, DDLOCK_NOSYSLOCK, NULL) != DD_OK) {
|
||||
std::cout << "lpDDSSystem->Lock(NULL, &ddsd, DDLOCK_NOSYSLOCK, NULL) failed" << std::endl;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
||||
setPixelBuffer(ddsd.lpSurface, pixelFormat, pixelFormat == MediaSource::RGB16 ? ddsd.lPitch >> 1 : (ddsd.lPitch >> 2));
|
||||
return;
|
||||
|
||||
|
||||
fail:
|
||||
uninit();
|
||||
}
|
||||
@ -375,7 +374,7 @@ void DirectDrawBlitter::uninit() {
|
||||
lpDDSSystem->Release();
|
||||
lpDDSSystem = NULL;
|
||||
}
|
||||
|
||||
|
||||
if (lpDDSVideo) {
|
||||
lpDDSVideo->Release();
|
||||
lpDDSVideo = NULL;
|
||||
@ -389,9 +388,9 @@ void DirectDrawBlitter::uninit() {
|
||||
|
||||
void DirectDrawBlitter::setFrameTime(const long ft) {
|
||||
BlitterWidget::setFrameTime(ft);
|
||||
|
||||
|
||||
vblankHz = (1000000 + (ft >> 1)) / ft;
|
||||
|
||||
|
||||
QString text("Sync to vertical blank in ");
|
||||
text += QString::number(vblankHz);
|
||||
text += " Hz modes";
|
||||
@ -403,7 +402,7 @@ const BlitterWidget::Estimate DirectDrawBlitter::frameTimeEst() const {
|
||||
const Estimate est = { ftEst.est(), ftEst.var() };
|
||||
return est;
|
||||
}
|
||||
|
||||
|
||||
return BlitterWidget::frameTimeEst();
|
||||
}
|
||||
|
||||
@ -411,81 +410,81 @@ const BlitterWidget::Estimate DirectDrawBlitter::frameTimeEst() const {
|
||||
if (vblank && hz == vblankHz) {
|
||||
return Rational(1, hz);
|
||||
}
|
||||
|
||||
|
||||
return BlitterWidget::frameTime();
|
||||
}*/
|
||||
|
||||
long DirectDrawBlitter::sync(const long ft) {
|
||||
if (lpDDSPrimary == NULL)
|
||||
if (lpDDSVideo == NULL)
|
||||
return -1;
|
||||
|
||||
|
||||
lpDDSVideo->PageLock(0);
|
||||
|
||||
|
||||
RECT rcRectDest;
|
||||
GetWindowRect(winId(), &rcRectDest);
|
||||
|
||||
|
||||
const bool vsync = vblank && hz == vblankHz;
|
||||
|
||||
|
||||
if (vsync) {
|
||||
if (!(exclusive && flipping))
|
||||
lpDD->WaitForVerticalBlank(DDWAITVB_BLOCKBEGIN, 0);
|
||||
} else
|
||||
BlitterWidget::sync(ft);
|
||||
|
||||
|
||||
const bool dontwait = exclusive && flipping && !vsync;
|
||||
|
||||
|
||||
HRESULT ddrval = lpDDSBack->Blt(&rcRectDest, lpDDSVideo, NULL, dontwait ? DDBLT_DONOTWAIT : DDBLT_WAIT, NULL);
|
||||
|
||||
|
||||
if (ddrval == DDERR_SURFACELOST) {
|
||||
if (!restoreSurfaces())
|
||||
ddrval = lpDDSBack->Blt(&rcRectDest, lpDDSVideo, NULL, dontwait ? DDBLT_DONOTWAIT : DDBLT_WAIT, NULL);
|
||||
}
|
||||
|
||||
|
||||
lpDDSVideo->PageUnlock(0);
|
||||
|
||||
|
||||
if (ddrval == DD_OK && exclusive && flipping) {
|
||||
ddrval = lpDDSPrimary->Flip(NULL, dontwait ? DDFLIP_DONOTWAIT : DDFLIP_WAIT);
|
||||
}
|
||||
|
||||
|
||||
if (vsync)
|
||||
ftEst.update(getusecs());
|
||||
|
||||
|
||||
if (ddrval != DD_OK && ddrval != DDERR_WASSTILLDRAWING) {
|
||||
std::cout << "final blit failed" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void DirectDrawBlitter::acceptSettings() {
|
||||
bool needReinit = false;
|
||||
|
||||
|
||||
vblank = vblankBox->isChecked();
|
||||
|
||||
|
||||
if (static_cast<int>(deviceIndex) != deviceSelector->currentIndex()) {
|
||||
deviceIndex = deviceSelector->currentIndex();
|
||||
needReinit = true;
|
||||
}
|
||||
|
||||
|
||||
if (flipping != flippingBox->isChecked()) {
|
||||
flipping = flippingBox->isChecked();
|
||||
needReinit |= exclusive;
|
||||
}
|
||||
|
||||
|
||||
if (videoSurface != videoSurfaceBox->isChecked()) {
|
||||
videoSurface = videoSurfaceBox->isChecked();
|
||||
|
||||
|
||||
if (!needReinit && lpDDSVideo) {
|
||||
lpDDSVideo->Release();
|
||||
|
||||
|
||||
if (initVideoSurface()) {
|
||||
lpDDSPrimary->Release();
|
||||
lpDDSPrimary = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (needReinit)
|
||||
reinit();
|
||||
}
|
||||
@ -503,17 +502,17 @@ void DirectDrawBlitter::rateChange(int hz) {
|
||||
}
|
||||
|
||||
void DirectDrawBlitter::paintEvent(QPaintEvent */*event*/) {
|
||||
sync(true);
|
||||
sync(0);
|
||||
}
|
||||
|
||||
void DirectDrawBlitter::setExclusive(const bool exclusive) {
|
||||
if (this->exclusive == exclusive)
|
||||
return;
|
||||
|
||||
|
||||
this->exclusive = exclusive;
|
||||
|
||||
|
||||
// std::cout << "exclusive: " << exclusive << std::endl;
|
||||
|
||||
|
||||
if (flipping)
|
||||
reinit();
|
||||
}
|
||||
|
@ -51,7 +51,7 @@ class DirectDrawBlitter : public BlitterWidget {
|
||||
bool videoSurface;
|
||||
bool exclusive;
|
||||
bool flipping;
|
||||
|
||||
|
||||
static BOOL WINAPI enumCallback(GUID FAR *, char*, char*, LPVOID, HMONITOR);
|
||||
bool initPrimarySurface();
|
||||
bool initVideoSurface();
|
||||
@ -60,13 +60,13 @@ class DirectDrawBlitter : public BlitterWidget {
|
||||
void videoSurfaceBlit();
|
||||
//void detectExclusive();
|
||||
void reinit();
|
||||
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event);
|
||||
/*void resizeEvent(QResizeEvent *event);
|
||||
void moveEvent(QMoveEvent *event);
|
||||
void hideEvent(QHideEvent *event);*/
|
||||
|
||||
|
||||
public:
|
||||
DirectDrawBlitter(PixelBufferSetter setPixelBuffer, QWidget *parent = 0);
|
||||
~DirectDrawBlitter();
|
||||
@ -78,11 +78,13 @@ public:
|
||||
long sync(long turbo);
|
||||
void uninit();
|
||||
void setExclusive(bool exclusive);
|
||||
|
||||
|
||||
QWidget* settingsWidget() { return confWidget.get(); }
|
||||
void acceptSettings();
|
||||
void rejectSettings();
|
||||
|
||||
|
||||
QPaintEngine* paintEngine () const { return NULL; }
|
||||
|
||||
public slots:
|
||||
// void modeChange();
|
||||
void rateChange(int hz);
|
||||
|
@ -38,18 +38,18 @@ QPainterBlitter::QPainterBlitter(PixelBufferSetter setPixelBuffer, QWidget *pare
|
||||
settings.beginGroup("qpainterblitter");
|
||||
bf = settings.value("bf", false).toBool();
|
||||
settings.endGroup();
|
||||
|
||||
|
||||
confWidget->setLayout(new QVBoxLayout);
|
||||
confWidget->layout()->setMargin(0);
|
||||
confWidget->layout()->addWidget(bfBox);
|
||||
bfBox->setChecked(bf);
|
||||
|
||||
|
||||
setAttribute(Qt::WA_OpaquePaintEvent, true);
|
||||
}
|
||||
|
||||
QPainterBlitter::~QPainterBlitter() {
|
||||
uninit();
|
||||
|
||||
|
||||
QSettings settings;
|
||||
settings.beginGroup("qpainterblitter");
|
||||
settings.setValue("bf", bf);
|
||||
@ -61,13 +61,16 @@ void QPainterBlitter::blit() {
|
||||
}
|
||||
|
||||
void QPainterBlitter::paintEvent(QPaintEvent *const event) {
|
||||
if (!image.get())
|
||||
return;
|
||||
|
||||
if (buffer) {
|
||||
if (bf)
|
||||
linearScale<quint32, 0xFF00FF, 0x00FF00, 8>(buffer, reinterpret_cast<quint32*>(image->bits()), inWidth, inHeight, width(), height(), image->bytesPerLine() >> 2);
|
||||
else
|
||||
nearestNeighborScale(buffer, reinterpret_cast<quint32*>(image->bits()), inWidth, inHeight, width(), height(), image->bytesPerLine() >> 2);
|
||||
}
|
||||
|
||||
|
||||
QPainter painter(this);
|
||||
painter.setClipRegion(event->region());
|
||||
painter.drawImage(rect(), *image);
|
||||
@ -81,10 +84,10 @@ void QPainterBlitter::resizeEvent(QResizeEvent */*event*/) {
|
||||
void QPainterBlitter::setBufferDimensions(const unsigned int w, const unsigned int h) {
|
||||
inWidth = w;
|
||||
inHeight = h;
|
||||
|
||||
|
||||
uninit();
|
||||
image.reset(new QImage(width(), height(), QImage::Format_RGB32));
|
||||
|
||||
|
||||
if (width() != static_cast<int>(w) || height() != static_cast<int>(h)) {
|
||||
buffer = new quint32[w * h];
|
||||
setPixelBuffer(buffer, MediaSource::RGB32, w);
|
||||
@ -94,7 +97,7 @@ void QPainterBlitter::setBufferDimensions(const unsigned int w, const unsigned i
|
||||
|
||||
void QPainterBlitter::uninit() {
|
||||
image.reset();
|
||||
|
||||
|
||||
delete []buffer;
|
||||
buffer = NULL;
|
||||
}
|
||||
|
@ -60,14 +60,14 @@ void MainWindow::ButtonHandler::releaseEvent() { source->buttonReleaseEvent(butt
|
||||
class JoyObserver {
|
||||
MainWindow::InputObserver *const observer;
|
||||
const int mask;
|
||||
|
||||
|
||||
void notifyObserver(bool press) {
|
||||
if (press)
|
||||
observer->pressEvent();
|
||||
else
|
||||
observer->releaseEvent();
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
JoyObserver(MainWindow::InputObserver *observer, const int mask) : observer(observer), mask(mask) {}
|
||||
void valueChanged(const int value) { notifyObserver((value & mask) == mask); }
|
||||
@ -75,18 +75,18 @@ public:
|
||||
|
||||
MainWindow::JoystickIniter::JoystickIniter() {
|
||||
SDL_JoystickInit();
|
||||
|
||||
|
||||
SDL_SetEventFilter(SDL_JOYAXISMOTION | SDL_JOYBUTTONCHANGE | SDL_JOYHATMOTION);
|
||||
|
||||
|
||||
const int numJs = SDL_NumJoysticks();
|
||||
|
||||
|
||||
for (int i = 0; i < numJs; ++i) {
|
||||
SDL_Joystick *joy = SDL_JoystickOpen(i);
|
||||
|
||||
|
||||
if (joy)
|
||||
joysticks.push_back(joy);
|
||||
}
|
||||
|
||||
|
||||
SDL_JoystickUpdate();
|
||||
SDL_ClearEvents();
|
||||
}
|
||||
@ -94,7 +94,7 @@ MainWindow::JoystickIniter::JoystickIniter() {
|
||||
MainWindow::JoystickIniter::~JoystickIniter() {
|
||||
for (std::size_t i = 0; i < joysticks.size(); ++i)
|
||||
SDL_JoystickClose(joysticks[i]);
|
||||
|
||||
|
||||
SDL_JoystickQuit();
|
||||
}
|
||||
|
||||
@ -109,12 +109,12 @@ std::size_t MainWindow::SampleBuffer::update(qint16 *const out, MediaSource *con
|
||||
num += spf.num;
|
||||
const long insamples = num / spf.denom;
|
||||
num -= insamples * spf.denom;
|
||||
|
||||
|
||||
samplesBuffered += source->update(sndInBuffer + samplesBuffered * 2, insamples - samplesBuffered);
|
||||
samplesBuffered -= insamples;
|
||||
|
||||
|
||||
std::size_t outsamples = 0;
|
||||
|
||||
|
||||
if (out) {
|
||||
if (resampler->inRate() == resampler->outRate()) {
|
||||
std::memcpy(out, sndInBuffer, insamples * sizeof(qint16) * 2);
|
||||
@ -122,9 +122,9 @@ std::size_t MainWindow::SampleBuffer::update(qint16 *const out, MediaSource *con
|
||||
} else
|
||||
outsamples = resampler->resample(out, sndInBuffer, insamples);
|
||||
}
|
||||
|
||||
|
||||
std::memmove(sndInBuffer, sndInBuffer + insamples * 2, samplesBuffered * sizeof(qint16) * 2);
|
||||
|
||||
|
||||
return outsamples;
|
||||
}
|
||||
|
||||
@ -152,33 +152,33 @@ MainWindow::MainWindow(MediaSource *source,
|
||||
cursorHidden(false)
|
||||
{
|
||||
assert(!videoSourceInfos.empty());
|
||||
|
||||
|
||||
for (unsigned i = 0; i < buttonHandlers.size(); ++i)
|
||||
buttonHandlers[i] = ButtonHandler(source, i);
|
||||
|
||||
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
|
||||
setFocusPolicy(Qt::StrongFocus);
|
||||
|
||||
|
||||
{
|
||||
QSettings settings;
|
||||
settings.beginGroup("mainwindow");
|
||||
resize(settings.value("size", QSize(160, 144)).toSize());
|
||||
settings.endGroup();
|
||||
}
|
||||
|
||||
|
||||
addAudioEngines(audioEngines, winId());
|
||||
audioEngines.push_back(new NullAudioEngine);
|
||||
soundDialog = new SoundDialog(audioEngines, this);
|
||||
connect(soundDialog, SIGNAL(accepted()), this, SLOT(soundSettingsChange()));
|
||||
|
||||
|
||||
inputDialog = new InputDialog(buttonInfos, this);
|
||||
connect(inputDialog, SIGNAL(accepted()), this, SLOT(inputSettingsChange()));
|
||||
|
||||
addBlitterWidgets(blitters, PixelBufferSetter(source));
|
||||
blitters.push_back(new QGLBlitter(PixelBufferSetter(source)));
|
||||
blitters.push_back(new QPainterBlitter(PixelBufferSetter(source)));
|
||||
|
||||
|
||||
for (std::vector<BlitterWidget*>::iterator it = blitters.begin(); it != blitters.end();) {
|
||||
if ((*it)->isUnusable()) {
|
||||
delete *it;
|
||||
@ -189,38 +189,43 @@ MainWindow::MainWindow(MediaSource *source,
|
||||
|
||||
videoDialog = new VideoDialog(blitters, videoSourceInfos, videoSourceLabel, fullModeToggler.get(), aspectRatio, this);
|
||||
connect(videoDialog, SIGNAL(accepted()), this, SLOT(videoSettingsChange()));
|
||||
|
||||
|
||||
blitterContainer = new BlitterContainer(videoDialog, this);
|
||||
blitterContainer->setMinimumSize(160, 144);
|
||||
setCentralWidget(blitterContainer);
|
||||
|
||||
|
||||
for (std::vector<BlitterWidget*>::iterator it = blitters.begin(); it != blitters.end(); ++it) {
|
||||
(*it)->setVisible(false);
|
||||
(*it)->setParent(blitterContainer);
|
||||
}
|
||||
|
||||
source->setPixelBuffer(NULL, MediaSource::RGB32, 0);
|
||||
|
||||
|
||||
videoSettingsChange();
|
||||
inputSettingsChange();
|
||||
soundSettingsChange();
|
||||
|
||||
|
||||
setFrameTime(ftNum, ftDenom);
|
||||
|
||||
|
||||
cursorTimer = new QTimer(this);
|
||||
cursorTimer->setSingleShot(true);
|
||||
cursorTimer->setInterval(2500);
|
||||
connect(cursorTimer, SIGNAL(timeout()), this, SLOT(hideCursor()));
|
||||
|
||||
|
||||
jsTimer = new QTimer(this);
|
||||
jsTimer->setInterval(133);
|
||||
connect(jsTimer, SIGNAL(timeout()), this, SLOT(updateJoysticks()));
|
||||
|
||||
|
||||
setMouseTracking(true);
|
||||
setFocus();
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow() {
|
||||
clearInputVectors();
|
||||
|
||||
|
||||
for (uint i = 0; i < blitters.size(); ++i)
|
||||
delete blitters[i];
|
||||
|
||||
|
||||
for (uint i = 0; i < audioEngines.size(); ++i)
|
||||
delete audioEngines[i];
|
||||
}
|
||||
@ -228,7 +233,7 @@ MainWindow::~MainWindow() {
|
||||
void MainWindow::resetWindowSize(const QSize &s) {
|
||||
if (isFullScreen() || !isVisible())
|
||||
return;
|
||||
|
||||
|
||||
if (s == QSize(-1, -1)) {
|
||||
centralWidget()->setMinimumSize(videoDialog->sourceSize());
|
||||
layout()->setSizeConstraint(QLayout::SetMinimumSize);
|
||||
@ -251,7 +256,7 @@ static void saveWindowSize(const QSize &s) {
|
||||
|
||||
void MainWindow::correctFullScreenGeometry() {
|
||||
const QRect &screenRect = fullModeToggler->fullScreenRect(this);
|
||||
|
||||
|
||||
if (geometry() != screenRect) {
|
||||
setGeometry(screenRect);
|
||||
}
|
||||
@ -266,26 +271,30 @@ void MainWindow::toggleFullScreen() {
|
||||
activateWindow();
|
||||
} else {
|
||||
const int screen = QApplication::desktop()->screenNumber(this);
|
||||
|
||||
|
||||
fullModeToggler->setFullMode(true);
|
||||
saveWindowSize(size());
|
||||
resetWindowSize(QSize(-1, -1));
|
||||
|
||||
|
||||
// If the window is outside the screen it will be moved to the primary screen by Qt.
|
||||
{
|
||||
const QRect &rect = QApplication::desktop()->screenGeometry(screen);
|
||||
QPoint p(pos());
|
||||
|
||||
|
||||
if (p.x() > rect.right())
|
||||
p.setX(rect.right());
|
||||
|
||||
else if (p.x() < rect.left())
|
||||
p.setX(rect.left());
|
||||
|
||||
if (p.y() > rect.bottom())
|
||||
p.setY(rect.bottom());
|
||||
|
||||
else if (p.y() < rect.top())
|
||||
p.setY(rect.top());
|
||||
|
||||
if (p != pos())
|
||||
move(p);
|
||||
}
|
||||
|
||||
|
||||
showFullScreen();
|
||||
correctFullScreenGeometry();
|
||||
blitterContainer->parentExclusiveEvent(hasFocus());
|
||||
@ -298,7 +307,7 @@ void MainWindow::toggleMenuHidden() {
|
||||
// toggleFullScreen();
|
||||
#else
|
||||
menuBar()->setVisible(!menuBar()->isVisible());
|
||||
|
||||
|
||||
if (!menuBar()->isVisible()) {
|
||||
hideCursor();
|
||||
}
|
||||
@ -307,10 +316,10 @@ void MainWindow::toggleMenuHidden() {
|
||||
|
||||
void MainWindow::clearInputVectors() {
|
||||
keyInputs.clear();
|
||||
|
||||
|
||||
for (joymap_t::iterator it = joyInputs.begin(); it != joyInputs.end(); ++it)
|
||||
delete it->second;
|
||||
|
||||
|
||||
joyInputs.clear();
|
||||
}
|
||||
|
||||
@ -326,7 +335,7 @@ void MainWindow::pushInputObserver(const SDL_Event &data, InputObserver *observe
|
||||
|
||||
void MainWindow::inputSettingsChange() {
|
||||
clearInputVectors();
|
||||
|
||||
|
||||
for (std::size_t i = 0; i < inputDialog->getData().size(); ++i)
|
||||
pushInputObserver(inputDialog->getData()[i], &buttonHandlers[i >> 1]);
|
||||
}
|
||||
@ -344,53 +353,47 @@ void MainWindow::uninitBlitter() {
|
||||
void MainWindow::videoSettingsChange() {
|
||||
{
|
||||
const int engineIndex = videoDialog->engine();
|
||||
|
||||
|
||||
if (blitter != blitters[engineIndex]) {
|
||||
bool updatesEnabled = true;
|
||||
bool visible = false;
|
||||
|
||||
|
||||
if (blitter) {
|
||||
updatesEnabled = blitter->updatesEnabled();
|
||||
visible = blitter->isVisible();
|
||||
disconnect(fullModeToggler.get(), SIGNAL(rateChange(int)), blitter, SLOT(rateChange(int)));
|
||||
|
||||
if (running) {
|
||||
|
||||
if (running)
|
||||
uninitBlitter();
|
||||
}
|
||||
|
||||
|
||||
blitter->setVisible(false);
|
||||
}
|
||||
|
||||
|
||||
blitter = blitters[engineIndex];
|
||||
blitter->setVisible(false);
|
||||
blitter->setUpdatesEnabled(updatesEnabled);
|
||||
//connect(fullResToggler, SIGNAL(modeChange()), blitter, SLOT(modeChange()));
|
||||
connect(fullModeToggler.get(), SIGNAL(rateChange(int)), blitter, SLOT(rateChange(int)));
|
||||
fullModeToggler->emitRate();
|
||||
blitterContainer->setBlitter(blitter);
|
||||
blitter->setVisible(visible);
|
||||
|
||||
if (running) {
|
||||
|
||||
if (running)
|
||||
blitter->init();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
source->setVideoSource(videoDialog->sourceIndex());
|
||||
|
||||
|
||||
if (running)
|
||||
blitter->setBufferDimensions(videoDialog->sourceSize().width(), videoDialog->sourceSize().height());
|
||||
|
||||
|
||||
resetWindowSize(videoDialog->winRes());
|
||||
|
||||
|
||||
const unsigned screens = fullModeToggler->screens();
|
||||
|
||||
|
||||
for (unsigned i = 0; i < screens; ++i) {
|
||||
if (fullModeToggler->currentResIndex(i) != videoDialog->fullMode(i) ||
|
||||
fullModeToggler->currentRateIndex(i) != videoDialog->fullRate(i)) {
|
||||
blitterContainer->parentExclusiveEvent(false);
|
||||
fullModeToggler->setMode(i, videoDialog->fullMode(i), videoDialog->fullRate(i));
|
||||
|
||||
|
||||
if (fullModeToggler->isFullMode() && i == fullModeToggler->screen()) {
|
||||
#ifdef Q_WS_WIN
|
||||
showNormal();
|
||||
@ -398,28 +401,28 @@ void MainWindow::videoSettingsChange() {
|
||||
#endif
|
||||
correctFullScreenGeometry();
|
||||
}
|
||||
|
||||
|
||||
blitterContainer->parentExclusiveEvent(isFullScreen() & hasFocus());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// setSampleRate();
|
||||
|
||||
|
||||
blitterContainer->updateLayout();
|
||||
}
|
||||
|
||||
void MainWindow::execDialog(QDialog *const dialog) {
|
||||
const bool pausing = pauseOnDialogExec;
|
||||
|
||||
|
||||
paused += pausing << 1;
|
||||
|
||||
|
||||
if (paused)
|
||||
doPause();
|
||||
|
||||
|
||||
dialog->exec();
|
||||
|
||||
|
||||
paused -= pausing << 1;
|
||||
|
||||
|
||||
if (!paused)
|
||||
doUnpause();
|
||||
}
|
||||
@ -464,18 +467,18 @@ void MainWindow::setFrameTime(unsigned num, unsigned denom) {
|
||||
|
||||
ftNum = num;
|
||||
ftDenom = denom;
|
||||
|
||||
|
||||
if (!turbo)
|
||||
doSetFrameTime(num, denom);
|
||||
|
||||
|
||||
setSampleRate();
|
||||
}
|
||||
|
||||
static void adjustResamplerRate(Array<qint16> &sndOutBuf, Resampler *const resampler, const long maxspf, const long outRate) {
|
||||
resampler->adjustRate(resampler->inRate(), outRate);
|
||||
|
||||
|
||||
const std::size_t sz = resampler->maxOut(maxspf) * 2;
|
||||
|
||||
|
||||
if (sz > sndOutBuf.size())
|
||||
sndOutBuf.reset(sz);
|
||||
}
|
||||
@ -485,7 +488,7 @@ void MainWindow::setSampleRate() {
|
||||
const Rational fr(ftDenom, ftNum);
|
||||
const long insrate = fr.toDouble() * sampleBuffer.samplesPerFrame().toDouble() + 0.5;
|
||||
const long maxspf = sampleBuffer.samplesPerFrame().ceil();
|
||||
|
||||
|
||||
resampler.reset();
|
||||
resampler.reset(ResamplerInfo::get(soundDialog->getResamplerNum()).create(insrate, ae->rate(), maxspf));
|
||||
sndOutBuffer.reset(resampler->maxOut(maxspf) * 2);
|
||||
@ -500,12 +503,12 @@ void MainWindow::setSamplesPerFrame(const long num, const long denom) {
|
||||
void MainWindow::initAudio() {
|
||||
if (ae)
|
||||
ae->uninit();
|
||||
|
||||
|
||||
ae = audioEngines[soundDialog->getEngineIndex()];
|
||||
|
||||
|
||||
if (ae->init(soundDialog->getRate(), soundDialog->getLatency()) < 0)
|
||||
ae = NULL;
|
||||
|
||||
|
||||
setSampleRate();
|
||||
}
|
||||
|
||||
@ -519,51 +522,51 @@ void MainWindow::timerEvent(QTimerEvent */*event*/) {
|
||||
soundEngineFailure();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
updateJoysticks();
|
||||
|
||||
|
||||
const std::size_t outsamples = sampleBuffer.update(turbo ? NULL : static_cast<qint16*>(sndOutBuffer), source, resampler.get());
|
||||
|
||||
|
||||
long syncft = 0;
|
||||
|
||||
|
||||
if (!turbo) {
|
||||
RateEst::Result rsrate;
|
||||
AudioEngine::BufferState bstate;
|
||||
|
||||
|
||||
if (ae->write(sndOutBuffer, outsamples, bstate, rsrate) < 0) {
|
||||
ae->pause();
|
||||
soundEngineFailure();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
const long usecft = blitter->frameTime();
|
||||
syncft = static_cast<float>(usecft - (usecft >> 10)) * ae->rate() / rsrate.est;
|
||||
|
||||
|
||||
if (bstate.fromUnderrun != AudioEngine::BufferState::NOT_SUPPORTED &&
|
||||
bstate.fromUnderrun + outsamples * 2 < bstate.fromOverflow)
|
||||
syncft >>= 1;
|
||||
|
||||
|
||||
const BlitterWidget::Estimate &estft = blitter->frameTimeEst();
|
||||
|
||||
|
||||
if (estft.est) {
|
||||
float est = static_cast<float>(rsrate.est) * estft.est;
|
||||
const float var = static_cast<float>(rsrate.est + rsrate.var) * (estft.est + estft.var) - est;
|
||||
est += var;
|
||||
|
||||
|
||||
if (std::fabs(est - resampler->outRate() * static_cast<float>(usecft - (usecft >> 11))) > var * 2)
|
||||
adjustResamplerRate(sndOutBuffer, resampler.get(), sampleBuffer.samplesPerFrame().ceil(), est / (usecft - (usecft >> 11)));
|
||||
} else if (resampler->outRate() != ae->rate())
|
||||
adjustResamplerRate(sndOutBuffer, resampler.get(), sampleBuffer.samplesPerFrame().ceil(), ae->rate());
|
||||
}
|
||||
|
||||
|
||||
if (blitter->sync(syncft) < 0) {
|
||||
QMessageBox::critical(this, tr("Error"), tr("Video engine failure."));
|
||||
uninitBlitter();
|
||||
blitter->init();
|
||||
blitter->setBufferDimensions(videoDialog->sourceSize().width(), videoDialog->sourceSize().height());
|
||||
|
||||
|
||||
ae->pause();
|
||||
|
||||
|
||||
videoDialog->exec();
|
||||
return;
|
||||
}
|
||||
@ -572,19 +575,19 @@ void MainWindow::timerEvent(QTimerEvent */*event*/) {
|
||||
void MainWindow::run() {
|
||||
if (running)
|
||||
return;
|
||||
|
||||
|
||||
running = true;
|
||||
|
||||
|
||||
#ifdef PLATFORM_WIN32
|
||||
timeBeginPeriod(1);
|
||||
#endif
|
||||
|
||||
|
||||
initAudio();
|
||||
|
||||
blitter->setVisible(true);
|
||||
blitter->init();
|
||||
blitter->setBufferDimensions(videoDialog->sourceSize().width(), videoDialog->sourceSize().height());
|
||||
|
||||
|
||||
if (!paused)
|
||||
timerId = startTimer(0);
|
||||
else
|
||||
@ -594,21 +597,21 @@ void MainWindow::run() {
|
||||
void MainWindow::stop() {
|
||||
if (!running)
|
||||
return;
|
||||
|
||||
|
||||
running = false;
|
||||
jsTimer->stop();
|
||||
|
||||
|
||||
if (timerId) {
|
||||
killTimer(timerId);
|
||||
timerId = 0;
|
||||
}
|
||||
|
||||
|
||||
uninitBlitter();
|
||||
blitter->setVisible(false);
|
||||
|
||||
if (ae)
|
||||
ae->uninit();
|
||||
|
||||
|
||||
#ifdef PLATFORM_WIN32
|
||||
timeEndPeriod(1);
|
||||
#endif
|
||||
@ -617,10 +620,10 @@ void MainWindow::stop() {
|
||||
void MainWindow::doPause() {
|
||||
if (!running || !timerId)
|
||||
return;
|
||||
|
||||
|
||||
if (ae)
|
||||
ae->pause();
|
||||
|
||||
|
||||
killTimer(timerId);
|
||||
timerId = 0;
|
||||
jsTimer->start();
|
||||
@ -629,7 +632,7 @@ void MainWindow::doPause() {
|
||||
void MainWindow::doUnpause() {
|
||||
if (!running || timerId)
|
||||
return;
|
||||
|
||||
|
||||
jsTimer->stop();
|
||||
timerId = startTimer(0);
|
||||
}
|
||||
@ -641,7 +644,7 @@ void MainWindow::pause() {
|
||||
|
||||
void MainWindow::unpause() {
|
||||
paused &= ~1;
|
||||
|
||||
|
||||
if (!paused)
|
||||
doUnpause();
|
||||
}
|
||||
@ -649,7 +652,7 @@ void MainWindow::unpause() {
|
||||
void MainWindow::frameStep() {
|
||||
if (isRunning() && paused == 1) {
|
||||
timerEvent(NULL);
|
||||
|
||||
|
||||
if (ae)
|
||||
ae->pause();
|
||||
}
|
||||
@ -658,11 +661,11 @@ void MainWindow::frameStep() {
|
||||
void MainWindow::setTurbo(bool enable) {
|
||||
if (enable != turbo) {
|
||||
turbo = enable;
|
||||
|
||||
|
||||
if (enable) {
|
||||
if (ae)
|
||||
ae->pause();
|
||||
|
||||
|
||||
doSetFrameTime(1, 0xFFFF);
|
||||
} else
|
||||
doSetFrameTime(ftNum, ftDenom);
|
||||
@ -676,38 +679,38 @@ void MainWindow::toggleTurbo() {
|
||||
void MainWindow::hideCursor() {
|
||||
if (!cursorHidden)
|
||||
centralWidget()->setCursor(Qt::BlankCursor);
|
||||
|
||||
|
||||
cursorHidden = true;
|
||||
}
|
||||
|
||||
void MainWindow::showCursor() {
|
||||
if (cursorHidden)
|
||||
centralWidget()->unsetCursor();
|
||||
|
||||
|
||||
cursorHidden = false;
|
||||
}
|
||||
|
||||
void MainWindow::keyPressEvent(QKeyEvent *e) {
|
||||
e->ignore();
|
||||
|
||||
|
||||
if (isRunning() && !e->isAutoRepeat()) {
|
||||
std::pair<keymap_t::iterator,keymap_t::iterator> range = keyInputs.equal_range(e->key());
|
||||
|
||||
|
||||
while (range.first != range.second) {
|
||||
(range.first->second)->pressEvent();
|
||||
++range.first;
|
||||
}
|
||||
|
||||
|
||||
hideCursor();
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::keyReleaseEvent(QKeyEvent *e) {
|
||||
e->ignore();
|
||||
|
||||
|
||||
if (isRunning() && !e->isAutoRepeat()) {
|
||||
std::pair<keymap_t::iterator,keymap_t::iterator> range = keyInputs.equal_range(e->key());
|
||||
|
||||
|
||||
while (range.first != range.second) {
|
||||
(range.first->second)->releaseEvent();
|
||||
++range.first;
|
||||
@ -718,22 +721,22 @@ void MainWindow::keyReleaseEvent(QKeyEvent *e) {
|
||||
void MainWindow::updateJoysticks() {
|
||||
if (hasFocus()/* || QApplication::desktop()->numScreens() != 1*/) {
|
||||
bool hit = false;
|
||||
|
||||
|
||||
SDL_JoystickUpdate();
|
||||
|
||||
|
||||
SDL_Event ev;
|
||||
|
||||
|
||||
while (pollJsEvent(&ev)) {
|
||||
std::pair<joymap_t::iterator,joymap_t::iterator> range = joyInputs.equal_range(ev.id);
|
||||
|
||||
|
||||
while (range.first != range.second) {
|
||||
(range.first->second)->valueChanged(ev.value);
|
||||
++range.first;
|
||||
}
|
||||
|
||||
|
||||
hit = true;
|
||||
}
|
||||
|
||||
|
||||
if (hit) {
|
||||
#ifdef Q_WS_X11
|
||||
XResetScreenSaver(QX11Info::display());
|
||||
@ -750,11 +753,11 @@ void MainWindow::mouseMoveEvent(QMouseEvent */*e*/) {
|
||||
|
||||
void MainWindow::closeEvent(QCloseEvent */*e*/) {
|
||||
stop();
|
||||
|
||||
|
||||
if (!isFullScreen()) {
|
||||
saveWindowSize(size());
|
||||
}
|
||||
|
||||
|
||||
fullModeToggler->setFullMode(false); // avoid misleading auto-minimize on close focusOut event.
|
||||
}
|
||||
|
||||
@ -772,14 +775,14 @@ void MainWindow::resizeEvent(QResizeEvent */*event*/) {
|
||||
|
||||
void MainWindow::focusOutEvent(QFocusEvent */*event*/) {
|
||||
blitterContainer->parentExclusiveEvent(false);
|
||||
|
||||
|
||||
#ifndef Q_WS_MAC // Minimize is ugly on mac (especially full screen windows) and there doesn't seem to be a "qApp->hide()" which would be more appropriate.
|
||||
if (isFullScreen() && fullModeToggler->isFullMode() && !qApp->activeWindow()/* && QApplication::desktop()->numScreens() == 1*/) {
|
||||
fullModeToggler->setFullMode(false);
|
||||
showMinimized();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
showCursor();
|
||||
cursorTimer->stop();
|
||||
}
|
||||
@ -789,12 +792,12 @@ void MainWindow::focusInEvent(QFocusEvent */*event*/) {
|
||||
fullModeToggler->setFullMode(true);
|
||||
correctFullScreenGeometry();
|
||||
}
|
||||
|
||||
|
||||
blitterContainer->parentExclusiveEvent(isFullScreen());
|
||||
|
||||
|
||||
SDL_JoystickUpdate();
|
||||
SDL_ClearEvents();
|
||||
|
||||
|
||||
cursorTimer->start();
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user