root/drivers/gpu/drm/qxl/qxl_image.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. qxl_allocate_chunk
  2. qxl_image_alloc_objects
  3. qxl_image_free_objects
  4. qxl_image_init_helper
  5. qxl_image_init

   1 /*
   2  * Copyright 2013 Red Hat Inc.
   3  *
   4  * Permission is hereby granted, free of charge, to any person obtaining a
   5  * copy of this software and associated documentation files (the "Software"),
   6  * to deal in the Software without restriction, including without limitation
   7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
   8  * and/or sell copies of the Software, and to permit persons to whom the
   9  * Software is furnished to do so, subject to the following conditions:
  10  *
  11  * The above copyright notice and this permission notice shall be included in
  12  * all copies or substantial portions of the Software.
  13  *
  14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  17  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
  18  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  19  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  20  * OTHER DEALINGS IN THE SOFTWARE.
  21  *
  22  * Authors: Dave Airlie
  23  *          Alon Levy
  24  */
  25 
  26 #include <linux/gfp.h>
  27 #include <linux/slab.h>
  28 
  29 #include "qxl_drv.h"
  30 #include "qxl_object.h"
  31 
  32 static int
  33 qxl_allocate_chunk(struct qxl_device *qdev,
  34                    struct qxl_release *release,
  35                    struct qxl_drm_image *image,
  36                    unsigned int chunk_size)
  37 {
  38         struct qxl_drm_chunk *chunk;
  39         int ret;
  40 
  41         chunk = kmalloc(sizeof(struct qxl_drm_chunk), GFP_KERNEL);
  42         if (!chunk)
  43                 return -ENOMEM;
  44 
  45         ret = qxl_alloc_bo_reserved(qdev, release, chunk_size, &chunk->bo);
  46         if (ret) {
  47                 kfree(chunk);
  48                 return ret;
  49         }
  50 
  51         list_add_tail(&chunk->head, &image->chunk_list);
  52         return 0;
  53 }
  54 
  55 int
  56 qxl_image_alloc_objects(struct qxl_device *qdev,
  57                         struct qxl_release *release,
  58                         struct qxl_drm_image **image_ptr,
  59                         int height, int stride)
  60 {
  61         struct qxl_drm_image *image;
  62         int ret;
  63 
  64         image = kmalloc(sizeof(struct qxl_drm_image), GFP_KERNEL);
  65         if (!image)
  66                 return -ENOMEM;
  67 
  68         INIT_LIST_HEAD(&image->chunk_list);
  69 
  70         ret = qxl_alloc_bo_reserved(qdev, release, sizeof(struct qxl_image), &image->bo);
  71         if (ret) {
  72                 kfree(image);
  73                 return ret;
  74         }
  75 
  76         ret = qxl_allocate_chunk(qdev, release, image, sizeof(struct qxl_data_chunk) + stride * height);
  77         if (ret) {
  78                 qxl_bo_unref(&image->bo);
  79                 kfree(image);
  80                 return ret;
  81         }
  82         *image_ptr = image;
  83         return 0;
  84 }
  85 
  86 void qxl_image_free_objects(struct qxl_device *qdev, struct qxl_drm_image *dimage)
  87 {
  88         struct qxl_drm_chunk *chunk, *tmp;
  89 
  90         list_for_each_entry_safe(chunk, tmp, &dimage->chunk_list, head) {
  91                 qxl_bo_unref(&chunk->bo);
  92                 kfree(chunk);
  93         }
  94 
  95         qxl_bo_unref(&dimage->bo);
  96         kfree(dimage);
  97 }
  98 
  99 static int
 100 qxl_image_init_helper(struct qxl_device *qdev,
 101                       struct qxl_release *release,
 102                       struct qxl_drm_image *dimage,
 103                       const uint8_t *data,
 104                       int width, int height,
 105                       int depth, unsigned int hash,
 106                       int stride)
 107 {
 108         struct qxl_drm_chunk *drv_chunk;
 109         struct qxl_image *image;
 110         struct qxl_data_chunk *chunk;
 111         int i;
 112         int chunk_stride;
 113         int linesize = width * depth / 8;
 114         struct qxl_bo *chunk_bo, *image_bo;
 115         void *ptr;
 116         /* Chunk */
 117         /* FIXME: Check integer overflow */
 118         /* TODO: variable number of chunks */
 119 
 120         drv_chunk = list_first_entry(&dimage->chunk_list, struct qxl_drm_chunk, head);
 121 
 122         chunk_bo = drv_chunk->bo;
 123         chunk_stride = stride; /* TODO: should use linesize, but it renders
 124                                   wrong (check the bitmaps are sent correctly
 125                                   first) */
 126 
 127         ptr = qxl_bo_kmap_atomic_page(qdev, chunk_bo, 0);
 128         chunk = ptr;
 129         chunk->data_size = height * chunk_stride;
 130         chunk->prev_chunk = 0;
 131         chunk->next_chunk = 0;
 132         qxl_bo_kunmap_atomic_page(qdev, chunk_bo, ptr);
 133 
 134         {
 135                 void *k_data, *i_data;
 136                 int remain;
 137                 int page;
 138                 int size;
 139 
 140                 if (stride == linesize && chunk_stride == stride) {
 141                         remain = linesize * height;
 142                         page = 0;
 143                         i_data = (void *)data;
 144 
 145                         while (remain > 0) {
 146                                 ptr = qxl_bo_kmap_atomic_page(qdev, chunk_bo, page << PAGE_SHIFT);
 147 
 148                                 if (page == 0) {
 149                                         chunk = ptr;
 150                                         k_data = chunk->data;
 151                                         size = PAGE_SIZE - offsetof(struct qxl_data_chunk, data);
 152                                 } else {
 153                                         k_data = ptr;
 154                                         size = PAGE_SIZE;
 155                                 }
 156                                 size = min(size, remain);
 157 
 158                                 memcpy(k_data, i_data, size);
 159 
 160                                 qxl_bo_kunmap_atomic_page(qdev, chunk_bo, ptr);
 161                                 i_data += size;
 162                                 remain -= size;
 163                                 page++;
 164                         }
 165                 } else {
 166                         unsigned int page_base, page_offset, out_offset;
 167 
 168                         for (i = 0 ; i < height ; ++i) {
 169                                 i_data = (void *)data + i * stride;
 170                                 remain = linesize;
 171                                 out_offset = offsetof(struct qxl_data_chunk, data) + i * chunk_stride;
 172 
 173                                 while (remain > 0) {
 174                                         page_base = out_offset & PAGE_MASK;
 175                                         page_offset = offset_in_page(out_offset);
 176                                         size = min((int)(PAGE_SIZE - page_offset), remain);
 177 
 178                                         ptr = qxl_bo_kmap_atomic_page(qdev, chunk_bo, page_base);
 179                                         k_data = ptr + page_offset;
 180                                         memcpy(k_data, i_data, size);
 181                                         qxl_bo_kunmap_atomic_page(qdev, chunk_bo, ptr);
 182                                         remain -= size;
 183                                         i_data += size;
 184                                         out_offset += size;
 185                                 }
 186                         }
 187                 }
 188         }
 189         qxl_bo_kunmap(chunk_bo);
 190 
 191         image_bo = dimage->bo;
 192         ptr = qxl_bo_kmap_atomic_page(qdev, image_bo, 0);
 193         image = ptr;
 194 
 195         image->descriptor.id = 0;
 196         image->descriptor.type = SPICE_IMAGE_TYPE_BITMAP;
 197 
 198         image->descriptor.flags = 0;
 199         image->descriptor.width = width;
 200         image->descriptor.height = height;
 201 
 202         switch (depth) {
 203         case 1:
 204                 /* TODO: BE? check by arch? */
 205                 image->u.bitmap.format = SPICE_BITMAP_FMT_1BIT_BE;
 206                 break;
 207         case 24:
 208                 image->u.bitmap.format = SPICE_BITMAP_FMT_24BIT;
 209                 break;
 210         case 32:
 211                 image->u.bitmap.format = SPICE_BITMAP_FMT_32BIT;
 212                 break;
 213         default:
 214                 DRM_ERROR("unsupported image bit depth\n");
 215                 qxl_bo_kunmap_atomic_page(qdev, image_bo, ptr);
 216                 return -EINVAL;
 217         }
 218         image->u.bitmap.flags = QXL_BITMAP_TOP_DOWN;
 219         image->u.bitmap.x = width;
 220         image->u.bitmap.y = height;
 221         image->u.bitmap.stride = chunk_stride;
 222         image->u.bitmap.palette = 0;
 223         image->u.bitmap.data = qxl_bo_physical_address(qdev, chunk_bo, 0);
 224 
 225         qxl_bo_kunmap_atomic_page(qdev, image_bo, ptr);
 226 
 227         return 0;
 228 }
 229 
 230 int qxl_image_init(struct qxl_device *qdev,
 231                      struct qxl_release *release,
 232                      struct qxl_drm_image *dimage,
 233                      const uint8_t *data,
 234                      int x, int y, int width, int height,
 235                      int depth, int stride)
 236 {
 237         data += y * stride + x * (depth / 8);
 238         return qxl_image_init_helper(qdev, release, dimage, data,
 239                                        width, height, depth, 0, stride);
 240 }

/* [<][>][^][v][top][bottom][index][help] */