1 /*
2 * Copyright (C) 2011 Intel Corporation.
3 * Copyright (C) 2016-2020 Red Hat
4 * Copyright (C) 2018 DisplayLink (UK) Ltd.
5 * Copyright (C) 2018 Canonical Ltd.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 of the
10 * License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20 * 02111-1307, USA.
21 *
22 * Author: Daniel van Vugt <daniel.van.vugt@canonical.com>
23 */
24
25 #include "config.h"
26
27 #include "backends/native/meta-drm-buffer-private.h"
28
29 #include <drm_fourcc.h>
30
31 #include "backends/native/meta-device-pool.h"
32 #include "backends/native/meta-kms-utils.h"
33
34 #define INVALID_FB_ID 0U
35
36 enum
37 {
38 PROP_0,
39
40 PROP_DEVICE_FILE,
41
42 N_PROPS
43 };
44
45 static GParamSpec *obj_props[N_PROPS];
46
47 typedef struct _MetaDrmBufferPrivate
48 {
49 MetaDeviceFile *device_file;
50 uint32_t fb_id;
51 } MetaDrmBufferPrivate;
52
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE(MetaDrmBuffer,meta_drm_buffer,G_TYPE_OBJECT)53 G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (MetaDrmBuffer, meta_drm_buffer,
54 G_TYPE_OBJECT)
55
56 MetaDeviceFile *
57 meta_drm_buffer_get_device_file (MetaDrmBuffer *buffer)
58 {
59 MetaDrmBufferPrivate *priv = meta_drm_buffer_get_instance_private (buffer);
60
61 return priv->device_file;
62 }
63
64 gboolean
meta_drm_buffer_ensure_fb_id(MetaDrmBuffer * buffer,gboolean use_modifiers,const MetaDrmFbArgs * fb_args,GError ** error)65 meta_drm_buffer_ensure_fb_id (MetaDrmBuffer *buffer,
66 gboolean use_modifiers,
67 const MetaDrmFbArgs *fb_args,
68 GError **error)
69 {
70 MetaDrmBufferPrivate *priv = meta_drm_buffer_get_instance_private (buffer);
71 int fd;
72 MetaDrmFormatBuf tmp;
73 uint32_t fb_id;
74
75 fd = meta_device_file_get_fd (priv->device_file);
76
77 if (use_modifiers && fb_args->modifiers[0] != DRM_FORMAT_MOD_INVALID)
78 {
79 if (drmModeAddFB2WithModifiers (fd,
80 fb_args->width,
81 fb_args->height,
82 fb_args->format,
83 fb_args->handles,
84 fb_args->strides,
85 fb_args->offsets,
86 fb_args->modifiers,
87 &fb_id,
88 DRM_MODE_FB_MODIFIERS))
89 {
90 g_set_error (error,
91 G_IO_ERROR,
92 g_io_error_from_errno (errno),
93 "drmModeAddFB2WithModifiers failed: %s",
94 g_strerror (errno));
95 return FALSE;
96 }
97 }
98 else if (drmModeAddFB2 (fd,
99 fb_args->width,
100 fb_args->height,
101 fb_args->format,
102 fb_args->handles,
103 fb_args->strides,
104 fb_args->offsets,
105 &fb_id,
106 0))
107 {
108 if (fb_args->format != DRM_FORMAT_XRGB8888)
109 {
110 g_set_error (error,
111 G_IO_ERROR,
112 G_IO_ERROR_FAILED,
113 "drmModeAddFB does not support format '%s' (0x%x)",
114 meta_drm_format_to_string (&tmp, fb_args->format),
115 fb_args->format);
116 return FALSE;
117 }
118
119 if (drmModeAddFB (fd,
120 fb_args->width,
121 fb_args->height,
122 24,
123 32,
124 fb_args->strides[0],
125 fb_args->handles[0],
126 &fb_id))
127 {
128 g_set_error (error,
129 G_IO_ERROR,
130 g_io_error_from_errno (errno),
131 "drmModeAddFB failed: %s",
132 g_strerror (errno));
133 return FALSE;
134 }
135 }
136
137 priv->fb_id = fb_id;
138 return TRUE;
139 }
140
141 static void
meta_drm_buffer_release_fb_id(MetaDrmBuffer * buffer)142 meta_drm_buffer_release_fb_id (MetaDrmBuffer *buffer)
143 {
144 MetaDrmBufferPrivate *priv = meta_drm_buffer_get_instance_private (buffer);
145 int fd;
146 int ret;
147
148 fd = meta_device_file_get_fd (priv->device_file);
149 ret = drmModeRmFB (fd, priv->fb_id);
150 if (ret != 0)
151 g_warning ("drmModeRmFB: %s", g_strerror (-ret));
152
153 priv->fb_id = 0;
154 }
155
156 uint32_t
meta_drm_buffer_get_fb_id(MetaDrmBuffer * buffer)157 meta_drm_buffer_get_fb_id (MetaDrmBuffer *buffer)
158 {
159 MetaDrmBufferPrivate *priv = meta_drm_buffer_get_instance_private (buffer);
160
161 return priv->fb_id;
162 }
163
164 int
meta_drm_buffer_get_width(MetaDrmBuffer * buffer)165 meta_drm_buffer_get_width (MetaDrmBuffer *buffer)
166 {
167 return META_DRM_BUFFER_GET_CLASS (buffer)->get_width (buffer);
168 }
169
170 int
meta_drm_buffer_get_height(MetaDrmBuffer * buffer)171 meta_drm_buffer_get_height (MetaDrmBuffer *buffer)
172 {
173 return META_DRM_BUFFER_GET_CLASS (buffer)->get_height (buffer);
174 }
175
176 int
meta_drm_buffer_get_stride(MetaDrmBuffer * buffer)177 meta_drm_buffer_get_stride (MetaDrmBuffer *buffer)
178 {
179 return META_DRM_BUFFER_GET_CLASS (buffer)->get_stride (buffer);
180 }
181
182 uint32_t
meta_drm_buffer_get_format(MetaDrmBuffer * buffer)183 meta_drm_buffer_get_format (MetaDrmBuffer *buffer)
184 {
185 return META_DRM_BUFFER_GET_CLASS (buffer)->get_format (buffer);
186 }
187
188 gboolean
meta_drm_buffer_supports_fill_timings(MetaDrmBuffer * buffer)189 meta_drm_buffer_supports_fill_timings (MetaDrmBuffer *buffer)
190 {
191 return META_DRM_BUFFER_GET_CLASS (buffer)->fill_timings != NULL;
192 }
193
194 gboolean
meta_drm_buffer_fill_timings(MetaDrmBuffer * buffer,CoglFrameInfo * info,GError ** error)195 meta_drm_buffer_fill_timings (MetaDrmBuffer *buffer,
196 CoglFrameInfo *info,
197 GError **error)
198 {
199 if (!meta_drm_buffer_supports_fill_timings (buffer))
200 {
201 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
202 "Buffer doesn't support filling timing info");
203 return FALSE;
204 }
205
206 return META_DRM_BUFFER_GET_CLASS (buffer)->fill_timings (buffer, info, error);
207 }
208
209 static void
meta_drm_buffer_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)210 meta_drm_buffer_get_property (GObject *object,
211 guint prop_id,
212 GValue *value,
213 GParamSpec *pspec)
214 {
215 MetaDrmBuffer *buffer = META_DRM_BUFFER (object);
216 MetaDrmBufferPrivate *priv = meta_drm_buffer_get_instance_private (buffer);
217
218 switch (prop_id)
219 {
220 case PROP_DEVICE_FILE:
221 g_value_set_pointer (value, priv->device_file);
222 break;
223 default:
224 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
225 break;
226 }
227 }
228
229 static void
meta_drm_buffer_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)230 meta_drm_buffer_set_property (GObject *object,
231 guint prop_id,
232 const GValue *value,
233 GParamSpec *pspec)
234 {
235 MetaDrmBuffer *buffer = META_DRM_BUFFER (object);
236 MetaDrmBufferPrivate *priv = meta_drm_buffer_get_instance_private (buffer);
237
238 switch (prop_id)
239 {
240 case PROP_DEVICE_FILE:
241 priv->device_file = g_value_get_pointer (value);
242 break;
243 default:
244 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
245 break;
246 }
247 }
248
249 static void
meta_drm_buffer_finalize(GObject * object)250 meta_drm_buffer_finalize (GObject *object)
251 {
252 MetaDrmBuffer *buffer = META_DRM_BUFFER (object);
253 MetaDrmBufferPrivate *priv = meta_drm_buffer_get_instance_private (buffer);
254
255 if (priv->fb_id != INVALID_FB_ID)
256 meta_drm_buffer_release_fb_id (buffer);
257 meta_device_file_release (priv->device_file);
258
259 G_OBJECT_CLASS (meta_drm_buffer_parent_class)->finalize (object);
260 }
261
262 static void
meta_drm_buffer_constructed(GObject * object)263 meta_drm_buffer_constructed (GObject *object)
264 {
265 MetaDrmBuffer *buffer = META_DRM_BUFFER (object);
266 MetaDrmBufferPrivate *priv = meta_drm_buffer_get_instance_private (buffer);
267
268 meta_device_file_acquire (priv->device_file);
269
270 G_OBJECT_CLASS (meta_drm_buffer_parent_class)->constructed (object);
271 }
272
273 static void
meta_drm_buffer_init(MetaDrmBuffer * buffer)274 meta_drm_buffer_init (MetaDrmBuffer *buffer)
275 {
276 }
277
278 static void
meta_drm_buffer_class_init(MetaDrmBufferClass * klass)279 meta_drm_buffer_class_init (MetaDrmBufferClass *klass)
280 {
281 GObjectClass *object_class = G_OBJECT_CLASS (klass);
282
283 object_class->get_property = meta_drm_buffer_get_property;
284 object_class->set_property = meta_drm_buffer_set_property;
285 object_class->constructed = meta_drm_buffer_constructed;
286 object_class->finalize = meta_drm_buffer_finalize;
287
288 obj_props[PROP_DEVICE_FILE] =
289 g_param_spec_pointer ("device-file",
290 "device file",
291 "MetaDeviceFile",
292 G_PARAM_READWRITE |
293 G_PARAM_CONSTRUCT_ONLY |
294 G_PARAM_STATIC_STRINGS);
295 g_object_class_install_properties (object_class, N_PROPS, obj_props);
296 }
297