From 10b3815a11c39b154ec7b74a2af43e019b50d48c Mon Sep 17 00:00:00 2001 From: jvanverth Date: Fri, 27 May 2016 05:47:00 -0700 Subject: [PATCH] Add OpenGL support to Linux viewer Also adds a command line option (--vulkan) to choose between Vulkan and OpenGL. GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2011473003 Review-Url: https://codereview.chromium.org/2011473003 --- tools/viewer/Viewer.cpp | 11 +- tools/viewer/sk_app/VulkanWindowContext.cpp | 1 + tools/viewer/sk_app/Window.cpp | 1 + .../sk_app/unix/VulkanWindowContext_unix.cpp | 5 +- tools/viewer/sk_app/unix/Window_unix.cpp | 128 +++++++++++++++--- tools/viewer/sk_app/unix/Window_unix.h | 29 ++-- 6 files changed, 141 insertions(+), 34 deletions(-) diff --git a/tools/viewer/Viewer.cpp b/tools/viewer/Viewer.cpp index 6519a3c8be..c1f890a4c3 100644 --- a/tools/viewer/Viewer.cpp +++ b/tools/viewer/Viewer.cpp @@ -41,7 +41,7 @@ static void on_ui_state_changed_handler(const SkString& stateName, const SkStrin return viewer->onUIStateChanged(stateName, stateValue); } -DEFINE_bool2(fullscreen, f, true, "Run fullscreen."); +DEFINE_bool2(fullscreen, f, false, "Run fullscreen."); DEFINE_string(key, "", "Space-separated key/value pairs to add to JSON identifying this builder."); DEFINE_string2(match, m, nullptr, "[~][^]substring[$] [...] of bench name to run.\n" @@ -53,6 +53,7 @@ DEFINE_string2(match, m, nullptr, "If a bench does not match any list entry,\n" "it is skipped unless some list entry starts with ~"); DEFINE_string(skps, "skps", "Directory to read skps from."); +DEFINE_bool(vulkan, true, "Run with Vulkan."); const char *kBackendTypeStrings[sk_app::Window::kBackendTypeCount] = { " [OpenGL]", @@ -84,6 +85,9 @@ Viewer::Viewer(int argc, char** argv, void* platformData) SkCommandLineFlags::Parse(argc, argv); + fBackendType = FLAGS_vulkan ? sk_app::Window::kVulkan_BackendType + : sk_app::Window::kNativeGL_BackendType; + fWindow = Window::CreateNativeWindow(platformData); fWindow->attach(fBackendType, DisplayParams()); @@ -130,6 +134,7 @@ Viewer::Viewer(int argc, char** argv, void* platformData) this->changeZoomLevel(-1.f / 32.f); fWindow->inval(); }); +#if 0 // this doesn't seem to work on any platform right now #ifndef SK_BUILD_FOR_ANDROID fCommands.addCommand('d', "Modes", "Change rendering backend", [this]() { fWindow->detach(); @@ -137,14 +142,16 @@ Viewer::Viewer(int argc, char** argv, void* platformData) if (sk_app::Window::kVulkan_BackendType == fBackendType) { fBackendType = sk_app::Window::kNativeGL_BackendType; } - // TODO: get Vulkan -> OpenGL working without swapchain creation failure + // TODO: get Vulkan -> OpenGL working on Windows without swapchain creation failure //else if (sk_app::Window::kNativeGL_BackendType == fBackendType) { // fBackendType = sk_app::Window::kVulkan_BackendType; //} fWindow->attach(fBackendType, DisplayParams()); this->updateTitle(); + fWindow->inval(); }); +#endif #endif // set up slides diff --git a/tools/viewer/sk_app/VulkanWindowContext.cpp b/tools/viewer/sk_app/VulkanWindowContext.cpp index 2e2b8a988c..f192c697e8 100644 --- a/tools/viewer/sk_app/VulkanWindowContext.cpp +++ b/tools/viewer/sk_app/VulkanWindowContext.cpp @@ -388,6 +388,7 @@ void VulkanWindowContext::destroyContext() { return; } + GR_VK_CALL(fBackendContext->fInterface, QueueWaitIdle(fPresentQueue)); GR_VK_CALL(fBackendContext->fInterface, DeviceWaitIdle(fBackendContext->fDevice)); this->destroyBuffers(); diff --git a/tools/viewer/sk_app/Window.cpp b/tools/viewer/sk_app/Window.cpp index a02e993d21..1c798df399 100644 --- a/tools/viewer/sk_app/Window.cpp +++ b/tools/viewer/sk_app/Window.cpp @@ -83,6 +83,7 @@ void Window::onPaint() { fWindowContext->swapBuffers(); } else { + printf("no backbuffer!?\n"); // try recreating testcontext } } diff --git a/tools/viewer/sk_app/unix/VulkanWindowContext_unix.cpp b/tools/viewer/sk_app/unix/VulkanWindowContext_unix.cpp index ddfc8e3068..02bf516b22 100644 --- a/tools/viewer/sk_app/unix/VulkanWindowContext_unix.cpp +++ b/tools/viewer/sk_app/unix/VulkanWindowContext_unix.cpp @@ -39,7 +39,7 @@ VkSurfaceKHR VulkanWindowContext::createVkSurface(VkInstance instance, void* pla surfaceCreateInfo.pNext = nullptr; surfaceCreateInfo.flags = 0; surfaceCreateInfo.connection = XGetXCBConnection(unixPlatformData->fDisplay); - surfaceCreateInfo.window = unixPlatformData->fHWnd; + surfaceCreateInfo.window = unixPlatformData->fWindow; VkResult res = createXcbSurfaceKHR(instance, &surfaceCreateInfo, nullptr, &surface); if (VK_SUCCESS != res) { @@ -64,10 +64,11 @@ bool VulkanWindowContext::canPresent(VkInstance instance, VkPhysicalDevice physD reinterpret_cast(platformData); Display* display = unixPlatformData->fDisplay; + VisualID visualID = unixPlatformData->fVisualInfo->visualid; VkBool32 check = getPhysicalDeviceXcbPresentationSupportKHR(physDev, queueFamilyIndex, XGetXCBConnection(display), - unixPlatformData->fVisualID); + visualID); return (VK_FALSE != check); } diff --git a/tools/viewer/sk_app/unix/Window_unix.cpp b/tools/viewer/sk_app/unix/Window_unix.cpp index 953eb36d74..431f156491 100644 --- a/tools/viewer/sk_app/unix/Window_unix.cpp +++ b/tools/viewer/sk_app/unix/Window_unix.cpp @@ -9,6 +9,7 @@ #include "SkUtils.h" #include "Timer.h" +#include "../GLWindowContext.h" #include "../VulkanWindowContext.h" #include "Window_unix.h" @@ -26,7 +27,7 @@ Window* Window::CreateNativeWindow(void* platformData) { Display* display = (Display*)platformData; Window_unix* window = new Window_unix(); - if (!window->init(display)) { + if (!window->initWindow(display, nullptr)) { delete window; return nullptr; } @@ -34,27 +35,87 @@ Window* Window::CreateNativeWindow(void* platformData) { return window; } -bool Window_unix::init(Display* display) { +const long kEventMask = ExposureMask | StructureNotifyMask | + KeyPressMask | KeyReleaseMask | + PointerMotionMask | ButtonPressMask | ButtonReleaseMask; + +bool Window_unix::initWindow(Display* display, const DisplayParams* params) { + if (params && params->fMSAASampleCount != fMSAASampleCount) { + this->closeWindow(); + } + // we already have a window + if (fDisplay) { + return true; + } 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; + // Attempt to create a window that supports GL + GLint att[] = { + GLX_RGBA, + GLX_DEPTH_SIZE, 24, + GLX_DOUBLEBUFFER, + GLX_STENCIL_SIZE, 8, + None + }; + SkASSERT(nullptr == fVisualInfo); + if (params && params->fMSAASampleCount > 0) { + static const GLint kAttCount = SK_ARRAY_COUNT(att); + GLint msaaAtt[kAttCount + 4]; + memcpy(msaaAtt, att, sizeof(att)); + SkASSERT(None == msaaAtt[kAttCount - 1]); + msaaAtt[kAttCount - 1] = GLX_SAMPLE_BUFFERS_ARB; + msaaAtt[kAttCount + 0] = 1; + msaaAtt[kAttCount + 1] = GLX_SAMPLES_ARB; + msaaAtt[kAttCount + 2] = params->fMSAASampleCount; + msaaAtt[kAttCount + 3] = None; + fVisualInfo = glXChooseVisual(display, DefaultScreen(display), msaaAtt); + fMSAASampleCount = params->fMSAASampleCount; + } + if (nullptr == fVisualInfo) { + fVisualInfo = glXChooseVisual(display, DefaultScreen(display), att); + fMSAASampleCount = 0; } - // choose the events we care about - XSelectInput(display, fHWnd, - ExposureMask | StructureNotifyMask | KeyPressMask | KeyReleaseMask | - PointerMotionMask | ButtonPressMask | ButtonReleaseMask); + if (fVisualInfo) { + Colormap colorMap = XCreateColormap(display, + RootWindow(display, fVisualInfo->screen), + fVisualInfo->visual, + AllocNone); + XSetWindowAttributes swa; + swa.colormap = colorMap; + swa.event_mask = kEventMask; + fWindow = XCreateWindow(display, + RootWindow(display, fVisualInfo->screen), + 0, 0, // x, y + fWidth, fHeight, + 0, // border width + fVisualInfo->depth, + InputOutput, + fVisualInfo->visual, + CWEventMask | CWColormap, + &swa); + } else { + // Create a simple window instead. We will not be able to show GL + fWindow = XCreateSimpleWindow(display, + DefaultRootWindow(display), + 0, 0, // x, y + fWidth, fHeight, + 0, // border width + 0, // border value + 0); // background value + XSelectInput(display, fWindow, kEventMask); + } + + if (!fWindow) { + return false; + } // set up to catch window delete message fWmDeleteMessage = XInternAtom(display, "WM_DELETE_WINDOW", False); - XSetWMProtocols(display, fHWnd, &fWmDeleteMessage, 1); + XSetWMProtocols(display, fWindow, &fWmDeleteMessage, 1); // add to hashtable of windows gWindowMap.add(this); @@ -66,6 +127,21 @@ bool Window_unix::init(Display* display) { return true; } +void Window_unix::closeWindow() { + if (fDisplay) { + this->detach(); + SkASSERT(fGC); + XFreeGC(fDisplay, fGC); + fGC = nullptr; + gWindowMap.remove(fWindow); + XDestroyWindow(fDisplay, fWindow); + fWindow = 0; + fVisualInfo = nullptr; + fDisplay = nullptr; + fMSAASampleCount = 0; + } +} + static Window::Key get_key(KeySym keysym) { static const struct { KeySym fXK; @@ -108,6 +184,12 @@ static uint32_t get_modifiers(const XEvent& event) { bool Window_unix::handleEvent(const XEvent& event) { switch (event.type) { + case MapNotify: + if (!fGC) { + fGC = XCreateGC(fDisplay, fWindow, 0, nullptr); + } + break; + case ClientMessage: if ((Atom)event.xclient.data.l[0] == fWmDeleteMessage && gWindowMap.count() == 1) { @@ -179,25 +261,29 @@ bool Window_unix::handleEvent(const XEvent& event) { void Window_unix::setTitle(const char* title) { XTextProperty textproperty; XStringListToTextProperty(const_cast(&title), 1, &textproperty); - XSetWMName(fDisplay, fHWnd, &textproperty); + XSetWMName(fDisplay, fWindow, &textproperty); } void Window_unix::show() { - XMapWindow(fDisplay, fHWnd); + XMapWindow(fDisplay, fWindow); } bool Window_unix::attach(BackendType attachType, const DisplayParams& params) { + this->initWindow(fDisplay, ¶ms); + ContextPlatformData_unix platformData; platformData.fDisplay = fDisplay; - platformData.fHWnd = fHWnd; - XWindowAttributes attribs; - XGetWindowAttributes(fDisplay, fHWnd, &attribs); - platformData.fVisualID = XVisualIDFromVisual(attribs.visual); + platformData.fWindow = fWindow; + platformData.fVisualInfo = fVisualInfo; switch (attachType) { case kVulkan_BackendType: - default: fWindowContext = VulkanWindowContext::Create((void*)&platformData, params); break; + + case kNativeGL_BackendType: + default: + fWindowContext = GLWindowContext::Create((void*)&platformData, params); + break; } return (SkToBool(fWindowContext)); @@ -208,14 +294,14 @@ void Window_unix::onInval() { event.type = Expose; event.xexpose.send_event = True; event.xexpose.display = fDisplay; - event.xexpose.window = fHWnd; + event.xexpose.window = fWindow; 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); + XSendEvent(fDisplay, fWindow, 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 index c2156fc6ae..fb6b22d413 100644 --- a/tools/viewer/sk_app/unix/Window_unix.h +++ b/tools/viewer/sk_app/unix/Window_unix.h @@ -9,6 +9,7 @@ #define Window_unix_DEFINED #include +#include #include "../Window.h" #include "SkChecksum.h" #include "SkTDynamicHash.h" @@ -18,17 +19,22 @@ typedef Window XWindow; namespace sk_app { struct ContextPlatformData_unix { - Display* fDisplay; - XWindow fHWnd; - VisualID fVisualID; + Display* fDisplay; + XWindow fWindow; + XVisualInfo* fVisualInfo; }; class Window_unix : public Window { public: - Window_unix() : Window() {} - ~Window_unix() override {} + Window_unix() : Window() + , fDisplay(nullptr) + , fWindow(0) + , fGC(nullptr) + , fVisualInfo(nullptr) + , fMSAASampleCount(0) {} + ~Window_unix() override { this->closeWindow(); } - bool init(Display* display); + bool initWindow(Display* display, const DisplayParams* params); void setTitle(const char*) override; void show() override; @@ -40,7 +46,7 @@ public: bool handleEvent(const XEvent& event); static const XWindow& GetKey(const Window_unix& w) { - return w.fHWnd; + return w.fWindow; } static uint32_t Hash(const XWindow& w) { @@ -70,8 +76,13 @@ public: } private: - Display* fDisplay; - XWindow fHWnd; + void closeWindow(); + + Display* fDisplay; + XWindow fWindow; + GC fGC; + XVisualInfo* fVisualInfo; + int fMSAASampleCount; Atom fWmDeleteMessage; -- 2.34.1