gbm: Add gbm_bo_write entry point
authorKristian Høgsberg <krh@bitplanet.net>
Wed, 2 May 2012 19:30:13 +0000 (15:30 -0400)
committerKristian Høgsberg <krh@bitplanet.net>
Thu, 3 May 2012 14:57:32 +0000 (10:57 -0400)
This new gbm entry point allows writing data into a gbm bo.  The bo has
to be created with the GBM_BO_USE_WRITE flag, and it's only required to
work for GBM_BO_USE_CURSOR_64X64 bos.

The gbm API is designed to be the glue layer between EGL and KMS, but there
was never a mechanism initialize a buffer suitable for use with KMS
hw cursors.  The hw cursor bo is typically not compatible with anything EGL
can render to, and thus there's no way to get data into such a bo.

gbm_bo_write() fills that gap while staying out of the efficient
cpu->gpu pixel transfer business.

Reviewed-by: Ander Conselvan de Oliveira <conselvan2@gmail.com>
include/GL/internal/dri_interface.h
src/gbm/backends/dri/gbm_dri.c
src/gbm/main/gbm.c
src/gbm/main/gbm.h
src/gbm/main/gbmint.h
src/mesa/drivers/dri/intel/intel_regions.h
src/mesa/drivers/dri/intel/intel_screen.c

index eafbe10f9b05120d69452bc16670936333588641..e37917eda991a07510ca50a42060a68e46dcbc45 100644 (file)
@@ -894,7 +894,7 @@ struct __DRIdri2ExtensionRec {
  * extensions.
  */
 #define __DRI_IMAGE "DRI_IMAGE"
-#define __DRI_IMAGE_VERSION 3
+#define __DRI_IMAGE_VERSION 4
 
 /**
  * These formats correspond to the similarly named MESA_FORMAT_*
@@ -911,6 +911,7 @@ struct __DRIdri2ExtensionRec {
 #define __DRI_IMAGE_USE_SHARE          0x0001
 #define __DRI_IMAGE_USE_SCANOUT                0x0002
 #define __DRI_IMAGE_USE_CURSOR         0x0004
+#define __DRI_IMAGE_USE_WRITE          0x0008
 
 /**
  * queryImage attributes
@@ -955,6 +956,13 @@ struct __DRIimageExtensionRec {
     * \since 2
     */
    GLboolean (*validateUsage)(__DRIimage *image, unsigned int use);
+
+   /**
+    * Write data into image.
+    *
+    * \since 4
+    */
+   int (*write)(__DRIimage *image, const void *buf, size_t count);
 };
 
 
index 4df6e8fcf06dc40cf395a8f93c25304bbbe7e331..e5ddfb6ce69ebf78074062b4fa9d3838f4367312 100644 (file)
@@ -291,6 +291,18 @@ gbm_dri_is_format_supported(struct gbm_device *gbm,
    return 1;
 }
 
