Commits

Lenard Lindstrom  committed 59c3bbb

Add new buffer interface to pygame._view.View, and update Surface.get_view.

For Python 3.x, pygame._view.View now exposes a new buffer interface. Internally, View now stores a Py_buffer. This makes it comparable to a Python memoryview. However, View also takes callbacks that support buffer creation and release event. This enables explicit control of Surface locking through the View proxy.

This is a preliminary commit. The changes build with Python 3.3. However, further buffer interface unit testing is needed.

  • Participants
  • Parent commits bf94911

Comments (0)

Files changed (4)

 #define VIEW_OTHER_ENDIAN '<'
 #endif
 
+typedef struct PgViewObject_s {
+    PyObject_HEAD
+    Py_buffer bufview;
+    Py_ssize_t imem[6];                   /* shape/stride alloc for ndim <= 3 */
+    char cmem[3];                         /* format alloc for simple types    */
+    int flags;                            /* contiguity and array shape order */
+    PgView_PreludeCallback prelude;       /* Lock callback                    */
+    PgView_PostscriptCallback postscript; /* Release callback                 */
+    PyObject *pyprelude;                  /* Python lock callable             */
+    PyObject *pypostscript;               /* Python release callback          */
+    int global_release;                   /* dealloc callback flag            */
+    PyObject *weakrefs;                   /* There can be reference cycles    */
+} PgViewObject;
+
+typedef struct capsule_interface_s {
+    PyArrayInterface inter;
+    PyObject *parent;
+    Py_intptr_t imem[1];
+} CapsuleInterface;
+
 static int Pg_GetArrayInterface(PyObject *, PyObject **, PyArrayInterface **);
 static PyObject *Pg_ArrayStructAsDict(PyArrayInterface *);
