mirror of
https://github.com/gentoo-mirror/gentoo.git
synced 2026-08-05 12:38:09 -07:00
media-gfx/mypaint: apply upstream patch for openmp crash
We apply the upstream patch for an OpenMP crash which was (after quite some effort by upstream and a contributor) now solved. Thanks-to: Red Rozenglass <rozenglass@protonmail.com> URL: https://github.com/mypaint/mypaint/issues/1107 Closes: https://bugs.gentoo.org/739122 Package-Manager: Portage-3.0.6, Repoman-3.0.1 Signed-off-by: Sam James <sam@gentoo.org>
This commit is contained in:
112
media-gfx/mypaint/files/mypaint-2.0.1-GIL-hold.patch
Normal file
112
media-gfx/mypaint/files/mypaint-2.0.1-GIL-hold.patch
Normal file
@@ -0,0 +1,112 @@
|
||||
https://github.com/mypaint/mypaint/issues/1107
|
||||
https://bugs.gentoo.org/739122
|
||||
https://github.com/mypaint/mypaint/commit/356716e7bacfcbb1f3ab80171fea405fdd10b2b9.patch
|
||||
----
|
||||
From 356716e7bacfcbb1f3ab80171fea405fdd10b2b9 Mon Sep 17 00:00:00 2001
|
||||
From: Red Rozenglass <rozenglass@protonmail.com>
|
||||
Date: Fri, 11 Sep 2020 02:43:49 +0300
|
||||
Subject: [PATCH] Acquire/release the GIL while processing tile requests
|
||||
|
||||
Fixes crashes on some Linux distros, potentially improves performance.
|
||||
|
||||
When handling tile requests we currently use an openmp critical block in a
|
||||
callback registered with libmypaint. The callback calls into Python code
|
||||
without locking the GIL. This sometimes crashes mypaint in numpy's memory
|
||||
cache allocator on some Linux distros that compile numpy with run-time
|
||||
asserts (without `-DNDEBUG`), like Gentoo, as numpy uses Python's GIL
|
||||
internally as a locking mechanism for its non-thread-safe global cache
|
||||
management.
|
||||
|
||||
Acquiring the GIL in the C callback, before calling into Python, ensures
|
||||
that the GIL is still locked by the current thread when it reaches numpy's
|
||||
code, and thus prevents the crashes. We yield the GIL whenever Python code
|
||||
calls again into libmypaint, This allows other threads to acquire it, and
|
||||
concurrent callbacks to run, which prevents deadlocks that would otherwise
|
||||
happen while waiting for all the callbacks to finish on Python's side. When
|
||||
libmypaint is done we re-acquire the GIL, and return up to the callback
|
||||
where the GIL is released again after some Python reference count
|
||||
bookkeeping.
|
||||
|
||||
The OpenMP critical block is no longer necessary after introducing the GIL
|
||||
locking mechanism. This would potentially improve performance as the C code
|
||||
in libmypaint can process multiple callbacks at the same time during the
|
||||
`Py_BEGIN_ALLOW_THREADS' period that yields the GIL.
|
||||
---
|
||||
lib/brush.hpp | 16 ++++++++++++++--
|
||||
lib/pythontiledsurface.cpp | 7 +++++--
|
||||
lib/tiledsurface.hpp | 4 +++-
|
||||
3 files changed, 22 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/lib/brush.hpp b/lib/brush.hpp
|
||||
index f717a42df..0db455377 100644
|
||||
--- a/lib/brush.hpp
|
||||
+++ b/lib/brush.hpp
|
||||
@@ -66,13 +66,25 @@ class Brush {
|
||||
bool stroke_to (Surface * surface, float x, float y, float pressure, float xtilt, float ytilt, double dtime, float viewzoom, float viewrotation, float barrel_rotation)
|
||||
{
|
||||
MyPaintSurface2 *c_surface = surface->get_surface2_interface();
|
||||
- return mypaint_brush_stroke_to_2(c_brush, c_surface, x, y, pressure, xtilt, ytilt, dtime, viewzoom, viewrotation, barrel_rotation);
|
||||
+ bool stroke_finished_or_empty;
|
||||
+
|
||||
+ Py_BEGIN_ALLOW_THREADS
|
||||
+ stroke_finished_or_empty = mypaint_brush_stroke_to_2(c_brush, c_surface, x, y, pressure, xtilt, ytilt, dtime, viewzoom, viewrotation, barrel_rotation);
|
||||
+ Py_END_ALLOW_THREADS
|
||||
+
|
||||
+ return stroke_finished_or_empty;
|
||||
}
|
||||
|
||||
bool stroke_to_linear (Surface * surface, float x, float y, float pressure, float xtilt, float ytilt, double dtime, float viewzoom, float viewrotation, float barrel_rotation)
|
||||
{
|
||||
MyPaintSurface2 *c_surface = surface->get_surface2_interface();
|
||||
- return mypaint_brush_stroke_to_2_linearsRGB(c_brush, c_surface, x, y, pressure, xtilt, ytilt, dtime, viewzoom, viewrotation, barrel_rotation);
|
||||
+ bool stroke_finished_or_empty;
|
||||
+
|
||||
+ Py_BEGIN_ALLOW_THREADS
|
||||
+ stroke_finished_or_empty = mypaint_brush_stroke_to_2_linearsRGB(c_brush, c_surface, x, y, pressure, xtilt, ytilt, dtime, viewzoom, viewrotation, barrel_rotation);
|
||||
+ Py_END_ALLOW_THREADS
|
||||
+
|
||||
+ return stroke_finished_or_empty;
|
||||
}
|
||||
|
||||
double get_total_stroke_painting_time()
|
||||
diff --git a/lib/pythontiledsurface.cpp b/lib/pythontiledsurface.cpp
|
||||
index 46c515c99..2c6e773db 100644
|
||||
--- a/lib/pythontiledsurface.cpp
|
||||
+++ b/lib/pythontiledsurface.cpp
|
||||
@@ -36,8 +36,9 @@ tile_request_start(MyPaintTiledSurface2 *tiled_surface, MyPaintTileRequest *requ
|
||||
const int ty = request->ty;
|
||||
PyArrayObject* rgba = NULL;
|
||||
|
||||
-#pragma omp critical
|
||||
{
|
||||
+ PyGILState_STATE gstate = PyGILState_Ensure();
|
||||
+
|
||||
rgba = (PyArrayObject*)PyObject_CallMethod(self->py_obj, "_get_tile_numpy", "(iii)", tx, ty, readonly);
|
||||
if (rgba == NULL) {
|
||||
request->buffer = NULL;
|
||||
@@ -59,7 +60,9 @@ tile_request_start(MyPaintTiledSurface2 *tiled_surface, MyPaintTileRequest *requ
|
||||
Py_DECREF((PyObject *)rgba);
|
||||
request->buffer = (uint16_t*)PyArray_DATA(rgba);
|
||||
}
|
||||
-} // #end pragma opt critical
|
||||
+
|
||||
+ PyGILState_Release(gstate);
|
||||
+}
|
||||
|
||||
|
||||
}
|
||||
diff --git a/lib/tiledsurface.hpp b/lib/tiledsurface.hpp
|
||||
index 3a6b2e61d..d1a5d1307 100644
|
||||
--- a/lib/tiledsurface.hpp
|
||||
+++ b/lib/tiledsurface.hpp
|
||||
@@ -66,7 +66,9 @@ class TiledSurface : public Surface {
|
||||
MyPaintRectangle* rects = this->bbox_rectangles;
|
||||
MyPaintRectangles bboxes = {BBOXES, rects};
|
||||
|
||||
- mypaint_surface2_end_atomic((MyPaintSurface2 *)c_surface, &bboxes);
|
||||
+ Py_BEGIN_ALLOW_THREADS
|
||||
+ mypaint_surface2_end_atomic((MyPaintSurface2 *)c_surface, &bboxes);
|
||||
+ Py_END_ALLOW_THREADS
|
||||
|
||||
// The capacity of the bounding box array will most often exceed the number
|
||||
// of rectangles that are actually used. The call to mypaint_surface_end_atomic
|
||||
22
media-gfx/mypaint/files/mypaint-2.0.1-r1-build-system.patch
Normal file
22
media-gfx/mypaint/files/mypaint-2.0.1-r1-build-system.patch
Normal file
@@ -0,0 +1,22 @@
|
||||
diff --git a/setup.py b/setup.py
|
||||
index 670df4d..703f9d2 100644
|
||||
--- a/setup.py
|
||||
+++ b/setup.py
|
||||
@@ -471,9 +471,6 @@ class BuildExt (build_ext):
|
||||
linkflags.extend([
|
||||
"-O0",
|
||||
])
|
||||
- else:
|
||||
- linkflags.append("-O3")
|
||||
- ccflags.append("-O3")
|
||||
|
||||
return build_ext.build_extension(self, ext)
|
||||
|
||||
@@ -869,7 +866,6 @@ def get_ext_modules():
|
||||
'-Wno-write-strings',
|
||||
'-D_POSIX_C_SOURCE=200809L',
|
||||
"-DNO_TESTS", # FIXME: we're building against shared libmypaint now
|
||||
- '-g', # always include symbols, for profiling
|
||||
]
|
||||
extra_link_args = []
|
||||
|
||||
76
media-gfx/mypaint/mypaint-2.0.1-r1.ebuild
Normal file
76
media-gfx/mypaint/mypaint-2.0.1-r1.ebuild
Normal file
@@ -0,0 +1,76 @@
|
||||
# Copyright 1999-2020 Gentoo Authors
|
||||
# Distributed under the terms of the GNU General Public License v2
|
||||
|
||||
EAPI=7
|
||||
|
||||
PYTHON_COMPAT=( python3_{6,7,8,9} )
|
||||
DISTUTILS_SINGLE_IMPL=1
|
||||
|
||||
inherit desktop distutils-r1 xdg
|
||||
|
||||
DESCRIPTION="Fast and easy graphics application for digital painters"
|
||||
HOMEPAGE="http://mypaint.org/"
|
||||
SRC_URI="https://github.com/mypaint/${PN}/releases/download/v${PV}/${P}.tar.xz"
|
||||
|
||||
LICENSE="GPL-2"
|
||||
SLOT="0"
|
||||
KEYWORDS="~amd64 ~x86"
|
||||
IUSE="openmp"
|
||||
LANGS="cs de en_CA en_GB es fr hu id it ja ko nb nn_NO pl pt_BR ro ru sl sv uk zh_CN zh_TW"
|
||||
|
||||
BDEPEND="
|
||||
${PYTHON_DEPS}
|
||||
dev-lang/swig
|
||||
sys-devel/gettext
|
||||
virtual/pkgconfig
|
||||
"
|
||||
RDEPEND="
|
||||
${PYTHON_DEPS}
|
||||
$(python_gen_cond_dep '
|
||||
dev-python/pygobject:3[${PYTHON_USEDEP}]
|
||||
dev-python/numpy[${PYTHON_USEDEP}]
|
||||
>=dev-python/pycairo-1.4[${PYTHON_USEDEP}]
|
||||
dev-python/protobuf-python[${PYTHON_USEDEP}]
|
||||
')
|
||||
>=dev-libs/json-c-0.11:=
|
||||
gnome-base/librsvg
|
||||
media-gfx/mypaint-brushes:2.0
|
||||
media-libs/lcms:2
|
||||
>=media-libs/libmypaint-1.5.0[openmp?]
|
||||
media-libs/libpng:0=
|
||||
sys-devel/gettext
|
||||
sys-libs/libomp
|
||||
x11-libs/gtk+:3
|
||||
"
|
||||
DEPEND="${RDEPEND}"
|
||||
|
||||
PATCHES=(
|
||||
"${FILESDIR}/${PN}-2.0.1-r1-build-system.patch"
|
||||
"${FILESDIR}/${P}-GIL-hold.patch"
|
||||
)
|
||||
|
||||
distutils_enable_tests setup.py
|
||||
|
||||
src_compile() {
|
||||
# --disable-openmp can't be passed to setup.py build,
|
||||
# only setup.py build_ext.
|
||||
# Trying to call build_ext then build and such fails.
|
||||
#
|
||||
# We just override the environment instead for simplicity.
|
||||
local openmp=$(usex openmp '-fopenmp' '-fno-openmp')
|
||||
|
||||
OPENMP_CFLAG="${openmp}" OPENMP_LDFLAG="${openmp}" distutils-r1_src_compile
|
||||
}
|
||||
|
||||
src_install() {
|
||||
distutils-r1_src_install
|
||||
|
||||
newicon pixmaps/${PN}_logo.png ${PN}.png
|
||||
|
||||
local lang=
|
||||
for lang in ${LANGS}; do
|
||||
if ! has ${lang} ${LINGUAS}; then
|
||||
rm -rf "${ED}"/usr/share/locale/${lang} || die
|
||||
fi
|
||||
done
|
||||
}
|
||||
Reference in New Issue
Block a user