diff options
author | YimingWu <xp8110@outlook.com> | 2021-03-10 02:59:23 +0300 |
---|---|---|
committer | YimingWu <xp8110@outlook.com> | 2021-03-10 02:59:23 +0300 |
commit | 9166075cbeb4163566bf943f7844759702147a8a (patch) | |
tree | 1109502274df385ceabfbb3707a56e164c121edc /source/blender/python | |
parent | 10c097eff0416368bf769c3349e9c81c12f19d5f (diff) | |
parent | 53b82efed66baddff3b7ef6c93a919ef10f4ef42 (diff) |
Merge remote-tracking branch 'origin/master' into lanpr-under-gp
Diffstat (limited to 'source/blender/python')
-rw-r--r-- | source/blender/python/gpu/gpu_py_offscreen.c | 14 | ||||
-rw-r--r-- | source/blender/python/intern/CMakeLists.txt | 2 | ||||
-rw-r--r-- | source/blender/python/intern/bpy.c | 3 | ||||
-rw-r--r-- | source/blender/python/intern/bpy_library_load.c | 16 | ||||
-rw-r--r-- | source/blender/python/intern/bpy_rna.c | 20 | ||||
-rw-r--r-- | source/blender/python/intern/bpy_rna_data.c | 219 | ||||
-rw-r--r-- | source/blender/python/intern/bpy_rna_data.h | 29 | ||||
-rw-r--r-- | source/blender/python/intern/bpy_rna_types_capi.c | 7 |
8 files changed, 295 insertions, 15 deletions
diff --git a/source/blender/python/gpu/gpu_py_offscreen.c b/source/blender/python/gpu/gpu_py_offscreen.c index dff4b169f9a..4a2b359bf39 100644 --- a/source/blender/python/gpu/gpu_py_offscreen.c +++ b/source/blender/python/gpu/gpu_py_offscreen.c @@ -96,20 +96,20 @@ static int pygpu_offscreen_valid_check(BPyGPUOffScreen *py_ofs) typedef struct { PyObject_HEAD /* required python macro */ - BPyGPUOffScreen *py_offs; + BPyGPUOffScreen *py_offscreen; int level; bool is_explicitly_bound; /* Bound by "bind" method. */ } OffScreenStackContext; static void pygpu_offscreen_stack_context__tp_dealloc(OffScreenStackContext *self) { - Py_DECREF(self->py_offs); + Py_DECREF(self->py_offscreen); PyObject_DEL(self); } static PyObject *pygpu_offscreen_stack_context_enter(OffScreenStackContext *self) { - BPY_GPU_OFFSCREEN_CHECK_OBJ(self->py_offs); + BPY_GPU_OFFSCREEN_CHECK_OBJ(self->py_offscreen); if (!self->is_explicitly_bound) { if (self->level != -1) { @@ -117,7 +117,7 @@ static PyObject *pygpu_offscreen_stack_context_enter(OffScreenStackContext *self return NULL; } - GPU_offscreen_bind(self->py_offs->ofs, true); + GPU_offscreen_bind(self->py_offscreen->ofs, true); self->level = GPU_framebuffer_stack_level_get(); } @@ -127,7 +127,7 @@ static PyObject *pygpu_offscreen_stack_context_enter(OffScreenStackContext *self static PyObject *pygpu_offscreen_stack_context_exit(OffScreenStackContext *self, PyObject *UNUSED(args)) { - BPY_GPU_OFFSCREEN_CHECK_OBJ(self->py_offs); + BPY_GPU_OFFSCREEN_CHECK_OBJ(self->py_offscreen); if (self->level == -1) { PyErr_SetString(PyExc_RuntimeError, "Not yet in use\n"); @@ -140,7 +140,7 @@ static PyObject *pygpu_offscreen_stack_context_exit(OffScreenStackContext *self, PyExc_RuntimeError, "Level of bind mismatch, expected %d, got %d\n", self->level, level); } - GPU_offscreen_unbind(self->py_offs->ofs, true); + GPU_offscreen_unbind(self->py_offscreen->ofs, true); Py_RETURN_NONE; } @@ -166,7 +166,7 @@ static PyObject *pygpu_offscreen_bind(BPyGPUOffScreen *self) { OffScreenStackContext *ret = PyObject_New(OffScreenStackContext, &PyGPUOffscreenStackContext_Type); - ret->py_offs = self; + ret->py_offscreen = self; ret->level = -1; ret->is_explicitly_bound = false; Py_INCREF(self); diff --git a/source/blender/python/intern/CMakeLists.txt b/source/blender/python/intern/CMakeLists.txt index 352787b4fdb..822ab0bd969 100644 --- a/source/blender/python/intern/CMakeLists.txt +++ b/source/blender/python/intern/CMakeLists.txt @@ -75,6 +75,7 @@ set(SRC bpy_rna_anim.c bpy_rna_array.c bpy_rna_callback.c + bpy_rna_data.c bpy_rna_driver.c bpy_rna_gizmo.c bpy_rna_id_collection.c @@ -113,6 +114,7 @@ set(SRC bpy_rna.h bpy_rna_anim.h bpy_rna_callback.h + bpy_rna_data.h bpy_rna_driver.h bpy_rna_gizmo.h bpy_rna_id_collection.h diff --git a/source/blender/python/intern/bpy.c b/source/blender/python/intern/bpy.c index 74fc8bcfec9..547cf2ad38f 100644 --- a/source/blender/python/intern/bpy.c +++ b/source/blender/python/intern/bpy.c @@ -44,6 +44,7 @@ #include "bpy_operator.h" #include "bpy_props.h" #include "bpy_rna.h" +#include "bpy_rna_data.h" #include "bpy_rna_gizmo.h" #include "bpy_rna_id_collection.h" #include "bpy_rna_types_capi.h" @@ -425,6 +426,8 @@ void BPy_init_modules(struct bContext *C) /* needs to be first so bpy_types can run */ BPY_library_load_type_ready(); + BPY_rna_data_context_type_ready(); + BPY_rna_gizmo_module(mod); bpy_import_test("bpy_types"); diff --git a/source/blender/python/intern/bpy_library_load.c b/source/blender/python/intern/bpy_library_load.c index 03771a8c294..1ee14df24cf 100644 --- a/source/blender/python/intern/bpy_library_load.c +++ b/source/blender/python/intern/bpy_library_load.c @@ -34,6 +34,7 @@ #include "BLI_string.h" #include "BLI_utildefines.h" +#include "BKE_context.h" #include "BKE_idtype.h" #include "BKE_lib_id.h" #include "BKE_main.h" @@ -67,8 +68,10 @@ typedef struct { BlendHandle *blo_handle; int flag; PyObject *dict; - /* Borrowed reference to the `bmain`, taken from the RNA instance of #RNA_BlendDataLibraries. */ + /* Borrowed reference to the `bmain`, taken from the RNA instance of #RNA_BlendDataLibraries. + * Defaults to #G.main, Otherwise use a temporary #Main when `bmain_is_temp` is true. */ Main *bmain; + bool bmain_is_temp; } BPy_Library; static PyObject *bpy_lib_load(BPy_PropertyRNA *self, PyObject *args, PyObject *kwds); @@ -185,6 +188,7 @@ PyDoc_STRVAR( " :type assets_only: bool\n"); static PyObject *bpy_lib_load(BPy_PropertyRNA *self, PyObject *args, PyObject *kw) { + Main *bmain_base = CTX_data_main(BPY_context_get()); Main *bmain = self->ptr.data; /* Typically #G_MAIN */ BPy_Library *ret; const char *filename = NULL; @@ -212,6 +216,7 @@ static PyObject *bpy_lib_load(BPy_PropertyRNA *self, PyObject *args, PyObject *k BLI_path_abs(ret->abspath, BKE_main_blendfile_path(bmain)); ret->bmain = bmain; + ret->bmain_is_temp = (bmain != bmain_base); ret->blo_handle = NULL; ret->flag = ((is_link ? FILE_LINK : 0) | (is_rel ? FILE_RELPATH : 0) | @@ -344,8 +349,9 @@ static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args)) BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, true); /* here appending/linking starts */ + const int id_tag_extra = self->bmain_is_temp ? LIB_TAG_TEMP_MAIN : 0; struct LibraryLink_Params liblink_params; - BLO_library_link_params_init(&liblink_params, bmain, self->flag); + BLO_library_link_params_init(&liblink_params, bmain, self->flag, id_tag_extra); mainl = BLO_library_link_begin(&(self->blo_handle), self->relpath, &liblink_params); @@ -372,6 +378,12 @@ static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args)) ID *id = BLO_library_link_named_part( mainl, &(self->blo_handle), idcode, item_idname, &liblink_params); if (id) { + + if (self->bmain_is_temp) { + /* If this fails, #LibraryLink_Params.id_tag_extra is not being applied. */ + BLI_assert(id->tag & LIB_TAG_TEMP_MAIN); + } + #ifdef USE_RNA_DATABLOCKS /* swap name for pointer to the id */ item_dst = PyCapsule_New((void *)id, NULL, NULL); diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index cdf121a6864..7a43c9cb997 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -2061,6 +2061,19 @@ static int pyrna_py_to_prop( Py_XDECREF(value_new); return -1; } + + if (value_owner_id->tag & LIB_TAG_TEMP_MAIN) { + /* Allow passing temporary ID's to functions, but not attribute assignment. */ + if (ptr->type != &RNA_Function) { + PyErr_Format(PyExc_TypeError, + "%.200s %.200s.%.200s ID type assignment is temporary, can't assign", + error_prefix, + RNA_struct_identifier(ptr->type), + RNA_property_identifier(prop)); + Py_XDECREF(value_new); + return -1; + } + } } } @@ -4598,13 +4611,12 @@ static PyObject *pyrna_prop_collection_getattro(BPy_PropertyRNA *self, PyObject #else { /* Could just do this except for 1 awkward case. - * PyObject_GenericGetAttr((PyObject *)self, pyname); - * so as to support 'bpy.data.library.load()' - * note, this _only_ supports static methods */ + * `PyObject_GenericGetAttr((PyObject *)self, pyname);` + * so as to support `bpy.data.library.load()` */ PyObject *ret = PyObject_GenericGetAttr((PyObject *)self, pyname); - if (ret == NULL && name[0] != '_') { /* Avoid inheriting __call__ and similar. */ + if (ret == NULL && name[0] != '_') { /* Avoid inheriting `__call__` and similar. */ /* Since this is least common case, handle it last. */ PointerRNA r_ptr; if (RNA_property_collection_type_get(&self->ptr, self->prop, &r_ptr)) { diff --git a/source/blender/python/intern/bpy_rna_data.c b/source/blender/python/intern/bpy_rna_data.c new file mode 100644 index 00000000000..3771cc05490 --- /dev/null +++ b/source/blender/python/intern/bpy_rna_data.c @@ -0,0 +1,219 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup pythonintern + * + * This file defines the API to support temporarily creating #Main data. + * The only use case for this is currently to support temporarily loading data-blocks + * which can be freed, without them polluting the current #G_MAIN. + * + * This is exposed via a context manager `bpy.types.BlendData.temp_data(...)` + * which returns a new `bpy.types.BlendData` that is freed once the context manager exits. + */ + +#include <Python.h> +#include <stddef.h> + +#include "BLI_string.h" +#include "BLI_utildefines.h" + +#include "BKE_global.h" +#include "BKE_main.h" + +#include "RNA_access.h" + +#include "bpy_rna.h" +#include "bpy_rna_data.h" + +typedef struct { + PyObject_HEAD /* required python macro */ + BPy_StructRNA *data_rna; + char filepath[1024]; +} BPy_DataContext; + +static PyObject *bpy_rna_data_temp_data(PyObject *self, PyObject *args, PyObject *kwds); +static PyObject *bpy_rna_data_context_enter(BPy_DataContext *self); +static PyObject *bpy_rna_data_context_exit(BPy_DataContext *self, PyObject *args); + +static PyMethodDef bpy_rna_data_context_methods[] = { + {"__enter__", (PyCFunction)bpy_rna_data_context_enter, METH_NOARGS}, + {"__exit__", (PyCFunction)bpy_rna_data_context_exit, METH_VARARGS}, + {NULL} /* sentinel */ +}; + +static int bpy_rna_data_context_traverse(BPy_DataContext *self, visitproc visit, void *arg) +{ + Py_VISIT(self->data_rna); + return 0; +} + +static int bpy_rna_data_context_clear(BPy_DataContext *self) +{ + Py_CLEAR(self->data_rna); + return 0; +} + +static void bpy_rna_data_context_dealloc(BPy_DataContext *self) +{ + PyObject_GC_UnTrack(self); + Py_CLEAR(self->data_rna); + PyObject_GC_Del(self); +} + +static PyTypeObject bpy_rna_data_context_Type = { + PyVarObject_HEAD_INIT(NULL, 0) "bpy_rna_data_context", /* tp_name */ + sizeof(BPy_DataContext), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)bpy_rna_data_context_dealloc, /* tp_dealloc */ + 0, /* tp_vectorcall_offset */ + NULL, /* getattrfunc tp_getattr; */ + NULL, /* setattrfunc tp_setattr; */ + NULL, + /* tp_compare */ /* DEPRECATED in python 3.0! */ + NULL, /* tp_repr */ + + /* Method suites for standard classes */ + + NULL, /* PyNumberMethods *tp_as_number; */ + NULL, /* PySequenceMethods *tp_as_sequence; */ + NULL, /* PyMappingMethods *tp_as_mapping; */ + + /* More standard operations (here for binary compatibility) */ + + NULL, /* hashfunc tp_hash; */ + NULL, /* ternaryfunc tp_call; */ + NULL, /* reprfunc tp_str; */ + + /* will only use these if this is a subtype of a py class */ + NULL /*PyObject_GenericGetAttr is assigned later */, /* getattrofunc tp_getattro; */ + NULL, /* setattrofunc tp_setattro; */ + + /* Functions to access object as input/output buffer */ + NULL, /* PyBufferProcs *tp_as_buffer; */ + + /*** Flags to define presence of optional/expanded features ***/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* long tp_flags; */ + + NULL, /* char *tp_doc; Documentation string */ + /*** Assigned meaning in release 2.0 ***/ + /* call function for all accessible objects */ + (traverseproc)bpy_rna_data_context_traverse, /* traverseproc tp_traverse; */ + + /* delete references to contained objects */ + (inquiry)bpy_rna_data_context_clear, /* inquiry tp_clear; */ + + /*** Assigned meaning in release 2.1 ***/ + /*** rich comparisons (subclassed) ***/ + NULL, /* richcmpfunc tp_richcompare; */ + + /*** weak reference enabler ***/ + 0, + /*** Added in release 2.2 ***/ + /* Iterators */ + NULL, /* getiterfunc tp_iter; */ + NULL, /* iternextfunc tp_iternext; */ + + /*** Attribute descriptor and subclassing stuff ***/ + bpy_rna_data_context_methods, /* struct PyMethodDef *tp_methods; */ + NULL, /* struct PyMemberDef *tp_members; */ + NULL, /* struct PyGetSetDef *tp_getset; */ + NULL, /* struct _typeobject *tp_base; */ + NULL, /* PyObject *tp_dict; */ + NULL, /* descrgetfunc tp_descr_get; */ + NULL, /* descrsetfunc tp_descr_set; */ + 0, /* long tp_dictoffset; */ + NULL, /* initproc tp_init; */ + NULL, /* allocfunc tp_alloc; */ + NULL, /* newfunc tp_new; */ + /* Low-level free-memory routine */ + NULL, /* freefunc tp_free; */ + /* For PyObject_IS_GC */ + NULL, /* inquiry tp_is_gc; */ + NULL, /* PyObject *tp_bases; */ + /* method resolution order */ + NULL, /* PyObject *tp_mro; */ + NULL, /* PyObject *tp_cache; */ + NULL, /* PyObject *tp_subclasses; */ + NULL, /* PyObject *tp_weaklist; */ + NULL, +}; + +PyDoc_STRVAR(bpy_rna_data_context_load_doc, + ".. method:: temp_data(filepath=None)\n" + "\n" + " A context manager that temporarily creates blender file data.\n" + "\n" + " :arg filepath: The file path for the newly temporary data. " + "When None, the path of the currently open file is used.\n" + " :type filepath: str or NoneType\n" + "\n" + " :return: Blend file data which is freed once the context exists.\n" + " :rtype: :class:`bpy.types.BlendData`\n"); + +static PyObject *bpy_rna_data_temp_data(PyObject *UNUSED(self), PyObject *args, PyObject *kw) +{ + BPy_DataContext *ret; + const char *filepath = NULL; + static const char *_keywords[] = {"filepath", NULL}; + static _PyArg_Parser _parser = {"|$z:temp_data", _keywords, 0}; + if (!_PyArg_ParseTupleAndKeywordsFast(args, kw, &_parser, &filepath)) { + return NULL; + } + + ret = PyObject_GC_New(BPy_DataContext, &bpy_rna_data_context_Type); + + STRNCPY(ret->filepath, filepath ? filepath : G_MAIN->name); + + return (PyObject *)ret; +} + +static PyObject *bpy_rna_data_context_enter(BPy_DataContext *self) +{ + Main *bmain_temp = BKE_main_new(); + PointerRNA ptr; + RNA_pointer_create(NULL, &RNA_BlendData, bmain_temp, &ptr); + + self->data_rna = (BPy_StructRNA *)pyrna_struct_CreatePyObject(&ptr); + + PyObject_GC_Track(self); + + return (PyObject *)self->data_rna; +} + +static PyObject *bpy_rna_data_context_exit(BPy_DataContext *self, PyObject *UNUSED(args)) +{ + BKE_main_free(self->data_rna->ptr.data); + RNA_POINTER_INVALIDATE(&self->data_rna->ptr); + Py_RETURN_NONE; +} + +PyMethodDef BPY_rna_data_context_method_def = { + "temp_data", + (PyCFunction)bpy_rna_data_temp_data, + METH_STATIC | METH_VARARGS | METH_KEYWORDS, + bpy_rna_data_context_load_doc, +}; + +int BPY_rna_data_context_type_ready(void) +{ + if (PyType_Ready(&bpy_rna_data_context_Type) < 0) { + return -1; + } + + return 0; +} diff --git a/source/blender/python/intern/bpy_rna_data.h b/source/blender/python/intern/bpy_rna_data.h new file mode 100644 index 00000000000..b1d226d9dc4 --- /dev/null +++ b/source/blender/python/intern/bpy_rna_data.h @@ -0,0 +1,29 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup pythonintern + */ + +#pragma once + +int BPY_rna_data_context_type_ready(void); + +extern PyMethodDef BPY_rna_data_context_method_def; + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/python/intern/bpy_rna_types_capi.c b/source/blender/python/intern/bpy_rna_types_capi.c index 042f7b6fd67..9b15e84663d 100644 --- a/source/blender/python/intern/bpy_rna_types_capi.c +++ b/source/blender/python/intern/bpy_rna_types_capi.c @@ -36,6 +36,7 @@ #include "bpy_library.h" #include "bpy_rna.h" #include "bpy_rna_callback.h" +#include "bpy_rna_data.h" #include "bpy_rna_id_collection.h" #include "bpy_rna_types_capi.h" #include "bpy_rna_ui.h" @@ -56,6 +57,7 @@ static struct PyMethodDef pyrna_blenddata_methods[] = { {NULL, NULL, 0, NULL}, /* #BPY_rna_id_collection_user_map_method_def */ {NULL, NULL, 0, NULL}, /* #BPY_rna_id_collection_batch_remove_method_def */ {NULL, NULL, 0, NULL}, /* #BPY_rna_id_collection_orphans_purge_method_def */ + {NULL, NULL, 0, NULL}, /* #BPY_rna_data_context_method_def */ {NULL, NULL, 0, NULL}, }; @@ -207,8 +209,9 @@ void BPY_rna_types_extend_capi(void) ARRAY_SET_ITEMS(pyrna_blenddata_methods, BPY_rna_id_collection_user_map_method_def, BPY_rna_id_collection_batch_remove_method_def, - BPY_rna_id_collection_orphans_purge_method_def); - BLI_assert(ARRAY_SIZE(pyrna_blenddata_methods) == 4); + BPY_rna_id_collection_orphans_purge_method_def, + BPY_rna_data_context_method_def); + BLI_assert(ARRAY_SIZE(pyrna_blenddata_methods) == 5); pyrna_struct_type_extend_capi(&RNA_BlendData, pyrna_blenddata_methods, NULL); /* BlendDataLibraries */ |