Graphics: improved the performance of DX9 mode

This commit is contained in:
NovaRain
2020-09-15 10:21:35 +08:00
parent 0ce02e2a12
commit f16ba16d21
3 changed files with 101 additions and 188 deletions
+88 -177
View File
@@ -32,7 +32,7 @@ namespace sfall
#define SAFERELEASE(a) { if (a) { a->Release(); a = nullptr; } }
typedef HRESULT (__stdcall *DDrawCreateProc)(void*, IDirectDraw**, void*);
typedef IDirect3D9* (__stdcall *D3DCreateProc)(UINT version);
//typedef IDirect3D9* (__stdcall *D3DCreateProc)(UINT version);
static IDirectDrawSurface* primaryDDSurface = nullptr;
@@ -45,8 +45,6 @@ DWORD Graphics::mode;
bool Graphics::PlayAviMovie = false;
bool Graphics::AviMovieWidthFit = false;
static BYTE* titlesBuffer = nullptr;
static DWORD yoffset;
//static DWORD xoffset;
@@ -133,8 +131,8 @@ static const char* gpuEffect =
"}"
"float4 P0( in float2 Tex : TEXCOORD0 ) : COLOR0 {"
"float3 result = tex1D(s1, tex2D(s0, Tex).a);"
"return float4(result.b, result.g, result.r, 1);" // GPU swap R <> B
"float3 result = tex1D(s1, tex2D(s0, Tex).a);" // get color in palette
"return float4(result.b, result.g, result.r, 1);" // swap R <> B
"}"
"technique T0"
@@ -142,7 +140,7 @@ static const char* gpuEffect =
"pass p0 { PixelShader = compile ps_2_0 P0(); }"
"}";
static D3DXHANDLE gpuBltBuf;
static D3DXHANDLE gpuBltMainTex;
static D3DXHANDLE gpuBltPalette;
static D3DXHANDLE gpuBltHead;
static D3DXHANDLE gpuBltHeadSize;
@@ -204,7 +202,7 @@ const float* Graphics::rcpresGet() {
static void GetDisplayMode(D3DDISPLAYMODE &ddm) {
ZeroMemory(&ddm, sizeof(ddm));
d3d9->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &ddm);
dlog_f("Display mode format id: %d\n", DL_INIT, ddm.Format);
dlog_f("\nDisplay mode format id: %d", DL_INIT, ddm.Format);
}
static void ResetDevice(bool createNew) {
@@ -246,7 +244,7 @@ static void ResetDevice(bool createNew) {
if (Graphics::GPUBlt) {
D3DXCreateEffect(d3d9Device, gpuEffect, strlen(gpuEffect), 0, 0, 0, 0, &gpuBltEffect, 0);
gpuBltBuf = gpuBltEffect->GetParameterByName(0, "image");
gpuBltMainTex = gpuBltEffect->GetParameterByName(0, "image");
gpuBltPalette = gpuBltEffect->GetParameterByName(0, "palette");
// for head textures
gpuBltHead = gpuBltEffect->GetParameterByName(0, "head");
@@ -277,7 +275,7 @@ static void ResetDevice(bool createNew) {
d3d9Device->CreateTexture(ResWidth, ResHeight, 1, D3DUSAGE_RENDERTARGET, D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, &sTex2, 0);
if (Graphics::GPUBlt) {
d3d9Device->CreateTexture(256, 1, 1, D3DUSAGE_DYNAMIC, D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, &gpuPalette, 0);
gpuBltEffect->SetTexture(gpuBltBuf, mainTex);
gpuBltEffect->SetTexture(gpuBltMainTex, mainTex);
gpuBltEffect->SetTexture(gpuBltPalette, gpuPalette);
}
@@ -325,8 +323,8 @@ static void ResetDevice(bool createNew) {
d3d9Device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
d3d9Device->SetRenderState(D3DRS_LIGHTING, false);
d3d9Device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
d3d9Device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);
//d3d9Device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_NONE); //D3DTEXF_LINEAR
//d3d9Device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_NONE); //D3DTEXF_LINEAR
//d3d9Device->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(255, 0, 255), 1.0f, 0); // for debbuging
dlogr(" Done", DL_MAIN);
@@ -398,22 +396,22 @@ static void Present() {
}
}
void Graphics::RefreshGraphics() {
if (DeviceLost || Graphics::PlayAviMovie) return;
static void Refresh() {
if (DeviceLost) return;
d3d9Device->BeginScene();
d3d9Device->SetStreamSource(0, vBuffer, 0, sizeof(VertexFormat));
d3d9Device->SetRenderTarget(0, sSurf1);
UINT unused;
if (Graphics::GPUBlt && ScriptShaders::Count()) {
if (ScriptShaders::Count() && Graphics::GPUBlt) {
gpuBltEffect->Begin(&unused, 0);
gpuBltEffect->BeginPass(0);
d3d9Device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
gpuBltEffect->EndPass();
gpuBltEffect->End();
d3d9Device->StretchRect(sSurf1, 0, sSurf2, 0, D3DTEXF_NONE); // copy: sSurf1 to sSurf2
d3d9Device->StretchRect(sSurf1, 0, sSurf2, 0, D3DTEXF_NONE); // copy sSurf1 to sSurf2
d3d9Device->SetTexture(0, sTex2);
} else {
d3d9Device->SetTexture(0, mainTex);
@@ -423,12 +421,12 @@ void Graphics::RefreshGraphics() {
d3d9Device->SetStreamSource(0, vBuffer2, 0, sizeof(VertexFormat));
d3d9Device->SetRenderTarget(0, backBuffer);
if (Graphics::GPUBlt && !ScriptShaders::Count()) {
if (!ScriptShaders::Count() && Graphics::GPUBlt) {
gpuBltEffect->Begin(&unused, 0);
gpuBltEffect->BeginPass(0);
}
d3d9Device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
if (Graphics::GPUBlt && !ScriptShaders::Count()) {
if (!ScriptShaders::Count() && Graphics::GPUBlt) {
gpuBltEffect->EndPass();
gpuBltEffect->End();
}
@@ -437,6 +435,10 @@ void Graphics::RefreshGraphics() {
Present();
}
void Graphics::RefreshGraphics() {
if (!Graphics::PlayAviMovie) Refresh();
}
HRESULT Graphics::CreateMovieTexture(D3DSURFACE_DESC &desc) {
HRESULT hr = d3d9Device->CreateTexture(desc.Width, desc.Height, 1, 0, desc.Format, D3DPOOL_DEFAULT, &movieTex, nullptr);
if (movieTex) movieTex->GetLevelDesc(0, &movieDesc);
@@ -603,17 +605,19 @@ class FakeDirectDrawSurface : IDirectDrawSurface {
private:
ULONG Refs;
bool isPrimary;
BYTE* lockTarget;
BYTE* lockTarget = nullptr;
public:
static bool IsPlayMovie;
static bool subTitlesShow;
FakeDirectDrawSurface(bool primary) {
Refs = 1;
isPrimary = primary;
lockTarget = new BYTE[ResWidth * ResHeight];
if (!windowInit) std::memset(lockTarget, 0, ResWidth * ResHeight);
if (primary && Graphics::GPUBlt) {
// use the mainTex texture as a buffer
} else {
lockTarget = new BYTE[ResWidth * ResHeight];
}
}
/* IUnknown methods */
@@ -635,59 +639,32 @@ public:
HRESULT __stdcall AddAttachedSurface(LPDIRECTDRAWSURFACE) { UNUSEDFUNCTION; }
HRESULT __stdcall AddOverlayDirtyRect(LPRECT) { UNUSEDFUNCTION; }
HRESULT __stdcall Blt(LPRECT a, LPDIRECTDRAWSURFACE b, LPRECT c, DWORD d, LPDDBLTFX e) { // called 0x4868DA movie_MVE_ShowFrame_ (used for game movies, only for w/o HRP)
mveDesc.dwHeight = (a->bottom - a->top);
HRESULT __stdcall Blt(LPRECT dsc, LPDIRECTDRAWSURFACE b, LPRECT scr, DWORD d, LPDDBLTFX e) { // called 0x4868DA movie_MVE_ShowFrame_ (used for game movies, only for w/o HRP)
mveDesc.dwHeight = (dsc->bottom - dsc->top);
yoffset = (ResHeight - mveDesc.dwHeight) / 2;
mveDesc.lPitch = (a->right - a->left);
mveDesc.lPitch = (dsc->right - dsc->left);
//xoffset = (ResWidth - mveDesc.lPitch) / 2;
dlog_f("\nBlt: [mveDesc: w:%d, h:%d]", DL_INIT, mveDesc.lPitch, mveDesc.dwHeight);
//dlog_f("\nBlt: [mveDesc: w:%d, h:%d]", DL_INIT, mveDesc.lPitch, mveDesc.dwHeight);
IsPlayMovie = true;
//mainTexLock = true;
BYTE* lockTarget = ((FakeDirectDrawSurface*)b)->lockTarget;
D3DLOCKED_RECT dRect;
mainTex->LockRect(0, &dRect, a, 0);
mainTex->LockRect(0, &dRect, dsc, 0);
DWORD width = mveDesc.lPitch; // the current size of the width of the mve movie
int pitch = dRect.Pitch;
if (Graphics::GPUBlt) {
char* pBits = (char*)dRect.pBits;
if (subTitlesShow) {
subTitlesShow = false;
DWORD bottom = yoffset + mveDesc.dwHeight;
long x_shift = (ResWidth - width) / 2; // shift the position of subtitles relative to the width difference
for (DWORD y = bottom; y < ResHeight; y++) {
//if (y < yoffset || y > bottom) { // paste subtitles excluding video region
CopyMemory(&pBits[(y - yoffset) * pitch], &titlesBuffer[(y * ResWidth) + x_shift], width);
//}
}
}
for (DWORD y = 0; y < mveDesc.dwHeight; y++) {
CopyMemory(&pBits[y * pitch], &lockTarget[y * width], width);
}
//if (ResWidth > 640) {
// for (DWORD y = yoffset; y < ResHeight - yoffset; y++) {
// ZeroMemory(&pBits[y*dRect.Pitch], xoffset);
// ZeroMemory(&pBits[y*dRect.Pitch + (ResWidth - xoffset)], xoffset);
// }
//}
} else {
pitch /= 4;
if (subTitlesShow) {
subTitlesShow = false;
DWORD bottom = yoffset + mveDesc.dwHeight;
long x_shift = (ResWidth - width) / 2; // shift the position of subtitles relative to the width difference
for (DWORD y = bottom; y < ResHeight; y++) {
//if (y < yoffset || y > bottom) {
int yyp = (y - yoffset) * pitch;
int yw = (y * ResWidth) + x_shift;
for (DWORD x = 0; x < width; x++) {
((DWORD*)dRect.pBits)[yyp + x] = palette[titlesBuffer[yw + x]];
}
//}
}
}
for (DWORD y = 0; y < mveDesc.dwHeight; y++) {
int yp = y * pitch;
int yw = y * width;
@@ -695,12 +672,6 @@ public:
((DWORD*)dRect.pBits)[yp + x] = palette[lockTarget[yw + x]];
}
}
//if (ResWidth > 640) {
// for (DWORD y = yoffset; y < ResHeight - yoffset; y++) {
// for (DWORD x = 0; x < xoffset; x++) ((DWORD*)dRect.pBits)[(y)*dRect.Pitch + x] = 0;
// for (DWORD x = ResWidth - xoffset; x < ResWidth; x++) ((DWORD*)dRect.pBits)[(y)*dRect.Pitch + x] = 0;
// }
//}
}
mainTex->UnlockRect(0);
//mainTexLock = false;
@@ -755,20 +726,44 @@ public:
0x486861 movie_MVE_ShowFrame_ [c=1] (capture, never called)
*/
HRESULT __stdcall Lock(LPRECT a, LPDDSURFACEDESC b, DWORD c, HANDLE d) {
if (DeviceLost) return DDERR_SURFACELOST;
if (isPrimary) {
*b = surfaceDesc;
if (Graphics::GPUBlt) {
D3DLOCKED_RECT buf;
HRESULT hr = mainTex->LockRect(0, &buf, 0, 0);
if (hr) goto surface; // lock failed, use old method
mainTexLock = true;
b->lpSurface = buf.pBits;
b->lPitch = buf.Pitch;
} else {
surface:
*b = surfaceDesc;
b->lpSurface = lockTarget;
}
} else {
mveDesc.lPitch = *(DWORD*)FO_VAR_lastMovieW;
mveDesc.dwHeight = *(DWORD*)FO_VAR_lastMovieH;
dlog_f("\nLock: [mveDesc: w:%d, h:%d]", DL_INIT, mveDesc.lPitch, mveDesc.dwHeight);
//dlog_f("\nLock: [mveDesc: w:%d, h:%d]", DL_INIT, mveDesc.lPitch, mveDesc.dwHeight);
*b = mveDesc;
b->lpSurface = lockTarget;
}
b->lpSurface = lockTarget;
return DD_OK;
}
HRESULT __stdcall ReleaseDC(HDC) { UNUSEDFUNCTION; }
HRESULT __stdcall Restore() { UNUSEDFUNCTION; } // called 0x4CB907 GNW95_ShowRect_
HRESULT __stdcall Restore() { // called 0x4CB907 GNW95_ShowRect_
if (!d3d9Device) return DD_FALSE;
if (d3d9Device->TestCooperativeLevel() == D3DERR_DEVICENOTRESET) {
ResetDevice(false);
DeviceLost = false;
fo::RefreshGNW();
}
return !DeviceLost;
}
HRESULT __stdcall SetClipper(LPDIRECTDRAWCLIPPER) { UNUSEDFUNCTION; }
HRESULT __stdcall SetColorKey(DWORD, LPDDCOLORKEY) { UNUSEDFUNCTION; }
HRESULT __stdcall SetOverlayPosition(LONG, LONG) { UNUSEDFUNCTION; }
@@ -789,7 +784,7 @@ public:
int yp = y * pitch;
int yw = y * width;
for (DWORD x = 0; x < width; x++) {
pBits[yp + x] = palette[lockTarget[yw + x]];
pBits[yp + x] = palette[lockTarget[yw + x]]; // takes the color index in the palette and copies the color value to the texture surface
}
}
mainTex->UnlockRect(0);
@@ -797,119 +792,43 @@ public:
return DD_OK;
}
#define FASTCOPY(a) __asm { \
__asm movzx eax, [esi] \
__asm mov eax, [ebx + eax * 4] \
__asm inc esi \
__asm mov dword ptr ds:[edi + a], eax \
}
/* Called from:
0x4CB8F0 GNW95_ShowRect_
0x4CB8F0 GNW95_ShowRect_ (common game, primary)
0x486A87 movieShowFrame_
0x4CBC5A GNW95_zero_vid_mem_ (clear surface)
0x4F5ECC sub_4F5E60 (from MVE_rmStepMovie_)
0x4868BA movie_MVE_ShowFrame_ (capture, never called)
0x4CBC5A GNW95_zero_vid_mem_ (clear surface)
0x4F5ECC sub_4F5E60 (from MVE_rmStepMovie_)
0x4868BA movie_MVE_ShowFrame_ (capture never call)
*/
HRESULT __stdcall Unlock(LPVOID) { // common game (primary)
HRESULT __stdcall Unlock(LPVOID) {
//dlog("\nUnlock", DL_INIT);
if (!isPrimary || !d3d9Device) return DD_OK;
if ((DeviceLost && Restore() == DD_FALSE) || !isPrimary) return DD_OK;
//dlog("\nUnlock primary", DL_INIT);
if (DeviceLost) {
if (d3d9Device->TestCooperativeLevel() == D3DERR_DEVICENOTRESET) {
dlog("\nResetDevice", DL_INIT);
ResetDevice(false);
DeviceLost = false;
}
if (DeviceLost) return DD_OK;
}
//dlog("\nUnlock -> primary", DL_INIT);
mainTexLock = true;
if (Graphics::GPUBlt == 0) {
mainTexLock = true;
D3DLOCKED_RECT dRect;
mainTex->LockRect(0, &dRect, 0, 0);
D3DLOCKED_RECT dRect;
mainTex->LockRect(0, &dRect, 0, 0);
int pitch = dRect.Pitch;
DWORD width = ResWidth;
if (Graphics::GPUBlt) {
if (IsPlayMovie) { // for subtitles (w/o HRP)
subTitlesShow = true;
if (!titlesBuffer) titlesBuffer = new BYTE[ResWidth * ResHeight]();
DWORD bottom = (yoffset + mveDesc.dwHeight);
for (DWORD y = bottom; y < ResHeight; y++) {
//if (y < yoffset || y > bottom)
CopyMemory(&titlesBuffer[y * width], &lockTarget[y * width], width); // copy subtitles region to buffer
}
} else {
char* pBits = (char*)dRect.pBits;
for (DWORD y = 0; y < ResHeight; y++) {
CopyMemory(&pBits[y * pitch], &lockTarget[y * width], width);
}
}
} else {
pitch /= 4;
if (IsPlayMovie) { // for subtitles (w/o HRP)
subTitlesShow = true;
if (!titlesBuffer) titlesBuffer = new BYTE[ResWidth * ResHeight]();
DWORD bottom = (yoffset + mveDesc.dwHeight);
for (DWORD y = bottom; y < ResHeight; y++) {
//if (y >= yoffset && y <= bottom) continue;
int yw = y * width;
for (DWORD x = 0; x < width; x++) {
titlesBuffer[yw + x] = lockTarget[yw + x];
}
}
} else if (!(ResWidth % 8)) {
DWORD* source = (DWORD*)&lockTarget[0];
pitch = (pitch - ResWidth) * 4;
DWORD width = ResWidth / 8;
__asm {
mov esi, source; // source surface
mov edi, dRect.pBits; // target surface
lea ebx, [palette];
mov edx, ResHeight;
start:
mov ecx, width;
start2:
movzx eax, [esi]; // color index in the palette
mov eax, [ebx + eax * 4]; // take the color value from the palette
inc esi;
mov [edi], eax; // write the color to dRect.pBits
FASTCOPY(4)
FASTCOPY(8)
FASTCOPY(12)
FASTCOPY(16)
FASTCOPY(20)
FASTCOPY(24)
FASTCOPY(28)
lea edi, [edi + 32];
dec ecx;
jnz start2;
add edi, pitch;
dec edx;
jnz start;
}
} else {
DWORD* pBits = (DWORD*)dRect.pBits;
for (DWORD y = 0; y < ResHeight; y++) {
int yp = y * pitch;
int yw = y * width;
for (DWORD x = 0; x < width; x++) {
pBits[yp + x] = palette[lockTarget[yw + x]];
}
int pitch = dRect.Pitch / 4;
DWORD* pBits = (DWORD*)dRect.pBits;
DWORD width = ResWidth;
// slow copy method
for (DWORD y = 0; y < ResHeight; y++) {
int yp = y * pitch;
int yw = y * width;
for (DWORD x = 0; x < width; x++) {
pBits[yp + x] = palette[lockTarget[yw + x]];
}
}
}
mainTex->UnlockRect(0);
if (mainTexLock) mainTex->UnlockRect(0);
mainTexLock = false;
if (!IsPlayMovie && !Graphics::PlayAviMovie) {
subTitlesShow = false;
//dlog("\nUnlock: -> RefreshGraphics", DL_INIT);
Graphics::RefreshGraphics();
//dlog("\nUnlock -> RefreshGraphics", DL_INIT);
Refresh();
}
IsPlayMovie = false;
return DD_OK;
@@ -921,7 +840,6 @@ public:
};
bool FakeDirectDrawSurface::IsPlayMovie;
bool FakeDirectDrawSurface::subTitlesShow;
class FakeDirectDrawPalette : IDirectDrawPalette {
private:
@@ -975,12 +893,8 @@ public:
if (FakeDirectDrawSurface::IsPlayMovie) return DD_OK; // prevents flickering at the beginning of playback (w/o HRP & GPUBlt=2)
}
if (!Graphics::PlayAviMovie) {
//dlog("\nSetEntries: -> RefreshGraphics", DL_INIT);
Graphics::RefreshGraphics();
} else {
// only for debugging
//dlog("\nSetEntries: -> ShowMovieFrame", DL_INIT);
//Graphics::ShowMovieFrame();
//dlog("\nSetEntries -> RefreshGraphics", DL_INIT);
Refresh();
}
return DD_OK;
}
@@ -1098,9 +1012,7 @@ HRESULT __stdcall InitFakeDirectDrawCreate(void*, IDirectDraw** b, void*) {
ResWidth = *(DWORD*)0x4CAD6B; // 640
ResHeight = *(DWORD*)0x4CAD66; // 480
if (!d3d9) {
d3d9 = Direct3DCreate9(D3D_SDK_VERSION);
}
if (!d3d9) d3d9 = Direct3DCreate9(D3D_SDK_VERSION);
ZeroMemory(&surfaceDesc, sizeof(DDSURFACEDESC));
@@ -1239,7 +1151,6 @@ void Graphics::exit() {
unsigned int data = windowTop | (windowLeft << 16);
if (data != windowData) SetConfigInt("Graphics", "WindowData", data);
}
if (titlesBuffer) delete[] titlesBuffer;
CoUninitialize();
}
}
+1 -1
View File
@@ -192,7 +192,7 @@ static struct sDSTexture {
IVMRSurfaceAllocatorNotify9 *pAlloc;
IMediaControl *pControl;
IMediaSeeking *pSeek;
IBasicAudio *pAudio;
IBasicAudio *pAudio;
bool released = false;
} movieInterface;
+12 -10
View File
@@ -164,22 +164,24 @@ static void ResetShaders() {
}
void ScriptShaders::Refresh(IDirect3DSurface9* sSurf1, IDirect3DSurface9* sSurf2, IDirect3DTexture9* sTex2) {
for (int d = shadersSize - 1; d >= 0; d--) {
if (!shaders[d].Effect || !shaders[d].Active) continue;
if (shaders[d].mode2 && !(shaders[d].mode2 & GetLoopFlags())) continue;
if (shaders[d].mode & GetLoopFlags()) continue;
for (int i = shadersSize - 1; i >= 0; i--) {
if (!shaders[i].Effect || !shaders[i].Active) continue;
if (shaders[i].mode2 && !(shaders[i].mode2 & GetLoopFlags())) continue;
if (shaders[i].mode & GetLoopFlags()) continue;
if (shaders[i].ehTicks) shaders[i].Effect->SetInt(shaders[i].ehTicks, GetTickCount());
if (shaders[d].ehTicks) shaders[d].Effect->SetInt(shaders[d].ehTicks, GetTickCount());
UINT passes;
shaders[d].Effect->Begin(&passes, 0);
shaders[i].Effect->Begin(&passes, 0);
for (DWORD pass = 0; pass < passes; pass++) {
shaders[d].Effect->BeginPass(pass);
shaders[i].Effect->BeginPass(pass);
d3d9Device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
shaders[d].Effect->EndPass();
d3d9Device->StretchRect(sSurf1, 0, sSurf2, 0, D3DTEXF_NONE);
shaders[i].Effect->EndPass();
d3d9Device->StretchRect(sSurf1, 0, sSurf2, 0, D3DTEXF_NONE); // copy sSurf1 to sSurf2
d3d9Device->SetTexture(0, sTex2);
}
shaders[d].Effect->End();
shaders[i].Effect->End();
d3d9Device->SetTexture(0, sTex2);
}
}