#include <stdlib.h>
#include "libds/log.h"
+#include "libds/allocator/tbm.h"
#include "tdm.h"
+#include <tbm_surface.h>
static const struct ds_output_interface tdm_output_iface;
static bool tdm_output_init_modes(struct ds_tdm_output *output);
static void tdm_output_destroy(struct ds_tdm_output *output);
+static void tdm_output_init_hwc(struct ds_tdm_output *output);
struct ds_tdm_output *
create_tdm_output(struct ds_tdm_backend *tdm, tdm_output *tdm_output)
ds_output_init(&output->base, &tdm->base, &tdm_output_iface,
tdm->wl_display);
- output->tdm = tdm;
- output->tdm_output = tdm_output;
+ output->backend = tdm;
+ output->tdm.output = tdm_output;
err = tdm_output_get_conn_status(tdm_output, &conn);
if (err != TDM_ERROR_NONE) {
output->status = DS_TDM_OUTPUT_DISCONNECTED;
}
- ds_inf("TDM output(%p) created.", output);
+ if (tdm_output_get_hwc(output->tdm.output, NULL) != NULL)
+ tdm_output_init_hwc(output);
+
+ ds_inf("TDM output(%p) created: hwc(%p)", output, output->tdm.hwc);
return output;
tdm_output_destroy(output);
}
+void
+destroy_tdm_buffer(struct ds_tdm_buffer *buffer)
+{
+ if (buffer == NULL)
+ return;
+
+ wl_list_remove(&buffer->buffer_destroy.link);
+ wl_list_remove(&buffer->link);
+ free(buffer);
+}
+
+static void
+buffer_handle_buffer_destroy(struct wl_listener *listener, void *data)
+{
+ struct ds_tdm_buffer *buffer;
+
+ buffer = wl_container_of(listener, buffer, buffer_destroy);
+ destroy_tdm_buffer(buffer);
+}
+
+static struct ds_tdm_buffer *
+create_tdm_buffer(struct ds_tdm_backend *backend, struct ds_buffer *ds_buffer)
+{
+ struct ds_tdm_buffer *buffer;
+ tbm_surface_h surface;
+
+ surface = ds_tbm_buffer_get_surface(ds_buffer);
+ if (!surface) {
+ ds_err("Could not get tbm_surface_h");
+ return NULL;
+ }
+
+ buffer = calloc(1, sizeof *buffer);
+ if (!buffer) {
+ return NULL;
+ }
+
+ buffer->surface = surface;
+ buffer->buffer = ds_buffer_lock(ds_buffer);
+ wl_list_insert(&backend->buffers, &buffer->link);
+
+ buffer->buffer_destroy.notify = buffer_handle_buffer_destroy;
+ ds_buffer_add_destroy_listener(ds_buffer, &buffer->buffer_destroy);
+
+ return buffer;
+}
+
+static struct ds_tdm_buffer *
+get_or_create_tdm_buffer(struct ds_tdm_backend *backend,
+ struct ds_buffer *ds_buffer)
+{
+ struct ds_tdm_buffer *buffer;
+
+ wl_list_for_each(buffer, &backend->buffers, link) {
+ if (buffer->buffer == ds_buffer && buffer->released) {
+ buffer->released = false;
+ ds_buffer_lock(buffer->buffer);
+ return buffer;
+ }
+ }
+
+ return create_tdm_buffer(backend, ds_buffer);
+}
+
+static void
+tdm_output_hwc_commit_handler(tdm_hwc *hwc, unsigned int sequence,
+ unsigned int tv_sec, unsigned int tv_usec, void *user_data)
+{
+ struct ds_tdm_output *output;
+
+ output = user_data;
+
+ if (output->front_buffer) {
+ output->front_buffer->released = true;
+ ds_buffer_unlock(output->front_buffer->buffer);
+ }
+
+ output->front_buffer = output->back_buffer;
+ output->back_buffer = NULL;
+
+ wl_signal_emit(&output->base.events.frame, &output->base);
+}
+
static bool
tdm_output_iface_commit(struct ds_output *ds_output)
{
- // TODO
+ struct ds_tdm_output *output;
+ struct ds_tdm_buffer *buffer;
+ struct ds_buffer *ds_buffer;
+
+ output = tdm_output_from_output(ds_output);
+
+ ds_buffer = ds_output->pending.buffer;
+ buffer = get_or_create_tdm_buffer(output->backend, ds_buffer);
+ if (!buffer)
+ return false;
+
+ if (ds_output->pending.committed & DS_OUTPUT_STATE_BUFFER) {
+ tdm_region fb_damage;
+ tdm_error err;
+ uint32_t num_changes;
+
+ memset(&fb_damage, 0, sizeof(fb_damage));
+ err = tdm_hwc_set_client_target_buffer(output->tdm.hwc,
+ buffer->surface, fb_damage);
+ if (err != TDM_ERROR_NONE) {
+ ds_err("Could not set hwc client target buffer");
+ ds_buffer_unlock(buffer->buffer);
+ return false;
+ }
+
+ err = tdm_hwc_validate(output->tdm.hwc, NULL, 0, &num_changes);
+ if (err != TDM_ERROR_NONE) {
+ ds_err("Could not hwc validate");
+ ds_buffer_unlock(buffer->buffer);
+ return false;
+ }
+
+ err = tdm_hwc_accept_validation(output->tdm.hwc);
+ if (err != TDM_ERROR_NONE) {
+ ds_err("Could not hwc accept validation");
+ ds_buffer_unlock(buffer->buffer);
+ return false;
+ }
+
+ err = tdm_hwc_commit(output->tdm.hwc, 0, tdm_output_hwc_commit_handler, output);
+ if (err != TDM_ERROR_NONE) {
+ ds_err("Could not hwc commit");
+ ds_buffer_unlock(buffer->buffer);
+ return false;
+ }
+
+ if (output->back_buffer) {
+ output->back_buffer->released = true;
+ ds_buffer_unlock(output->back_buffer->buffer);
+ }
+
+ output->back_buffer = buffer;
+
+ ds_dbg("Swap Buffer!!!!!");
+ }
+
return true;
}
free(mode);
}
+ if (output->back_buffer)
+ ds_buffer_unlock(output->back_buffer->buffer);
+
+ if (output->front_buffer)
+ ds_buffer_unlock(output->front_buffer->buffer);
+
free(output);
}
tdm_error err;
int num_modes, i;
- err = tdm_output_get_available_modes(output->tdm_output, &tdm_modes,
+ err = tdm_output_get_available_modes(output->tdm.output, &tdm_modes,
&num_modes);
if (err != TDM_ERROR_NONE) {
ds_err("Could not get available modes: output(%p)", output);
wl_list_insert(&output->base.modes, &mode->base.link);
else
wl_list_insert(output->base.modes.prev, &mode->base.link);
+
+ // FIXME
+ if (mode->base.preferred) {
+ err = tdm_output_set_mode(output->tdm.output, tdm_mode);
+ if (err != TDM_ERROR_NONE) {
+ ds_err("Could not set mode");
+ }
+ }
}
return true;
}
+
+static void
+tdm_output_init_hwc(struct ds_tdm_output *output)
+{
+ tdm_error err;
+
+ output->tdm.hwc = tdm_output_get_hwc(output->tdm.output, &err);
+ if (err != TDM_ERROR_NONE || !output->tdm.hwc) {
+ ds_err("Could not get tdm_hwc: output(%p)", output);
+ return;
+ }
+}