43#include <OpenGL/OpenGL.h>
44#include <OpenGL/glext.h>
48#include <GLFW/glfw3.h>
57#include <condition_variable>
65#include <unordered_map>
85#define MAGIC_GL 0x1331018e
86#define MOD_NAME "[GL] "
87#define DEFAULT_WIN_NAME "Ultragrid - OpenGL Display"
88#define GL_DEINTERLACE_IMPOSSIBLE_MSG_ID 0x38e52705
89#define GL_DISABLE_10B_OPT_PARAM_NAME "gl-disable-10b"
90#define GL_WINDOW_HINT_OPT_PARAM_NAME "glfw-window-hint"
91#define MAX_BUFFER_SIZE 1
92#define ADAPTIVE_VSYNC -1
93#define SYSTEM_VSYNC 0xFE
94#define SINGLE_BUF 0xFF
99using std::condition_variable;
105using std::lock_guard;
109using std::ostringstream;
116using std::string_view;
118using std::unique_lock;
119using std::unordered_map;
121using std::chrono::duration;
122using std::chrono::duration_cast;
123using std::chrono::seconds;
124using std::chrono::steady_clock;
125using namespace std::chrono_literals;
129uniform sampler2D image;
130uniform float lineOff;
135 pix = texture2D(image, gl_TexCoord[0].xy);
136 pix_down = texture2D(image, vec2(gl_TexCoord[0].x, gl_TexCoord[0].y + lineOff));
137 gl_FragColor = (pix + pix_down) / 2.0;
143uniform sampler2D image;
144uniform float imageWidth;
148 imageWidthRaw = float((int(imageWidth) + 1) / 2 * 2);
150 yuv.rgba = texture2D(image, vec2(gl_TexCoord[0].x / imageWidthRaw * imageWidth, gl_TexCoord[0].y)).grba;
151 if(gl_TexCoord[0].x * imageWidth / 2.0 - floor(gl_TexCoord[0].x * imageWidth / 2.0) > 0.5)
153 yuv.r = Y_SCALED_PLACEHOLDER * (yuv.r - 0.0625);
156 gl_FragColor.r = yuv.r + R_CR_PLACEHOLDER * yuv.b;
157 gl_FragColor.g = yuv.r + G_CB_PLACEHOLDER * yuv.g + G_CR_PLACEHOLDER * yuv.b;
158 gl_FragColor.b = yuv.r + B_CB_PLACEHOLDER * yuv.g;
159 gl_FragColor.a = 1.0;
165uniform sampler2D image;
169 yuv.rgba = texture2D(image, gl_TexCoord[0].xy).grba;
170 yuv.r = Y_SCALED_PLACEHOLDER * (yuv.r - 0.0625);
173 gl_FragColor.r = yuv.r + R_CR_PLACEHOLDER * yuv.b;
174 gl_FragColor.g = yuv.r + G_CB_PLACEHOLDER * yuv.g + G_CR_PLACEHOLDER * yuv.b;
175 gl_FragColor.b = yuv.r + B_CB_PLACEHOLDER * yuv.g;
176 gl_FragColor.a = yuv.a;
184#extension GL_EXT_gpu_shader4 : enable
185uniform sampler2D image;
186uniform float imageWidth;
189const vec3 yuvOffset = vec3(-0.0625, -0.5, -0.5);
192const vec3 Rcoeff = vec3(Y_SCALED_PLACEHOLDER, 0.0, R_CR_PLACEHOLDER);
193const vec3 Gcoeff = vec3(Y_SCALED_PLACEHOLDER, G_CB_PLACEHOLDER, G_CR_PLACEHOLDER);
194const vec3 Bcoeff = vec3(Y_SCALED_PLACEHOLDER, B_CB_PLACEHOLDER, 0.0);
196// U Y V A | Y U Y A | V Y U A | Y V Y A
198int GROUP_FOR_INDEX(int i) {
202int SUBINDEX_FOR_INDEX(int i) {
215 return 4 * (i / 2) + 2;
222vec3 ycbcr2rgb(vec3 yuvToConvert) {
224 yuvToConvert += yuvOffset;
225 pix.r = dot(yuvToConvert, Rcoeff);
226 pix.g = dot(yuvToConvert, Gcoeff);
227 pix.b = dot(yuvToConvert, Bcoeff);
232 float imageWidthRaw; // v210 texture size
233 imageWidthRaw = float((int(imageWidth) + 47) / 48 * 32); // 720->480
235 // interpolate (0,1) texcoords to [0,719]
237 texcoordDenormX = int(round(gl_TexCoord[0].x * imageWidth - .5));
239 // 0 1 1 2 3 3 4 5 5 6 7 7 etc.
241 yOffset = offset(_y(texcoordDenormX));
242 int sourceColumnIndexY;
243 sourceColumnIndexY = GROUP_FOR_INDEX(yOffset);
245 // 0 0 1 1 2 2 4 4 5 5 6 6 etc.
247 uOffset = offset(_u(texcoordDenormX));
248 int sourceColumnIndexU;
249 sourceColumnIndexU = GROUP_FOR_INDEX(uOffset);
251 // 0 0 2 2 3 3 4 4 6 6 7 7 etc.
253 vOffset = offset(_v(texcoordDenormX));
254 int sourceColumnIndexV;
255 sourceColumnIndexV = GROUP_FOR_INDEX(vOffset);
257 // 1 0 2 1 0 2 1 0 2 etc.
259 compY = SUBINDEX_FOR_INDEX(yOffset);
261 // 0 0 1 1 2 2 0 0 1 1 2 2 etc.
263 compU = SUBINDEX_FOR_INDEX(uOffset);
265 // 2 2 0 0 1 1 2 2 0 0 1 1 etc.
267 compV = SUBINDEX_FOR_INDEX(vOffset);
272 y = texture2D(image, vec2((float(sourceColumnIndexY) + .5) / imageWidthRaw, gl_TexCoord[0].y));
273 u = texture2D(image, vec2((float(sourceColumnIndexU) + .5) / imageWidthRaw, gl_TexCoord[0].y));
274 v = texture2D(image, vec2((float(sourceColumnIndexV) + .5) / imageWidthRaw, gl_TexCoord[0].y));
276 vec3 outColor = ycbcr2rgb(vec3(y[compY], u[compU], v[compV]));
278 gl_FragColor = vec4(outColor, 1.0);
285uniform sampler2D image;
288 vec4 col = texture2D(image, gl_TexCoord[0].st);
290 float Y = 1.1643 * (col[0] - 0.0625);
291 float U = (col[1] - 0.5);
292 float V = (col[2] - 0.5);
294 float R = Y + 1.7926 * V;
295 float G = Y - 0.2132 * U - 0.5328 * V;
296 float B = Y + 2.1124 * U;
298 gl_FragColor=vec4(R,G,B,1.0);
302static const char *
vert = R
"raw(
305 gl_TexCoord[0] = gl_MultiTexCoord0;
306 gl_Position = ftransform();
312uniform sampler2D image;
320 color = texture2D(image, gl_TexCoord[0].xy);
321 scale = (color.z * ( 255.0 / 8.0 )) + 1.0;
322 Co = (color.x - (0.5 * 256.0 / 255.0)) / scale;
323 Cg = (color.y - (0.5 * 256.0 / 255.0)) / scale;
325 gl_FragColor = vec4(Y + Co - Cg, Y + Cg, Y - Co - Cg, 1.0);
338 pair<int64_t, string_view>{
'f',
"toggle fullscreen"},
339 pair<int64_t, string_view>{
'q',
"quit"},
340 pair<int64_t, string_view>{
K_ALT(
'd'),
"toggle deinterlace"},
341 pair<int64_t, string_view>{
K_ALT(
'p'),
"pause video"},
342 pair<int64_t, string_view>{
K_ALT(
's'),
"screenshot"},
343 pair<int64_t, string_view>{
K_ALT(
'c'),
"show/hide cursor"},
344 pair<int64_t, string_view>{
K_CTRL_DOWN,
"make window 10% smaller"},
345 pair<int64_t, string_view>{
K_CTRL_UP,
"make window 10% bigger"}
353static void gl_draw(
double ratio,
double bottom_offset,
bool double_buf);
355static void gl_resize(GLFWwindow *win,
int width,
int height);
429 {GLFW_AUTO_ICONIFY, GLFW_FALSE}
434 struct state_vdpau vdp;
482 printf(
"\nmonitors:\n");
484 GLFWmonitor **mon = glfwGetMonitors(&
count);
488 GLFWmonitor *primary = glfwGetPrimaryMonitor();
489 for (
int i = 0; i <
count; ++i) {
490 col() <<
"\t" << (mon[i] == primary ?
"*" :
" ") <<
TBOLD(<< i <<) <<
") " << glfwGetMonitorName(mon[i]);
491#if GLFW_VERSION_MAJOR > 3 || (GLFW_VERSION_MAJOR == 3 && GLFW_VERSION_MINOR >= 3)
492 int xpos, ypos, width, height;
493 glfwGetMonitorWorkarea(mon[i], &xpos, &ypos, &width, &height);
494 cout <<
" - " << width <<
"x" << height <<
"+" << xpos <<
"+" << ypos <<
"\n";
502 const GLFWvidmode *modes = glfwGetVideoModes(mon[i], &mod_count);
503 for (
int mod = 0; mod < mod_count; ++mod) {
504 cout <<
"\t\t- " << modes[mod].width <<
"x" << modes[mod].height <<
"@" << modes[mod].refreshRate <<
", bits: " <<
505 modes[mod].redBits <<
", " <<
506 modes[mod].greenBits <<
", " <<
507 modes[mod].blueBits <<
"\n";
511 cout <<
"(use \"fullhelp\" to see modes)\n";
517#define FEATURE_PRESENT(x) (strcmp(STRINGIFY(x), "1") == 0 ? "on" : "off")
528 col() <<
SBOLD(
"\t-d gl:[full]help")
"\n\n";
529 col() <<
"options:\n";
530 col() <<
TBOLD(
"\taspect=<w>/<h>") <<
"\trequested video aspect (eg. 16/9). Leave unset if PAR = 1.\n";
531 col() <<
TBOLD(
"\tcursor") <<
"\t\tshow visible cursor\n";
532 col() <<
TBOLD(
"\td[force]") <<
"\tdeinterlace (optionally forcing deinterlace of progressive video)\n";
533 col() <<
TBOLD(
"\tfs[=<monitor>]") <<
"\tfullscreen with optional display specification\n";
535 <<
"\tgamma value to be added _in addition_ to the hardware "
536 "gamma correction\n";
537 col() <<
TBOLD(
"\thide-window") <<
"\tdo not show OpenGL window (useful with Syphon/SPOUT)\n";
539 <<
"\tset received video mode as display mode (in fullscreen)\n"
542 <<
SUNDERLINE(
"modeset=size") <<
" - set only size\n";
543 col() <<
TBOLD(
"\tnodecorate") <<
"\tdisable window decorations\n";
544 col() <<
TBOLD(
"\tnovsync") <<
"\t\tdo not turn sync on VBlank\n";
545 col() <<
TBOLD(
"\t[no]pbo") <<
"\t\tWhether or not use PBO (ignore if not sure)\n";
546 col() <<
TBOLD(
"\tsingle") <<
"\t\tuse single buffer (instead of double-buffering)\n";
548 <<
"\tspecifies desired size of window relative\n"
549 "\t\t\tto native resolution (in percents)\n";
551 <<
"\twindow size in pixels, with optional position; full\n"
552 <<
"\t\t\tsyntax: " TBOLD(
"[<W>x<H>][{+-}<X>[{+-}<Y>]]")
553 << (full ?
" [1]" :
"") <<
"\n";
554 col() <<
TBOLD(
"\tfixed_size") <<
"\tdo not resize window on new stream\n";
555 col() <<
TBOLD(
"\tnoresizable") <<
"\twindow won't be resizable (useful with size=)\n";
557 col() <<
TBOLD(
"\tspout") <<
"\t\tuse Spout (optionally with name)\n";
560 col() <<
TBOLD(
"\tsyphon") <<
"\t\tuse Syphon (optionally with name)\n";
562 col() <<
TBOLD(
"\tvsync=<x>") <<
"\tsets vsync to: 0 - disable; 1 - enable; -1 - adaptive vsync; D - leaves system default\n";
564 col() <<
TBOLD(
"\tinit_hint=<k>=<v>[,<k2>=<v2>]")
" set GLFW "
566 "\t\t\t<k> to value <v> (" TBOLD(
"list_hints")
" to enumerate)\n";
567 col() <<
TBOLD(
"\twindow_hint=<k>=<v>[,<k2>=<v2>]")
" set GLFW "
569 "\t\t\t<k> to value <v>, (" TBOLD(
"list_hints")
" to enumerate)\n";
572 "[1]")
" position doesn't work in Wayland\n";
575 printf(
"\nkeyboard shortcuts:\n");
579 col() <<
"\t" <<
TBOLD(<< keyname <<) <<
"\t\t" << i.second <<
"\n";
583 col() <<
"\nCompiled " <<
SBOLD(
"features: ") <<
"SPOUT - "
598 if (strstr(tok,
"fixed_size=") == tok) {
600 MOD_NAME "fixed_size with dimensions is"
601 " deprecated, use size"
604 tok = strchr(tok,
'=') + 1;
605 if (strchr(tok,
'%') != NULL) {
607 }
else if (strpbrk(tok,
"x+-") == NULL) {
611 if (strchr(tok,
'x') != NULL) {
614 s->
fixed_h = atoi(strchr(tok,
'x') + 1);
616 tok = strpbrk(tok,
"+-");
618 s->
pos_x = atoi(tok);
619 tok = strpbrk(tok + 1,
"+-");
622 s->
pos_y = atoi(tok);
628 {
"autoiconify", 0x20006},
629 {
"platform", 0x50003},
631 {
"wayland", 0x60004},
639 char *save_ptr =
nullptr;
640 while ((tok = strtok_r(hints,
",", &save_ptr)) !=
nullptr) {
642 if (strchr(tok,
'=') ==
nullptr) {
643 MSG(ERROR,
"Malformed window hint - missing value "
644 "(expected <k>=<v>).\n");
647 const char *key_s = tok;
648 const char *val_s = strchr(tok,
'=') + 1;
649 *strchr(tok,
'=') =
'\0';
652 : stoi(key_s,
nullptr, 0);
655 : stoi(val_s,
nullptr, 0);
668 "Very " TBOLD(
"incomplete")
" list of hints and its values.\n");
669 color_printf(
"Keywords listed below can be passed to the options "
670 "instead of the numberic value.\n\n");
672 color_printf(
"The list contains both keys and values for init and "
674 color_printf(
"Window hints start witn 0x20000, init with 0x50000, the "
675 "others are values.\n\n");
677 color_printf(
"For commplete list refer to glfw3.h (eg. online "
678 "<https://github.com/glfw/glfw/blob/master/include/GLFW/"
689 "Example usage: " TBOLD(
"-d gl:init_hint=platform=x11")
"\n\n");
693 if (strstr(ptr,
"help") != 0) {
698 char *tok, *save_ptr = NULL;
700 while((tok = strtok_r(ptr,
":", &save_ptr)) != NULL) {
701 if (!strcmp(tok,
"d") || !strcmp(tok,
"dforce")) {
703 }
else if(!strncmp(tok,
"fs", 2)) {
705 if (
char *
val = strchr(tok,
'=')) {
708 }
else if(strstr(tok,
"modeset") !=
nullptr) {
709 if (strcmp(tok,
"nomodeset") != 0) {
710 if (
char *
val = strchr(tok,
'=')) {
717 }
else if(!strncmp(tok,
"aspect=", strlen(
"aspect="))) {
719 char *pos = strchr(tok,
'/');
721 }
else if(!strcasecmp(tok,
"nodecorate")) {
723 }
else if(!strcasecmp(tok,
"novsync")) {
725 }
else if(!strcasecmp(tok,
"single")) {
728 }
else if (!strncmp(tok,
"vsync=", strlen(
"vsync="))) {
729 if (toupper((tok + strlen(
"vsync="))[0]) ==
'D') {
732 s->
vsync = atoi(tok + strlen(
"vsync="));
734 }
else if (!strcasecmp(tok,
"cursor")) {
736 }
else if (strstr(tok,
"syphon") == tok || strstr(tok,
"spout") == tok) {
737#if defined HAVE_SYPHON || defined HAVE_SPOUT
738 if (strchr(tok,
'=')) {
747 }
else if (strstr(tok,
"gamma=") == tok) {
748 s->
gamma = stof(strchr(tok,
'=') + 1);
749 if (strchr(tok,
'/')) {
750 s->
gamma /= stof(strchr(tok,
'/') + 1);
752 }
else if (!strcasecmp(tok,
"hide-window")) {
754 }
else if (strcasecmp(tok,
"pbo") == 0 || strcasecmp(tok,
"nopbo") == 0) {
755 s->
use_pbo = strcasecmp(tok,
"pbo") == 0 ? 1 : 0;
756 }
else if (strstr(tok,
"size=") == tok ||
757 strstr(tok,
"fixed_size=") == tok) {
761 }
else if (strcmp(tok,
"fixed_size") == 0) {
763 }
else if (strcmp(tok,
"noresizable") == 0) {
765 }
else if (strstr(tok,
"window_hint=") == tok) {
767 }
else if (strstr(tok,
"init_hint=") == tok) {
769 }
else if (strcmp(tok,
"list_hints") == 0) {
793 char *tmp = strdup(
fmt);
797 }
catch (std::invalid_argument &e) {
814 if (i.first ==
'q') {
818 snprintf(
msg,
sizeof msg,
"%" PRIx64, i.first);
822#if GLFW_VERSION_MAJOR < 3 || (GLFW_VERSION_MAJOR == 3 && GLFW_VERSION_MINOR < 3)
828 glfwInitHint(hint.first, hint.second);
840#if defined HAVE_SPOUT || HAVE_SYPHON
842#define NAME_SPOUT_SYPHON_RAW spout
844#define NAME_SPOUT_SYPHON_RAW syphon
846#define NAME_SPOUT_SYPHON TOSTRING(NAME_SPOUT_SYPHON_RAW) " disp."
847static void * display_spout_syphon_init(
struct module *
parent,
const char *
fmt,
unsigned int flags) {
848 char config_str[1024] =
"hide-window:" NAME_SPOUT_SYPHON;
849 if (strcmp(
fmt,
"help") == 0) {
850 color_printf(
"Display " TBOLD(NAME_SPOUT_SYPHON)
" is a tiny wrapper over OpenGL display (that may be used directly as well).\n\n");
854 TBOLD(
"\tname")
" - name of the created server\n");
857 if (strstr(
fmt,
"name=") ==
fmt) {
858 snprintf(config_str + strlen(config_str),
sizeof config_str - strlen(config_str),
"=%s", strchr(
fmt,
'=') + 1);
859 }
else if (strlen(
fmt) != 0) {
881 LOG(
LOG_LEVEL_WARNING) <<
MOD_NAME "Receiving interlaced video but deinterlacing is off - suggesting toggling it on (press 'd' or pass cmdline option)\n";
893 const GLFWvidmode*
mode = glfwGetVideoMode(s->
monitor);
899 return GLFW_DONT_CARE;
903 return round(video_refresh_rate);
905 return GLFW_DONT_CARE;
907 const GLFWvidmode*
mode = glfwGetVideoMode(mon);
908 return mode->refreshRate;
911 return static_cast<int>(
modeset);
919 auto *s = (
struct state_gl *) glfwGetWindowUserPointer(win);
920 if (
fs && s->monitor !=
nullptr) {
922 GLFWmonitor *mon = s->monitor;
925 const GLFWvidmode*
mode = glfwGetVideoMode(mon);
927 height =
mode->height;
929 glfwSetWindowMonitor(win, mon, GLFW_DONT_CARE, GLFW_DONT_CARE, width, height, refresh_rate);
933 glfwSwapBuffers(win);
944 glfwSwapInterval(value);
955 time_ptr = localtime(&t);
958 localtime_r(&t, &time_tmp);
959 time_ptr = &time_tmp;
962 strftime(
name,
sizeof(
name),
"screenshot-%a, %d %b %Y %H:%M:%S %z.pnm",
994 glActiveTexture(GL_TEXTURE0 + 0);
997 glActiveTexture(GL_TEXTURE0 + 2);
1001 char *buffer = (
char *) malloc(data_len);
1002 glCompressedTexImage2D(GL_TEXTURE_2D, 0,
1003 GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,
1012 glActiveTexture(GL_TEXTURE0 + 0);
1014 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
1016 GL_RGBA, GL_UNSIGNED_BYTE,
1021 glActiveTexture(GL_TEXTURE0 + 2);
1023 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
1025 GL_RGBA, GL_UNSIGNED_BYTE,
1027 glActiveTexture(GL_TEXTURE0 + 0);
1029 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
1031 GL_RGBA, GL_UNSIGNED_BYTE,
1035 glActiveTexture(GL_TEXTURE0 + 2);
1037 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB10_A2,
1039 GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV,
1041 glActiveTexture(GL_TEXTURE0 + 0);
1043 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
1045 GL_RGBA, GL_UNSIGNED_SHORT,
1050 glActiveTexture(GL_TEXTURE0 + 2);
1052 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
1054 GL_RGBA, GL_UNSIGNED_SHORT,
1056 glActiveTexture(GL_TEXTURE0 + 0);
1058 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
1060 GL_RGBA, GL_UNSIGNED_SHORT,
1064 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
1066 GL_RGBA, GL_UNSIGNED_BYTE,
1070 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,
1072 GL_RGB, GL_UNSIGNED_BYTE,
1076 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB10_A2,
1078 GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV,
1082 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,
1084 GL_RGB, GL_UNSIGNED_SHORT,
1087 glActiveTexture(GL_TEXTURE0 + 2);
1089 glCompressedTexImage2D(GL_TEXTURE_2D, 0,
1090 GL_COMPRESSED_RGBA_S3TC_DXT5_EXT,
1094 glActiveTexture(GL_TEXTURE0 + 0);
1096 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
1098 GL_RGBA, GL_UNSIGNED_BYTE,
1109 if (GLint l = glGetUniformLocation(s->
current_program,
"image"); l != -1) {
1112 if (GLint l = glGetUniformLocation(s->
current_program,
"imageWidth"); l != -1) {
1119 glUniform1i(glGetUniformLocation(s->
PHandle_deint,
"image"), 0);
1125 glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, s->
pbo_id);
1127 glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
1136 glfwGetFramebufferSize(s->
window, &width, &height);
1186#define BAR_WIDTH (.01)
1187#define LEFT_BAR_LEFT (-.9)
1188#define LEFT_BAR_RIGHT (LEFT_BAR_LEFT + BAR_WIDTH)
1189#define RIGHT_BAR_LEFT (LEFT_BAR_RIGHT + BAR_WIDTH)
1190#define RIGHT_BAR_RIGHT (RIGHT_BAR_LEFT + BAR_WIDTH)
1191#define BARS_TOP (.9)
1192#define BARS_BOTTOM (.8)
1193#define BAR_GREY_COL (0.9)
1194 glBindTexture(GL_TEXTURE_2D, 0);
1196 glMatrixMode(GL_MODELVIEW);
1199 glMatrixMode(GL_PROJECTION);
1214 glColor4f(1, 1, 1, 1);
1215 glMatrixMode(GL_PROJECTION);
1217 glMatrixMode(GL_MODELVIEW);
1231 if (strncasecmp(msg_univ->text,
"win-title ", strlen(
"win-title ")) == 0) {
1232 glfwSetWindowTitle(s->
window, msg_univ->text + strlen(
"win-title "));
1235 if (strlen(msg_univ->text) == 0) {
1239 int ret = sscanf(msg_univ->text,
"%" SCNx64, &
key);
1254 const auto now = steady_clock::now();
1256 glfwSetInputMode(s->
window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
1263 unique_lock<mutex> lk(s->
lock);
1276 glfwMakeContextCurrent(s->
window);
1307#elif defined HAVE_SPOUT
1316 glfwSwapBuffers(s->
window);
1320 unique_lock<mutex> lk(s->
lock);
1327 if (mods == GLFW_MOD_CONTROL) {
1334 }
else if (mods == GLFW_MOD_ALT) {
1339 }
else if (mods == 0) {
1341 case GLFW_KEY_LEFT:
return K_LEFT;
1342 case GLFW_KEY_UP:
return K_UP;
1343 case GLFW_KEY_RIGHT:
return K_RIGHT;
1344 case GLFW_KEY_DOWN:
return K_DOWN;
1345 case GLFW_KEY_PAGE_UP:
return K_PGUP;
1346 case GLFW_KEY_PAGE_DOWN:
return K_PGDOWN;
1347 default:
return key;
1362 GLFWmonitor *mon = s->
fs ? s->
monitor :
nullptr;
1364 const GLFWvidmode*
mode = glfwGetVideoMode(mon);
1365 width =
mode->width;
1366 height =
mode->height;
1369 glfwSetWindowMonitor(s->
window, mon, GLFW_DONT_CARE, GLFW_DONT_CARE, width, height, refresh_rate);
1380 MSG(NOTICE,
"Deinterlacing: %s\n",
1386 s->
paused ?
"Paused (press 'Alt-p' to unpause)"
1414 if (action != GLFW_PRESS) {
1417 auto *s = (
struct state_gl *) glfwGetWindowUserPointer(win);
1423 ugk > 0 ?
name :
"unknown");
1437 auto *s = (
struct state_gl *) glfwGetWindowUserPointer(win);
1439 if (s->cursor_shown_from == steady_clock::time_point()) {
1440 glfwSetInputMode(s->window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
1442 s->cursor_shown_from = steady_clock::now();
1447 auto version = (
const char *) glGetString(GL_VERSION);
1452 if (atof(version) < 2.0) {
1457 MSG(VERBOSE,
"Supported OpenGL version is %s.\n", version);
1463 glGetIntegerv(GL_RED_BITS, &bits[0]);
1464 glGetIntegerv(GL_GREEN_BITS, &bits[1]);
1465 glGetIntegerv(GL_BLUE_BITS, &bits[2]);
1466 LOG(
LOG_LEVEL_INFO) <<
MOD_NAME <<
"Buffer depth - R: " << bits[0] <<
"b, G: " << bits[1] <<
"b, B: " << bits[2] <<
"b\n";
1470 auto *s = (
struct state_gl *) glfwGetWindowUserPointer(win);
1471 unique_lock<mutex> lk(s->lock);
1472 auto *f = s->current_frame;
1473 s->current_frame =
nullptr;
1482#if defined __linux__ || defined _WIN32
1483#ifndef GLEW_ERROR_NO_GLX_DISPLAY
1484#define GLEW_ERROR_NO_GLX_DISPLAY 4
1486static const char *glewGetError(GLenum err) {
1488 case GLEW_ERROR_NO_GL_VERSION:
return "missing GL version";
1489 case GLEW_ERROR_GL_VERSION_10_ONLY:
return "Need at least OpenGL 1.1";
1490 case GLEW_ERROR_GLX_VERSION_11_ONLY:
return "Need at least GLX 1.2";
1491 case GLEW_ERROR_NO_GLX_DISPLAY:
return "Need GLX display for GLX support";
1492 default:
return (
const char *) glewGetErrorString(err);
1506#ifdef GLFW_COCOA_NS_COLOR_SPACE
1511 glfwWindowHint(GLFW_COCOA_NS_COLOR_SPACE, stoi(
col,
nullptr, 16));
1517 char *fp = strdup(fprogram);
1521 int color = stol(
col,
nullptr, 16) >> 4;
1522 if (color > 0 && color <= 3) {
1529 double kr = cs_coeffs[2 * index];
1530 double kb = cs_coeffs[2 * index + 1];
1531 const char *placeholders[] = {
"Y_SCALED_PLACEHOLDER",
"R_CR_PLACEHOLDER",
"G_CB_PLACEHOLDER",
"G_CR_PLACEHOLDER",
"B_CB_PLACEHOLDER" };
1532 double values[] = {
Y_LIMIT_INV(8),
R_CR(8,kr,kb),
G_CB(8,kr,kb),
G_CR(8,kr,kb),
B_CB(8,kr,kb)};
1534 for (
size_t i = 0; i <
sizeof placeholders /
sizeof placeholders[0]; ++i) {
1536 while ((tok = strstr(fp, placeholders[i])) !=
nullptr) {
1537 memset(tok,
' ', strlen(placeholders[i]));
1538 int written = snprintf(tok,
sizeof placeholders - 1,
"%.6f", values[i]);
1551 glfwWindowHint(hint.first, hint.second);
1555 glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
1561 if (hints ==
nullptr) {
1564 vector<char> data(strlen(hints) + 1);
1565 copy(hints, hints + strlen(hints) + 1, data.begin());
1566 char *hints_c = data.data();
1567 char *tmp = hints_c;
1568 char *tok =
nullptr;
1569 char *save_ptr =
nullptr;
1570 while ((tok = strtok_r(tmp,
":", &save_ptr)) !=
nullptr) {
1572 if (strchr(tok,
'=') ==
nullptr) {
1576 int key = stoi(tok, 0, 0);
1577 int val = stoi(strchr(tok,
'=') + 1, 0, 0);
1578 glfwWindowHint(
key,
val);
1583 const struct GLFWgammaramp *ramp = glfwGetGammaRamp(monitor);
1584 if (ramp ==
nullptr) {
1589 oss <<
"Gamma ramp:\n";
1590 for (
unsigned int i = 0; i < ramp->size; ++i) {
1591 oss <<
"r[" << i <<
"]=" << ramp->red[i] <<
1592 ", g[" << i <<
"]=" << ramp->green[i] <<
1593 ", b[" << i <<
"]=" << ramp->blue[i] <<
"\n";
1614 if (hwacc_param !=
nullptr && strcmp(hwacc_param,
"vdpau-copy") == 0) {
1617 if (strstr((
const char *) glGetString(GL_EXTENSIONS),
1618 "GL_NV_vdpau_interop") !=
nullptr) {
1622 MOD_NAME "VDPAU interop NOT supported!\n");
1623 MSG(
DEBUG,
"Available extensions:%s\n", glGetString(GL_EXTENSIONS));
1630 " Disable 10 bit codec processing to improve performance\n");
1633 " Set window hint <k> to value <v> (deprecated, use option)\n");
1643 .value_or(GLFW_TRUE) == GLFW_FALSE) {
1650 GLFWmonitor **mon = glfwGetMonitors(&
count);
1652 MSG(ERROR,
"Wrong monitor index: %d (max %d)\n",
1660 s->
monitor = glfwGetPrimaryMonitor();
1667 for (
auto const & bits : {GLFW_RED_BITS, GLFW_GREEN_BITS, GLFW_BLUE_BITS}) {
1668 glfwWindowHint(bits, 10);
1673 glfwWindowHint(GLFW_DOUBLEBUFFER, s->
vsync ==
SINGLE_BUF ? GLFW_FALSE : GLFW_TRUE);
1678 GLFWmonitor *mon = s->
fs ? s->
monitor :
nullptr;
1683 const GLFWvidmode*
mode = glfwGetVideoMode(mon);
1684 width =
mode->width;
1685 height =
mode->height;
1686 glfwWindowHint(GLFW_REFRESH_RATE,
mode->refreshRate);
1692 if (s->
pos_x != INT_MIN) {
1693 const int y = s->
pos_y == INT_MIN ? 0 : s->
pos_y;
1697 glfwSetWindowSizeLimits(s->
window, width, height, width,
1700 if (mon !=
nullptr) {
1704 glfwSetWindowUserPointer(s->
window, s);
1707 glfwMakeContextCurrent(s->
window);
1714#if defined __linux__ || defined _WIN32
1715 if (GLenum err = glewInit()) {
1717 if (err != GLEW_ERROR_NO_GLX_DISPLAY) {
1723 glfwDestroyWindow(s->
window);
1729 glClearColor( 0.0f, 0.0f, 0.0f, 1.0f );
1730 glEnable( GL_TEXTURE_2D );
1734 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1735 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1736 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1737 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1741 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1742 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1743 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1744 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1761 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
1765 glGenFramebuffersEXT(1, &s->
fbo_id);
1767 glGenBuffersARB(1, &s->
pbo_id);
1771 glfwMakeContextCurrent(
nullptr);
1779 glfwMakeContextCurrent(s->
window);
1782 glDeleteProgram(it.second);
1786 glDeleteFramebuffersEXT(1, &s->
fbo_id);
1787 glDeleteBuffersARB(1, &s->
pbo_id);
1788 glfwDestroyWindow(s->
window);
1793#elif defined HAVE_SPOUT
1804 glfwMakeContextCurrent(s->
window);
1805 while (!glfwWindowShouldClose(s->
window)) {
1809 glfwMakeContextCurrent(
nullptr);
1817 glViewport( 0, 0, ( GLint )width, ( GLint )height );
1819 glMatrixMode( GL_PROJECTION );
1822 double screen_ratio = (double) width / height;
1823 if(screen_ratio > s->
aspect) {
1824 x = (double) height * s->
aspect / width;
1826 y = (double) width / (height * s->
aspect);
1833static void gl_resize(GLFWwindow *win,
int width,
int height)
1835 auto *s = (
struct state_gl *) glfwGetWindowUserPointer(win);
1836 debug_msg(
"Resized to: %dx%d\n", width, height);
1841 glDrawBuffer(GL_FRONT);
1843 glClear(GL_COLOR_BUFFER_BIT);
1850 glCompressedTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0,
1852 GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,
1857 glCompressedTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0,
1859 GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,
1864 glCompressedTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0,
1866 GL_COMPRESSED_RGBA_S3TC_DXT5_EXT,
1879 s->vdp.loadFrame(
reinterpret_cast<hw_vdpau_frame *
>(data));
1888 GLenum
type = GL_UNSIGNED_BYTE;
1890 type = GL_UNSIGNED_INT_2_10_10_10_REV;
1892 type = GL_UNSIGNED_SHORT;
1899 auto process_r10k = [](uint32_t * __restrict out,
const uint32_t *__restrict in,
long width,
long height) {
1902 for (
long i = 0; i < height; i += 1) {
1906 (x & 0xFFU) << 2U | (x & 0xC0'00U) >> 14U |
1907 (x & 0x3F'00U) << 6U | (x & 0xF0'00'00) >> 10U |
1908 (x & 0x0F'00'00U) << 10U | (x & 0xFC'00'00'00U) >> 6U;
1910 in += line_padding_b /
sizeof(uint32_t);
1916 glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, s->
pbo_id);
1917 glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, data_size, 0, GL_STREAM_DRAW_ARB);
1918 if (
void *ptr = glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, GL_WRITE_ONLY_ARB)) {
1923 memcpy(ptr, data, data_size);
1925 glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB);
1929 glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
1941#if ! defined __linux__
1944 std::ifstream cpuinfo(
"/proc/cpuinfo");
1948 bool detected_rpi =
false;
1949 bool detected_bcm2835 =
false;
1951 while (std::getline(cpuinfo, line) && !detected_rpi) {
1952 detected_bcm2835 |= line.find(
"BCM2835") != std::string::npos;
1953 detected_rpi |= line.find(
"Raspberry Pi") != std::string::npos;
1956 return detected_rpi || detected_bcm2835;
1963 glBindTexture(GL_TEXTURE_2D, 0);
1964 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, s->
fbo_id);
1966 glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, s->
texture_display, 0);
1967 status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
1968 assert(
status == GL_FRAMEBUFFER_COMPLETE_EXT);
1969 glActiveTexture(GL_TEXTURE0 + 2);
1972 glMatrixMode( GL_PROJECTION );
1976 glMatrixMode( GL_MODELVIEW );
1980 glPushAttrib(GL_VIEWPORT_BIT);
1989 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
1993 glTexCoord2f(0.0, 0.0); glVertex2f(-1.0, -1.0);
1994 glTexCoord2f(1.0, 0.0); glVertex2f(1.0, -1.0);
1995 glTexCoord2f(1.0, 1.0); glVertex2f(1.0, 1.0);
1996 glTexCoord2f(0.0, 1.0); glVertex2f(-1.0, 1.0);
2001 glMatrixMode( GL_PROJECTION );
2003 glMatrixMode( GL_MODELVIEW );
2007 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
2008 glActiveTexture(GL_TEXTURE0 + 0);
2012static void gl_draw(
double ratio,
double bottom_offset,
bool double_buf)
2017 glDrawBuffer(double_buf ? GL_BACK : GL_FRONT);
2019 glClear(GL_COLOR_BUFFER_BIT);
2022 glMatrixMode( GL_MODELVIEW );
2024 glTranslatef( 0.0f, 0.0f, -1.35f );
2029 bottom = 1.0f - bottom_offset;
2035 glTexCoord2f( 0.0f, bottom ); glVertex2f( -1.0f, -1/ratio);
2037 glTexCoord2f( 1.0f, bottom ); glVertex2f( 1.0f, -1/ratio);
2039 glTexCoord2f( 1.0f, 0.0f ); glVertex2f( 1.0f, 1/ratio);
2041 glTexCoord2f( 0.0f, 0.0f ); glVertex2f( -1.0f, 1/ratio);
2049 glfwSetWindowShouldClose(win, GLFW_TRUE);
2058 int rgb_shift[] = {0, 8, 16};
2063 auto filter_codecs = [s](
codec_t c) {
2072 s->PHandles.find(c) ==
2073 s->PHandles.end()) {
2077 if (c ==
HW_VDPAU && !s->vdp_interop) {
2085 *
len = (
const char *) endptr - (
char *)
val;
2090 memcpy(
val, rgb_shift,
sizeof(rgb_shift));
2091 *
len =
sizeof(rgb_shift);
2100 memcpy(
val, supported_il_modes,
sizeof(supported_il_modes));
2101 *
len =
sizeof(supported_il_modes);
2160 unique_lock<mutex> lk(s->
lock);
2163 glfwSetWindowShouldClose(s->
window, GLFW_TRUE);
2170 switch (timeout_ns) {
2203 strcpy((*available_cards)[0].
dev,
"");
2204 strcpy((*available_cards)[0].
name,
"OpenGL SW display");
2206 dev_add_option(&(*available_cards)[0],
"Deinterlace",
"Deinterlace",
"deinterlace",
":d",
true);
2207 dev_add_option(&(*available_cards)[0],
"Fullscreen",
"Launch as fullscreen",
"fullscreen",
":fs",
true);
2208 dev_add_option(&(*available_cards)[0],
"No decorate",
"Disable window decorations",
"nodecorate",
":nodecorate",
true);
2209 dev_add_option(&(*available_cards)[0],
"Show cursor",
"Show visible cursor",
"cursor",
":cursor",
true);
2210 dev_add_option(&(*available_cards)[0],
"Disable vsync",
"Disable vsync",
"novsync",
":novsync",
true);
2211 dev_add_option(&(*available_cards)[0],
"Aspect",
"Requested video aspect <w>/<h>",
"aspect",
":aspect=",
false);
2213 (*available_cards)[0].repeatable =
true;
2229#if defined HAVE_SPOUT || HAVE_SYPHON
2230#if defined HAVE_SPOUT && HAVE_SYPHON
2231#error "Both SPOUT and Syphon defined, please fix!"
2239 strcpy((*available_cards)[0].
dev,
"syphon");
2240 strcpy((*available_cards)[0].
name,
"Syphon display");
2242 strcpy((*available_cards)[0].
dev,
"spout");
2243 strcpy((*available_cards)[0].
name,
"SPOUT display");
2246 display_spout_syphon_init,
2255 "[" NAME_SPOUT_SYPHON
"] ",
struct video_frame * frame
const char unsigned int flags
int void(** deleter)(void *))
void vf_free(struct video_frame *buf)
Frees video_frame structure.
struct video_desc video_desc_from_frame(const struct video_frame *frame)
Returns struct video_desc from video frame.
int vc_get_linesize(unsigned int width, codec_t codec)
struct video_frame * vf_alloc_desc_data(struct video_desc desc)
const char * get_codec_name(codec_t codec)
#define G_CR(in_depth, kr, kb)
#define B_CB(in_depth, kr, kb)
#define R_CR(in_depth, kr, kb)
#define Y_LIMIT_INV(in_depth)
#define G_CB(in_depth, kr, kb)
int color_printf(const char *format,...)
static __device__ void swap(T &a, T &b)
Swaps two referenced values.
static __device__ vec3 round(const vec3 &v)
void log_msg(int level, const char *format,...)
#define DEBUG_TIMER_START(name)
#define LOG_LEVEL_NOTICE
information that may be interesting
#define LOG_LEVEL_INFO
normal reporting
#define DEBUG_TIMER_STOP(name)
#define LOG_LEVEL_ERROR
general errors
#define LOG_LEVEL_VERBOSE
#define debug_msg(...)
#define debug_msg(...) log_msg(LOG_LEVEL_DEBUG, "[pid/%d +%d %s] ", getpid(), LINE,...
#define LOG_LEVEL_WARNING
less severe errors
steady_clock::duration duration
#define GL_WINDOW_HINT_OPT_PARAM_NAME
static GLuint gl_substitute_compile_link(const char *vprogram, const char *fprogram)
static void display_gl_render_last(GLFWwindow *win)
static void glfw_print_error(int error_code, const char *description)
static void gl_change_aspect(struct state_gl *s, int width, int height)
static void display_gl_set_window_hints(struct state_gl *s)
static void upload_texture(struct state_gl *s, char *data)
static bool check_rpi_pbo_quirks()
static void display_gl_cleanup_opengl(struct state_gl *s)
static void glfw_print_video_mode(struct state_gl *s)
static void gl_reconfigure_screen(struct state_gl *s, struct video_desc desc)
static bool display_gl_reconfigure(void *state, struct video_desc desc)
static void parse_hints(struct state_gl *s, bool window_hints, char *hints)
static bool display_gl_process_key(struct state_gl *s, long long int key)
static bool display_gl_init_opengl(struct state_gl *s)
static void glfw_close_callback(GLFWwindow *win)
static void glfw_resize_window(GLFWwindow *win, bool fs, int height, double aspect, double fps, double window_size_factor)
#define GL_DISABLE_10B_OPT_PARAM_NAME
static void gl_render(struct state_gl *s, char *data)
static const char * fp_display_dxt1_yuv
static void gl_print_monitors(bool fullhelp)
static const char fp_display_dxt5ycocg[]
static bool display_gl_get_property(void *state, int property, void *val, size_t *len)
static void gl_resize(GLFWwindow *win, int width, int height)
static void upload_compressed_texture(struct state_gl *s, char *data)
static void set_mac_color_space(void)
static void display_gl_print_depth()
static void display_gl_set_sync_on_vblank(int value)
unordered_map< codec_t, const char * > glsl_programs
static bool vdp_interop_supported()
static void set_gamma(struct state_gl *s)
static void gl_process_frames(struct state_gl *s)
static int64_t translate_glfw_to_ug(int key, int mods)
static void gl_show_help(bool full)
static void screenshot(struct video_frame *frame)
static void * display_gl_parse_fmt(struct state_gl *s, char *ptr)
static void gl_load_splashscreen(struct state_gl *s)
static void print_gamma_ramp(GLFWmonitor *monitor)
static void gl_render_glsl(struct state_gl *s, char *data)
static const char * v210_to_rgb_fp
static const char * uyvy_to_rgb_fp
static void display_gl_run(void *arg)
static bool set_size(struct state_gl *s, const char *tok)
static const char * deinterlace_fp
static void glfw_mouse_callback(GLFWwindow *win, double x, double y)
static void glfw_key_callback(GLFWwindow *win, int key, int scancode, int action, int mods)
static bool display_gl_putf(void *state, struct video_frame *frame, long long timeout)
static struct video_frame * display_gl_getf(void *state)
static void gl_draw(double ratio, double bottom_offset, bool double_buf)
static const char * yuva_to_rgb_fp
static const struct video_display_info display_gl_info
static const map< string, int > hint_map
static void draw_pause()
draw pause symbol (2 vertical bars) to the lefttop part of the frame
#define FEATURE_PRESENT(x)
static int get_refresh_rate(enum state_gl::modeset_t modeset, GLFWmonitor *mon, double video_refresh_rate)
static constexpr codec_t gl_supp_codecs[]
static void * display_gl_init(struct module *parent, const char *fmt, unsigned int flags)
static void pop_frame(struct state_gl *s, unique_lock< mutex > &lk)
static constexpr pair< int64_t, string_view > keybindings[]
static bool display_gl_check_gl_version()
static void display_gl_done(void *state)
GLuint glsl_compile_link(const char *vprogram, const char *fprogram)
#define PITCH_DEFAULT
default pitch, i. e. respective linesize
#define VIDEO_DISPLAY_ABI_VERSION
struct video_frame * get_splashscreen()
@ DISPLAY_PROPERTY_BUF_PITCH
requested framebuffer pitch - int (bytes), may be PITCH_DEFAULT
@ DISPLAY_PROPERTY_RGB_SHIFT
red,green,blue shift - int[3] (bits)
@ DISPLAY_PROPERTY_SUPPORTED_IL_MODES
display supported interlacing modes - enum interlacing_t[]
@ DISPLAY_PROPERTY_CODECS
list of natively supported codecs - codec_t[]
void module_init_default(struct module *module_data)
void module_register(struct module *module_data, struct module *parent)
void module_done(struct module *module_data)
struct module * get_root_module(struct module *node)
void handle_error(int status)
int glfw_init_count
0->1 - call glfwInit, 1->0 call glfwTerminate; glfw{Init,Terminate} should be called from main thr,...
const char * get_commandline_param(const char *key)
std::unordered_map< std::string, std::string > commandline_params
#define ADD_TO_PARAM(param, doc)
bool keycontrol_register_key(struct module *receiver_mod, int64_t key, const char *message, const char *description)
Registers callback message for given key.
void get_keycode_name(int64_t ch, char *buf, size_t buflen)
void keycontrol_send_key(struct module *root, int64_t key)
#define MAX_KEYCODE_NAME_LEN
@ LIBRARY_CLASS_VIDEO_DISPLAY
#define REGISTER_MODULE(name, info, lclass, abi)
Registers module to global modules' registry.
#define UG_ASSERT(cond)
unconditional alternative to assert that is not affected by NDEBUG macro
#define IF_NOT_NULL_ELSE(val, default_val)
void free_message(struct message *msg, struct response *r)
struct response * new_response(int status, const char *text)
struct message * check_message(struct module *mod)
#define RESPONSE_BAD_REQUEST
void spout_sender_unregister(void *s)
void spout_sender_sendframe(void *s, int width, int height, unsigned int id)
void * spout_sender_register(const char *name)
enum state_gl::modeset_t modeset
positive vals force framerate
condition_variable frame_consumed_cv
queue< struct video_frame * > frame_queue
string syphon_spout_srv_name
vector< char > scratchpad
scratchpad sized WxHx8
double window_size_factor
steady_clock::time_point cursor_shown_from
indicates time point from which is cursor show if show_cursor == SC_AUTOHIDE, timepoint() means curso...
enum state_gl::deint deinterlace
enum state_gl::show_cursor_t show_cursor
state_gl(struct module *parent)
static const char * deint_to_string(state_gl::deint val)
condition_variable new_frame_ready_cv
unordered_map< codec_t, GLuint > PHandles
struct video_desc current_desc
queue< struct video_frame * > free_frame_queue
map< int, int > init_hints
map< int, int > window_hints
struct video_frame * current_frame
char * data
Raw tile data. Pointer must be at least 4B aligned.
enum interlacing_t interlacing
unsigned int width
width of every tile (!)
unsigned int height
height of every tile (!)
Struct video_frame represents a video frame and contains video description.
struct tile tiles[FLEXIBLE_ARRAY_MEMBER]
static const char * vprogram
void syphon_server_publish(void *s, int width, int height, unsigned int id)
void * syphon_server_register(void *context, const char *name)
void syphon_server_unregister(void *s)
void dev_add_option(struct device_info *dev, const char *name, const char *desc, const char *key, const char *opt_str, bool is_boolean)
@ PROGRESSIVE
progressive frame
@ SEGMENTED_FRAME
Segmented frame. Contains the same data as progressive frame.
@ INTERLACED_MERGED
Columngs of both fields are interlaced together.
@ DXT1
S3 Texture Compression DXT1.
@ R10k
RGB 10-bit packed - RGBX, big-endian (2 bit padding)
@ RGB
RGB 8-bit (packed into 24-bit word)
@ UYVY
YCbCr 422 8-bit - Cb Y0 Cr Y1.
@ HW_VDPAU
VDPAU hardware surface.
@ RG48
16-bit RGB little-endian (RlRhGl...)
@ Y416
interleaved little-endian YCbCr 4444 16-bit - UYVA
@ DXT5
S3 Texture Compression DXT5.
@ DXT1_YUV
Structure same as DXT1, instead of RGB, YCbCr values are stored.
@ RGBA
RGBA 8-bit, big-endian.
@ v210
YCbCr 422 10-bit - xVY0U|xY2UY1|xUY3V|xY5VY4, little-endian (2 bit padding /'x'/),...
This is an umbrella header for video functions.
int get_bits_per_component(codec_t codec)
void vf_clear(struct video_frame *f)
void vf_recycle(struct video_frame *buf)
This function should be called before returning a frame back to a frame pool. Currently this is used ...
bool save_video_frame_as_pnm(struct video_frame *frame, const char *name)
bool video_desc_eq(struct video_desc a, struct video_desc b)
Compares two video descriptions.