Changeset View
Changeset View
Standalone View
Standalone View
source/blender/python/gpu/gpu_py_offscreen.c
| Show First 20 Lines • Show All 72 Lines • ▼ Show 20 Lines | if (UNLIKELY(py_offscreen_valid_check(bpygpu) == -1)) { \ | ||||
| return NULL; \ | return NULL; \ | ||||
| } \ | } \ | ||||
| } \ | } \ | ||||
| ((void)0) | ((void)0) | ||||
| /** \} */ | /** \} */ | ||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name Stack (Context Manager) | |||||
| * | |||||
| * Safer alternative to ensure balanced push/pop calls. | |||||
| * | |||||
| * \{ */ | |||||
| typedef struct { | |||||
| PyObject_HEAD /* required python macro */ | |||||
| BPyGPUOffScreen *py_offs; | |||||
| int level; | |||||
| } PyOffScreenStackContext; | |||||
| static void py_offscreen_stack_context__tp_dealloc(PyOffScreenStackContext *self) | |||||
| { | |||||
| Py_DECREF(self->py_offs); | |||||
| PyObject_DEL(self); | |||||
| } | |||||
| static PyObject *py_offscreen_stack_context_enter(PyOffScreenStackContext *self) | |||||
| { | |||||
| BPY_GPU_OFFSCREEN_CHECK_OBJ(self->py_offs); | |||||
| /* sanity - should never happen */ | |||||
| if (self->level != -1) { | |||||
| PyErr_SetString(PyExc_RuntimeError, "Already in use"); | |||||
| return NULL; | |||||
| } | |||||
| GPU_offscreen_bind(self->py_offs->ofs, true); | |||||
| self->level = GPU_framebuffer_stack_level_get(); | |||||
| Py_RETURN_NONE; | |||||
| } | |||||
| static PyObject *py_offscreen_stack_context_exit(PyOffScreenStackContext *self, | |||||
| PyObject *UNUSED(args)) | |||||
| { | |||||
| BPY_GPU_OFFSCREEN_CHECK_OBJ(self->py_offs); | |||||
| /* sanity - should never happen */ | |||||
| if (self->level == -1) { | |||||
| fprintf(stderr, "Not yet in use\n"); | |||||
| return NULL; | |||||
| } | |||||
| const int level = GPU_framebuffer_stack_level_get(); | |||||
| if (level != self->level) { | |||||
| fprintf(stderr, "Level of bind mismatch, expected %d, got %d\n", self->level, level); | |||||
campbellbarton: Should be `PyErr_Format` | |||||
| } | |||||
| GPU_offscreen_unbind(self->py_offs->ofs, true); | |||||
| Py_RETURN_NONE; | |||||
| } | |||||
| static PyMethodDef py_offscreen_stack_context_methods[] = { | |||||
| {"__enter__", (PyCFunction)py_offscreen_stack_context_enter, METH_NOARGS}, | |||||
| {"__exit__", (PyCFunction)py_offscreen_stack_context_exit, METH_VARARGS}, | |||||
| {NULL}, | |||||
| }; | |||||
| static PyTypeObject py_offscreen_stack_context_Type = { | |||||
| PyVarObject_HEAD_INIT(NULL, 0).tp_name = "GPUFrameBufferStackContext", | |||||
| .tp_basicsize = sizeof(PyOffScreenStackContext), | |||||
| .tp_dealloc = (destructor)py_offscreen_stack_context__tp_dealloc, | |||||
| .tp_flags = Py_TPFLAGS_DEFAULT, | |||||
| .tp_methods = py_offscreen_stack_context_methods, | |||||
| }; | |||||
| PyDoc_STRVAR(py_offscreen_bind_doc, | |||||
| ".. function:: bind()\n" | |||||
| "\n" | |||||
| " Context manager to ensure balanced bind calls, even in the case of an error.\n"); | |||||
| static PyObject *py_offscreen_bind(BPyGPUOffScreen *self) | |||||
| { | |||||
| PyOffScreenStackContext *ret = PyObject_New(PyOffScreenStackContext, | |||||
| &py_offscreen_stack_context_Type); | |||||
| ret->py_offs = self; | |||||
| ret->level = -1; | |||||
| Py_INCREF(self); | |||||
| return (PyObject *)ret; | |||||
| } | |||||
| /** \} */ | |||||
| /* -------------------------------------------------------------------- */ | |||||
| /** \name GPUOffscreen Type | /** \name GPUOffscreen Type | ||||
| * \{ */ | * \{ */ | ||||
| static PyObject *py_offscreen_new(PyTypeObject *UNUSED(self), PyObject *args, PyObject *kwds) | static PyObject *py_offscreen_new(PyTypeObject *UNUSED(self), PyObject *args, PyObject *kwds) | ||||
| { | { | ||||
| BPYGPU_IS_INIT_OR_ERROR_OBJ; | BPYGPU_IS_INIT_OR_ERROR_OBJ; | ||||
| GPUOffScreen *ofs = NULL; | GPUOffScreen *ofs = NULL; | ||||
| int width, height; | int width, height; | ||||
| char err_out[256]; | char err_out[256]; | ||||
| static const char *_keywords[] = {"width", "height", NULL}; | static const char *_keywords[] = {"width", "height", NULL}; | ||||
| static _PyArg_Parser _parser = {"ii|i:GPUOffScreen.__new__", _keywords, 0}; | static _PyArg_Parser _parser = {"ii:GPUOffScreen.__new__", _keywords, 0}; | ||||
| if (!_PyArg_ParseTupleAndKeywordsFast(args, kwds, &_parser, &width, &height)) { | if (!_PyArg_ParseTupleAndKeywordsFast(args, kwds, &_parser, &width, &height)) { | ||||
| return NULL; | return NULL; | ||||
| } | } | ||||
| if (GPU_context_active_get()) { | if (GPU_context_active_get()) { | ||||
| ofs = GPU_offscreen_create(width, height, true, false, err_out); | ofs = GPU_offscreen_create(width, height, true, false, err_out); | ||||
| } | } | ||||
| else { | else { | ||||
| Show All 29 Lines | |||||
| static PyObject *py_offscreen_color_texture_get(BPyGPUOffScreen *self, void *UNUSED(type)) | static PyObject *py_offscreen_color_texture_get(BPyGPUOffScreen *self, void *UNUSED(type)) | ||||
| { | { | ||||
| BPY_GPU_OFFSCREEN_CHECK_OBJ(self); | BPY_GPU_OFFSCREEN_CHECK_OBJ(self); | ||||
| GPUTexture *texture = GPU_offscreen_color_texture(self->ofs); | GPUTexture *texture = GPU_offscreen_color_texture(self->ofs); | ||||
| return PyLong_FromLong(GPU_texture_opengl_bindcode(texture)); | return PyLong_FromLong(GPU_texture_opengl_bindcode(texture)); | ||||
| } | } | ||||
| PyDoc_STRVAR( | PyDoc_STRVAR( | ||||
| py_offscreen_bind_doc, | |||||
| ".. method:: bind(save=True)\n" | |||||
| "\n" | |||||
| " Bind the offscreen object.\n" | |||||
| " To make sure that the offscreen gets unbind whether an exception occurs or not,\n" | |||||
| " pack it into a `with` statement.\n" | |||||
| "\n" | |||||
| " :arg save: Save the current OpenGL state, so that it can be restored when unbinding.\n" | |||||
| " :type save: `bool`\n"); | |||||
| static PyObject *py_offscreen_bind(BPyGPUOffScreen *self, PyObject *args, PyObject *kwds) | |||||
| { | |||||
| BPY_GPU_OFFSCREEN_CHECK_OBJ(self); | |||||
| bool save = true; | |||||
| static const char *_keywords[] = {"save", NULL}; | |||||
| static _PyArg_Parser _parser = {"|O&:bind", _keywords, 0}; | |||||
| if (!_PyArg_ParseTupleAndKeywordsFast(args, kwds, &_parser, PyC_ParseBool, &save)) { | |||||
| return NULL; | |||||
| } | |||||
| GPU_offscreen_bind(self->ofs, save); | |||||
| GPU_apply_state(); | |||||
| self->is_saved = save; | |||||
| Py_INCREF(self); | |||||
| return (PyObject *)self; | |||||
| } | |||||
| PyDoc_STRVAR(py_offscreen_unbind_doc, | |||||
| ".. method:: unbind(restore=True)\n" | |||||
| "\n" | |||||
| " Unbind the offscreen object.\n" | |||||
| "\n" | |||||
| " :arg restore: Restore the OpenGL state, can only be used when the state has been " | |||||
| "saved before.\n" | |||||
| " :type restore: `bool`\n"); | |||||
| static PyObject *py_offscreen_unbind(BPyGPUOffScreen *self, PyObject *args, PyObject *kwds) | |||||
| { | |||||
| bool restore = true; | |||||
| BPY_GPU_OFFSCREEN_CHECK_OBJ(self); | |||||
| static const char *_keywords[] = {"restore", NULL}; | |||||
| static _PyArg_Parser _parser = {"|O&:unbind", _keywords, 0}; | |||||
| if (!_PyArg_ParseTupleAndKeywordsFast(args, kwds, &_parser, PyC_ParseBool, &restore)) { | |||||
| return NULL; | |||||
| } | |||||
| GPU_offscreen_unbind(self->ofs, restore); | |||||
| GPU_apply_state(); | |||||
| Py_RETURN_NONE; | |||||
| } | |||||
| PyDoc_STRVAR( | |||||
| py_offscreen_draw_view3d_doc, | py_offscreen_draw_view3d_doc, | ||||
| ".. method:: draw_view3d(scene, view_layer, view3d, region, view_matrix, projection_matrix)\n" | ".. method:: draw_view3d(scene, view_layer, view3d, region, view_matrix, projection_matrix)\n" | ||||
| "\n" | "\n" | ||||
| " Draw the 3d viewport in the offscreen object.\n" | " Draw the 3d viewport in the offscreen object.\n" | ||||
| "\n" | "\n" | ||||
| " :arg scene: Scene to draw.\n" | " :arg scene: Scene to draw.\n" | ||||
| " :type scene: :class:`bpy.types.Scene`\n" | " :type scene: :class:`bpy.types.Scene`\n" | ||||
| " :arg view_layer: View layer to draw.\n" | " :arg view_layer: View layer to draw.\n" | ||||
| ▲ Show 20 Lines • Show All 88 Lines • ▼ Show 20 Lines | |||||
| { | { | ||||
| BPY_GPU_OFFSCREEN_CHECK_OBJ(self); | BPY_GPU_OFFSCREEN_CHECK_OBJ(self); | ||||
| GPU_offscreen_free(self->ofs); | GPU_offscreen_free(self->ofs); | ||||
| self->ofs = NULL; | self->ofs = NULL; | ||||
| Py_RETURN_NONE; | Py_RETURN_NONE; | ||||
| } | } | ||||
| static PyObject *py_offscreen_bind_context_enter(BPyGPUOffScreen *UNUSED(self)) | |||||
| { | |||||
| Py_RETURN_NONE; | |||||
| } | |||||
| static PyObject *py_offscreen_bind_context_exit(BPyGPUOffScreen *self, PyObject *UNUSED(args)) | |||||
| { | |||||
| GPU_offscreen_unbind(self->ofs, self->is_saved); | |||||
| Py_RETURN_NONE; | |||||
| } | |||||
| static void BPyGPUOffScreen__tp_dealloc(BPyGPUOffScreen *self) | static void BPyGPUOffScreen__tp_dealloc(BPyGPUOffScreen *self) | ||||
| { | { | ||||
| if (self->ofs) { | if (self->ofs) { | ||||
| GPU_offscreen_free(self->ofs); | GPU_offscreen_free(self->ofs); | ||||
| } | } | ||||
| Py_TYPE(self)->tp_free((PyObject *)self); | Py_TYPE(self)->tp_free((PyObject *)self); | ||||
| } | } | ||||
| static PyGetSetDef py_offscreen_getseters[] = { | static PyGetSetDef py_offscreen_getseters[] = { | ||||
| {"color_texture", | {"color_texture", | ||||
| (getter)py_offscreen_color_texture_get, | (getter)py_offscreen_color_texture_get, | ||||
| (setter)NULL, | (setter)NULL, | ||||
| py_offscreen_color_texture_doc, | py_offscreen_color_texture_doc, | ||||
| NULL}, | NULL}, | ||||
| {"width", (getter)py_offscreen_width_get, (setter)NULL, py_offscreen_width_doc, NULL}, | {"width", (getter)py_offscreen_width_get, (setter)NULL, py_offscreen_width_doc, NULL}, | ||||
| {"height", (getter)py_offscreen_height_get, (setter)NULL, py_offscreen_height_doc, NULL}, | {"height", (getter)py_offscreen_height_get, (setter)NULL, py_offscreen_height_doc, NULL}, | ||||
| {NULL, NULL, NULL, NULL, NULL} /* Sentinel */ | {NULL, NULL, NULL, NULL, NULL} /* Sentinel */ | ||||
| }; | }; | ||||
| static struct PyMethodDef py_offscreen_methods[] = { | static struct PyMethodDef py_offscreen_methods[] = { | ||||
| {"bind", (PyCFunction)py_offscreen_bind, METH_VARARGS | METH_KEYWORDS, py_offscreen_bind_doc}, | {"bind", (PyCFunction)py_offscreen_bind, METH_VARARGS | METH_KEYWORDS, py_offscreen_bind_doc}, | ||||
| {"unbind", | |||||
| (PyCFunction)py_offscreen_unbind, | |||||
| METH_VARARGS | METH_KEYWORDS, | |||||
| py_offscreen_unbind_doc}, | |||||
| {"draw_view3d", | {"draw_view3d", | ||||
| (PyCFunction)py_offscreen_draw_view3d, | (PyCFunction)py_offscreen_draw_view3d, | ||||
| METH_VARARGS | METH_KEYWORDS, | METH_VARARGS | METH_KEYWORDS, | ||||
| py_offscreen_draw_view3d_doc}, | py_offscreen_draw_view3d_doc}, | ||||
| {"free", (PyCFunction)py_offscreen_free, METH_NOARGS, py_offscreen_free_doc}, | {"free", (PyCFunction)py_offscreen_free, METH_NOARGS, py_offscreen_free_doc}, | ||||
| {"__enter__", (PyCFunction)py_offscreen_bind_context_enter, METH_NOARGS}, | |||||
| {"__exit__", (PyCFunction)py_offscreen_bind_context_exit, METH_VARARGS}, | |||||
| {NULL, NULL, 0, NULL}, | {NULL, NULL, 0, NULL}, | ||||
| }; | }; | ||||
| PyDoc_STRVAR(py_offscreen_doc, | PyDoc_STRVAR(py_offscreen_doc, | ||||
| ".. class:: GPUOffScreen(width, height)\n" | ".. class:: GPUOffScreen(width, height)\n" | ||||
| "\n" | "\n" | ||||
| " This object gives access to off screen buffers.\n" | " This object gives access to off screen buffers.\n" | ||||
| "\n" | "\n" | ||||
| Show All 34 Lines | |||||
Should be PyErr_Format