2014-04-29 02:59:53 +02:00
|
|
|
#include <glad/glad.h>
|
|
|
|
#include <glad/glad_glx.h>
|
|
|
|
#include <X11/Xlib.h>
|
|
|
|
#include <X11/extensions/Xcomposite.h>
|
|
|
|
#include <pthread.h>
|
|
|
|
|
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
#include <obs-module.h>
|
|
|
|
#include <graphics/vec4.h>
|
|
|
|
#include <util/platform.h>
|
|
|
|
|
2014-08-29 17:05:32 -07:00
|
|
|
#include "xcompcap-main.hpp"
|
|
|
|
#include "xcompcap-helper.hpp"
|
2014-08-29 17:17:04 -07:00
|
|
|
#include "xcursor.h"
|
2014-04-29 02:59:53 +02:00
|
|
|
|
|
|
|
#define xdisp (XCompcap::disp())
|
|
|
|
#define WIN_STRING_DIV "\r\n"
|
|
|
|
|
|
|
|
bool XCompcapMain::init()
|
|
|
|
{
|
2014-05-15 02:12:22 -07:00
|
|
|
if (!xdisp) {
|
2014-04-29 02:59:53 +02:00
|
|
|
blog(LOG_ERROR, "failed opening display");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
int eventBase, errorBase;
|
2014-05-15 02:12:22 -07:00
|
|
|
if (!XCompositeQueryExtension(xdisp, &eventBase, &errorBase)) {
|
2014-04-29 02:59:53 +02:00
|
|
|
blog(LOG_ERROR, "Xcomposite extension not supported");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
int major = 0, minor = 2;
|
|
|
|
XCompositeQueryVersion(xdisp, &major, &minor);
|
|
|
|
|
2014-05-15 02:12:22 -07:00
|
|
|
if (major == 0 && minor < 2) {
|
|
|
|
blog(LOG_ERROR, "Xcomposite extension is too old: %d.%d < 0.2",
|
|
|
|
major, minor);
|
2014-04-29 02:59:53 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void XCompcapMain::deinit()
|
|
|
|
{
|
|
|
|
XCompcap::cleanupDisplay();
|
|
|
|
}
|
|
|
|
|
2014-09-25 17:44:05 -07:00
|
|
|
obs_properties_t *XCompcapMain::properties()
|
2014-04-29 02:59:53 +02:00
|
|
|
{
|
2014-09-25 17:44:05 -07:00
|
|
|
obs_properties_t *props = obs_properties_create();
|
2014-04-29 02:59:53 +02:00
|
|
|
|
2014-09-25 17:44:05 -07:00
|
|
|
obs_property_t *wins = obs_properties_add_list(
|
2014-07-09 22:12:57 -07:00
|
|
|
props, "capture_window", obs_module_text("Window"),
|
|
|
|
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_STRING);
|
2014-04-29 02:59:53 +02:00
|
|
|
|
2014-05-15 02:12:22 -07:00
|
|
|
for (Window win : XCompcap::getTopLevelWindows()) {
|
2014-04-29 02:59:53 +02:00
|
|
|
std::string wname = XCompcap::getWindowName(win);
|
2016-07-02 23:49:19 -07:00
|
|
|
std::string cls = XCompcap::getWindowClass(win);
|
2014-04-29 02:59:53 +02:00
|
|
|
std::string winid = std::to_string((long long)win);
|
2014-05-15 02:12:22 -07:00
|
|
|
std::string desc =
|
|
|
|
(winid + WIN_STRING_DIV + wname + WIN_STRING_DIV + cls);
|
|
|
|
|
|
|
|
obs_property_list_add_string(wins, wname.c_str(), desc.c_str());
|
2014-04-29 02:59:53 +02:00
|
|
|
}
|
|
|
|
|
2014-07-09 22:12:57 -07:00
|
|
|
obs_properties_add_int(props, "cut_top", obs_module_text("CropTop"), 0,
|
2014-05-15 02:12:22 -07:00
|
|
|
4096, 1);
|
2014-07-09 22:12:57 -07:00
|
|
|
obs_properties_add_int(props, "cut_left", obs_module_text("CropLeft"),
|
2014-05-15 02:12:22 -07:00
|
|
|
0, 4096, 1);
|
2014-07-09 22:12:57 -07:00
|
|
|
obs_properties_add_int(props, "cut_right", obs_module_text("CropRight"),
|
2014-05-15 02:12:22 -07:00
|
|
|
0, 4096, 1);
|
2014-07-09 22:12:57 -07:00
|
|
|
obs_properties_add_int(props, "cut_bot", obs_module_text("CropBottom"),
|
2014-05-15 02:12:22 -07:00
|
|
|
0, 4096, 1);
|
2014-04-29 02:59:53 +02:00
|
|
|
|
2014-07-09 22:12:57 -07:00
|
|
|
obs_properties_add_bool(props, "swap_redblue",
|
|
|
|
obs_module_text("SwapRedBlue"));
|
|
|
|
obs_properties_add_bool(props, "lock_x", obs_module_text("LockX"));
|
2014-04-29 02:59:53 +02:00
|
|
|
|
2014-08-29 17:17:04 -07:00
|
|
|
obs_properties_add_bool(props, "show_cursor",
|
|
|
|
obs_module_text("CaptureCursor"));
|
|
|
|
|
2014-11-05 18:40:17 -06:00
|
|
|
obs_properties_add_bool(props, "include_border",
|
|
|
|
obs_module_text("IncludeXBorder"));
|
|
|
|
|
2016-02-28 02:49:34 -05:00
|
|
|
obs_properties_add_bool(props, "exclude_alpha",
|
|
|
|
obs_module_text("ExcludeAlpha"));
|
|
|
|
|
2014-04-29 02:59:53 +02:00
|
|
|
return props;
|
|
|
|
}
|
|
|
|
|
2014-09-25 17:44:05 -07:00
|
|
|
void XCompcapMain::defaults(obs_data_t *settings)
|
2014-04-29 02:59:53 +02:00
|
|
|
{
|
2014-06-22 12:51:58 +02:00
|
|
|
obs_data_set_default_string(settings, "capture_window", "");
|
|
|
|
obs_data_set_default_int(settings, "cut_top", 0);
|
|
|
|
obs_data_set_default_int(settings, "cut_left", 0);
|
|
|
|
obs_data_set_default_int(settings, "cut_right", 0);
|
|
|
|
obs_data_set_default_int(settings, "cut_bot", 0);
|
|
|
|
obs_data_set_default_bool(settings, "swap_redblue", false);
|
|
|
|
obs_data_set_default_bool(settings, "lock_x", false);
|
2014-08-29 17:17:04 -07:00
|
|
|
obs_data_set_default_bool(settings, "show_cursor", true);
|
2014-11-05 18:40:17 -06:00
|
|
|
obs_data_set_default_bool(settings, "include_border", false);
|
2016-02-28 02:49:34 -05:00
|
|
|
obs_data_set_default_bool(settings, "exclude_alpha", false);
|
2014-04-29 02:59:53 +02:00
|
|
|
}
|
|
|
|
|
linux-capture: Fix window capture crashes
The xcomposite window capture crashes were due to a few factors:
-------------------------------
1.) The source's X error handler was possibly being overwritten by
another part of the program despite us locking the display, presumably
something in Qt which isn't locking the display when pushing/popping its
own error handler (though this is not yet certain). The source's calls
to X functions happen in the graphics thread, which is separate from the
UI thread, and it was noticed that somehow the error handler would be
overwritten almost seemingly at random, indicating that something else
in the program outside of OBS code was not locking the display while
pushing/popping the error handler.
To replicate this, make it so that the source cannot find the target
window and so it continually searches for it each video_tick call, then
resize the main OBS window continually (which causes Qt to push/pop its
own error handlers). A crash will almost always occur due to BadWindow
despite our error handling.
2.) Calling X functions with a window ID that no longer exists,
particularly XGetWindowAttributes, in conjunction the unknown error
handler set in case #1 would cause the program to outright crash because
that error handler is programmed to crash on BadWindow for whatever
reason. The source would call X functions without even checking if
'win' was 0.
3.) The source stored window IDs (in JSON, even if they've long since
become invalid/pointless, such as system restarts). This is a bad
practice and will result in more cases of BadWindow.
Fixing the problem (reducing the possibility of getting BadWindow):
-------------------------------
Step 1.) Deprecate and ignore window IDs in stored settings. Instead of
using window IDs to find the window, we now must always search the
windows and find the target window via the window name exclusively.
This helps ensure that we actually consistently have a working window
ID.
Step 2.) Do not call any X functions if the window ID is 0.
Step 3.) Reset the window ID to 0 any time the window has updated, and
make the source find the window again to ensure it still exists before
attempting to use any X functions on the window ID again.
2016-06-04 14:20:41 -07:00
|
|
|
#define FIND_WINDOW_INTERVAL 2.0
|
2014-04-29 02:59:53 +02:00
|
|
|
|
|
|
|
struct XCompcapMain_private {
|
|
|
|
XCompcapMain_private()
|
|
|
|
: win(0),
|
2014-05-15 02:12:22 -07:00
|
|
|
cut_top(0),
|
|
|
|
cur_cut_top(0),
|
|
|
|
cut_left(0),
|
|
|
|
cur_cut_left(0),
|
|
|
|
cut_right(0),
|
|
|
|
cur_cut_right(0),
|
|
|
|
cut_bot(0),
|
|
|
|
cur_cut_bot(0),
|
2014-04-29 02:59:53 +02:00
|
|
|
inverted(false),
|
|
|
|
width(0),
|
|
|
|
height(0),
|
|
|
|
pixmap(0),
|
|
|
|
glxpixmap(0),
|
|
|
|
tex(0),
|
|
|
|
gltex(0)
|
|
|
|
{
|
|
|
|
pthread_mutexattr_init(&lockattr);
|
|
|
|
pthread_mutexattr_settype(&lockattr, PTHREAD_MUTEX_RECURSIVE);
|
|
|
|
|
|
|
|
pthread_mutex_init(&lock, &lockattr);
|
|
|
|
}
|
|
|
|
|
|
|
|
~XCompcapMain_private()
|
|
|
|
{
|
|
|
|
pthread_mutex_destroy(&lock);
|
|
|
|
pthread_mutexattr_destroy(&lockattr);
|
|
|
|
}
|
|
|
|
|
2014-09-25 17:44:05 -07:00
|
|
|
obs_source_t *source;
|
2014-04-29 02:59:53 +02:00
|
|
|
|
2015-08-16 16:37:50 +03:00
|
|
|
std::string windowName;
|
linux-capture: Fix window capture crashes
The xcomposite window capture crashes were due to a few factors:
-------------------------------
1.) The source's X error handler was possibly being overwritten by
another part of the program despite us locking the display, presumably
something in Qt which isn't locking the display when pushing/popping its
own error handler (though this is not yet certain). The source's calls
to X functions happen in the graphics thread, which is separate from the
UI thread, and it was noticed that somehow the error handler would be
overwritten almost seemingly at random, indicating that something else
in the program outside of OBS code was not locking the display while
pushing/popping the error handler.
To replicate this, make it so that the source cannot find the target
window and so it continually searches for it each video_tick call, then
resize the main OBS window continually (which causes Qt to push/pop its
own error handlers). A crash will almost always occur due to BadWindow
despite our error handling.
2.) Calling X functions with a window ID that no longer exists,
particularly XGetWindowAttributes, in conjunction the unknown error
handler set in case #1 would cause the program to outright crash because
that error handler is programmed to crash on BadWindow for whatever
reason. The source would call X functions without even checking if
'win' was 0.
3.) The source stored window IDs (in JSON, even if they've long since
become invalid/pointless, such as system restarts). This is a bad
practice and will result in more cases of BadWindow.
Fixing the problem (reducing the possibility of getting BadWindow):
-------------------------------
Step 1.) Deprecate and ignore window IDs in stored settings. Instead of
using window IDs to find the window, we now must always search the
windows and find the target window via the window name exclusively.
This helps ensure that we actually consistently have a working window
ID.
Step 2.) Do not call any X functions if the window ID is 0.
Step 3.) Reset the window ID to 0 any time the window has updated, and
make the source find the window again to ensure it still exists before
attempting to use any X functions on the window ID again.
2016-06-04 14:20:41 -07:00
|
|
|
Window win = 0;
|
2014-04-29 02:59:53 +02:00
|
|
|
int cut_top, cur_cut_top;
|
|
|
|
int cut_left, cur_cut_left;
|
|
|
|
int cut_right, cur_cut_right;
|
|
|
|
int cut_bot, cur_cut_bot;
|
|
|
|
bool inverted;
|
|
|
|
bool swapRedBlue;
|
|
|
|
bool lockX;
|
2014-11-05 18:40:17 -06:00
|
|
|
bool include_border;
|
2016-02-28 02:49:34 -05:00
|
|
|
bool exclude_alpha;
|
2018-09-13 07:52:19 -05:00
|
|
|
bool draw_opaque;
|
2014-04-29 02:59:53 +02:00
|
|
|
|
linux-capture: Fix window capture crashes
The xcomposite window capture crashes were due to a few factors:
-------------------------------
1.) The source's X error handler was possibly being overwritten by
another part of the program despite us locking the display, presumably
something in Qt which isn't locking the display when pushing/popping its
own error handler (though this is not yet certain). The source's calls
to X functions happen in the graphics thread, which is separate from the
UI thread, and it was noticed that somehow the error handler would be
overwritten almost seemingly at random, indicating that something else
in the program outside of OBS code was not locking the display while
pushing/popping the error handler.
To replicate this, make it so that the source cannot find the target
window and so it continually searches for it each video_tick call, then
resize the main OBS window continually (which causes Qt to push/pop its
own error handlers). A crash will almost always occur due to BadWindow
despite our error handling.
2.) Calling X functions with a window ID that no longer exists,
particularly XGetWindowAttributes, in conjunction the unknown error
handler set in case #1 would cause the program to outright crash because
that error handler is programmed to crash on BadWindow for whatever
reason. The source would call X functions without even checking if
'win' was 0.
3.) The source stored window IDs (in JSON, even if they've long since
become invalid/pointless, such as system restarts). This is a bad
practice and will result in more cases of BadWindow.
Fixing the problem (reducing the possibility of getting BadWindow):
-------------------------------
Step 1.) Deprecate and ignore window IDs in stored settings. Instead of
using window IDs to find the window, we now must always search the
windows and find the target window via the window name exclusively.
This helps ensure that we actually consistently have a working window
ID.
Step 2.) Do not call any X functions if the window ID is 0.
Step 3.) Reset the window ID to 0 any time the window has updated, and
make the source find the window again to ensure it still exists before
attempting to use any X functions on the window ID again.
2016-06-04 14:20:41 -07:00
|
|
|
double window_check_time = 0.0;
|
|
|
|
|
2014-04-29 02:59:53 +02:00
|
|
|
uint32_t width;
|
|
|
|
uint32_t height;
|
2014-11-05 18:40:17 -06:00
|
|
|
uint32_t border;
|
2014-04-29 02:59:53 +02:00
|
|
|
|
|
|
|
Pixmap pixmap;
|
|
|
|
GLXPixmap glxpixmap;
|
2014-09-25 17:44:05 -07:00
|
|
|
gs_texture_t *tex;
|
|
|
|
gs_texture_t *gltex;
|
2014-04-29 02:59:53 +02:00
|
|
|
|
|
|
|
pthread_mutex_t lock;
|
|
|
|
pthread_mutexattr_t lockattr;
|
2014-08-29 17:17:04 -07:00
|
|
|
|
|
|
|
bool show_cursor = true;
|
|
|
|
bool cursor_outside = false;
|
|
|
|
xcursor_t *cursor = nullptr;
|
2014-04-29 02:59:53 +02:00
|
|
|
};
|
|
|
|
|
2014-09-25 17:44:05 -07:00
|
|
|
XCompcapMain::XCompcapMain(obs_data_t *settings, obs_source_t *source)
|
2014-04-29 02:59:53 +02:00
|
|
|
{
|
|
|
|
p = new XCompcapMain_private;
|
|
|
|
p->source = source;
|
|
|
|
|
2014-08-29 17:17:04 -07:00
|
|
|
obs_enter_graphics();
|
|
|
|
p->cursor = xcursor_init(xdisp);
|
|
|
|
obs_leave_graphics();
|
|
|
|
|
2014-04-29 02:59:53 +02:00
|
|
|
updateSettings(settings);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void xcc_cleanup(XCompcapMain_private *p);
|
|
|
|
|
|
|
|
XCompcapMain::~XCompcapMain()
|
|
|
|
{
|
|
|
|
ObsGsContextHolder obsctx;
|
|
|
|
|
2014-05-15 02:12:22 -07:00
|
|
|
if (p->tex) {
|
2014-08-07 23:42:07 -07:00
|
|
|
gs_texture_destroy(p->tex);
|
2014-04-29 02:59:53 +02:00
|
|
|
p->tex = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
xcc_cleanup(p);
|
|
|
|
|
2014-08-29 17:17:04 -07:00
|
|
|
if (p->cursor) {
|
|
|
|
xcursor_destroy(p->cursor);
|
|
|
|
p->cursor = nullptr;
|
|
|
|
}
|
|
|
|
|
2014-04-29 02:59:53 +02:00
|
|
|
delete p;
|
|
|
|
}
|
|
|
|
|
|
|
|
static Window getWindowFromString(std::string wstr)
|
|
|
|
{
|
linux-capture: Fix window capture crashes
The xcomposite window capture crashes were due to a few factors:
-------------------------------
1.) The source's X error handler was possibly being overwritten by
another part of the program despite us locking the display, presumably
something in Qt which isn't locking the display when pushing/popping its
own error handler (though this is not yet certain). The source's calls
to X functions happen in the graphics thread, which is separate from the
UI thread, and it was noticed that somehow the error handler would be
overwritten almost seemingly at random, indicating that something else
in the program outside of OBS code was not locking the display while
pushing/popping the error handler.
To replicate this, make it so that the source cannot find the target
window and so it continually searches for it each video_tick call, then
resize the main OBS window continually (which causes Qt to push/pop its
own error handlers). A crash will almost always occur due to BadWindow
despite our error handling.
2.) Calling X functions with a window ID that no longer exists,
particularly XGetWindowAttributes, in conjunction the unknown error
handler set in case #1 would cause the program to outright crash because
that error handler is programmed to crash on BadWindow for whatever
reason. The source would call X functions without even checking if
'win' was 0.
3.) The source stored window IDs (in JSON, even if they've long since
become invalid/pointless, such as system restarts). This is a bad
practice and will result in more cases of BadWindow.
Fixing the problem (reducing the possibility of getting BadWindow):
-------------------------------
Step 1.) Deprecate and ignore window IDs in stored settings. Instead of
using window IDs to find the window, we now must always search the
windows and find the target window via the window name exclusively.
This helps ensure that we actually consistently have a working window
ID.
Step 2.) Do not call any X functions if the window ID is 0.
Step 3.) Reset the window ID to 0 any time the window has updated, and
make the source find the window again to ensure it still exists before
attempting to use any X functions on the window ID again.
2016-06-04 14:20:41 -07:00
|
|
|
XErrorLock xlock;
|
|
|
|
|
2014-05-15 02:12:22 -07:00
|
|
|
if (wstr == "") {
|
2014-04-29 02:59:53 +02:00
|
|
|
return XCompcap::getTopLevelWindows().front();
|
|
|
|
}
|
|
|
|
|
2014-05-15 02:12:22 -07:00
|
|
|
if (wstr.substr(0, 4) == "root") {
|
2014-04-29 02:59:53 +02:00
|
|
|
int i = std::stoi("0" + wstr.substr(4));
|
|
|
|
return RootWindow(xdisp, i);
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t firstMark = wstr.find(WIN_STRING_DIV);
|
2016-07-02 23:49:19 -07:00
|
|
|
size_t markSize = strlen(WIN_STRING_DIV);
|
2014-04-29 02:59:53 +02:00
|
|
|
|
2014-05-15 02:12:22 -07:00
|
|
|
if (firstMark == std::string::npos)
|
2014-04-29 02:59:53 +02:00
|
|
|
return (Window)std::stol(wstr);
|
|
|
|
|
linux-capture: Fix window capture crashes
The xcomposite window capture crashes were due to a few factors:
-------------------------------
1.) The source's X error handler was possibly being overwritten by
another part of the program despite us locking the display, presumably
something in Qt which isn't locking the display when pushing/popping its
own error handler (though this is not yet certain). The source's calls
to X functions happen in the graphics thread, which is separate from the
UI thread, and it was noticed that somehow the error handler would be
overwritten almost seemingly at random, indicating that something else
in the program outside of OBS code was not locking the display while
pushing/popping the error handler.
To replicate this, make it so that the source cannot find the target
window and so it continually searches for it each video_tick call, then
resize the main OBS window continually (which causes Qt to push/pop its
own error handlers). A crash will almost always occur due to BadWindow
despite our error handling.
2.) Calling X functions with a window ID that no longer exists,
particularly XGetWindowAttributes, in conjunction the unknown error
handler set in case #1 would cause the program to outright crash because
that error handler is programmed to crash on BadWindow for whatever
reason. The source would call X functions without even checking if
'win' was 0.
3.) The source stored window IDs (in JSON, even if they've long since
become invalid/pointless, such as system restarts). This is a bad
practice and will result in more cases of BadWindow.
Fixing the problem (reducing the possibility of getting BadWindow):
-------------------------------
Step 1.) Deprecate and ignore window IDs in stored settings. Instead of
using window IDs to find the window, we now must always search the
windows and find the target window via the window name exclusively.
This helps ensure that we actually consistently have a working window
ID.
Step 2.) Do not call any X functions if the window ID is 0.
Step 3.) Reset the window ID to 0 any time the window has updated, and
make the source find the window again to ensure it still exists before
attempting to use any X functions on the window ID again.
2016-06-04 14:20:41 -07:00
|
|
|
Window wid = 0;
|
2014-04-29 02:59:53 +02:00
|
|
|
|
2016-07-02 23:49:19 -07:00
|
|
|
wstr = wstr.substr(firstMark + markSize);
|
2014-04-29 02:59:53 +02:00
|
|
|
|
|
|
|
size_t lastMark = wstr.rfind(WIN_STRING_DIV);
|
|
|
|
std::string wname = wstr.substr(0, lastMark);
|
2016-07-02 23:49:19 -07:00
|
|
|
std::string wcls = wstr.substr(lastMark + markSize);
|
2014-04-29 02:59:53 +02:00
|
|
|
|
|
|
|
Window matchedNameWin = wid;
|
2014-05-15 02:12:22 -07:00
|
|
|
for (Window cwin : XCompcap::getTopLevelWindows()) {
|
2014-04-29 02:59:53 +02:00
|
|
|
std::string cwinname = XCompcap::getWindowName(cwin);
|
2016-07-02 23:49:19 -07:00
|
|
|
std::string ccls = XCompcap::getWindowClass(cwin);
|
2014-04-29 02:59:53 +02:00
|
|
|
|
2016-07-02 23:49:19 -07:00
|
|
|
if (cwin == wid && wname == cwinname && wcls == ccls)
|
2014-04-29 02:59:53 +02:00
|
|
|
return wid;
|
|
|
|
|
2016-07-03 19:46:55 -07:00
|
|
|
if (wname == cwinname ||
|
|
|
|
(!matchedNameWin && !wcls.empty() && wcls == ccls))
|
2014-04-29 02:59:53 +02:00
|
|
|
matchedNameWin = cwin;
|
|
|
|
}
|
|
|
|
|
|
|
|
return matchedNameWin;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void xcc_cleanup(XCompcapMain_private *p)
|
|
|
|
{
|
2016-01-25 08:43:32 -08:00
|
|
|
PLock lock(&p->lock);
|
2019-06-28 13:59:06 -07:00
|
|
|
XErrorLock xlock;
|
2016-01-25 08:43:32 -08:00
|
|
|
|
2014-05-15 02:12:22 -07:00
|
|
|
if (p->gltex) {
|
2018-10-08 12:18:40 -05:00
|
|
|
GLuint gltex = *(GLuint *)gs_texture_get_obj(p->gltex);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, gltex);
|
2019-06-28 13:59:06 -07:00
|
|
|
if (p->glxpixmap) {
|
|
|
|
glXReleaseTexImageEXT(xdisp, p->glxpixmap,
|
|
|
|
GLX_FRONT_LEFT_EXT);
|
|
|
|
if (xlock.gotError()) {
|
|
|
|
blog(LOG_ERROR,
|
|
|
|
"cleanup glXReleaseTexImageEXT failed: %s",
|
|
|
|
xlock.getErrorText().c_str());
|
|
|
|
xlock.resetError();
|
|
|
|
}
|
|
|
|
glXDestroyPixmap(xdisp, p->glxpixmap);
|
|
|
|
if (xlock.gotError()) {
|
|
|
|
blog(LOG_ERROR,
|
|
|
|
"cleanup glXDestroyPixmap failed: %s",
|
|
|
|
xlock.getErrorText().c_str());
|
|
|
|
xlock.resetError();
|
|
|
|
}
|
|
|
|
p->glxpixmap = 0;
|
|
|
|
}
|
2014-08-07 23:42:07 -07:00
|
|
|
gs_texture_destroy(p->gltex);
|
2014-04-29 02:59:53 +02:00
|
|
|
p->gltex = 0;
|
|
|
|
}
|
|
|
|
|
2014-05-15 02:12:22 -07:00
|
|
|
if (p->pixmap) {
|
2014-04-29 02:59:53 +02:00
|
|
|
XFreePixmap(xdisp, p->pixmap);
|
2019-06-28 13:59:06 -07:00
|
|
|
if (xlock.gotError()) {
|
|
|
|
blog(LOG_ERROR, "cleanup glXDestroyPixmap failed: %s",
|
|
|
|
xlock.getErrorText().c_str());
|
|
|
|
xlock.resetError();
|
|
|
|
}
|
2014-04-29 02:59:53 +02:00
|
|
|
p->pixmap = 0;
|
|
|
|
}
|
|
|
|
|
2014-05-15 02:12:22 -07:00
|
|
|
if (p->win) {
|
|
|
|
XCompositeUnredirectWindow(xdisp, p->win,
|
|
|
|
CompositeRedirectAutomatic);
|
2014-04-29 02:59:53 +02:00
|
|
|
XSelectInput(xdisp, p->win, 0);
|
|
|
|
p->win = 0;
|
|
|
|
}
|
2019-06-28 13:59:06 -07:00
|
|
|
|
|
|
|
if (p->tex) {
|
|
|
|
gs_texture_destroy(p->tex);
|
|
|
|
p->tex = 0;
|
|
|
|
}
|
2014-04-29 02:59:53 +02:00
|
|
|
}
|
|
|
|
|
2019-06-28 13:59:06 -07:00
|
|
|
static gs_color_format gs_format_from_tex()
|
|
|
|
{
|
|
|
|
GLint iformat = 0;
|
2019-08-11 17:45:56 -07:00
|
|
|
// consider GL_ARB_internalformat_query
|
2019-06-28 13:59:06 -07:00
|
|
|
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT,
|
|
|
|
&iformat);
|
2019-08-11 17:45:56 -07:00
|
|
|
|
|
|
|
// These formats are known to be wrong on Intel platforms. We intentionally
|
|
|
|
// use swapped internal formats here to preserve historic behavior which
|
|
|
|
// swapped colors accidentally and because D3D11 would not support a
|
|
|
|
// GS_RGBX format
|
2019-06-28 13:59:06 -07:00
|
|
|
switch (iformat) {
|
|
|
|
case GL_RGB:
|
2019-08-11 17:45:56 -07:00
|
|
|
return GS_BGRX;
|
2019-06-28 13:59:06 -07:00
|
|
|
case GL_RGBA:
|
|
|
|
return GS_RGBA;
|
|
|
|
default:
|
|
|
|
return GS_RGBA;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// from libobs-opengl/gl-subsystem.h because we need to handle GLX modifying textures outside libobs.
|
|
|
|
struct fb_info;
|
|
|
|
|
|
|
|
struct gs_texture {
|
|
|
|
gs_device_t *device;
|
|
|
|
enum gs_texture_type type;
|
|
|
|
enum gs_color_format format;
|
|
|
|
GLenum gl_format;
|
|
|
|
GLenum gl_target;
|
|
|
|
GLenum gl_internal_format;
|
|
|
|
GLenum gl_type;
|
|
|
|
GLuint texture;
|
|
|
|
uint32_t levels;
|
|
|
|
bool is_dynamic;
|
|
|
|
bool is_render_target;
|
|
|
|
bool is_dummy;
|
|
|
|
bool gen_mipmaps;
|
|
|
|
|
|
|
|
gs_samplerstate_t *cur_sampler;
|
|
|
|
struct fbo_info *fbo;
|
|
|
|
};
|
|
|
|
// End shitty hack.
|
|
|
|
|
2014-09-25 17:44:05 -07:00
|
|
|
void XCompcapMain::updateSettings(obs_data_t *settings)
|
2014-04-29 02:59:53 +02:00
|
|
|
{
|
|
|
|
PLock lock(&p->lock);
|
|
|
|
ObsGsContextHolder obsctx;
|
|
|
|
|
|
|
|
blog(LOG_DEBUG, "Settings updating");
|
|
|
|
|
|
|
|
Window prevWin = p->win;
|
|
|
|
|
|
|
|
xcc_cleanup(p);
|
|
|
|
|
2014-05-15 02:12:22 -07:00
|
|
|
if (settings) {
|
2014-08-05 11:09:29 -07:00
|
|
|
const char *windowName =
|
|
|
|
obs_data_get_string(settings, "capture_window");
|
2014-05-15 02:12:22 -07:00
|
|
|
|
2015-08-16 16:37:50 +03:00
|
|
|
p->windowName = windowName;
|
2014-05-15 02:12:22 -07:00
|
|
|
p->win = getWindowFromString(windowName);
|
2014-04-29 02:59:53 +02:00
|
|
|
|
2014-08-05 11:09:29 -07:00
|
|
|
p->cut_top = obs_data_get_int(settings, "cut_top");
|
|
|
|
p->cut_left = obs_data_get_int(settings, "cut_left");
|
|
|
|
p->cut_right = obs_data_get_int(settings, "cut_right");
|
|
|
|
p->cut_bot = obs_data_get_int(settings, "cut_bot");
|
|
|
|
p->lockX = obs_data_get_bool(settings, "lock_x");
|
|
|
|
p->swapRedBlue = obs_data_get_bool(settings, "swap_redblue");
|
2014-08-29 17:17:04 -07:00
|
|
|
p->show_cursor = obs_data_get_bool(settings, "show_cursor");
|
2014-11-05 18:40:17 -06:00
|
|
|
p->include_border =
|
|
|
|
obs_data_get_bool(settings, "include_border");
|
2016-02-28 02:49:34 -05:00
|
|
|
p->exclude_alpha = obs_data_get_bool(settings, "exclude_alpha");
|
2018-09-13 07:52:19 -05:00
|
|
|
p->draw_opaque = false;
|
2014-05-15 02:12:22 -07:00
|
|
|
} else {
|
2014-04-29 02:59:53 +02:00
|
|
|
p->win = prevWin;
|
|
|
|
}
|
|
|
|
|
2019-06-28 13:59:06 -07:00
|
|
|
XErrorLock xlock;
|
linux-capture: Fix window capture crashes
The xcomposite window capture crashes were due to a few factors:
-------------------------------
1.) The source's X error handler was possibly being overwritten by
another part of the program despite us locking the display, presumably
something in Qt which isn't locking the display when pushing/popping its
own error handler (though this is not yet certain). The source's calls
to X functions happen in the graphics thread, which is separate from the
UI thread, and it was noticed that somehow the error handler would be
overwritten almost seemingly at random, indicating that something else
in the program outside of OBS code was not locking the display while
pushing/popping the error handler.
To replicate this, make it so that the source cannot find the target
window and so it continually searches for it each video_tick call, then
resize the main OBS window continually (which causes Qt to push/pop its
own error handlers). A crash will almost always occur due to BadWindow
despite our error handling.
2.) Calling X functions with a window ID that no longer exists,
particularly XGetWindowAttributes, in conjunction the unknown error
handler set in case #1 would cause the program to outright crash because
that error handler is programmed to crash on BadWindow for whatever
reason. The source would call X functions without even checking if
'win' was 0.
3.) The source stored window IDs (in JSON, even if they've long since
become invalid/pointless, such as system restarts). This is a bad
practice and will result in more cases of BadWindow.
Fixing the problem (reducing the possibility of getting BadWindow):
-------------------------------
Step 1.) Deprecate and ignore window IDs in stored settings. Instead of
using window IDs to find the window, we now must always search the
windows and find the target window via the window name exclusively.
This helps ensure that we actually consistently have a working window
ID.
Step 2.) Do not call any X functions if the window ID is 0.
Step 3.) Reset the window ID to 0 any time the window has updated, and
make the source find the window again to ensure it still exists before
attempting to use any X functions on the window ID again.
2016-06-04 14:20:41 -07:00
|
|
|
if (p->win)
|
|
|
|
XCompositeRedirectWindow(xdisp, p->win,
|
|
|
|
CompositeRedirectAutomatic);
|
2014-05-15 02:12:22 -07:00
|
|
|
if (xlock.gotError()) {
|
|
|
|
blog(LOG_ERROR, "XCompositeRedirectWindow failed: %s",
|
|
|
|
xlock.getErrorText().c_str());
|
2014-04-29 02:59:53 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
linux-capture: Fix window capture crashes
The xcomposite window capture crashes were due to a few factors:
-------------------------------
1.) The source's X error handler was possibly being overwritten by
another part of the program despite us locking the display, presumably
something in Qt which isn't locking the display when pushing/popping its
own error handler (though this is not yet certain). The source's calls
to X functions happen in the graphics thread, which is separate from the
UI thread, and it was noticed that somehow the error handler would be
overwritten almost seemingly at random, indicating that something else
in the program outside of OBS code was not locking the display while
pushing/popping the error handler.
To replicate this, make it so that the source cannot find the target
window and so it continually searches for it each video_tick call, then
resize the main OBS window continually (which causes Qt to push/pop its
own error handlers). A crash will almost always occur due to BadWindow
despite our error handling.
2.) Calling X functions with a window ID that no longer exists,
particularly XGetWindowAttributes, in conjunction the unknown error
handler set in case #1 would cause the program to outright crash because
that error handler is programmed to crash on BadWindow for whatever
reason. The source would call X functions without even checking if
'win' was 0.
3.) The source stored window IDs (in JSON, even if they've long since
become invalid/pointless, such as system restarts). This is a bad
practice and will result in more cases of BadWindow.
Fixing the problem (reducing the possibility of getting BadWindow):
-------------------------------
Step 1.) Deprecate and ignore window IDs in stored settings. Instead of
using window IDs to find the window, we now must always search the
windows and find the target window via the window name exclusively.
This helps ensure that we actually consistently have a working window
ID.
Step 2.) Do not call any X functions if the window ID is 0.
Step 3.) Reset the window ID to 0 any time the window has updated, and
make the source find the window again to ensure it still exists before
attempting to use any X functions on the window ID again.
2016-06-04 14:20:41 -07:00
|
|
|
if (p->win)
|
2017-03-28 17:57:14 -05:00
|
|
|
XSelectInput(xdisp, p->win,
|
|
|
|
StructureNotifyMask | ExposureMask |
|
|
|
|
VisibilityChangeMask);
|
2014-04-29 02:59:53 +02:00
|
|
|
XSync(xdisp, 0);
|
|
|
|
|
|
|
|
XWindowAttributes attr;
|
linux-capture: Fix window capture crashes
The xcomposite window capture crashes were due to a few factors:
-------------------------------
1.) The source's X error handler was possibly being overwritten by
another part of the program despite us locking the display, presumably
something in Qt which isn't locking the display when pushing/popping its
own error handler (though this is not yet certain). The source's calls
to X functions happen in the graphics thread, which is separate from the
UI thread, and it was noticed that somehow the error handler would be
overwritten almost seemingly at random, indicating that something else
in the program outside of OBS code was not locking the display while
pushing/popping the error handler.
To replicate this, make it so that the source cannot find the target
window and so it continually searches for it each video_tick call, then
resize the main OBS window continually (which causes Qt to push/pop its
own error handlers). A crash will almost always occur due to BadWindow
despite our error handling.
2.) Calling X functions with a window ID that no longer exists,
particularly XGetWindowAttributes, in conjunction the unknown error
handler set in case #1 would cause the program to outright crash because
that error handler is programmed to crash on BadWindow for whatever
reason. The source would call X functions without even checking if
'win' was 0.
3.) The source stored window IDs (in JSON, even if they've long since
become invalid/pointless, such as system restarts). This is a bad
practice and will result in more cases of BadWindow.
Fixing the problem (reducing the possibility of getting BadWindow):
-------------------------------
Step 1.) Deprecate and ignore window IDs in stored settings. Instead of
using window IDs to find the window, we now must always search the
windows and find the target window via the window name exclusively.
This helps ensure that we actually consistently have a working window
ID.
Step 2.) Do not call any X functions if the window ID is 0.
Step 3.) Reset the window ID to 0 any time the window has updated, and
make the source find the window again to ensure it still exists before
attempting to use any X functions on the window ID again.
2016-06-04 14:20:41 -07:00
|
|
|
if (!p->win || !XGetWindowAttributes(xdisp, p->win, &attr)) {
|
2014-04-29 02:59:53 +02:00
|
|
|
p->win = 0;
|
|
|
|
p->width = 0;
|
|
|
|
p->height = 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
linux-capture: Fix window capture crashes
The xcomposite window capture crashes were due to a few factors:
-------------------------------
1.) The source's X error handler was possibly being overwritten by
another part of the program despite us locking the display, presumably
something in Qt which isn't locking the display when pushing/popping its
own error handler (though this is not yet certain). The source's calls
to X functions happen in the graphics thread, which is separate from the
UI thread, and it was noticed that somehow the error handler would be
overwritten almost seemingly at random, indicating that something else
in the program outside of OBS code was not locking the display while
pushing/popping the error handler.
To replicate this, make it so that the source cannot find the target
window and so it continually searches for it each video_tick call, then
resize the main OBS window continually (which causes Qt to push/pop its
own error handlers). A crash will almost always occur due to BadWindow
despite our error handling.
2.) Calling X functions with a window ID that no longer exists,
particularly XGetWindowAttributes, in conjunction the unknown error
handler set in case #1 would cause the program to outright crash because
that error handler is programmed to crash on BadWindow for whatever
reason. The source would call X functions without even checking if
'win' was 0.
3.) The source stored window IDs (in JSON, even if they've long since
become invalid/pointless, such as system restarts). This is a bad
practice and will result in more cases of BadWindow.
Fixing the problem (reducing the possibility of getting BadWindow):
-------------------------------
Step 1.) Deprecate and ignore window IDs in stored settings. Instead of
using window IDs to find the window, we now must always search the
windows and find the target window via the window name exclusively.
This helps ensure that we actually consistently have a working window
ID.
Step 2.) Do not call any X functions if the window ID is 0.
Step 3.) Reset the window ID to 0 any time the window has updated, and
make the source find the window again to ensure it still exists before
attempting to use any X functions on the window ID again.
2016-06-04 14:20:41 -07:00
|
|
|
if (p->win && p->cursor && p->show_cursor) {
|
2014-08-29 17:17:04 -07:00
|
|
|
Window child;
|
|
|
|
int x, y;
|
|
|
|
|
|
|
|
XTranslateCoordinates(xdisp, p->win, attr.root, 0, 0, &x, &y,
|
|
|
|
&child);
|
2014-08-30 13:09:00 -05:00
|
|
|
xcursor_offset(p->cursor, x, y);
|
2014-08-29 17:17:04 -07:00
|
|
|
}
|
|
|
|
|
2019-06-28 13:59:06 -07:00
|
|
|
const int config_attrs[] = {GLX_BIND_TO_TEXTURE_RGBA_EXT,
|
|
|
|
GL_TRUE,
|
|
|
|
GLX_DRAWABLE_TYPE,
|
|
|
|
GLX_PIXMAP_BIT,
|
|
|
|
GLX_BIND_TO_TEXTURE_TARGETS_EXT,
|
|
|
|
GLX_TEXTURE_2D_BIT_EXT,
|
|
|
|
GLX_DOUBLEBUFFER,
|
|
|
|
GL_FALSE,
|
|
|
|
None};
|
2018-10-08 12:18:40 -05:00
|
|
|
int nelem = 0;
|
2019-06-28 13:59:06 -07:00
|
|
|
GLXFBConfig *configs = glXChooseFBConfig(
|
|
|
|
xdisp, XCompcap::getRootWindowScreen(attr.root), config_attrs,
|
|
|
|
&nelem);
|
2018-10-08 12:18:40 -05:00
|
|
|
|
2019-06-28 13:59:06 -07:00
|
|
|
bool found = false;
|
2018-10-08 12:18:40 -05:00
|
|
|
GLXFBConfig config;
|
|
|
|
for (int i = 0; i < nelem; i++) {
|
|
|
|
config = configs[i];
|
|
|
|
XVisualInfo *visual = glXGetVisualFromFBConfig(xdisp, config);
|
|
|
|
if (!visual)
|
|
|
|
continue;
|
|
|
|
|
2019-06-28 13:59:06 -07:00
|
|
|
if (attr.depth != visual->depth) {
|
2018-10-08 12:18:40 -05:00
|
|
|
XFree(visual);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
XFree(visual);
|
2019-06-28 13:59:06 -07:00
|
|
|
found = true;
|
2018-10-08 12:18:40 -05:00
|
|
|
break;
|
2018-09-13 07:52:19 -05:00
|
|
|
}
|
2019-06-28 13:59:06 -07:00
|
|
|
if (!found) {
|
2018-10-08 12:18:40 -05:00
|
|
|
blog(LOG_ERROR, "no matching fb config found");
|
|
|
|
p->win = 0;
|
|
|
|
p->height = 0;
|
|
|
|
p->width = 0;
|
2019-06-28 13:59:06 -07:00
|
|
|
XFree(configs);
|
2018-10-08 12:18:40 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-06-28 13:59:06 -07:00
|
|
|
if (p->exclude_alpha || attr.depth != 32) {
|
2018-09-13 07:52:19 -05:00
|
|
|
p->draw_opaque = true;
|
|
|
|
}
|
|
|
|
|
2018-10-08 12:18:40 -05:00
|
|
|
int inverted;
|
|
|
|
glXGetFBConfigAttrib(xdisp, config, GLX_Y_INVERTED_EXT, &inverted);
|
|
|
|
p->inverted = inverted != 0;
|
|
|
|
|
2014-11-05 18:40:17 -06:00
|
|
|
p->border = attr.border_width;
|
|
|
|
|
|
|
|
if (p->include_border) {
|
|
|
|
p->width = attr.width + p->border * 2;
|
|
|
|
p->height = attr.height + p->border * 2;
|
|
|
|
} else {
|
|
|
|
p->width = attr.width;
|
|
|
|
p->height = attr.height;
|
|
|
|
}
|
2014-04-29 02:59:53 +02:00
|
|
|
|
2014-05-15 02:12:22 -07:00
|
|
|
if (p->cut_top + p->cut_bot < (int)p->height) {
|
2014-04-29 02:59:53 +02:00
|
|
|
p->cur_cut_top = p->cut_top;
|
|
|
|
p->cur_cut_bot = p->cut_bot;
|
2014-05-15 02:12:22 -07:00
|
|
|
} else {
|
2014-04-29 02:59:53 +02:00
|
|
|
p->cur_cut_top = 0;
|
|
|
|
p->cur_cut_bot = 0;
|
|
|
|
}
|
|
|
|
|
2014-05-15 02:12:22 -07:00
|
|
|
if (p->cut_left + p->cut_right < (int)p->width) {
|
2014-04-29 02:59:53 +02:00
|
|
|
p->cur_cut_left = p->cut_left;
|
|
|
|
p->cur_cut_right = p->cut_right;
|
2014-05-15 02:12:22 -07:00
|
|
|
} else {
|
2014-04-29 02:59:53 +02:00
|
|
|
p->cur_cut_left = 0;
|
|
|
|
p->cur_cut_right = 0;
|
|
|
|
}
|
|
|
|
|
2019-06-28 13:59:06 -07:00
|
|
|
// Precautionary since we dont error check every GLX call above.
|
2014-04-29 02:59:53 +02:00
|
|
|
xlock.resetError();
|
|
|
|
|
|
|
|
p->pixmap = XCompositeNameWindowPixmap(xdisp, p->win);
|
2014-05-15 02:12:22 -07:00
|
|
|
if (xlock.gotError()) {
|
|
|
|
blog(LOG_ERROR, "XCompositeNameWindowPixmap failed: %s",
|
|
|
|
xlock.getErrorText().c_str());
|
2014-04-29 02:59:53 +02:00
|
|
|
p->pixmap = 0;
|
|
|
|
XFree(configs);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-06-28 13:59:06 -07:00
|
|
|
// Should be consistent format with config we are using. Since we searched on RGBA lets use RGBA here.
|
|
|
|
const int pixmap_attrs[] = {GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT,
|
|
|
|
GLX_TEXTURE_FORMAT_EXT,
|
|
|
|
GLX_TEXTURE_FORMAT_RGBA_EXT, None};
|
2014-04-29 02:59:53 +02:00
|
|
|
|
2019-06-28 13:59:06 -07:00
|
|
|
p->glxpixmap = glXCreatePixmap(xdisp, config, p->pixmap, pixmap_attrs);
|
2014-05-15 02:12:22 -07:00
|
|
|
if (xlock.gotError()) {
|
|
|
|
blog(LOG_ERROR, "glXCreatePixmap failed: %s",
|
|
|
|
xlock.getErrorText().c_str());
|
2014-04-29 02:59:53 +02:00
|
|
|
XFreePixmap(xdisp, p->pixmap);
|
|
|
|
XFree(configs);
|
|
|
|
p->pixmap = 0;
|
|
|
|
p->glxpixmap = 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
XFree(configs);
|
|
|
|
|
2019-06-28 13:59:06 -07:00
|
|
|
// Build an OBS texture to bind the pixmap to.
|
|
|
|
p->gltex = gs_texture_create(p->width, p->height, GS_RGBA, 1, 0,
|
2014-05-15 02:12:22 -07:00
|
|
|
GS_GL_DUMMYTEX);
|
2014-08-07 23:42:07 -07:00
|
|
|
GLuint gltex = *(GLuint *)gs_texture_get_obj(p->gltex);
|
2014-04-29 02:59:53 +02:00
|
|
|
glBindTexture(GL_TEXTURE_2D, gltex);
|
|
|
|
glXBindTexImageEXT(xdisp, p->glxpixmap, GLX_FRONT_LEFT_EXT, NULL);
|
2019-06-28 13:59:06 -07:00
|
|
|
if (xlock.gotError()) {
|
|
|
|
blog(LOG_ERROR, "glXBindTexImageEXT failed: %s",
|
|
|
|
xlock.getErrorText().c_str());
|
|
|
|
XFreePixmap(xdisp, p->pixmap);
|
|
|
|
XFree(configs);
|
|
|
|
p->pixmap = 0;
|
|
|
|
p->glxpixmap = 0;
|
|
|
|
return;
|
|
|
|
}
|
2014-04-29 02:59:53 +02:00
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
2019-06-28 13:59:06 -07:00
|
|
|
// glxBindTexImageEXT might modify the textures format.
|
|
|
|
gs_color_format format = gs_format_from_tex();
|
|
|
|
glBindTexture(GL_TEXTURE_2D, 0);
|
|
|
|
// sync OBS texture format based on any glxBindTexImageEXT changes
|
|
|
|
p->gltex->format = format;
|
|
|
|
|
|
|
|
// Create a pure OBS texture to use for rendering. Using the same
|
|
|
|
// format so we can copy instead of drawing from the source gltex.
|
|
|
|
if (p->tex)
|
|
|
|
gs_texture_destroy(p->tex);
|
|
|
|
p->tex = gs_texture_create(width(), height(), format, 1, 0,
|
|
|
|
GS_GL_DUMMYTEX);
|
|
|
|
if (p->swapRedBlue) {
|
2019-08-17 22:46:51 -07:00
|
|
|
GLuint tex = *(GLuint *)gs_texture_get_obj(p->tex);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, tex);
|
2019-06-28 13:59:06 -07:00
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_BLUE);
|
2019-08-17 22:46:51 -07:00
|
|
|
glBindTexture(GL_TEXTURE_2D, 0);
|
2019-06-28 13:59:06 -07:00
|
|
|
}
|
2017-05-31 05:47:10 -04:00
|
|
|
|
|
|
|
if (!p->windowName.empty()) {
|
|
|
|
blog(LOG_INFO,
|
|
|
|
"[window-capture: '%s'] update settings:\n"
|
|
|
|
"\ttitle: %s\n"
|
2018-09-13 07:52:19 -05:00
|
|
|
"\tclass: %s\n"
|
2019-06-28 13:59:06 -07:00
|
|
|
"\tBit depth: %i\n"
|
|
|
|
"\tFound proper GLXFBConfig (in %i): %s\n",
|
2017-05-31 05:47:10 -04:00
|
|
|
obs_source_get_name(p->source),
|
|
|
|
XCompcap::getWindowName(p->win).c_str(),
|
2019-06-28 13:59:06 -07:00
|
|
|
XCompcap::getWindowClass(p->win).c_str(), attr.depth,
|
|
|
|
nelem, found ? "yes" : "no");
|
2017-05-31 05:47:10 -04:00
|
|
|
}
|
2014-04-29 02:59:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void XCompcapMain::tick(float seconds)
|
|
|
|
{
|
2015-01-03 22:39:21 -08:00
|
|
|
if (!obs_source_showing(p->source))
|
|
|
|
return;
|
|
|
|
|
2014-04-29 02:59:53 +02:00
|
|
|
PLock lock(&p->lock, true);
|
|
|
|
|
2014-05-15 02:12:22 -07:00
|
|
|
if (!lock.isLocked())
|
2014-04-29 02:59:53 +02:00
|
|
|
return;
|
|
|
|
|
|
|
|
XCompcap::processEvents();
|
|
|
|
|
linux-capture: Fix window capture crashes
The xcomposite window capture crashes were due to a few factors:
-------------------------------
1.) The source's X error handler was possibly being overwritten by
another part of the program despite us locking the display, presumably
something in Qt which isn't locking the display when pushing/popping its
own error handler (though this is not yet certain). The source's calls
to X functions happen in the graphics thread, which is separate from the
UI thread, and it was noticed that somehow the error handler would be
overwritten almost seemingly at random, indicating that something else
in the program outside of OBS code was not locking the display while
pushing/popping the error handler.
To replicate this, make it so that the source cannot find the target
window and so it continually searches for it each video_tick call, then
resize the main OBS window continually (which causes Qt to push/pop its
own error handlers). A crash will almost always occur due to BadWindow
despite our error handling.
2.) Calling X functions with a window ID that no longer exists,
particularly XGetWindowAttributes, in conjunction the unknown error
handler set in case #1 would cause the program to outright crash because
that error handler is programmed to crash on BadWindow for whatever
reason. The source would call X functions without even checking if
'win' was 0.
3.) The source stored window IDs (in JSON, even if they've long since
become invalid/pointless, such as system restarts). This is a bad
practice and will result in more cases of BadWindow.
Fixing the problem (reducing the possibility of getting BadWindow):
-------------------------------
Step 1.) Deprecate and ignore window IDs in stored settings. Instead of
using window IDs to find the window, we now must always search the
windows and find the target window via the window name exclusively.
This helps ensure that we actually consistently have a working window
ID.
Step 2.) Do not call any X functions if the window ID is 0.
Step 3.) Reset the window ID to 0 any time the window has updated, and
make the source find the window again to ensure it still exists before
attempting to use any X functions on the window ID again.
2016-06-04 14:20:41 -07:00
|
|
|
if (p->win && XCompcap::windowWasReconfigured(p->win)) {
|
|
|
|
p->window_check_time = FIND_WINDOW_INTERVAL;
|
|
|
|
p->win = 0;
|
|
|
|
}
|
2014-04-29 02:59:53 +02:00
|
|
|
|
linux-capture: Fix window capture crashes
The xcomposite window capture crashes were due to a few factors:
-------------------------------
1.) The source's X error handler was possibly being overwritten by
another part of the program despite us locking the display, presumably
something in Qt which isn't locking the display when pushing/popping its
own error handler (though this is not yet certain). The source's calls
to X functions happen in the graphics thread, which is separate from the
UI thread, and it was noticed that somehow the error handler would be
overwritten almost seemingly at random, indicating that something else
in the program outside of OBS code was not locking the display while
pushing/popping the error handler.
To replicate this, make it so that the source cannot find the target
window and so it continually searches for it each video_tick call, then
resize the main OBS window continually (which causes Qt to push/pop its
own error handlers). A crash will almost always occur due to BadWindow
despite our error handling.
2.) Calling X functions with a window ID that no longer exists,
particularly XGetWindowAttributes, in conjunction the unknown error
handler set in case #1 would cause the program to outright crash because
that error handler is programmed to crash on BadWindow for whatever
reason. The source would call X functions without even checking if
'win' was 0.
3.) The source stored window IDs (in JSON, even if they've long since
become invalid/pointless, such as system restarts). This is a bad
practice and will result in more cases of BadWindow.
Fixing the problem (reducing the possibility of getting BadWindow):
-------------------------------
Step 1.) Deprecate and ignore window IDs in stored settings. Instead of
using window IDs to find the window, we now must always search the
windows and find the target window via the window name exclusively.
This helps ensure that we actually consistently have a working window
ID.
Step 2.) Do not call any X functions if the window ID is 0.
Step 3.) Reset the window ID to 0 any time the window has updated, and
make the source find the window again to ensure it still exists before
attempting to use any X functions on the window ID again.
2016-06-04 14:20:41 -07:00
|
|
|
XDisplayLock xlock;
|
2015-08-16 16:37:50 +03:00
|
|
|
XWindowAttributes attr;
|
|
|
|
|
linux-capture: Fix window capture crashes
The xcomposite window capture crashes were due to a few factors:
-------------------------------
1.) The source's X error handler was possibly being overwritten by
another part of the program despite us locking the display, presumably
something in Qt which isn't locking the display when pushing/popping its
own error handler (though this is not yet certain). The source's calls
to X functions happen in the graphics thread, which is separate from the
UI thread, and it was noticed that somehow the error handler would be
overwritten almost seemingly at random, indicating that something else
in the program outside of OBS code was not locking the display while
pushing/popping the error handler.
To replicate this, make it so that the source cannot find the target
window and so it continually searches for it each video_tick call, then
resize the main OBS window continually (which causes Qt to push/pop its
own error handlers). A crash will almost always occur due to BadWindow
despite our error handling.
2.) Calling X functions with a window ID that no longer exists,
particularly XGetWindowAttributes, in conjunction the unknown error
handler set in case #1 would cause the program to outright crash because
that error handler is programmed to crash on BadWindow for whatever
reason. The source would call X functions without even checking if
'win' was 0.
3.) The source stored window IDs (in JSON, even if they've long since
become invalid/pointless, such as system restarts). This is a bad
practice and will result in more cases of BadWindow.
Fixing the problem (reducing the possibility of getting BadWindow):
-------------------------------
Step 1.) Deprecate and ignore window IDs in stored settings. Instead of
using window IDs to find the window, we now must always search the
windows and find the target window via the window name exclusively.
This helps ensure that we actually consistently have a working window
ID.
Step 2.) Do not call any X functions if the window ID is 0.
Step 3.) Reset the window ID to 0 any time the window has updated, and
make the source find the window again to ensure it still exists before
attempting to use any X functions on the window ID again.
2016-06-04 14:20:41 -07:00
|
|
|
if (!p->win || !XGetWindowAttributes(xdisp, p->win, &attr)) {
|
|
|
|
p->window_check_time += (double)seconds;
|
|
|
|
|
|
|
|
if (p->window_check_time < FIND_WINDOW_INTERVAL)
|
|
|
|
return;
|
|
|
|
|
2015-08-16 16:37:50 +03:00
|
|
|
Window newWin = getWindowFromString(p->windowName);
|
|
|
|
|
linux-capture: Fix window capture crashes
The xcomposite window capture crashes were due to a few factors:
-------------------------------
1.) The source's X error handler was possibly being overwritten by
another part of the program despite us locking the display, presumably
something in Qt which isn't locking the display when pushing/popping its
own error handler (though this is not yet certain). The source's calls
to X functions happen in the graphics thread, which is separate from the
UI thread, and it was noticed that somehow the error handler would be
overwritten almost seemingly at random, indicating that something else
in the program outside of OBS code was not locking the display while
pushing/popping the error handler.
To replicate this, make it so that the source cannot find the target
window and so it continually searches for it each video_tick call, then
resize the main OBS window continually (which causes Qt to push/pop its
own error handlers). A crash will almost always occur due to BadWindow
despite our error handling.
2.) Calling X functions with a window ID that no longer exists,
particularly XGetWindowAttributes, in conjunction the unknown error
handler set in case #1 would cause the program to outright crash because
that error handler is programmed to crash on BadWindow for whatever
reason. The source would call X functions without even checking if
'win' was 0.
3.) The source stored window IDs (in JSON, even if they've long since
become invalid/pointless, such as system restarts). This is a bad
practice and will result in more cases of BadWindow.
Fixing the problem (reducing the possibility of getting BadWindow):
-------------------------------
Step 1.) Deprecate and ignore window IDs in stored settings. Instead of
using window IDs to find the window, we now must always search the
windows and find the target window via the window name exclusively.
This helps ensure that we actually consistently have a working window
ID.
Step 2.) Do not call any X functions if the window ID is 0.
Step 3.) Reset the window ID to 0 any time the window has updated, and
make the source find the window again to ensure it still exists before
attempting to use any X functions on the window ID again.
2016-06-04 14:20:41 -07:00
|
|
|
p->window_check_time = 0.0;
|
|
|
|
|
|
|
|
if (newWin && XGetWindowAttributes(xdisp, newWin, &attr)) {
|
2015-08-16 16:37:50 +03:00
|
|
|
p->win = newWin;
|
|
|
|
updateSettings(0);
|
linux-capture: Fix window capture crashes
The xcomposite window capture crashes were due to a few factors:
-------------------------------
1.) The source's X error handler was possibly being overwritten by
another part of the program despite us locking the display, presumably
something in Qt which isn't locking the display when pushing/popping its
own error handler (though this is not yet certain). The source's calls
to X functions happen in the graphics thread, which is separate from the
UI thread, and it was noticed that somehow the error handler would be
overwritten almost seemingly at random, indicating that something else
in the program outside of OBS code was not locking the display while
pushing/popping the error handler.
To replicate this, make it so that the source cannot find the target
window and so it continually searches for it each video_tick call, then
resize the main OBS window continually (which causes Qt to push/pop its
own error handlers). A crash will almost always occur due to BadWindow
despite our error handling.
2.) Calling X functions with a window ID that no longer exists,
particularly XGetWindowAttributes, in conjunction the unknown error
handler set in case #1 would cause the program to outright crash because
that error handler is programmed to crash on BadWindow for whatever
reason. The source would call X functions without even checking if
'win' was 0.
3.) The source stored window IDs (in JSON, even if they've long since
become invalid/pointless, such as system restarts). This is a bad
practice and will result in more cases of BadWindow.
Fixing the problem (reducing the possibility of getting BadWindow):
-------------------------------
Step 1.) Deprecate and ignore window IDs in stored settings. Instead of
using window IDs to find the window, we now must always search the
windows and find the target window via the window name exclusively.
This helps ensure that we actually consistently have a working window
ID.
Step 2.) Do not call any X functions if the window ID is 0.
Step 3.) Reset the window ID to 0 any time the window has updated, and
make the source find the window again to ensure it still exists before
attempting to use any X functions on the window ID again.
2016-06-04 14:20:41 -07:00
|
|
|
} else {
|
|
|
|
return;
|
2015-08-16 16:37:50 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-05-15 02:12:22 -07:00
|
|
|
if (!p->tex || !p->gltex)
|
2014-04-29 02:59:53 +02:00
|
|
|
return;
|
|
|
|
|
2014-08-04 05:48:58 -07:00
|
|
|
obs_enter_graphics();
|
2014-04-29 02:59:53 +02:00
|
|
|
|
2014-05-15 02:12:22 -07:00
|
|
|
if (p->lockX) {
|
2019-06-28 13:59:06 -07:00
|
|
|
// XDisplayLock is still live so we should already be locked.
|
2014-04-29 02:59:53 +02:00
|
|
|
XLockDisplay(xdisp);
|
|
|
|
XSync(xdisp, 0);
|
|
|
|
}
|
|
|
|
|
2014-11-05 18:40:17 -06:00
|
|
|
if (p->include_border) {
|
|
|
|
gs_copy_texture_region(p->tex, 0, 0, p->gltex, p->cur_cut_left,
|
|
|
|
p->cur_cut_top, width(), height());
|
|
|
|
} else {
|
|
|
|
gs_copy_texture_region(p->tex, 0, 0, p->gltex,
|
|
|
|
p->cur_cut_left + p->border,
|
|
|
|
p->cur_cut_top + p->border, width(),
|
|
|
|
height());
|
|
|
|
}
|
2014-04-29 02:59:53 +02:00
|
|
|
|
2014-08-29 17:17:04 -07:00
|
|
|
if (p->cursor && p->show_cursor) {
|
|
|
|
xcursor_tick(p->cursor);
|
|
|
|
|
|
|
|
p->cursor_outside =
|
|
|
|
p->cursor->x < p->cur_cut_left ||
|
|
|
|
p->cursor->y < p->cur_cut_top ||
|
|
|
|
p->cursor->x > int(p->width - p->cur_cut_right) ||
|
|
|
|
p->cursor->y > int(p->height - p->cur_cut_bot);
|
|
|
|
}
|
|
|
|
|
2014-05-15 02:12:22 -07:00
|
|
|
if (p->lockX)
|
2014-04-29 02:59:53 +02:00
|
|
|
XUnlockDisplay(xdisp);
|
|
|
|
|
2014-08-04 05:48:58 -07:00
|
|
|
obs_leave_graphics();
|
2014-04-29 02:59:53 +02:00
|
|
|
}
|
|
|
|
|
2014-09-25 17:44:05 -07:00
|
|
|
void XCompcapMain::render(gs_effect_t *effect)
|
2014-04-29 02:59:53 +02:00
|
|
|
{
|
2016-02-21 18:25:36 -08:00
|
|
|
if (!p->win)
|
|
|
|
return;
|
|
|
|
|
linux-capture: Fix window capture crashes
The xcomposite window capture crashes were due to a few factors:
-------------------------------
1.) The source's X error handler was possibly being overwritten by
another part of the program despite us locking the display, presumably
something in Qt which isn't locking the display when pushing/popping its
own error handler (though this is not yet certain). The source's calls
to X functions happen in the graphics thread, which is separate from the
UI thread, and it was noticed that somehow the error handler would be
overwritten almost seemingly at random, indicating that something else
in the program outside of OBS code was not locking the display while
pushing/popping the error handler.
To replicate this, make it so that the source cannot find the target
window and so it continually searches for it each video_tick call, then
resize the main OBS window continually (which causes Qt to push/pop its
own error handlers). A crash will almost always occur due to BadWindow
despite our error handling.
2.) Calling X functions with a window ID that no longer exists,
particularly XGetWindowAttributes, in conjunction the unknown error
handler set in case #1 would cause the program to outright crash because
that error handler is programmed to crash on BadWindow for whatever
reason. The source would call X functions without even checking if
'win' was 0.
3.) The source stored window IDs (in JSON, even if they've long since
become invalid/pointless, such as system restarts). This is a bad
practice and will result in more cases of BadWindow.
Fixing the problem (reducing the possibility of getting BadWindow):
-------------------------------
Step 1.) Deprecate and ignore window IDs in stored settings. Instead of
using window IDs to find the window, we now must always search the
windows and find the target window via the window name exclusively.
This helps ensure that we actually consistently have a working window
ID.
Step 2.) Do not call any X functions if the window ID is 0.
Step 3.) Reset the window ID to 0 any time the window has updated, and
make the source find the window again to ensure it still exists before
attempting to use any X functions on the window ID again.
2016-06-04 14:20:41 -07:00
|
|
|
PLock lock(&p->lock, true);
|
|
|
|
|
2018-09-13 07:52:19 -05:00
|
|
|
if (p->draw_opaque)
|
|
|
|
effect = obs_get_base_effect(OBS_EFFECT_OPAQUE);
|
|
|
|
else
|
|
|
|
effect = obs_get_base_effect(OBS_EFFECT_DEFAULT);
|
2014-04-29 02:59:53 +02:00
|
|
|
|
2014-05-15 02:12:22 -07:00
|
|
|
if (!lock.isLocked() || !p->tex)
|
2014-04-29 02:59:53 +02:00
|
|
|
return;
|
|
|
|
|
2014-09-25 17:44:05 -07:00
|
|
|
gs_eparam_t *image = gs_effect_get_param_by_name(effect, "image");
|
2014-08-07 23:42:07 -07:00
|
|
|
gs_effect_set_texture(image, p->tex);
|
2014-04-29 02:59:53 +02:00
|
|
|
|
2015-03-14 00:38:09 -07:00
|
|
|
while (gs_effect_loop(effect, "Draw")) {
|
|
|
|
gs_draw_sprite(p->tex, 0, 0, 0);
|
|
|
|
}
|
2014-07-03 14:12:48 -07:00
|
|
|
|
2015-03-14 00:38:09 -07:00
|
|
|
if (p->cursor && p->gltex && p->show_cursor && !p->cursor_outside) {
|
2015-10-16 07:31:52 -07:00
|
|
|
effect = obs_get_base_effect(OBS_EFFECT_DEFAULT);
|
2014-08-29 17:17:04 -07:00
|
|
|
|
2015-03-14 00:38:09 -07:00
|
|
|
while (gs_effect_loop(effect, "Draw")) {
|
2019-10-28 19:59:19 +11:00
|
|
|
xcursor_render(p->cursor, -p->cur_cut_left,
|
|
|
|
-p->cur_cut_top);
|
2015-03-14 00:38:09 -07:00
|
|
|
}
|
|
|
|
}
|
2014-04-29 02:59:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t XCompcapMain::width()
|
|
|
|
{
|
linux-capture: Fix window capture crashes
The xcomposite window capture crashes were due to a few factors:
-------------------------------
1.) The source's X error handler was possibly being overwritten by
another part of the program despite us locking the display, presumably
something in Qt which isn't locking the display when pushing/popping its
own error handler (though this is not yet certain). The source's calls
to X functions happen in the graphics thread, which is separate from the
UI thread, and it was noticed that somehow the error handler would be
overwritten almost seemingly at random, indicating that something else
in the program outside of OBS code was not locking the display while
pushing/popping the error handler.
To replicate this, make it so that the source cannot find the target
window and so it continually searches for it each video_tick call, then
resize the main OBS window continually (which causes Qt to push/pop its
own error handlers). A crash will almost always occur due to BadWindow
despite our error handling.
2.) Calling X functions with a window ID that no longer exists,
particularly XGetWindowAttributes, in conjunction the unknown error
handler set in case #1 would cause the program to outright crash because
that error handler is programmed to crash on BadWindow for whatever
reason. The source would call X functions without even checking if
'win' was 0.
3.) The source stored window IDs (in JSON, even if they've long since
become invalid/pointless, such as system restarts). This is a bad
practice and will result in more cases of BadWindow.
Fixing the problem (reducing the possibility of getting BadWindow):
-------------------------------
Step 1.) Deprecate and ignore window IDs in stored settings. Instead of
using window IDs to find the window, we now must always search the
windows and find the target window via the window name exclusively.
This helps ensure that we actually consistently have a working window
ID.
Step 2.) Do not call any X functions if the window ID is 0.
Step 3.) Reset the window ID to 0 any time the window has updated, and
make the source find the window again to ensure it still exists before
attempting to use any X functions on the window ID again.
2016-06-04 14:20:41 -07:00
|
|
|
if (!p->win)
|
|
|
|
return 0;
|
|
|
|
|
2014-04-29 02:59:53 +02:00
|
|
|
return p->width - p->cur_cut_left - p->cur_cut_right;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t XCompcapMain::height()
|
|
|
|
{
|
linux-capture: Fix window capture crashes
The xcomposite window capture crashes were due to a few factors:
-------------------------------
1.) The source's X error handler was possibly being overwritten by
another part of the program despite us locking the display, presumably
something in Qt which isn't locking the display when pushing/popping its
own error handler (though this is not yet certain). The source's calls
to X functions happen in the graphics thread, which is separate from the
UI thread, and it was noticed that somehow the error handler would be
overwritten almost seemingly at random, indicating that something else
in the program outside of OBS code was not locking the display while
pushing/popping the error handler.
To replicate this, make it so that the source cannot find the target
window and so it continually searches for it each video_tick call, then
resize the main OBS window continually (which causes Qt to push/pop its
own error handlers). A crash will almost always occur due to BadWindow
despite our error handling.
2.) Calling X functions with a window ID that no longer exists,
particularly XGetWindowAttributes, in conjunction the unknown error
handler set in case #1 would cause the program to outright crash because
that error handler is programmed to crash on BadWindow for whatever
reason. The source would call X functions without even checking if
'win' was 0.
3.) The source stored window IDs (in JSON, even if they've long since
become invalid/pointless, such as system restarts). This is a bad
practice and will result in more cases of BadWindow.
Fixing the problem (reducing the possibility of getting BadWindow):
-------------------------------
Step 1.) Deprecate and ignore window IDs in stored settings. Instead of
using window IDs to find the window, we now must always search the
windows and find the target window via the window name exclusively.
This helps ensure that we actually consistently have a working window
ID.
Step 2.) Do not call any X functions if the window ID is 0.
Step 3.) Reset the window ID to 0 any time the window has updated, and
make the source find the window again to ensure it still exists before
attempting to use any X functions on the window ID again.
2016-06-04 14:20:41 -07:00
|
|
|
if (!p->win)
|
|
|
|
return 0;
|
|
|
|
|
2014-04-29 02:59:53 +02:00
|
|
|
return p->height - p->cur_cut_bot - p->cur_cut_top;
|
|
|
|
}
|