gbm: Add gbm_bo_import for gallium gbm backend
[mesa.git] / src / gallium / state_trackers / gbm / gbm_drm.c
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
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
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
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
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 *
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 *
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
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 *
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 }