Преглед изворни кода

GLX implementation and *nix-specific file handling implementation

I added gl-x11 which allows compatibility with X11 (Xlib-based) and GLX.
I also added various functions to handle file finding based on FHS.
Various changes to autotools to both install files correctly and to configure correctly.
Zachary Lund пре 11 година
родитељ
комит
80b8176e29

+ 5 - 0
build/makefile.am

@@ -1,10 +1,15 @@
 obs_plugin_datadir = $(datadir)/obs-plugins
 obs_plugin_data_testdir = $(obs_plugin_datadir)/test-input
 data_libobsdir = $(datadir)/libobs
+obs_localedir = $(datadir)/obs-studio/locale
+
 
 obs_plugin_data_test_DATA = data/obs-plugins/test-input/draw.effect \
 			    data/obs-plugins/test-input/test.effect
 data_libobs_DATA = data/libobs/default.effect
+obs_locale_DATA = data/obs-studio/locale/en.txt \
+	data/obs-studio/locale/ja.txt \
+	data/obs-studio/locale/locale.ini 
 
 #uninstall-local:
 #	rm -r $(DESTDIR)$(obs_plugin_datadir)

+ 5 - 2
configure.ac

@@ -55,6 +55,8 @@ case $host_os in
 		AM_CONDITIONAL([OS_OSX], false)
 		AM_CONDITIONAL([OS_NIX], true)
 		PKG_CHECK_MODULES([X11], [x11])
+		PKG_CHECK_MODULES([XINERAMA], [xinerama])
+		PKG_CHECK_MODULES([GTK], [gtk+-x11-2.0])
 		;;
 esac
 
