Commits

Lenard Lindstrom  committed 389535a

Filled in surface BufferProxy PyBUF_* flag support for 0D to 2D view kinds

  • Participants
  • Parent commits 789e644

Comments (0)

Files changed (2)

File src/surface.c

     view_p->buf = surface->pixels;
     view_p->itemsize = 1;
     view_p->len = surface->pitch * surface->h;
-    if (!PyBUF_IS_DIMLESS(flags)) {
-        view_p->ndim = 1;
-    }
     view_p->readonly = 0;
     if (PyBUF_HAS_FLAG(flags, PyBUF_FORMAT)) {
         view_p->format = FormatUint8;
     }
     if (PyBUF_HAS_FLAG(flags, PyBUF_ND)) {
+        view_p->ndim = 1;
         view_p->shape[0] = view_p->len;
-    }
-    if (PyBUF_HAS_FLAG(flags, PyBUF_STRIDES)) {
-        view_p->strides[0] = view_p->itemsize;
+        if (PyBUF_HAS_FLAG(flags, PyBUF_STRIDES)) {
+            view_p->strides[0] = view_p->itemsize;
+        }
     }
     Py_INCREF (obj);
     view_p->obj = obj;
     Py_buffer *view_p = (Py_buffer *)pg_view_p;
     SDL_Surface *surface = PySurface_AsSurface (obj);
     Py_ssize_t itemsize = surface->format->BytesPerPixel;
-    char *format;
 
     view_p->obj = 0;
     if (itemsize == 1) {
         return _get_buffer_0D (obj, pg_view_p, flags);
     }
-    if (flags == PyBUF_SIMPLE) {
-        PyErr_Format (PgExc_BufferError,
-                      "PyBUF_SIMPLE flag unsupported for a "
-                      "%i bytes-per-pixel 1D surface view", itemsize);
-        return -1;
-    }
-    if ((flags & PyBUF_ND) != PyBUF_ND) {
-        PyErr_Format (PgExc_BufferError,
-                      "PyBUF_ND flag required for a "
-                      "%i bytes-per-pixel 1D surface view", itemsize);
-        return -1;
-    }
-    if ((flags & PyBUF_FORMAT) != PyBUF_FORMAT) {
-        PyErr_Format (PgExc_BufferError,
-                      "PyBUF_FORMAT required for a 1D view of a "
-                      "%i bytes-per-pixel surface", itemsize);
-        return -1;
-    }
-    switch (itemsize) {
-
-    case 2:
-        format = FormatUint16;
-        break;
-    case 3:
-        format = FormatUint24;
-        break;
-    case 4:
-        format = FormatUint32;
-        break;
-    default:
-        /* Should not get here! */
-        PyErr_Format (PyExc_SystemError,
-                      "Pygame bug caught at line %i in file %s: "
-                      "unknown pixel size %i. Please report",
-                      (int)__LINE__, __FILE__, itemsize);
-        return -1;
-    }
     if (_init_buffer (obj, pg_view_p, flags)) {
         return -1;
     }
-    view_p->format = format;
+    if (PyBUF_HAS_FLAG (flags, PyBUF_FORMAT)) {
+        switch (itemsize) {
+
+        case 2:
+            view_p->format = FormatUint16;
+            break;
+        case 3:
+            view_p->format = FormatUint24;
+            break;
+        case 4:
+            view_p->format = FormatUint32;
+            break;
+        default:
+            /* Should not get here! */
+            PyErr_Format (PyExc_SystemError,
+                          "Pygame bug caught at line %i in file %s: "
+                          "unknown pixel size %i. Please report",
+                          (int)__LINE__, __FILE__, itemsize);
+            return -1;
+        }
+    }
     view_p->buf = surface->pixels;
     view_p->itemsize = itemsize;
-    view_p->ndim = 1;
     view_p->readonly = 0;
