aboutsummaryrefslogtreecommitdiffhomepage
path: root/tools/viewer/sk_app/unix
diff options
context:
space:
mode:
authorGravatar jvanverth <jvanverth@google.com>2016-05-23 13:13:36 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2016-05-23 13:13:36 -0700
commit1d1559620058365e0de25636f1bcf07fcc071c3d (patch)
treeaa9cae557fade884de8c1a5359dc0624cd44a288 /tools/viewer/sk_app/unix
parent50134ccafdc509d4d430d068d7e68e38473ffe0a (diff)
Add Xlib support to viewer
Diffstat (limited to 'tools/viewer/sk_app/unix')
-rw-r--r--tools/viewer/sk_app/unix/VulkanWindowContext_unix.cpp74
-rw-r--r--tools/viewer/sk_app/unix/Window_unix.cpp221
-rw-r--r--tools/viewer/sk_app/unix/Window_unix.h86
-rw-r--r--tools/viewer/sk_app/unix/main_unix.cpp90
4 files changed, 471 insertions, 0 deletions
diff --git a/tools/viewer/sk_app/unix/VulkanWindowContext_unix.cpp b/tools/viewer/sk_app/unix/VulkanWindowContext_unix.cpp
new file mode 100644
index 0000000000..ddfc8e3068
--- /dev/null
+++ b/tools/viewer/sk_app/unix/VulkanWindowContext_unix.cpp
@@ -0,0 +1,74 @@
+
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "../VulkanWindowContext.h"
+#include "Window_unix.h"
+
+#include "vk/GrVkInterface.h"
+#include "vk/GrVkUtil.h"
+
+#include <X11/Xlib-xcb.h>
+
+namespace sk_app {
+
+// Platform dependant call
+VkSurfaceKHR VulkanWindowContext::createVkSurface(VkInstance instance, void* platformData) {
+ static PFN_vkCreateXcbSurfaceKHR createXcbSurfaceKHR = nullptr;
+ if (!createXcbSurfaceKHR) {
+ createXcbSurfaceKHR = (PFN_vkCreateXcbSurfaceKHR) vkGetInstanceProcAddr(instance,
+ "vkCreateXcbSurfaceKHR");
+ }
+
+ if (!platformData) {
+ return VK_NULL_HANDLE;
+ }
+ ContextPlatformData_unix* unixPlatformData =
+ reinterpret_cast<ContextPlatformData_unix*>(platformData);
+
+
+ VkSurfaceKHR surface;
+
+ VkXcbSurfaceCreateInfoKHR surfaceCreateInfo;
+ memset(&surfaceCreateInfo, 0, sizeof(VkXcbSurfaceCreateInfoKHR));
+ surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR;
+ surfaceCreateInfo.pNext = nullptr;
+ surfaceCreateInfo.flags = 0;
+ surfaceCreateInfo.connection = XGetXCBConnection(unixPlatformData->fDisplay);
+ surfaceCreateInfo.window = unixPlatformData->fHWnd;
+
+ VkResult res = createXcbSurfaceKHR(instance, &surfaceCreateInfo, nullptr, &surface);
+ if (VK_SUCCESS != res) {
+ return VK_NULL_HANDLE;
+ }
+
+ return surface;
+}
+
+// Platform dependant call
+bool VulkanWindowContext::canPresent(VkInstance instance, VkPhysicalDevice physDev,
+ uint32_t queueFamilyIndex, void* platformData) {
+ static PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR
+ getPhysicalDeviceXcbPresentationSupportKHR = nullptr;
+ if (!getPhysicalDeviceXcbPresentationSupportKHR) {
+ getPhysicalDeviceXcbPresentationSupportKHR =
+ (PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR) vkGetInstanceProcAddr(instance,
+ "vkGetPhysicalDeviceXcbPresentationSupportKHR");
+ }
+
+ ContextPlatformData_unix* unixPlatformData =
+ reinterpret_cast<ContextPlatformData_unix*>(platformData);
+
+ Display* display = unixPlatformData->fDisplay;
+ VkBool32 check = getPhysicalDeviceXcbPresentationSupportKHR(physDev,
+ queueFamilyIndex,
+ XGetXCBConnection(display),
+ unixPlatformData->fVisualID);
+ return (VK_FALSE != check);
+}
+
+} // namespace sk_app
diff --git a/tools/viewer/sk_app/unix/Window_unix.cpp b/tools/viewer/sk_app/unix/Window_unix.cpp
new file mode 100644
index 0000000000..953eb36d74
--- /dev/null
+++ b/tools/viewer/sk_app/unix/Window_unix.cpp
@@ -0,0 +1,221 @@
+/*
+* Copyright 2016 Google Inc.
+*
+* Use of this source code is governed by a BSD-style license that can be
+* found in the LICENSE file.
+*/
+
+//#include <tchar.h>
+
+#include "SkUtils.h"
+#include "Timer.h"
+#include "../VulkanWindowContext.h"
+#include "Window_unix.h"
+
+extern "C" {
+ #include "keysym2ucs.h"
+}
+#include <X11/Xutil.h>
+#include <X11/XKBlib.h>
+
+namespace sk_app {
+
+SkTDynamicHash<Window_unix, XWindow> Window_unix::gWindowMap;
+
+Window* Window::CreateNativeWindow(void* platformData) {
+ Display* display = (Display*)platformData;
+
+ Window_unix* window = new Window_unix();
+ if (!window->init(display)) {
+ delete window;
+ return nullptr;
+ }
+
+ return window;
+}
+
+bool Window_unix::init(Display* display) {
+ fDisplay = display;
+
+ fWidth = 1280;
+ fHeight = 960;
+ fHWnd = XCreateSimpleWindow(display, DefaultRootWindow(display), 0, 0, fWidth, fHeight,
+ 0, BlackPixel(display, DefaultScreen(display)),
+ BlackPixel(display, DefaultScreen(display)));
+
+ if (!fHWnd) {
+ return false;
+ }
+
+ // choose the events we care about
+ XSelectInput(display, fHWnd,
+ ExposureMask | StructureNotifyMask | KeyPressMask | KeyReleaseMask |
+ PointerMotionMask | ButtonPressMask | ButtonReleaseMask);
+
+ // set up to catch window delete message
+ fWmDeleteMessage = XInternAtom(display, "WM_DELETE_WINDOW", False);
+ XSetWMProtocols(display, fHWnd, &fWmDeleteMessage, 1);
+
+ // add to hashtable of windows
+ gWindowMap.add(this);
+
+ // init event variables
+ fPendingPaint = false;
+ fPendingResize = false;
+
+ return true;
+}
+
+static Window::Key get_key(KeySym keysym) {
+ static const struct {
+ KeySym fXK;
+ Window::Key fKey;
+ } gPair[] = {
+ { XK_BackSpace, Window::Key::kBack },
+ { XK_Clear, Window::Key::kBack },
+ { XK_Return, Window::Key::kOK },
+ { XK_Up, Window::Key::kUp },
+ { XK_Down, Window::Key::kDown },
+ { XK_Left, Window::Key::kLeft },
+ { XK_Right, Window::Key::kRight }
+ };
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gPair); i++) {
+ if (gPair[i].fXK == keysym) {
+ return gPair[i].fKey;
+ }
+ }
+ return Window::Key::kNONE;
+}
+
+static uint32_t get_modifiers(const XEvent& event) {
+ static const struct {
+ unsigned fXMask;
+ unsigned fSkMask;
+ } gModifiers[] = {
+ { ShiftMask, Window::kShift_ModifierKey },
+ { ControlMask, Window::kControl_ModifierKey },
+ { Mod1Mask, Window::kOption_ModifierKey },
+ };
+
+ auto modifiers = 0;
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gModifiers); ++i) {
+ if (event.xkey.state & gModifiers[i].fXMask) {
+ modifiers |= gModifiers[i].fSkMask;
+ }
+ }
+ return modifiers;
+}
+
+bool Window_unix::handleEvent(const XEvent& event) {
+ switch (event.type) {
+ case ClientMessage:
+ if ((Atom)event.xclient.data.l[0] == fWmDeleteMessage &&
+ gWindowMap.count() == 1) {
+ return true;
+ }
+ break;
+
+ case ButtonPress:
+ if (event.xbutton.button == Button1) {
+ this->onMouse(event.xbutton.x, event.xbutton.y,
+ Window::kDown_InputState, get_modifiers(event));
+ }
+ break;
+
+ case ButtonRelease:
+ if (event.xbutton.button == Button1) {
+ this->onMouse(event.xbutton.x, event.xbutton.y,
+ Window::kUp_InputState, get_modifiers(event));
+ }
+ break;
+
+ case MotionNotify:
+ // only track if left button is down
+ if (event.xmotion.state & Button1Mask) {
+ this->onMouse(event.xmotion.x, event.xmotion.y,
+ Window::kMove_InputState, get_modifiers(event));
+ }
+ break;
+
+ case KeyPress: {
+ int shiftLevel = (event.xkey.state & ShiftMask) ? 1 : 0;
+ KeySym keysym = XkbKeycodeToKeysym(fDisplay, event.xkey.keycode,
+ 0, shiftLevel);
+ if (keysym == XK_Escape) {
+ return true;
+ }
+ Window::Key key = get_key(keysym);
+ if (key != Window::Key::kNONE) {
+ (void) this->onKey(key, Window::kDown_InputState,
+ get_modifiers(event));
+ } else {
+ long uni = keysym2ucs(keysym);
+ if (uni != -1) {
+ (void) this->onChar((SkUnichar) uni,
+ get_modifiers(event));
+ }
+ }
+ } break;
+
+ case KeyRelease: {
+ int shiftLevel = (event.xkey.state & ShiftMask) ? 1 : 0;
+ KeySym keysym = XkbKeycodeToKeysym(fDisplay, event.xkey.keycode,
+ 0, shiftLevel);
+ Window::Key key = get_key(keysym);
+ (void) this->onKey(key, Window::kUp_InputState,
+ get_modifiers(event));
+ } break;
+
+
+ default:
+ // these events should be handled in the main event loop
+ SkASSERT(event.type != Expose && event.type != ConfigureNotify);
+ break;
+ }
+
+ return false;
+}
+
+void Window_unix::setTitle(const char* title) {
+ XTextProperty textproperty;
+ XStringListToTextProperty(const_cast<char**>(&title), 1, &textproperty);
+ XSetWMName(fDisplay, fHWnd, &textproperty);
+}
+
+void Window_unix::show() {
+ XMapWindow(fDisplay, fHWnd);
+}
+
+bool Window_unix::attach(BackendType attachType, const DisplayParams& params) {
+ ContextPlatformData_unix platformData;
+ platformData.fDisplay = fDisplay;
+ platformData.fHWnd = fHWnd;
+ XWindowAttributes attribs;
+ XGetWindowAttributes(fDisplay, fHWnd, &attribs);
+ platformData.fVisualID = XVisualIDFromVisual(attribs.visual);
+ switch (attachType) {
+ case kVulkan_BackendType:
+ default:
+ fWindowContext = VulkanWindowContext::Create((void*)&platformData, params);
+ break;
+ }
+
+ return (SkToBool(fWindowContext));
+}
+
+void Window_unix::onInval() {
+ XEvent event;
+ event.type = Expose;
+ event.xexpose.send_event = True;
+ event.xexpose.display = fDisplay;
+ event.xexpose.window = fHWnd;
+ event.xexpose.x = 0;
+ event.xexpose.y = 0;
+ event.xexpose.width = fWidth;
+ event.xexpose.height = fHeight;
+ event.xexpose.count = 0;
+
+ XSendEvent(fDisplay, fHWnd, False, 0, &event);
+}
+
+} // namespace sk_app
diff --git a/tools/viewer/sk_app/unix/Window_unix.h b/tools/viewer/sk_app/unix/Window_unix.h
new file mode 100644
index 0000000000..c2156fc6ae
--- /dev/null
+++ b/tools/viewer/sk_app/unix/Window_unix.h
@@ -0,0 +1,86 @@
+/*
+* Copyright 2016 Google Inc.
+*
+* Use of this source code is governed by a BSD-style license that can be
+* found in the LICENSE file.
+*/
+
+#ifndef Window_unix_DEFINED
+#define Window_unix_DEFINED
+
+#include <X11/Xlib.h>
+#include "../Window.h"
+#include "SkChecksum.h"
+#include "SkTDynamicHash.h"
+
+typedef Window XWindow;
+
+namespace sk_app {
+
+struct ContextPlatformData_unix {
+ Display* fDisplay;
+ XWindow fHWnd;
+ VisualID fVisualID;
+};
+
+class Window_unix : public Window {
+public:
+ Window_unix() : Window() {}
+ ~Window_unix() override {}
+
+ bool init(Display* display);
+
+ void setTitle(const char*) override;
+ void show() override;
+
+ bool attach(BackendType attachType, const DisplayParams& params) override;
+
+ void onInval() override;
+
+ bool handleEvent(const XEvent& event);
+
+ static const XWindow& GetKey(const Window_unix& w) {
+ return w.fHWnd;
+ }
+
+ static uint32_t Hash(const XWindow& w) {
+ return SkChecksum::Mix(w);
+ }
+
+ static SkTDynamicHash<Window_unix, XWindow> gWindowMap;
+
+ void markPendingPaint() { fPendingPaint = true; }
+ void finishPaint() {
+ if (fPendingPaint) {
+ this->onPaint();
+ fPendingPaint = false;
+ }
+ }
+
+ void markPendingResize(int width, int height) {
+ fPendingWidth = width;
+ fPendingHeight = height;
+ fPendingResize = true;
+ }
+ void finishResize() {
+ if (fPendingResize) {
+ this->onResize(fPendingWidth, fPendingHeight);
+ fPendingResize = false;
+ }
+ }
+
+private:
+ Display* fDisplay;
+ XWindow fHWnd;
+
+ Atom fWmDeleteMessage;
+
+ bool fPendingPaint;
+ int fPendingWidth;
+ int fPendingHeight;
+ bool fPendingResize;
+};
+
+} // namespace sk_app
+
+#endif
diff --git a/tools/viewer/sk_app/unix/main_unix.cpp b/tools/viewer/sk_app/unix/main_unix.cpp
new file mode 100644
index 0000000000..d595379174
--- /dev/null
+++ b/tools/viewer/sk_app/unix/main_unix.cpp
@@ -0,0 +1,90 @@
+/*
+* Copyright 2016 Google Inc.
+*
+* Use of this source code is governed by a BSD-style license that can be
+* found in the LICENSE file.
+*/
+
+#include "SkTypes.h"
+#include "SkTHash.h"
+#include "Timer.h"
+#include "Window_unix.h"
+#include "../Application.h"
+
+using sk_app::Application;
+
+static double now_ms() { return SkTime::GetNSecs() * 1e-6; }
+
+void finishWindow(sk_app::Window_unix* win) {
+ win->finishResize();
+ win->finishPaint();
+}
+
+int main(int argc, char**argv) {
+
+ Display* display = XOpenDisplay(nullptr);
+
+ Application* app = Application::Create(argc, argv, (void*)display);
+
+ double currentTime = 0.0;
+ double previousTime = 0.0;
+
+ // Get the file descriptor for the X display
+ int x11_fd = ConnectionNumber(display);
+ fd_set in_fds;
+
+ SkTHashSet<sk_app::Window_unix*> pendingWindows;
+ bool done = false;
+ while (!done) {
+ // Create a file description set containing x11_fd
+ FD_ZERO(&in_fds);
+ FD_SET(x11_fd, &in_fds);
+
+ // Set a sleep timer
+ struct timeval tv;
+ tv.tv_usec = 100;
+ tv.tv_sec = 0;
+
+ // Wait for an event on the file descriptor or for timer expiration
+ (void) select(1, &in_fds, NULL, NULL, &tv);
+
+ // Handle XEvents (if any) and flush the input
+ XEvent event;
+ while (XPending(display) && !done) {
+ XNextEvent(display, &event);
+
+ sk_app::Window_unix* win = sk_app::Window_unix::gWindowMap.find(event.xany.window);
+ // paint and resize events get collapsed
+ switch (event.type) {
+ case Expose:
+ win->markPendingPaint();
+ pendingWindows.add(win);
+ break;
+ case ConfigureNotify:
+ win->markPendingResize(event.xconfigurerequest.width,
+ event.xconfigurerequest.height);
+ pendingWindows.add(win);
+ break;
+ default:
+ if (win->handleEvent(event)) {
+ done = true;
+ }
+ break;
+ }
+ }
+
+ pendingWindows.foreach(finishWindow);
+ if (pendingWindows.count() > 0) {
+ previousTime = currentTime;
+ currentTime = now_ms();
+ app->onIdle(currentTime - previousTime);
+ }
+ pendingWindows.reset();
+ }
+
+ delete app;
+
+ XCloseDisplay(display);
+
+ return 0;
+}