From 48a4b0639cc1b816ab6640cf54e182b56f786004 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josip=20Komljenovi=C4=87?= Date: Mon, 28 Apr 2025 11:45:47 +0200 Subject: [PATCH 1/2] Remove surflock as the module --- buildconfig/Setup.Android.SDL2.in | 1 - buildconfig/Setup.Emscripten.SDL2.in | 1 - buildconfig/Setup.SDL2.in | 1 - buildconfig/stubs/gen_stubs.py | 1 - buildconfig/stubs/pygame/__init__.pyi | 1 - buildconfig/stubs/pygame/surflock.pyi | 2 - docs/reST/c_api.rst | 1 - docs/reST/c_api/surface.rst | 31 ++++ docs/reST/c_api/surflock.rst | 47 ----- src_c/_pygame.h | 3 +- src_c/include/_pygame.h | 45 ++--- src_c/meson.build | 9 - src_c/static.c | 18 +- src_c/surface.c | 180 ++++++++++++++++++- src_c/surflock.c | 243 -------------------------- src_py/__init__.py | 1 - test/meson.build | 1 - test/surface_test.py | 133 ++++++++++++++ test/surflock_test.py | 144 --------------- 19 files changed, 365 insertions(+), 498 deletions(-) delete mode 100644 buildconfig/stubs/pygame/surflock.pyi delete mode 100644 docs/reST/c_api/surflock.rst delete mode 100644 src_c/surflock.c delete mode 100644 test/surflock_test.py diff --git a/buildconfig/Setup.Android.SDL2.in b/buildconfig/Setup.Android.SDL2.in index 610d897d8c..a2443916c4 100644 --- a/buildconfig/Setup.Android.SDL2.in +++ b/buildconfig/Setup.Android.SDL2.in @@ -49,7 +49,6 @@ mouse src_c/mouse.c $(SDL) $(DEBUG) rect src_c/rect.c src_c/pgcompat_rect.c $(SDL) $(DEBUG) rwobject src_c/rwobject.c $(SDL) $(DEBUG) surface src_c/simd_blitters_sse2.c src_c/simd_blitters_avx2.c src_c/surface.c src_c/alphablit.c src_c/surface_fill.c src_c/simd_surface_fill_avx2.c src_c/simd_surface_fill_sse2.c $(SDL) $(DEBUG) -surflock src_c/surflock.c $(SDL) $(DEBUG) time src_c/time.c $(SDL) $(DEBUG) joystick src_c/joystick.c $(SDL) $(DEBUG) draw src_c/draw.c $(SDL) $(DEBUG) diff --git a/buildconfig/Setup.Emscripten.SDL2.in b/buildconfig/Setup.Emscripten.SDL2.in index 9c465102f1..3ea4a7e942 100644 --- a/buildconfig/Setup.Emscripten.SDL2.in +++ b/buildconfig/Setup.Emscripten.SDL2.in @@ -59,7 +59,6 @@ mouse src_c/void.c pixelcopy src_c/void.c pixelarray src_c/void.c surface src_c/void.c -surflock src_c/void.c rect src_c/void.c rwobject src_c/void.c system src_c/void.c diff --git a/buildconfig/Setup.SDL2.in b/buildconfig/Setup.SDL2.in index 0acde7e2fe..fe783b3faf 100644 --- a/buildconfig/Setup.SDL2.in +++ b/buildconfig/Setup.SDL2.in @@ -60,7 +60,6 @@ mouse src_c/mouse.c $(SDL) $(DEBUG) rect src_c/rect.c src_c/pgcompat_rect.c $(SDL) $(DEBUG) rwobject src_c/rwobject.c $(SDL) $(DEBUG) surface src_c/simd_blitters_sse2.c src_c/simd_blitters_avx2.c src_c/surface.c src_c/alphablit.c src_c/surface_fill.c src_c/simd_surface_fill_avx2.c src_c/simd_surface_fill_sse2.c $(SDL) $(DEBUG) -surflock src_c/surflock.c $(SDL) $(DEBUG) time src_c/time.c $(SDL) $(DEBUG) joystick src_c/joystick.c $(SDL) $(DEBUG) draw src_c/draw.c $(SDL) $(DEBUG) diff --git a/buildconfig/stubs/gen_stubs.py b/buildconfig/stubs/gen_stubs.py index f78d5e9f11..a3472ec508 100644 --- a/buildconfig/stubs/gen_stubs.py +++ b/buildconfig/stubs/gen_stubs.py @@ -46,7 +46,6 @@ "rect", "rwobject", "surface", - "surflock", "sysfont", "_debug", "system", diff --git a/buildconfig/stubs/pygame/__init__.pyi b/buildconfig/stubs/pygame/__init__.pyi index 8611d810da..d1bed5ebf6 100644 --- a/buildconfig/stubs/pygame/__init__.pyi +++ b/buildconfig/stubs/pygame/__init__.pyi @@ -33,7 +33,6 @@ from . import ( rect as rect, rwobject as rwobject, surface as surface, - surflock as surflock, sysfont as sysfont, _debug as _debug, system as system, diff --git a/buildconfig/stubs/pygame/surflock.pyi b/buildconfig/stubs/pygame/surflock.pyi deleted file mode 100644 index cd91285d28..0000000000 --- a/buildconfig/stubs/pygame/surflock.pyi +++ /dev/null @@ -1,2 +0,0 @@ -# surflock is a private pygame module that does not export any public API -# this file is kept here to make stubtest happy diff --git a/docs/reST/c_api.rst b/docs/reST/c_api.rst index f83223722d..782de109ee 100644 --- a/docs/reST/c_api.rst +++ b/docs/reST/c_api.rst @@ -17,7 +17,6 @@ pygame C API c_api/rect.rst c_api/rwobject.rst c_api/surface.rst - c_api/surflock.rst c_api/version.rst c_api/window.rst diff --git a/docs/reST/c_api/surface.rst b/docs/reST/c_api/surface.rst index a394d629f0..92ab93f0dc 100644 --- a/docs/reST/c_api/surface.rst +++ b/docs/reST/c_api/surface.rst @@ -57,3 +57,34 @@ Header file: src_c/include/pygame.h The C version of the :py:meth:`pygame.Surface.blit` method. Return ``1`` on success, ``0`` on an exception. + +.. c:function:: void pgSurface_Prep(pgSurfaceObject *surfobj) + + If *surfobj* is a subsurface, then lock the parent surface with *surfobj* + the owner of the lock. + +.. c:function:: void pgSurface_Unprep(pgSurfaceObject *surfobj) + + If *surfobj* is a subsurface, then release its lock on the parent surface. + +.. c:function:: int pgSurface_Lock(pgSurfaceObject *surfobj) + + Lock pygame surface *surfobj*, with *surfobj* owning its own lock. + +.. c:function:: int pgSurface_LockBy(pgSurfaceObject *surfobj, PyObject *lockobj) + + Lock pygame surface *surfobj* with Python object *lockobj* the owning + the lock. + + The surface will keep a weak reference to object *lockobj*, + and eventually remove the lock on itself if *lockobj* is garbage collected. + However, it is best if *lockobj* also keep a reference to the locked surface + and call to :c:func:`pgSurface_UnLockBy` when finished with the surface. + +.. c:function:: int pgSurface_UnLock(pgSurfaceObject *surfobj) + + Remove the pygame surface *surfobj* object's lock on itself. + +.. c:function:: int pgSurface_UnLockBy(pgSurfaceObject *surfobj, PyObject *lockobj) + + Remove the lock on pygame surface *surfobj* owned by Python object *lockobj*. diff --git a/docs/reST/c_api/surflock.rst b/docs/reST/c_api/surflock.rst deleted file mode 100644 index 9e08034dea..0000000000 --- a/docs/reST/c_api/surflock.rst +++ /dev/null @@ -1,47 +0,0 @@ -.. include:: ../common.txt - -.. highlight:: c - -*********************************** - API exported by pygame.surflock -*********************************** - -src_c/surflock.c -================ - -This extension module implements SDL surface locking for the -:py:class:`pygame.Surface` type. - -Header file: src_c/include/pygame.h - - -.. c:function:: void pgSurface_Prep(pgSurfaceObject *surfobj) - - If *surfobj* is a subsurface, then lock the parent surface with *surfobj* - the owner of the lock. - -.. c:function:: void pgSurface_Unprep(pgSurfaceObject *surfobj) - - If *surfobj* is a subsurface, then release its lock on the parent surface. - -.. c:function:: int pgSurface_Lock(pgSurfaceObject *surfobj) - - Lock pygame surface *surfobj*, with *surfobj* owning its own lock. - -.. c:function:: int pgSurface_LockBy(pgSurfaceObject *surfobj, PyObject *lockobj) - - Lock pygame surface *surfobj* with Python object *lockobj* the owning - the lock. - - The surface will keep a weak reference to object *lockobj*, - and eventually remove the lock on itself if *lockobj* is garbage collected. - However, it is best if *lockobj* also keep a reference to the locked surface - and call to :c:func:`pgSurface_UnLockBy` when finished with the surface. - -.. c:function:: int pgSurface_UnLock(pgSurfaceObject *surfobj) - - Remove the pygame surface *surfobj* object's lock on itself. - -.. c:function:: int pgSurface_UnLockBy(pgSurfaceObject *surfobj, PyObject *lockobj) - - Remove the lock on pygame surface *surfobj* owned by Python object *lockobj*. diff --git a/src_c/_pygame.h b/src_c/_pygame.h index 77fda23aeb..8526413dde 100644 --- a/src_c/_pygame.h +++ b/src_c/_pygame.h @@ -615,8 +615,7 @@ typedef enum { #define PYGAMEAPI_RECT_NUMSLOTS 10 #define PYGAMEAPI_JOYSTICK_NUMSLOTS 3 #define PYGAMEAPI_DISPLAY_NUMSLOTS 2 -#define PYGAMEAPI_SURFACE_NUMSLOTS 4 -#define PYGAMEAPI_SURFLOCK_NUMSLOTS 6 +#define PYGAMEAPI_SURFACE_NUMSLOTS 10 #define PYGAMEAPI_RWOBJECT_NUMSLOTS 5 #define PYGAMEAPI_PIXELARRAY_NUMSLOTS 2 #define PYGAMEAPI_COLOR_NUMSLOTS 5 diff --git a/src_c/include/_pygame.h b/src_c/include/_pygame.h index 6f9942cb6c..c455c2e344 100644 --- a/src_c/include/_pygame.h +++ b/src_c/include/_pygame.h @@ -340,44 +340,37 @@ typedef struct { (*(int (*)(pgSurfaceObject *, pgSurfaceObject *, SDL_Rect *, SDL_Rect *, \ int))PYGAMEAPI_GET_SLOT(surface, 2)) -#define import_pygame_surface() \ - do { \ - IMPORT_PYGAME_MODULE(surface); \ - if (PyErr_Occurred() != NULL) \ - break; \ - IMPORT_PYGAME_MODULE(surflock); \ - } while (0) - -#define pgSurface_New(surface) pgSurface_New2((surface), 1) -#define pgSurface_NewNoOwn(surface) pgSurface_New2((surface), 0) - -#endif /* ~PYGAMEAPI_SURFACE_INTERNAL */ - -/* - * SURFLOCK module - * auto imported/initialized by surface - */ -#ifndef PYGAMEAPI_SURFLOCK_INTERNAL #define pgSurface_Prep(x) \ if ((x)->subsurface) \ - (*(*(void (*)(pgSurfaceObject *))PYGAMEAPI_GET_SLOT(surflock, 0)))(x) + (*(*(void (*)(pgSurfaceObject *))PYGAMEAPI_GET_SLOT(surface, 4)))(x) #define pgSurface_Unprep(x) \ if ((x)->subsurface) \ - (*(*(void (*)(pgSurfaceObject *))PYGAMEAPI_GET_SLOT(surflock, 1)))(x) + (*(*(void (*)(pgSurfaceObject *))PYGAMEAPI_GET_SLOT(surface, 5)))(x) #define pgSurface_Lock \ - (*(int (*)(pgSurfaceObject *))PYGAMEAPI_GET_SLOT(surflock, 2)) + (*(int (*)(pgSurfaceObject *))PYGAMEAPI_GET_SLOT(surface, 6)) #define pgSurface_Unlock \ - (*(int (*)(pgSurfaceObject *))PYGAMEAPI_GET_SLOT(surflock, 3)) + (*(int (*)(pgSurfaceObject *))PYGAMEAPI_GET_SLOT(surface, 7)) #define pgSurface_LockBy \ - (*(int (*)(pgSurfaceObject *, PyObject *))PYGAMEAPI_GET_SLOT(surflock, 4)) + (*(int (*)(pgSurfaceObject *, PyObject *))PYGAMEAPI_GET_SLOT(surface, 8)) #define pgSurface_UnlockBy \ - (*(int (*)(pgSurfaceObject *, PyObject *))PYGAMEAPI_GET_SLOT(surflock, 5)) -#endif + (*(int (*)(pgSurfaceObject *, PyObject *))PYGAMEAPI_GET_SLOT(surface, 9)) + +#define import_pygame_surface() \ + do { \ + IMPORT_PYGAME_MODULE(surface); \ + if (PyErr_Occurred() != NULL) \ + break; \ + } while (0) + +#define pgSurface_New(surface) pgSurface_New2((surface), 1) +#define pgSurface_NewNoOwn(surface) pgSurface_New2((surface), 0) + +#endif /* ~PYGAMEAPI_SURFACE_INTERNAL */ /* * EVENT module @@ -604,7 +597,6 @@ PYGAMEAPI_DEFINE_SLOTS(rect); PYGAMEAPI_DEFINE_SLOTS(joystick); PYGAMEAPI_DEFINE_SLOTS(display); PYGAMEAPI_DEFINE_SLOTS(surface); -PYGAMEAPI_DEFINE_SLOTS(surflock); PYGAMEAPI_DEFINE_SLOTS(event); PYGAMEAPI_DEFINE_SLOTS(rwobject); PYGAMEAPI_DEFINE_SLOTS(pixelarray); @@ -620,7 +612,6 @@ PYGAMEAPI_EXTERN_SLOTS(rect); PYGAMEAPI_EXTERN_SLOTS(joystick); PYGAMEAPI_EXTERN_SLOTS(display); PYGAMEAPI_EXTERN_SLOTS(surface); -PYGAMEAPI_EXTERN_SLOTS(surflock); PYGAMEAPI_EXTERN_SLOTS(event); PYGAMEAPI_EXTERN_SLOTS(rwobject); PYGAMEAPI_EXTERN_SLOTS(pixelarray); diff --git a/src_c/meson.build b/src_c/meson.build index fde0cf8fcc..8c0f3ae645 100644 --- a/src_c/meson.build +++ b/src_c/meson.build @@ -134,15 +134,6 @@ surface = py.extension_module( ) endif -surflock = py.extension_module( - 'surflock', - 'surflock.c', - c_args: warnings_error, - dependencies: pg_base_deps, - install: true, - subdir: pg, -) - time = py.extension_module( 'time', 'time.c', diff --git a/src_c/static.c b/src_c/static.c index 2a2a6fe1aa..b230867e46 100644 --- a/src_c/static.c +++ b/src_c/static.c @@ -97,8 +97,6 @@ PyInit_rect(void); PyMODINIT_FUNC PyInit_geometry(void); PyMODINIT_FUNC -PyInit_surflock(void); -PyMODINIT_FUNC PyInit_rwobject(void); PyMODINIT_FUNC PyInit_bufferproxy(void); @@ -289,7 +287,6 @@ PyInit_pygame_static() load_submodule("pygame", PyInit_base(), "base"); load_submodule("pygame", PyInit_constants(), "constants"); - load_submodule("pygame", PyInit_surflock(), "surflock"); load_submodule("pygame", PyInit_rwobject(), "rwobject"); load_submodule("pygame", PyInit_pg_math(), "math"); load_submodule("pygame", PyInit_display(), "display"); @@ -339,15 +336,6 @@ PyInit_pygame_static() #include "rect.c" #include "pgcompat_rect.c" -#undef pgSurface_Lock -#undef pgSurface_Unlock -#undef pgSurface_LockBy -#undef pgSurface_UnlockBy -#undef pgSurface_Prep -#undef pgSurface_Unprep - -#include "surflock.c" - #undef pgColor_New #undef pgColor_NewLength #undef pg_RGBAFromObjEx @@ -364,6 +352,12 @@ PyInit_pygame_static() #undef pgSurface_New #undef pgSurface_Type #undef pgSurface_SetSurface +#undef pgSurface_Lock +#undef pgSurface_Unlock +#undef pgSurface_LockBy +#undef pgSurface_UnlockBy +#undef pgSurface_Prep +#undef pgSurface_Unprep #include "surface.c" #include "simd_blitters_avx2.c" diff --git a/src_c/surface.c b/src_c/surface.c index aaecc7e93f..173ef66d4a 100644 --- a/src_c/surface.c +++ b/src_c/surface.c @@ -69,6 +69,14 @@ pgSurface_Blit(pgSurfaceObject *dstobj, pgSurfaceObject *srcobj, /* statics */ static pgSurfaceObject * pgSurface_New2(SDL_Surface *info, int owner); +static int +pgSurface_Lock(pgSurfaceObject *); +static int +pgSurface_Unlock(pgSurfaceObject *); +static int +pgSurface_LockBy(pgSurfaceObject *, PyObject *); +static int +pgSurface_UnlockBy(pgSurfaceObject *, PyObject *); static PyObject * surf_subtype_new(PyTypeObject *type, SDL_Surface *s, int owner); static PyObject * @@ -712,6 +720,168 @@ surface_init(pgSurfaceObject *self, PyObject *args, PyObject *kwds) return 0; } +/* surflock methods */ +static void +pgSurface_Prep(pgSurfaceObject *surfobj) +{ + struct pgSubSurface_Data *data = ((pgSurfaceObject *)surfobj)->subsurface; + if (data != NULL) { + pgSurface_LockBy((pgSurfaceObject *)data->owner, (PyObject *)surfobj); + } +} + +static void +pgSurface_Unprep(pgSurfaceObject *surfobj) +{ + struct pgSubSurface_Data *data = ((pgSurfaceObject *)surfobj)->subsurface; + if (data != NULL) { + pgSurface_UnlockBy((pgSurfaceObject *)data->owner, + (PyObject *)surfobj); + } +} + +static int +pgSurface_Lock(pgSurfaceObject *surfobj) +{ + return pgSurface_LockBy(surfobj, (PyObject *)surfobj); +} + +static int +pgSurface_Unlock(pgSurfaceObject *surfobj) +{ + return pgSurface_UnlockBy(surfobj, (PyObject *)surfobj); +} + +static int +pgSurface_LockBy(pgSurfaceObject *surfobj, PyObject *lockobj) +{ + PyObject *ref; + pgSurfaceObject *surf = (pgSurfaceObject *)surfobj; + + if (surf->locklist == NULL) { + surf->locklist = PyList_New(0); + if (surf->locklist == NULL) { + return 0; + } + } + ref = PyWeakref_NewRef(lockobj, NULL); + if (ref == NULL) { + return 0; + } + if (ref == Py_None) { + Py_DECREF(ref); + return 0; + } + if (0 != PyList_Append(surf->locklist, ref)) { + Py_DECREF(ref); + return 0; /* Exception already set. */ + } + Py_DECREF(ref); + + if (surf->subsurface != NULL) { + pgSurface_Prep(surfobj); + } +#if SDL_VERSION_ATLEAST(3, 0, 0) + if (!SDL_LockSurface(surf->surf)) +#else + if (SDL_LockSurface(surf->surf) == -1) +#endif + { + PyErr_SetString(PyExc_RuntimeError, "error locking surface"); + return 0; + } + return 1; +} + +static int +pgSurface_UnlockBy(pgSurfaceObject *surfobj, PyObject *lockobj) +{ + PG_DECLARE_EXCEPTION_SAVER + + pgSurfaceObject *surf = (pgSurfaceObject *)surfobj; + int found = 0; + int noerror = 1; + int weakref_getref_result; + + if (surf->locklist != NULL) { + PyObject *item, *ref; + Py_ssize_t len = PyList_Size(surf->locklist); + while (--len >= 0 && !found) { + item = PyList_GetItem(surf->locklist, len); + + weakref_getref_result = PyWeakref_GetRef(item, &ref); + if (weakref_getref_result == -1) { + noerror = 0; + } + if (weakref_getref_result == 1) { + if (ref == lockobj) { + // Need to cache any currently set exceptions before + // calling PySequence_DelItem + PG_SAVE_EXCEPTION + + if (PySequence_DelItem(surf->locklist, len) == -1) { + Py_DECREF(ref); + // Restore the previously set exception before + // returning + PG_UNSAVE_EXCEPTION + return 0; + } + else { + found = 1; + } + // Restore the previously set exception + PG_UNSAVE_EXCEPTION + } + Py_DECREF(ref); + } + } + + /* Clear dead references */ + len = PyList_Size(surf->locklist); + while (--len >= 0) { + item = PyList_GetItem(surf->locklist, len); + + weakref_getref_result = PyWeakref_GetRef(item, &ref); + if (weakref_getref_result == -1) { + noerror = 0; + } + else if (weakref_getref_result == 0) { + // Need to cache any currently set exceptions before calling + // PySequence_DelItem + PG_SAVE_EXCEPTION + if (PySequence_DelItem(surf->locklist, len) == -1) { + noerror = 0; + } + else { + found++; + } + // Restore the previously set exception + PG_UNSAVE_EXCEPTION + } + else if (weakref_getref_result == 1) { + Py_DECREF(ref); + } + } + } + + if (!found) { + return noerror; + } + + /* Release all found locks. */ + while (found > 0) { + if (surf->surf != NULL) { + SDL_UnlockSurface(surf->surf); + } + if (surf->subsurface != NULL) { + pgSurface_Unprep(surfobj); + } + found--; + } + + return noerror; +} + /* surface object methods */ static PyObject * surf_get_at(PyObject *self, PyObject *position) @@ -4308,10 +4478,6 @@ MODINIT_DEFINE(surface) if (PyErr_Occurred()) { return NULL; } - _IMPORT_PYGAME_MODULE(surflock); - if (PyErr_Occurred()) { - return NULL; - } /* type preparation */ if (PyType_Ready(&pgSurface_Type) < 0) { @@ -4347,6 +4513,12 @@ MODINIT_DEFINE(surface) c_api[1] = pgSurface_New2; c_api[2] = pgSurface_Blit; c_api[3] = pgSurface_SetSurface; + c_api[4] = pgSurface_Prep; + c_api[5] = pgSurface_Unprep; + c_api[6] = pgSurface_Lock; + c_api[7] = pgSurface_Unlock; + c_api[8] = pgSurface_LockBy; + c_api[9] = pgSurface_UnlockBy; apiobj = encapsulate_api(c_api, "surface"); if (PyModule_AddObject(module, PYGAMEAPI_LOCAL_ENTRY, apiobj)) { Py_XDECREF(apiobj); diff --git a/src_c/surflock.c b/src_c/surflock.c deleted file mode 100644 index f34fac3ce4..0000000000 --- a/src_c/surflock.c +++ /dev/null @@ -1,243 +0,0 @@ -/* - pygame-ce - Python Game Library - Copyright (C) 2000-2001 Pete Shinners - Copyright (C) 2008 Marcus von Appen - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - Pete Shinners - pete@shinners.org -*/ - -/* - * internal surface locking support for python objects - */ -#define PYGAMEAPI_SURFLOCK_INTERNAL - -#include "pygame.h" - -#include "pgcompat.h" - -static int -pgSurface_Lock(pgSurfaceObject *); -static int -pgSurface_Unlock(pgSurfaceObject *); -static int -pgSurface_LockBy(pgSurfaceObject *, PyObject *); -static int -pgSurface_UnlockBy(pgSurfaceObject *, PyObject *); - -static void -pgSurface_Prep(pgSurfaceObject *surfobj) -{ - struct pgSubSurface_Data *data = ((pgSurfaceObject *)surfobj)->subsurface; - if (data != NULL) { - pgSurface_LockBy((pgSurfaceObject *)data->owner, (PyObject *)surfobj); - } -} - -static void -pgSurface_Unprep(pgSurfaceObject *surfobj) -{ - struct pgSubSurface_Data *data = ((pgSurfaceObject *)surfobj)->subsurface; - if (data != NULL) { - pgSurface_UnlockBy((pgSurfaceObject *)data->owner, - (PyObject *)surfobj); - } -} - -static int -pgSurface_Lock(pgSurfaceObject *surfobj) -{ - return pgSurface_LockBy(surfobj, (PyObject *)surfobj); -} - -static int -pgSurface_Unlock(pgSurfaceObject *surfobj) -{ - return pgSurface_UnlockBy(surfobj, (PyObject *)surfobj); -} - -static int -pgSurface_LockBy(pgSurfaceObject *surfobj, PyObject *lockobj) -{ - PyObject *ref; - pgSurfaceObject *surf = (pgSurfaceObject *)surfobj; - - if (surf->locklist == NULL) { - surf->locklist = PyList_New(0); - if (surf->locklist == NULL) { - return 0; - } - } - ref = PyWeakref_NewRef(lockobj, NULL); - if (ref == NULL) { - return 0; - } - if (ref == Py_None) { - Py_DECREF(ref); - return 0; - } - if (0 != PyList_Append(surf->locklist, ref)) { - Py_DECREF(ref); - return 0; /* Exception already set. */ - } - Py_DECREF(ref); - - if (surf->subsurface != NULL) { - pgSurface_Prep(surfobj); - } -#if SDL_VERSION_ATLEAST(3, 0, 0) - if (!SDL_LockSurface(surf->surf)) -#else - if (SDL_LockSurface(surf->surf) == -1) -#endif - { - PyErr_SetString(PyExc_RuntimeError, "error locking surface"); - return 0; - } - return 1; -} - -static int -pgSurface_UnlockBy(pgSurfaceObject *surfobj, PyObject *lockobj) -{ - PG_DECLARE_EXCEPTION_SAVER - - pgSurfaceObject *surf = (pgSurfaceObject *)surfobj; - int found = 0; - int noerror = 1; - int weakref_getref_result; - - if (surf->locklist != NULL) { - PyObject *item, *ref; - Py_ssize_t len = PyList_Size(surf->locklist); - while (--len >= 0 && !found) { - item = PyList_GetItem(surf->locklist, len); - - weakref_getref_result = PyWeakref_GetRef(item, &ref); - if (weakref_getref_result == -1) { - noerror = 0; - } - if (weakref_getref_result == 1) { - if (ref == lockobj) { - // Need to cache any currently set exceptions before - // calling PySequence_DelItem - PG_SAVE_EXCEPTION - - if (PySequence_DelItem(surf->locklist, len) == -1) { - Py_DECREF(ref); - // Restore the previously set exception before - // returning - PG_UNSAVE_EXCEPTION - return 0; - } - else { - found = 1; - } - // Restore the previously set exception - PG_UNSAVE_EXCEPTION - } - Py_DECREF(ref); - } - } - - /* Clear dead references */ - len = PyList_Size(surf->locklist); - while (--len >= 0) { - item = PyList_GetItem(surf->locklist, len); - - weakref_getref_result = PyWeakref_GetRef(item, &ref); - if (weakref_getref_result == -1) { - noerror = 0; - } - else if (weakref_getref_result == 0) { - // Need to cache any currently set exceptions before calling - // PySequence_DelItem - PG_SAVE_EXCEPTION - if (PySequence_DelItem(surf->locklist, len) == -1) { - noerror = 0; - } - else { - found++; - } - // Restore the previously set exception - PG_UNSAVE_EXCEPTION - } - else if (weakref_getref_result == 1) { - Py_DECREF(ref); - } - } - } - - if (!found) { - return noerror; - } - - /* Release all found locks. */ - while (found > 0) { - if (surf->surf != NULL) { - SDL_UnlockSurface(surf->surf); - } - if (surf->subsurface != NULL) { - pgSurface_Unprep(surfobj); - } - found--; - } - - return noerror; -} - -static PyMethodDef _surflock_methods[] = {{NULL, NULL, 0, NULL}}; - -/*DOC*/ static char _surflock_doc[] = - /*DOC*/ "Surface locking support"; - -MODINIT_DEFINE(surflock) -{ - PyObject *module, *apiobj; - static void *c_api[PYGAMEAPI_SURFLOCK_NUMSLOTS]; - - static struct PyModuleDef _module = {PyModuleDef_HEAD_INIT, - "surflock", - _surflock_doc, - -1, - _surflock_methods, - NULL, - NULL, - NULL, - NULL}; - - /* Create the module and add the functions */ - module = PyModule_Create(&_module); - if (module == NULL) { - return NULL; - } - - /* export the c api */ - c_api[0] = pgSurface_Prep; - c_api[1] = pgSurface_Unprep; - c_api[2] = pgSurface_Lock; - c_api[3] = pgSurface_Unlock; - c_api[4] = pgSurface_LockBy; - c_api[5] = pgSurface_UnlockBy; - apiobj = encapsulate_api(c_api, "surflock"); - if (PyModule_AddObject(module, PYGAMEAPI_LOCAL_ENTRY, apiobj)) { - Py_XDECREF(apiobj); - Py_DECREF(module); - return NULL; - } - return module; -} diff --git a/src_py/__init__.py b/src_py/__init__.py index c227a9e55e..b8014ec035 100644 --- a/src_py/__init__.py +++ b/src_py/__init__.py @@ -146,7 +146,6 @@ def warn(self): from pygame.version import * # pylint: disable=wildcard-import; lgtm[py/polluting-import] from pygame.rect import Rect, FRect from pygame.rwobject import encode_string, encode_file_path -import pygame.surflock import pygame.color Color = pygame.color.Color diff --git a/test/meson.build b/test/meson.build index d789ad01e0..c1900928eb 100644 --- a/test/meson.build +++ b/test/meson.build @@ -44,7 +44,6 @@ test_files = files( 'surface_test.py', 'surfarray_tags.py', 'surfarray_test.py', - 'surflock_test.py', 'sysfont_test.py', 'system_test.py', 'time_test.py', diff --git a/test/surface_test.py b/test/surface_test.py index c3bb3d098a..6d9a7cf8a3 100644 --- a/test/surface_test.py +++ b/test/surface_test.py @@ -4347,5 +4347,138 @@ def test_fill_negative_rectpos(self): ) +@unittest.skipIf(IS_PYPY, "pypy skip known failure") # TODO +class SurfaceLockTest(unittest.TestCase): + def test_lock(self): + sf = pygame.Surface((5, 5)) + + sf.lock() + self.assertEqual(sf.get_locked(), True) + self.assertEqual(sf.get_locks(), (sf,)) + + sf.lock() + self.assertEqual(sf.get_locked(), True) + self.assertEqual(sf.get_locks(), (sf, sf)) + + sf.unlock() + self.assertEqual(sf.get_locked(), True) + self.assertEqual(sf.get_locks(), (sf,)) + + sf.unlock() + self.assertEqual(sf.get_locked(), False) + self.assertEqual(sf.get_locks(), ()) + + def test_subsurface_lock(self): + sf = pygame.Surface((5, 5)) + subsf = sf.subsurface((1, 1, 2, 2)) + sf2 = pygame.Surface((5, 5)) + + # Simple blits, nothing should happen here. + sf2.blit(subsf, (0, 0)) + sf2.blit(sf, (0, 0)) + + # Test blitting on self: + self.assertRaises(pygame.error, sf.blit, subsf, (0, 0)) + # self.assertRaises(pygame.error, subsf.blit, sf, (0, 0)) + # ^ Fails although it should not in my opinion. If I cannot + # blit the subsurface to the surface, it should not be allowed + # the other way around as well. + + # Test additional locks. + sf.lock() + sf2.blit(subsf, (0, 0)) + self.assertRaises(pygame.error, sf2.blit, sf, (0, 0)) + + subsf.lock() + self.assertRaises(pygame.error, sf2.blit, subsf, (0, 0)) + self.assertRaises(pygame.error, sf2.blit, sf, (0, 0)) + + # sf and subsf are now explicitly locked. Unlock sf, so we can + # (assume) to blit it. + # It will fail though as the subsurface still has a lock around, + # which is okay and correct behaviour. + sf.unlock() + self.assertRaises(pygame.error, sf2.blit, subsf, (0, 0)) + self.assertRaises(pygame.error, sf2.blit, sf, (0, 0)) + + # Run a second unlock on the surface. This should ideally have + # no effect as the subsurface is the locking reason! + sf.unlock() + self.assertRaises(pygame.error, sf2.blit, sf, (0, 0)) + self.assertRaises(pygame.error, sf2.blit, subsf, (0, 0)) + subsf.unlock() + + sf.lock() + self.assertEqual(sf.get_locked(), True) + self.assertEqual(sf.get_locks(), (sf,)) + self.assertEqual(subsf.get_locked(), False) + self.assertEqual(subsf.get_locks(), ()) + + subsf.lock() + self.assertEqual(sf.get_locked(), True) + self.assertEqual(sf.get_locks(), (sf, subsf)) + self.assertEqual(subsf.get_locked(), True) + self.assertEqual(subsf.get_locks(), (subsf,)) + + sf.unlock() + self.assertEqual(sf.get_locked(), True) + self.assertEqual(sf.get_locks(), (subsf,)) + self.assertEqual(subsf.get_locked(), True) + self.assertEqual(subsf.get_locks(), (subsf,)) + + subsf.unlock() + self.assertEqual(sf.get_locked(), False) + self.assertEqual(sf.get_locks(), ()) + self.assertEqual(subsf.get_locked(), False) + self.assertEqual(subsf.get_locks(), ()) + + subsf.lock() + self.assertEqual(sf.get_locked(), True) + self.assertEqual(sf.get_locks(), (subsf,)) + self.assertEqual(subsf.get_locked(), True) + self.assertEqual(subsf.get_locks(), (subsf,)) + + subsf.lock() + self.assertEqual(sf.get_locked(), True) + self.assertEqual(sf.get_locks(), (subsf, subsf)) + self.assertEqual(subsf.get_locked(), True) + self.assertEqual(subsf.get_locks(), (subsf, subsf)) + + def test_pxarray_ref(self): + sf = pygame.Surface((5, 5)) + ar = pygame.PixelArray(sf) + ar2 = pygame.PixelArray(sf) + + self.assertEqual(sf.get_locked(), True) + self.assertEqual(sf.get_locks(), (ar, ar2)) + + del ar + self.assertEqual(sf.get_locked(), True) + self.assertEqual(sf.get_locks(), (ar2,)) + + ar = ar2[:] + self.assertEqual(sf.get_locked(), True) + self.assertEqual(sf.get_locks(), (ar2,)) + + del ar + self.assertEqual(sf.get_locked(), True) + self.assertEqual(len(sf.get_locks()), 1) + + def test_buffer(self): + sf = pygame.Surface((5, 5)) + buf = sf.get_buffer() + + self.assertEqual(sf.get_locked(), True) + self.assertEqual(sf.get_locks(), (buf,)) + + sf.unlock() + self.assertEqual(sf.get_locked(), True) + self.assertEqual(sf.get_locks(), (buf,)) + + del buf + self.assertEqual(sf.get_locked(), False) + self.assertEqual(sf.get_locks(), ()) + + if __name__ == "__main__": unittest.main() diff --git a/test/surflock_test.py b/test/surflock_test.py deleted file mode 100644 index c56bffe021..0000000000 --- a/test/surflock_test.py +++ /dev/null @@ -1,144 +0,0 @@ -import platform -import sys -import unittest - -import pygame - -IS_PYPY = "PyPy" == platform.python_implementation() - - -@unittest.skipIf(IS_PYPY, "pypy skip known failure") # TODO -class SurfaceLockTest(unittest.TestCase): - def test_lock(self): - sf = pygame.Surface((5, 5)) - - sf.lock() - self.assertEqual(sf.get_locked(), True) - self.assertEqual(sf.get_locks(), (sf,)) - - sf.lock() - self.assertEqual(sf.get_locked(), True) - self.assertEqual(sf.get_locks(), (sf, sf)) - - sf.unlock() - self.assertEqual(sf.get_locked(), True) - self.assertEqual(sf.get_locks(), (sf,)) - - sf.unlock() - self.assertEqual(sf.get_locked(), False) - self.assertEqual(sf.get_locks(), ()) - - def test_subsurface_lock(self): - sf = pygame.Surface((5, 5)) - subsf = sf.subsurface((1, 1, 2, 2)) - sf2 = pygame.Surface((5, 5)) - - # Simple blits, nothing should happen here. - sf2.blit(subsf, (0, 0)) - sf2.blit(sf, (0, 0)) - - # Test blitting on self: - self.assertRaises(pygame.error, sf.blit, subsf, (0, 0)) - # self.assertRaises(pygame.error, subsf.blit, sf, (0, 0)) - # ^ Fails although it should not in my opinion. If I cannot - # blit the subsurface to the surface, it should not be allowed - # the other way around as well. - - # Test additional locks. - sf.lock() - sf2.blit(subsf, (0, 0)) - self.assertRaises(pygame.error, sf2.blit, sf, (0, 0)) - - subsf.lock() - self.assertRaises(pygame.error, sf2.blit, subsf, (0, 0)) - self.assertRaises(pygame.error, sf2.blit, sf, (0, 0)) - - # sf and subsf are now explicitly locked. Unlock sf, so we can - # (assume) to blit it. - # It will fail though as the subsurface still has a lock around, - # which is okay and correct behaviour. - sf.unlock() - self.assertRaises(pygame.error, sf2.blit, subsf, (0, 0)) - self.assertRaises(pygame.error, sf2.blit, sf, (0, 0)) - - # Run a second unlock on the surface. This should ideally have - # no effect as the subsurface is the locking reason! - sf.unlock() - self.assertRaises(pygame.error, sf2.blit, sf, (0, 0)) - self.assertRaises(pygame.error, sf2.blit, subsf, (0, 0)) - subsf.unlock() - - sf.lock() - self.assertEqual(sf.get_locked(), True) - self.assertEqual(sf.get_locks(), (sf,)) - self.assertEqual(subsf.get_locked(), False) - self.assertEqual(subsf.get_locks(), ()) - - subsf.lock() - self.assertEqual(sf.get_locked(), True) - self.assertEqual(sf.get_locks(), (sf, subsf)) - self.assertEqual(subsf.get_locked(), True) - self.assertEqual(subsf.get_locks(), (subsf,)) - - sf.unlock() - self.assertEqual(sf.get_locked(), True) - self.assertEqual(sf.get_locks(), (subsf,)) - self.assertEqual(subsf.get_locked(), True) - self.assertEqual(subsf.get_locks(), (subsf,)) - - subsf.unlock() - self.assertEqual(sf.get_locked(), False) - self.assertEqual(sf.get_locks(), ()) - self.assertEqual(subsf.get_locked(), False) - self.assertEqual(subsf.get_locks(), ()) - - subsf.lock() - self.assertEqual(sf.get_locked(), True) - self.assertEqual(sf.get_locks(), (subsf,)) - self.assertEqual(subsf.get_locked(), True) - self.assertEqual(subsf.get_locks(), (subsf,)) - - subsf.lock() - self.assertEqual(sf.get_locked(), True) - self.assertEqual(sf.get_locks(), (subsf, subsf)) - self.assertEqual(subsf.get_locked(), True) - self.assertEqual(subsf.get_locks(), (subsf, subsf)) - - def test_pxarray_ref(self): - sf = pygame.Surface((5, 5)) - ar = pygame.PixelArray(sf) - ar2 = pygame.PixelArray(sf) - - self.assertEqual(sf.get_locked(), True) - self.assertEqual(sf.get_locks(), (ar, ar2)) - - del ar - self.assertEqual(sf.get_locked(), True) - self.assertEqual(sf.get_locks(), (ar2,)) - - ar = ar2[:] - self.assertEqual(sf.get_locked(), True) - self.assertEqual(sf.get_locks(), (ar2,)) - - del ar - self.assertEqual(sf.get_locked(), True) - self.assertEqual(len(sf.get_locks()), 1) - - def test_buffer(self): - sf = pygame.Surface((5, 5)) - buf = sf.get_buffer() - - self.assertEqual(sf.get_locked(), True) - self.assertEqual(sf.get_locks(), (buf,)) - - sf.unlock() - self.assertEqual(sf.get_locked(), True) - self.assertEqual(sf.get_locks(), (buf,)) - - del buf - self.assertEqual(sf.get_locked(), False) - self.assertEqual(sf.get_locks(), ()) - - -if __name__ == "__main__": - unittest.main() From f79fbdc9eb5ef91af519a7ec8fb31360606ca2e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josip=20Komljenovi=C4=87?= Date: Mon, 28 Apr 2025 11:55:22 +0200 Subject: [PATCH 2/2] Remove surflock as the module --- src_c/include/_pygame.h | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src_c/include/_pygame.h b/src_c/include/_pygame.h index c455c2e344..8b2827e2de 100644 --- a/src_c/include/_pygame.h +++ b/src_c/include/_pygame.h @@ -360,12 +360,7 @@ typedef struct { #define pgSurface_UnlockBy \ (*(int (*)(pgSurfaceObject *, PyObject *))PYGAMEAPI_GET_SLOT(surface, 9)) -#define import_pygame_surface() \ - do { \ - IMPORT_PYGAME_MODULE(surface); \ - if (PyErr_Occurred() != NULL) \ - break; \ - } while (0) +#define import_pygame_surface() IMPORT_PYGAME_MODULE(surface) #define pgSurface_New(surface) pgSurface_New2((surface), 1) #define pgSurface_NewNoOwn(surface) pgSurface_New2((surface), 0)