-    view_p->len = surface->w * surface->h * itemsize;
-    view_p->shape[0] = surface->w * surface->h;
-    if ((flags & PyBUF_STRIDES) == PyBUF_STRIDES) {
-        view_p->strides[0] = itemsize;
+    view_p->len = surface->pitch * surface->h;
+    if (PyBUF_HAS_FLAG (flags, PyBUF_ND)) {
+        view_p->ndim = 1;
+        view_p->shape[0] = surface->w * surface->h;
+        if (PyBUF_HAS_FLAG (flags, PyBUF_STRIDES)) {
+            view_p->strides[0] = itemsize;
+        }
     }
     view_p->suboffsets = 0;
     Py_INCREF (obj);
     Py_buffer *view_p = (Py_buffer *)pg_view_p;
     SDL_Surface *surface = PySurface_AsSurface (obj);
     int itemsize = surface->format->BytesPerPixel;
-    char *format;
 
     view_p->obj = 0;
-    if ((flags & PyBUF_RECORDS_RO) != PyBUF_RECORDS_RO) {
-        PyErr_SetString (PgExc_BufferError,
-                         "A PyBUF_RECORDS(_RO) flag is required for a "
-                         "2D surface view");
-        return -1;
+    if (PyBUF_IS_DIMLESS (flags)) {
+        if (surface->pitch != surface->w * itemsize) {
+            PyErr_SetString (PgExc_BufferError,
+                             "A 2D surface view is not C contiguous");
+            return -1;
+        }
+        return _get_buffer_1D (obj, pg_view_p, flags);
     }
-    if ((flags & PyBUF_C_CONTIGUOUS) == PyBUF_C_CONTIGUOUS) {
+    if (!PyBUF_HAS_FLAG (flags, PyBUF_STRIDES)) {
+            PyErr_SetString (PgExc_BufferError,
+                             "A 2D surface view is not C contiguous: "
+                             "need strides");
+            return -1;
+    }
+    if (PyBUF_HAS_FLAG (flags, PyBUF_C_CONTIGUOUS)) {
         PyErr_SetString (PgExc_BufferError,
                          "A 2D surface view is not C contiguous");
         return -1;
     }
-    if ((flags & PyBUF_F_CONTIGUOUS) == PyBUF_F_CONTIGUOUS &&
+    if (PyBUF_HAS_FLAG (flags, PyBUF_F_CONTIGUOUS) &&
         surface->pitch != surface->w * itemsize) {
         PyErr_SetString (PgExc_BufferError,
                          "This 2D surface view is not F contiguous");
         return -1;
     }
-    if ((flags & PyBUF_ANY_CONTIGUOUS) == PyBUF_ANY_CONTIGUOUS &&
+    if (PyBUF_HAS_FLAG (flags, PyBUF_ANY_CONTIGUOUS) &&
         surface->pitch != surface->w * itemsize) {
         PyErr_SetString (PgExc_BufferError,
                          "This 2D surface view is not contiguous");
         return -1;
     }
-    switch (itemsize) {
-
-    case 1:
-        format = FormatUint8;
-        break;
-    case 2:
-        format = FormatUint16;
-        break;
-    case 3:
-        format = FormatUint24;
-        break;
-    case 4:
-        format = FormatUint32;
-        break;
-    default:
-        /* Should not get here! */
-        PyErr_Format (PyExc_SystemError,
-                      "Pygame bug caught at line %i in file %s: "
-                      "unknown pixel size %i. Please report",
-                      (int)__LINE__, __FILE__, itemsize);
-        return -1;
-    }
     if (_init_buffer (obj, pg_view_p, flags)) {
         return -1;
     }
-    view_p->format = format;
+    if (PyBUF_HAS_FLAG (flags, PyBUF_FORMAT)) {
+        switch (itemsize) {
+
+        case 1:
+            view_p->format = FormatUint8;
+            break;
+        case 2:
+            view_p->format = FormatUint16;
+            break;
+        case 3:
+            view_p->format = FormatUint24;
+            break;
+        case 4:
+            view_p->format = FormatUint32;
+            break;
+        default:
+            /* Should not get here! */
+            PyErr_Format (PyExc_SystemError,
+                          "Pygame bug caught at line %i in file %s: "
+                          "unknown pixel size %i. Please report",
+                          (int)__LINE__, __FILE__, itemsize);
+            return -1;
+        }
+    }
     view_p->buf = surface->pixels;
     view_p->itemsize = itemsize;
     view_p->ndim = 2;
     view_p->len = surface->w * surface->h * itemsize;
     view_p->shape[0] = surface->w;
     view_p->shape[1] = surface->h;
-    view_p->len = view_p->itemsize * view_p->shape[0] * view_p->shape[1];
     view_p->strides[0] = itemsize;
     view_p->strides[1] = surface->pitch;
     view_p->suboffsets = 0;
         PyMem_Free (internal);
         return -1;
     }
-    if ((flags & PyBUF_ND) == PyBUF_ND) {
+    if (PyBUF_HAS_FLAG (flags, PyBUF_ND)) {
         ((Py_buffer *)pg_view_p)->shape = internal->mem;
-        if ((flags & PyBUF_STRIDES) == PyBUF_STRIDES) {
+        if (PyBUF_HAS_FLAG (flags, PyBUF_STRIDES)) {
             ((Py_buffer *)pg_view_p)->strides = internal->mem + 3;
         }
         else {

File test/surface_test.py

         def test_newbuf_PyBUF_flags_bytes(self):
             self.NEWBUF_test_newbuf_PyBUF_flags_bytes()
         def test_newbuf_PyBUF_flags_0D(self):
-            self.NEWBUF_test_newbuf_PyBUF_flags_2D()
+            self.NEWBUF_test_newbuf_PyBUF_flags_0D()
         def test_newbuf_PyBUF_flags_1D(self):
-            self.NEWBUF_test_newbuf_PyBUF_flags_2D()
+            self.NEWBUF_test_newbuf_PyBUF_flags_1D()
         def test_newbuf_PyBUF_flags_2D(self):
             self.NEWBUF_test_newbuf_PyBUF_flags_2D()
         def test_newbuf_PyBUF_flags_3D(self):
-            self.NEWBUF_test_newbuf_PyBUF_flags_2D()
+            self.NEWBUF_test_newbuf_PyBUF_flags_3D()
         def test_newbuf_PyBUF_flags_rgba(self):
-            self.NEWBUF_test_newbuf_PyBUF_flags_2D()
+            self.NEWBUF_test_newbuf_PyBUF_flags_rgba()
         if is_pygame_pkg:
             from pygame.tests.test_utils import buftools
         else:
         self.assertEqual(b.strides, (1,))
 
     def NEWBUF_test_newbuf_PyBUF_flags_0D(self):
-        self.fail()
+        # This is the same handler as for the '&' buffer kind, so just
+        # confirm that it succeeds for one case.
+        buftools = self.buftools
+        BufferImporter = buftools.BufferImporter
+        s = pygame.Surface((10, 6), 0, 32)
+        a = s.get_buffer('0')
+        b = BufferImporter(a, buftools.PyBUF_SIMPLE)
+        self.assertEqual(b.ndim, 0)
+        self.assertTrue(b.format is None)
+        self.assertEqual(b.len, a.length)
+        self.assertEqual(b.itemsize, 1)
+        self.assertTrue(b.shape is None)
+        self.assertTrue(b.strides is None)
+        self.assertTrue(b.suboffsets is None)
+        self.assertFalse(b.readonly)
+        self.assertEqual(b.buf, s._pixels_address)
+
     def NEWBUF_test_newbuf_PyBUF_flags_1D(self):
-        self.fail()
+        buftools = self.buftools
+        BufferImporter = buftools.BufferImporter
+        s = pygame.Surface((10, 6), 0, 32)
+        a = s.get_buffer('1')
+        b = BufferImporter(a, buftools.PyBUF_SIMPLE)
+        self.assertEqual(b.ndim, 0)
+        self.assertTrue(b.format is None)
+        self.assertEqual(b.len, a.length)
+        self.assertEqual(b.itemsize, s.get_bytesize())
+        self.assertTrue(b.shape is None)
+        self.assertTrue(b.strides is None)
+        self.assertTrue(b.suboffsets is None)
+        self.assertFalse(b.readonly)
+        self.assertEqual(b.buf, s._pixels_address)
+        b = BufferImporter(a, buftools.PyBUF_WRITABLE)
+        self.assertEqual(b.ndim, 0)
+        self.assertTrue(b.format is None)
+        self.assertFalse(b.readonly)
+        b = BufferImporter(a, buftools.PyBUF_FORMAT)
+        self.assertEqual(b.ndim, 0)
+        self.assertEqual(b.format, '=I')
+        b = BufferImporter(a, buftools.PyBUF_ND)
+        self.assertEqual(b.ndim, 1)
+        self.assertTrue(b.format is None)
+        self.assertEqual(b.len, a.length)
+        self.assertEqual(b.itemsize, s.get_bytesize())
+        self.assertEqual(b.shape, (s.get_width() * s.get_height(),))
+        self.assertTrue(b.strides is None)
+        self.assertTrue(b.suboffsets is None)
+        self.assertFalse(b.readonly)
+        self.assertEqual(b.buf, s._pixels_address)
+        b = BufferImporter(a, buftools.PyBUF_STRIDES)
+        self.assertEqual(b.ndim, 1)
+        self.assertTrue(b.format is None)
+        self.assertEqual(b.strides, (s.get_bytesize(),))
+
     def NEWBUF_test_newbuf_PyBUF_flags_2D(self):
-        self.fail()
+        buftools = self.buftools
+        BufferImporter = buftools.BufferImporter
+        s = pygame.Surface((10, 6), 0, 32)
+        a = s.get_buffer('2')
+        # Non dimensional requests, no PyDEF_ND, are handled by the
+        # 1D surface buffer code, so only need to confirm a success.
+        b = BufferImporter(a, buftools.PyBUF_SIMPLE)
+        self.assertEqual(b.ndim, 0)
+        self.assertTrue(b.format is None)
+        self.assertEqual(b.len, a.length)
+        self.assertEqual(b.itemsize, s.get_bytesize())
+        self.assertTrue(b.shape is None)
+        self.assertTrue(b.strides is None)
+        self.assertTrue(b.suboffsets is None)
+        self.assertFalse(b.readonly)
+        self.assertEqual(b.buf, s._pixels_address)
+        # Uniquely 2D
+        b = BufferImporter(a, buftools.PyBUF_STRIDES)
+        self.assertEqual(b.ndim, 2)
+        self.assertTrue(b.format is None)
+        self.assertEqual(b.len, a.length)
+        self.assertEqual(b.itemsize, s.get_bytesize())
+        self.assertEqual(b.shape, s.get_size())
+        self.assertEqual(b.strides, (s.get_bytesize(), s.get_pitch()))
+        self.assertTrue(b.suboffsets is None)
+        self.assertFalse(b.readonly)
+        self.assertEqual(b.buf, s._pixels_address)
+        b = BufferImporter(a, buftools.PyBUF_RECORDS_RO)
+        self.assertEqual(b.ndim, 2)
+        self.assertEqual(b.format, '=I')
+        self.assertEqual(b.strides, (s.get_bytesize(), s.get_pitch()))
+        b = BufferImporter(a, buftools.PyBUF_RECORDS)
+        self.assertEqual(b.ndim, 2)
+        self.assertEqual(b.format, '=I')
+        self.assertEqual(b.strides, (s.get_bytesize(), s.get_pitch()))
+        b = BufferImporter(a, buftools.PyBUF_F_CONTIGUOUS)
+        self.assertEqual(b.ndim, 2)
+        self.assertEqual(b.format, None)
+        self.assertEqual(b.strides, (s.get_bytesize(), s.get_pitch()))
+        b = BufferImporter(a, buftools.PyBUF_ANY_CONTIGUOUS)
+        self.assertEqual(b.ndim, 2)
+        self.assertEqual(b.format, None)
+        self.assertEqual(b.strides, (s.get_bytesize(), s.get_pitch()))
+        self.assertRaises(BufferError, BufferImporter, a, buftools.PyBUF_ND)
+        self.assertRaises(BufferError, BufferImporter, a,
+                          buftools.PyBUF_C_CONTIGUOUS)
+        s2 = s.subsurface((1, 1, 7, 4)) # Not contiguous
+        a = s2.get_buffer('2')
+        b = BufferImporter(a, buftools.PyBUF_STRIDES)
+        self.assertEqual(b.ndim, 2)
+        self.assertTrue(b.format is None)
+        self.assertEqual(b.len, a.length)
+        self.assertEqual(b.itemsize, s2.get_bytesize())
+        self.assertEqual(b.shape, s2.get_size())
+        self.assertEqual(b.strides, (s2.get_bytesize(), s.get_pitch()))
+        self.assertTrue(b.suboffsets is None)
+        self.assertFalse(b.readonly)
+        self.assertEqual(b.buf, s2._pixels_address)
+        b = BufferImporter(a, buftools.PyBUF_RECORDS)
+        self.assertEqual(b.ndim, 2)
+        self.assertEqual(b.format, '=I')
+        self.assertRaises(BufferError, BufferImporter, a, buftools.PyBUF_SIMPLE)
+        self.assertRaises(BufferError, BufferImporter, a, buftools.PyBUF_FORMAT)
+        self.assertRaises(BufferError, BufferImporter, a,
+                          buftools.PyBUF_WRITABLE)
+        self.assertRaises(BufferError, BufferImporter, a, buftools.PyBUF_ND)
+        self.assertRaises(BufferError, BufferImporter, a,
+                          buftools.PyBUF_C_CONTIGUOUS)
+        self.assertRaises(BufferError, BufferImporter, a,
+                          buftools.PyBUF_F_CONTIGUOUS)
+        self.assertRaises(BufferError, BufferImporter, a,
+                          buftools.PyBUF_ANY_CONTIGUOUS)
+
     def NEWBUF_test_newbuf_PyBUF_flags_3D(self):
         self.fail()
     def NEWBUF_test_newbuf_PyBUF_flags_rgba(self):