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);
15 struct ds_tdm_output *
16 create_tdm_output(struct ds_tdm_backend *tdm, tdm_output *tdm_output)
18 struct ds_tdm_output *output;
19 tdm_output_conn_status conn;
22 output = calloc(1, sizeof *output);
26 ds_output_init(&output->base, &tdm->base, &tdm_output_iface,
29 output->backend = tdm;
30 output->tdm.output = tdm_output;
32 err = tdm_output_get_conn_status(tdm_output, &conn);
33 if (err != TDM_ERROR_NONE) {
34 ds_err("Could not get connection status of tdm output(%p): err(%d)",
39 if (conn == TDM_OUTPUT_CONN_STATUS_CONNECTED) {
40 output->status = DS_TDM_OUTPUT_CONNECTED;
42 if (!tdm_output_init_modes(output)) {
43 ds_err("Could not initialize modes of tdm output(%p)",
48 else if (conn == TDM_OUTPUT_CONN_STATUS_DISCONNECTED) {
49 output->status = DS_TDM_OUTPUT_DISCONNECTED;
52 if (tdm_output_get_hwc(output->tdm.output, NULL) != NULL)
53 tdm_output_init_hwc(output);
55 ds_inf("TDM output(%p) created: hwc(%p)", output, output->tdm.hwc);
65 static struct ds_tdm_output *
66 tdm_output_from_output(struct ds_output *ds_output)
68 assert(ds_output->iface == &tdm_output_iface);
69 return (struct ds_tdm_output *)ds_output;
73 tdm_output_iface_destroy(struct ds_output *ds_output)
75 struct ds_tdm_output *output;
77 output = tdm_output_from_output(ds_output);
78 tdm_output_destroy(output);
82 destroy_tdm_buffer(struct ds_tdm_buffer *buffer)
87 wl_list_remove(&buffer->buffer_destroy.link);
88 wl_list_remove(&buffer->link);
93 buffer_handle_buffer_destroy(struct wl_listener *listener, void *data)
95 struct ds_tdm_buffer *buffer;
97 buffer = wl_container_of(listener, buffer, buffer_destroy);
98 destroy_tdm_buffer(buffer);
101 static struct ds_tdm_buffer *
102 create_tdm_buffer(struct ds_tdm_backend *backend, struct ds_buffer *ds_buffer)
104 struct ds_tdm_buffer *buffer;
105 tbm_surface_h surface;
107 surface = ds_tbm_buffer_get_surface(ds_buffer);
109 ds_err("Could not get tbm_surface_h");
113 buffer = calloc(1, sizeof *buffer);
118 buffer->surface = surface;
119 buffer->buffer = ds_buffer_lock(ds_buffer);
120 wl_list_insert(&backend->buffers, &buffer->link);
122 buffer->buffer_destroy.notify = buffer_handle_buffer_destroy;
123 ds_buffer_add_destroy_listener(ds_buffer, &buffer->buffer_destroy);
128 static struct ds_tdm_buffer *
129 get_or_create_tdm_buffer(struct ds_tdm_backend *backend,
130 struct ds_buffer *ds_buffer)
132 struct ds_tdm_buffer *buffer;
134 wl_list_for_each(buffer, &backend->buffers, link) {
135 if (buffer->buffer == ds_buffer && buffer->released) {
136 buffer->released = false;
137 ds_buffer_lock(buffer->buffer);
142 return create_tdm_buffer(backend, ds_buffer);
146 tdm_buffer_release(struct ds_tdm_buffer *buffer)
148 buffer->released = true;
149 ds_buffer_unlock(buffer->buffer);
153 tdm_output_update_front_buffer(struct ds_tdm_output *output)
155 if (output->front_buffer)
156 tdm_buffer_release(output->front_buffer);
157 output->front_buffer = output->back_buffer;
158 output->back_buffer = NULL;
162 tdm_output_attach_back_buffer(struct ds_tdm_output *output,
163 struct ds_tdm_buffer *buffer)
165 if (output->back_buffer)
166 tdm_buffer_release(output->back_buffer);
167 output->back_buffer = buffer;
171 tdm_output_hwc_commit_handler(tdm_hwc *hwc, unsigned int sequence,
172 unsigned int tv_sec, unsigned int tv_usec, void *user_data)
174 struct ds_tdm_output *output;
178 tdm_output_update_front_buffer(output);
180 wl_signal_emit(&output->base.events.frame, &output->base);
184 tdm_output_iface_commit(struct ds_output *ds_output)
186 struct ds_tdm_output *output;
187 struct ds_tdm_buffer *buffer;
188 struct ds_buffer *ds_buffer;
190 output = tdm_output_from_output(ds_output);
192 if (ds_output->pending.committed & DS_OUTPUT_STATE_MODE) {
193 if (!tdm_output_update_mode(output)) {
194 ds_err("Could not update TDM mode");
199 if (ds_output->pending.committed & DS_OUTPUT_STATE_BUFFER) {
200 tdm_region fb_damage;
202 uint32_t num_changes;
204 ds_buffer = ds_output->pending.buffer;
205 buffer = get_or_create_tdm_buffer(output->backend, ds_buffer);
209 memset(&fb_damage, 0, sizeof(fb_damage));
210 err = tdm_hwc_set_client_target_buffer(output->tdm.hwc,
211 buffer->surface, fb_damage);
212 if (err != TDM_ERROR_NONE) {
213 ds_err("Could not set hwc client target buffer");
214 ds_buffer_unlock(buffer->buffer);
218 err = tdm_hwc_validate(output->tdm.hwc, NULL, 0, &num_changes);
219 if (err != TDM_ERROR_NONE) {
220 ds_err("Could not hwc validate");
221 ds_buffer_unlock(buffer->buffer);
225 err = tdm_hwc_accept_validation(output->tdm.hwc);
226 if (err != TDM_ERROR_NONE) {
227 ds_err("Could not hwc accept validation");
228 ds_buffer_unlock(buffer->buffer);
232 err = tdm_hwc_commit(output->tdm.hwc, 0, tdm_output_hwc_commit_handler,
234 if (err != TDM_ERROR_NONE) {
235 ds_err("Could not hwc commit");
236 ds_buffer_unlock(buffer->buffer);
240 tdm_output_attach_back_buffer(output, buffer);
242 ds_dbg("Swap Buffer!!!!!");
248 static const struct ds_output_interface tdm_output_iface =
250 .destroy = tdm_output_iface_destroy,
251 .commit = tdm_output_iface_commit,
255 tdm_output_destroy(struct ds_tdm_output *output)
257 struct ds_tdm_output_mode *mode, *mode_tmp;
259 wl_list_for_each_safe(mode, mode_tmp, &output->base.modes, base.link) {
260 wl_list_remove(&mode->base.link);
264 if (output->back_buffer)
265 ds_buffer_unlock(output->back_buffer->buffer);
267 if (output->front_buffer)
268 ds_buffer_unlock(output->front_buffer->buffer);
274 tdm_output_init_modes(struct ds_tdm_output *output)
276 struct ds_tdm_output_mode *mode;
277 const tdm_output_mode *tdm_modes, *tdm_mode;
281 err = tdm_output_get_available_modes(output->tdm.output, &tdm_modes,
283 if (err != TDM_ERROR_NONE) {
284 ds_err("Could not get available modes: output(%p)", output);
288 ds_inf("Detected modes:");
290 for (i = 0; i < num_modes; i++) {
291 tdm_mode = &tdm_modes[i];
293 mode = calloc(1, sizeof *mode);
295 ds_err("Could not allocate memory");
299 mode->tdm_mode = tdm_mode;
300 mode->base.width = tdm_mode->hdisplay;
301 mode->base.height = tdm_mode->vdisplay;
302 mode->base.refresh = (int32_t)tdm_mode->vrefresh; // FIXME
304 if (tdm_mode->type & TDM_OUTPUT_MODE_TYPE_PREFERRED)
305 mode->base.preferred = true;
307 ds_dbg(" %dx%d@%d %s", mode->base.width, mode->base.height,
309 mode->base.preferred ? "(preferred)" : "");
311 if (tdm_mode->type & TDM_OUTPUT_MODE_TYPE_DEFAULT)
312 wl_list_insert(&output->base.modes, &mode->base.link);
314 wl_list_insert(output->base.modes.prev, &mode->base.link);
321 tdm_output_init_hwc(struct ds_tdm_output *output)
325 output->tdm.hwc = tdm_output_get_hwc(output->tdm.output, &err);
326 if (err != TDM_ERROR_NONE || !output->tdm.hwc) {
327 ds_err("Could not get tdm_hwc: output(%p)", output);
333 tdm_output_update_mode(struct ds_tdm_output *output)
335 const struct ds_tdm_output_mode *mode;
338 mode = (struct ds_tdm_output_mode *)output->base.pending.mode;
340 ds_inf("TDM output(%p) set mode %dx%d %d mHz", output,
341 mode->base.width, mode->base.height, mode->base.refresh);
343 err = tdm_output_set_mode(output->tdm.output, mode->tdm_mode);
344 if (err != TDM_ERROR_NONE)