+static int
+gbm_dri_bo_write(struct gbm_bo *_bo, const void *buf, size_t count)
+{
+   struct gbm_dri_device *dri = gbm_dri_device(_bo->gbm);
+   struct gbm_dri_bo *bo = gbm_dri_bo(_bo);
+
+   if (dri->image->base.version < 4)
+      return -1;
+
+   return dri->image->write(bo->image, buf, count);
+}
+
 static void
 gbm_dri_bo_destroy(struct gbm_bo *_bo)
 {
@@ -390,6 +402,9 @@ gbm_dri_bo_create(struct gbm_device *gbm,
    int dri_format;
    unsigned dri_use = 0;
 
+   if (dri->image->base.version < 4 && (usage & GBM_BO_USE_WRITE))
+      return NULL;
+
    bo = calloc(1, sizeof *bo);
    if (bo == NULL)
       return NULL;
@@ -421,6 +436,8 @@ gbm_dri_bo_create(struct gbm_device *gbm,
       dri_use |= __DRI_IMAGE_USE_SCANOUT;
    if (usage & GBM_BO_USE_CURSOR_64X64)
       dri_use |= __DRI_IMAGE_USE_CURSOR;
+   if (usage & GBM_BO_USE_WRITE)
+      dri_use |= __DRI_IMAGE_USE_WRITE;
 
    bo->image =
       dri->image->createImage(dri->screen,
@@ -491,6 +508,7 @@ dri_device_create(int fd)
    dri->base.base.bo_create = gbm_dri_bo_create;
    dri->base.base.bo_create_from_egl_image = gbm_dri_bo_create_from_egl_image;
    dri->base.base.is_format_supported = gbm_dri_is_format_supported;
+   dri->base.base.bo_write = gbm_dri_bo_write;
    dri->base.base.bo_destroy = gbm_dri_bo_destroy;
    dri->base.base.destroy = dri_destroy;
    dri->base.base.surface_create = gbm_dri_surface_create;
index 987e96500f845811fcafa9f4068077adf8a11de1..3994f86aafc0dcecd08da8d38207c390ef2344ab 100644 (file)
@@ -231,6 +231,25 @@ gbm_bo_get_handle(struct gbm_bo *bo)
    return bo->handle;
 }
 
+/** Write data into the buffer object
+ *
+ * If the buffer object was created with the GBM_BO_USE_WRITE flag,
+ * this function can used to write data into the buffer object.  The
+ * data is copied directly into the object and it's the responsiblity
+ * of the caller to make sure the data represents valid pixel data,
+ * according to the width, height, stride and format of the buffer object.
+ *
+ * \param bo The buffer object
+ * \param buf The data to write
+ * \param count The number of bytes to write
+ * \return Returns -1 on error, 0 otherwise
+ */
+GBM_EXPORT int
+gbm_bo_write(struct gbm_bo *bo, const void *buf, size_t count)
+{
+   return bo->gbm->bo_write(bo, buf, count);
+}
+
 /** Get the gbm device used to create the buffer object
  *
  * \param bo The buffer object
index cf3d4752c36486dc51b139da6b848eeba0a472f3..af5dc5aee8cdff130c240a435d378daee303fedd 100644 (file)
@@ -201,6 +201,12 @@ enum gbm_bo_flags {
     * as the storage for a color buffer
     */
    GBM_BO_USE_RENDERING    = (1 << 2),
+   /**
+    * Buffer can be used for gbm_bo_write.  This is guaranteed to work
+    * with GBM_BO_USE_CURSOR_64X64. but may not work for other
+    * combinations.
+    */
+   GBM_BO_USE_WRITE    = (1 << 3),
 };
 
 int
@@ -248,6 +254,9 @@ gbm_bo_get_device(struct gbm_bo *bo);
 union gbm_bo_handle
 gbm_bo_get_handle(struct gbm_bo *bo);
 
+int
+gbm_bo_write(struct gbm_bo *bo, const void *buf, size_t count);
+
 void
 gbm_bo_set_user_data(struct gbm_bo *bo, void *data,
                     void (*destroy_user_data)(struct gbm_bo *, void *));
index 0e98bdf3d8d07c21987a4b32903a416079e4b27e..8eb8671aeb2cb1105315e8b5ae67c1a9d606bc5d 100644 (file)
@@ -70,6 +70,7 @@ struct gbm_device {
                                               void *egl_dpy, void *egl_img,
                                               uint32_t width, uint32_t height,
                                               uint32_t usage);
+   int (*bo_write)(struct gbm_bo *bo, const void *buf, size_t data);
    void (*bo_destroy)(struct gbm_bo *bo);
 
    struct gbm_surface *(*surface_create)(struct gbm_device *gbm,
index 4ea970ad6d139201347e5f86093219e25f953b36..af3a059560a229ed96d65035bb276b4a43a16f8c 100644 (file)
@@ -132,6 +132,7 @@ void _mesa_copy_rect(GLubyte * dst,
 struct __DRIimageRec {
    struct intel_region *region;
    GLenum internal_format;
+   uint32_t usage;
    uint32_t dri_format;
    GLuint format;
    GLenum data_type;
index 9db56064bea44aa769c92d9652e64cfc7e32cd7b..458178fe927a0066db4b69da5060a7859df58f48 100644 (file)
@@ -305,10 +305,16 @@ intel_create_image(__DRIscreen *screen,
       tiling = I915_TILING_NONE;
    }
 
+   /* We only support write for cursor drm images */
+   if ((use & __DRI_IMAGE_USE_WRITE) &&
+       use != (__DRI_IMAGE_USE_WRITE | __DRI_IMAGE_USE_CURSOR))
+      return NULL;
+
    image = CALLOC(sizeof *image);
    if (image == NULL)
       return NULL;
 
+   image->usage = use;
    image->dri_format = format;
 
    switch (format) {
@@ -392,6 +398,7 @@ intel_dup_image(__DRIimage *orig_image, void *loaderPrivate)
    }
 
    image->internal_format = orig_image->internal_format;
+   image->usage           = orig_image->usage;
    image->dri_format      = orig_image->dri_format;
    image->format          = orig_image->format;
    image->data_type       = orig_image->data_type;
@@ -408,18 +415,39 @@ intel_validate_usage(__DRIimage *image, unsigned int use)
         return GL_FALSE;
    }
 
+   /* We only support write for cursor drm images */
+   if ((use & __DRI_IMAGE_USE_WRITE) &&
+       use != (__DRI_IMAGE_USE_WRITE | __DRI_IMAGE_USE_CURSOR))
+      return GL_FALSE;
+
    return GL_TRUE;
 }
 
+static int
+intel_image_write(__DRIimage *image, const void *buf, size_t count)
+{
+   if (image->region->map_refcount)
+      return -1;
+   if (!(image->usage & __DRI_IMAGE_USE_WRITE))
+      return -1;
+
+   drm_intel_bo_map(image->region->bo, true);
+   memcpy(image->region->bo->virtual, buf, count);
+   drm_intel_bo_unmap(image->region->bo);
+
+   return 0;
+}
+
 static struct __DRIimageExtensionRec intelImageExtension = {
-    { __DRI_IMAGE, 3 },
+    { __DRI_IMAGE, 4 },
     intel_create_image_from_name,
     intel_create_image_from_renderbuffer,
     intel_destroy_image,
     intel_create_image,
     intel_query_image,
     intel_dup_image,
-    intel_validate_usage
+    intel_validate_usage,
+    intel_image_write
 };
 
 static const __DRIextension *intelScreenExtensions[] = {