From a5f83a3719238832fd2d088322ddbadd5456c8e9 Mon Sep 17 00:00:00 2001 From: sinamas Date: Sun, 19 Oct 2008 20:24:27 +0000 Subject: [PATCH] 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 --- common/rateest.cpp | 19 +- common/rateest.h | 10 +- .../audioengines/directsoundengine.cpp | 181 +++++++------ .../audioengines/directsoundengine.h | 11 +- .../src/framework/blittercontainer.cpp | 14 +- gambatte_qt/src/framework/blitterwidget.cpp | 34 +-- gambatte_qt/src/framework/blitterwidget.h | 18 +- .../blitterwidgets/direct3dblitter.cpp | 169 ++++++------ .../blitterwidgets/direct3dblitter.h | 14 +- .../blitterwidgets/directdrawblitter.cpp | 197 +++++++------- .../blitterwidgets/directdrawblitter.h | 12 +- .../blitterwidgets/qpainterblitter.cpp | 17 +- gambatte_qt/src/framework/mainwindow.cpp | 251 +++++++++--------- 13 files changed, 496 insertions(+), 451 deletions(-) diff --git a/common/rateest.cpp b/common/rateest.cpp index e4648ae..4dfa1ad 100644 --- a/common/rateest.cpp +++ b/common/rateest.cpp @@ -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; } diff --git a/common/rateest.h b/common/rateest.h index dad95aa..e202ed0 100644 --- a/common/rateest.h +++ b/common/rateest.h @@ -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 diff --git a/gambatte_qt/src/framework/audioengines/directsoundengine.cpp b/gambatte_qt/src/framework/audioengines/directsoundengine.cpp index 06f9da5..9d1293e 100644 --- a/gambatte_qt/src/framework/audioengines/directsoundengine.cpp +++ b/gambatte_qt/src/framework/audioengines/directsoundengine.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2007 by Sindre Aam�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 #include #include +#include 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(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(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(), &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(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; } diff --git a/gambatte_qt/src/framework/audioengines/directsoundengine.h b/gambatte_qt/src/framework/audioengines/directsoundengine.h index 03f1f13..c076903 100644 --- a/gambatte_qt/src/framework/audioengines/directsoundengine.h +++ b/gambatte_qt/src/framework/audioengines/directsoundengine.h @@ -26,29 +26,34 @@ class QComboBox; #include #include #include +#include class DirectSoundEngine : public AudioEngine { + RateEst est; const std::auto_ptr confWidget; QCheckBox *const globalBufBox; QComboBox *const deviceSelector; LPDIRECTSOUND lpDS; LPDIRECTSOUNDBUFFER lpDSB; QList 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(); } diff --git a/gambatte_qt/src/framework/blittercontainer.cpp b/gambatte_qt/src/framework/blittercontainer.cpp index fd70a6d..a086c58 100644 --- a/gambatte_qt/src/framework/blittercontainer.cpp +++ b/gambatte_qt/src/framework/blittercontainer.cpp @@ -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(); } diff --git a/gambatte_qt/src/framework/blitterwidget.cpp b/gambatte_qt/src/framework/blitterwidget.cpp index 2e25356..75832f9 100644 --- a/gambatte_qt/src/framework/blitterwidget.cpp +++ b/gambatte_qt/src/framework/blitterwidget.cpp @@ -30,24 +30,24 @@ void FtEst::init(const long frameTime) { } void FtEst::update(const usec_t t) { - if (t - last < static_cast(frameTime + (frameTime >> 2))) { + if (t - last < static_cast(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(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; } }; diff --git a/gambatte_qt/src/framework/blitterwidget.h b/gambatte_qt/src/framework/blitterwidget.h index e8b477e..be5941a 100644 --- a/gambatte_qt/src/framework/blitterwidget.h +++ b/gambatte_qt/src/framework/blitterwidget.h @@ -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; diff --git a/gambatte_qt/src/framework/blitterwidgets/direct3dblitter.cpp b/gambatte_qt/src/framework/blitterwidgets/direct3dblitter.cpp index a830a51..708a6d2 100644 --- a/gambatte_qt/src/framework/blitterwidgets/direct3dblitter.cpp +++ b/gambatte_qt/src/framework/blitterwidgets/direct3dblitter.cpp @@ -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(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(width()) ? backBufferWidth - width() >> 1 : 0; const unsigned yoffset = backBufferHeight > static_cast(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(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(inWidth) / textRes; vertices[2].v = static_cast(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(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(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(); diff --git a/gambatte_qt/src/framework/blitterwidgets/direct3dblitter.h b/gambatte_qt/src/framework/blitterwidgets/direct3dblitter.h index d173146..2a56be1 100644 --- a/gambatte_qt/src/framework/blitterwidgets/direct3dblitter.h +++ b/gambatte_qt/src/framework/blitterwidgets/direct3dblitter.h @@ -28,7 +28,7 @@ class QComboBox; class Direct3DBlitter : public BlitterWidget { typedef IDirect3D9* (WINAPI *Direct3DCreate9Ptr)(UINT); - + FtEst ftEst; const std::auto_ptr 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); }; diff --git a/gambatte_qt/src/framework/blitterwidgets/directdrawblitter.cpp b/gambatte_qt/src/framework/blitterwidgets/directdrawblitter.cpp index 3e466b2..c2e8ab1 100644 --- a/gambatte_qt/src/framework/blitterwidgets/directdrawblitter.cpp +++ b/gambatte_qt/src/framework/blitterwidgets/directdrawblitter.cpp @@ -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(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(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(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(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(); } diff --git a/gambatte_qt/src/framework/blitterwidgets/directdrawblitter.h b/gambatte_qt/src/framework/blitterwidgets/directdrawblitter.h index 2c182ce..e9351a3 100644 --- a/gambatte_qt/src/framework/blitterwidgets/directdrawblitter.h +++ b/gambatte_qt/src/framework/blitterwidgets/directdrawblitter.h @@ -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); diff --git a/gambatte_qt/src/framework/blitterwidgets/qpainterblitter.cpp b/gambatte_qt/src/framework/blitterwidgets/qpainterblitter.cpp index ba761bf..2a51ed5 100644 --- a/gambatte_qt/src/framework/blitterwidgets/qpainterblitter.cpp +++ b/gambatte_qt/src/framework/blitterwidgets/qpainterblitter.cpp @@ -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(buffer, reinterpret_cast(image->bits()), inWidth, inHeight, width(), height(), image->bytesPerLine() >> 2); else nearestNeighborScale(buffer, reinterpret_cast(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(w) || height() != static_cast(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; } diff --git a/gambatte_qt/src/framework/mainwindow.cpp b/gambatte_qt/src/framework/mainwindow.cpp index 4e8d390..acf1c44 100644 --- a/gambatte_qt/src/framework/mainwindow.cpp +++ b/gambatte_qt/src/framework/mainwindow.cpp @@ -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::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::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 &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(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(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(rsrate.est) * estft.est; const float var = static_cast(rsrate.est + rsrate.var) * (estft.est + estft.var) - est; est += var; - + if (std::fabs(est - resampler->outRate() * static_cast(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 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 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 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(); }