瀏覽代碼

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
共有 11 個文件被更改,包括 402 次插入21 次删除
  1. 5 0
      build/makefile.am
  2. 5 2
      configure.ac
  3. 251 0
      libobs-opengl/gl-x11.c
  4. 4 0
      libobs-opengl/makefile.am
  5. 2 3
      libobs/graphics/graphics.h
  6. 60 7
      libobs/obs-nix.c
  7. 1 4
      makefile.am
  8. 2 0
      obs/makefile.am
  9. 62 3
      obs/platform-x11.cpp
  10. 9 1
      obs/wx-wrappers.cpp
  11. 1 1
      test/test-input/makefile.am

+ 5 - 0
build/makefile.am

@@ -1,10 +1,15 @@
 obs_plugin_datadir = $(datadir)/obs-plugins
 obs_plugin_datadir = $(datadir)/obs-plugins
 obs_plugin_data_testdir = $(obs_plugin_datadir)/test-input
 obs_plugin_data_testdir = $(obs_plugin_datadir)/test-input
 data_libobsdir = $(datadir)/libobs
 data_libobsdir = $(datadir)/libobs
+obs_localedir = $(datadir)/obs-studio/locale
+
 
 
 obs_plugin_data_test_DATA = data/obs-plugins/test-input/draw.effect \
 obs_plugin_data_test_DATA = data/obs-plugins/test-input/draw.effect \
 			    data/obs-plugins/test-input/test.effect
 			    data/obs-plugins/test-input/test.effect
 data_libobs_DATA = data/libobs/default.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:
 #uninstall-local:
 #	rm -r $(DESTDIR)$(obs_plugin_datadir)
 #	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_OSX], false)
 		AM_CONDITIONAL([OS_NIX], true)
 		AM_CONDITIONAL([OS_NIX], true)
 		PKG_CHECK_MODULES([X11], [x11])
 		PKG_CHECK_MODULES([X11], [x11])
+		PKG_CHECK_MODULES([XINERAMA], [xinerama])
+		PKG_CHECK_MODULES([GTK], [gtk+-x11-2.0])
 		;;
 		;;
 esac
 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([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_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([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([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([swscale], [sws_scale], , AC_MSG_ERROR([libswscale not found]))
 AC_CHECK_LIB([swresample], [swr_convert], , AC_MSG_ERROR([libswresample 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_HEADER([jansson.h], , AC_MSG_ERROR([libjansson header not found]))
 AC_CHECK_LIB([jansson], [json_load_file], , AC_MSG_ERROR([libjansson 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"
 CPPFLAGS="$CPPFLAGS $WX_CPPFLAGS"
 CXXFLAGS="$CXXFLAGS $WX_CXXFLAGS_ONLY"
 CXXFLAGS="$CXXFLAGS $WX_CXXFLAGS_ONLY"
-CFLAGS="$CFLAGS $WX_CFLAGS_ONLY"
+CFLAGS="$CFLAGS $WX_CFLAGS_ONLY  "
 LIBS="$LIBS $WX_LIBS"
 LIBS="$LIBS $WX_LIBS"
 
 
 # Checks for header files.
 # 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
 if OS_WIN
 libobs_opengl_la_SOURCES += gl-windows.c
 libobs_opengl_la_SOURCES += gl-windows.c
 endif
 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;
 	void                    *hwnd;
 #elif defined(__APPLE__)
 #elif defined(__APPLE__)
 	__unsafe_unretained id  view;
 	__unsafe_unretained id  view;
-#elif defined(__posix__)
-	int bla;
-	/* TODO */
+#elif defined(__linux__)
+	uint32_t id;
 #endif
 #endif
 };
 };
 
 

+ 60 - 7
libobs/obs-nix.c

@@ -16,17 +16,52 @@
 ******************************************************************************/
 ******************************************************************************/
 
 
 #include <stdlib.h>
 #include <stdlib.h>
-
+#include <stdio.h>
+#include <unistd.h>
 #include "util/dstr.h"
 #include "util/dstr.h"
 #include "obs.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/local/lib/obs-plugins
  *   /usr/lib/obs-plugins
  *   /usr/lib/obs-plugins
  */
  */
 char *find_plugin(const char *plugin)
 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;
 	return NULL;
 }
 }
 
 
@@ -36,7 +71,16 @@ char *find_plugin(const char *plugin)
  */
  */
 char *find_libobs_data_file(const char *file)
 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;
 	return NULL;
 }
 }
 
 
@@ -45,7 +89,16 @@ char *find_libobs_data_file(const char *file)
  *   /usr/share/obs-plugins
  *   /usr/share/obs-plugins
  */
  */
 char *obs_find_plugin_file(const char *file)
 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
 ACLOCAL_AMFLAGS = -I m4
 EXTRA_DIST = autogen.sh COPYING README
 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
 endif
 
 
 if OS_NIX
 if OS_NIX
+obs_CPPFLAGS = $(AM_CPPFLAGS) $(GTK_CFLAGS) $(X11_CFLAGS) $(XINERAMA_CFLAGS)
 obs_SOURCES += platform-x11.cpp
 obs_SOURCES += platform-x11.cpp
+obs_LDADD += $(GTK_LIBS) $(X11_LIBS) $(XINERAMA_LIBS)
 endif
 endif

+ 62 - 3
obs/platform-x11.cpp

@@ -14,19 +14,78 @@
     You should have received a copy of the GNU General Public License
     You should have received a copy of the GNU General Public License
     along with this program.  If not, see <http://www.gnu.org/licenses/>.
     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 <sstream>
+
 #include "platform.hpp"
 #include "platform.hpp"
 using namespace std;
 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)
 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;
 	return false;
 }
 }
 
 
 void GetMonitors(vector<MonitorInfo> &monitors)
 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();
 	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>
 #include <memory>
 using namespace std;
 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 WxToGSWindow(const wxWindow *wxwin)
 {
 {
 	gs_window window;
 	gs_window window;
@@ -31,7 +39,7 @@ gs_window WxToGSWindow(const wxWindow *wxwin)
 #elif _WIN32
 #elif _WIN32
 	window.hwnd     = wxwin->GetHandle();
 	window.hwnd     = wxwin->GetHandle();
 #else
 #else
-	/* TODO: linux stuff */
+	window.id 	= gdk_x11_drawable_get_xid(gtk_widget_get_window(wxwin->GetHandle()));
 #endif
 #endif
 	return window;
 	return window;
 }
 }

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

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