4 #include <tbm_surface.h>
7 #include "libds-tizen/allocator/tbm.h"
10 #include "tdm_buffer_queue.h"
12 static const struct ds_output_interface tdm_output_iface;
13 static bool output_init_modes(struct ds_tdm_output *output);
14 static void output_destroy(struct ds_tdm_output *output);
15 static void output_init_hwc(struct ds_tdm_output *output);
16 static bool output_update_mode(struct ds_tdm_output *output);
17 static bool output_set_pending_fb(struct ds_tdm_output *output,
18 struct ds_buffer *ds_buffer);
19 static bool output_hwc_commit(struct ds_tdm_output *output);
21 WL_EXPORT struct ds_tdm_output *
22 ds_tdm_output_from_output(struct ds_output *ds_output)
24 if (ds_output->iface != &tdm_output_iface) {
25 ds_err("Given ds_output is not for ds_tdm_output");
29 return (struct ds_tdm_output *)ds_output;
32 WL_EXPORT struct ds_tdm_buffer_queue *
33 ds_tdm_output_get_buffer_queue(struct ds_tdm_output *output)
38 output->queue = create_buffer_queue(output);
40 ds_err("Could not create tbm_queue with output(%p)", output);
47 struct ds_tdm_output *
48 create_tdm_output(struct ds_tdm_backend *tdm, tdm_output *tdm_output)
50 struct ds_tdm_output *output;
51 tdm_output_conn_status conn;
54 output = calloc(1, sizeof *output);
58 ds_output_init(&output->base, &tdm->base, &tdm_output_iface,
61 output->backend = tdm;
62 output->tdm.output = tdm_output;
64 err = tdm_output_get_conn_status(tdm_output, &conn);
65 if (err != TDM_ERROR_NONE) {
66 ds_err("Could not get connection status of tdm output(%p): err(%d)",
71 if (conn == TDM_OUTPUT_CONN_STATUS_CONNECTED) {
72 output->status = DS_TDM_OUTPUT_CONNECTED;
74 if (!output_init_modes(output)) {
75 ds_err("Could not initialize modes of tdm output(%p)",
80 else if (conn == TDM_OUTPUT_CONN_STATUS_DISCONNECTED) {
81 output->status = DS_TDM_OUTPUT_DISCONNECTED;
84 if (tdm_output_get_hwc(output->tdm.output, NULL) != NULL)
85 output_init_hwc(output);
87 ds_inf("TDM output(%p) created: hwc(%p)", output, output->tdm.hwc);
97 static struct ds_tdm_output *
98 tdm_output_from_output(struct ds_output *ds_output)
100 assert(ds_output->iface == &tdm_output_iface);
101 return (struct ds_tdm_output *)ds_output;
105 output_iface_destroy(struct ds_output *ds_output)
107 struct ds_tdm_output *output;
109 output = tdm_output_from_output(ds_output);
110 output_destroy(output);
114 destroy_tdm_buffer(struct ds_tdm_buffer *buffer)
119 if (!buffer->released)
120 wl_list_remove(&buffer->buffer_release.link);
122 wl_list_remove(&buffer->buffer_destroy.link);
123 wl_list_remove(&buffer->link);
128 buffer_handle_buffer_release(struct wl_listener *listener, void *data)
130 struct ds_tdm_buffer *buffer;
132 buffer = wl_container_of(listener, buffer, buffer_release);
133 wl_list_remove(&buffer->buffer_release.link);
134 buffer->released = true;
138 buffer_handle_buffer_destroy(struct wl_listener *listener, void *data)
140 struct ds_tdm_buffer *buffer;
142 buffer = wl_container_of(listener, buffer, buffer_destroy);
143 destroy_tdm_buffer(buffer);
146 static struct ds_tdm_buffer *
147 create_tdm_buffer(struct ds_tdm_backend *backend, struct ds_buffer *ds_buffer)
149 struct ds_tdm_buffer *buffer;
150 tbm_surface_h surface;
152 surface = ds_tbm_buffer_get_surface(ds_buffer);
154 ds_err("Could not get tbm_surface_h");
158 buffer = calloc(1, sizeof *buffer);
162 buffer->surface = surface;
163 buffer->buffer = ds_buffer;
164 wl_list_insert(&backend->buffers, &buffer->link);
166 buffer->buffer_destroy.notify = buffer_handle_buffer_destroy;
167 ds_buffer_add_destroy_listener(ds_buffer, &buffer->buffer_destroy);
172 static struct ds_tdm_buffer *
173 get_or_create_tdm_buffer(struct ds_tdm_backend *backend,
174 struct ds_buffer *ds_buffer)
176 struct ds_tdm_buffer *buffer;
178 wl_list_for_each(buffer, &backend->buffers, link) {
179 if (buffer->buffer == ds_buffer && buffer->released) {
184 buffer = create_tdm_buffer(backend, ds_buffer);
187 buffer->released = false;
189 buffer->buffer_release.notify = buffer_handle_buffer_release;
190 ds_buffer_add_release_listener(ds_buffer, &buffer->buffer_release);
192 ds_buffer_lock(buffer->buffer);
198 output_update_front_buffer(struct ds_tdm_output *output)
200 if (output->front_buffer)
201 ds_buffer_unlock(output->front_buffer);
202 output->front_buffer = output->back_buffer;
203 output->back_buffer = NULL;
207 output_attach_back_buffer(struct ds_tdm_output *output,
208 struct ds_buffer *buffer)
210 if (output->back_buffer)
211 ds_buffer_unlock(output->back_buffer);
212 output->back_buffer = buffer;
216 output_iface_commit(struct ds_output *ds_output)
218 struct ds_tdm_output *output;
220 output = tdm_output_from_output(ds_output);
222 if (ds_output->pending.committed & DS_OUTPUT_STATE_MODE) {
223 if (!output_update_mode(output)) {
224 ds_err("Could not update TDM mode");
229 if (ds_output->pending.committed & DS_OUTPUT_STATE_BUFFER) {
230 if (!output_set_pending_fb(output, ds_output->pending.buffer))
231 ds_err("Could not update buffer");
234 if (!output_hwc_commit(output)) {
235 ds_err("Could not commit tdm output");
236 if (output->back_buffer)
237 ds_buffer_unlock(output->back_buffer);
243 static const struct ds_output_interface tdm_output_iface =
245 .destroy = output_iface_destroy,
246 .commit = output_iface_commit,
250 output_destroy(struct ds_tdm_output *output)
252 struct ds_tdm_output_mode *mode, *mode_tmp;
254 wl_list_for_each_safe(mode, mode_tmp, &output->base.modes, base.link) {
255 wl_list_remove(&mode->base.link);
259 if (output->back_buffer)
260 ds_buffer_unlock(output->back_buffer);
262 if (output->front_buffer)
263 ds_buffer_unlock(output->front_buffer);
266 buffer_queue_destroy(output->queue);
272 output_init_modes(struct ds_tdm_output *output)
274 struct ds_tdm_output_mode *mode;
275 const tdm_output_mode *tdm_modes, *tdm_mode;
279 err = tdm_output_get_available_modes(output->tdm.output, &tdm_modes,
281 if (err != TDM_ERROR_NONE) {
282 ds_err("Could not get available modes: output(%p)", output);
286 ds_dbg("Detected modes:");
288 for (i = 0; i < num_modes; i++) {
289 tdm_mode = &tdm_modes[i];
291 mode = calloc(1, sizeof *mode);
293 ds_err("Could not allocate memory");
297 mode->tdm_mode = tdm_mode;
298 mode->base.width = tdm_mode->hdisplay;
299 mode->base.height = tdm_mode->vdisplay;
300 mode->base.refresh = (int32_t)tdm_mode->vrefresh; // FIXME
302 if (tdm_mode->type & TDM_OUTPUT_MODE_TYPE_PREFERRED)
303 mode->base.preferred = true;
305 ds_dbg(" %dx%d@%d %s", mode->base.width, mode->base.height,
307 mode->base.preferred ? "(preferred)" : "");
309 if (tdm_mode->type & TDM_OUTPUT_MODE_TYPE_DEFAULT)
310 wl_list_insert(&output->base.modes, &mode->base.link);
312 wl_list_insert(output->base.modes.prev, &mode->base.link);
319 output_init_hwc(struct ds_tdm_output *output)
323 output->tdm.hwc = tdm_output_get_hwc(output->tdm.output, &err);
324 if (err != TDM_ERROR_NONE || !output->tdm.hwc) {
325 ds_err("Could not get tdm_hwc: output(%p)", output);
331 output_update_mode(struct ds_tdm_output *output)
333 const struct ds_tdm_output_mode *mode;
336 mode = (struct ds_tdm_output_mode *)output->base.pending.mode;
338 ds_inf("TDM output(%p) set mode %dx%d %d mHz", output,
339 mode->base.width, mode->base.height, mode->base.refresh);
341 err = tdm_output_set_mode(output->tdm.output, mode->tdm_mode);
342 if (err != TDM_ERROR_NONE)
349 output_set_pending_fb(struct ds_tdm_output *output,
350 struct ds_buffer *ds_buffer)
352 struct ds_tdm_queue_buffer *queue_buffer;
353 struct ds_tdm_buffer *buffer;
354 tbm_surface_h surface = NULL;
355 tdm_region fb_damage;
359 queue_buffer = buffer_queue_find_buffer(output->queue, ds_buffer);
361 ds_buffer_lock(ds_buffer);
362 surface = queue_buffer->surface;
367 buffer = get_or_create_tdm_buffer(output->backend, ds_buffer);
371 surface = buffer->surface;
374 memset(&fb_damage, 0, sizeof(fb_damage));
375 err = tdm_hwc_set_client_target_buffer(output->tdm.hwc,
377 if (err != TDM_ERROR_NONE) {
378 ds_err("Could not set hwc client target buffer");
379 ds_buffer_unlock(ds_buffer);
383 output_attach_back_buffer(output, ds_buffer);
389 output_hwc_commit_handler(tdm_hwc *hwc, unsigned int sequence,
390 unsigned int tv_sec, unsigned int tv_usec, void *user_data)
392 struct ds_tdm_output *output = user_data;
394 output_update_front_buffer(output);
396 wl_signal_emit(&output->base.events.frame, &output->base);
400 output_hwc_commit(struct ds_tdm_output *output)
403 uint32_t num_changes;
405 err = tdm_hwc_validate(output->tdm.hwc, NULL, 0, &num_changes);
406 if (err != TDM_ERROR_NONE) {
407 ds_err("Could not hwc validate");
411 err = tdm_hwc_accept_validation(output->tdm.hwc);
412 if (err != TDM_ERROR_NONE) {
413 ds_err("Could not hwc accept validation");
417 err = tdm_hwc_commit(output->tdm.hwc, 0, output_hwc_commit_handler,
419 if (err != TDM_ERROR_NONE) {
420 ds_err("Could not hwc commit");