diff --git a/src/rendering/polyrenderer/backend/poly_framebuffer.cpp b/src/rendering/polyrenderer/backend/poly_framebuffer.cpp index c5e2a6707..3d8b75bd8 100644 --- a/src/rendering/polyrenderer/backend/poly_framebuffer.cpp +++ b/src/rendering/polyrenderer/backend/poly_framebuffer.cpp @@ -48,13 +48,20 @@ extern bool keepGpuStatActive; extern FString gpuStatOutput; #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 -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 PolyFrameBuffer::PolyFrameBuffer(void *hMonitor, bool fullscreen) : Super(hMonitor, fullscreen) { + I_PolyPresentInit(); } PolyFrameBuffer::~PolyFrameBuffer() @@ -74,6 +81,8 @@ PolyFrameBuffer::~PolyFrameBuffer() mShadowMap.Reset(); screen = tmp; + + I_PolyPresentDeinit(); } void PolyFrameBuffer::InitializeState() @@ -145,7 +154,20 @@ void PolyFrameBuffer::Update() 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(); diff --git a/src/win32/win32polyvideo.cpp b/src/win32/win32polyvideo.cpp index e783c710b..a6e74218a 100644 --- a/src/win32/win32polyvideo.cpp +++ b/src/win32/win32polyvideo.cpp @@ -4,26 +4,72 @@ #include "doomerrors.h" #include -extern HWND Window; +EXTERN_CVAR(Bool, vid_vsync) -#if 1 +extern HWND Window; #include #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); - if (!d3d9) + I_FatalError("Direct3DCreate9 failed"); + } + + 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; - RECT rect = {}; - GetClientRect(Window, &rect); + CurrentVSync = vid_vsync; ClientWidth = rect.right; ClientHeight = rect.bottom; @@ -34,120 +80,108 @@ struct D3D9Present pp.BackBufferHeight = ClientHeight; pp.BackBufferCount = 1; 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)) { - 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; - if (SrcWidth != w || SrcHeight != h || !surface) + pitch = 0; + 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) - { - surface->Release(); - surface = nullptr; - } - - SrcWidth = w; - SrcHeight = h; - result = device->CreateOffscreenPlainSurface(SrcWidth, SrcHeight, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &surface, 0); - if (FAILED(result)) - { - I_FatalError("IDirect3DDevice9.CreateOffscreenPlainSurface failed"); - } + clearrects[count].x1 = 0; + clearrects[count].y1 = 0; + clearrects[count].x2 = ClientWidth; + clearrects[count].y2 = y; + count++; } - - 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++) + if (y + height < ClientHeight) { - 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; - device->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &backbuffer); - if (FAILED(result)) - return; - - result = device->BeginScene(); + result = device->EndScene(); if (SUCCEEDED(result)) - { - 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(); + device->Present(nullptr, nullptr, 0, nullptr); } - ~D3D9Present() - { - 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); + backbuffer->Release(); } -#else - -void I_PresentPolyImage(int w, int h, const void *pixels) +void I_PolyPresentDeinit() { - BITMAPV5HEADER info = {}; - info.bV5Size = sizeof(BITMAPV5HEADER); - info.bV5Width = w; - 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); + if (surface) surface->Release(); + if (device) device->Release(); + if (d3d9) d3d9->Release(); } - -#endif