diff --git a/kitty/__init__.py b/kitty/__init__.py index 81be94848..8b1378917 100644 --- a/kitty/__init__.py +++ b/kitty/__init__.py @@ -1,5 +1 @@ -import OpenGL -# PyOpenGL error checking is extremely slow, so disable it, since by default it -# runs for every call into the OpenGL API -OpenGL.ERROR_CHECKING = False diff --git a/kitty/data-types.c b/kitty/data-types.c index b4885ac0e..24f4b0ff3 100644 --- a/kitty/data-types.c +++ b/kitty/data-types.c @@ -9,24 +9,26 @@ extern int init_LineBuf(PyObject *); extern int init_Cursor(PyObject *); extern int init_Line(PyObject *); +#include "gl.h" static PyMethodDef module_methods[] = { + GL_METHODS {NULL, NULL, 0, NULL} /* Sentinel */ }; + static struct PyModuleDef module = { - PyModuleDef_HEAD_INIT, - "fast_data_types", /* name of module */ - NULL, - -1, - module_methods + .m_base = PyModuleDef_HEAD_INIT, + .m_name = "fast_data_types", /* name of module */ + .m_doc = NULL, + .m_size = -1, + .m_methods = module_methods }; PyMODINIT_FUNC PyInit_fast_data_types(void) { PyObject *m; - m = PyModule_Create(&module); if (m == NULL) return NULL; diff --git a/kitty/develop_gl.py b/kitty/develop_gl.py index 16528c1c0..a0a542575 100644 --- a/kitty/develop_gl.py +++ b/kitty/develop_gl.py @@ -9,6 +9,7 @@ import sys from kitty.shaders import ShaderProgram, GL_VERSION, Sprites, check_for_required_extensions from kitty.fonts import set_font_family, cell_size from kitty.char_grid import calculate_vertices, cell_shader +from kitty.fast_data_types import glViewport, enable_automatic_opengl_error_checking def rectangle_uv(left=0, top=0, right=1, bottom=1): @@ -37,7 +38,7 @@ class Renderer: self.do_layout() def on_resize(self, window, w, h): - gl.glViewport(0, 0, w, h) + glViewport(0, 0, w, h) self.w, self.h = w, h self.do_layout() @@ -137,6 +138,7 @@ def main(): glfw.glfwSetErrorCallback(on_error) if not glfw.glfwInit(): raise SystemExit('GLFW initialization failed') + enable_automatic_opengl_error_checking(True) set_font_family('monospace', 144) try: _main() diff --git a/kitty/gl.h b/kitty/gl.h new file mode 100644 index 000000000..f29cc17f7 --- /dev/null +++ b/kitty/gl.h @@ -0,0 +1,63 @@ +/* + * gl.c + * Copyright (C) 2016 Kovid Goyal + * + * Distributed under terms of the GPL3 license. + */ + +#include "data-types.h" +#include + +#define STRINGIFY(x) #x +#define METH(name, argtype) {STRINGIFY(gl##name), (PyCFunction)name, argtype, NULL}, + +static int _enable_error_checking = 1; + +#define SET_GL_ERR \ + switch(glGetError()) { \ + case GL_NO_ERROR: break; \ + case GL_INVALID_ENUM: \ + PyErr_SetString(PyExc_ValueError, "An enum value is invalid (GL_INVALID_ENUM)"); break; \ + case GL_INVALID_VALUE: \ + PyErr_SetString(PyExc_ValueError, "An numeric value is invalid (GL_INVALID_VALUE)"); break; \ + case GL_INVALID_OPERATION: \ + PyErr_SetString(PyExc_ValueError, "This operation is not allowed in the current state (GL_INVALID_OPERATION)"); break; \ + case GL_INVALID_FRAMEBUFFER_OPERATION: \ + PyErr_SetString(PyExc_ValueError, "The framebuffer object is not complete (GL_INVALID_FRAMEBUFFER_OPERATION)"); break; \ + case GL_OUT_OF_MEMORY: \ + PyErr_SetString(PyExc_MemoryError, "There is not enough memory left to execute the command. (GL_OUT_OF_MEMORY)"); break; \ + case GL_STACK_UNDERFLOW: \ + PyErr_SetString(PyExc_OverflowError, "An attempt has been made to perform an operation that would cause an internal stack to underflow. (GL_STACK_UNDERFLOW)"); break; \ + case GL_STACK_OVERFLOW: \ + PyErr_SetString(PyExc_OverflowError, "An attempt has been made to perform an operation that would cause an internal stack to underflow. (GL_STACK_UNDERFLOW)"); break; \ + default: \ + PyErr_SetString(PyExc_RuntimeError, "An unknown OpenGL error occurred."); break; \ + } + +#define CHECK_ERROR if (_enable_error_checking) { SET_GL_ERR; if (PyErr_Occurred()) return NULL; } + +static PyObject* +enable_automatic_error_checking(PyObject UNUSED *self, PyObject *val) { + _enable_error_checking = PyObject_IsTrue(val) ? 1 : 0; + Py_RETURN_NONE; +} + +static PyObject* +Viewport(PyObject UNUSED *self, PyObject *args) { + unsigned int x, y, w, h; + if (!PyArg_ParseTuple(args, "IIII", &x, &y, &w, &h)) return NULL; + glViewport(x, y, w, h); + CHECK_ERROR; + Py_RETURN_NONE; +} + +static PyObject* +CheckError(PyObject UNUSED *self) { + CHECK_ERROR; Py_RETURN_NONE; +} + +#define GL_METHODS \ + {"enable_automatic_opengl_error_checking", (PyCFunction)enable_automatic_error_checking, METH_O, NULL}, \ + METH(Viewport, METH_VARARGS) \ + METH(CheckError, METH_NOARGS) \ + diff --git a/setup.py b/setup.py index 7457df332..a974d7741 100644 --- a/setup.py +++ b/setup.py @@ -21,6 +21,10 @@ version = tuple(map(int, re.search(r"^version = \((\d+), (\d+), (\d+)\)", consta cflags = ldflags = cc = ldpaths = None +def pkg_config(pkg, *args): + return shlex.split(subprocess.check_output(['pkg-config', pkg] + list(args)).decode('utf-8')) + + def init_env(): global cflags, ldflags, cc, ldpaths cc = os.environ.get('CC', 'gcc') @@ -34,11 +38,12 @@ def init_env(): ldflags += shlex.split(os.environ.get('LDFLAGS', '')) cflags.append('-pthread') + cflags.extend(pkg_config('glew', '--cflags-only-I')) ldflags.append('-pthread') ldflags.append('-shared') cflags.append('-I' + sysconfig.get_config_var('CONFINCLUDEPY')) lib = sysconfig.get_config_var('LDLIBRARY')[3:-3] - ldpaths = ['-L' + sysconfig.get_config_var('LIBDIR'), '-l' + lib] + ldpaths = ['-L' + sysconfig.get_config_var('LIBDIR'), '-l' + lib] + pkg_config('glew', '--libs') try: os.mkdir(build_dir)