case HAL_PIXEL_FORMAT_RGBX_8888:
return DRM_FORMAT_XBGR8888;
case HAL_PIXEL_FORMAT_RGBA_8888:
- return DRM_FORMAT_RGBA8888;
+// return DRM_FORMAT_ABGR8888;
+ return DRM_FORMAT_XBGR8888;
case HAL_PIXEL_FORMAT_RGB_565:
return DRM_FORMAT_RGB565;
case HAL_PIXEL_FORMAT_YV12:
err = drmModeSetPlane(drm->fd,
plane->drm_plane->plane_id,
- drm->primary.crtc_id,
+ drm->primary->crtc_id,
bo ? bo->fb_id : 0,
0, // flags
plane->dst_x,
ALOGE("drmModeSetPlane : error (%s) (plane %d crtc %d fb %d)",
strerror(-err),
plane->drm_plane->plane_id,
- drm->primary.crtc_id,
+ drm->primary->crtc_id,
bo ? bo->fb_id : 0);
}
const struct gralloc_drm_plane_t *plane)
{
/* Planes are only supported on primary pipe for now */
- return plane->drm_plane->possible_crtcs & (1 << drm->primary.pipe);
+ return plane->drm_plane->possible_crtcs & (1 << drm->primary->pipe);
}
/*
return -EINVAL;
}
-static int drm_kms_blit_to_hdmi(struct gralloc_drm_t *drm, struct gralloc_drm_bo_t *bo)
+static int drm_kms_blit_to_mirror_connectors(struct gralloc_drm_t *drm, struct gralloc_drm_bo_t *bo)
{
int ret = 0;
- if (drm->hdmi.active && drm->hdmi.output_mode == DRM_OUTPUT_CLONED && drm->hdmi.bo) {
+ for (int i = 1; i < drm->output_capacity; i++) {
+ struct gralloc_drm_output *output = &drm->outputs[i];
+
+ if (output->active && output->output_mode == DRM_OUTPUT_CLONED && output->bo) {
- int dst_x1 = 0, dst_y1 = 0;
+ int dst_x1 = 0, dst_y1 = 0;
- if (drm->hdmi.bo->handle->width > bo->handle->width)
- dst_x1 = (drm->hdmi.bo->handle->width - bo->handle->width) / 2;
- if (drm->hdmi.bo->handle->height > bo->handle->height)
- dst_y1 = (drm->hdmi.bo->handle->height - bo->handle->height) / 2;
+ if (output->bo->handle->width > bo->handle->width)
+ dst_x1 = (output->bo->handle->width - bo->handle->width) / 2;
+ if (output->bo->handle->height > bo->handle->height)
+ dst_y1 = (output->bo->handle->height - bo->handle->height) / 2;
- drm->drv->blit(drm->drv, drm->hdmi.bo, bo,
- dst_x1, dst_y1,
- dst_x1 + bo->handle->width,
- dst_y1 + bo->handle->height,
- 0, 0, bo->handle->width, bo->handle->height);
+ drm->drv->blit(drm->drv, output->bo, bo,
+ dst_x1, dst_y1,
+ dst_x1 + bo->handle->width,
+ dst_y1 + bo->handle->height,
+ 0, 0, bo->handle->width, bo->handle->height);
- ret = drmModePageFlip(drm->fd, drm->hdmi.crtc_id, drm->hdmi.bo->fb_id, 0, NULL);
- if (ret && errno != EBUSY)
- ALOGE("failed to perform page flip for hdmi (%s) (crtc %d fb %d))",
- strerror(errno), drm->hdmi.crtc_id, drm->hdmi.bo->fb_id);
+ ret = drmModePageFlip(drm->fd, output->crtc_id, output->bo->fb_id, 0, NULL);
+ if (ret && errno != EBUSY)
+ ALOGE("failed to perform page flip for output (%s) (crtc %d fb %d))",
+ strerror(errno), output->crtc_id, output->bo->fb_id);
+ }
}
return ret;
if (!bo)
return 0;
- pthread_mutex_lock(&drm->hdmi_mutex);
- drm_kms_blit_to_hdmi(drm, bo);
- pthread_mutex_unlock(&drm->hdmi_mutex);
+ pthread_mutex_lock(&drm->outputs_mutex);
+ drm_kms_blit_to_mirror_connectors(drm, bo);
+ pthread_mutex_unlock(&drm->outputs_mutex);
/* set planes to be displayed */
gralloc_drm_set_planes(drm);
- ret = drmModePageFlip(drm->fd, drm->primary.crtc_id, bo->fb_id,
+ ret = drmModePageFlip(drm->fd, drm->primary->crtc_id, bo->fb_id,
DRM_MODE_PAGE_FLIP_EVENT, (void *) drm);
if (ret) {
ALOGE("failed to perform page flip for primary (%s) (crtc %d fb %d))",
- strerror(errno), drm->primary.crtc_id, bo->fb_id);
+ strerror(errno), drm->primary->crtc_id, bo->fb_id);
/* try to set mode for next frame */
if (errno != EBUSY)
drm->first_post = 1;
bo = dst;
}
- ret = drm_kms_set_crtc(drm, &drm->primary, bo->fb_id);
+ ret = drm_kms_set_crtc(drm, drm->primary, bo->fb_id);
if (!ret) {
drm->first_post = 0;
drm->current_front = bo;
drm->next_front = NULL;
}
- pthread_mutex_lock(&drm->hdmi_mutex);
- if (drm->hdmi.active && drm->hdmi.output_mode == DRM_OUTPUT_CLONED && drm->hdmi.bo)
- drm_kms_set_crtc(drm, &drm->hdmi, drm->hdmi.bo->fb_id);
- pthread_mutex_unlock(&drm->hdmi_mutex);
+ pthread_mutex_lock(&drm->outputs_mutex);
+ for (int i = 1; i < drm->output_capacity; i++) {
+ struct gralloc_drm_output *output = &drm->outputs[i];
+ if (output->active && output->output_mode == DRM_OUTPUT_CLONED && output->bo)
+ drm_kms_set_crtc(drm, output, output->bo->fb_id);
+ }
+ pthread_mutex_unlock(&drm->outputs_mutex);
return ret;
}
* will be written by CPU
*/
if (drm->mode_sync_flip ||
- (drm->current_front->handle->usage &
- GRALLOC_USAGE_SW_WRITE_MASK))
+ (drm->current_front->handle->usage &
+ GRALLOC_USAGE_SW_WRITE_MASK))
drm_kms_page_flip(drm, NULL);
}
break;
break;
case DRM_SWAP_SETCRTC:
drm_kms_wait_for_post(drm, 0);
- ret = drm_kms_set_crtc(drm, &drm->primary, bo->fb_id);
+ ret = drm_kms_set_crtc(drm, drm->primary, bo->fb_id);
- pthread_mutex_lock(&drm->hdmi_mutex);
- if (drm->hdmi.active && drm->hdmi.output_mode == DRM_OUTPUT_CLONED && drm->hdmi.bo)
- drm_kms_set_crtc(drm, &drm->hdmi, drm->hdmi.bo->fb_id);
- pthread_mutex_unlock(&drm->hdmi_mutex);
+ pthread_mutex_lock(&drm->outputs_mutex);
+ for (int i = 1; i < drm->output_capacity; i++) {
+ struct gralloc_drm_output *output = &drm->outputs[i];
+ if (output->active && output->output_mode == DRM_OUTPUT_CLONED && output->bo)
+ drm_kms_set_crtc(drm, output, output->bo->fb_id);
+ }
+ pthread_mutex_unlock(&drm->outputs_mutex);
drm->current_front = bo;
break;
/* create the real front buffer */
front = gralloc_drm_bo_create(drm,
- drm->primary.mode.hdisplay,
- drm->primary.mode.vdisplay,
- drm->primary.fb_format,
+ drm->primary->mode.hdisplay,
+ drm->primary->mode.vdisplay,
+ drm->primary->fb_format,
GRALLOC_USAGE_HW_FB);
if (front && gralloc_drm_bo_add_fb(front)) {
gralloc_drm_bo_decref(front);
connector->modes[0].name);
}
- if (property_get_bool("persist.remixos.disp_best_fit", 1) && output != &drm->primary) {
- mode = find_mode(connector, &bpp, &drm->primary.mode);
+ if (drm->primary && output != drm->primary && property_get_bool("persist.remixos.disp_best_fit", 1)) {
+ mode = find_mode(connector, &bpp, &drm->primary->mode);
} else {
mode = find_mode(connector, &bpp, NULL);
}
break;
case 4:
default:
- output->fb_format = HAL_PIXEL_FORMAT_BGRA_8888;
+ output->fb_format = HAL_PIXEL_FORMAT_RGBA_8888;
break;
}
return 0;
}
+static struct gralloc_drm_output*
+drm_kms_init_with_new_connector(struct gralloc_drm_t *drm, drmModeConnectorPtr connector)
+{
+ struct gralloc_drm_output *output = NULL;
+
+ for (int i=0;i<drm->output_capacity;i++) {
+ if (!drm->outputs[i].active) {
+ output = &drm->outputs[i];
+ break;
+ }
+ }
+
+ if (output && !drm_kms_init_with_connector(drm, output, connector)) {
+ drm->output_count++;
+ output->active = 1;
+ if (!drm->primary) {
+ drm->primary = output;
+ }
+ }
+
+ return output;
+}
+
/*
* Fetch a connector of particular type
return NULL;
for (i = 0; i < drm->resources->count_connectors; i++) {
- drmModeConnectorPtr connector =
- connector = drmModeGetConnector(drm->fd,
+ drmModeConnectorPtr connector = drmModeGetConnector(drm->fd,
drm->resources->connectors[i]);
if (connector) {
if (connector->connector_type == type &&
/*
- * Initializes hdmi output with a connector and allocates
+ * Initializes external output with a connector and allocates
* a private framebuffer for it. This is called on startup if
- * hdmi cable is connected and also on hotplug events.
+ * external cable is connected and also on hotplug events.
*/
-static int init_hdmi_output(struct gralloc_drm_t *drm,
+static int init_external_output(struct gralloc_drm_t *drm,
drmModeConnectorPtr connector)
{
- drm_kms_init_with_connector(drm, &drm->hdmi, connector);
+ struct gralloc_drm_output *output;
+ output = drm_kms_init_with_new_connector(drm, connector);
+ if (output == NULL || !output->active) {
+ ALOGW("connector 0x%x output is null or not active", connector->connector_id);
+ return -EINVAL;
+ }
ALOGD("%s, allocate private buffer for hdmi [%dx%d]",
- __func__, drm->hdmi.mode.hdisplay, drm->hdmi.mode.vdisplay);
+ __func__, output->mode.hdisplay, output->mode.vdisplay);
- drm->hdmi.bo = gralloc_drm_bo_create(drm,
- drm->hdmi.mode.hdisplay, drm->hdmi.mode.vdisplay,
- drm->hdmi.fb_format,
+ output->bo = gralloc_drm_bo_create(drm,
+ output->mode.hdisplay, output->mode.vdisplay,
+ output->fb_format,
GRALLOC_USAGE_HW_RENDER);
- int err = gralloc_drm_bo_add_fb(drm->hdmi.bo);
+ int err = gralloc_drm_bo_add_fb(output->bo);
if (err) {
ALOGE("%s: could not create drm fb, (%s)",
__func__, strerror(-err));
return err;
}
- drm->hdmi.output_mode = DRM_OUTPUT_CLONED;
- drm->hdmi.active = 1;
+ output->output_mode = DRM_OUTPUT_CLONED;
+ output->active = 1;
+
+ /* This is a hack to workaround mirror mode render error */
+ drm_kms_set_crtc(drm, output, output->bo->fb_id);
+
+ return 0;
+}
+
+
+static int init_connectors(struct gralloc_drm_t *drm)
+{
+ if (!drm->resources)
+ return -1;
+
+ for (int i = 0; i<drm->resources->count_connectors; i++) {
+ drmModeConnectorPtr connector = drmModeGetConnector(drm->fd,
+ drm->resources->connectors[i]);
+ if (connector) {
+ if (connector->connection == DRM_MODE_CONNECTED &&
+ connector->connector_id != drm->primary->connector_id) {
+ init_external_output(drm, connector);
+ } else if (connector->connection == DRM_MODE_DISCONNECTED) {
+ for (int j = 1; j < drm->output_capacity; j++) {
+ if (drm->outputs[j].connector_id == connector->connector_id && drm->outputs[j].active) {
+ drm->outputs[j].active = 0;
+ used_crtcs &= ~(1 << drm->outputs[j].pipe);
+ gralloc_drm_bo_decref(drm->outputs[j].bo);
+ drm->outputs[j].bo = NULL;
+ break;
+ }
+ }
+ }
+ drmModeFreeConnector(connector);
+ }
+ }
return 0;
}
/*
* Thread that listens to uevents and checks if hdmi state changes
*/
-static void *hdmi_observer(void *data)
+static void *extcon_observer(void *data)
{
- static char uevent_desc[4096];
+ char uevent_desc[2048];
drmModeConnectorPtr hdmi;
struct gralloc_drm_t *drm =
(struct gralloc_drm_t *) data;
if (!strcmp(event.path, "devices/virtual/switch/hdmi")) {
if (event.switchstate != -1) {
- pthread_mutex_lock(&drm->hdmi_mutex);
-
- if (event.switchstate) {
- hdmi = fetch_connector(drm, DRM_MODE_CONNECTOR_HDMIA);
- if (hdmi) {
- ALOGD("init hdmi on switch_state event");
- init_hdmi_output(drm, hdmi);
+ pthread_mutex_lock(&drm->outputs_mutex);
- /* will trigger modeset */
- drm->first_post = 1;
+ init_connectors(drm);
- drmModeFreeConnector(hdmi);
- }
- } else {
- drm->hdmi.active = 0;
- used_crtcs &= ~(1 << drm->hdmi.pipe);
-
- ALOGD("destroy hdmi private buffer");
- gralloc_drm_bo_decref(drm->hdmi.bo);
- drm->hdmi.bo = NULL;
- }
+ /* will trigger modeset */
+ drm->first_post = 1;
- pthread_mutex_unlock(&drm->hdmi_mutex);
+ pthread_mutex_unlock(&drm->outputs_mutex);
}
} else if (!strcmp(event.subsystem, "drm") &&
!strcmp(event.device_name, "dri/card0") && event.hotplug) {
- pthread_mutex_lock(&drm->hdmi_mutex);
+ pthread_mutex_lock(&drm->outputs_mutex);
- hdmi = fetch_connector(drm, DRM_MODE_CONNECTOR_HDMIA);
- if (hdmi && !drm->hdmi.active) {
- ALOGD("init hdmi on hotplug event");
- if (!init_hdmi_output(drm, hdmi)) {
- drm_kms_set_crtc(drm, &drm->hdmi, drm->hdmi.bo->fb_id);
- }
-
- /* will trigger modeset */
- drm->first_post = 1;
- } else if (!hdmi && drm->hdmi.active) {
- drm->hdmi.active = 0;
- used_crtcs &= ~(1 << drm->hdmi.pipe);
+ init_connectors(drm);
- ALOGD("destroy hdmi private buffer");
- gralloc_drm_bo_decref(drm->hdmi.bo);
- drm->hdmi.bo = NULL;
- }
-
- if (hdmi)
- drmModeFreeConnector(hdmi);
+ /* will trigger modeset */
+ drm->first_post = 1;
- pthread_mutex_unlock(&drm->hdmi_mutex);
+ pthread_mutex_unlock(&drm->outputs_mutex);
}
}
*/
int gralloc_drm_init_kms(struct gralloc_drm_t *drm)
{
- drmModeConnectorPtr lvds, hdmi;
- int i, ret;
-
if (drm->resources)
return 0;
}
}
+ drm->output_capacity = drm->resources->count_connectors;
+ drm->output_count = 0;
+
+ drm->outputs = calloc(sizeof(*drm->outputs), drm->output_capacity);
+
/* find the crtc/connector/mode to use */
- lvds = fetch_connector(drm, DRM_MODE_CONNECTOR_LVDS);
- if (lvds) {
- drm_kms_init_with_connector(drm, &drm->primary, lvds);
- drmModeFreeConnector(lvds);
- drm->primary.active = 1;
+ uint32_t internal_connectors[] = {
+ DRM_MODE_CONNECTOR_LVDS,
+ DRM_MODE_CONNECTOR_DSI,
+ };
+ for (size_t i = 0; i < sizeof(internal_connectors) / sizeof(uint32_t); i++) {
+ drmModeConnectorPtr connector;
+ connector = fetch_connector(drm, internal_connectors[i]);
+ if (connector) {
+ drm_kms_init_with_new_connector(drm, connector);
+ drmModeFreeConnector(connector);
+ break;
+ }
}
/* if still no connector, find first connected connector and try it */
- if (!drm->primary.active) {
+ if (!drm->primary) {
+ int i;
+ ALOGI("Try to find the first connected connector");
for (i = 0; i < drm->resources->count_connectors; i++) {
drmModeConnectorPtr connector;
connector = drmModeGetConnector(drm->fd,
drm->resources->connectors[i]);
if (connector) {
- if (connector->connection == DRM_MODE_CONNECTED) {
- if (!drm_kms_init_with_connector(drm,
- &drm->primary, connector))
- break;
- }
-
+ bool found = (connector->connection == DRM_MODE_CONNECTED)
+ && !!drm_kms_init_with_new_connector(drm, connector);
drmModeFreeConnector(connector);
+ if (found)
+ break;
}
}
if (i == drm->resources->count_connectors) {
}
}
- /* HDMI mirror mode need driver support for blitting. which is not implemented for
- drivers other than intel. skip HDMI detection for them to avoid crash
+ /* Mirror mode need driver support for blitting. which is not implemented for
+ drivers other than intel. skip external detection for them to avoid crash
*/
- if (!drm->drv->blit)
- goto skip_hdmi_modes;
-
- /* check if hdmi is connected already */
- hdmi = fetch_connector(drm, DRM_MODE_CONNECTOR_HDMIA);
- if (hdmi) {
-
- if (hdmi->connector_id == drm->primary.connector_id) {
- /* special case: our primary connector is hdmi */
- ALOGD("hdmi is the primary connector");
- goto skip_hdmi_modes;
- }
+ if (drm->drv->blit) {
+ init_connectors(drm);
- ALOGD("init hdmi on startup");
- init_hdmi_output(drm, hdmi);
-
- drmModeFreeConnector(hdmi);
+ /* launch external display observer thread */
+ pthread_mutex_init(&drm->outputs_mutex, NULL);
+ pthread_create(&drm->hotplug_thread, NULL, extcon_observer, drm);
}
- /* launch hdmi observer thread */
- pthread_mutex_init(&drm->hdmi_mutex, NULL);
- pthread_create(&drm->hdmi_hotplug_thread, NULL, hdmi_observer, drm);
-
-skip_hdmi_modes:
-
drm_kms_init_features(drm);
drm->first_post = 1;
drm->plane_resources = NULL;
}
- /* destroy private buffer of hdmi output */
- if (drm->hdmi.bo)
- gralloc_drm_bo_decref(drm->hdmi.bo);
+ /* destroy private buffer of external output */
+ for (int i = 1; i < drm->output_capacity; i++)
+ if (drm->outputs[i].bo)
+ gralloc_drm_bo_decref(drm->outputs[i].bo);
+
+ free(drm->outputs);
drm_singleton = NULL;
}
struct framebuffer_device_t *fb)
{
*((uint32_t *) &fb->flags) = 0x0;
- *((uint32_t *) &fb->width) = drm->primary.mode.hdisplay;
- *((uint32_t *) &fb->height) = drm->primary.mode.vdisplay;
- *((int *) &fb->stride) = drm->primary.mode.hdisplay;
- *((float *) &fb->fps) = drm->primary.mode.vrefresh;
-
- *((int *) &fb->format) = drm->primary.fb_format;
- *((float *) &fb->xdpi) = drm->primary.xdpi;
- *((float *) &fb->ydpi) = drm->primary.ydpi;
+ *((uint32_t *) &fb->width) = drm->primary->mode.hdisplay;
+ *((uint32_t *) &fb->height) = drm->primary->mode.vdisplay;
+ *((int *) &fb->stride) = drm->primary->mode.hdisplay;
+ *((float *) &fb->fps) = drm->primary->mode.vrefresh;
+
+ *((int *) &fb->format) = drm->primary->fb_format;
+ *((float *) &fb->xdpi) = drm->primary->xdpi;
+ *((float *) &fb->ydpi) = drm->primary->ydpi;
*((int *) &fb->minSwapInterval) = drm->swap_interval;
*((int *) &fb->maxSwapInterval) = drm->swap_interval;
}