From 7ab377f28e51d6f0565c82a1e03b3b902ceea898 Mon Sep 17 00:00:00 2001 From: rdb Date: Mon, 29 Jul 2019 13:07:26 +0200 Subject: [PATCH 1/7] dgui: fix option menu's cancelFrame not working in scrolled frame Fixes #658 --- direct/src/gui/DirectOptionMenu.py | 1 + 1 file changed, 1 insertion(+) diff --git a/direct/src/gui/DirectOptionMenu.py b/direct/src/gui/DirectOptionMenu.py index 24064a25d2..cbf3a2974e 100644 --- a/direct/src/gui/DirectOptionMenu.py +++ b/direct/src/gui/DirectOptionMenu.py @@ -77,6 +77,7 @@ class DirectOptionMenu(DirectButton): state = 'normal') # Make sure this is on top of all the other widgets self.cancelFrame.setBin('gui-popup', 0) + self.cancelFrame.node().setBounds(OmniBoundingVolume()) self.cancelFrame.bind(DGG.B1PRESS, self.hidePopupMenu) # Default action on press is to show popup menu self.bind(DGG.B1PRESS, self.showPopupMenu) From f989bce584ac4169f76b6e26384a772f54676ccc Mon Sep 17 00:00:00 2001 From: rdb Date: Mon, 29 Jul 2019 17:04:30 +0200 Subject: [PATCH 2/7] wgldisplay: don't restore gamma atexit if we never modified it This avoids possible instability (see #685) when this feature isn't even used --- panda/src/wgldisplay/wglGraphicsStateGuardian.cxx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/panda/src/wgldisplay/wglGraphicsStateGuardian.cxx b/panda/src/wgldisplay/wglGraphicsStateGuardian.cxx index ed9b0e0b2c..dc32a1ddcd 100644 --- a/panda/src/wgldisplay/wglGraphicsStateGuardian.cxx +++ b/panda/src/wgldisplay/wglGraphicsStateGuardian.cxx @@ -16,6 +16,7 @@ #include "wglGraphicsBuffer.h" #include "wglGraphicsPipe.h" #include "string_utils.h" +#include TypeHandle wglGraphicsStateGuardian::_type_handle; @@ -49,7 +50,6 @@ wglGraphicsStateGuardian(GraphicsEngine *engine, GraphicsPipe *pipe, _wglCreateContextAttribsARB = nullptr; get_gamma_table(); - atexit(atexit_function); } /** @@ -886,6 +886,12 @@ static_set_gamma(bool restore, PN_stdfloat gamma) { if (SetDeviceGammaRamp (hdc, ramp)) { set = true; + + // Register an atexit handler + static std::atomic_flag gamma_modified = ATOMIC_FLAG_INIT; + if (!gamma_modified.test_and_set()) { + atexit(atexit_function); + } } ReleaseDC (nullptr, hdc); From 7b9f87412aecaafe42ce0bd3e6b496bc142e8d31 Mon Sep 17 00:00:00 2001 From: rdb Date: Tue, 30 Jul 2019 12:07:47 +0200 Subject: [PATCH 3/7] loader: support Python loader plug-ins This allows defining custom loader types from Python code. Packages can use metadata entry points to register file types with the loader. Example code: https://gist.github.com/rdb/cb3c2f4a98ce371c722e3f297b445153 --- direct/src/showbase/Loader.py | 16 + panda/src/pgraph/loaderFileTypeRegistry.h | 3 + .../src/pgraph/loaderFileTypeRegistry_ext.cxx | 66 +++ panda/src/pgraph/loaderFileTypeRegistry_ext.h | 38 ++ panda/src/pgraph/p3pgraph_ext_composite.cxx | 2 + panda/src/pgraph/pythonLoaderFileType.cxx | 409 ++++++++++++++++++ panda/src/pgraph/pythonLoaderFileType.h | 81 ++++ 7 files changed, 615 insertions(+) create mode 100644 panda/src/pgraph/loaderFileTypeRegistry_ext.cxx create mode 100644 panda/src/pgraph/loaderFileTypeRegistry_ext.h create mode 100644 panda/src/pgraph/pythonLoaderFileType.cxx create mode 100644 panda/src/pgraph/pythonLoaderFileType.h diff --git a/direct/src/showbase/Loader.py b/direct/src/showbase/Loader.py index 270b537078..0ded4d3d30 100644 --- a/direct/src/showbase/Loader.py +++ b/direct/src/showbase/Loader.py @@ -147,12 +147,28 @@ class Loader(DirectObject): Loader.loaderIndex += 1 self.accept(self.hook, self.__gotAsyncObject) + if ConfigVariableBool('loader-support-entry-points', True): + self._loadPythonFileTypes() + def destroy(self): self.ignore(self.hook) self.loader.stopThreads() del self.base del self.loader + def _loadPythonFileTypes(self): + import importlib + try: + pkg_resources = importlib.import_module('pkg_resources') + except ImportError: + pkg_resources = None + + if pkg_resources: + registry = LoaderFileTypeRegistry.getGlobalPtr() + + for entry_point in pkg_resources.iter_entry_points('panda3d.loaders'): + registry.register_deferred_type(entry_point) + # model loading funcs def loadModel(self, modelPath, loaderOptions = None, noCache = None, allowInstance = False, okMissing = None, diff --git a/panda/src/pgraph/loaderFileTypeRegistry.h b/panda/src/pgraph/loaderFileTypeRegistry.h index 1cc1cd8f6f..2a4c569329 100644 --- a/panda/src/pgraph/loaderFileTypeRegistry.h +++ b/panda/src/pgraph/loaderFileTypeRegistry.h @@ -36,6 +36,9 @@ public: void register_deferred_type(const std::string &extension, const std::string &library); PUBLISHED: + EXTENSION(void register_type(PyObject *type)); + EXTENSION(void register_deferred_type(PyObject *entry_point)); + int get_num_types() const; LoaderFileType *get_type(int n) const; MAKE_SEQ(get_types, get_num_types, get_type); diff --git a/panda/src/pgraph/loaderFileTypeRegistry_ext.cxx b/panda/src/pgraph/loaderFileTypeRegistry_ext.cxx new file mode 100644 index 0000000000..8fa9ea295e --- /dev/null +++ b/panda/src/pgraph/loaderFileTypeRegistry_ext.cxx @@ -0,0 +1,66 @@ +/** + * PANDA 3D SOFTWARE + * Copyright (c) Carnegie Mellon University. All rights reserved. + * + * All use of this software is subject to the terms of the revised BSD + * license. You should have received a copy of this license along + * with this source code in a file named "LICENSE." + * + * @file loaderFileTypeRegistry_ext.cxx + * @author rdb + * @date 2019-07-30 + */ + +#include "loaderFileTypeRegistry_ext.h" + +#ifdef HAVE_PYTHON + +#include "pythonLoaderFileType.h" + +/** + * Registers a loader file type that is implemented in Python. + */ +void Extension:: +register_type(PyObject *type) { + PythonLoaderFileType *loader = new PythonLoaderFileType(); + + if (loader->init(type)) { + _this->register_type(loader); + } else { + delete loader; + } +} + +/** + * Registers a loader file type from a pkg_resources.EntryPoint object, which + * will be loaded when a file with the extension is encountered. + */ +void Extension:: +register_deferred_type(PyObject *entry_point) { + // The "name" attribute holds the extension. + PyObject *name = PyObject_GetAttrString(entry_point, "name"); + if (name == nullptr) { + Dtool_Raise_TypeError("entry_point argument is missing name attribute"); + return; + } + + const char *name_str; + Py_ssize_t name_len; +#if PY_MAJOR_VERSION >= 3 + name_str = PyUnicode_AsUTF8AndSize(name, &name_len); +#else + if (PyString_AsStringAndSize(name, (char **)&name_str, &name_len) == -1) { + name_str = nullptr; + } +#endif + + if (name_str == nullptr) { + Dtool_Raise_TypeError("entry_point.name is expected to be str"); + return; + } + + PythonLoaderFileType *loader = new PythonLoaderFileType(std::string(name_str, name_len), entry_point); + _this->register_type(loader); +} + +#endif diff --git a/panda/src/pgraph/loaderFileTypeRegistry_ext.h b/panda/src/pgraph/loaderFileTypeRegistry_ext.h new file mode 100644 index 0000000000..63eee84f72 --- /dev/null +++ b/panda/src/pgraph/loaderFileTypeRegistry_ext.h @@ -0,0 +1,38 @@ +/** + * PANDA 3D SOFTWARE + * Copyright (c) Carnegie Mellon University. All rights reserved. + * + * All use of this software is subject to the terms of the revised BSD + * license. You should have received a copy of this license along + * with this source code in a file named "LICENSE." + * + * @file loaderFileTypeRegistry_ext.h + * @author rdb + * @date 2019-07-30 + */ + +#ifndef LOADERFILETYPEREGISTRYEXT_H +#define LOADERFILETYPEREGISTRYEXT_H + +#include "pandabase.h" + +#ifdef HAVE_PYTHON + +#include "extension.h" +#include "loaderFileTypeRegistry.h" +#include "py_panda.h" + +/** + * This class defines the extension methods for LoaderFileTypeRegistry, which are called + * instead of any C++ methods with the same prototype. + */ +template<> +class Extension : public ExtensionBase { +public: + void register_type(PyObject *type); + void register_deferred_type(PyObject *entry_point); +}; + +#endif // HAVE_PYTHON + +#endif diff --git a/panda/src/pgraph/p3pgraph_ext_composite.cxx b/panda/src/pgraph/p3pgraph_ext_composite.cxx index d16f600c0a..37b9012c76 100644 --- a/panda/src/pgraph/p3pgraph_ext_composite.cxx +++ b/panda/src/pgraph/p3pgraph_ext_composite.cxx @@ -1,6 +1,8 @@ +#include "loaderFileTypeRegistry_ext.cxx" #include "nodePath_ext.cxx" #include "nodePathCollection_ext.cxx" #include "pandaNode_ext.cxx" +#include "pythonLoaderFileType.cxx" #include "renderState_ext.cxx" #include "shaderAttrib_ext.cxx" #include "shaderInput_ext.cxx" diff --git a/panda/src/pgraph/pythonLoaderFileType.cxx b/panda/src/pgraph/pythonLoaderFileType.cxx new file mode 100644 index 0000000000..bf563aedb4 --- /dev/null +++ b/panda/src/pgraph/pythonLoaderFileType.cxx @@ -0,0 +1,409 @@ +/** + * PANDA 3D SOFTWARE + * Copyright (c) Carnegie Mellon University. All rights reserved. + * + * All use of this software is subject to the terms of the revised BSD + * license. You should have received a copy of this license along + * with this source code in a file named "LICENSE." + * + * @file pythonLoaderFileType.cxx + * @author rdb + * @date 2019-07-29 + */ + +#include "pythonLoaderFileType.h" + +#ifdef HAVE_PYTHON + +#include "modelRoot.h" +#include "pythonThread.h" +#include "py_panda.h" +#include "virtualFileSystem.h" + +extern struct Dtool_PyTypedObject Dtool_BamCacheRecord; +extern struct Dtool_PyTypedObject Dtool_Filename; +extern struct Dtool_PyTypedObject Dtool_LoaderOptions; +extern struct Dtool_PyTypedObject Dtool_PandaNode; +extern struct Dtool_PyTypedObject Dtool_PythonLoaderFileType; + +TypeHandle PythonLoaderFileType::_type_handle; + +/** + * This constructor expects init() to be called manually. + */ +PythonLoaderFileType:: +PythonLoaderFileType() { + init_type(); +} + +/** + * This constructor expects a single pkg_resources.EntryPoint argument for a + * deferred loader. + */ +PythonLoaderFileType:: +PythonLoaderFileType(std::string extension, PyObject *entry_point) : + _extension(std::move(extension)), + _entry_point(entry_point) { + + init_type(); + Py_INCREF(entry_point); +} + +/** + * Destructor. + */ +PythonLoaderFileType:: +~PythonLoaderFileType() { + if (_entry_point != nullptr || _load_func != nullptr || _save_func != nullptr) { +#if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS) + PyGILState_STATE gstate; + gstate = PyGILState_Ensure(); +#endif + + Py_CLEAR(_entry_point); + Py_CLEAR(_load_func); + Py_CLEAR(_save_func); + +#if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS) + PyGILState_Release(gstate); +#endif + } +} + +/** + * Initializes the fields from the given Python loader object. + */ +bool PythonLoaderFileType:: +init(PyObject *loader) { + nassertr(loader != nullptr, false); + nassertr(_load_func == nullptr, false); + nassertr(_save_func == nullptr, false); + + // Check the extensions member. If we already have a registered extension, + // it must occur in the list. + PyObject *extensions = PyObject_GetAttrString(loader, "extensions"); + if (extensions != nullptr) { + PyObject *sequence = PySequence_Fast(extensions, "extensions must be a sequence"); + PyObject **items = PySequence_Fast_ITEMS(sequence); + Py_ssize_t num_items = PySequence_Fast_GET_SIZE(sequence); + Py_DECREF(extensions); + bool found_extension = false; + + for (Py_ssize_t i = 0; i < num_items; ++i) { + PyObject *extension = items[i]; + const char *extension_str; + Py_ssize_t extension_len; + #if PY_MAJOR_VERSION >= 3 + extension_str = PyUnicode_AsUTF8AndSize(extension, &extension_len); + #else + if (PyString_AsStringAndSize(extension, (char **)&extension_str, &extension_len) == -1) { + extension_str = nullptr; + } + #endif + + if (extension_str == nullptr) { + Py_DECREF(sequence); + return false; + } + + if (_extension.empty()) { + _extension.assign(extension_str, extension_len); + found_extension = true; + } else { + std::string new_extension(extension_str, extension_len); + if (_extension == new_extension) { + found_extension = true; + } else { + if (!_additional_extensions.empty()) { + _additional_extensions += ' '; + } + _additional_extensions += new_extension; + } + } + } + Py_DECREF(sequence); + + if (!found_extension) { + PyObject *repr = PyObject_Repr(loader); + loader_cat.error() + << "Registered extension '" << _extension + << "' does not occur in extensions list of " +#if PY_MAJOR_VERSION >= 3 + << PyUnicode_AsUTF8(repr) << "\n"; +#else + << PyString_AsString(repr) << "\n"; +#endif + Py_DECREF(repr); + return false; + } + } else { + return false; + } + + PyObject *supports_compressed = PyObject_GetAttrString(loader, "supports_compressed"); + if (supports_compressed != nullptr) { + if (supports_compressed == Py_True) { + _supports_compressed = true; + } + else if (supports_compressed == Py_False) { + _supports_compressed = false; + } + else { + Dtool_Raise_TypeError("supports_compressed must be a bool"); + Py_DECREF(supports_compressed); + return false; + } + Py_DECREF(supports_compressed); + } + + _load_func = PyObject_GetAttrString(loader, "load_file"); + _save_func = PyObject_GetAttrString(loader, "save_file"); + PyErr_Clear(); + + if (_load_func == nullptr && _save_func == nullptr) { +#if PY_MAJOR_VERSION >= 3 + PyErr_Format(PyExc_TypeError, + "loader plug-in %R does not define load_file or save_file function", + loader); +#else + PyObject *repr = PyObject_Repr(loader); + PyErr_Format(PyExc_TypeError, + "loader plug-in %s does not define load_file or save_file function", + PyString_AsString(repr)); + Py_DECREF(repr); +#endif + return false; + } + + // We don't need this any more. + Py_CLEAR(_entry_point); + + return true; +} + +/** + * Ensures that the referenced Python module is loaded. + */ +bool PythonLoaderFileType:: +ensure_loaded() const { + if (_load_func != nullptr || _save_func != nullptr) { + return true; + } + nassertr_always(_entry_point != nullptr, false); + +#if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS) + PyGILState_STATE gstate; + gstate = PyGILState_Ensure(); +#endif + + if (loader_cat.is_info()) { + PyObject *repr = PyObject_Repr(_entry_point); + + loader_cat.info() + << "loading file type module: " +#if PY_MAJOR_VERSION >= 3 + << PyUnicode_AsUTF8(repr) << "\n"; +#else + << PyString_AsString(repr) << "\n"; +#endif + Py_DECREF(repr); + } + + PyObject *result = PyObject_CallMethod(_entry_point, (char *)"load", nullptr); + + bool success = false; + if (result != nullptr) { + success = ((PythonLoaderFileType *)this)->init(result); + } else { + PyErr_Clear(); + PyObject *repr = PyObject_Repr(_entry_point); + + loader_cat.error() + << "unable to load " +#if PY_MAJOR_VERSION >= 3 + << PyUnicode_AsUTF8(repr) << "\n"; +#else + << PyString_AsString(repr) << "\n"; +#endif + Py_DECREF(repr); + } + +#if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS) + PyGILState_Release(gstate); +#endif + + return success; +} + +/** + * + */ +std::string PythonLoaderFileType:: +get_name() const { + return "Python loader"; +} + +/** + * + */ +std::string PythonLoaderFileType:: +get_extension() const { + return _extension; +} + +/** + * Returns a space-separated list of extension, in addition to the one + * returned by get_extension(), that are recognized by this converter. + */ +std::string PythonLoaderFileType:: +get_additional_extensions() const { + return _additional_extensions; +} + +/** + * Returns true if this file type can transparently load compressed files + * (with a .pz or .gz extension), false otherwise. + */ +bool PythonLoaderFileType:: +supports_compressed() const { + return ensure_loaded() && _supports_compressed; +} + +/** + * Returns true if the file type can be used to load files, and load_file() is + * supported. Returns false if load_file() is unimplemented and will always + * fail. + */ +bool PythonLoaderFileType:: +supports_load() const { + return ensure_loaded() && _load_func != nullptr; +} + +/** + * Returns true if the file type can be used to save files, and save_file() is + * supported. Returns false if save_file() is unimplemented and will always + * fail. + */ +bool PythonLoaderFileType:: +supports_save() const { + return ensure_loaded() && _save_func != nullptr; +} + +/** + * + */ +PT(PandaNode) PythonLoaderFileType:: +load_file(const Filename &path, const LoaderOptions &options, + BamCacheRecord *record) const { + // Let's check whether the file even exists before calling Python. + VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr(); + PT(VirtualFile) vfile = vfs->get_file(path); + if (vfile == nullptr) { + return nullptr; + } + + if (!supports_load()) { + return nullptr; + } + + if (record != nullptr) { + record->add_dependent_file(vfile); + } + +#if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS) + PyGILState_STATE gstate; + gstate = PyGILState_Ensure(); +#endif + + // Wrap the arguments. + PyObject *args = PyTuple_New(3); + PyTuple_SET_ITEM(args, 0, DTool_CreatePyInstance((void *)&path, Dtool_Filename, false, true)); + PyTuple_SET_ITEM(args, 1, DTool_CreatePyInstance((void *)&options, Dtool_LoaderOptions, false, true)); + if (record != nullptr) { + record->ref(); + PyTuple_SET_ITEM(args, 2, DTool_CreatePyInstanceTyped((void *)record, Dtool_BamCacheRecord, true, false, record->get_type_index())); + } else { + PyTuple_SET_ITEM(args, 2, Py_None); + Py_INCREF(Py_None); + } + + PT(PandaNode) node; + + PyObject *result = PythonThread::call_python_func(_load_func, args); + if (result != nullptr) { + if (DtoolInstance_Check(result)) { + node = (PandaNode *)DtoolInstance_UPCAST(result, Dtool_PandaNode); + } + Py_DECREF(result); + } + + Py_DECREF(args); + + if (node == nullptr) { + PyObject *exc_type = _PyErr_OCCURRED(); + if (!exc_type) { + loader_cat.error() + << "load_file must return valid PandaNode or raise exception\n"; + } else { + loader_cat.error() + << "Loading " << path.get_basename() + << " failed with " << ((PyTypeObject *)exc_type)->tp_name << " exception.\n"; + PyErr_Clear(); + } + } + +#if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS) + PyGILState_Release(gstate); +#endif + + if (node != nullptr && node->is_of_type(ModelRoot::get_class_type())) { + ModelRoot *model_root = DCAST(ModelRoot, node.p()); + model_root->set_fullpath(path); + model_root->set_timestamp(vfile->get_timestamp()); + } + + return node; +} + +/** + * + */ +bool PythonLoaderFileType:: +save_file(const Filename &path, const LoaderOptions &options, + PandaNode *node) const { + if (!supports_save()) { + return false; + } + + nassertr(node != nullptr, false); + node->ref(); + +#if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS) + PyGILState_STATE gstate; + gstate = PyGILState_Ensure(); +#endif + + // Wrap the arguments. + PyObject *args = PyTuple_New(3); + PyTuple_SET_ITEM(args, 0, DTool_CreatePyInstance((void *)&path, Dtool_Filename, false, true)); + PyTuple_SET_ITEM(args, 1, DTool_CreatePyInstance((void *)&options, Dtool_LoaderOptions, false, true)); + PyTuple_SET_ITEM(args, 2, DTool_CreatePyInstanceTyped((void *)node, Dtool_PandaNode, true, false, node->get_type_index())); + + PyObject *result = PythonThread::call_python_func(_load_func, args); + Py_DECREF(args); + if (result != nullptr) { + Py_DECREF(result); + } else { + PyErr_Clear(); + loader_cat.error() + << "save_file failed with an exception.\n"; + } + +#if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS) + PyGILState_Release(gstate); +#endif + + return (result != nullptr); +} + +#endif // HAVE_PYTHON diff --git a/panda/src/pgraph/pythonLoaderFileType.h b/panda/src/pgraph/pythonLoaderFileType.h new file mode 100644 index 0000000000..3d7312208b --- /dev/null +++ b/panda/src/pgraph/pythonLoaderFileType.h @@ -0,0 +1,81 @@ +/** + * PANDA 3D SOFTWARE + * Copyright (c) Carnegie Mellon University. All rights reserved. + * + * All use of this software is subject to the terms of the revised BSD + * license. You should have received a copy of this license along + * with this source code in a file named "LICENSE." + * + * @file pythonLoaderFileType.h + * @author rdb + * @date 2019-07-29 + */ + +#ifndef PYTHONLOADERFILETYPE_H +#define PYTHONLOADERFILETYPE_H + +#include "pandabase.h" + +#ifdef HAVE_PYTHON + +#include "loaderFileType.h" + +/** + * This defines a Python-based loader plug-in. An instance of this can be + * constructed by inheritance and explicitly registered, or it can be created + * by passing in a pkg_resources.EntryPoint instance. + */ +class EXPCL_PANDA_PGRAPH PythonLoaderFileType : public LoaderFileType { +public: + PythonLoaderFileType(); + PythonLoaderFileType(std::string extension, PyObject *entry_point); + ~PythonLoaderFileType(); + + bool init(PyObject *loader); + bool ensure_loaded() const; + + virtual std::string get_name() const override; + virtual std::string get_extension() const override; + virtual std::string get_additional_extensions() const override; + virtual bool supports_compressed() const override; + + virtual bool supports_load() const override; + virtual bool supports_save() const override; + + virtual PT(PandaNode) load_file(const Filename &path, const LoaderOptions &options, + BamCacheRecord *record) const override; + virtual bool save_file(const Filename &path, const LoaderOptions &options, + PandaNode *node) const override; + +private: + std::string _extension; + std::string _additional_extensions; + PyObject *_entry_point = nullptr; + PyObject *_load_func = nullptr; + PyObject *_save_func = nullptr; + bool _supports_compressed = false; + +public: + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + LoaderFileType::init_type(); + register_type(_type_handle, "PythonLoaderFileType", + LoaderFileType::get_class_type()); + } + virtual TypeHandle get_type() const override { + return get_class_type(); + } + virtual TypeHandle force_init_type() override { + init_type(); + return get_class_type(); + } + +private: + static TypeHandle _type_handle; +}; + +#endif // HAVE_PYTHON + +#endif From 93ed9632ac4d96d6958065bf5d76cac4765cf257 Mon Sep 17 00:00:00 2001 From: rdb Date: Tue, 30 Jul 2019 13:28:10 +0200 Subject: [PATCH 4/7] loader: fix incorrect EXPCL that prevents compilation on Windows --- panda/src/pgraph/pythonLoaderFileType.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/panda/src/pgraph/pythonLoaderFileType.h b/panda/src/pgraph/pythonLoaderFileType.h index 3d7312208b..10dc27055b 100644 --- a/panda/src/pgraph/pythonLoaderFileType.h +++ b/panda/src/pgraph/pythonLoaderFileType.h @@ -25,7 +25,7 @@ * constructed by inheritance and explicitly registered, or it can be created * by passing in a pkg_resources.EntryPoint instance. */ -class EXPCL_PANDA_PGRAPH PythonLoaderFileType : public LoaderFileType { +class PythonLoaderFileType : public LoaderFileType { public: PythonLoaderFileType(); PythonLoaderFileType(std::string extension, PyObject *entry_point); From aea5ee8c7a58a3e9bfb8c6ea38472fb4d56353f1 Mon Sep 17 00:00:00 2001 From: rdb Date: Tue, 30 Jul 2019 18:38:16 +0200 Subject: [PATCH 5/7] task: work around MSVC compiler bug crashing test suite in release mode --- panda/src/event/asyncFuture.cxx | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/panda/src/event/asyncFuture.cxx b/panda/src/event/asyncFuture.cxx index 4805650260..07dd5b3707 100644 --- a/panda/src/event/asyncFuture.cxx +++ b/panda/src/event/asyncFuture.cxx @@ -30,6 +30,20 @@ AsyncFuture:: // If this triggers, the future destroyed before it was cancelled, which is // not valid. Unless we should simply call cancel() here? nassertv(_waiting.empty()); + + // This is an attempt to work around what appears to be a compiler bug in + // MSVC when compiling with optimizations and having an EventStoreInt stored + // in this field. It crashes when we delete via the ReferenceCount base + // instead of via the TypedObject. I haven't been able to find out why; + // just that it doesn't happen with ParamString. ~rdb + ReferenceCount *result_ref = _result_ref.p(); + if (result_ref != nullptr) { + _result_ref.cheat() = nullptr; + if (!result_ref->unref()) { + delete _result; + } + _result = nullptr; + } } /** From 5449f963a5e99b951b382de5d7a73e30180c72d2 Mon Sep 17 00:00:00 2001 From: rdb Date: Tue, 30 Jul 2019 19:29:18 +0200 Subject: [PATCH 6/7] loader: fix leak of EntryPoint.name reference --- panda/src/pgraph/loaderFileTypeRegistry_ext.cxx | 1 + 1 file changed, 1 insertion(+) diff --git a/panda/src/pgraph/loaderFileTypeRegistry_ext.cxx b/panda/src/pgraph/loaderFileTypeRegistry_ext.cxx index 8fa9ea295e..0e1df98d02 100644 --- a/panda/src/pgraph/loaderFileTypeRegistry_ext.cxx +++ b/panda/src/pgraph/loaderFileTypeRegistry_ext.cxx @@ -53,6 +53,7 @@ register_deferred_type(PyObject *entry_point) { name_str = nullptr; } #endif + Py_DECREF(name); if (name_str == nullptr) { Dtool_Raise_TypeError("entry_point.name is expected to be str"); From 7f385b5ddfe2f72640c699a536e8d86b21be95fc Mon Sep 17 00:00:00 2001 From: rdb Date: Tue, 30 Jul 2019 19:29:36 +0200 Subject: [PATCH 7/7] glsl: fix use of multiple p3d_TextureMatrix[] values --- panda/src/glstuff/glShaderContext_src.cxx | 1 + 1 file changed, 1 insertion(+) diff --git a/panda/src/glstuff/glShaderContext_src.cxx b/panda/src/glstuff/glShaderContext_src.cxx index 200e39004d..d61d75beb6 100644 --- a/panda/src/glstuff/glShaderContext_src.cxx +++ b/panda/src/glstuff/glShaderContext_src.cxx @@ -890,6 +890,7 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) { // Add it once for each index. for (bind._index = 0; bind._index < param_size; ++bind._index) { + bind._id._seqno = p + bind._index; _shader->_mat_spec.push_back(bind); } _shader->_mat_deps |= bind._dep[0];