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:
Tim Allen
2019-07-07 19:44:09 +10:00
parent becbca47d4
commit d87a0f633d
280 changed files with 120826 additions and 1521 deletions

View File

@@ -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)

View File

@@ -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>

View File

@@ -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();

View File

@@ -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;

View File

@@ -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;

View File

@@ -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 = {};

View File

@@ -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;

View File

@@ -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;

View File

@@ -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[] = {

View File

@@ -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 {

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;