--- /dev/null
+/*
+ Copyright 2011 Google Inc.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ */
+
+#include "GrGLInterface.h"
+
+#include <GL/glx.h>
+#include <GL/gl.h>
+#include <GL/glext.h>
+#include <GL/glu.h>
+
+#define GR_GL_GET_PROC(F) gDefaultInterface.f ## F = (GrGLInterface::GrGL ## F ## Proc) \
+ glXGetProcAddress(reinterpret_cast<const GLubyte*>("gl" #F));
+#define GR_GL_GET_PROC_SUFFIX(F, S) gDefaultInterface.f ## F = (GrGLInterface::GrGL ## F ## Proc) \
+ glXGetProcAddress(reinterpret_cast<const GLubyte*>("gl" #F #S));
+
+void GrGLSetDefaultGLInterface() {
+ static GrGLInterface gDefaultInterface;
+ static bool gDefaultInterfaceInit;
+ if (!gDefaultInterfaceInit && NULL != glXGetCurrentContext()) {
+ int major, minor;
+ const char* versionString = (const char*) glGetString(GL_VERSION);
+ const char* extString = (const char*) glGetString(GL_EXTENSIONS);
+ gl_version_from_string(&major, &minor, versionString);
+
+ if (major == 1 && minor < 5) {
+ // We must have array and element_array buffer objects.
+ return;
+ }
+
+ gDefaultInterface.fActiveTexture = glActiveTexture;
+ GR_GL_GET_PROC(AttachShader);
+ GR_GL_GET_PROC(BindAttribLocation);
+ GR_GL_GET_PROC(BindBuffer);
+ gDefaultInterface.fBindTexture = glBindTexture;
+ gDefaultInterface.fBlendColor = glBlendColor;
+ gDefaultInterface.fBlendFunc = glBlendFunc;
+ GR_GL_GET_PROC(BufferData);
+ GR_GL_GET_PROC(BufferSubData);
+ gDefaultInterface.fClear = glClear;
+ gDefaultInterface.fClearColor = glClearColor;
+ gDefaultInterface.fClearStencil = glClearStencil;
+ gDefaultInterface.fClientActiveTexture = glClientActiveTexture;
+ gDefaultInterface.fColorMask = glColorMask;
+ gDefaultInterface.fColorPointer = glColorPointer;
+ gDefaultInterface.fColor4ub = glColor4ub;
+ GR_GL_GET_PROC(CompileShader);
+ gDefaultInterface.fCompressedTexImage2D = glCompressedTexImage2D;
+ GR_GL_GET_PROC(CreateProgram);
+ GR_GL_GET_PROC(CreateShader);
+ gDefaultInterface.fCullFace = glCullFace;
+ GR_GL_GET_PROC(DeleteBuffers);
+ GR_GL_GET_PROC(DeleteProgram);
+ GR_GL_GET_PROC(DeleteShader);
+ gDefaultInterface.fDeleteTextures = glDeleteTextures;
+ gDefaultInterface.fDepthMask = glDepthMask;
+ gDefaultInterface.fDisable = glDisable;
+ gDefaultInterface.fDisableClientState = glDisableClientState;
+ GR_GL_GET_PROC(DisableVertexAttribArray);
+ gDefaultInterface.fDrawArrays = glDrawArrays;
+ gDefaultInterface.fDrawElements = glDrawElements;
+ gDefaultInterface.fEnable = glEnable;
+ gDefaultInterface.fEnableClientState = glEnableClientState;
+ GR_GL_GET_PROC(EnableVertexAttribArray);
+ gDefaultInterface.fFrontFace = glFrontFace;
+ GR_GL_GET_PROC(GenBuffers);
+ GR_GL_GET_PROC(GetBufferParameteriv);
+ gDefaultInterface.fGetError = glGetError;
+ gDefaultInterface.fGetIntegerv = glGetIntegerv;
+ GR_GL_GET_PROC(GetProgramInfoLog);
+ GR_GL_GET_PROC(GetProgramiv);
+ GR_GL_GET_PROC(GetShaderInfoLog);
+ GR_GL_GET_PROC(GetShaderiv);
+ gDefaultInterface.fGetString = glGetString;
+ gDefaultInterface.fGenTextures = glGenTextures;
+ GR_GL_GET_PROC(GetUniformLocation);
+ gDefaultInterface.fLineWidth = glLineWidth;
+ GR_GL_GET_PROC(LinkProgram);
+ gDefaultInterface.fLoadMatrixf = glLoadMatrixf;
+ GR_GL_GET_PROC(MapBuffer);
+ gDefaultInterface.fMatrixMode = glMatrixMode;
+ gDefaultInterface.fPointSize = glPointSize;
+ gDefaultInterface.fPixelStorei = glPixelStorei;
+ gDefaultInterface.fReadPixels = glReadPixels;
+ gDefaultInterface.fScissor = glScissor;
+ gDefaultInterface.fShadeModel = glShadeModel;
+ GR_GL_GET_PROC(ShaderSource);
+ gDefaultInterface.fStencilFunc = glStencilFunc;
+ GR_GL_GET_PROC(StencilFuncSeparate);
+ gDefaultInterface.fStencilMask = glStencilMask;
+ GR_GL_GET_PROC(StencilMaskSeparate);
+ gDefaultInterface.fStencilOp = glStencilOp;
+ GR_GL_GET_PROC(StencilOpSeparate);
+ gDefaultInterface.fTexCoordPointer = glTexCoordPointer;
+ gDefaultInterface.fTexEnvi = glTexEnvi;
+ // mac uses GLenum for internalFormat param (non-standard)
+ // amounts to int vs. uint.
+ gDefaultInterface.fTexImage2D =
+ (GrGLInterface::GrGLTexImage2DProc)glTexImage2D;
+ gDefaultInterface.fTexParameteri = glTexParameteri;
+ gDefaultInterface.fTexSubImage2D = glTexSubImage2D;
+ GR_GL_GET_PROC(Uniform1fv);
+ GR_GL_GET_PROC(Uniform1i);
+ GR_GL_GET_PROC(Uniform4fv);
+ GR_GL_GET_PROC(UniformMatrix3fv);
+ GR_GL_GET_PROC(UnmapBuffer);
+ GR_GL_GET_PROC(UseProgram);
+ GR_GL_GET_PROC(VertexAttrib4fv);
+ GR_GL_GET_PROC(VertexAttribPointer);
+ gDefaultInterface.fVertexPointer = glVertexPointer;
+ gDefaultInterface.fViewport = glViewport;
+
+ // First look for GL3.0 FBO or GL_ARB_framebuffer_object (same since
+ // GL_ARB_framebuffer_object doesn't use ARB suffix.)
+ if (major >= 3 || has_gl_extension("GL_ARB_framebuffer_object")) {
+ GR_GL_GET_PROC(GenFramebuffers);
+ GR_GL_GET_PROC(BindFramebuffer);
+ GR_GL_GET_PROC(FramebufferTexture2D);
+ GR_GL_GET_PROC(CheckFramebufferStatus);
+ GR_GL_GET_PROC(DeleteFramebuffers);
+ GR_GL_GET_PROC(RenderbufferStorage);
+ GR_GL_GET_PROC(GenRenderbuffers);
+ GR_GL_GET_PROC(DeleteRenderbuffers);
+ GR_GL_GET_PROC(FramebufferRenderbuffer);
+ GR_GL_GET_PROC(BindRenderbuffer);
+ GR_GL_GET_PROC(RenderbufferStorageMultisample);
+ GR_GL_GET_PROC(BlitFramebuffer);
+ } else if (has_gl_extension_from_string("GL_EXT_framebuffer_object",
+ extString)) {
+ GR_GL_GET_PROC_SUFFIX(GenFramebuffers, EXT);
+ GR_GL_GET_PROC_SUFFIX(BindFramebuffer, EXT);
+ GR_GL_GET_PROC_SUFFIX(FramebufferTexture2D, EXT);
+ GR_GL_GET_PROC_SUFFIX(CheckFramebufferStatus, EXT);
+ GR_GL_GET_PROC_SUFFIX(DeleteFramebuffers, EXT);
+ GR_GL_GET_PROC_SUFFIX(RenderbufferStorage, EXT);
+ GR_GL_GET_PROC_SUFFIX(GenRenderbuffers, EXT);
+ GR_GL_GET_PROC_SUFFIX(DeleteRenderbuffers, EXT);
+ GR_GL_GET_PROC_SUFFIX(FramebufferRenderbuffer, EXT);
+ GR_GL_GET_PROC_SUFFIX(BindRenderbuffer, EXT);
+ if (has_gl_extension_from_string("GL_EXT_framebuffer_multisample",
+ extString)) {
+ GR_GL_GET_PROC_SUFFIX(RenderbufferStorageMultisample, EXT);
+ }
+ if (has_gl_extension_from_string("GL_EXT_framebuffer_blit",
+ extString)) {
+ GR_GL_GET_PROC_SUFFIX(BlitFramebuffer, EXT);
+ }
+ } else {
+ // we must have FBOs
+ return;
+ }
+ gDefaultInterface.fBindingsExported = kDesktop_GrGLBinding;
+
+ gDefaultInterfaceInit = true;
+ }
+ if (gDefaultInterfaceInit)
+ GrGLSetGLInterface(&gDefaultInterface);
+}
'../gpu/src/mac/GrGLDefaultInterface_mac.cpp',
'../gpu/src/win/GrGLDefaultInterface_win.cpp',
+
+ '../gpu/src/unix/GrGLDefaultInterface_unix.cpp',
],
'defines': [
'GR_IMPLEMENTATION=1',
'defines': [
'GR_LINUX_BUILD=1',
],
+ 'sources!': [
+ '../gpu/src/GrGLDefaultInterface_none.cpp',
+ ],
'link_settings': {
'libraries': [
'-lGL',
'../gpu/src/mac/GrGLDefaultInterface_mac.cpp',
],
}],
+ [ 'OS != "linux"', {
+ 'sources!': [
+ '../gpu/src/unix/GrGLDefaultInterface_unix.cpp',
+ ],
+ }],
],
'direct_dependent_settings': {
'conditions': [
#include "SkWindow.h"
#include <X11/Xlib.h>
+#include <GL/glx.h>
class SkBitmap;
class SkEvent;
Window fWin;
size_t fOSWin;
GC fGc;
+ GLXContext fGLContext;
+ bool fGLCreated;
};
class SkOSWindow : public SkWindow {
void* getHWND() const { return (void*)fUnixWindow.fWin; }
void* getDisplay() const { return (void*)fUnixWindow.fDisplay; }
void* getUnixWindow() const { return (void*)&fUnixWindow; }
- void setUnixWindow(Display*, Window, size_t, GC);
+ void loop();
+ void post_linuxevent();
bool attachGL();
void detachGL();
void presentGL();
private:
SkUnixWindow fUnixWindow;
+ bool fGLAttached;
+ bool fRestart;
+
+ // Needed for GL
+ XVisualInfo* fVi;
void doPaint();
+ void restartLoop();
+ void mapWindowAndWait();
typedef SkWindow INHERITED;
};
#include <X11/Xatom.h>
#include <X11/keysym.h>
#include <GL/glx.h>
+#include <GL/gl.h>
+#include <GL/glu.h>
#include "SkWindow.h"
#include "SkCanvas.h"
#include "SkColor.h"
#include "SkEvent.h"
+#include "SkKey.h"
+#include "SkWindow.h"
+#include "XkeysToSkKeys.h"
+extern "C" {
+ #include "keysym2ucs.h"
+}
+
+const int WIDTH = 1000;
+const int HEIGHT = 1000;
+
+// Determine which events to listen for.
+const long EVENT_MASK = StructureNotifyMask|ButtonPressMask|ButtonReleaseMask
+ |ExposureMask|PointerMotionMask|KeyPressMask|KeyReleaseMask;
SkOSWindow::SkOSWindow(void* unused)
{
- fUnixWindow.fDisplay = NULL;
+ fUnixWindow.fDisplay = XOpenDisplay(NULL);
+ Display* dsp = fUnixWindow.fDisplay;
+ if (dsp) {
+ // Attempt to create a window that supports GL
+ GLint att[] = { GLX_RGBA, GLX_DEPTH_SIZE, 24, GLX_DOUBLEBUFFER,
+ GLX_STENCIL_SIZE, 8, None };
+ fVi = glXChooseVisual(dsp, 0, att);
+ if (fVi) {
+ XSetWindowAttributes swa;
+ swa.event_mask = EVENT_MASK;
+ fUnixWindow.fWin = XCreateWindow(dsp, DefaultRootWindow(dsp),
+ 0, 0, WIDTH, HEIGHT, 0, fVi->depth,
+ InputOutput, fVi->visual, CWEventMask, &swa);
+
+ } else {
+ // Create a simple window instead. We will not be able to
+ // show GL
+ fUnixWindow.fWin = XCreateSimpleWindow(dsp, DefaultRootWindow(dsp),
+ 0, 0, WIDTH, HEIGHT, 0, 0, 0);
+ }
+ mapWindowAndWait();
+ fUnixWindow.fGc = XCreateGC(dsp, fUnixWindow.fWin, 0, NULL);
+ }
+ this->resize(WIDTH, HEIGHT);
+ fRestart = false;
+ fUnixWindow.fGLCreated = false;
}
SkOSWindow::~SkOSWindow()
{
+ if (fUnixWindow.fDisplay) {
+ if (fGLAttached)
+ glXMakeCurrent(fUnixWindow.fDisplay, None, NULL);
+ XFreeGC(fUnixWindow.fDisplay, fUnixWindow.fGc);
+ if (fUnixWindow.fGLCreated)
+ glXDestroyContext(fUnixWindow.fDisplay, fUnixWindow.fGLContext);
+ XDestroyWindow(fUnixWindow.fDisplay, fUnixWindow.fWin);
+ XCloseDisplay(fUnixWindow.fDisplay);
+ fUnixWindow.fDisplay = 0;
+ }
+}
+
+void SkOSWindow::post_linuxevent()
+{
+ // Put an event in the X queue to fire an SkEvent.
+ if (!fUnixWindow.fDisplay) return;
+ long event_mask = NoEventMask;
+ XClientMessageEvent event;
+ event.type = ClientMessage;
+ Atom myAtom;
+ event.message_type = myAtom;
+ event.format = 32;
+ event.data.l[0] = 0;
+ XSendEvent(fUnixWindow.fDisplay, fUnixWindow.fWin, false, 0,
+ (XEvent*) &event);
+}
+
+void SkOSWindow::restartLoop()
+{
+ // We have a new window, so we need to set the title again and restart the
+ // loop.
+ this->setTitle(this->getTitle());
+ fRestart = true;
+}
+
+void SkOSWindow::loop()
+{
+ Display* dsp = fUnixWindow.fDisplay;
+ XSelectInput(dsp, fUnixWindow.fWin, EVENT_MASK);
+
+ bool loop = true;
+ XEvent evt;
+ while (loop) {
+ if (fRestart) {
+ fRestart = false;
+ this->loop();
+ return;
+ }
+ XNextEvent(dsp, &evt);
+ switch (evt.type) {
+ case Expose:
+ if (evt.xexpose.count == 0)
+ this->inval(NULL);
+ break;
+ case ConfigureNotify:
+ this->resize(evt.xconfigure.width, evt.xconfigure.height);
+ break;
+ case ButtonPress:
+ if (evt.xbutton.button == Button1)
+ this->handleClick(evt.xbutton.x, evt.xbutton.y, SkView::Click::kDown_State);
+ break;
+ case ButtonRelease:
+ if (evt.xbutton.button == Button1)
+ this->handleClick(evt.xbutton.x, evt.xbutton.y, SkView::Click::kUp_State);
+ break;
+ case MotionNotify:
+ this->handleClick(evt.xmotion.x, evt.xmotion.y, SkView::Click::kMoved_State);
+ break;
+ case KeyPress:
+ {
+ KeySym keysym = XKeycodeToKeysym(dsp, evt.xkey.keycode, 0);
+ //SkDebugf("pressed key %i!\n\tKeySym:%i\n", evt.xkey.keycode, XKeycodeToKeysym(dsp, evt.xkey.keycode, 0));
+ if (keysym == XK_Escape) {
+ loop = false;
+ break;
+ }
+ this->handleKey(XKeyToSkKey(keysym));
+ long uni = keysym2ucs(keysym);
+ if (uni != -1) {
+ this->handleChar((SkUnichar) uni);
+ }
+ break;
+ }
+ case KeyRelease:
+ //SkDebugf("released key %i\n", evt.xkey.keycode);
+ this->handleKeyUp(XKeyToSkKey(XKeycodeToKeysym(dsp, evt.xkey.keycode, 0)));
+ break;
+ case ClientMessage:
+ if (SkEvent::ProcessEvent()) {
+ this->post_linuxevent();
+ }
+ break;
+ default:
+ // Do nothing for other events
+ break;
+ }
+ }
}
-void SkOSWindow::setUnixWindow(Display* dsp, Window win, size_t screenNumber, GC gc)
+void SkOSWindow::mapWindowAndWait()
{
- fUnixWindow.fDisplay = dsp;
- fUnixWindow.fWin = win;
- fUnixWindow.fOSWin = screenNumber;
- fUnixWindow.fGc = gc;
+ Display* dsp = fUnixWindow.fDisplay;
+ Window win = fUnixWindow.fWin;
+ XMapWindow(dsp, win);
+
+ long eventMask = StructureNotifyMask;
+ XSelectInput(dsp, win, eventMask);
+
+ // Wait until screen is ready.
+ XEvent evt;
+ do {
+ XNextEvent(dsp, &evt);
+ } while(evt.type != MapNotify);
+
}
bool SkOSWindow::attachGL()
{
- return false;
+ if (fGLAttached) return true;
+ Display* dsp = fUnixWindow.fDisplay;
+ if (!dsp || !fVi) return false;
+
+ if (!fUnixWindow.fGLCreated) {
+ fUnixWindow.fGLContext = glXCreateContext(dsp, fVi, NULL, GL_TRUE);
+ fUnixWindow.fGLCreated = true;
+ glXMakeCurrent(dsp, fUnixWindow.fWin, fUnixWindow.fGLContext);
+ glViewport(0, 0, SkScalarRound(this->width()), SkScalarRound(this->height()));
+ glClearColor(0, 0, 0, 0);
+ glClearStencil(0);
+ glStencilMask(0xffffffff);
+ glDisable(GL_SCISSOR_TEST);
+ glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+ }
+ else
+ glXMakeCurrent(dsp, fUnixWindow.fWin, fUnixWindow.fGLContext);
+ fGLAttached = true;
+
+
+ this->restartLoop();
+ return true;
}
void SkOSWindow::detachGL()
{
-
+ if (!fUnixWindow.fDisplay || !fGLAttached) return;
+ fGLAttached = false;
+ // Returns back to normal drawing.
+ glXMakeCurrent(fUnixWindow.fDisplay, None, NULL);
+ this->restartLoop();
+ // Ensure that we redraw when switching back to raster.
+ this->inval(NULL);
}
void SkOSWindow::presentGL()
{
-
+ if (fUnixWindow.fDisplay && fGLAttached) {
+ glXSwapBuffers(fUnixWindow.fDisplay, fUnixWindow.fWin);
+ }
}
void SkOSWindow::onSetTitle(const char title[])
{
if (evt.isType("inval-imageview")) {
update(NULL);
- doPaint();
+ if (!fGLAttached)
+ doPaint();
return true;
}
return INHERITED::onEvent(evt);
#include "X11/keysym.h"
#include "SkApplication.h"
-#include "SkKey.h"
-#include "SkView.h"
+#include "SkEvent.h"
#include "SkWindow.h"
-#include "XkeysToSkKeys.h"
-extern "C" {
- #include "keysym2ucs.h"
-}
#include "SkTypes.h"
+
//#include <signal.h>
//#include <sys/time.h>
-// Globals for access to the window
-Display* dsp = 0;
-Window win;
-
-const int WIDTH = 1000;
-const int HEIGHT = 1000;
-
-// Put an event in the X queue to fire an SkEvent.
-static void post_linuxevent()
-{
- if (!dsp) return;
- long event_mask = NoEventMask;
- XClientMessageEvent event;
- event.type = ClientMessage;
- Atom myAtom;
- event.message_type = myAtom;
- event.format = 32;
- event.data.l[0] = 0;
- XSendEvent(dsp, win, false, 0, (XEvent*) &event);
-}
+SkOSWindow* gWindow;
#if 0
static void catch_alarm(int sig)
#endif
int main(){
- dsp = XOpenDisplay(NULL);
- if(!dsp) {
- return 1;
- }
-
// signal(SIGALRM, catch_alarm);
- win = XCreateSimpleWindow(dsp, DefaultRootWindow(dsp), 0, 0, WIDTH, HEIGHT, 0, 0, 0);
- XMapWindow(dsp, win);
-
- long eventMask = StructureNotifyMask;
- XSelectInput(dsp, win, eventMask);
-
- // Wait until screen is ready.
- XEvent evt;
- do {
- XNextEvent(dsp, &evt);
- } while(evt.type != MapNotify);
-
- GC gc = XCreateGC(dsp, win, 0, NULL);
+ gWindow = create_sk_window(NULL);
// Start normal Skia sequence
application_init();
- SkOSWindow* window = create_sk_window(NULL);
- window->setUnixWindow(dsp, win, DefaultScreen(dsp), gc);
- window->resize(WIDTH, HEIGHT);
-
-
- // Determine which events to listen for.
- eventMask = StructureNotifyMask|ButtonPressMask|ButtonReleaseMask
- |ExposureMask|PointerMotionMask|KeyPressMask|KeyReleaseMask;
- XSelectInput(dsp, win, eventMask);
-
- bool loop = true;
- while (loop) {
- XNextEvent(dsp, &evt);
- switch (evt.type) {
- case Expose:
- if (evt.xexpose.count == 0)
- window->inval(NULL);
- break;
- case ConfigureNotify:
- window->resize(evt.xconfigure.width, evt.xconfigure.height);
- break;
- case ButtonPress:
- if (evt.xbutton.button == Button1)
- window->handleClick(evt.xbutton.x, evt.xbutton.y, SkView::Click::kDown_State);
- break;
- case ButtonRelease:
- if (evt.xbutton.button == Button1)
- window->handleClick(evt.xbutton.x, evt.xbutton.y, SkView::Click::kUp_State);
- break;
- case MotionNotify:
- window->handleClick(evt.xmotion.x, evt.xmotion.y, SkView::Click::kMoved_State);
- break;
- case KeyPress:
- {
- KeySym keysym = XKeycodeToKeysym(dsp, evt.xkey.keycode, 0);
- //SkDebugf("pressed key %i!\n\tKeySym:%i\n", evt.xkey.keycode, XKeycodeToKeysym(dsp, evt.xkey.keycode, 0));
- if (keysym == XK_Escape) {
- loop = false;
- break;
- }
- window->handleKey(XKeyToSkKey(keysym));
- long uni = keysym2ucs(keysym);
- if (uni != -1) {
- window->handleChar((SkUnichar) uni);
- }
- break;
- }
- case KeyRelease:
- //SkDebugf("released key %i\n", evt.xkey.keycode);
- window->handleKeyUp(XKeyToSkKey(XKeycodeToKeysym(dsp, evt.xkey.keycode, 0)));
- break;
- case ClientMessage:
- if (SkEvent::ProcessEvent()) {
- post_linuxevent();
- }
- break;
- default:
- // Do nothing for other events
- break;
- }
- }
-
- XFreeGC(dsp, gc);
- XDestroyWindow(dsp, win);
- XCloseDisplay(dsp);
+ gWindow->loop();
application_term();
return 0;
void SkEvent::SignalNonEmptyQueue()
{
- post_linuxevent();
+ if (gWindow)
+ gWindow->post_linuxevent();
+ else
+ while (SkEvent::ProcessEvent());
}
void SkEvent::SignalQueueTimer(SkMSec delay)
#generate debugging info
CFLAGS = -g
-SRC_LIST := main.cpp SkOSWindow_Unix.cpp SkXMLParser_empty.cpp SkDebug.cpp
+SRC_LIST := main.cpp SkOSWindow_Unix.cpp SkXMLParser_empty.cpp SkDebug.cpp ../gpu/src/unix/GrGLDefaultInterface_unix.cpp
#views files
include ../src/views/views_files.mk