Fallback implementation for glCopyImageSubData
OS X is missing this function so we fallback to a very slow, GPU->CPU->GPU roundtrip. Fortunately this is needed only rarely so it should not have a noticeable performance imapct. Le bubbling sigh!
This commit is contained in:
parent
6b01b9613a
commit
063ec7dc02
47
kitty/gl.h
47
kitty/gl.h
@ -127,10 +127,6 @@ _glewInit(PyObject UNUSED *self) {
|
|||||||
PyErr_Format(PyExc_RuntimeError, "GLEW init failed: %s", glewGetErrorString(err));
|
PyErr_Format(PyExc_RuntimeError, "GLEW init failed: %s", glewGetErrorString(err));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if(!GLEW_ARB_copy_image) {
|
|
||||||
PyErr_SetString(PyExc_RuntimeError, "OpenGL is missing the required ARB_copy_image extension");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
if(!GLEW_ARB_texture_storage) {
|
if(!GLEW_ARB_texture_storage) {
|
||||||
PyErr_SetString(PyExc_RuntimeError, "OpenGL is missing the required ARB_texture_storage extension");
|
PyErr_SetString(PyExc_RuntimeError, "OpenGL is missing the required ARB_texture_storage extension");
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -439,6 +435,10 @@ static PyObject*
|
|||||||
CopyImageSubData(PyObject UNUSED *self, PyObject *args) {
|
CopyImageSubData(PyObject UNUSED *self, PyObject *args) {
|
||||||
int src_target, src_level, srcX, srcY, srcZ, dest_target, dest_level, destX, destY, destZ;
|
int src_target, src_level, srcX, srcY, srcZ, dest_target, dest_level, destX, destY, destZ;
|
||||||
unsigned int src, dest, width, height, depth;
|
unsigned int src, dest, width, height, depth;
|
||||||
|
if(!GLEW_ARB_copy_image) {
|
||||||
|
PyErr_SetString(PyExc_RuntimeError, "OpenGL is missing the required ARB_copy_image extension");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
if (!PyArg_ParseTuple(args, "IiiiiiIiiiiiIII",
|
if (!PyArg_ParseTuple(args, "IiiiiiIiiiiiIII",
|
||||||
&src, &src_target, &src_level, &srcX, &srcY, &srcZ,
|
&src, &src_target, &src_level, &srcX, &srcY, &srcZ,
|
||||||
&dest, &dest_target, &dest_level, &destX, &destY, &destZ,
|
&dest, &dest_target, &dest_level, &destX, &destY, &destZ,
|
||||||
@ -451,6 +451,26 @@ CopyImageSubData(PyObject UNUSED *self, PyObject *args) {
|
|||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static PyObject*
|
||||||
|
copy_image_sub_data(PyObject UNUSED *self, PyObject *args) {
|
||||||
|
int src_target, dest_target;
|
||||||
|
unsigned int width, height, num_levels;
|
||||||
|
if (!PyArg_ParseTuple(args, "iiIII", &src_target, &dest_target, &width, &height, &num_levels)) return NULL;
|
||||||
|
uint8_t *src = (uint8_t*)PyMem_Malloc(5 * width * height * num_levels);
|
||||||
|
if (src == NULL) return PyErr_NoMemory();
|
||||||
|
uint8_t *dest = src + (4 * width * height * num_levels);
|
||||||
|
Py_BEGIN_ALLOW_THREADS;
|
||||||
|
glBindTexture(GL_TEXTURE_2D_ARRAY, src_target);
|
||||||
|
glGetTexImage(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA, GL_UNSIGNED_BYTE, src);
|
||||||
|
glBindTexture(GL_TEXTURE_2D_ARRAY, dest_target);
|
||||||
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||||
|
for(unsigned int i = 0; i < width * height * num_levels; i++) dest[i] = src[4*i];
|
||||||
|
glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, width, height, num_levels, GL_RED, GL_UNSIGNED_BYTE, dest);
|
||||||
|
Py_END_ALLOW_THREADS;
|
||||||
|
PyMem_Free(src);
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
TexSubImage3D(PyObject UNUSED *self, PyObject *args) {
|
TexSubImage3D(PyObject UNUSED *self, PyObject *args) {
|
||||||
int target, level, x, y, z, fmt, type;
|
int target, level, x, y, z, fmt, type;
|
||||||
@ -466,6 +486,21 @@ TexSubImage3D(PyObject UNUSED *self, PyObject *args) {
|
|||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static PyObject*
|
||||||
|
GetTexImage(PyObject UNUSED *self, PyObject *args) {
|
||||||
|
int target, level, fmt, type;
|
||||||
|
PyObject *pixels;
|
||||||
|
if (!PyArg_ParseTuple(args, "iiiiO!", &target, &level, &fmt, &type, &PyLong_Type, &pixels)) return NULL;
|
||||||
|
void *data = PyLong_AsVoidPtr(pixels);
|
||||||
|
if (data == NULL) { PyErr_SetString(PyExc_TypeError, "Not a valid data pointer"); return NULL; }
|
||||||
|
Py_BEGIN_ALLOW_THREADS;
|
||||||
|
glGetTexImage(target, level, fmt, type, data);
|
||||||
|
Py_END_ALLOW_THREADS;
|
||||||
|
CHECK_ERROR;
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
NamedBufferData(PyObject UNUSED *self, PyObject *args) {
|
NamedBufferData(PyObject UNUSED *self, PyObject *args) {
|
||||||
int usage;
|
int usage;
|
||||||
@ -609,7 +644,7 @@ int add_module_gl_constants(PyObject *module) {
|
|||||||
GLC(GL_TEXTURE_MIN_FILTER); GLC(GL_TEXTURE_MAG_FILTER);
|
GLC(GL_TEXTURE_MIN_FILTER); GLC(GL_TEXTURE_MAG_FILTER);
|
||||||
GLC(GL_TEXTURE_WRAP_S); GLC(GL_TEXTURE_WRAP_T);
|
GLC(GL_TEXTURE_WRAP_S); GLC(GL_TEXTURE_WRAP_T);
|
||||||
GLC(GL_UNPACK_ALIGNMENT);
|
GLC(GL_UNPACK_ALIGNMENT);
|
||||||
GLC(GL_R8); GLC(GL_RED); GLC(GL_UNSIGNED_BYTE); GLC(GL_RGB32UI);
|
GLC(GL_R8); GLC(GL_RED); GLC(GL_UNSIGNED_BYTE); GLC(GL_RGB32UI); GLC(GL_RGBA);
|
||||||
GLC(GL_TEXTURE_BUFFER); GLC(GL_STATIC_DRAW); GLC(GL_STREAM_DRAW);
|
GLC(GL_TEXTURE_BUFFER); GLC(GL_STATIC_DRAW); GLC(GL_STREAM_DRAW);
|
||||||
GLC(GL_SRC_ALPHA); GLC(GL_ONE_MINUS_SRC_ALPHA);
|
GLC(GL_SRC_ALPHA); GLC(GL_ONE_MINUS_SRC_ALPHA);
|
||||||
GLC(GL_BLEND); GLC(GL_FLOAT); GLC(GL_ARRAY_BUFFER);
|
GLC(GL_BLEND); GLC(GL_FLOAT); GLC(GL_ARRAY_BUFFER);
|
||||||
@ -619,6 +654,7 @@ int add_module_gl_constants(PyObject *module) {
|
|||||||
|
|
||||||
#define GL_METHODS \
|
#define GL_METHODS \
|
||||||
{"enable_automatic_opengl_error_checking", (PyCFunction)enable_automatic_error_checking, METH_O, NULL}, \
|
{"enable_automatic_opengl_error_checking", (PyCFunction)enable_automatic_error_checking, METH_O, NULL}, \
|
||||||
|
{"copy_image_sub_data", (PyCFunction)copy_image_sub_data, METH_VARARGS, NULL}, \
|
||||||
{"glewInit", (PyCFunction)_glewInit, METH_NOARGS, NULL}, \
|
{"glewInit", (PyCFunction)_glewInit, METH_NOARGS, NULL}, \
|
||||||
METH(Viewport, METH_VARARGS) \
|
METH(Viewport, METH_VARARGS) \
|
||||||
METH(CheckError, METH_NOARGS) \
|
METH(CheckError, METH_NOARGS) \
|
||||||
@ -668,6 +704,7 @@ int add_module_gl_constants(PyObject *module) {
|
|||||||
METH(TexStorage3D, METH_VARARGS) \
|
METH(TexStorage3D, METH_VARARGS) \
|
||||||
METH(CopyImageSubData, METH_VARARGS) \
|
METH(CopyImageSubData, METH_VARARGS) \
|
||||||
METH(TexSubImage3D, METH_VARARGS) \
|
METH(TexSubImage3D, METH_VARARGS) \
|
||||||
|
METH(GetTexImage, METH_VARARGS) \
|
||||||
METH(NamedBufferData, METH_VARARGS) \
|
METH(NamedBufferData, METH_VARARGS) \
|
||||||
METH(BlendFunc, METH_VARARGS) \
|
METH(BlendFunc, METH_VARARGS) \
|
||||||
|
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
# vim:fileencoding=utf-8
|
# vim:fileencoding=utf-8
|
||||||
# License: GPL v3 Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
|
# License: GPL v3 Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
|
||||||
|
|
||||||
|
import sys
|
||||||
from ctypes import addressof, sizeof
|
from ctypes import addressof, sizeof
|
||||||
from functools import lru_cache
|
from functools import lru_cache
|
||||||
from threading import Lock
|
from threading import Lock
|
||||||
@ -23,8 +24,9 @@ from .fast_data_types import (
|
|||||||
GL_TEXTURE_BUFFER, GL_RGB32UI, GL_FLOAT, GL_ARRAY_BUFFER, glBindBuffer,
|
GL_TEXTURE_BUFFER, GL_RGB32UI, GL_FLOAT, GL_ARRAY_BUFFER, glBindBuffer,
|
||||||
glPixelStorei, glTexBuffer, glActiveTexture, glTexStorage3D,
|
glPixelStorei, glTexBuffer, glActiveTexture, glTexStorage3D,
|
||||||
glCopyImageSubData, glTexSubImage3D, ITALIC, BOLD, SpriteMap,
|
glCopyImageSubData, glTexSubImage3D, ITALIC, BOLD, SpriteMap,
|
||||||
glEnableVertexAttribArray, glVertexAttribPointer
|
glEnableVertexAttribArray, glVertexAttribPointer, copy_image_sub_data
|
||||||
)
|
)
|
||||||
|
from .utils import safe_print
|
||||||
|
|
||||||
GL_VERSION = (3, 3)
|
GL_VERSION = (3, 3)
|
||||||
VERSION = GL_VERSION[0] * 100 + GL_VERSION[1] * 10
|
VERSION = GL_VERSION[0] * 100 + GL_VERSION[1] * 10
|
||||||
@ -120,8 +122,18 @@ class Sprites:
|
|||||||
ynum = self.backend.ynum
|
ynum = self.backend.ynum
|
||||||
if self.backend.z == 0:
|
if self.backend.z == 0:
|
||||||
ynum -= 1 # Only copy the previous rows
|
ynum -= 1 # Only copy the previous rows
|
||||||
glCopyImageSubData(self.texture_id, tgt, 0, 0, 0, 0, tex, tgt, 0, 0, 0, 0,
|
try:
|
||||||
width, ynum * self.cell_height, self.last_num_of_layers)
|
glCopyImageSubData(self.texture_id, tgt, 0, 0, 0, 0, tex, tgt, 0, 0, 0, 0,
|
||||||
|
width, ynum * self.cell_height, self.last_num_of_layers)
|
||||||
|
except RuntimeError:
|
||||||
|
# OpenGL does not have ARB_copy_image
|
||||||
|
if not hasattr(self, 'realloc_warned'):
|
||||||
|
safe_print(
|
||||||
|
'WARNING: Your system\'s OpenGL implementation does not have glCopyImageSubData, falling back to a slower implementation',
|
||||||
|
file=sys.stderr)
|
||||||
|
self.realloc_warned = True
|
||||||
|
copy_image_sub_data(self.texture_id, tex, width, ynum * self.cell_height, self.last_num_of_layers)
|
||||||
|
glBindTexture(tgt, tex)
|
||||||
glDeleteTexture(self.texture_id)
|
glDeleteTexture(self.texture_id)
|
||||||
self.last_num_of_layers = znum
|
self.last_num_of_layers = znum
|
||||||
self.last_ynum = self.backend.ynum
|
self.last_ynum = self.backend.ynum
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user