1 /*
2  * Copyright © 2011 Intel Corporation
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 (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18  * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22  * DEALINGS IN THE SOFTWARE.
23  *
24  * Authors:
25  *    Benjamin Franzke <benjaminfranzke@googlemail.com>
26  */
27 
28 #include "util/u_memory.h"
29 #include "util/u_inlines.h"
30 
31 #include "state_tracker/drm_driver.h"
32 
33 #include <unistd.h>
34 #include <sys/types.h>
35 
36 #include "gbm_gallium_drmint.h"
37 
38 /* For importing wl_buffer */
39 #if HAVE_WAYLAND_PLATFORM
40 #include "../../../egl/wayland/wayland-drm/wayland-drm.h"
41 #endif
42 
43 static INLINE enum pipe_format
gbm_format_to_gallium(enum gbm_bo_format format)44 gbm_format_to_gallium(enum gbm_bo_format format)
45 {
46    switch (format) {
47    case GBM_BO_FORMAT_XRGB8888:
48       return PIPE_FORMAT_B8G8R8X8_UNORM;
49    case GBM_BO_FORMAT_ARGB8888:
50       return PIPE_FORMAT_B8G8R8A8_UNORM;
51    default:
52       return PIPE_FORMAT_NONE;
53    }
54 
55    return PIPE_FORMAT_NONE;
56 }
57 
58 static INLINE uint
gbm_usage_to_gallium(uint usage)59 gbm_usage_to_gallium(uint usage)
60 {
61    uint resource_usage = 0;
62 
63    if (usage & GBM_BO_USE_SCANOUT)
64       resource_usage |= PIPE_BIND_SCANOUT;
65 
66    if (usage & GBM_BO_USE_RENDERING)
67       resource_usage |= PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW;
68 
69    if (usage & GBM_BO_USE_CURSOR_64X64)
70       resource_usage |= PIPE_BIND_CURSOR;
71 
72    return resource_usage;
73 }
74 
75 static int
gbm_gallium_drm_is_format_supported(struct gbm_device * gbm,enum gbm_bo_format format,uint32_t usage)76 gbm_gallium_drm_is_format_supported(struct gbm_device *gbm,
77                                     enum gbm_bo_format format,
78                                     uint32_t usage)
79 {
80    struct gbm_gallium_drm_device *gdrm = gbm_gallium_drm_device(gbm);
81    enum pipe_format pf;
82 
83    pf = gbm_format_to_gallium(format);
84    if (pf == PIPE_FORMAT_NONE)
85       return 0;
86 
87    if (!gdrm->screen->is_format_supported(gdrm->screen, PIPE_TEXTURE_2D, pf, 0,
88                                           gbm_usage_to_gallium(usage)))
89       return 0;
90 
91    if (usage & GBM_BO_USE_SCANOUT && format != GBM_BO_FORMAT_XRGB8888)
92       return 0;
93 
94    return 1;
95 }
96 
97 static void
gbm_gallium_drm_bo_destroy(struct gbm_bo * _bo)98 gbm_gallium_drm_bo_destroy(struct gbm_bo *_bo)
99 {
100    struct gbm_gallium_drm_bo *bo = gbm_gallium_drm_bo(_bo);
101 
102    pipe_resource_reference(&bo->resource, NULL);
103    free(bo);
104 }
105 
106 static struct gbm_bo *
gbm_gallium_drm_bo_import(struct gbm_device * gbm,uint32_t type,void * buffer,uint32_t usage)107 gbm_gallium_drm_bo_import(struct gbm_device *gbm,
108                           uint32_t type, void *buffer, uint32_t usage)
109 {
110    struct gbm_gallium_drm_device *gdrm = gbm_gallium_drm_device(gbm);
111    struct gbm_gallium_drm_bo *bo;
112    struct winsys_handle whandle;
113    struct pipe_resource *resource;
114 
115    switch (type) {
116 #if HAVE_WAYLAND_PLATFORM
117    case GBM_BO_IMPORT_WL_BUFFER:
118    {
119       struct wl_drm_buffer *wb = (struct wl_drm_buffer *) buffer;
120 
121       resource = wb->driver_buffer;
122       break;
123    }
124 #endif
125 
126    case GBM_BO_IMPORT_EGL_IMAGE:
127       if (!gdrm->lookup_egl_image)
128          return NULL;
129 
130       resource = gdrm->lookup_egl_image(gdrm->lookup_egl_image_data, buffer);
131       if (resource == NULL)
132          return NULL;
133       break;
134 
135    default:
136       return NULL;
137    }
138 
139    bo = CALLOC_STRUCT(gbm_gallium_drm_bo);
140    if (bo == NULL)
141       return NULL;
142 
143    bo->base.base.gbm = gbm;
144    bo->base.base.width = resource->width0;
145    bo->base.base.height = resource->height0;
146 
147    switch (resource->format) {
148    case PIPE_FORMAT_B8G8R8X8_UNORM:
149       bo->base.base.format = GBM_BO_FORMAT_XRGB8888;
150       break;
151    case PIPE_FORMAT_B8G8R8A8_UNORM:
152       bo->base.base.format = GBM_BO_FORMAT_ARGB8888;
153       break;
154    default:
155       FREE(bo);
156       return NULL;
157    }
158 
159    pipe_resource_reference(&bo->resource, resource);
160 
161    memset(&whandle, 0, sizeof(whandle));
162    whandle.type = DRM_API_HANDLE_TYPE_KMS;
163    gdrm->screen->resource_get_handle(gdrm->screen, bo->resource, &whandle);
164 
165    bo->base.base.handle.u32 = whandle.handle;
166    bo->base.base.stride      = whandle.stride;
167 
168    return &bo->base.base;
169 }
170 
171 static struct gbm_bo *
gbm_gallium_drm_bo_create(struct gbm_device * gbm,uint32_t width,uint32_t height,enum gbm_bo_format format,uint32_t usage)172 gbm_gallium_drm_bo_create(struct gbm_device *gbm,
173                           uint32_t width, uint32_t height,
174                           enum gbm_bo_format format, uint32_t usage)
175 {
176    struct gbm_gallium_drm_device *gdrm = gbm_gallium_drm_device(gbm);
177    struct gbm_gallium_drm_bo *bo;
178    struct pipe_resource templ;
179    struct winsys_handle whandle;
180    enum pipe_format pf;
181 
182    bo = CALLOC_STRUCT(gbm_gallium_drm_bo);
183    if (bo == NULL)
184       return NULL;
185 
186    bo->base.base.gbm = gbm;
187    bo->base.base.width = width;
188    bo->base.base.height = height;
189    bo->base.base.format = format;
190 
191    pf = gbm_format_to_gallium(format);
192    if (pf == PIPE_FORMAT_NONE)
193       return NULL;
194 
195    memset(&templ, 0, sizeof(templ));
196    templ.bind = gbm_usage_to_gallium(usage);
197    templ.format = pf;
198    templ.target = PIPE_TEXTURE_2D;
199    templ.last_level = 0;
200    templ.width0 = width;
201    templ.height0 = height;
202    templ.depth0 = 1;
203    templ.array_size = 1;
204 
205    bo->resource = gdrm->screen->resource_create(gdrm->screen, &templ);
206    if (bo->resource == NULL) {
207       FREE(bo);
208       return NULL;
209    }
210 
211    memset(&whandle, 0, sizeof(whandle));
212    whandle.type = DRM_API_HANDLE_TYPE_KMS;
213    gdrm->screen->resource_get_handle(gdrm->screen, bo->resource, &whandle);
214 
215    bo->base.base.handle.u32 = whandle.handle;
216    bo->base.base.stride      = whandle.stride;
217 
218    return &bo->base.base;
219 }
220 
221 static void
gbm_gallium_drm_destroy(struct gbm_device * gbm)222 gbm_gallium_drm_destroy(struct gbm_device *gbm)
223 {
224    struct gbm_gallium_drm_device *gdrm = gbm_gallium_drm_device(gbm);
225 
226    gallium_screen_destroy(gdrm);
227    FREE(gdrm);
228 }
229 
230 struct gbm_device *
gbm_gallium_drm_device_create(int fd)231 gbm_gallium_drm_device_create(int fd)
232 {
233    struct gbm_gallium_drm_device *gdrm;
234    int ret;
235 
236    gdrm = calloc(1, sizeof *gdrm);
237 
238    gdrm->base.base.fd = fd;
239    gdrm->base.base.bo_create = gbm_gallium_drm_bo_create;
240    gdrm->base.base.bo_import = gbm_gallium_drm_bo_import;
241    gdrm->base.base.bo_destroy = gbm_gallium_drm_bo_destroy;
242    gdrm->base.base.is_format_supported = gbm_gallium_drm_is_format_supported;
243    gdrm->base.base.destroy = gbm_gallium_drm_destroy;
244 
245    gdrm->base.type = GBM_DRM_DRIVER_TYPE_GALLIUM;
246    gdrm->base.base.name = "drm";
247 
248    ret = gallium_screen_create(gdrm);
249    if (ret) {
250       free(gdrm);
251       return NULL;
252    }
253 
254    return &gdrm->base.base;
255 }
256