+static PyObject *Pg_BufferViewAsDict(Py_buffer *);
 
 /**
  * Helper functions.
 {
     PgViewObject *v = (PgViewObject *)view;
     PyObject *rvalue;
+    PyObject *parent;
     int failed = 0;
     
-    rvalue = PyObject_CallFunctionObjArgs(v->pyprelude, v->parent, 0);
+    parent = (PyObject *)v->bufview.obj;
+    if (!parent) {
+        parent = Py_None;
+    }
+    Py_INCREF(parent);
+    rvalue = PyObject_CallFunctionObjArgs(v->pyprelude, parent, 0);
+    Py_DECREF(parent);
     if (rvalue) {
         Py_DECREF(rvalue);
     }
 {
     PgViewObject *v = (PgViewObject *)view;
     PyObject *rvalue;
+    PyObject *parent;
 
-    rvalue = PyObject_CallFunctionObjArgs(v->pypostscript, v->parent, 0);
+    parent = (PyObject *)v->bufview.obj;
+    if (!parent) {
+        parent = Py_None;
+    }
+    Py_INCREF(parent);
+    rvalue = PyObject_CallFunctionObjArgs(v->pypostscript, parent, 0);
     PyErr_Clear();
     Py_XDECREF(rvalue);
+    Py_DECREF(parent);
 }
 
 static PyObject *
 _view_new_from_type(PyTypeObject *type,
-                    PyArrayInterface *inter_p,
-                    PyObject *parent,
+                    Py_buffer *bufview,
+                    int flags,
                     PgView_PreludeCallback prelude,
                     PgView_PostscriptCallback postscript,
                     PyObject *pyprelude,
                     PyObject *pypostscript)
 {
-    int nd = inter_p->nd;
+    int ndim = bufview->ndim;
     PgViewObject *self;
-    Py_intptr_t *intmem;
-    int i;
+    Py_ssize_t *shape = 0;
+    Py_ssize_t *strides = 0;
+    Py_ssize_t format_len = 0;
+    char *format = 0;
 
-    if (inter_p->two != 2) {
-        PyErr_SetString(PyExc_SystemError,
-                        "pygame: _view_new_from_type:"
-                        " array interface two.");
+    if (bufview->suboffsets) {
+        PyErr_SetString(PyExc_BufferError, "unable to handle suboffsets");
         return 0;
     }
-    if ((inter_p->flags & PAI_ARR_HAS_DESCR) && !inter_p->descr) {
-        PyErr_SetString(PyExc_SystemError,
-                        "pygame: _view_new_from_type:"
-                        " array interface descr");
-        return 0;
+    if (bufview->format) {
+        format_len = strlen(bufview->format);
+        if (format_len > 2) {
+            format = PyMem_New(char, format_len + 1);
+            if (!format) {
+                return PyErr_NoMemory();
+            }
+        }
     }
-    
-    intmem = PyMem_New(Py_intptr_t, (inter_p->strides ? 2 : 1) * nd);
-    if (!intmem) {
-        return PyErr_NoMemory();
+    if (ndim > 3) {
+        shape = PyMem_New(Py_ssize_t, 2 * ndim);
+        if (!shape) {
+            if (format) {
+                PyMem_Free(format);
+            }
+            return PyErr_NoMemory();
+        }
+        strides = shape + ndim;
     }
     
     self = (PgViewObject *)type->tp_alloc(type, 0);
     if (!self) {
-        PyMem_Free(intmem);
+        if (format) {
+            PyMem_Free(format);
+        }
+        if (shape) {
+            PyMem_Free(shape);
+        }
         return 0;
     }
-    
+
+    if (!shape) {
+        shape = self->imem;
+        strides = shape + ndim;
+    }
+    if (!format) {
+        format = self->cmem;
+    }
     self->weakrefs = 0;
-    self->inter.two = 2;
-    self->inter.nd = nd;
-    self->inter.typekind = inter_p->typekind;
-    self->inter.itemsize = inter_p->itemsize;
-    self->inter.flags = inter_p->flags;
-    self->inter.shape = intmem;
-    for (i = 0; i < nd; ++i) {
-        intmem[i] = inter_p->shape[i];
-    }
-    if (inter_p->strides) {
-        intmem += nd;
-        self->inter.strides = intmem;
-        for (i = 0; i < nd; ++i) {
-            intmem[i] = inter_p->strides[i];
-        }
+    memcpy(&(self->bufview), bufview, sizeof(Py_buffer));
+    self->bufview.format = format;
+    if (bufview->format) {
+        strcpy(format, bufview->format);
     }
     else {
-        inter_p->strides = 0;
+        format[0] = 'B';
+        format[1] = '\0';
     }
-    self->inter.data = inter_p->data;
-    if (inter_p->flags & PAI_ARR_HAS_DESCR) {
-        Py_INCREF(inter_p->descr);
-        self->inter.descr = inter_p->descr;
+    if (bufview->shape) {
+        self->bufview.shape = shape;
+        memcpy(shape, bufview->shape, sizeof(Py_ssize_t) * ndim);
     }
-    else {
-        self->inter.descr = 0;
+    if (bufview->strides) {
+        self->bufview.strides = strides;
+        memcpy(strides, bufview->strides, sizeof(Py_ssize_t) * ndim);
     }
-    if (!parent) {
-        parent = Py_None;
-    }
-    Py_INCREF(parent);
-    self->parent = parent;
+    
+    self->flags = flags;
     self->prelude = _view_null_prelude;
     if (pyprelude) {
         Py_INCREF(pyprelude);
     return (PyObject *)self;
 }
 
+static char
+_as_arrayinter_typekind(const Py_buffer *view)
+{
+    char type = view->format[0];
+    char typekind;
+    
+    switch (type) {
+    
+    case '<':
+    case '>':
+    case '=':
+    case '@':
+    case '!':
+        type = view->format[1];
+    }
+    switch (type) {
+        
+    case 'c':
+    case 'h':
+    case 'i':
+    case 'l':
+    case 'q':
+        typekind = 'i';
+        break;
+    case 'b':
+    case 'B':
+    case 'H':
+    case 'I':
+    case 'L':
+    case 'Q':
+    case 's':
+        typekind = 'u';
+        break;
+    default:
+        /* Unknown type */
+        typekind = 's';
+    }
+    return typekind;
+}
+
+static char
+_as_arrayinter_byteorder(const Py_buffer *view)
+{
+    char format_0 = view->format[0];
+    char byteorder;
+    
+    switch (format_0) {
+        
+    case '<':
+    case '>':
+        byteorder = format_0;
+        break;
+    case '!':
+        byteorder = '>';
+        break;
+    case 'c':
+    case 's':
+    case 'p':
+    case 'b':
+    case 'B':
+        byteorder = '|';
+        break;
+    default:
+        byteorder = VIEW_MY_ENDIAN;
+    }
+    return byteorder;
+}
+
+static int
+_as_arrayinter_flags(const Py_buffer *view, int flags)
+{
+    int inter_flags = PAI_ALIGNED; /* atomic int types always aligned */
+    
+    if (!view->readonly) {
+        inter_flags |= PAI_WRITEABLE;
+    }
+    switch (view->format[0]) {
+        
+    case '<':
+        inter_flags |= SDL_BYTEORDER == SDL_LIL_ENDIAN ? PAI_NOTSWAPPED : 0;
+        break;
+    case '>':
+    case '!':
+        inter_flags |= SDL_BYTEORDER == SDL_BIG_ENDIAN ? PAI_NOTSWAPPED : 0;
+        break;
+    default:
+        inter_flags |= PAI_NOTSWAPPED;
+    }
+    if (flags & VIEW_CONTIGUOUS) {
+        inter_flags |= PAI_CONTIGUOUS;
+    }
+    if (flags & VIEW_F_ORDER) {
+        inter_flags |= PAI_FORTRAN;
+    }
+    return inter_flags;
+}
+
+static CapsuleInterface *
+_new_capsuleinterface(const Py_buffer *view, int flags)
+{
+    int ndim = view->ndim;
+    Py_ssize_t cinter_size;
+    CapsuleInterface *cinter_p;
+    int i;
+    
+    cinter_size = (sizeof(CapsuleInterface) +
+                   sizeof(Py_intptr_t) * (2 * ndim - 1));
+    cinter_p = (CapsuleInterface *)PyMem_Malloc(cinter_size);
+    if (!cinter_p) {
+        PyErr_NoMemory();
+        return 0;
+    }
+    cinter_p->inter.two = 2;
+    cinter_p->inter.nd = ndim;
+    cinter_p->inter.typekind = _as_arrayinter_typekind(view);
+    cinter_p->inter.itemsize = view->itemsize;
+    cinter_p->inter.flags = _as_arrayinter_flags(view, flags);
+    if (view->shape) {
+        cinter_p->inter.shape = cinter_p->imem;
+        for (i = 0; i < ndim; ++i) {
+            cinter_p->inter.shape[i] = (Py_intptr_t)view->shape[i];
+        }
+    }
+    if (view->strides) {
+        cinter_p->inter.strides = cinter_p->imem + ndim;
+        for (i = 0; i < ndim; ++i) {
+            cinter_p->inter.strides[i] = (Py_intptr_t)view->strides[i];
+        }
+    }
+    cinter_p->inter.data = view->buf;
+    cinter_p->inter.descr = 0;
+    cinter_p->parent = (PyObject *)view->obj;
+    Py_XINCREF(cinter_p->parent);
+    return cinter_p;
+}
+
+static void
+_free_capsuleinterface(void *p)
+{
+    CapsuleInterface *cinter_p = (CapsuleInterface *)p;
+    
+    Py_XDECREF(cinter_p->parent);
+    PyMem_Free(p);
+}
+
+#if PY3
+static void
+_capsule_free_capsuleinterface(PyObject *capsule)
+{
+    _free_capsuleinterface(PyCapsule_GetPointer(capsule, 0));
+}
+#endif
+
+static PyObject *
+_view_get_typestr_obj(Py_buffer *view)
+{
+    return Text_FromFormat("%c%c%i",
+                           _as_arrayinter_byteorder(view),
+                           _as_arrayinter_typekind(view),
+                           (int)view->itemsize);
+}
+
+static PyObject *
+_view_get_shape_obj(Py_buffer *view)
+{
+    PyObject *shapeobj = PyTuple_New(view->ndim);
+    PyObject *lengthobj;
+    Py_ssize_t i;
+
+    if (!shapeobj) {
+        return 0;
+    }
+    for (i = 0; i < view->ndim; ++i) {
+        lengthobj = PyInt_FromLong((long)view->shape[i]);
+        if (!lengthobj) {
+            Py_DECREF(shapeobj);
+            return 0;
+        }
+        PyTuple_SET_ITEM(shapeobj, i, lengthobj);
+    }
+    return shapeobj;
+}
+
+static PyObject *
+_view_get_strides_obj(Py_buffer *view)
+{
+    PyObject *shapeobj = PyTuple_New(view->ndim);
+    PyObject *lengthobj;
+    Py_ssize_t i;
+
+    if (!shapeobj) {
+        return 0;
+    }
+    for (i = 0; i < view->ndim; ++i) {
+        lengthobj = PyInt_FromLong((long)view->strides[i]);
+        if (!lengthobj) {
+            Py_DECREF(shapeobj);
+            return 0;
+        }
+        PyTuple_SET_ITEM(shapeobj, i, lengthobj);
+    }
+    return shapeobj;
+}
+
+static PyObject *
+_view_get_data_obj(Py_buffer *view)
+{
+    return Py_BuildValue("NN",
+                         PyLong_FromVoidPtr(view->buf),
+                         PyBool_FromLong((long)view->readonly));
+}
+
 static PyObject *
 _shape_as_tuple(PyArrayInterface *inter_p)
 {
 static int
 _shape_arg_convert(PyObject *o, void *a)
 {
-    PyArrayInterface *inter_p = (PyArrayInterface *)a;
+    Py_buffer *view = (Py_buffer *)a;
     
-    if (!_tuple_as_ints(o, "shape", &(inter_p->shape), &(inter_p->nd))) {
+    if (!_tuple_as_ints(o, "shape", &view->shape, &view->ndim)) {
         return 0;
     }
     return 1;
      * as well as significant unicode changes in Python 3.3, this will
      * only handle integer types.
      */
-    PyArrayInterface *inter_p = (PyArrayInterface *)a;
-    int flags = inter_p->flags;
-    char typekind;
+    Py_buffer *view = (Py_buffer *)a;
+    char type;
+    int is_signed;
+    int is_swapped;
+    char byteorder = '\0';
     int itemsize;
+    char *format;
     PyObject *s;
     const char *typestr;
     
+    format = (char *)&view->internal;
     if (PyUnicode_Check(o)) {
         s = PyUnicode_AsASCIIString(o);
         if (!s) {
     switch (typestr[0]) {
 
     case VIEW_MY_ENDIAN:
-        flags |= PAI_NOTSWAPPED;
+        is_swapped = 0;
         break;
     case VIEW_OTHER_ENDIAN:
+        is_swapped = 1;
         break;
     case '|':
+        is_swapped = 0;
         break;
     default:
         PyErr_Format(PyExc_ValueError,
         Py_DECREF(s);
         return 0;
     }
-    typekind = typestr[1];
-    switch (typekind) {
+    switch (typestr[1]) {
 
     case 'i':
+        is_signed = 1;
         break;
     case 'u':
+        is_signed = 0;
         break;
     default:
         PyErr_Format(PyExc_ValueError,
                      "unsupported typekind %c in typestr",
-                     typekind);
+                     typestr[1]);
         Py_DECREF(s);
         return 0;
     }
     switch (typestr[2]) {
 
     case '1':
+        type = is_signed ? 'c' : 'B';
         itemsize = 1;
         break;
     case '2':
+        byteorder = is_swapped ? VIEW_OTHER_ENDIAN : '=';
+        type = is_signed ? 'h' : 'H';
         itemsize = 2;
         break;
     case '3':
+        type = 's';
         itemsize = 3;
         break;
     case '4':
+        byteorder = is_swapped ? VIEW_OTHER_ENDIAN : '=';
+        type = is_signed ? 'i' : 'I';
         itemsize = 4;
         break;
     case '6':
+        type = 's';
         itemsize = 6;
         break;
     case '8':
+        byteorder = is_swapped ? VIEW_OTHER_ENDIAN : '=';
+        type = is_signed ? 'q' : 'Q';
         itemsize = 8;
         break;
     default:
         Py_DECREF(s);
         return 0;
     }
-    inter_p->typekind = typekind;
-    inter_p->itemsize = itemsize;
-    inter_p->flags = flags;
+    if (byteorder != '\0') {
+        format[0] = byteorder;
+        format[1] = type;
+        format[2] = '\0';
+    }
+    else {
+        format[0] = type;
+        format[1] = '\0';
+    }
+    view->format = format;
+    view->itemsize = itemsize;
     return 1;
 }
 
 {
     /* Must be called after the array interface nd field has been filled in.
      */
-    PyArrayInterface *inter_p = (PyArrayInterface *)a;
+    Py_buffer *view = (Py_buffer *)a;
     int n = 0;
 
     if (o == Py_None) {
         return 1; /* no strides (optional) given */
     }
-    if (!_tuple_as_ints(o, "strides", &(inter_p->strides), &n)) {
+    if (!_tuple_as_ints(o, "strides", &view->strides, &n)) {
         return 0;
     }
-    if (n != inter_p->nd) {
+    if (n != view->ndim) {
         PyErr_SetString(PyExc_TypeError,
                         "strides and shape tuple lengths differ");
         return 0;
 static int
 _data_arg_convert(PyObject *o, void *a)
 {
-    PyArrayInterface *inter_p = (PyArrayInterface *)a;
+    Py_buffer *view = (Py_buffer *)a;
     Py_ssize_t address;
     int readonly;
     
                      Py_TYPE(PyTuple_GET_ITEM(o, 0))->tp_name);
         return 0;
     }
-    inter_p->data = (void *)address;
-    inter_p->flags |= readonly ? 0 : PAI_WRITEABLE;
+    view->buf = (void *)address;
+    view->readonly = readonly;
+    return 1;
+}
+
+static int
+_parent_arg_convert(PyObject *o, void *a)
+{
+    Py_buffer *view = (Py_buffer *)a;
+    
+    if (o != Py_None) {
+        view->obj = o;
+        Py_INCREF(o);
+    }
     return 1;
 }
 
 static void
-_free_inter(PyArrayInterface *inter_p)
+_free_bufview(Py_buffer *view)
 {
-    if (inter_p->shape) {
-        PyMem_Free(inter_p->shape);
+    if (view->shape) {
+        PyMem_Free(view->shape);
     }
-    if (inter_p->strides) {
-        PyMem_Free(inter_p->strides);
+    if (view->strides) {
+        PyMem_Free(view->strides);
     }
+    Py_XDECREF(view->obj);
 }
 
 /**
 static PyObject *
 _view_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
 {
-    PyArrayInterface inter = {0, 0, '\0', 0, 0, 0, 0, 0, 0};
-    PyObject *parent = 0;
+    Py_buffer bufview;
     PyObject *pyprelude = 0;
     PyObject *pypostscript = 0;
-    void *inter_vp = (void *)&inter;
     PyObject *self = 0;
     /* The argument evaluation order is important: strides must follow shape. */
     char *keywords[] = {"shape", "typestr", "data", "strides", "parent",
                         "prelude", "postscript", 0};
-                        
-    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&O&O&|O&OOO:View", keywords,
-                                     _shape_arg_convert, inter_vp,
-                                     _typestr_arg_convert, inter_vp,
-                                     _data_arg_convert, inter_vp,
-                                     _strides_arg_convert, inter_vp,
-                                     &parent, &pyprelude, &pypostscript)) {
-        _free_inter(&inter);
+               
+    bufview.obj = 0;
+    bufview.len = 0;
+    bufview.readonly = 1;
+    bufview.ndim = 0;
+    bufview.shape = 0;
+    bufview.strides = 0;
+    bufview.suboffsets = 0;
+    bufview.itemsize = 0;
+    bufview.internal = 0;
+    
+    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&O&O&|O&O&OO:View", keywords,
+                                     _shape_arg_convert, &bufview,
+                                     _typestr_arg_convert, &bufview,
+                                     _data_arg_convert, &bufview,
+                                     _strides_arg_convert, &bufview,
+                                     _parent_arg_convert, &bufview,
+                                     &pyprelude, &pypostscript)) {
+        _free_bufview(&bufview);
         return 0;
     }
-    if (parent == Py_None) {
-        parent = 0;
-    }
     if (pyprelude == Py_None) {
         pyprelude = 0;
     }
     if (pypostscript == Py_None) {
         pypostscript = 0;
     }
-    inter.two = 2;
-    self = _view_new_from_type(type,
-                               &inter,
-                               parent,
-                               0,
-                               0,
-                               pyprelude,
-                               pypostscript);
-    _free_inter(&inter);
+    Py_XINCREF((PyObject *)bufview.obj);
+    self = _view_new_from_type(type, &bufview, 0,
+                               0, 0, pyprelude, pypostscript);
+    _free_bufview(&bufview);
     return self;
 }
 
 _view_dealloc(PgViewObject *self)
 {
     /* Guard against recursion */
-    if (self->inter.two == 0) {
+    if (!self->prelude) {
         return;
     }
-    self->inter.two = 0;
+    self->prelude = 0;
     
     if (self->global_release) {
         self->postscript((PyObject *)self);
     }
-    Py_DECREF(self->parent);
+    Py_XDECREF((PyObject *)self->bufview.obj);
     Py_XDECREF(self->pyprelude);
     Py_XDECREF(self->pypostscript);
     if (self->weakrefs) {
         PyObject_ClearWeakRefs((PyObject *)self);
     }
-    PyMem_Free(self->inter.shape);
+    if (self->bufview.shape && self->bufview.shape != self->imem) {
+        PyMem_Free(self->bufview.shape);
+    }
+    if (self->bufview.format && self->bufview.format != self->cmem) {
+        PyMem_Free(self->bufview.format);
+    }
     Py_TYPE(self)->tp_free(self);
 }
 
 static PyObject *
 _view_get_arraystruct(PgViewObject *self, PyObject *closure)
 {
-    PyObject *capsule = Capsule_New(&self->inter);
-
-    if (capsule && !self->global_release /* conditional && */ ) {
+    void *cinter_p;
+    PyObject *capsule;
+    
+    cinter_p = _new_capsuleinterface(&self->bufview, self->flags);
+    if (!cinter_p) {
+        return 0;
+    }
+#if PY3
+    capsule = PyCapsule_New(cinter_p, 0, _capsule_free_capsuleinterface);
+#else
+    capsule = PyCObject_FromVoidPtr(cinter_p, _free_capsuleinterface);
+#endif
+    if (!capsule) {
+        _free_capsuleinterface((void *)cinter_p);
+        return 0;
+    }
+    if (!self->global_release) {
         if (self->prelude((PyObject *)self)) {
             Py_DECREF(capsule);
             capsule = 0;
     return capsule;
 }
 
+#if PY3
+#else
+#endif
+
 static PyObject *
 _view_get_arrayinterface(PgViewObject *self, PyObject *closure)
 {
-    PyObject *dict = Pg_ArrayStructAsDict(&self->inter);
+    PyObject *dict = Pg_BufferViewAsDict(&self->bufview);
     
     if (dict && !self->global_release) {
         if (self->prelude((PyObject *)self)) {
 static PyObject *
 _view_get_parent(PgViewObject *self, PyObject *closure)
 {
-    if (!self->parent) {
+    PyObject *parent = (PyObject *)self->bufview.obj;
+    
+    if (!parent) {
         Py_RETURN_NONE;
     }
-    Py_INCREF(self->parent);
-    return self->parent;
+    Py_INCREF(parent);
+    return parent;
 }
 
 /**** Methods ****/
     {0, 0, 0, 0, 0}
 };
 
+#if PY3
+static int
+_view_getbuffer(PyObject *obj, Py_buffer *view, int flags)
+{
+    PgViewObject *v = (PgViewObject *)obj;
+    
+    if (flags == PyBUF_SIMPLE && !(v->flags & VIEW_CONTIGUOUS)) {
+        PyErr_SetString(PyExc_BufferError, "buffer not contiguous");
+        return -1;
+    }
+    if (flags & PyBUF_WRITABLE && v->bufview.readonly) {
+        PyErr_SetString(PyExc_BufferError, "buffer is readonly");
+        return -1;
+    }
+    if (flags & PyBUF_ND && !v->bufview.shape) {
+        PyErr_SetString(PyExc_BufferError, "buffer shape unavailable");
+        return -1;
+    }
+    if (flags & PyBUF_STRIDES && !v->bufview.strides) {
+        PyErr_SetString(PyExc_BufferError, "buffer strides unavailable");
+        return -1;
+    }
+    else if (flags & PyBUF_ND &&
+             !(v->flags & (VIEW_CONTIGUOUS | VIEW_C_ORDER))) {
+        PyErr_SetString(PyExc_BufferError, "buffer not C contiguous");
+        return -1;
+    }            
+    if (flags & PyBUF_ANY_CONTIGUOUS &&
+        !(v->flags & (VIEW_CONTIGUOUS | VIEW_C_ORDER | VIEW_F_ORDER))) {
+        PyErr_SetString(PyExc_BufferError, "buffer not contiguous");
+        return -1;
+    }
+    if (flags & PyBUF_C_CONTIGUOUS &&
+        !(v->flags & (VIEW_CONTIGUOUS | VIEW_C_ORDER))) {
+        PyErr_SetString(PyExc_BufferError, "buffer not C contiguous");
+        return -1;
+    }
+    if (flags & PyBUF_F_CONTIGUOUS &&
+        !(v->flags & (VIEW_CONTIGUOUS | VIEW_F_ORDER))) {
+        PyErr_SetString(PyExc_BufferError, "buffer not F contiguous");
+        return -1;
+    }
+    if (v->prelude(obj)) {
+        return -1;
+    }
+    view->obj = obj;
+    Py_INCREF(obj);
+    view->buf = v->bufview.buf;
+    view->len = v->bufview.len;
+    view->readonly = v->bufview.readonly;
+    view->format = v->bufview.format;
+    view->ndim = v->bufview.ndim;
+    view->shape = v->bufview.shape;
+    view->strides = v->bufview.strides;
+    view->suboffsets = v->bufview.suboffsets;
+    view->itemsize = v->bufview.itemsize;
+    view->internal = 0;
+    return 0;
+}
+
+static void
+_view_releasebuffer(PyObject *obj, Py_buffer *view)
+{
+    ((PgViewObject *)obj)->postscript(obj);
+}
+
+static PyBufferProcs _view_bufferprocs = 
+    {_view_getbuffer, _view_releasebuffer};
+#endif
 
 static PyTypeObject PgView_Type =
 {
     0,                          /* tp_str */
     0,                          /* tp_getattro */
     0,                          /* tp_setattro */
+#if PY3
+    &_view_bufferprocs,         /* tp_as_buffer */
+#else
     0,                          /* tp_as_buffer */
-    (Py_TPFLAGS_HAVE_WEAKREFS | Py_TPFLAGS_BASETYPE |
-     Py_TPFLAGS_HAVE_CLASS),
+#endif
+    Py_TPFLAGS_DEFAULT,         /* tp_flags */
     "Object view as an array struct\n",
     0,                          /* tp_traverse */
     0,                          /* tp_clear */
 /**** Public C api ***/
 
 static PyObject *
-PgView_New(PyArrayInterface *inter_p,
-           PyObject *parent,
+PgView_New(Py_buffer *bufview,
+           int flags,
            PgView_PreludeCallback prelude,
            PgView_PostscriptCallback postscript)
 {
     return _view_new_from_type(&PgView_Type,
-                               inter_p,
-                               parent,
+                               bufview,
+                               flags,
                                prelude,
                                postscript,
                                0,
                                0);
 }
 
+static PyObject *
+PgView_GetParent(PyObject *view)
+{
+    PyObject *parent = (PyObject *)((PgViewObject *) view)->bufview.obj;
+    
+    if (!parent) {
+        parent = Py_None;
+    }
+    Py_INCREF(parent);
+    return parent;
+}
+
 static int
 Pg_GetArrayInterface(PyObject *obj,
                      PyObject **cobj_p,
         inter = (PyArrayInterface *)PyCapsule_GetPointer(cobj, NULL);
     }
 #endif
-    if (inter == NULL ||   /* conditional or */
-        inter->two != 2  ) {
+    if (inter == NULL || inter->two != 2 /* conditional or */) {
         Py_DECREF(cobj);
         PyErr_SetString(PyExc_ValueError, "invalid array interface");
         return -1;
             return 0;
         }
         if (PyDict_SetItemString(dictobj, "descr", inter_p->descr)) {
+            Py_DECREF(dictobj);
+            return 0;
+        }
+    }
+    return dictobj;
+}
+
+static PyObject *
+Pg_BufferViewAsDict(Py_buffer *bufview)
+{
+    PyObject *dictobj = Py_BuildValue("{sisNsNsNsN}",
+                                      "version", (int)3,
+                                      "typestr", _view_get_typestr_obj(bufview),
+                                      "shape", _view_get_shape_obj(bufview),
+                                      "strides", _view_get_strides_obj(bufview),
+                                      "data", _view_get_data_obj(bufview));
+    PyObject *obj = (PyObject *)bufview->obj;
+
+    if (!dictobj) {
+        return 0;
+    }
+    if (obj) {
+        if (PyDict_SetItemString(dictobj, "__obj", obj)) {
+            Py_DECREF(dictobj);
             return 0;
         }
     }
         DECREF_MOD(module);
         MODINIT_ERROR;
     }
-#if PYGAMEAPI_VIEW_NUMSLOTS != 4
+#if PYGAMEAPI_VIEW_NUMSLOTS != 5
 #error export slot count mismatch
 #endif
     c_api[0] = &PgView_Type;
     c_api[1] = PgView_New;
-    c_api[2] = Pg_GetArrayInterface;
-    c_api[3] = Pg_ArrayStructAsDict;
+    c_api[2] = PgView_GetParent;
+    c_api[3] = Pg_GetArrayInterface;
+    c_api[4] = Pg_ArrayStructAsDict;
     apiobj = encapsulate_api(c_api, "_view");
     if (apiobj == NULL) {
         DECREF_MOD(module);

File src/pgcompat.h

 #define PyInt_AsSsize_t PyInt_AsLong
 #endif
 
+/* Python 2.5 and earlier (PEP 3118) Py_buffer */
+#if PY_VERSION_HEX < 0x02060000
+struct bufferinfo {
+    void *obj;
+    void *buf;
+    Py_ssize_t len;
+    int readonly;
+    const char *format;
+    int ndim;
+    Py_ssize_t *shape;
+    Py_ssize_t *strides;
+    Py_ssize_t *suboffsets;
+    Py_ssize_t itemsize;
+    void *internal;
+} Py_buffer;
+#endif
+
 #endif /* #if !defined(PGCOMPAT_H) */

File src/pgview.h

 typedef int (*PgView_PreludeCallback)(PyObject *);
 typedef void (*PgView_PostscriptCallback)(PyObject *);
 
-typedef struct PgViewObject_s {
-    PyObject_HEAD
-    PyArrayInterface inter;
-    PyObject *parent;                     /* Object responsible for the view  */
-    PgView_PreludeCallback prelude;       /* Lock callback                    */
-    PgView_PostscriptCallback postscript; /* Release callback                 */
-    PyObject *pyprelude;                  /* Python lock callable             */
-    PyObject *pypostscript;               /* Python release callback          */
-    int global_release;                   /* dealloc callback flag            */
-    PyObject *weakrefs;                   /* There can be reference cycles    */
-} PgViewObject;
+/* View flags */
+#define VIEW_CONTIGUOUS    1
+#define VIEW_C_ORDER       2
+#define VIEW_F_ORDER       4 
 
-#define PYGAMEAPI_VIEW_NUMSLOTS 4
+#define PYGAMEAPI_VIEW_NUMSLOTS 5
 #define PYGAMEAPI_VIEW_FIRSTSLOT 0
 
 #if !(defined(PYGAMEAPI_VIEW_INTERNAL) || defined(NO_PYGAME_C_API))
 static void *PgVIEW_C_API[PYGAMEAPI_VIEW_NUMSLOTS];
 
-typedef PyObject *(*_pgview_new_t)(PyArrayInterface *inter_p,
-                                   PyObject *parent,
-                                   PgView_PreludeCallback prelude,
-                                   PgView_PostscriptCallback postscript);
-typedef PyObject *(*_pgview_get_t)(PyObject *view);
-typedef int *(*_pg_getarrayinterface_t)(PyObject *obj,
-                                        PyObject **cobj_p,
-                                        PyArrayInterface **inter_p);
+typedef PyObject *(*_pgview_new_t)(Py_buffer *,
+                                   int,
+                                   PgView_PreludeCallback,
+                                   PgView_PostscriptCallback);
+typedef PyObject *(*_pgview_get_obj_t)(PyObject *);
+typedef int *(*_pg_getarrayinterface_t)(PyObject *,
+                                        PyObject **,
+                                        PyArrayInterface **);
 typedef PyObject *(*_pg_arraystructasdict_t)(PyArrayInterface *inter_p);
 
 #define PgView_Type (*(PyTypeObject*)PgVIEW_C_API[0])
 #define PgView_New (*(_pgview_new_t)PgVIEW_C_API[1])
-#define Pg_GetArrayInterface (*(_pg_getarrayinterface_t)PgVIEW_C_API[2])
-#define Pg_ArrayStructAsDict (*(_pg_arraystructasdict_t)PgVIEW_C_API[3])
+#define PgView_GetParent (*(_pgview_get_obj_t)PgVIEW_C_API[2])
+#define Pg_GetArrayInterface (*(_pg_getarrayinterface_t)PgVIEW_C_API[3])
+#define Pg_ArrayStructAsDict (*(_pg_arraystructasdict_t)PgVIEW_C_API[4])
 #define PgView_Check(x) ((x)->ob_type == (PgView_Type))
 #define import_pygame_view() \
     _IMPORT_PYGAME_MODULE(_view, VIEW, PgVIEW_C_API)
 
 #endif /* #if !(defined(PYGAMEAPI_VIEW_INTERNAL) || ... */
 
-#define PgView_GET_PYARRAYINTERFACE(o) (&(((PgViewObject *)(o))->inter))
-#define PgView_GET_PARENT(o) (((PgViewObject *)(o))->parent)
-
 #define PG_VIEW_HEADER
 
 #endif /* #if !defined(PG_VIEW_HEADER) */

File src/surface.c

                                          PyObject *kwargs);
 static PyObject *surf_get_pixels_address (PyObject *self,
                                           PyObject *closure);
-static int surf_view_kind(PyObject *obj, void *view_kind_vptr);
-static int _surf_view_prelude(PyObject *view);
-static void _surf_view_postscript(PyObject *view);
+static int _view_kind(PyObject *obj, void *view_kind_vptr);
+static int _view_prelude(PyObject *view);
+static void _view_postscript(PyObject *view);
 static PyObject *_raise_get_view_ndim_error(int bitsize, SurfViewKind kind);
 
 
     return rect;
 }
 
-static PyObject
-*surf_get_buffer (PyObject *self)
+static PyObject*
+surf_get_buffer (PyObject *self)
 {
     PyObject *buffer;
     PyObject *lock;
     return 0;
 }
 
-static PyObject *
-surf_get_view(PyObject *self, PyObject *args, PyObject *kwds)
+static PyObject*
+surf_get_view (PyObject *self, PyObject *args, PyObject *kwds)
 {
 #   define SURF_GET_VIEW_MAXDIM 3
     const int lilendian = (SDL_BYTEORDER == SDL_LIL_ENDIAN);
     const int maxdim = SURF_GET_VIEW_MAXDIM;
-    Py_intptr_t shape[SURF_GET_VIEW_MAXDIM];
-    Py_intptr_t strides[SURF_GET_VIEW_MAXDIM];
-    PyArrayInterface inter = {0, 0, 'u', 0,
-                              PAI_ALIGNED | PAI_NOTSWAPPED | PAI_WRITEABLE,
-                              shape, strides, 0, 0};
+    Py_ssize_t shape[SURF_GET_VIEW_MAXDIM];
+    Py_ssize_t strides[SURF_GET_VIEW_MAXDIM];
+    char format[] = {'B', '\0', '\0'};
+    Py_buffer bufview;
 #   undef SURF_GET_VIEW_MAXDIM
     SurfViewKind view_kind = VIEWKIND_2D;
     int ndim = maxdim;
-    SDL_Surface *surface = PySurface_AsSurface(self);
+    SDL_Surface *surface = PySurface_AsSurface (self);
     int pixelsize;
-    int itemsize = 0;
+    Py_ssize_t itemsize = 0;
     Uint8 *startpixel;
     Uint32 mask = 0;
     int pixelstep;
+    int flags = 0;
     
     char *keywords[] = {"kind", 0};
 
-    if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O&", keywords,
-                     surf_view_kind, &view_kind)) {
+    if (!PyArg_ParseTupleAndKeywords (args, kwds, "|O&", keywords,
+                                      _view_kind, &view_kind)) {
         return 0;
     }
 
     if (!surface) {
-        return RAISE(PyExc_SDLError, "display Surface quit");
+        return RAISE (PyExc_SDLError, "display Surface quit");
     }
 
+    bufview.readonly = 0;
+    bufview.shape = shape;
+    bufview.strides = strides;
+    bufview.format = format;
+    bufview.suboffsets = 0;
+    bufview.internal = 0;
+    
     startpixel = surface->pixels;
     pixelsize = surface->format->BytesPerPixel;
-    shape[0] = (Py_intptr_t)surface->w;
-    shape[1] = (Py_intptr_t)surface->h;
-    strides[0] = (Py_intptr_t)pixelsize;
-    strides[1] = (Py_intptr_t)surface->pitch;
+    shape[0] = (Py_ssize_t)surface->w;
+    shape[1] = (Py_ssize_t)surface->h;
+    strides[0] = (Py_ssize_t)pixelsize;
+    strides[1] = (Py_ssize_t)surface->pitch;
     switch (view_kind) {
 
     case VIEWKIND_2D:
         ndim = 2;
         itemsize = pixelsize;
-        if (strides[1] == shape[0] * pixelsize) {
-            inter.flags |= PAI_CONTIGUOUS;
+        flags |= VIEW_F_ORDER;
+        if (strides[1] == shape[0] * itemsize) {
+            flags |= VIEW_CONTIGUOUS;
         }
         break;
     case VIEWKIND_3D:
         if (pixelsize < 3) {
-            return _raise_get_view_ndim_error(pixelsize * 8, view_kind);
+            return _raise_get_view_ndim_error (pixelsize * 8, view_kind);
         }
         ndim = 3;
         itemsize = 1;
         shape[2] = 3;
         if (surface->format->Rmask == 0xff0000 &&
             surface->format->Gmask == 0x00ff00 &&
-            surface->format->Bmask == 0x0000ff)
-        {
+            surface->format->Bmask == 0x0000ff)   {
             strides[2] = lilendian ? -1 : 1;
             startpixel += lilendian ? 2 : 1;
         }
         else if (surface->format->Bmask == 0xff0000 &&
                  surface->format->Gmask == 0x00ff00 &&
-                 surface->format->Rmask == 0x0000ff)
-        {
+                 surface->format->Rmask == 0x0000ff)   {
             strides[2] = lilendian ? 1 : -1;
             startpixel += lilendian ? 0 : (pixelsize - 1);
         }
         else {
-            return RAISE(PyExc_ValueError,
-                         "unsupport colormasks for 3D reference array");
+            return RAISE (PyExc_ValueError,
+                          "unsupport colormasks for 3D reference array");
+        }
+        if (strides[1] == shape[2] * shape[1]) {
+            flags |= VIEW_CONTIGUOUS;
         }
         break;
     case VIEWKIND_RED:
         mask = surface->format->Amask;
         break;
     default:
-        PyErr_Format(PyExc_SystemError,
-                     "pygame bug in surf_get_view:"
-                     " unrecognized view kind %d", (int)view_kind);
+        PyErr_Format (PyExc_SystemError,
+                      "pygame bug in surf_get_view:"
+                      " unrecognized view kind %d", (int)view_kind);
         return 0;
     }
     if (!itemsize) {
         ndim = 2;
         pixelstep = pixelsize;
         itemsize = 1;
+        flags |= VIEW_F_ORDER;
         switch (mask) {
 
         case 0x000000ffU:
             startpixel += lilendian ? 3 : 0;
             break;
         default:
-            return RAISE(PyExc_ValueError,
-                         "unsupported colormasks for alpha reference array");
+            return RAISE (PyExc_ValueError,
+                          "unsupported colormasks for alpha reference array");
         }
     }
-    if (ndim < 3) {
-        inter.flags |= PAI_FORTRAN;
+    bufview.ndim = ndim;
+    bufview.buf = startpixel;
+    bufview.itemsize = itemsize;
+    switch (itemsize) {
+    
+    case 1:
+        break; /* default */
+    case 2:
+        format[0] = '=';
+        format[1] = 'H';
+        break;
+    case 3:
+        format[0] = 's';
+        break;
+    case 4:
+        format[0] = '=';
+        format[1] = 'I';
+        break;
+    default:
+        /* Should not get here. */
+        PyErr_Format (PyExc_SystemError,
+                      "Pygame: Surface.get_item: unrecognized itemsize %d",
+                      (int)itemsize);
+        return 0;
     }
-    inter.nd = ndim;
-    inter.itemsize = itemsize;
-    inter.data = startpixel;
-    inter.two = 2;
-    
-    return PgView_New(&inter, self, _surf_view_prelude, _surf_view_postscript);
+    bufview.len = itemsize * shape[0] * shape[1];
+    if (ndim == 3) {
+        bufview.len *= shape[2];
+    }
+    bufview.obj = self;
+    Py_INCREF (self);
+
+    return PgView_New (&bufview, flags, _view_prelude, _view_postscript);
 }
 
 static int
-surf_view_kind(PyObject *obj, void *view_kind_vptr)
+_view_kind (PyObject *obj, void *view_kind_vptr)
 {
     unsigned long ch;
     SurfViewKind *view_kind_ptr = (SurfViewKind *)view_kind_vptr;
 
-    if (PyUnicode_Check(obj)) {
-        if (PyUnicode_GET_SIZE(obj) != 1) {
-            PyErr_SetString(PyExc_TypeError,
-                            "expected a length 1 string for argument 1");
+    if (PyUnicode_Check (obj)) {
+        if (PyUnicode_GET_SIZE (obj) != 1) {
+            PyErr_SetString (PyExc_TypeError,
+                             "expected a length 1 string for argument 1");
             return 0;
         }
-        ch = *PyUnicode_AS_UNICODE(obj);
+        ch = *PyUnicode_AS_UNICODE (obj);
     }
-    else if (Bytes_Check(obj)) {
-        if (Bytes_GET_SIZE(obj) != 1) {
-            PyErr_SetString(PyExc_TypeError,
-                            "expected a length 1 string for argument 1");
+    else if (Bytes_Check (obj)) {
+        if (Bytes_GET_SIZE (obj) != 1) {
+            PyErr_SetString (PyExc_TypeError,
+                             "expected a length 1 string for argument 1");
             return 0;
         }
-        ch = *Bytes_AS_STRING(obj);
+        ch = *Bytes_AS_STRING (obj);
     }
     else {
-        PyErr_Format(PyExc_TypeError,
-                     "expected a length one string for argument 1: got '%s'",
-                     Py_TYPE(obj)->tp_name);
+        PyErr_Format (PyExc_TypeError,
+                      "expected a length one string for argument 1: got '%s'",
+                      Py_TYPE (obj)->tp_name);
         return 0;
     }
     switch (ch) {
         *view_kind_ptr = VIEWKIND_3D;
         break;
     default:
-        PyErr_Format(PyExc_TypeError,
-                     "unrecognized view kind '%c' for argument 1", (int)ch);
+        PyErr_Format (PyExc_TypeError,
+                      "unrecognized view kind '%c' for argument 1", (int)ch);
         return 0;
     }
     return 1;
 }
 
 static int
-_surf_view_prelude(PyObject *view)
+_view_prelude (PyObject *view)
 {
-    PyObject *surf = PgView_GET_PARENT(view);
+    PyObject *surf = PgView_GetParent (view);
+    int rcode;
     
-    return PySurface_LockBy(surf, view) ? 0 : -1;
+    rcode = PySurface_LockBy (surf, view) ? 0 : -1;
+    Py_DECREF (surf);
+    return rcode;
 }
 
 static void
-_surf_view_postscript(PyObject *view)
+_view_postscript (PyObject *view)
 {
-    PyObject *surf = PgView_GET_PARENT(view);
-
-    PySurface_UnlockBy(surf, view);
+    PyObject *surf = PgView_GetParent(view);
+    
+    PySurface_UnlockBy (surf, view);
+    Py_DECREF (surf);
 }
 
 static PyObject *