- Direct3DBlitter and DirectDrawBlitter: Force blocking updates when sync to vblank is enabled.

Some updates only block if there's a prior unfinished update in progress. This screws up frame time estimation
  in turn screwing up vsync. To fix this we do a double update (and extra blit) if close to a frame time
  period has passed since the last update when sync to vblank is enabled. I really should have noticed this earlier
  as it pretty much breaks vsync adaption completely.
- Direct3DBlitter: Use the D3DCREATE_FPU_PRESERVE flag when creating device. Omitting this flag can screw up floating point
  calculations in other parts of the code. For instance WASAPI cursor timestamps get utterly screwed up here.
- Direct3DBlitter: It appears that managed textures are updated before they are unlocked, which screws up redraws, making
  things appear choppy in some situations. Use a default memory texture and a system memory texture and the UpdateTexure
  method instead.



git-svn-id: https://gambatte.svn.sourceforge.net/svnroot/gambatte@214 9dfb2916-2d38-0410-aef4-c5fe6c9ffc24
This commit is contained in:
sinamas 2009-01-09 01:59:53 +00:00
parent e3f1d0ecb1
commit d9edc2e78d
3 changed files with 111 additions and 39 deletions

View File

@ -68,7 +68,9 @@ Direct3DBlitter::Direct3DBlitter(PixelBufferSetter setPixelBuffer, QWidget *pare
d3d(NULL), d3d(NULL),
device(NULL), device(NULL),
vertexBuffer(NULL), vertexBuffer(NULL),
texture(NULL), stexture(NULL),
vtexture(NULL),
lastblank(0),
inWidth(1), inWidth(1),
inHeight(1), inHeight(1),
textRes(1), textRes(1),
@ -200,8 +202,8 @@ void Direct3DBlitter::lockTexture() {
D3DLOCKED_RECT lockedrect; D3DLOCKED_RECT lockedrect;
lockedrect.pBits = NULL; lockedrect.pBits = NULL;
if (texture) if (stexture)
texture->LockRect(0, &lockedrect, &rect, D3DLOCK_NOSYSLOCK); stexture->LockRect(0, &lockedrect, &rect, D3DLOCK_NOSYSLOCK);
setPixelBuffer(lockedrect.pBits, MediaSource::RGB32, lockedrect.Pitch >> 2); setPixelBuffer(lockedrect.pBits, MediaSource::RGB32, lockedrect.Pitch >> 2);
} }
@ -271,15 +273,20 @@ void Direct3DBlitter::resetDevice() {
if (device && device->TestCooperativeLevel() != D3DERR_DEVICELOST) { if (device && device->TestCooperativeLevel() != D3DERR_DEVICELOST) {
device->SetTexture(0, NULL); device->SetTexture(0, NULL);
if (vtexture) {
vtexture->Release();
vtexture = NULL;
}
D3DPRESENT_PARAMETERS presentParams; D3DPRESENT_PARAMETERS presentParams;
getPresentParams(&presentParams); getPresentParams(&presentParams);
if (FAILED(device->Reset(&presentParams)) && FAILED(device->Reset(&presentParams))) { if (FAILED(device->Reset(&presentParams)) && FAILED(device->Reset(&presentParams))) {
if (texture) { if (stexture) {
setPixelBuffer(NULL, MediaSource::RGB32, 0); setPixelBuffer(NULL, MediaSource::RGB32, 0);
texture->Release(); stexture->Release();
texture = NULL; stexture = NULL;
} }
if (vertexBuffer) { if (vertexBuffer) {
@ -297,7 +304,7 @@ void Direct3DBlitter::resetDevice() {
windowed = presentParams.Windowed; windowed = presentParams.Windowed;
clear = presentParams.BackBufferCount + 1; clear = presentParams.BackBufferCount + 1;
setDeviceState(); setDeviceState();
device->SetTexture(0, texture); setVideoTexture();
setVertexBuffer(); setVertexBuffer();
} }
} }
@ -351,15 +358,32 @@ void Direct3DBlitter::present() {
resetDevice(); resetDevice();
if (device) { if (device) {
IDirect3DSwapChain9 *swapChain = NULL; if (swapInterval) {
const unsigned long estft = ftEst.est();
const usec_t swaplimit = getusecs() - lastblank > estft - estft / 32 ? estft * 2 - 500000 / hz : 0;
device->GetSwapChain(0, &swapChain);
if (swapChain) {
swapChain->Present(NULL, NULL, 0, NULL, vblankblit && !swapInterval ? 1 : 0);
swapChain->Release();
} else
device->Present(NULL, NULL, 0, NULL); device->Present(NULL, NULL, 0, NULL);
usec_t now = getusecs();
if (now - lastblank < swaplimit) {
drawn = false;
draw();
device->Present(NULL, NULL, 0, NULL);
now = getusecs();
}
lastblank = now;
} else {
IDirect3DSwapChain9 *swapChain = NULL;
device->GetSwapChain(0, &swapChain);
if (swapChain) {
swapChain->Present(NULL, NULL, 0, NULL, vblankblit ? 1 : 0);
swapChain->Release();
} else
device->Present(NULL, NULL, 0, NULL);
}
} }
drawn = false; drawn = false;
@ -371,9 +395,10 @@ void Direct3DBlitter::init() {
getPresentParams(&presentParams); getPresentParams(&presentParams);
// Omitting the D3DCREATE_FPU_PRESERVE will cause problems with floating point code elsewhere. For instance WASAPI screws up cursor time stamps.
for (unsigned n = 2; n--;) { for (unsigned n = 2; n--;) {
if (!FAILED(d3d->CreateDevice(adapterIndex, D3DDEVTYPE_HAL, if (!FAILED(d3d->CreateDevice(adapterIndex, D3DDEVTYPE_HAL,
parentWidget()->parentWidget()->winId(), D3DCREATE_SOFTWARE_VERTEXPROCESSING, &presentParams, &device))) { parentWidget()->parentWidget()->winId(), D3DCREATE_FPU_PRESERVE | D3DCREATE_SOFTWARE_VERTEXPROCESSING, &presentParams, &device))) {
break; break;
} }
} }
@ -401,10 +426,15 @@ void Direct3DBlitter::uninit() {
device->SetTexture(0, NULL); device->SetTexture(0, NULL);
} }
if (texture) { if (stexture) {
texture->UnlockRect(0); stexture->UnlockRect(0);
texture->Release(); stexture->Release();
texture = NULL; stexture = NULL;
}
if (vtexture) {
vtexture->Release();
vtexture = NULL;
} }
if (vertexBuffer) { if (vertexBuffer) {
@ -418,17 +448,31 @@ void Direct3DBlitter::uninit() {
} }
} }
void Direct3DBlitter::setVideoTexture() {
if (device) {
device->SetTexture(0, NULL);
if (vtexture) {
vtexture->Release();
vtexture = NULL;
}
if (FAILED(device->CreateTexture(textRes, textRes, 1, 0, D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, &vtexture, NULL)))
std::cout << "device->CreateTexture failed" << std::endl;
device->SetTexture(0, vtexture);
}
}
void Direct3DBlitter::setBufferDimensions(unsigned w, unsigned h) { void Direct3DBlitter::setBufferDimensions(unsigned w, unsigned h) {
inWidth = w; inWidth = w;
inHeight = h; inHeight = h;
if (device) { if (device) {
device->SetTexture(0, NULL); if (stexture) {
stexture->UnlockRect(0);
if (texture) { stexture->Release();
texture->UnlockRect(0); stexture = NULL;
texture->Release();
texture = NULL;
} }
textRes = std::max(w, h); textRes = std::max(w, h);
@ -440,20 +484,20 @@ void Direct3DBlitter::setBufferDimensions(unsigned w, unsigned h) {
textRes |= textRes >> 8; textRes |= textRes >> 8;
++textRes; ++textRes;
if (FAILED(device->CreateTexture(textRes, textRes, 1, 0, D3DFMT_X8R8G8B8, D3DPOOL_MANAGED, &texture, NULL))) if (FAILED(device->CreateTexture(textRes, textRes, 1, 0, D3DFMT_X8R8G8B8, D3DPOOL_SYSTEMMEM, &stexture, NULL)))
std::cout << "device->CreateTexture failed" << std::endl; std::cout << "device->CreateTexture failed" << std::endl;
device->SetTexture(0, texture);
} }
lockTexture(); lockTexture();
setVideoTexture();
setVertexBuffer(); setVertexBuffer();
} }
void Direct3DBlitter::blit() { void Direct3DBlitter::blit() {
if (texture) { if (device && stexture && vtexture) {
texture->UnlockRect(0); stexture->UnlockRect(0);
device->UpdateTexture(stexture, vtexture);
draw(); draw();
drawn = true; drawn = true;

View File

@ -42,7 +42,9 @@ class Direct3DBlitter : public BlitterWidget {
IDirect3D9 *d3d; IDirect3D9 *d3d;
IDirect3DDevice9* device; IDirect3DDevice9* device;
IDirect3DVertexBuffer9* vertexBuffer; IDirect3DVertexBuffer9* vertexBuffer;
IDirect3DTexture9 *texture; IDirect3DTexture9 *stexture;
IDirect3DTexture9 *vtexture;
usec_t lastblank;
unsigned inWidth; unsigned inWidth;
unsigned inHeight; unsigned inHeight;
unsigned textRes; unsigned textRes;
@ -64,6 +66,7 @@ class Direct3DBlitter : public BlitterWidget {
void getPresentParams(D3DPRESENT_PARAMETERS *presentParams) const; void getPresentParams(D3DPRESENT_PARAMETERS *presentParams) const;
void lockTexture(); void lockTexture();
void setVertexBuffer(); void setVertexBuffer();
void setVideoTexture();
void setFilter(); void setFilter();
void setDeviceState(); void setDeviceState();
void resetDevice(); void resetDevice();

View File

@ -571,15 +571,40 @@ long DirectDrawBlitter::sync(const long ft) {
HRESULT ddrval = DD_OK; HRESULT ddrval = DD_OK;
if (exclusive & flipping) { if (exclusive & flipping) {
const bool wf = swapInterval || !vblankflip; if (swapInterval) {
const unsigned long estft = ftEst.est();
const usec_t swaplimit = getusecs() - lastblank > estft - estft / 32 ? estft * 2 - 500000 / hz : 0;
if (!blitted) if (!blitted)
finalBlit(wf ? DDBLT_WAIT : DDBLT_DONOTWAIT); finalBlit(DDBLT_WAIT);
if (lpDDSPrimary && blitted) const DWORD flipflags = DDFLIP_WAIT | (swapInterval == 2 ? DDFLIP_INTERVAL2 : 0);
ddrval = lpDDSPrimary->Flip(NULL,
(wf ? DDFLIP_WAIT : DDFLIP_DONOTWAIT) | if (lpDDSPrimary)
((vblankflip | swapInterval) ? (swapInterval == 2 ? DDFLIP_INTERVAL2 : 0) : DDFLIP_NOVSYNC)); ddrval = lpDDSPrimary->Flip(NULL, flipflags);
usec_t now = getusecs();
if (now - lastblank < swaplimit) {
blitted = false;
finalBlit(DDBLT_WAIT);
if (lpDDSPrimary)
ddrval = lpDDSPrimary->Flip(NULL, flipflags);
now = getusecs();
}
lastblank = now;
} else {
if (!blitted)
finalBlit(vblankflip ? DDBLT_DONOTWAIT : DDBLT_WAIT);
if (lpDDSPrimary && blitted)
ddrval = lpDDSPrimary->Flip(NULL,
(vblankflip ? DDFLIP_DONOTWAIT : DDFLIP_WAIT) |
(vblankflip ? 0 : DDFLIP_NOVSYNC));
}
} else { } else {
if (swapInterval) { if (swapInterval) {
const usec_t refreshPeriod = 1000000 / hz; const usec_t refreshPeriod = 1000000 / hz;
@ -595,7 +620,7 @@ long DirectDrawBlitter::sync(const long ft) {
} }
if (swapInterval) if (swapInterval)
ftEst.update(getusecs()); ftEst.update(lastblank);
blitted = false; blitted = false;