@@ -66,12 +68,13 @@ AC_CHECK_HEADER([libavutil/channel_layout.h], , AC_MSG_ERROR([libavutil header n
 AC_CHECK_HEADER([libswscale/swscale.h], , AC_MSG_ERROR([libswscale header not found]))
 AC_CHECK_HEADER([libswresample/swresample.h], , AC_MSG_ERROR([libswresample header not found]))
 
-AC_CHECK_LIB([avcodec], [avcodec_find_encoder_by_name], , AC_MSG_ERROR([libavcodec not found]), )
+AC_CHECK_LIB([avcodec], [avcodec_find_encoder_by_name], , AC_MSG_ERROR([libavcodec not found]))
 AC_CHECK_LIB([avformat], [av_guess_format], , AC_MSG_ERROR([libavformat not found]))
 AC_CHECK_LIB([avutil], [av_samples_alloc], , AC_MSG_ERROR([libavutil not found]))
 AC_CHECK_LIB([swscale], [sws_scale], , AC_MSG_ERROR([libswscale not found]))
 AC_CHECK_LIB([swresample], [swr_convert], , AC_MSG_ERROR([libswresample not found]))
 
+# checks for jansson
 AC_CHECK_HEADER([jansson.h], , AC_MSG_ERROR([libjansson header not found]))
 AC_CHECK_LIB([jansson], [json_load_file], , AC_MSG_ERROR([libjansson not found]))
 
@@ -92,7 +95,7 @@ WX_CONFIG_CHECK(
 
 CPPFLAGS="$CPPFLAGS $WX_CPPFLAGS"
 CXXFLAGS="$CXXFLAGS $WX_CXXFLAGS_ONLY"
-CFLAGS="$CFLAGS $WX_CFLAGS_ONLY"
+CFLAGS="$CFLAGS $WX_CFLAGS_ONLY  "
 LIBS="$LIBS $WX_LIBS"
 
 # Checks for header files.

+ 251 - 0
libobs-opengl/gl-x11.c

@@ -0,0 +1,251 @@
+#include <X11/Xlib.h>
+
+#include <stdio.h>
+
+#include "gl-subsystem.h"
+
+#include <GL/glx.h>
+#include <GL/glxext.h>
+	
+static PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB;
+	
+static const GLenum fb_attribs[] = {
+	/* Hardcoded for now... */
+	GLX_STENCIL_SIZE, 8,
+	GLX_DEPTH_SIZE, 24, 
+	GLX_BUFFER_SIZE, 32, /* Color buffer depth */
+	GLX_DOUBLEBUFFER, True,
+	None
+};
+
+static const GLenum ctx_attribs[] = {
+	GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
+	GLX_CONTEXT_MINOR_VERSION_ARB, 2,
+	GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_DEBUG_BIT_ARB |
+	                       GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB,
+	GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
+	0, 0
+};
+
+static const char* __GLX_error_table[] = {
+	"Success",
+	"Bad Screen",
+	"Bad Attribute",
+	"No Extension",
+	"Bad Visual",
+	"Bad Content",
+	"Bad Value",
+	"Bad Enumeration"
+};
+
+#define GET_GLX_ERROR(x) \
+	__GLX_error_table[x]
+
+struct gl_windowinfo {
+	uint32_t id;
+	Display *display;
+};
+	
+struct gl_platform {
+	GLXContext context;
+	struct gs_swap_chain swap;
+};
+
+static int GLXErrorHandler(Display *disp, XErrorEvent *error)
+{
+	blog(LOG_ERROR, "GLX error: %s\n", GET_GLX_ERROR(error->error_code));
+	return 0;
+}
+
+extern struct gs_swap_chain *gl_platform_getswap(struct gl_platform *platform) 
+{
+	return &platform->swap;
+}
+
+extern struct gl_windowinfo *gl_windowinfo_create(struct gs_init_data *info) 
+{
+	struct gl_windowinfo *wi = bmalloc(sizeof(struct gl_windowinfo));
+	memset(wi, 0, sizeof(struct gl_windowinfo));
+	
+	wi->id = info->window.id;
+	
+	return wi;
+}
+
+extern void gl_windowinfo_destroy(struct gl_windowinfo *wi) 
+{
+	blog(LOG_DEBUG, "%s called.", __FUNCTION__);
+	bfree(wi);
+}
+
+extern void gl_getclientsize(struct gs_swap_chain *swap,
+			     uint32_t *width, uint32_t *height) 
+{
+	XWindowAttributes info = { 0 };
+	
+	XGetWindowAttributes(swap->wi->display, swap->wi->id, &info);
+	
+	*height = info.height;
+	*width = info.width;
+}
+
+static void print_info_stuff(struct gs_init_data *info)
+{
+	blog(	LOG_DEBUG,
+		"X and Y: %i %i\n"
+		"Backbuffers: %i\n"
+		"Color Format: %i\n"
+		"ZStencil Format: %i\n"
+		"Adapter: %i\n",
+		info->cx, info->cy, 
+		info->num_backbuffers,
+		info->format, info->zsformat, 
+		info->adapter
+	);
+}
+
+struct gl_platform *gl_platform_create(device_t device,
+		struct gs_init_data *info)
+{	
+	/* X11 */
+	int num_configs = 0;
+	int error_base = 0, event_base = 0;
+	Display *display = XOpenDisplay(NULL); /* Open default screen */
+	
+	/* OBS */
+	struct gl_platform *plat = bmalloc(sizeof(struct gl_platform));
+	
+	/* GLX */
+	GLXFBConfig* configs;
+	
+	print_info_stuff(info);
+	
+	if (!plat) { 
+		blog(LOG_ERROR, "Out of memory");
+		return NULL;
+	}
+	
+	memset(plat, 0, sizeof(struct gl_platform));
+	
+	if (!display) {
+		blog(LOG_ERROR, "Unable to find display. DISPLAY variable may not be set correctly.");
+		goto fail0;
+	}
+	
+	
+	if (!glXQueryExtension(display, &error_base, &event_base)) {
+		blog(LOG_ERROR, "GLX not supported.");
+		goto fail0;
+	}
+	
+	XSetErrorHandler(GLXErrorHandler);
+	
+	glXCreateContextAttribsARB = (PFNGLXCREATECONTEXTATTRIBSARBPROC)glXGetProcAddress("glXCreateContextAttribsARB");
+	if (!glXCreateContextAttribsARB) {
+		blog(LOG_ERROR, "ARB_GLX_create_context not supported!");
+		goto fail0;
+	}
+	
+	configs = glXChooseFBConfig(display, DefaultScreen(display), fb_attribs, &num_configs);
+
+	if(!configs) {
+		blog(LOG_ERROR, "Attribute list or screen is invalid.");
+		goto fail0;
+	}
+	
+	if(num_configs == 0) {
+		blog(LOG_ERROR, "No framebuffer configurations found.");
+		goto fail1;
+	}
+	
+	/* We just use the first configuration found... as it does everything we want at the very least. */
+	plat->context = glXCreateContextAttribsARB(display, configs[0], NULL, True, ctx_attribs);
+	if(!plat->context) { 
+		blog(LOG_ERROR, "Failed to create OpenGL context.");
+		goto fail1;
+	}
+	
+	if(!glXMakeCurrent(display, info->window.id, plat->context)) {
+		blog(LOG_ERROR, "Failed to make context current.");
+		goto fail2;
+	}
+
+	blog(LOG_INFO, "OpenGL version: %s\n", glGetString(GL_VERSION));
+
+	/* Initialize GLEW */
+	{
+		GLenum err = glewInit();
+		if (GLEW_OK != err) {
+			blog(LOG_ERROR, glewGetErrorString(err));
+			goto fail2;
+		}
+	}
+	
+	glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
+	glEnable(GL_DEBUG_OUTPUT);
+	glEnable(GL_CULL_FACE);
+	
+	plat->swap.device = device;
+	plat->swap.info	  = *info;
+	plat->swap.wi     = gl_windowinfo_create(info);
+	plat->swap.wi->display = display;
+	
+	XFree(configs);
+	XSync(display, False);
+	
+	return plat;
+	
+fail2:
+	glXDestroyContext(display, plat->context);
+fail1: 
+	XFree(configs);
+fail0:
+	bfree(plat);
+	return NULL;
+}
+
+extern void gl_platform_destroy(struct gl_platform *platform) 
+{
+	blog(LOG_DEBUG, "%s called.", __FUNCTION__);
+	glXMakeCurrent(platform->swap.wi->display, None, NULL);
+	glXDestroyContext(platform->swap.wi->display, platform->context);
+	XCloseDisplay(platform->swap.wi->display);
+	bfree(platform);
+}
+
+void device_entercontext(device_t device) 
+{
+	GLXContext context = device->plat->context;
+	XID window = device->plat->swap.wi->id;
+	Display *display = device->plat->swap.wi->display;
+	
+	if (device->cur_swap)
+		 device->plat->swap.wi->id = device->cur_swap->wi->id;
+	
+	if (!glXMakeCurrent(display, window, context)) {
+		blog(LOG_ERROR, "Failed to make context current.");
+	}
+}
+void device_leavecontext(device_t device) 
+{
+	Display *display = device->plat->swap.wi->display;
+	
+	if(!glXMakeCurrent(display, None, NULL)) { 
+		blog(LOG_ERROR, "Failed to reset current context.");
+	}
+}
+void device_load_swapchain(device_t device, swapchain_t swap) 
+{
+	if(!swap)
+		swap = &device->plat->swap;
+	
+	device->cur_swap = swap;
+}
+
+void device_present(device_t device) 
+{
+	Display *display = device->plat->swap.wi->display;
+	XID window = device->plat->swap.wi->id;
+	
+	glXSwapBuffers(display, window);
+}

+ 4 - 0
libobs-opengl/makefile.am

@@ -39,3 +39,7 @@ endif
 if OS_WIN
 libobs_opengl_la_SOURCES += gl-windows.c
 endif
+
+if OS_NIX
+libobs_opengl_la_SOURCES += gl-x11.c
+endif

+ 2 - 3
libobs/graphics/graphics.h

@@ -414,9 +414,8 @@ struct gs_window {
 	void                    *hwnd;
 #elif defined(__APPLE__)
 	__unsafe_unretained id  view;
-#elif defined(__posix__)
-	int bla;
-	/* TODO */
+#elif defined(__linux__)
+	uint32_t id;
 #endif
 };
 

+ 60 - 7
libobs/obs-nix.c

@@ -16,17 +16,52 @@
 ******************************************************************************/
 
 #include <stdlib.h>
-
+#include <stdio.h>
+#include <unistd.h>
 #include "util/dstr.h"
 #include "obs.h"
 
+static inline bool check_path(const char* data, const char *path, struct dstr * output)
+{
+	dstr_copy(output, path);
+	dstr_cat(output, data);
+	
+    blog(LOG_INFO, "Attempting path: %s\n", output->array);
+	
+	return access(output->array, R_OK) == 0;
+}
+
+static inline bool check_lib_path(const char* data, const char *path, struct dstr *output)
+{
+	bool result = false;
+	struct dstr tmp;
+	
+    dstr_init_copy(&tmp, "lib");
+    dstr_cat(&tmp, data);
+	dstr_cat(&tmp, ".so");
+	result = check_path(tmp.array, path, output); 
+	
+	dstr_free(&tmp);
+	
+	return result;
+}
+
 /*
  *   /usr/local/lib/obs-plugins
  *   /usr/lib/obs-plugins
  */
 char *find_plugin(const char *plugin)
-{
-	/* TODO */
+{ 
+	struct dstr output;
+	dstr_init(&output);
+
+	if (check_lib_path(plugin, "/usr/local/lib/obs-plugins/", &output))
+		return output.array;
+
+	if (check_lib_path(plugin, "/usr/lib/obs-plugins/", &output))
+		return output.array;
+
+	dstr_free(&output);
 	return NULL;
 }
 
@@ -36,7 +71,16 @@ char *find_plugin(const char *plugin)
  */
 char *find_libobs_data_file(const char *file)
 {
-	/* TODO */
+	struct dstr output;
+		dstr_init(&output);
+
+	if (check_path(file, "/usr/local/share/libobs/", &output))
+		return output.array;
+
+	if (check_path(file, "/usr/share/libobs/", &output))
+		return output.array;
+
+	dstr_free(&output);
 	return NULL;
 }
 
@@ -45,7 +89,16 @@ char *find_libobs_data_file(const char *file)
  *   /usr/share/obs-plugins
  */
 char *obs_find_plugin_file(const char *file)
-{
-	/* TODO */
-	return NULL;
+{ 	
+    struct dstr output;
+    dstr_init(&output);
+
+    if (check_path(file, "/usr/local/share/obs-plugins/", &output))
+        return output.array;
+
+    if (check_path(file, "/usr/share/obs-plugins", &output))
+        return output.array;
+
+    dstr_free(&output);
+    return NULL;
 }

+ 1 - 4
makefile.am

@@ -1,7 +1,4 @@
 ACLOCAL_AMFLAGS = -I m4
 EXTRA_DIST = autogen.sh COPYING README
-SUBDIRS = libobs libobs-opengl test obs
+SUBDIRS = libobs libobs-opengl test obs build
 
-if OS_WIN
-SUBDIRS += build
-endif

+ 2 - 0
obs/makefile.am

@@ -33,5 +33,7 @@ obs_SOURCES += platform-osx.mm
 endif
 
 if OS_NIX
+obs_CPPFLAGS = $(AM_CPPFLAGS) $(GTK_CFLAGS) $(X11_CFLAGS) $(XINERAMA_CFLAGS)
 obs_SOURCES += platform-x11.cpp
+obs_LDADD += $(GTK_LIBS) $(X11_LIBS) $(XINERAMA_LIBS)
 endif

+ 62 - 3
obs/platform-x11.cpp

@@ -14,19 +14,78 @@
     You should have received a copy of the GNU General Public License
     along with this program.  If not, see <http://www.gnu.org/licenses/>.
 ******************************************************************************/
-
+/* Here we use xinerama to fetch data about monitor geometry
+ * Even if there are not multiple monitors, this should still work. 
+ */
+#include <X11/Xlib.h>
+#include <X11/extensions/Xinerama.h>
+#include <unistd.h>
 #include <sstream>
+
 #include "platform.hpp"
 using namespace std;
 
+static inline bool check_path(const char* data, const char *path, string &output)
+{
+	ostringstream str;
+	str << "/usr/local/share/obs-studio/" << data;
+	output = str.str();
+		
+	printf("Attempted path: %s\n", output.c_str());
+		
+	return (access(output.c_str(), R_OK) == 0);
+}
+
 bool GetDataFilePath(const char *data, string &output)
 {
-	// TODO
+	char *data_path = getenv("OBS_DATA_PATH");
+	if (data_path != NULL) {
+		if (check_path(data, data_path, output))
+			return true;
+	}
+	
+	if (check_path(data, "/usr/local/share/obs-studio/", output))
+		return true;
+	
+	if (check_path(data, "/usr/share/obs-studio/", output))
+		return true;
+	
 	return false;
 }
 
 void GetMonitors(vector<MonitorInfo> &monitors)
 {
+	int num_screens;
+	XineramaScreenInfo *screens;
+	int event_code = 0, error_code = 0;
+	Display* display = XOpenDisplay(NULL);
+	
+	if (!XineramaQueryExtension(display, &event_code, &error_code)) {
+		printf("Xinerama extension unavailable. We don't handle this yet.\n");
+		return;
+	}
+	
+	/* Do I need to make a call to XineramaQueryVersion...? */
+	
+	screens = XineramaQueryScreens(display, &num_screens);
+	
+	if (num_screens == 0 || !screens) { 
+		printf("Xinerama isn't active on this screen.\n");
+		return;
+	}
+	
 	monitors.clear();
-	// TODO
+	
+	do {
+		--num_screens;
+		
+		monitors.emplace_back(
+			screens[num_screens].x_org, 
+			screens[num_screens].y_org,
+			screens[num_screens].width,
+			screens[num_screens].height
+                );
+	} while (num_screens > 0);
+	
+	XCloseDisplay(display);
 }

+ 9 - 1
obs/wx-wrappers.cpp

@@ -23,6 +23,14 @@
 #include <memory>
 using namespace std;
 
+#ifdef __linux__
+#include <gdk/gdkx.h>
+#include <gtk/gtk.h>
+#endif
+
+#include <memory>
+using namespace std;
+
 gs_window WxToGSWindow(const wxWindow *wxwin)
 {
 	gs_window window;
@@ -31,7 +39,7 @@ gs_window WxToGSWindow(const wxWindow *wxwin)
 #elif _WIN32
 	window.hwnd     = wxwin->GetHandle();
 #else
-	/* TODO: linux stuff */
+	window.id 	= gdk_x11_drawable_get_xid(gtk_widget_get_window(wxwin->GetHandle()));
 #endif
 	return window;
 }

+ 1 - 1
test/test-input/makefile.am

@@ -10,7 +10,7 @@ else
 libtestdir = $(libdir)/obs-plugins
 endif
 
-pkglib_LTLIBRARIES = libtest-input.la
+libtest_LTLIBRARIES = libtest-input.la
 
 libtest_input_la_LDFLAGS = -no-undefined
 if OS_WIN