OSDN Git Service

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