OSDN Git Service

minigbm: virtio_gpu: set vma->length when mmap.
[android-x86/external-minigbm.git] / virtio_virgl.c
1 /*
2  * Copyright 2017 The Chromium OS Authors. All rights reserved.
3  * Use of this source code is governed by a BSD-style license that can be
4  * found in the LICENSE file.
5  */
6
7 #ifdef DRV_VIRGL
8
9 #include <errno.h>
10 #include <stdint.h>
11 #include <stdio.h>
12 #include <string.h>
13 #include <sys/mman.h>
14 #include <virtgpu_drm.h>
15 #include <xf86drm.h>
16
17 #include "drv_priv.h"
18 #include "helpers.h"
19 #include "util.h"
20 #include "virgl_hw.h"
21
22 #ifndef PAGE_SIZE
23 #define PAGE_SIZE 0x1000
24 #endif
25 #define PIPE_TEXTURE_2D 2
26
27 static const uint32_t render_target_formats[] = { DRM_FORMAT_ABGR8888, DRM_FORMAT_ARGB8888,
28                                                   DRM_FORMAT_RGB565, DRM_FORMAT_XBGR8888,
29                                                   DRM_FORMAT_XRGB8888 };
30
31 static const uint32_t texture_source_formats[] = { DRM_FORMAT_R8, DRM_FORMAT_RG88 };
32
33 static uint32_t translate_format(uint32_t drm_fourcc, uint32_t plane)
34 {
35         switch (drm_fourcc) {
36         case DRM_FORMAT_XRGB8888:
37                 return VIRGL_FORMAT_B8G8R8X8_UNORM;
38         case DRM_FORMAT_ARGB8888:
39                 return VIRGL_FORMAT_B8G8R8A8_UNORM;
40         case DRM_FORMAT_XBGR8888:
41                 return VIRGL_FORMAT_R8G8B8X8_UNORM;
42         case DRM_FORMAT_ABGR8888:
43                 return VIRGL_FORMAT_R8G8B8A8_UNORM;
44         case DRM_FORMAT_RGB565:
45                 return VIRGL_FORMAT_B5G6R5_UNORM;
46         case DRM_FORMAT_R8:
47                 return VIRGL_FORMAT_R8_UNORM;
48         case DRM_FORMAT_RG88:
49                 return VIRGL_FORMAT_R8G8_UNORM;
50         default:
51                 return 0;
52         }
53 }
54
55 static int virtio_gpu_init(struct driver *drv)
56 {
57         drv_add_combinations(drv, render_target_formats, ARRAY_SIZE(render_target_formats),
58                              &LINEAR_METADATA, BO_USE_RENDER_MASK);
59
60         drv_add_combinations(drv, texture_source_formats, ARRAY_SIZE(texture_source_formats),
61                              &LINEAR_METADATA, BO_USE_TEXTURE_MASK);
62
63         return drv_modify_linear_combinations(drv);
64 }
65
66 static int virtio_gpu_bo_create(struct bo *bo, uint32_t width, uint32_t height, uint32_t format,
67                                 uint64_t use_flags)
68 {
69         int ret;
70         ssize_t plane;
71         ssize_t num_planes = drv_num_planes_from_format(format);
72         uint32_t stride0;
73
74         for (plane = 0; plane < num_planes; plane++) {
75                 uint32_t stride = drv_stride_from_format(format, width, plane);
76                 uint32_t size = drv_size_from_format(format, stride, height, plane);
77                 uint32_t res_format = translate_format(format, plane);
78                 struct drm_virtgpu_resource_create res_create;
79
80                 memset(&res_create, 0, sizeof(res_create));
81                 size = ALIGN(size, PAGE_SIZE);
82                 /*
83                  * Setting the target is intended to ensure this resource gets bound as a 2D
84                  * texture in the host renderer's GL state. All of these resource properties are
85                  * sent unchanged by the kernel to the host, which in turn sends them unchanged to
86                  * virglrenderer. When virglrenderer makes a resource, it will convert the target
87                  * enum to the equivalent one in GL and then bind the resource to that target.
88                  */
89                 res_create.target = PIPE_TEXTURE_2D;
90                 res_create.format = res_format;
91                 res_create.bind = VIRGL_BIND_RENDER_TARGET;
92                 res_create.width = width;
93                 res_create.height = height;
94                 res_create.depth = 1;
95                 res_create.array_size = 1;
96                 res_create.last_level = 0;
97                 res_create.nr_samples = 0;
98                 res_create.stride = stride;
99                 res_create.size = size;
100
101                 ret = drmIoctl(bo->drv->fd, DRM_IOCTL_VIRTGPU_RESOURCE_CREATE, &res_create);
102                 if (ret) {
103                         fprintf(stderr, "drv: DRM_IOCTL_VIRTGPU_RESOURCE_CREATE failed with %s\n",
104                                 strerror(errno));
105                         goto fail;
106                 }
107
108                 bo->handles[plane].u32 = res_create.bo_handle;
109         }
110
111         stride0 = drv_stride_from_format(format, width, 0);
112         drv_bo_from_format(bo, stride0, height, format);
113
114         for (plane = 0; plane < num_planes; plane++)
115                 bo->offsets[plane] = 0;
116
117         return 0;
118
119 fail:
120         for (plane--; plane >= 0; plane--) {
121                 struct drm_gem_close gem_close;
122                 memset(&gem_close, 0, sizeof(gem_close));
123                 gem_close.handle = bo->handles[plane].u32;
124                 drmIoctl(bo->drv->fd, DRM_IOCTL_GEM_CLOSE, &gem_close);
125         }
126
127         return ret;
128 }
129
130 static void *virgl_bo_map(struct bo *bo, struct vma *vma, size_t plane, uint32_t map_flags)
131 {
132         int ret;
133         struct drm_virtgpu_map gem_map;
134
135         memset(&gem_map, 0, sizeof(gem_map));
136         gem_map.handle = bo->handles[0].u32;
137
138         ret = drmIoctl(bo->drv->fd, DRM_IOCTL_VIRTGPU_MAP, &gem_map);
139         if (ret) {
140                 fprintf(stderr, "drv: DRM_IOCTL_VIRTGPU_MAP failed with %s\n", strerror(errno));
141                 return MAP_FAILED;
142         }
143
144         vma->length = bo->total_size;
145         return mmap(0, bo->total_size, drv_get_prot(map_flags), MAP_SHARED, bo->drv->fd,
146                     gem_map.offset);
147 }
148
149 static int virtio_gpu_bo_invalidate(struct bo *bo, struct mapping *mapping)
150 {
151         int ret;
152         struct drm_virtgpu_3d_transfer_from_host xfer;
153
154         memset(&xfer, 0, sizeof(xfer));
155         xfer.bo_handle = mapping->vma->handle;
156         xfer.box.x = mapping->rect.x;
157         xfer.box.y = mapping->rect.y;
158         xfer.box.w = mapping->rect.width;
159         xfer.box.h = mapping->rect.height;
160         xfer.box.d = 1;
161
162         ret = drmIoctl(bo->drv->fd, DRM_IOCTL_VIRTGPU_TRANSFER_FROM_HOST, &xfer);
163         if (ret) {
164                 fprintf(stderr, "drv: DRM_IOCTL_VIRTGPU_TRANSFER_FROM_HOST failed with %s\n",
165                         strerror(errno));
166                 return ret;
167         }
168
169         return 0;
170 }
171
172 static int virtio_gpu_bo_flush(struct bo *bo, struct mapping *mapping)
173 {
174         int ret;
175         struct drm_virtgpu_3d_transfer_to_host xfer;
176
177         if (!(mapping->vma->map_flags & BO_MAP_WRITE))
178                 return 0;
179
180         memset(&xfer, 0, sizeof(xfer));
181         xfer.bo_handle = mapping->vma->handle;
182         xfer.box.x = mapping->rect.x;
183         xfer.box.y = mapping->rect.y;
184         xfer.box.w = mapping->rect.width;
185         xfer.box.h = mapping->rect.height;
186         xfer.box.d = 1;
187
188         ret = drmIoctl(bo->drv->fd, DRM_IOCTL_VIRTGPU_TRANSFER_TO_HOST, &xfer);
189         if (ret) {
190                 fprintf(stderr, "drv: DRM_IOCTL_VIRTGPU_TRANSFER_TO_HOST failed with %s\n",
191                         strerror(errno));
192                 return ret;
193         }
194
195         return 0;
196 }
197
198 static uint32_t virtio_gpu_resolve_format(uint32_t format, uint64_t use_flags)
199 {
200         switch (format) {
201         case DRM_FORMAT_FLEX_IMPLEMENTATION_DEFINED:
202                 /*HACK: See b/28671744 */
203                 return DRM_FORMAT_XBGR8888;
204         default:
205                 return format;
206         }
207 }
208
209 struct backend backend_virtio_gpu = {
210         .name = "virtio_gpu",
211         .init = virtio_gpu_init,
212         .bo_create = virtio_gpu_bo_create,
213         .bo_destroy = drv_gem_bo_destroy,
214         .bo_import = drv_prime_bo_import,
215         .bo_map = virgl_bo_map,
216         .bo_unmap = drv_bo_munmap,
217         .bo_invalidate = virtio_gpu_bo_invalidate,
218         .bo_flush = virtio_gpu_bo_flush,
219         .resolve_format = virtio_gpu_resolve_format,
220 };
221
222 #endif