5 #include "libds/allocator/tbm.h"
7 #include <tbm_surface.h>
9 static const struct ds_output_interface tdm_output_iface;
10 static bool tdm_output_init_modes(struct ds_tdm_output *output);
11 static void tdm_output_destroy(struct ds_tdm_output *output);
12 static void tdm_output_init_hwc(struct ds_tdm_output *output);
13 static bool tdm_output_update_mode(struct ds_tdm_output *output);
14 static bool tdm_output_set_pending_fb(struct ds_tdm_output *output,
15 struct ds_buffer *ds_buffer);
16 static bool tdm_output_hwc_commit(struct ds_tdm_output *output);
18 struct ds_tdm_output *
19 create_tdm_output(struct ds_tdm_backend *tdm, tdm_output *tdm_output)
21 struct ds_tdm_output *output;
22 tdm_output_conn_status conn;
25 output = calloc(1, sizeof *output);
29 ds_output_init(&output->base, &tdm->base, &tdm_output_iface,
32 output->backend = tdm;
33 output->tdm.output = tdm_output;
35 err = tdm_output_get_conn_status(tdm_output, &conn);
36 if (err != TDM_ERROR_NONE) {
37 ds_err("Could not get connection status of tdm output(%p): err(%d)",
42 if (conn == TDM_OUTPUT_CONN_STATUS_CONNECTED) {
43 output->status = DS_TDM_OUTPUT_CONNECTED;
45 if (!tdm_output_init_modes(output)) {
46 ds_err("Could not initialize modes of tdm output(%p)",
51 else if (conn == TDM_OUTPUT_CONN_STATUS_DISCONNECTED) {
52 output->status = DS_TDM_OUTPUT_DISCONNECTED;
55 if (tdm_output_get_hwc(output->tdm.output, NULL) != NULL)
56 tdm_output_init_hwc(output);
58 ds_inf("TDM output(%p) created: hwc(%p)", output, output->tdm.hwc);
68 static struct ds_tdm_output *
69 tdm_output_from_output(struct ds_output *ds_output)
71 assert(ds_output->iface == &tdm_output_iface);
72 return (struct ds_tdm_output *)ds_output;
76 tdm_output_iface_destroy(struct ds_output *ds_output)
78 struct ds_tdm_output *output;
80 output = tdm_output_from_output(ds_output);
81 tdm_output_destroy(output);
85 destroy_tdm_buffer(struct ds_tdm_buffer *buffer)
90 wl_list_remove(&buffer->buffer_destroy.link);
91 wl_list_remove(&buffer->link);
96 buffer_handle_buffer_destroy(struct wl_listener *listener, void *data)
98 struct ds_tdm_buffer *buffer;
100 buffer = wl_container_of(listener, buffer, buffer_destroy);
101 destroy_tdm_buffer(buffer);
104 static struct ds_tdm_buffer *
105 create_tdm_buffer(struct ds_tdm_backend *backend, struct ds_buffer *ds_buffer)
107 struct ds_tdm_buffer *buffer;
108 tbm_surface_h surface;
110 surface = ds_tbm_buffer_get_surface(ds_buffer);
112 ds_err("Could not get tbm_surface_h");
116 buffer = calloc(1, sizeof *buffer);
121 buffer->surface = surface;
122 buffer->buffer = ds_buffer_lock(ds_buffer);
123 wl_list_insert(&backend->buffers, &buffer->link);
125 buffer->buffer_destroy.notify = buffer_handle_buffer_destroy;
126 ds_buffer_add_destroy_listener(ds_buffer, &buffer->buffer_destroy);
131 static struct ds_tdm_buffer *
132 get_or_create_tdm_buffer(struct ds_tdm_backend *backend,
133 struct ds_buffer *ds_buffer)
135 struct ds_tdm_buffer *buffer;
137 wl_list_for_each(buffer, &backend->buffers, link) {
138 if (buffer->buffer == ds_buffer && buffer->released) {
139 buffer->released = false;
140 ds_buffer_lock(buffer->buffer);
145 return create_tdm_buffer(backend, ds_buffer);
149 tdm_buffer_release(struct ds_tdm_buffer *buffer)
151 buffer->released = true;
152 ds_buffer_unlock(buffer->buffer);
156 tdm_output_update_front_buffer(struct ds_tdm_output *output)
158 if (output->front_buffer)
159 tdm_buffer_release(output->front_buffer);
160 output->front_buffer = output->back_buffer;
161 output->back_buffer = NULL;
165 tdm_output_attach_back_buffer(struct ds_tdm_output *output,
166 struct ds_tdm_buffer *buffer)
168 if (output->back_buffer)
169 tdm_buffer_release(output->back_buffer);
170 output->back_buffer = buffer;
174 tdm_output_iface_commit(struct ds_output *ds_output)
176 struct ds_tdm_output *output;
178 output = tdm_output_from_output(ds_output);
180 if (ds_output->pending.committed & DS_OUTPUT_STATE_MODE) {
181 if (!tdm_output_update_mode(output)) {
182 ds_err("Could not update TDM mode");
187 if (ds_output->pending.committed & DS_OUTPUT_STATE_BUFFER) {
188 if (!tdm_output_set_pending_fb(output, ds_output->pending.buffer))
189 ds_err("Could not update buffer");
192 if (!tdm_output_hwc_commit(output)) {
193 ds_err("Could not commit tdm output");
194 if (output->back_buffer) {
195 tdm_buffer_release(output->back_buffer);
199 ds_dbg("Swap Buffer!!!!!");
204 static const struct ds_output_interface tdm_output_iface =
206 .destroy = tdm_output_iface_destroy,
207 .commit = tdm_output_iface_commit,
211 tdm_output_destroy(struct ds_tdm_output *output)
213 struct ds_tdm_output_mode *mode, *mode_tmp;
215 wl_list_for_each_safe(mode, mode_tmp, &output->base.modes, base.link) {
216 wl_list_remove(&mode->base.link);
220 if (output->back_buffer)
221 ds_buffer_unlock(output->back_buffer->buffer);
223 if (output->front_buffer)
224 ds_buffer_unlock(output->front_buffer->buffer);
230 tdm_output_init_modes(struct ds_tdm_output *output)
232 struct ds_tdm_output_mode *mode;
233 const tdm_output_mode *tdm_modes, *tdm_mode;
237 err = tdm_output_get_available_modes(output->tdm.output, &tdm_modes,
239 if (err != TDM_ERROR_NONE) {
240 ds_err("Could not get available modes: output(%p)", output);
244 ds_inf("Detected modes:");
246 for (i = 0; i < num_modes; i++) {
247 tdm_mode = &tdm_modes[i];
249 mode = calloc(1, sizeof *mode);
251 ds_err("Could not allocate memory");
255 mode->tdm_mode = tdm_mode;
256 mode->base.width = tdm_mode->hdisplay;
257 mode->base.height = tdm_mode->vdisplay;
258 mode->base.refresh = (int32_t)tdm_mode->vrefresh; // FIXME
260 if (tdm_mode->type & TDM_OUTPUT_MODE_TYPE_PREFERRED)
261 mode->base.preferred = true;
263 ds_dbg(" %dx%d@%d %s", mode->base.width, mode->base.height,
265 mode->base.preferred ? "(preferred)" : "");
267 if (tdm_mode->type & TDM_OUTPUT_MODE_TYPE_DEFAULT)
268 wl_list_insert(&output->base.modes, &mode->base.link);
270 wl_list_insert(output->base.modes.prev, &mode->base.link);
277 tdm_output_init_hwc(struct ds_tdm_output *output)
281 output->tdm.hwc = tdm_output_get_hwc(output->tdm.output, &err);
282 if (err != TDM_ERROR_NONE || !output->tdm.hwc) {
283 ds_err("Could not get tdm_hwc: output(%p)", output);
289 tdm_output_update_mode(struct ds_tdm_output *output)
291 const struct ds_tdm_output_mode *mode;
294 mode = (struct ds_tdm_output_mode *)output->base.pending.mode;
296 ds_inf("TDM output(%p) set mode %dx%d %d mHz", output,
297 mode->base.width, mode->base.height, mode->base.refresh);
299 err = tdm_output_set_mode(output->tdm.output, mode->tdm_mode);
300 if (err != TDM_ERROR_NONE)
307 tdm_output_set_pending_fb(struct ds_tdm_output *output,
308 struct ds_buffer *ds_buffer)
310 struct ds_tdm_buffer *buffer;
311 tdm_region fb_damage;
314 buffer = get_or_create_tdm_buffer(output->backend, ds_buffer);
318 memset(&fb_damage, 0, sizeof(fb_damage));
319 err = tdm_hwc_set_client_target_buffer(output->tdm.hwc,
320 buffer->surface, fb_damage);
321 if (err != TDM_ERROR_NONE) {
322 ds_err("Could not set hwc client target buffer");
323 ds_buffer_unlock(buffer->buffer);
327 tdm_output_attach_back_buffer(output, buffer);
333 tdm_output_hwc_commit_handler(tdm_hwc *hwc, unsigned int sequence,
334 unsigned int tv_sec, unsigned int tv_usec, void *user_data)
336 struct ds_tdm_output *output;
340 tdm_output_update_front_buffer(output);
342 wl_signal_emit(&output->base.events.frame, &output->base);
346 tdm_output_hwc_commit(struct ds_tdm_output *output)
349 uint32_t num_changes;
351 err = tdm_hwc_validate(output->tdm.hwc, NULL, 0, &num_changes);
352 if (err != TDM_ERROR_NONE) {
353 ds_err("Could not hwc validate");
357 err = tdm_hwc_accept_validation(output->tdm.hwc);
358 if (err != TDM_ERROR_NONE) {
359 ds_err("Could not hwc accept validation");
363 err = tdm_hwc_commit(output->tdm.hwc, 0, tdm_output_hwc_commit_handler,
365 if (err != TDM_ERROR_NONE) {
366 ds_err("Could not hwc commit");