Kaynağa Gözat

Merge pull request #15 from computerquip/master

GLX Implementation along with appropriate autotools changes
Jim 12 yıl önce
ebeveyn
işleme
980083c58d

+ 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