mirror of
https://github.com/ZDoom/gzdoom-gles.git
synced 2024-12-12 05:11:45 +00:00
- implement vsync and letterbox
This commit is contained in:
parent
4bbab49e04
commit
4a7824c380
2 changed files with 166 additions and 110 deletions
|
@ -48,13 +48,20 @@ extern bool keepGpuStatActive;
|
||||||
extern FString gpuStatOutput;
|
extern FString gpuStatOutput;
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
void I_PresentPolyImage(int w, int h, const void *pixels);
|
void I_PolyPresentInit();
|
||||||
|
uint8_t *I_PolyPresentLock(int w, int h, int &pitch);
|
||||||
|
void I_PolyPresentUnlock(int x, int y, int w, int h);
|
||||||
|
void I_PolyPresentDeinit();
|
||||||
#else
|
#else
|
||||||
void I_PresentPolyImage(int w, int h, const void *pixels) { }
|
void I_PolyPresentInit() { }
|
||||||
|
uint8_t *I_PolyPresentLock(int w, int h, int &pitch) { pitch = 0; return nullptr; }
|
||||||
|
void I_PolyPresentUnlock() { }
|
||||||
|
void I_PolyPresentDeinit() { }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
PolyFrameBuffer::PolyFrameBuffer(void *hMonitor, bool fullscreen) : Super(hMonitor, fullscreen)
|
PolyFrameBuffer::PolyFrameBuffer(void *hMonitor, bool fullscreen) : Super(hMonitor, fullscreen)
|
||||||
{
|
{
|
||||||
|
I_PolyPresentInit();
|
||||||
}
|
}
|
||||||
|
|
||||||
PolyFrameBuffer::~PolyFrameBuffer()
|
PolyFrameBuffer::~PolyFrameBuffer()
|
||||||
|
@ -74,6 +81,8 @@ PolyFrameBuffer::~PolyFrameBuffer()
|
||||||
mShadowMap.Reset();
|
mShadowMap.Reset();
|
||||||
|
|
||||||
screen = tmp;
|
screen = tmp;
|
||||||
|
|
||||||
|
I_PolyPresentDeinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PolyFrameBuffer::InitializeState()
|
void PolyFrameBuffer::InitializeState()
|
||||||
|
@ -145,7 +154,20 @@ void PolyFrameBuffer::Update()
|
||||||
|
|
||||||
if (mCanvas)
|
if (mCanvas)
|
||||||
{
|
{
|
||||||
I_PresentPolyImage(mCanvas->GetWidth(), mCanvas->GetHeight(), mCanvas->GetPixels());
|
int w = mCanvas->GetWidth();
|
||||||
|
int h = mCanvas->GetHeight();
|
||||||
|
int pixelsize = 4;
|
||||||
|
const uint8_t *src = (const uint8_t*)mCanvas->GetPixels();
|
||||||
|
int pitch = 0;
|
||||||
|
uint8_t *dst = I_PolyPresentLock(w, h, pitch);
|
||||||
|
if (dst)
|
||||||
|
{
|
||||||
|
for (int y = 0; y < h; y++)
|
||||||
|
{
|
||||||
|
memcpy(dst + y * pitch, src + y * w * pixelsize, w * pixelsize);
|
||||||
|
}
|
||||||
|
I_PolyPresentUnlock(mOutputLetterbox.left, mOutputLetterbox.top, mOutputLetterbox.width, mOutputLetterbox.height);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CheckCanvas();
|
CheckCanvas();
|
||||||
|
|
|
@ -4,26 +4,72 @@
|
||||||
#include "doomerrors.h"
|
#include "doomerrors.h"
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
|
|
||||||
extern HWND Window;
|
EXTERN_CVAR(Bool, vid_vsync)
|
||||||
|
|
||||||
#if 1
|
extern HWND Window;
|
||||||
|
|
||||||
#include <d3d9.h>
|
#include <d3d9.h>
|
||||||
#pragma comment(lib, "d3d9.lib")
|
#pragma comment(lib, "d3d9.lib")
|
||||||
|
|
||||||
struct D3D9Present
|
namespace
|
||||||
{
|
{
|
||||||
D3D9Present()
|
int SrcWidth = 0;
|
||||||
|
int SrcHeight = 0;
|
||||||
|
int ClientWidth = 0;
|
||||||
|
int ClientHeight = 0;
|
||||||
|
bool CurrentVSync = false;
|
||||||
|
|
||||||
|
IDirect3D9 *d3d9 = nullptr;
|
||||||
|
IDirect3DDevice9 *device = nullptr;
|
||||||
|
IDirect3DSurface9 *surface = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void I_PolyPresentInit()
|
||||||
|
{
|
||||||
|
d3d9 = Direct3DCreate9(D3D_SDK_VERSION);
|
||||||
|
if (!d3d9)
|
||||||
{
|
{
|
||||||
d3d9 = Direct3DCreate9(D3D_SDK_VERSION);
|
I_FatalError("Direct3DCreate9 failed");
|
||||||
if (!d3d9)
|
}
|
||||||
|
|
||||||
|
RECT rect = {};
|
||||||
|
GetClientRect(Window, &rect);
|
||||||
|
|
||||||
|
CurrentVSync = vid_vsync;
|
||||||
|
ClientWidth = rect.right;
|
||||||
|
ClientHeight = rect.bottom;
|
||||||
|
|
||||||
|
D3DPRESENT_PARAMETERS pp = {};
|
||||||
|
pp.Windowed = true;
|
||||||
|
pp.SwapEffect = D3DSWAPEFFECT_DISCARD;
|
||||||
|
pp.BackBufferWidth = ClientWidth;
|
||||||
|
pp.BackBufferHeight = ClientHeight;
|
||||||
|
pp.BackBufferCount = 1;
|
||||||
|
pp.hDeviceWindow = Window;
|
||||||
|
pp.PresentationInterval = CurrentVSync ? D3DPRESENT_INTERVAL_ONE : D3DPRESENT_INTERVAL_IMMEDIATE;
|
||||||
|
|
||||||
|
HRESULT result = d3d9->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, Window, D3DCREATE_HARDWARE_VERTEXPROCESSING, &pp, &device);
|
||||||
|
if (FAILED(result))
|
||||||
|
{
|
||||||
|
I_FatalError("IDirect3D9.CreateDevice failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t *I_PolyPresentLock(int w, int h, int &pitch)
|
||||||
|
{
|
||||||
|
HRESULT result;
|
||||||
|
|
||||||
|
RECT rect = {};
|
||||||
|
GetClientRect(Window, &rect);
|
||||||
|
if (rect.right != ClientWidth || rect.bottom != ClientHeight || CurrentVSync != vid_vsync)
|
||||||
|
{
|
||||||
|
if (surface)
|
||||||
{
|
{
|
||||||
I_FatalError("Direct3DCreate9 failed");
|
surface->Release();
|
||||||
|
surface = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool vsync = false;
|
CurrentVSync = vid_vsync;
|
||||||
RECT rect = {};
|
|
||||||
GetClientRect(Window, &rect);
|
|
||||||
ClientWidth = rect.right;
|
ClientWidth = rect.right;
|
||||||
ClientHeight = rect.bottom;
|
ClientHeight = rect.bottom;
|
||||||
|
|
||||||
|
@ -34,120 +80,108 @@ struct D3D9Present
|
||||||
pp.BackBufferHeight = ClientHeight;
|
pp.BackBufferHeight = ClientHeight;
|
||||||
pp.BackBufferCount = 1;
|
pp.BackBufferCount = 1;
|
||||||
pp.hDeviceWindow = Window;
|
pp.hDeviceWindow = Window;
|
||||||
pp.PresentationInterval = vsync ? D3DPRESENT_INTERVAL_ONE : D3DPRESENT_INTERVAL_IMMEDIATE;
|
pp.PresentationInterval = CurrentVSync ? D3DPRESENT_INTERVAL_ONE : D3DPRESENT_INTERVAL_IMMEDIATE;
|
||||||
|
device->Reset(&pp);
|
||||||
|
}
|
||||||
|
|
||||||
HRESULT result = d3d9->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, Window, D3DCREATE_HARDWARE_VERTEXPROCESSING, &pp, &device);
|
if (SrcWidth != w || SrcHeight != h || !surface)
|
||||||
|
{
|
||||||
|
if (surface)
|
||||||
|
{
|
||||||
|
surface->Release();
|
||||||
|
surface = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
SrcWidth = w;
|
||||||
|
SrcHeight = h;
|
||||||
|
result = device->CreateOffscreenPlainSurface(SrcWidth, SrcHeight, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &surface, 0);
|
||||||
if (FAILED(result))
|
if (FAILED(result))
|
||||||
{
|
{
|
||||||
I_FatalError("IDirect3D9.CreateDevice failed");
|
I_FatalError("IDirect3DDevice9.CreateOffscreenPlainSurface failed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Present(int w, int h, const void *pixels)
|
D3DLOCKED_RECT lockrect = {};
|
||||||
|
result = surface->LockRect(&lockrect, nullptr, D3DLOCK_DISCARD);
|
||||||
|
if (FAILED(result))
|
||||||
{
|
{
|
||||||
HRESULT result;
|
pitch = 0;
|
||||||
if (SrcWidth != w || SrcHeight != h || !surface)
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
pitch = lockrect.Pitch;
|
||||||
|
return (uint8_t*)lockrect.pBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
void I_PolyPresentUnlock(int x, int y, int width, int height)
|
||||||
|
{
|
||||||
|
surface->UnlockRect();
|
||||||
|
|
||||||
|
IDirect3DSurface9 *backbuffer = nullptr;
|
||||||
|
HRESULT result = device->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &backbuffer);
|
||||||
|
if (FAILED(result))
|
||||||
|
return;
|
||||||
|
|
||||||
|
result = device->BeginScene();
|
||||||
|
if (SUCCEEDED(result))
|
||||||
|
{
|
||||||
|
int count = 0;
|
||||||
|
D3DRECT clearrects[4];
|
||||||
|
if (y > 0)
|
||||||
{
|
{
|
||||||
if (surface)
|
clearrects[count].x1 = 0;
|
||||||
{
|
clearrects[count].y1 = 0;
|
||||||
surface->Release();
|
clearrects[count].x2 = ClientWidth;
|
||||||
surface = nullptr;
|
clearrects[count].y2 = y;
|
||||||
}
|
count++;
|
||||||
|
|
||||||
SrcWidth = w;
|
|
||||||
SrcHeight = h;
|
|
||||||
result = device->CreateOffscreenPlainSurface(SrcWidth, SrcHeight, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &surface, 0);
|
|
||||||
if (FAILED(result))
|
|
||||||
{
|
|
||||||
I_FatalError("IDirect3DDevice9.CreateOffscreenPlainSurface failed");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if (y + height < ClientHeight)
|
||||||
D3DLOCKED_RECT lockrect = {};
|
|
||||||
result = surface->LockRect(&lockrect, nullptr, D3DLOCK_DISCARD);
|
|
||||||
if (FAILED(result))
|
|
||||||
return;
|
|
||||||
|
|
||||||
int pixelsize = 4;
|
|
||||||
const uint8_t *src = (const uint8_t*)pixels;
|
|
||||||
uint8_t *dst = (uint8_t*)lockrect.pBits;
|
|
||||||
for (int y = 0; y < h; y++)
|
|
||||||
{
|
{
|
||||||
memcpy(dst + y * lockrect.Pitch, src + y * w * pixelsize, w * pixelsize);
|
clearrects[count].x1 = 0;
|
||||||
|
clearrects[count].y1 = y + height;
|
||||||
|
clearrects[count].x2 = ClientWidth;
|
||||||
|
clearrects[count].y2 = ClientHeight;
|
||||||
|
count++;
|
||||||
}
|
}
|
||||||
|
if (x > 0)
|
||||||
|
{
|
||||||
|
clearrects[count].x1 = 0;
|
||||||
|
clearrects[count].y1 = y;
|
||||||
|
clearrects[count].x2 = x;
|
||||||
|
clearrects[count].y2 = y + height;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
if (x + width < ClientWidth)
|
||||||
|
{
|
||||||
|
clearrects[count].x1 = x + width;
|
||||||
|
clearrects[count].y1 = y;
|
||||||
|
clearrects[count].x2 = ClientWidth;
|
||||||
|
clearrects[count].y2 = y + height;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
if (count > 0)
|
||||||
|
device->Clear(count, clearrects, D3DCLEAR_TARGET, 0, 0.0f, 0);
|
||||||
|
|
||||||
surface->UnlockRect();
|
RECT srcrect = {}, dstrect = {};
|
||||||
|
srcrect.right = SrcWidth;
|
||||||
|
srcrect.bottom = SrcHeight;
|
||||||
|
dstrect.left = x;
|
||||||
|
dstrect.top = y;
|
||||||
|
dstrect.right = x + width;
|
||||||
|
dstrect.bottom = y + height;
|
||||||
|
device->StretchRect(surface, &srcrect, backbuffer, &dstrect, D3DTEXF_LINEAR);
|
||||||
|
|
||||||
IDirect3DSurface9 *backbuffer = nullptr;
|
result = device->EndScene();
|
||||||
device->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &backbuffer);
|
|
||||||
if (FAILED(result))
|
|
||||||
return;
|
|
||||||
|
|
||||||
result = device->BeginScene();
|
|
||||||
if (SUCCEEDED(result))
|
if (SUCCEEDED(result))
|
||||||
{
|
device->Present(nullptr, nullptr, 0, nullptr);
|
||||||
RECT srcrect = {}, dstrect = {};
|
|
||||||
srcrect.right = SrcWidth;
|
|
||||||
srcrect.bottom = SrcHeight;
|
|
||||||
dstrect.right = ClientWidth;
|
|
||||||
dstrect.bottom = ClientHeight;
|
|
||||||
device->StretchRect(surface, &srcrect, backbuffer, &dstrect, D3DTEXF_LINEAR);
|
|
||||||
|
|
||||||
result = device->EndScene();
|
|
||||||
if (SUCCEEDED(result))
|
|
||||||
device->Present(nullptr, nullptr, 0, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
backbuffer->Release();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
~D3D9Present()
|
backbuffer->Release();
|
||||||
{
|
|
||||||
if (surface) surface->Release();
|
|
||||||
if (device) device->Release();
|
|
||||||
if (d3d9) d3d9->Release();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
int SrcWidth = 0;
|
|
||||||
int SrcHeight = 0;
|
|
||||||
int ClientWidth = 0;
|
|
||||||
int ClientHeight = 0;
|
|
||||||
|
|
||||||
IDirect3D9 *d3d9 = nullptr;
|
|
||||||
IDirect3DDevice9 *device = nullptr;
|
|
||||||
IDirect3DSurface9 *surface = nullptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
void I_PresentPolyImage(int w, int h, const void *pixels)
|
|
||||||
{
|
|
||||||
static D3D9Present present;
|
|
||||||
present.Present(w, h, pixels);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
void I_PolyPresentDeinit()
|
||||||
|
|
||||||
void I_PresentPolyImage(int w, int h, const void *pixels)
|
|
||||||
{
|
{
|
||||||
BITMAPV5HEADER info = {};
|
if (surface) surface->Release();
|
||||||
info.bV5Size = sizeof(BITMAPV5HEADER);
|
if (device) device->Release();
|
||||||
info.bV5Width = w;
|
if (d3d9) d3d9->Release();
|
||||||
info.bV5Height = -h;
|
|
||||||
info.bV5Planes = 1;
|
|
||||||
info.bV5BitCount = 32;
|
|
||||||
info.bV5Compression = BI_RGB;
|
|
||||||
info.bV5SizeImage = 0;
|
|
||||||
info.bV5CSType = LCS_WINDOWS_COLOR_SPACE;
|
|
||||||
|
|
||||||
RECT box = {};
|
|
||||||
GetClientRect(Window, &box);
|
|
||||||
|
|
||||||
HDC dc = GetDC(Window);
|
|
||||||
if (box.right == w && box.bottom == h)
|
|
||||||
SetDIBitsToDevice(dc, 0, 0, w, h, 0, 0, 0, h, pixels, (const BITMAPINFO *)&info, DIB_RGB_COLORS);
|
|
||||||
else
|
|
||||||
StretchDIBits(dc, 0, 0, box.right, box.bottom, 0, 0, w, h, pixels, (const BITMAPINFO *)&info, DIB_RGB_COLORS, SRCCOPY);
|
|
||||||
ReleaseDC(Window, dc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
Loading…
Reference in a new issue