- 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),
device(NULL),
vertexBuffer(NULL),
texture(NULL),
stexture(NULL),
vtexture(NULL),
lastblank(0),
inWidth(1),
inHeight(1),
textRes(1),
@ -200,8 +202,8 @@ void Direct3DBlitter::lockTexture() {
D3DLOCKED_RECT lockedrect;
lockedrect.pBits = NULL;
if (texture)
texture->LockRect(0, &lockedrect, &rect, D3DLOCK_NOSYSLOCK);
if (stexture)
stexture->LockRect(0, &lockedrect, &rect, D3DLOCK_NOSYSLOCK);
setPixelBuffer(lockedrect.pBits, MediaSource::RGB32, lockedrect.Pitch >> 2);
}
@ -271,15 +273,20 @@ void Direct3DBlitter::resetDevice() {
if (device && device->TestCooperativeLevel() != D3DERR_DEVICELOST) {
device->SetTexture(0, NULL);
if (vtexture) {
vtexture->Release();
vtexture = NULL;
}
D3DPRESENT_PARAMETERS presentParams;
getPresentParams(&presentParams);
if (FAILED(device->Reset(&presentParams)) && FAILED(device->Reset(&presentParams))) {
if (texture) {
if (stexture) {
setPixelBuffer(NULL, MediaSource::RGB32, 0);
texture->Release();
texture = NULL;
stexture->Release();
stexture = NULL;
}
if (vertexBuffer) {
@ -297,7 +304,7 @@ void Direct3DBlitter::resetDevice() {
windowed = presentParams.Windowed;
clear = presentParams.BackBufferCount + 1;
setDeviceState();
device->SetTexture(0, texture);
setVideoTexture();
setVertexBuffer();
}
}
@ -351,15 +358,32 @@ void Direct3DBlitter::present() {
resetDevice();
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);
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;
@ -371,9 +395,10 @@ void Direct3DBlitter::init() {
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--;) {
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;
}
}
@ -401,10 +426,15 @@ void Direct3DBlitter::uninit() {
device->SetTexture(0, NULL);
}
if (texture) {
texture->UnlockRect(0);
texture->Release();
texture = NULL;
if (stexture) {
stexture->UnlockRect(0);
stexture->Release();
stexture = NULL;
}
if (vtexture) {
vtexture->Release();
vtexture = NULL;
}
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) {
inWidth = w;
inHeight = h;
if (device) {
device->SetTexture(0, NULL);
if (texture) {
texture->UnlockRect(0);
texture->Release();
texture = NULL;
if (stexture) {
stexture->UnlockRect(0);
stexture->Release();
stexture = NULL;
}
textRes = std::max(w, h);
@ -440,20 +484,20 @@ void Direct3DBlitter::setBufferDimensions(unsigned w, unsigned h) {
textRes |= textRes >> 8;
++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;
device->SetTexture(0, texture);
}
lockTexture();
setVideoTexture();
setVertexBuffer();
}
void Direct3DBlitter::blit() {
if (texture) {
texture->UnlockRect(0);
if (device && stexture && vtexture) {
stexture->UnlockRect(0);
device->UpdateTexture(stexture, vtexture);
draw();
drawn = true;

View File

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

View File

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