skia2/tools/sk_app/mac/Window_mac.cpp
Brian Osman 4013db8e08 Fix flicker when changing backend on Mac viewer
Tie the SDL GL context to the Window, not the context. Deleting the context
causes the window to render a frame of black - this keeps the context alive
along with the window, so that never happens.

Change-Id: Id4df18a6f2fe09f617ec2ff1809d000f18f547ba
Reviewed-on: https://skia-review.googlesource.com/107941
Reviewed-by: Jim Van Verth <jvanverth@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
2018-02-15 19:14:32 +00:00

291 lines
8.4 KiB
C++

/*
* 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 "SkUtils.h"
#include "Timer.h"
#include "WindowContextFactory_mac.h"
#include "Window_mac.h"
namespace sk_app {
SkTDynamicHash<Window_mac, Uint32> Window_mac::gWindowMap;
Window* Window::CreateNativeWindow(void*) {
Window_mac* window = new Window_mac();
if (!window->initWindow()) {
delete window;
return nullptr;
}
return window;
}
bool Window_mac::initWindow() {
if (fRequestedDisplayParams.fMSAASampleCount != fMSAASampleCount) {
this->closeWindow();
}
// we already have a window
if (fWindow) {
return true;
}
constexpr int initialWidth = 1280;
constexpr int initialHeight = 960;
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 0);
SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1);
if (fRequestedDisplayParams.fMSAASampleCount > 1) {
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, fRequestedDisplayParams.fMSAASampleCount);
} else {
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 0);
}
// TODO: handle other display params
uint32_t windowFlags = SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE;
fWindow = SDL_CreateWindow("SDL Window", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
initialWidth, initialHeight, windowFlags);
if (!fWindow) {
return false;
}
fMSAASampleCount = fRequestedDisplayParams.fMSAASampleCount;
// add to hashtable of windows
fWindowID = SDL_GetWindowID(fWindow);
gWindowMap.add(this);
fGLContext = SDL_GL_CreateContext(fWindow);
if (!fGLContext) {
SkDebugf("%s\n", SDL_GetError());
this->closeWindow();
return false;
}
return true;
}
void Window_mac::closeWindow() {
if (fGLContext) {
SDL_GL_DeleteContext(fGLContext);
fGLContext = nullptr;
}
if (fWindow) {
gWindowMap.remove(fWindowID);
SDL_DestroyWindow(fWindow);
fWindowID = 0;
fWindow = nullptr;
}
}
static Window::Key get_key(const SDL_Keysym& keysym) {
static const struct {
SDL_Keycode fSDLK;
Window::Key fKey;
} gPair[] = {
{ SDLK_BACKSPACE, Window::Key::kBack },
{ SDLK_CLEAR, Window::Key::kBack },
{ SDLK_RETURN, Window::Key::kOK },
{ SDLK_UP, Window::Key::kUp },
{ SDLK_DOWN, Window::Key::kDown },
{ SDLK_LEFT, Window::Key::kLeft },
{ SDLK_RIGHT, Window::Key::kRight },
{ SDLK_TAB, Window::Key::kTab },
{ SDLK_PAGEUP, Window::Key::kPageUp },
{ SDLK_PAGEDOWN, Window::Key::kPageDown },
{ SDLK_HOME, Window::Key::kHome },
{ SDLK_END, Window::Key::kEnd },
{ SDLK_DELETE, Window::Key::kDelete },
{ SDLK_ESCAPE, Window::Key::kEscape },
{ SDLK_LSHIFT, Window::Key::kShift },
{ SDLK_RSHIFT, Window::Key::kShift },
{ SDLK_LCTRL, Window::Key::kCtrl },
{ SDLK_RCTRL, Window::Key::kCtrl },
{ SDLK_LALT, Window::Key::kOption },
{ SDLK_LALT, Window::Key::kOption },
{ 'A', Window::Key::kA },
{ 'C', Window::Key::kC },
{ 'V', Window::Key::kV },
{ 'X', Window::Key::kX },
{ 'Y', Window::Key::kY },
{ 'Z', Window::Key::kZ },
};
for (size_t i = 0; i < SK_ARRAY_COUNT(gPair); i++) {
if (gPair[i].fSDLK == keysym.sym) {
return gPair[i].fKey;
}
}
return Window::Key::kNONE;
}
static uint32_t get_modifiers(const SDL_Event& event) {
static const struct {
unsigned fSDLMask;
unsigned fSkMask;
} gModifiers[] = {
{ KMOD_SHIFT, Window::kShift_ModifierKey },
{ KMOD_CTRL, Window::kControl_ModifierKey },
{ KMOD_ALT, Window::kOption_ModifierKey },
};
auto modifiers = 0;
switch (event.type) {
case SDL_KEYDOWN:
// fall through
case SDL_KEYUP: {
for (size_t i = 0; i < SK_ARRAY_COUNT(gModifiers); ++i) {
if (event.key.keysym.mod & gModifiers[i].fSDLMask) {
modifiers |= gModifiers[i].fSkMask;
}
}
if (0 == event.key.repeat) {
modifiers |= Window::kFirstPress_ModifierKey;
}
break;
}
default: {
SDL_Keymod mod = SDL_GetModState();
for (size_t i = 0; i < SK_ARRAY_COUNT(gModifiers); ++i) {
if (mod & gModifiers[i].fSDLMask) {
modifiers |= gModifiers[i].fSkMask;
}
}
break;
}
}
return modifiers;
}
bool Window_mac::HandleWindowEvent(const SDL_Event& event) {
Window_mac* win = gWindowMap.find(event.window.windowID);
if (win && win->handleEvent(event)) {
return true;
}
return false;
}
bool Window_mac::handleEvent(const SDL_Event& event) {
switch (event.type) {
case SDL_WINDOWEVENT:
if (SDL_WINDOWEVENT_EXPOSED == event.window.event) {
this->onPaint();
} else if (SDL_WINDOWEVENT_RESIZED == event.window.event) {
this->onResize(event.window.data1, event.window.data2);
}
break;
case SDL_MOUSEBUTTONDOWN:
if (event.button.button == SDL_BUTTON_LEFT) {
this->onMouse(event.button.x, event.button.y,
Window::kDown_InputState, get_modifiers(event));
}
break;
case SDL_MOUSEBUTTONUP:
if (event.button.button == SDL_BUTTON_LEFT) {
this->onMouse(event.button.x, event.button.y,
Window::kUp_InputState, get_modifiers(event));
}
break;
case SDL_MOUSEMOTION:
this->onMouse(event.motion.x, event.motion.y,
Window::kMove_InputState, get_modifiers(event));
break;
case SDL_MOUSEWHEEL:
this->onMouseWheel(event.wheel.y, get_modifiers(event));
break;
case SDL_KEYDOWN: {
Window::Key key = get_key(event.key.keysym);
if (key != Window::Key::kNONE) {
if (!this->onKey(key, Window::kDown_InputState, get_modifiers(event))) {
if (event.key.keysym.sym == SDLK_ESCAPE) {
return true;
}
}
}
} break;
case SDL_KEYUP: {
Window::Key key = get_key(event.key.keysym);
if (key != Window::Key::kNONE) {
(void) this->onKey(key, Window::kUp_InputState,
get_modifiers(event));
}
} break;
case SDL_TEXTINPUT: {
const char* textIter = &event.text.text[0];
while (SkUnichar c = SkUTF8_NextUnichar(&textIter)) {
(void) this->onChar(c, get_modifiers(event));
}
} break;
default:
break;
}
return false;
}
void Window_mac::setTitle(const char* title) {
SDL_SetWindowTitle(fWindow, title);
}
void Window_mac::show() {
SDL_ShowWindow(fWindow);
}
bool Window_mac::attach(BackendType attachType) {
this->initWindow();
window_context_factory::MacWindowInfo info;
info.fWindow = fWindow;
info.fGLContext = fGLContext;
switch (attachType) {
case kRaster_BackendType:
fWindowContext = NewRasterForMac(info, fRequestedDisplayParams);
break;
case kNativeGL_BackendType:
default:
fWindowContext = NewGLForMac(info, fRequestedDisplayParams);
break;
}
this->onBackendCreated();
return (SkToBool(fWindowContext));
}
void Window_mac::onInval() {
SDL_Event sdlevent;
sdlevent.type = SDL_WINDOWEVENT;
sdlevent.window.windowID = fWindowID;
sdlevent.window.event = SDL_WINDOWEVENT_EXPOSED;
SDL_PushEvent(&sdlevent);
}
} // namespace sk_app