mirror of
https://github.com/bsnes-emu/bsnes.git
synced 2025-08-17 05:03:59 +02:00
Update to bsnes v107r4 beta release.
byuu says: - bsnes: added video filters from bsnes v082 - bsnes: added ZSNES snow effect option when games paused or unloaded (no, I'm not joking) - bsnes: added 7-zip support (LZMA 19.00 SDK) [Recent higan WIPs have also mentioned bsnes changes, although the higan code no longer includes the bsnes code. These changes include: - higan, bsnes: added EXLOROM, EXLOROM-RAM, EXHIROM mappings - higan, bsnes: focus the viewport after leaving fullscreen exclusive mode - bsnes: re-added mightymo's cheat code database - bsnes: improved make install rules for the game and cheat code databases - bsnes: delayed construction of hiro::Window objects to properly show bsnes window icons - Ed.]
This commit is contained in:
@@ -8,7 +8,7 @@ ifeq ($(ruby),)
|
||||
ruby += audio.openal
|
||||
ruby += input.quartz input.carbon
|
||||
else ifeq ($(platform),linux)
|
||||
ruby += video.glx video.xvideo video.xshm
|
||||
ruby += video.glx video.glx2 video.xvideo video.xshm
|
||||
ruby += audio.oss audio.alsa audio.openal audio.pulseaudio audio.pulseaudiosimple audio.ao
|
||||
ruby += input.sdl input.xlib input.udev
|
||||
else ifeq ($(platform),bsd)
|
||||
|
@@ -7,6 +7,7 @@
|
||||
#include <nall/hid.hpp>
|
||||
#include <nall/image.hpp>
|
||||
#include <nall/matrix.hpp>
|
||||
#include <nall/matrix-multiply.hpp>
|
||||
#include <nall/queue.hpp>
|
||||
#include <nall/range.hpp>
|
||||
#include <nall/set.hpp>
|
||||
|
@@ -60,6 +60,14 @@ struct VideoCGL : VideoDriver, OpenGL {
|
||||
}
|
||||
}
|
||||
|
||||
auto size(uint& width, uint& height) -> void override {
|
||||
@autoreleasepool {
|
||||
auto area = [view convertRectToBacking:[view bounds]];
|
||||
width = area.size.width;
|
||||
height = area.size.height;
|
||||
}
|
||||
}
|
||||
|
||||
auto acquire(uint32_t*& data, uint& pitch, uint width, uint height) -> bool override {
|
||||
OpenGL::size(width, height);
|
||||
return OpenGL::lock(data, pitch);
|
||||
@@ -68,12 +76,16 @@ struct VideoCGL : VideoDriver, OpenGL {
|
||||
auto release() -> void override {
|
||||
}
|
||||
|
||||
auto output() -> void override {
|
||||
auto output(uint width, uint height) -> void override {
|
||||
uint windowWidth, windowHeight;
|
||||
size(windowWidth, windowHeight);
|
||||
|
||||
@autoreleasepool {
|
||||
if([view lockFocusIfCanDraw]) {
|
||||
auto area = [view convertRectToBacking:[view bounds]];
|
||||
OpenGL::outputWidth = area.size.width;
|
||||
OpenGL::outputHeight = area.size.height;
|
||||
OpenGL::absoluteWidth = width;
|
||||
OpenGL::absoluteHeight = height;
|
||||
OpenGL::outputWidth = windowWidth;
|
||||
OpenGL::outputHeight = windowHeight;
|
||||
OpenGL::output();
|
||||
[[view openGLContext] flushBuffer];
|
||||
if(self.flush) glFinish();
|
||||
|
@@ -3,14 +3,14 @@
|
||||
#include <d3d9.h>
|
||||
#undef interface
|
||||
|
||||
static LRESULT CALLBACK VideoDirect3D_WindowProcedure(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
|
||||
static LRESULT CALLBACK VideoDirect3D9_WindowProcedure(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
|
||||
return DefWindowProc(hwnd, msg, wparam, lparam);
|
||||
}
|
||||
|
||||
struct VideoDirect3D : VideoDriver {
|
||||
VideoDirect3D& self = *this;
|
||||
VideoDirect3D(Video& super) : VideoDriver(super) {}
|
||||
~VideoDirect3D() { terminate(); }
|
||||
VideoDirect3D(Video& super) : VideoDriver(super) { construct(); }
|
||||
~VideoDirect3D() { destruct(); }
|
||||
|
||||
auto create() -> bool override {
|
||||
return initialize();
|
||||
@@ -52,14 +52,25 @@ struct VideoDirect3D : VideoDriver {
|
||||
}
|
||||
}
|
||||
|
||||
auto acquire(uint32_t*& data, uint& pitch, uint width, uint height) -> bool override {
|
||||
if(_lost && !recover()) return false;
|
||||
auto size(uint& width, uint& height) -> void {
|
||||
if(_lost && !recover()) return;
|
||||
|
||||
RECT rectangle;
|
||||
GetClientRect(_context, &rectangle);
|
||||
|
||||
width = rectangle.right - rectangle.left;
|
||||
height = rectangle.bottom - rectangle.top;
|
||||
|
||||
//if output size changed, driver must be re-initialized.
|
||||
//failure to do so causes scaling issues on some video drivers.
|
||||
RECT rectangle;
|
||||
GetClientRect((HWND)self.context, &rectangle);
|
||||
if(_windowWidth != rectangle.right || _windowHeight != rectangle.bottom) initialize();
|
||||
if(width != _windowWidth || height != _windowHeight) initialize();
|
||||
}
|
||||
|
||||
auto acquire(uint32_t*& data, uint& pitch, uint width, uint height) -> bool override {
|
||||
if(_lost && !recover()) return false;
|
||||
|
||||
uint windowWidth, windowHeight;
|
||||
size(windowWidth, windowHeight);
|
||||
|
||||
if(width != _inputWidth || height != _inputHeight) {
|
||||
resize(_inputWidth = width, _inputHeight = height);
|
||||
@@ -81,17 +92,17 @@ struct VideoDirect3D : VideoDriver {
|
||||
_surface = nullptr;
|
||||
}
|
||||
|
||||
auto output() -> void override {
|
||||
auto output(uint width, uint height) -> void override {
|
||||
if(_lost && !recover()) return;
|
||||
|
||||
if(!width) width = _windowWidth;
|
||||
if(!height) height = _windowHeight;
|
||||
|
||||
_device->BeginScene();
|
||||
uint x = 0, y = 0;
|
||||
if(self.exclusive) {
|
||||
//center output in exclusive mode fullscreen window
|
||||
x = (_monitorWidth - _windowWidth) / 2;
|
||||
y = (_monitorHeight - _windowHeight) / 2;
|
||||
}
|
||||
setVertex(0, 0, _inputWidth, _inputHeight, _textureWidth, _textureHeight, x, y, _windowWidth, _windowHeight);
|
||||
//center output within window
|
||||
uint x = (_windowWidth - width) / 2;
|
||||
uint y = (_windowHeight - height) / 2;
|
||||
setVertex(0, 0, _inputWidth, _inputHeight, _textureWidth, _textureHeight, x, y, width, height);
|
||||
_device->SetTexture(0, _texture);
|
||||
_device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
|
||||
_device->EndScene();
|
||||
@@ -112,6 +123,25 @@ struct VideoDirect3D : VideoDriver {
|
||||
}
|
||||
|
||||
private:
|
||||
auto construct() -> void {
|
||||
WNDCLASS windowClass{};
|
||||
windowClass.cbClsExtra = 0;
|
||||
windowClass.cbWndExtra = 0;
|
||||
windowClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
|
||||
windowClass.hCursor = LoadCursor(0, IDC_ARROW);
|
||||
windowClass.hIcon = LoadIcon(nullptr, IDI_APPLICATION);
|
||||
windowClass.hInstance = GetModuleHandle(0);
|
||||
windowClass.lpfnWndProc = VideoDirect3D9_WindowProcedure;
|
||||
windowClass.lpszClassName = L"VideoDirect3D9_Window";
|
||||
windowClass.lpszMenuName = 0;
|
||||
windowClass.style = CS_HREDRAW | CS_VREDRAW;
|
||||
RegisterClass(&windowClass);
|
||||
}
|
||||
|
||||
auto destruct() -> void {
|
||||
terminate();
|
||||
}
|
||||
|
||||
auto recover() -> bool {
|
||||
if(!_device) return false;
|
||||
|
||||
@@ -211,36 +241,28 @@ private:
|
||||
|
||||
auto initialize() -> bool {
|
||||
terminate();
|
||||
if(!self.context) return false;
|
||||
if(!self.exclusive && !self.context) return false;
|
||||
|
||||
HMONITOR monitor = MonitorFromWindow((HWND)self.context, MONITOR_DEFAULTTOPRIMARY);
|
||||
MONITORINFOEX information = {};
|
||||
POINT point{0, 0};
|
||||
HMONITOR monitor = MonitorFromPoint(point, MONITOR_DEFAULTTOPRIMARY);
|
||||
MONITORINFOEX information{};
|
||||
information.cbSize = sizeof(MONITORINFOEX);
|
||||
GetMonitorInfo(monitor, &information);
|
||||
_monitorWidth = information.rcMonitor.right - information.rcMonitor.left;
|
||||
_monitorHeight = information.rcMonitor.bottom - information.rcMonitor.top;
|
||||
|
||||
WNDCLASS windowClass = {};
|
||||
windowClass.cbClsExtra = 0;
|
||||
windowClass.cbWndExtra = 0;
|
||||
windowClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
|
||||
windowClass.hCursor = LoadCursor(0, IDC_ARROW);
|
||||
windowClass.hIcon = LoadIcon(nullptr, IDI_APPLICATION);
|
||||
windowClass.hInstance = GetModuleHandle(0);
|
||||
windowClass.lpfnWndProc = VideoDirect3D_WindowProcedure;
|
||||
windowClass.lpszClassName = L"VideoDirect3D_Window";
|
||||
windowClass.lpszMenuName = 0;
|
||||
windowClass.style = CS_HREDRAW | CS_VREDRAW;
|
||||
RegisterClass(&windowClass);
|
||||
|
||||
_exclusiveContext = (uintptr)CreateWindow(L"VideoDirect3D_Window", L"", WS_POPUP,
|
||||
information.rcMonitor.left, information.rcMonitor.top, _monitorWidth, _monitorHeight,
|
||||
nullptr, nullptr, GetModuleHandle(0), nullptr);
|
||||
if(self.exclusive) {
|
||||
_context = _exclusive = CreateWindowEx(WS_EX_TOPMOST, L"VideoDirect3D9_Window", L"", WS_VISIBLE | WS_POPUP,
|
||||
information.rcMonitor.left, information.rcMonitor.top, _monitorWidth, _monitorHeight,
|
||||
nullptr, nullptr, GetModuleHandle(0), nullptr);
|
||||
} else {
|
||||
_context = (HWND)self.context;
|
||||
}
|
||||
|
||||
RECT rectangle;
|
||||
GetClientRect((HWND)self.context, &rectangle);
|
||||
_windowWidth = rectangle.right;
|
||||
_windowHeight = rectangle.bottom;
|
||||
GetClientRect(_context, &rectangle);
|
||||
_windowWidth = rectangle.right - rectangle.left;
|
||||
_windowHeight = rectangle.bottom - rectangle.top;
|
||||
|
||||
_instance = Direct3DCreate9(D3D_SDK_VERSION);
|
||||
if(!_instance) return false;
|
||||
@@ -254,36 +276,19 @@ private:
|
||||
_presentation.EnableAutoDepthStencil = false;
|
||||
_presentation.AutoDepthStencilFormat = D3DFMT_UNKNOWN;
|
||||
_presentation.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
|
||||
_presentation.hDeviceWindow = _context;
|
||||
_presentation.Windowed = !self.exclusive;
|
||||
_presentation.BackBufferFormat = self.exclusive ? D3DFMT_X8R8G8B8 : D3DFMT_UNKNOWN;
|
||||
_presentation.BackBufferWidth = self.exclusive ? _monitorWidth : 0;
|
||||
_presentation.BackBufferHeight = self.exclusive ? _monitorHeight : 0;
|
||||
_presentation.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
|
||||
|
||||
if(!self.exclusive) {
|
||||
_presentation.hDeviceWindow = (HWND)self.context;
|
||||
_presentation.Windowed = true;
|
||||
_presentation.BackBufferFormat = D3DFMT_UNKNOWN;
|
||||
_presentation.BackBufferWidth = 0;
|
||||
_presentation.BackBufferHeight = 0;
|
||||
|
||||
ShowWindow((HWND)_exclusiveContext, SW_HIDE);
|
||||
if(_instance->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, (HWND)self.context,
|
||||
D3DCREATE_FPU_PRESERVE | D3DCREATE_SOFTWARE_VERTEXPROCESSING, &_presentation, &_device) != D3D_OK) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
_presentation.hDeviceWindow = (HWND)_exclusiveContext;
|
||||
_presentation.Windowed = false;
|
||||
_presentation.BackBufferFormat = D3DFMT_X8R8G8B8;
|
||||
_presentation.BackBufferWidth = _monitorWidth;
|
||||
_presentation.BackBufferHeight = _monitorHeight;
|
||||
_presentation.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
|
||||
|
||||
ShowWindow((HWND)_exclusiveContext, SW_SHOWNORMAL);
|
||||
if(_instance->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, (HWND)_exclusiveContext,
|
||||
D3DCREATE_FPU_PRESERVE | D3DCREATE_SOFTWARE_VERTEXPROCESSING, &_presentation, &_device) != D3D_OK) {
|
||||
return false;
|
||||
}
|
||||
if(_instance->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, _context,
|
||||
D3DCREATE_FPU_PRESERVE | D3DCREATE_SOFTWARE_VERTEXPROCESSING, &_presentation, &_device) != D3D_OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
_device->GetDeviceCaps(&_capabilities);
|
||||
|
||||
if(_capabilities.Caps2 & D3DCAPS2_DYNAMICTEXTURES) {
|
||||
_textureUsage = D3DUSAGE_DYNAMIC;
|
||||
_texturePool = D3DPOOL_DEFAULT;
|
||||
@@ -307,7 +312,8 @@ private:
|
||||
if(_texture) { _texture->Release(); _texture = nullptr; }
|
||||
if(_device) { _device->Release(); _device = nullptr; }
|
||||
if(_instance) { _instance->Release(); _instance = nullptr; }
|
||||
if(_exclusiveContext) { DestroyWindow((HWND)_exclusiveContext); _exclusiveContext = 0; }
|
||||
if(_exclusive) { DestroyWindow(_exclusive); _exclusive = nullptr; }
|
||||
_context = nullptr;
|
||||
}
|
||||
|
||||
struct Vertex {
|
||||
@@ -316,8 +322,9 @@ private:
|
||||
};
|
||||
|
||||
bool _ready = false;
|
||||
uintptr _exclusiveContext = 0;
|
||||
|
||||
HWND _exclusive = nullptr;
|
||||
HWND _context = nullptr;
|
||||
LPDIRECT3D9 _instance = nullptr;
|
||||
LPDIRECT3DDEVICE9 _device = nullptr;
|
||||
LPDIRECT3DVERTEXBUFFER9 _vertexBuffer = nullptr;
|
||||
|
@@ -1,10 +1,14 @@
|
||||
#include <ddraw.h>
|
||||
#undef interface
|
||||
|
||||
static LRESULT CALLBACK VideoDirectDraw7_WindowProcedure(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
|
||||
return DefWindowProc(hwnd, msg, wparam, lparam);
|
||||
}
|
||||
|
||||
struct VideoDirectDraw : VideoDriver {
|
||||
VideoDirectDraw& self = *this;
|
||||
VideoDirectDraw(Video& super) : VideoDriver(super) {}
|
||||
~VideoDirectDraw() { terminate(); }
|
||||
VideoDirectDraw(Video& super) : VideoDriver(super) { construct(); }
|
||||
~VideoDirectDraw() { destruct(); }
|
||||
|
||||
auto create() -> bool override {
|
||||
super.setShader("Blur");
|
||||
@@ -14,9 +18,14 @@ struct VideoDirectDraw : VideoDriver {
|
||||
auto driver() -> string override { return "DirectDraw 7.0"; }
|
||||
auto ready() -> bool override { return _ready; }
|
||||
|
||||
auto hasExclusive() -> bool override { return true; }
|
||||
auto hasContext() -> bool override { return true; }
|
||||
auto hasBlocking() -> bool override { return true; }
|
||||
|
||||
auto setExclusive(bool exclusive) -> bool override {
|
||||
return initialize();
|
||||
}
|
||||
|
||||
auto setContext(uintptr context) -> bool override {
|
||||
return initialize();
|
||||
}
|
||||
@@ -26,13 +35,20 @@ struct VideoDirectDraw : VideoDriver {
|
||||
}
|
||||
|
||||
auto clear() -> void override {
|
||||
DDBLTFX fx = {};
|
||||
DDBLTFX fx{};
|
||||
fx.dwSize = sizeof(DDBLTFX);
|
||||
fx.dwFillColor = 0x00000000;
|
||||
_screen->Blt(0, 0, 0, DDBLT_WAIT | DDBLT_COLORFILL, &fx);
|
||||
_raster->Blt(0, 0, 0, DDBLT_WAIT | DDBLT_COLORFILL, &fx);
|
||||
}
|
||||
|
||||
auto size(uint& width, uint& height) -> void override {
|
||||
RECT rectangle;
|
||||
GetClientRect(_context, &rectangle);
|
||||
width = rectangle.right - rectangle.left;
|
||||
height = rectangle.bottom - rectangle.top;
|
||||
}
|
||||
|
||||
auto acquire(uint32_t*& data, uint& pitch, uint width, uint height) -> bool override {
|
||||
if(width != _width || height != _height) resize(_width = width, _height = height);
|
||||
DDSURFACEDESC2 description = {};
|
||||
@@ -49,7 +65,10 @@ struct VideoDirectDraw : VideoDriver {
|
||||
_raster->Unlock(0);
|
||||
}
|
||||
|
||||
auto output() -> void override {
|
||||
auto output(uint width, uint height) -> void override {
|
||||
uint windowWidth, windowHeight;
|
||||
size(windowWidth, windowHeight);
|
||||
|
||||
if(self.blocking) while(true) {
|
||||
BOOL vblank;
|
||||
_interface->GetVerticalBlankStatus(&vblank);
|
||||
@@ -59,13 +78,18 @@ struct VideoDirectDraw : VideoDriver {
|
||||
RECT source;
|
||||
SetRect(&source, 0, 0, _width, _height);
|
||||
|
||||
POINT point = {0, 0};
|
||||
ClientToScreen((HWND)self.context, &point);
|
||||
POINT point{0, 0};
|
||||
ClientToScreen(_context, &point);
|
||||
|
||||
RECT target;
|
||||
GetClientRect((HWND)self.context, &target);
|
||||
GetClientRect(_context, &target);
|
||||
OffsetRect(&target, point.x, point.y);
|
||||
|
||||
target.left += ((int)windowWidth - (int)width) / 2;
|
||||
target.top += ((int)windowHeight - (int)height) / 2;
|
||||
target.right = target.left + width;
|
||||
target.bottom = target.top + height;
|
||||
|
||||
if(_screen->Blt(&target, _raster, &source, DDBLT_WAIT, 0) == DDERR_SURFACELOST) {
|
||||
_screen->Restore();
|
||||
_raster->Restore();
|
||||
@@ -73,25 +97,60 @@ struct VideoDirectDraw : VideoDriver {
|
||||
}
|
||||
|
||||
private:
|
||||
auto construct() -> void {
|
||||
WNDCLASS windowClass{};
|
||||
windowClass.cbClsExtra = 0;
|
||||
windowClass.cbWndExtra = 0;
|
||||
windowClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
|
||||
windowClass.hCursor = LoadCursor(0, IDC_ARROW);
|
||||
windowClass.hIcon = LoadIcon(nullptr, IDI_APPLICATION);
|
||||
windowClass.hInstance = GetModuleHandle(0);
|
||||
windowClass.lpfnWndProc = VideoDirect3D9_WindowProcedure;
|
||||
windowClass.lpszClassName = L"VideoDirectDraw7_Window";
|
||||
windowClass.lpszMenuName = 0;
|
||||
windowClass.style = CS_HREDRAW | CS_VREDRAW;
|
||||
RegisterClass(&windowClass);
|
||||
}
|
||||
|
||||
auto destruct() -> void {
|
||||
terminate();
|
||||
}
|
||||
|
||||
auto initialize() -> bool {
|
||||
terminate();
|
||||
if(!self.context) return false;
|
||||
if(!self.exclusive && !self.context) return false;
|
||||
|
||||
POINT point{0, 0};
|
||||
HMONITOR monitor = MonitorFromPoint(point, MONITOR_DEFAULTTOPRIMARY);
|
||||
MONITORINFOEX information{};
|
||||
information.cbSize = sizeof(MONITORINFOEX);
|
||||
GetMonitorInfo(monitor, &information);
|
||||
uint monitorWidth = information.rcMonitor.right - information.rcMonitor.left;
|
||||
uint monitorHeight = information.rcMonitor.bottom - information.rcMonitor.top;
|
||||
|
||||
if(self.exclusive) {
|
||||
_context = _exclusive = CreateWindowEx(WS_EX_TOPMOST, L"VideoDirectDraw7_Window", L"", WS_VISIBLE | WS_POPUP,
|
||||
information.rcMonitor.left, information.rcMonitor.top, monitorWidth, monitorHeight,
|
||||
nullptr, nullptr, GetModuleHandle(0), nullptr);
|
||||
} else {
|
||||
_context = (HWND)self.context;
|
||||
}
|
||||
|
||||
LPDIRECTDRAW interface = nullptr;
|
||||
DirectDrawCreate(0, &interface, 0);
|
||||
interface->QueryInterface(IID_IDirectDraw7, (void**)&_interface);
|
||||
interface->Release();
|
||||
|
||||
_interface->SetCooperativeLevel((HWND)self.context, DDSCL_NORMAL);
|
||||
_interface->SetCooperativeLevel(_context, DDSCL_NORMAL);
|
||||
|
||||
DDSURFACEDESC2 description = {};
|
||||
DDSURFACEDESC2 description{};
|
||||
description.dwSize = sizeof(DDSURFACEDESC2);
|
||||
description.dwFlags = DDSD_CAPS;
|
||||
description.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
|
||||
_interface->CreateSurface(&description, &_screen, 0);
|
||||
|
||||
_interface->CreateClipper(0, &_clipper, 0);
|
||||
_clipper->SetHWnd(0, (HWND)self.context);
|
||||
_clipper->SetHWnd(0, _context);
|
||||
_screen->SetClipper(_clipper);
|
||||
|
||||
_raster = nullptr;
|
||||
@@ -107,6 +166,8 @@ private:
|
||||
if(_raster) { _raster->Release(); _raster = nullptr; }
|
||||
if(_screen) { _screen->Release(); _screen = nullptr; }
|
||||
if(_interface) { _interface->Release(); _interface = nullptr; }
|
||||
if(_exclusive) { DestroyWindow(_exclusive); _exclusive = nullptr; }
|
||||
_context = nullptr;
|
||||
}
|
||||
|
||||
auto resize(uint width, uint height) -> void {
|
||||
@@ -117,7 +178,7 @@ private:
|
||||
|
||||
if(_raster) _raster->Release();
|
||||
|
||||
DDSURFACEDESC2 description = {};
|
||||
DDSURFACEDESC2 description{};
|
||||
description.dwSize = sizeof(DDSURFACEDESC2);
|
||||
_screen->GetSurfaceDesc(&description);
|
||||
int depth = description.ddpfPixelFormat.dwRGBBitCount;
|
||||
@@ -155,6 +216,8 @@ private:
|
||||
uint _width = 0;
|
||||
uint _height = 0;
|
||||
|
||||
HWND _context = nullptr;
|
||||
HWND _exclusive = nullptr;
|
||||
LPDIRECTDRAW7 _interface = nullptr;
|
||||
LPDIRECTDRAWSURFACE7 _screen = nullptr;
|
||||
LPDIRECTDRAWSURFACE7 _raster = nullptr;
|
||||
|
@@ -1,7 +1,11 @@
|
||||
static LRESULT CALLBACK VideoGDI_WindowProcedure(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
|
||||
return DefWindowProc(hwnd, msg, wparam, lparam);
|
||||
}
|
||||
|
||||
struct VideoGDI : VideoDriver {
|
||||
VideoGDI& self = *this;
|
||||
VideoGDI(Video& super) : VideoDriver(super) {}
|
||||
~VideoGDI() { terminate(); }
|
||||
VideoGDI(Video& super) : VideoDriver(super) { construct(); }
|
||||
~VideoGDI() { destruct(); }
|
||||
|
||||
auto create() -> bool override {
|
||||
super.setShader("None");
|
||||
@@ -11,10 +15,19 @@ struct VideoGDI : VideoDriver {
|
||||
auto driver() -> string override { return "GDI"; }
|
||||
auto ready() -> bool override { return _ready; }
|
||||
|
||||
auto hasExclusive() -> bool override { return true; }
|
||||
auto hasContext() -> bool override { return true; }
|
||||
|
||||
auto setExclusive(bool exclusive) -> bool override { return initialize(); }
|
||||
auto setContext(uintptr context) -> bool override { return initialize(); }
|
||||
|
||||
auto size(uint& width, uint& height) -> void override {
|
||||
RECT rectangle;
|
||||
GetClientRect(_context, &rectangle);
|
||||
width = rectangle.right - rectangle.left;
|
||||
height = rectangle.bottom - rectangle.top;
|
||||
}
|
||||
|
||||
auto acquire(uint32_t*& data, uint& pitch, uint width, uint height) -> bool override {
|
||||
if(!_buffer || _width != width || _height != height) {
|
||||
if(_buffer) delete[] _buffer;
|
||||
@@ -25,11 +38,11 @@ struct VideoGDI : VideoDriver {
|
||||
_width = width;
|
||||
_height = height;
|
||||
|
||||
HDC hdc = GetDC((HWND)self.context);
|
||||
HDC hdc = GetDC(_context);
|
||||
_dc = CreateCompatibleDC(hdc);
|
||||
_bitmap = CreateCompatibleBitmap(hdc, width, height);
|
||||
SelectObject(_dc, _bitmap);
|
||||
ReleaseDC((HWND)self.context, hdc);
|
||||
ReleaseDC(_context, hdc);
|
||||
|
||||
memory::fill(&_info, sizeof(BITMAPINFO));
|
||||
_info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
||||
@@ -48,20 +61,58 @@ struct VideoGDI : VideoDriver {
|
||||
auto release() -> void override {
|
||||
}
|
||||
|
||||
auto output() -> void override {
|
||||
RECT rc;
|
||||
GetClientRect((HWND)self.context, &rc);
|
||||
auto output(uint width, uint height) -> void override {
|
||||
uint windowWidth, windowHeight;
|
||||
size(windowWidth, windowHeight);
|
||||
|
||||
SetDIBits(_dc, _bitmap, 0, _height, (void*)_buffer, &_info, DIB_RGB_COLORS);
|
||||
HDC hdc = GetDC((HWND)self.context);
|
||||
StretchBlt(hdc, rc.left, rc.top, rc.right, rc.bottom, _dc, 0, 0, _width, _height, SRCCOPY);
|
||||
ReleaseDC((HWND)self.context, hdc);
|
||||
HDC hdc = GetDC(_context);
|
||||
StretchBlt(hdc,
|
||||
((int)windowWidth - (int)width) / 2, ((int)windowHeight - (int)height) / 2, width, height, _dc,
|
||||
0, 0, _width, _height, SRCCOPY
|
||||
);
|
||||
ReleaseDC(_context, hdc);
|
||||
}
|
||||
|
||||
private:
|
||||
auto construct() -> void {
|
||||
WNDCLASS windowClass{};
|
||||
windowClass.cbClsExtra = 0;
|
||||
windowClass.cbWndExtra = 0;
|
||||
windowClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
|
||||
windowClass.hCursor = LoadCursor(0, IDC_ARROW);
|
||||
windowClass.hIcon = LoadIcon(nullptr, IDI_APPLICATION);
|
||||
windowClass.hInstance = GetModuleHandle(0);
|
||||
windowClass.lpfnWndProc = VideoGDI_WindowProcedure;
|
||||
windowClass.lpszClassName = L"VideoGDI_Window";
|
||||
windowClass.lpszMenuName = 0;
|
||||
windowClass.style = CS_HREDRAW | CS_VREDRAW;
|
||||
RegisterClass(&windowClass);
|
||||
}
|
||||
|
||||
auto destruct() -> void {
|
||||
terminate();
|
||||
}
|
||||
|
||||
auto initialize() -> bool {
|
||||
terminate();
|
||||
if(!self.context) return false;
|
||||
if(!self.exclusive && !self.context) return false;
|
||||
|
||||
POINT point{0, 0};
|
||||
HMONITOR monitor = MonitorFromPoint(point, MONITOR_DEFAULTTOPRIMARY);
|
||||
MONITORINFOEX information{};
|
||||
information.cbSize = sizeof(MONITORINFOEX);
|
||||
GetMonitorInfo(monitor, &information);
|
||||
uint monitorWidth = information.rcMonitor.right - information.rcMonitor.left;
|
||||
uint monitorHeight = information.rcMonitor.bottom - information.rcMonitor.top;
|
||||
|
||||
if(self.exclusive) {
|
||||
_context = _exclusive = CreateWindowEx(WS_EX_TOPMOST, L"VideoGDI_Window", L"", WS_VISIBLE | WS_POPUP,
|
||||
information.rcMonitor.left, information.rcMonitor.top, monitorWidth, monitorHeight,
|
||||
nullptr, nullptr, GetModuleHandle(0), nullptr);
|
||||
} else {
|
||||
_context = (HWND)self.context;
|
||||
}
|
||||
|
||||
_width = 0;
|
||||
_height = 0;
|
||||
@@ -73,6 +124,8 @@ private:
|
||||
if(_buffer) { delete[] _buffer; _buffer = nullptr; }
|
||||
if(_bitmap) { DeleteObject(_bitmap); _bitmap = nullptr; }
|
||||
if(_dc) { DeleteDC(_dc); _dc = nullptr; }
|
||||
if(_exclusive) { DestroyWindow(_exclusive); _exclusive = nullptr; }
|
||||
_context = nullptr;
|
||||
}
|
||||
|
||||
bool _ready = false;
|
||||
@@ -81,6 +134,8 @@ private:
|
||||
uint _width = 0;
|
||||
uint _height = 0;
|
||||
|
||||
HWND _exclusive = nullptr;
|
||||
HWND _context = nullptr;
|
||||
HBITMAP _bitmap = nullptr;
|
||||
HDC _dc = nullptr;
|
||||
BITMAPINFO _info = {};
|
||||
|
@@ -9,8 +9,8 @@ auto VideoGLX_X11ErrorHandler(Display*, XErrorEvent*) -> int {
|
||||
|
||||
struct VideoGLX : VideoDriver, OpenGL {
|
||||
VideoGLX& self = *this;
|
||||
VideoGLX(Video& super) : VideoDriver(super) {}
|
||||
~VideoGLX() { terminate(); }
|
||||
VideoGLX(Video& super) : VideoDriver(super) { construct(); }
|
||||
~VideoGLX() { destruct(); }
|
||||
|
||||
auto create() -> bool override {
|
||||
super.setFormat("RGB24");
|
||||
@@ -20,13 +20,20 @@ struct VideoGLX : VideoDriver, OpenGL {
|
||||
auto driver() -> string override { return "OpenGL 3.2"; }
|
||||
auto ready() -> bool override { return _ready; }
|
||||
|
||||
auto hasExclusive() -> bool override { return true; }
|
||||
auto hasContext() -> bool override { return true; }
|
||||
auto hasBlocking() -> bool override { return true; }
|
||||
auto hasFlush() -> bool override { return true; }
|
||||
auto hasShader() -> bool override { return true; }
|
||||
|
||||
auto hasFormats() -> vector<string> override {
|
||||
return {"RGB24"}; //"RGB30" is currently broken; use OpenGL 2.0 driver instead
|
||||
if(_depth == 30) return {"RGB30", "RGB24"};
|
||||
if(_depth == 24) return {"RGB24"};
|
||||
return {"RGB24"}; //fallback
|
||||
}
|
||||
|
||||
auto setExclusive(bool exclusive) -> bool override {
|
||||
return initialize();
|
||||
}
|
||||
|
||||
auto setContext(uintptr context) -> bool override {
|
||||
@@ -45,12 +52,12 @@ struct VideoGLX : VideoDriver, OpenGL {
|
||||
auto setFormat(string format) -> bool override {
|
||||
if(format == "RGB24") {
|
||||
OpenGL::inputFormat = GL_RGBA8;
|
||||
return true;
|
||||
return initialize();
|
||||
}
|
||||
|
||||
if(format == "RGB30") {
|
||||
OpenGL::inputFormat = GL_RGB10_A2;
|
||||
return true;
|
||||
return initialize();
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -66,6 +73,21 @@ struct VideoGLX : VideoDriver, OpenGL {
|
||||
if(_doubleBuffer) glXSwapBuffers(_display, _glXWindow);
|
||||
}
|
||||
|
||||
auto size(uint& width, uint& height) -> void override {
|
||||
XWindowAttributes window;
|
||||
XGetWindowAttributes(_display, _window, &window);
|
||||
|
||||
XWindowAttributes parent;
|
||||
XGetWindowAttributes(_display, _parent, &parent);
|
||||
|
||||
if(window.width != parent.width || window.height != parent.height) {
|
||||
XResizeWindow(_display, _window, parent.width, parent.height);
|
||||
}
|
||||
|
||||
width = parent.width;
|
||||
height = parent.height;
|
||||
}
|
||||
|
||||
auto acquire(uint32_t*& data, uint& pitch, uint width, uint height) -> bool override {
|
||||
OpenGL::size(width, height);
|
||||
return OpenGL::lock(data, pitch);
|
||||
@@ -74,20 +96,14 @@ struct VideoGLX : VideoDriver, OpenGL {
|
||||
auto release() -> void override {
|
||||
}
|
||||
|
||||
auto output() -> void override {
|
||||
//we must ensure that the child window is the same size as the parent window.
|
||||
//unfortunately, we cannot hook the parent window resize event notification,
|
||||
//as we did not create the parent window, nor have any knowledge of the toolkit used.
|
||||
//therefore, inelegant as it may be, we query each window size and resize as needed.
|
||||
XWindowAttributes parent, child;
|
||||
XGetWindowAttributes(_display, (Window)self.context, &parent);
|
||||
XGetWindowAttributes(_display, (Window)_window, &child);
|
||||
if(child.width != parent.width || child.height != parent.height) {
|
||||
XResizeWindow(_display, _window, parent.width, parent.height);
|
||||
}
|
||||
auto output(uint width, uint height) -> void override {
|
||||
uint windowWidth, windowHeight;
|
||||
size(windowWidth, windowHeight);
|
||||
|
||||
OpenGL::outputWidth = parent.width;
|
||||
OpenGL::outputHeight = parent.height;
|
||||
OpenGL::absoluteWidth = width;
|
||||
OpenGL::absoluteHeight = height;
|
||||
OpenGL::outputWidth = windowWidth;
|
||||
OpenGL::outputHeight = windowHeight;
|
||||
OpenGL::output();
|
||||
if(_doubleBuffer) glXSwapBuffers(_display, _glXWindow);
|
||||
if(self.flush) glFinish();
|
||||
@@ -106,20 +122,33 @@ struct VideoGLX : VideoDriver, OpenGL {
|
||||
}
|
||||
|
||||
private:
|
||||
auto initialize() -> bool {
|
||||
terminate();
|
||||
if(!self.context) return false;
|
||||
|
||||
auto construct() -> void {
|
||||
_display = XOpenDisplay(nullptr);
|
||||
_screen = DefaultScreen(_display);
|
||||
|
||||
XWindowAttributes attributes{};
|
||||
XGetWindowAttributes(_display, RootWindow(_display, _screen), &attributes);
|
||||
_depth = attributes.depth;
|
||||
}
|
||||
|
||||
auto destruct() -> void {
|
||||
terminate();
|
||||
|
||||
if(_display) {
|
||||
XCloseDisplay(_display);
|
||||
_display = nullptr;
|
||||
_screen = 0;
|
||||
}
|
||||
}
|
||||
|
||||
auto initialize() -> bool {
|
||||
terminate();
|
||||
if(!self.exclusive && !self.context) return false;
|
||||
|
||||
//require GLX 1.2+ API
|
||||
glXQueryVersion(_display, &_versionMajor, &_versionMinor);
|
||||
if(_versionMajor < 1 || (_versionMajor == 1 && _versionMinor < 2)) return false;
|
||||
|
||||
XWindowAttributes windowAttributes;
|
||||
XGetWindowAttributes(_display, (Window)self.context, &windowAttributes);
|
||||
|
||||
int redDepth = VideoDriver::format == "RGB30" ? 10 : 8;
|
||||
int greenDepth = VideoDriver::format == "RGB30" ? 10 : 8;
|
||||
int blueDepth = VideoDriver::format == "RGB30" ? 10 : 8;
|
||||
@@ -140,22 +169,27 @@ private:
|
||||
GLXFBConfig* fbConfig = glXChooseFBConfig(_display, _screen, attributeList, &fbCount);
|
||||
if(fbCount == 0) return false;
|
||||
|
||||
XVisualInfo* vi = glXGetVisualFromFBConfig(_display, fbConfig[0]);
|
||||
auto visual = glXGetVisualFromFBConfig(_display, fbConfig[0]);
|
||||
|
||||
_parent = self.exclusive ? RootWindow(_display, visual->screen) : (Window)self.context;
|
||||
XWindowAttributes windowAttributes;
|
||||
XGetWindowAttributes(_display, _parent, &windowAttributes);
|
||||
|
||||
//(Window)self.context has already been realized, most likely with DefaultVisual.
|
||||
//GLX requires that the GL output window has the same Visual as the GLX context.
|
||||
//it is not possible to change the Visual of an already realized (created) window.
|
||||
//therefore a new child window, using the same GLX Visual, must be created and binded to it.
|
||||
_colormap = XCreateColormap(_display, RootWindow(_display, vi->screen), vi->visual, AllocNone);
|
||||
XSetWindowAttributes attributes = {};
|
||||
attributes.colormap = _colormap;
|
||||
_colormap = XCreateColormap(_display, RootWindow(_display, visual->screen), visual->visual, AllocNone);
|
||||
XSetWindowAttributes attributes{};
|
||||
attributes.border_pixel = 0;
|
||||
_window = XCreateWindow(_display, /* parent = */ (Window)self.context,
|
||||
/* x = */ 0, /* y = */ 0, windowAttributes.width, windowAttributes.height,
|
||||
/* border_width = */ 0, vi->depth, InputOutput, vi->visual,
|
||||
CWColormap | CWBorderPixel, &attributes);
|
||||
attributes.colormap = _colormap;
|
||||
attributes.override_redirect = self.exclusive;
|
||||
_window = XCreateWindow(_display, _parent,
|
||||
0, 0, windowAttributes.width, windowAttributes.height,
|
||||
0, visual->depth, InputOutput, visual->visual,
|
||||
CWBorderPixel | CWColormap | CWOverrideRedirect, &attributes);
|
||||
XSelectInput(_display, _window, ExposureMask);
|
||||
XSetWindowBackground(_display, _window, /* color = */ 0);
|
||||
XSetWindowBackground(_display, _window, 0);
|
||||
XMapWindow(_display, _window);
|
||||
XFlush(_display);
|
||||
|
||||
@@ -165,7 +199,7 @@ private:
|
||||
XNextEvent(_display, &event);
|
||||
}
|
||||
|
||||
_glXContext = glXCreateContext(_display, vi, /* sharelist = */ 0, /* direct = */ GL_TRUE);
|
||||
_glXContext = glXCreateContext(_display, visual, 0, GL_TRUE);
|
||||
glXMakeCurrent(_display, _glXWindow = _window, _glXContext);
|
||||
|
||||
//glXSwapInterval is used to toggle Vsync
|
||||
@@ -203,7 +237,7 @@ private:
|
||||
|
||||
//read attributes of frame buffer for later use, as requested attributes from above are not always granted
|
||||
int value = 0;
|
||||
glXGetConfig(_display, vi, GLX_DOUBLEBUFFER, &value);
|
||||
glXGetConfig(_display, visual, GLX_DOUBLEBUFFER, &value);
|
||||
_doubleBuffer = value;
|
||||
_isDirect = glXIsDirect(_display, _glXContext);
|
||||
|
||||
@@ -228,11 +262,6 @@ private:
|
||||
XFreeColormap(_display, _colormap);
|
||||
_colormap = 0;
|
||||
}
|
||||
|
||||
if(_display) {
|
||||
XCloseDisplay(_display);
|
||||
_display = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool _ready = false;
|
||||
@@ -241,6 +270,8 @@ private:
|
||||
|
||||
Display* _display = nullptr;
|
||||
int _screen = 0;
|
||||
uint _depth = 24; //depth of the default root window
|
||||
Window _parent = 0;
|
||||
Window _window = 0;
|
||||
Colormap _colormap = 0;
|
||||
GLXContext _glXContext = nullptr;
|
||||
|
@@ -23,8 +23,8 @@
|
||||
|
||||
struct VideoGLX2 : VideoDriver {
|
||||
VideoGLX2& self = *this;
|
||||
VideoGLX2(Video& super) : VideoDriver(super) {}
|
||||
~VideoGLX2() { terminate(); }
|
||||
VideoGLX2(Video& super) : VideoDriver(super) { construct(); }
|
||||
~VideoGLX2() { destruct(); }
|
||||
|
||||
auto create() -> bool {
|
||||
super.setFormat("RGB24");
|
||||
@@ -34,12 +34,22 @@ struct VideoGLX2 : VideoDriver {
|
||||
auto driver() -> string override { return "OpenGL 2.0"; }
|
||||
auto ready() -> bool override { return _ready; }
|
||||
|
||||
auto hasExclusive() -> bool override { return true; }
|
||||
auto hasContext() -> bool override { return true; }
|
||||
auto hasBlocking() -> bool override { return true; }
|
||||
auto hasFlush() -> bool override { return true; }
|
||||
auto hasFormats() -> vector<string> override { return {"RGB24", "RGB30"}; }
|
||||
auto hasShader() -> bool override { return true; }
|
||||
|
||||
auto hasFormats() -> vector<string> override {
|
||||
if(_depth == 30) return {"RGB30", "RGB24"};
|
||||
if(_depth == 24) return {"RGB24"};
|
||||
return {"RGB24"}; //fallback
|
||||
}
|
||||
|
||||
auto setExclusive(bool exclusive) -> bool override {
|
||||
return initialize();
|
||||
}
|
||||
|
||||
auto setContext(uintptr context) -> bool override {
|
||||
return initialize();
|
||||
}
|
||||
@@ -67,11 +77,6 @@ struct VideoGLX2 : VideoDriver {
|
||||
return true;
|
||||
}
|
||||
|
||||
auto configure(uint width, uint height, double inputFrequency, double outputFrequency) -> bool override {
|
||||
XResizeWindow(_display, _window, width, height);
|
||||
return true;
|
||||
}
|
||||
|
||||
auto clear() -> void override {
|
||||
memory::fill<uint32_t>(_glBuffer, _glWidth * _glHeight);
|
||||
glClearColor(0.0, 0.0, 0.0, 1.0);
|
||||
@@ -80,6 +85,21 @@ struct VideoGLX2 : VideoDriver {
|
||||
if(_isDoubleBuffered) glXSwapBuffers(_display, _glXWindow);
|
||||
}
|
||||
|
||||
auto size(uint& width, uint& height) -> void override {
|
||||
XWindowAttributes window;
|
||||
XGetWindowAttributes(_display, _window, &window);
|
||||
|
||||
XWindowAttributes parent;
|
||||
XGetWindowAttributes(_display, _parent, &parent);
|
||||
|
||||
if(window.width != parent.width || window.height != parent.height) {
|
||||
XResizeWindow(_display, _window, parent.width, parent.height);
|
||||
}
|
||||
|
||||
width = parent.width;
|
||||
height = parent.height;
|
||||
}
|
||||
|
||||
auto acquire(uint32_t*& data, uint& pitch, uint width, uint height) -> bool override {
|
||||
if(width != _width || height != _height) resize(width, height);
|
||||
pitch = _glWidth * sizeof(uint32_t);
|
||||
@@ -89,7 +109,15 @@ struct VideoGLX2 : VideoDriver {
|
||||
auto release() -> void override {
|
||||
}
|
||||
|
||||
auto output() -> void override {
|
||||
auto output(uint width, uint height) -> void override {
|
||||
uint windowWidth, windowHeight;
|
||||
size(windowWidth, windowHeight);
|
||||
|
||||
if(!width) width = windowWidth;
|
||||
if(!height) height = windowHeight;
|
||||
int x = ((int)windowWidth - (int)width) / 2;
|
||||
int y = ((int)windowHeight - (int)height) / 2;
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, self.shader == "Blur" ? GL_LINEAR : GL_NEAREST);
|
||||
@@ -97,8 +125,8 @@ struct VideoGLX2 : VideoDriver {
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
glOrtho(0, self.width, 0, self.height, -1.0, 1.0);
|
||||
glViewport(0, 0, self.width, self.height);
|
||||
glOrtho(0, windowWidth, 0, windowHeight, -1.0, 1.0);
|
||||
glViewport(x, y, width, height);
|
||||
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
@@ -107,8 +135,8 @@ struct VideoGLX2 : VideoDriver {
|
||||
|
||||
double w = (double)_width / (double)_glWidth;
|
||||
double h = (double)_height / (double)_glHeight;
|
||||
int u = self.width;
|
||||
int v = self.height;
|
||||
int u = windowWidth;
|
||||
int v = windowHeight;
|
||||
|
||||
glBegin(GL_TRIANGLE_STRIP);
|
||||
glTexCoord2f(0, 0); glVertex3i(0, v, 0);
|
||||
@@ -135,20 +163,33 @@ struct VideoGLX2 : VideoDriver {
|
||||
}
|
||||
|
||||
private:
|
||||
auto initialize() -> bool {
|
||||
terminate();
|
||||
if(!self.context) return false;
|
||||
|
||||
auto construct() -> void {
|
||||
_display = XOpenDisplay(nullptr);
|
||||
_screen = DefaultScreen(_display);
|
||||
|
||||
XWindowAttributes attributes{};
|
||||
XGetWindowAttributes(_display, RootWindow(_display, _screen), &attributes);
|
||||
_depth = attributes.depth;
|
||||
}
|
||||
|
||||
auto destruct() -> void {
|
||||
terminate();
|
||||
|
||||
if(_display) {
|
||||
XCloseDisplay(_display);
|
||||
_display = nullptr;
|
||||
_screen = 0;
|
||||
}
|
||||
}
|
||||
|
||||
auto initialize() -> bool {
|
||||
terminate();
|
||||
if(!self.exclusive && !self.context) return false;
|
||||
|
||||
int versionMajor = 0, versionMinor = 0;
|
||||
glXQueryVersion(_display, &versionMajor, &versionMinor);
|
||||
if(versionMajor < 1 || (versionMajor == 1 && versionMinor < 2)) return false;
|
||||
|
||||
XWindowAttributes windowAttributes;
|
||||
XGetWindowAttributes(_display, (Window)self.context, &windowAttributes);
|
||||
|
||||
int redDepth = self.format == "RGB30" ? 10 : 8;
|
||||
int greenDepth = self.format == "RGB30" ? 10 : 8;
|
||||
int blueDepth = self.format == "RGB30" ? 10 : 8;
|
||||
@@ -167,13 +208,21 @@ private:
|
||||
auto fbConfig = glXChooseFBConfig(_display, _screen, attributeList, &fbCount);
|
||||
if(fbCount == 0) return false;
|
||||
|
||||
auto vi = glXGetVisualFromFBConfig(_display, fbConfig[0]);
|
||||
_colormap = XCreateColormap(_display, RootWindow(_display, vi->screen), vi->visual, AllocNone);
|
||||
XSetWindowAttributes attributes = {};
|
||||
attributes.colormap = _colormap;
|
||||
auto visual = glXGetVisualFromFBConfig(_display, fbConfig[0]);
|
||||
|
||||
_parent = self.exclusive ? RootWindow(_display, visual->screen) : (Window)self.context;
|
||||
XWindowAttributes windowAttributes;
|
||||
XGetWindowAttributes(_display, _parent, &windowAttributes);
|
||||
|
||||
_colormap = XCreateColormap(_display, RootWindow(_display, visual->screen), visual->visual, AllocNone);
|
||||
XSetWindowAttributes attributes{};
|
||||
attributes.border_pixel = 0;
|
||||
_window = XCreateWindow(_display, (Window)self.context, 0, 0, windowAttributes.width, windowAttributes.height,
|
||||
0, vi->depth, InputOutput, vi->visual, CWColormap | CWBorderPixel, &attributes);
|
||||
attributes.colormap = _colormap;
|
||||
attributes.override_redirect = self.exclusive;
|
||||
_window = XCreateWindow(_display, _parent,
|
||||
0, 0, windowAttributes.width, windowAttributes.height,
|
||||
0, visual->depth, InputOutput, visual->visual,
|
||||
CWBorderPixel | CWColormap | CWOverrideRedirect, &attributes);
|
||||
XSelectInput(_display, _window, ExposureMask);
|
||||
XSetWindowBackground(_display, _window, 0);
|
||||
XMapWindow(_display, _window);
|
||||
@@ -184,7 +233,7 @@ private:
|
||||
XNextEvent(_display, &event);
|
||||
}
|
||||
|
||||
_glXContext = glXCreateContext(_display, vi, 0, GL_TRUE);
|
||||
_glXContext = glXCreateContext(_display, visual, 0, GL_TRUE);
|
||||
glXMakeCurrent(_display, _glXWindow = _window, _glXContext);
|
||||
|
||||
if(!glXSwapInterval) glXSwapInterval = (int (*)(int))glGetProcAddress("glXSwapIntervalMESA");
|
||||
@@ -193,7 +242,7 @@ private:
|
||||
if(glXSwapInterval) glXSwapInterval(self.blocking);
|
||||
|
||||
int value = 0;
|
||||
glXGetConfig(_display, vi, GLX_DOUBLEBUFFER, &value);
|
||||
glXGetConfig(_display, visual, GLX_DOUBLEBUFFER, &value);
|
||||
_isDoubleBuffered = value;
|
||||
_isDirect = glXIsDirect(_display, _glXContext);
|
||||
|
||||
@@ -240,11 +289,6 @@ private:
|
||||
XFreeColormap(_display, _colormap);
|
||||
_colormap = 0;
|
||||
}
|
||||
|
||||
if(_display) {
|
||||
XCloseDisplay(_display);
|
||||
_display = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
auto resize(uint width, uint height) -> void {
|
||||
@@ -267,6 +311,8 @@ private:
|
||||
|
||||
Display* _display = nullptr;
|
||||
int _screen = 0;
|
||||
uint _depth = 24; //depth of the default root window
|
||||
Window _parent = 0;
|
||||
Window _window = 0;
|
||||
Colormap _colormap = 0;
|
||||
GLXContext _glXContext = nullptr;
|
||||
|
@@ -60,7 +60,7 @@ auto OpenGLSurface::render(uint sourceWidth, uint sourceHeight, uint targetWidth
|
||||
};
|
||||
|
||||
GLfloat modelViewProjection[4 * 4];
|
||||
Matrix::Multiply(modelViewProjection, modelView, 4, 4, projection, 4, 4);
|
||||
MatrixMultiply(modelViewProjection, modelView, 4, 4, projection, 4, 4);
|
||||
|
||||
GLfloat vertices[] = {
|
||||
0, 0, 0, 1,
|
||||
@@ -71,7 +71,7 @@ auto OpenGLSurface::render(uint sourceWidth, uint sourceHeight, uint targetWidth
|
||||
|
||||
GLfloat positions[4 * 4];
|
||||
for(uint n = 0; n < 16; n += 4) {
|
||||
Matrix::Multiply(&positions[n], &vertices[n], 1, 4, modelViewProjection, 4, 4);
|
||||
MatrixMultiply(&positions[n], &vertices[n], 1, 4, modelViewProjection, 4, 4);
|
||||
}
|
||||
|
||||
GLfloat texCoords[] = {
|
||||
|
@@ -80,18 +80,16 @@ auto Video::setShader(string shader) -> bool {
|
||||
|
||||
//
|
||||
|
||||
auto Video::configure(uint width, uint height, double inputFrequency, double outputFrequency) -> bool {
|
||||
instance->width = width;
|
||||
instance->height = height;
|
||||
instance->inputFrequency = inputFrequency;
|
||||
instance->outputFrequency = outputFrequency;
|
||||
return instance->configure(width, height, inputFrequency, outputFrequency);
|
||||
}
|
||||
|
||||
auto Video::clear() -> void {
|
||||
return instance->clear();
|
||||
}
|
||||
|
||||
auto Video::size() -> Size {
|
||||
Size result;
|
||||
instance->size(result.width, result.height);
|
||||
return result;
|
||||
}
|
||||
|
||||
auto Video::acquire(uint width, uint height) -> Acquire {
|
||||
Acquire result;
|
||||
if(instance->acquire(result.data, result.pitch, width, height)) return result;
|
||||
@@ -102,8 +100,8 @@ auto Video::release() -> void {
|
||||
return instance->release();
|
||||
}
|
||||
|
||||
auto Video::output() -> void {
|
||||
return instance->output();
|
||||
auto Video::output(uint width, uint height) -> void {
|
||||
return instance->output(width, height);
|
||||
}
|
||||
|
||||
auto Video::poll() -> void {
|
||||
|
@@ -24,11 +24,11 @@ struct VideoDriver {
|
||||
virtual auto setFormat(string format) -> bool { return true; }
|
||||
virtual auto setShader(string shader) -> bool { return true; }
|
||||
|
||||
virtual auto configure(uint width, uint height, double inputFrequency, double outputFrequency) -> bool { return true; }
|
||||
virtual auto clear() -> void {}
|
||||
virtual auto size(uint& width, uint& height) -> void {}
|
||||
virtual auto acquire(uint32_t*& data, uint& pitch, uint width, uint height) -> bool { return false; }
|
||||
virtual auto release() -> void {}
|
||||
virtual auto output() -> void {}
|
||||
virtual auto output(uint width = 0, uint height = 0) -> void {}
|
||||
virtual auto poll() -> void {}
|
||||
|
||||
protected:
|
||||
@@ -41,11 +41,6 @@ protected:
|
||||
bool flush = false;
|
||||
string format = "RGB24";
|
||||
string shader = "Blur";
|
||||
|
||||
uint width = 0;
|
||||
uint height = 0;
|
||||
double inputFrequency = 0.0;
|
||||
double outputFrequency = 0.0;
|
||||
};
|
||||
|
||||
struct Video {
|
||||
@@ -84,8 +79,12 @@ struct Video {
|
||||
auto setFormat(string format) -> bool;
|
||||
auto setShader(string shader) -> bool;
|
||||
|
||||
auto configure(uint width, uint height, double inputFrequency, double outputFrequency) -> bool;
|
||||
auto clear() -> void;
|
||||
struct Size {
|
||||
uint width = 0;
|
||||
uint height = 0;
|
||||
};
|
||||
auto size() -> Size;
|
||||
struct Acquire {
|
||||
explicit operator bool() const { return data; }
|
||||
uint32_t* data = nullptr;
|
||||
@@ -93,7 +92,7 @@ struct Video {
|
||||
};
|
||||
auto acquire(uint width, uint height) -> Acquire;
|
||||
auto release() -> void;
|
||||
auto output() -> void;
|
||||
auto output(uint width = 0, uint height = 0) -> void;
|
||||
auto poll() -> void;
|
||||
|
||||
auto onUpdate(const function<void (uint, uint)>&) -> void;
|
||||
|
@@ -3,10 +3,14 @@
|
||||
#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091
|
||||
#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092
|
||||
|
||||
static LRESULT CALLBACK VideoOpenGL32_WindowProcedure(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
|
||||
return DefWindowProc(hwnd, msg, wparam, lparam);
|
||||
}
|
||||
|
||||
struct VideoWGL : VideoDriver, OpenGL {
|
||||
VideoWGL& self = *this;
|
||||
VideoWGL(Video& super) : VideoDriver(super) {}
|
||||
~VideoWGL() { terminate(); }
|
||||
VideoWGL(Video& super) : VideoDriver(super) { construct(); }
|
||||
~VideoWGL() { destruct(); }
|
||||
|
||||
auto create() -> bool override {
|
||||
return initialize();
|
||||
@@ -15,11 +19,16 @@ struct VideoWGL : VideoDriver, OpenGL {
|
||||
auto driver() -> string override { return "OpenGL 3.2"; }
|
||||
auto ready() -> bool override { return _ready; }
|
||||
|
||||
auto hasExclusive() -> bool override { return true; }
|
||||
auto hasContext() -> bool override { return true; }
|
||||
auto hasBlocking() -> bool override { return true; }
|
||||
auto hasFlush() -> bool override { return true; }
|
||||
auto hasShader() -> bool override { return true; }
|
||||
|
||||
auto setExclusive(bool exclusive) -> bool override {
|
||||
return initialize();
|
||||
}
|
||||
|
||||
auto setContext(uintptr context) -> bool override {
|
||||
return initialize();
|
||||
}
|
||||
@@ -43,6 +52,13 @@ struct VideoWGL : VideoDriver, OpenGL {
|
||||
SwapBuffers(_display);
|
||||
}
|
||||
|
||||
auto size(uint& width, uint& height) -> void {
|
||||
RECT rectangle;
|
||||
GetClientRect(_context, &rectangle);
|
||||
width = rectangle.right - rectangle.left;
|
||||
height = rectangle.bottom - rectangle.top;
|
||||
}
|
||||
|
||||
auto acquire(uint32_t*& data, uint& pitch, uint width, uint height) -> bool override {
|
||||
OpenGL::size(width, height);
|
||||
return OpenGL::lock(data, pitch);
|
||||
@@ -51,28 +67,65 @@ struct VideoWGL : VideoDriver, OpenGL {
|
||||
auto release() -> void override {
|
||||
}
|
||||
|
||||
auto output() -> void override {
|
||||
RECT rectangle;
|
||||
GetClientRect((HWND)self.context, &rectangle);
|
||||
OpenGL::outputWidth = rectangle.right - rectangle.left;
|
||||
OpenGL::outputHeight = rectangle.bottom - rectangle.top;
|
||||
auto output(uint width, uint height) -> void override {
|
||||
uint windowWidth, windowHeight;
|
||||
size(windowWidth, windowHeight);
|
||||
OpenGL::absoluteWidth = width;
|
||||
OpenGL::absoluteHeight = height;
|
||||
OpenGL::outputWidth = windowWidth;
|
||||
OpenGL::outputHeight = windowHeight;
|
||||
OpenGL::output();
|
||||
SwapBuffers(_display);
|
||||
if(self.flush) glFinish();
|
||||
}
|
||||
|
||||
private:
|
||||
auto construct() -> void {
|
||||
WNDCLASS windowClass{};
|
||||
windowClass.cbClsExtra = 0;
|
||||
windowClass.cbWndExtra = 0;
|
||||
windowClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
|
||||
windowClass.hCursor = LoadCursor(0, IDC_ARROW);
|
||||
windowClass.hIcon = LoadIcon(nullptr, IDI_APPLICATION);
|
||||
windowClass.hInstance = GetModuleHandle(0);
|
||||
windowClass.lpfnWndProc = VideoOpenGL32_WindowProcedure;
|
||||
windowClass.lpszClassName = L"VideoOpenGL32_Window";
|
||||
windowClass.lpszMenuName = 0;
|
||||
windowClass.style = CS_HREDRAW | CS_VREDRAW;
|
||||
RegisterClass(&windowClass);
|
||||
}
|
||||
|
||||
auto destruct() -> void {
|
||||
terminate();
|
||||
}
|
||||
|
||||
auto initialize() -> bool {
|
||||
terminate();
|
||||
if(!self.context) return false;
|
||||
if(!self.exclusive && !self.context) return false;
|
||||
|
||||
PIXELFORMATDESCRIPTOR descriptor = {};
|
||||
POINT point{0, 0};
|
||||
HMONITOR monitor = MonitorFromPoint(point, MONITOR_DEFAULTTOPRIMARY);
|
||||
MONITORINFOEX information{};
|
||||
information.cbSize = sizeof(MONITORINFOEX);
|
||||
GetMonitorInfo(monitor, &information);
|
||||
_monitorWidth = information.rcMonitor.right - information.rcMonitor.left;
|
||||
_monitorHeight = information.rcMonitor.bottom - information.rcMonitor.top;
|
||||
|
||||
if(self.exclusive) {
|
||||
_context = _exclusive = CreateWindowEx(WS_EX_TOPMOST, L"VideoOpenGL32_Window", L"", WS_VISIBLE | WS_POPUP,
|
||||
information.rcMonitor.left, information.rcMonitor.top, _monitorWidth, _monitorHeight,
|
||||
nullptr, nullptr, GetModuleHandle(0), nullptr);
|
||||
} else {
|
||||
_context = (HWND)self.context;
|
||||
}
|
||||
|
||||
PIXELFORMATDESCRIPTOR descriptor{};
|
||||
descriptor.nSize = sizeof(PIXELFORMATDESCRIPTOR);
|
||||
descriptor.nVersion = 1;
|
||||
descriptor.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
|
||||
descriptor.iPixelType = PFD_TYPE_RGBA;
|
||||
|
||||
_display = GetDC((HWND)self.context);
|
||||
_display = GetDC(_context);
|
||||
GLuint pixelFormat = ChoosePixelFormat(_display, &descriptor);
|
||||
SetPixelFormat(_display, pixelFormat, &descriptor);
|
||||
|
||||
@@ -108,6 +161,13 @@ private:
|
||||
wglDeleteContext(_wglContext);
|
||||
_wglContext = nullptr;
|
||||
}
|
||||
|
||||
if(_exclusive) {
|
||||
DestroyWindow(_exclusive);
|
||||
_exclusive = nullptr;
|
||||
}
|
||||
|
||||
_context = nullptr;
|
||||
}
|
||||
|
||||
auto (APIENTRY* wglCreateContextAttribs)(HDC, HGLRC, const int*) -> HGLRC = nullptr;
|
||||
@@ -115,6 +175,11 @@ private:
|
||||
|
||||
bool _ready = false;
|
||||
|
||||
uint _monitorWidth = 0;
|
||||
uint _monitorHeight = 0;
|
||||
|
||||
HWND _exclusive = nullptr;
|
||||
HWND _context = nullptr;
|
||||
HDC _display = nullptr;
|
||||
HGLRC _wglContext = nullptr;
|
||||
HINSTANCE _glWindow = nullptr;
|
||||
|
@@ -20,33 +20,16 @@ struct VideoXShm : VideoDriver {
|
||||
auto driver() -> string override { return "XShm"; }
|
||||
auto ready() -> bool override { return _ready; }
|
||||
|
||||
auto hasExclusive() -> bool override { return true; }
|
||||
auto hasContext() -> bool override { return true; }
|
||||
auto hasShader() -> bool override { return true; }
|
||||
|
||||
auto hasFormats() -> vector<string> override { return {"RGB24"}; }
|
||||
|
||||
auto setExclusive(bool exclusive) -> bool override { return initialize(); }
|
||||
auto setContext(uintptr context) -> bool override { return initialize(); }
|
||||
auto setShader(string shader) -> bool override { return true; }
|
||||
|
||||
auto configure(uint width, uint height, double inputFrequency, double outputFrequency) -> bool override {
|
||||
if(width == _outputWidth && height == _outputHeight) return true;
|
||||
|
||||
_outputWidth = width;
|
||||
_outputHeight = height;
|
||||
XResizeWindow(_display, _window, _outputWidth, _outputHeight);
|
||||
free();
|
||||
|
||||
_shmInfo.shmid = shmget(IPC_PRIVATE, _outputWidth * _outputHeight * sizeof(uint32_t), IPC_CREAT | 0777);
|
||||
if(_shmInfo.shmid < 0) return false;
|
||||
|
||||
_shmInfo.shmaddr = (char*)shmat(_shmInfo.shmid, 0, 0);
|
||||
_shmInfo.readOnly = False;
|
||||
XShmAttach(_display, &_shmInfo);
|
||||
_outputBuffer = (uint32_t*)_shmInfo.shmaddr;
|
||||
_image = XShmCreateImage(_display, _visual, _depth, ZPixmap, _shmInfo.shmaddr, &_shmInfo, _outputWidth, _outputHeight);
|
||||
return (bool)_image;
|
||||
}
|
||||
|
||||
auto clear() -> void override {
|
||||
auto dp = _inputBuffer;
|
||||
uint length = _inputWidth * _inputHeight;
|
||||
@@ -54,6 +37,24 @@ struct VideoXShm : VideoDriver {
|
||||
output();
|
||||
}
|
||||
|
||||
auto size(uint& width, uint& height) -> void override {
|
||||
XWindowAttributes window;
|
||||
XGetWindowAttributes(_display, _window, &window);
|
||||
|
||||
XWindowAttributes parent;
|
||||
XGetWindowAttributes(_display, _parent, &parent);
|
||||
|
||||
if(window.width != parent.width || window.height != parent.height) {
|
||||
_outputWidth = parent.width;
|
||||
_outputHeight = parent.height;
|
||||
XResizeWindow(_display, _window, _outputWidth, _outputHeight);
|
||||
allocate();
|
||||
}
|
||||
|
||||
width = parent.width;
|
||||
height = parent.height;
|
||||
}
|
||||
|
||||
auto acquire(uint32_t*& data, uint& pitch, uint width, uint height) -> bool override {
|
||||
if(!_inputBuffer || _inputWidth != width || _inputHeight != height) {
|
||||
if(_inputBuffer) delete[] _inputBuffer;
|
||||
@@ -70,25 +71,51 @@ struct VideoXShm : VideoDriver {
|
||||
auto release() -> void override {
|
||||
}
|
||||
|
||||
auto output() -> void override {
|
||||
float xratio = (float)_inputWidth / (float)_outputWidth;
|
||||
float yratio = (float)_inputHeight / (float)_outputHeight;
|
||||
auto output(uint width = 0, uint height = 0) -> void override {
|
||||
uint windowWidth, windowHeight;
|
||||
size(windowWidth, windowHeight);
|
||||
if(!_image) return;
|
||||
|
||||
if(!width) width = _outputWidth;
|
||||
if(!height) height = _outputHeight;
|
||||
|
||||
float xratio = (float)_inputWidth / (float)width;
|
||||
float yratio = (float)_inputHeight / (float)height;
|
||||
|
||||
int x = ((int)_outputWidth - (int)width) / 2;
|
||||
int y = ((int)_outputHeight - (int)height) / 2;
|
||||
|
||||
width = min(width, _outputWidth);
|
||||
height = min(height, _outputHeight);
|
||||
|
||||
auto inputBuffer = _inputBuffer;
|
||||
auto outputBuffer = _outputBuffer;
|
||||
|
||||
if(x < 0) {
|
||||
inputBuffer += abs(x);
|
||||
x = 0;
|
||||
}
|
||||
|
||||
if(y < 0) {
|
||||
inputBuffer += abs(y) * _inputWidth;
|
||||
y = 0;
|
||||
}
|
||||
|
||||
#pragma omp parallel for
|
||||
for(uint y = 0; y < _outputHeight; y++) {
|
||||
for(uint y = 0; y < height; y++) {
|
||||
float ystep = y * yratio;
|
||||
float xstep = 0;
|
||||
|
||||
uint32_t* sp = _inputBuffer + (uint)ystep * _inputWidth;
|
||||
uint32_t* dp = _outputBuffer + y * _outputWidth;
|
||||
uint32_t* sp = inputBuffer + (uint)ystep * _inputWidth;
|
||||
uint32_t* dp = outputBuffer + y * _outputWidth;
|
||||
|
||||
if(self.shader != "Blur") {
|
||||
for(uint x = 0; x < _outputWidth; x++) {
|
||||
for(uint x = 0; x < width; x++) {
|
||||
*dp++ = 255u << 24 | sp[(uint)xstep];
|
||||
xstep += xratio;
|
||||
}
|
||||
} else {
|
||||
for(uint x = 0; x < _outputWidth; x++) {
|
||||
for(uint x = 0; x < width; x++) {
|
||||
*dp++ = 255u << 24 | interpolate(xstep - (uint)xstep, sp[(uint)xstep], sp[(uint)xstep + 1]);
|
||||
xstep += xratio;
|
||||
}
|
||||
@@ -96,7 +123,7 @@ struct VideoXShm : VideoDriver {
|
||||
}
|
||||
|
||||
GC gc = XCreateGC(_display, _window, 0, 0);
|
||||
XShmPutImage(_display, _window, gc, _image, 0, 0, 0, 0, _outputWidth, _outputHeight, False);
|
||||
XShmPutImage(_display, _window, gc, _image, 0, 0, x, y, width, height, False);
|
||||
XFreeGC(_display, gc);
|
||||
XFlush(_display);
|
||||
}
|
||||
@@ -126,12 +153,16 @@ private:
|
||||
|
||||
auto initialize() -> bool {
|
||||
terminate();
|
||||
if(!self.context) return false;
|
||||
if(!self.exclusive && !self.context) return false;
|
||||
|
||||
XWindowAttributes getAttributes{};
|
||||
XGetWindowAttributes(_display, (Window)self.context, &getAttributes);
|
||||
_depth = getAttributes.depth;
|
||||
_visual = getAttributes.visual;
|
||||
_parent = self.exclusive ? RootWindow(_display, _screen) : (Window)self.context;
|
||||
|
||||
XWindowAttributes windowAttributes{};
|
||||
XGetWindowAttributes(_display, _parent, &windowAttributes);
|
||||
_outputWidth = windowAttributes.width;
|
||||
_outputHeight = windowAttributes.height;
|
||||
_depth = windowAttributes.depth;
|
||||
_visual = windowAttributes.visual;
|
||||
//driver only supports 32-bit pixels
|
||||
//note that even on 15-bit and 16-bit displays, the window visual's depth should be 32
|
||||
if(_depth < 24 || _depth > 32) {
|
||||
@@ -139,12 +170,15 @@ private:
|
||||
return false;
|
||||
}
|
||||
|
||||
XSetWindowAttributes setAttributes = {};
|
||||
setAttributes.border_pixel = 0;
|
||||
_window = XCreateWindow(_display, (Window)self.context,
|
||||
0, 0, 256, 256, 0,
|
||||
getAttributes.depth, InputOutput, getAttributes.visual,
|
||||
CWBorderPixel, &setAttributes
|
||||
_colormap = XCreateColormap(_display, _parent, _visual, AllocNone);
|
||||
XSetWindowAttributes attributes{};
|
||||
attributes.border_pixel = 0;
|
||||
attributes.colormap = _colormap;
|
||||
attributes.override_redirect = self.exclusive;
|
||||
_window = XCreateWindow(_display, _parent,
|
||||
0, 0, _outputWidth, _outputHeight,
|
||||
0, _depth, InputOutput, _visual,
|
||||
CWBorderPixel | CWColormap | CWOverrideRedirect, &attributes
|
||||
);
|
||||
XSelectInput(_display, _window, ExposureMask);
|
||||
XSetWindowBackground(_display, _window, 0);
|
||||
@@ -156,11 +190,30 @@ private:
|
||||
XNextEvent(_display, &event);
|
||||
}
|
||||
|
||||
allocate();
|
||||
return _ready = true;
|
||||
}
|
||||
|
||||
auto terminate() -> void {
|
||||
free();
|
||||
|
||||
if(_colormap) {
|
||||
XFreeColormap(_display, _colormap);
|
||||
_colormap = 0;
|
||||
}
|
||||
}
|
||||
|
||||
auto allocate() -> void {
|
||||
free();
|
||||
|
||||
_shmInfo.shmid = shmget(IPC_PRIVATE, _outputWidth * _outputHeight * sizeof(uint32_t), IPC_CREAT | 0777);
|
||||
if(_shmInfo.shmid < 0) return;
|
||||
|
||||
_shmInfo.shmaddr = (char*)shmat(_shmInfo.shmid, 0, 0);
|
||||
_shmInfo.readOnly = False;
|
||||
XShmAttach(_display, &_shmInfo);
|
||||
_outputBuffer = (uint32_t*)_shmInfo.shmaddr;
|
||||
_image = XShmCreateImage(_display, _visual, _depth, ZPixmap, _shmInfo.shmaddr, &_shmInfo, _outputWidth, _outputHeight);
|
||||
}
|
||||
|
||||
auto free() -> void {
|
||||
@@ -198,7 +251,9 @@ private:
|
||||
int _screen = 0;
|
||||
int _depth = 0;
|
||||
Visual* _visual = nullptr;
|
||||
Window _parent = 0;
|
||||
Window _window = 0;
|
||||
Colormap _colormap = 0;
|
||||
|
||||
XShmSegmentInfo _shmInfo;
|
||||
XImage* _image = nullptr;
|
||||
|
@@ -19,6 +19,7 @@ struct VideoXVideo : VideoDriver {
|
||||
auto driver() -> string override { return "XVideo"; }
|
||||
auto ready() -> bool override { return _ready; }
|
||||
|
||||
auto hasExclusive() -> bool override { return true; }
|
||||
auto hasContext() -> bool override { return true; }
|
||||
auto hasBlocking() -> bool override { return true; }
|
||||
|
||||
@@ -26,6 +27,10 @@ struct VideoXVideo : VideoDriver {
|
||||
return _formatNames;
|
||||
}
|
||||
|
||||
auto setExclusive(bool exclusive) -> bool override {
|
||||
return initialize();
|
||||
}
|
||||
|
||||
auto setContext(uintptr context) -> bool override {
|
||||
return initialize();
|
||||
}
|
||||
@@ -53,6 +58,21 @@ struct VideoXVideo : VideoDriver {
|
||||
output();
|
||||
}
|
||||
|
||||
auto size(uint& width, uint& height) -> void override {
|
||||
XWindowAttributes window;
|
||||
XGetWindowAttributes(_display, _window, &window);
|
||||
|
||||
XWindowAttributes parent;
|
||||
XGetWindowAttributes(_display, _parent, &parent);
|
||||
|
||||
if(window.width != parent.width || window.height != parent.height) {
|
||||
XResizeWindow(_display, _window, parent.width, parent.height);
|
||||
}
|
||||
|
||||
width = parent.width;
|
||||
height = parent.height;
|
||||
}
|
||||
|
||||
auto acquire(uint32_t*& data, uint& pitch, uint width, uint height) -> bool override {
|
||||
if(width != _width || height != _height) resize(_width = width, _height = height);
|
||||
pitch = _bufferWidth * 4;
|
||||
@@ -62,22 +82,9 @@ struct VideoXVideo : VideoDriver {
|
||||
auto release() -> void override {
|
||||
}
|
||||
|
||||
auto output() -> void override {
|
||||
XWindowAttributes target;
|
||||
XGetWindowAttributes(_display, _window, &target);
|
||||
|
||||
//we must ensure that the child window is the same size as the parent window.
|
||||
//unfortunately, we cannot hook the parent window resize event notification,
|
||||
//as we did not create the parent window, nor have any knowledge of the toolkit used.
|
||||
//therefore, query each window size and resize as needed.
|
||||
XWindowAttributes parent;
|
||||
XGetWindowAttributes(_display, (Window)self.context, &parent);
|
||||
if(target.width != parent.width || target.height != parent.height) {
|
||||
XResizeWindow(_display, _window, parent.width, parent.height);
|
||||
}
|
||||
|
||||
//update target width and height attributes
|
||||
XGetWindowAttributes(_display, _window, &target);
|
||||
auto output(uint width = 0, uint height = 0) -> void override {
|
||||
uint windowWidth, windowHeight;
|
||||
size(windowWidth, windowHeight);
|
||||
|
||||
auto& name = _formatName;
|
||||
if(name == "RGB24" ) renderRGB24 (_width, _height);
|
||||
@@ -89,9 +96,14 @@ struct VideoXVideo : VideoDriver {
|
||||
if(name == "YV12" ) renderYV12 (_width, _height);
|
||||
if(name == "I420" ) renderI420 (_width, _height);
|
||||
|
||||
if(!width) width = windowWidth;
|
||||
if(!height) height = windowHeight;
|
||||
int x = (windowWidth - width) / 2;
|
||||
int y = (windowHeight - height) / 2;
|
||||
|
||||
XvShmPutImage(_display, _port, _window, _gc, _image,
|
||||
0, 0, _width, _height,
|
||||
0, 0, target.width, target.height,
|
||||
x, y, width, height,
|
||||
true);
|
||||
}
|
||||
|
||||
@@ -110,9 +122,10 @@ struct VideoXVideo : VideoDriver {
|
||||
private:
|
||||
auto initialize() -> bool {
|
||||
terminate();
|
||||
if(!self.context) return false;
|
||||
if(!self.exclusive && !self.context) return false;
|
||||
|
||||
_display = XOpenDisplay(nullptr);
|
||||
_screen = DefaultScreen(_display);
|
||||
|
||||
if(!XShmQueryExtension(_display)) {
|
||||
print("XVideo: XShm extension not found.\n");
|
||||
@@ -143,15 +156,9 @@ private:
|
||||
return false;
|
||||
}
|
||||
|
||||
//create child window to attach to parent window.
|
||||
//this is so that even if parent window visual depth doesn't match Xv visual
|
||||
//(common with composited windows), Xv can still render to child window.
|
||||
XWindowAttributes windowAttributes;
|
||||
XGetWindowAttributes(_display, (Window)self.context, &windowAttributes);
|
||||
|
||||
XVisualInfo visualTemplate;
|
||||
visualTemplate.visualid = visualID;
|
||||
visualTemplate.screen = DefaultScreen(_display);
|
||||
visualTemplate.screen = _screen;
|
||||
visualTemplate.depth = depth;
|
||||
visualTemplate.visual = 0;
|
||||
int visualMatches = 0;
|
||||
@@ -162,17 +169,25 @@ private:
|
||||
return false;
|
||||
}
|
||||
|
||||
_colormap = XCreateColormap(_display, (Window)self.context, visualInfo->visual, AllocNone);
|
||||
XSetWindowAttributes attributes = {};
|
||||
attributes.colormap = _colormap;
|
||||
_parent = self.exclusive ? RootWindow(_display, _screen) : (Window)self.context;
|
||||
//create child window to attach to parent window.
|
||||
//this is so that even if parent window visual depth doesn't match Xv visual
|
||||
//(common with composited windows), Xv can still render to child window.
|
||||
XWindowAttributes windowAttributes;
|
||||
XGetWindowAttributes(_display, _parent, &windowAttributes);
|
||||
|
||||
_colormap = XCreateColormap(_display, _parent, visualInfo->visual, AllocNone);
|
||||
XSetWindowAttributes attributes{};
|
||||
attributes.border_pixel = 0;
|
||||
_window = XCreateWindow(_display, /* parent = */ (Window)self.context,
|
||||
/* x = */ 0, /* y = */ 0, windowAttributes.width, windowAttributes.height,
|
||||
/* border_width = */ 0, depth, InputOutput, visualInfo->visual,
|
||||
CWColormap | CWBorderPixel | CWEventMask, &attributes);
|
||||
attributes.colormap = _colormap;
|
||||
attributes.override_redirect = self.exclusive;
|
||||
_window = XCreateWindow(_display, _parent,
|
||||
0, 0, windowAttributes.width, windowAttributes.height,
|
||||
0, depth, InputOutput, visualInfo->visual,
|
||||
CWBorderPixel | CWColormap | CWOverrideRedirect, &attributes);
|
||||
XSelectInput(_display, _window, ExposureMask);
|
||||
XFree(visualInfo);
|
||||
XSetWindowBackground(_display, _window, /* color = */ 0);
|
||||
XSetWindowBackground(_display, _window, 0);
|
||||
XMapWindow(_display, _window);
|
||||
|
||||
_gc = XCreateGC(_display, _window, 0, 0);
|
||||
@@ -500,7 +515,9 @@ private:
|
||||
uint8_t* _vtable = nullptr;
|
||||
|
||||
Display* _display = nullptr;
|
||||
int _screen = 0;
|
||||
GC _gc = 0;
|
||||
Window _parent = 0;
|
||||
Window _window = 0;
|
||||
Colormap _colormap = 0;
|
||||
XShmSegmentInfo _shmInfo;
|
||||
|
Reference in New Issue
Block a user