2 * Copyright (C) 2015 The Android Open Source Project
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #define LOG_TAG "hwcomposer-drm"
19 #include "drm_hwcomposer.h"
20 #include "drmresources.h"
22 #include "vsyncworker.h"
30 #include <sys/param.h>
31 #include <sys/resource.h>
33 #include <xf86drmMode.h>
35 #include <cutils/log.h>
36 #include <cutils/properties.h>
37 #include <hardware/hardware.h>
38 #include <hardware/hwcomposer.h>
40 #include <sync/sync.h>
42 #define UM_PER_INCH 25400
46 typedef struct hwc_drm_display {
47 struct hwc_context_t *ctx;
50 std::vector<uint32_t> config_ids;
52 VSyncWorker vsync_worker;
55 struct hwc_context_t {
56 // map of display:hwc_drm_display_t
57 typedef std::map<int, hwc_drm_display_t> DisplayMap;
58 typedef DisplayMap::iterator DisplayMapIter;
60 hwc_context_t() : procs(NULL), importer(NULL) {
67 hwc_composer_device_1_t device;
68 hwc_procs_t const *procs;
75 static int hwc_prepare(hwc_composer_device_1_t *dev, size_t num_displays,
76 hwc_display_contents_1_t **display_contents) {
77 // XXX: Once we have a GL compositor, just make everything HWC_OVERLAY
78 struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
79 Composition *composition =
80 ctx->drm.compositor()->CreateComposition(ctx->importer);
82 ALOGE("Drm composition init failed");
86 for (int i = 0; i < (int)num_displays; ++i) {
87 if (!display_contents[i])
90 int num_layers = display_contents[i]->numHwLayers;
91 int num_planes = composition->GetRemainingLayers(i, num_layers);
93 // XXX: Should go away with atomic modeset
94 DrmCrtc *crtc = ctx->drm.GetCrtcForDisplay(i);
96 ALOGE("No crtc for display %d", i);
100 if (crtc->requires_modeset())
103 for (int j = std::max(0, num_layers - num_planes); j < num_layers; j++) {
107 hwc_layer_1_t *layer = &display_contents[i]->hwLayers[j];
108 if (layer->compositionType == HWC_FRAMEBUFFER)
109 layer->compositionType = HWC_OVERLAY;
117 static void hwc_set_cleanup(size_t num_displays,
118 hwc_display_contents_1_t **display_contents,
119 Composition *composition) {
120 for (int i = 0; i < (int)num_displays; ++i) {
121 if (!display_contents[i])
124 hwc_display_contents_1_t *dc = display_contents[i];
125 for (size_t j = 0; j < dc->numHwLayers; ++j) {
126 hwc_layer_1_t *layer = &dc->hwLayers[j];
127 if (layer->acquireFenceFd >= 0) {
128 close(layer->acquireFenceFd);
129 layer->acquireFenceFd = -1;
132 if (dc->outbufAcquireFenceFd >= 0) {
133 close(dc->outbufAcquireFenceFd);
134 dc->outbufAcquireFenceFd = -1;
141 static int hwc_add_layer(int display, hwc_context_t *ctx, hwc_layer_1_t *layer,
142 Composition *composition) {
144 int ret = ctx->importer->ImportBuffer(layer->handle, &bo);
146 ALOGE("Failed to import handle to bo %d", ret);
150 ret = composition->AddLayer(display, layer, &bo);
154 int destroy_ret = ctx->importer->ReleaseBuffer(&bo);
156 ALOGE("Failed to destroy buffer %d", destroy_ret);
161 static int hwc_set(hwc_composer_device_1_t *dev, size_t num_displays,
162 hwc_display_contents_1_t **display_contents) {
163 struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
164 Composition *composition =
165 ctx->drm.compositor()->CreateComposition(ctx->importer);
167 ALOGE("Drm composition init failed");
168 hwc_set_cleanup(num_displays, display_contents, NULL);
173 for (int i = 0; i < (int)num_displays; ++i) {
174 if (!display_contents[i])
177 DrmCrtc *crtc = ctx->drm.GetCrtcForDisplay(i);
179 ALOGE("No crtc for display %d", i);
180 hwc_set_cleanup(num_displays, display_contents, composition);
184 hwc_display_contents_1_t *dc = display_contents[i];
185 unsigned num_layers = dc->numHwLayers;
186 unsigned num_planes = composition->GetRemainingLayers(i, num_layers);
187 bool use_target = false;
188 // XXX: We don't need to check for modeset required with atomic modeset
189 if (crtc->requires_modeset() || num_layers > num_planes)
192 // XXX: Won't need to worry about FB_TARGET with GL Compositor
193 for (int j = 0; use_target && j < (int)num_layers; ++j) {
194 hwc_layer_1_t *layer = &dc->hwLayers[j];
195 if (layer->compositionType != HWC_FRAMEBUFFER_TARGET)
198 ret = hwc_add_layer(i, ctx, layer, composition);
200 ALOGE("Add layer failed %d", ret);
201 hwc_set_cleanup(num_displays, display_contents, composition);
208 for (int j = 0; num_planes && j < (int)num_layers; ++j) {
209 hwc_layer_1_t *layer = &dc->hwLayers[j];
210 if (layer->compositionType != HWC_OVERLAY)
213 ret = hwc_add_layer(i, ctx, layer, composition);
215 ALOGE("Add layer failed %d", ret);
216 hwc_set_cleanup(num_displays, display_contents, composition);
223 ret = ctx->drm.compositor()->QueueComposition(composition);
225 ALOGE("Failed to queue the composition");
226 hwc_set_cleanup(num_displays, display_contents, composition);
229 hwc_set_cleanup(num_displays, display_contents, NULL);
233 static int hwc_event_control(struct hwc_composer_device_1 *dev, int display,
234 int event, int enabled) {
235 if (event != HWC_EVENT_VSYNC || (enabled != 0 && enabled != 1))
238 struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
239 hwc_drm_display_t *hd = &ctx->displays[display];
240 return hd->vsync_worker.VSyncControl(enabled);
243 static int hwc_set_power_mode(struct hwc_composer_device_1 *dev, int display,
245 struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
247 uint64_t dpmsValue = 0;
249 case HWC_POWER_MODE_OFF:
250 dpmsValue = DRM_MODE_DPMS_OFF;
253 /* We can't support dozing right now, so go full on */
254 case HWC_POWER_MODE_DOZE:
255 case HWC_POWER_MODE_DOZE_SUSPEND:
256 case HWC_POWER_MODE_NORMAL:
257 dpmsValue = DRM_MODE_DPMS_ON;
260 return ctx->drm.SetDpmsMode(display, dpmsValue);
263 static int hwc_query(struct hwc_composer_device_1 * /* dev */, int what,
266 case HWC_BACKGROUND_LAYER_SUPPORTED:
267 *value = 0; /* TODO: We should do this */
269 case HWC_VSYNC_PERIOD:
270 ALOGW("Query for deprecated vsync value, returning 60Hz");
271 *value = 1000 * 1000 * 1000 / 60;
273 case HWC_DISPLAY_TYPES_SUPPORTED:
274 *value = HWC_DISPLAY_PRIMARY | HWC_DISPLAY_EXTERNAL;
280 static void hwc_register_procs(struct hwc_composer_device_1 *dev,
281 hwc_procs_t const *procs) {
282 struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
286 for (hwc_context_t::DisplayMapIter iter = ctx->displays.begin();
287 iter != ctx->displays.end(); ++iter) {
288 iter->second.vsync_worker.SetProcs(procs);
292 static int hwc_get_display_configs(struct hwc_composer_device_1 *dev,
293 int display, uint32_t *configs,
294 size_t *num_configs) {
298 struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
299 hwc_drm_display_t *hd = &ctx->displays[display];
300 hd->config_ids.clear();
302 DrmConnector *connector = ctx->drm.GetConnectorForDisplay(display);
304 ALOGE("Failed to get connector for display %d", display);
308 int ret = connector->UpdateModes();
310 ALOGE("Failed to update display modes %d", ret);
314 for (DrmConnector::ModeIter iter = connector->begin_modes();
315 iter != connector->end_modes(); ++iter) {
316 size_t idx = hd->config_ids.size();
317 if (idx == *num_configs)
319 hd->config_ids.push_back(iter->id());
320 configs[idx] = iter->id();
322 *num_configs = hd->config_ids.size();
323 return *num_configs == 0 ? -1 : 0;
326 static int hwc_get_display_attributes(struct hwc_composer_device_1 *dev,
327 int display, uint32_t config,
328 const uint32_t *attributes,
330 struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
331 DrmConnector *c = ctx->drm.GetConnectorForDisplay(display);
333 ALOGE("Failed to get DrmConnector for display %d", display);
337 for (DrmConnector::ModeIter iter = c->begin_modes(); iter != c->end_modes();
339 if (iter->id() == config) {
344 if (mode.id() == 0) {
345 ALOGE("Failed to find active mode for display %d", display);
349 uint32_t mm_width = c->mm_width();
350 uint32_t mm_height = c->mm_height();
351 for (int i = 0; attributes[i] != HWC_DISPLAY_NO_ATTRIBUTE; ++i) {
352 switch (attributes[i]) {
353 case HWC_DISPLAY_VSYNC_PERIOD:
354 values[i] = 1000 * 1000 * 1000 / mode.v_refresh();
356 case HWC_DISPLAY_WIDTH:
357 values[i] = mode.h_display();
359 case HWC_DISPLAY_HEIGHT:
360 values[i] = mode.v_display();
362 case HWC_DISPLAY_DPI_X:
363 /* Dots per 1000 inches */
364 values[i] = mm_width ? (mode.h_display() * UM_PER_INCH) / mm_width : 0;
366 case HWC_DISPLAY_DPI_Y:
367 /* Dots per 1000 inches */
369 mm_height ? (mode.v_display() * UM_PER_INCH) / mm_height : 0;
376 static int hwc_get_active_config(struct hwc_composer_device_1 *dev,
378 struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
379 DrmConnector *c = ctx->drm.GetConnectorForDisplay(display);
381 ALOGE("Failed to get DrmConnector for display %d", display);
385 DrmMode mode = c->active_mode();
386 hwc_drm_display_t *hd = &ctx->displays[display];
387 for (size_t i = 0; i < hd->config_ids.size(); ++i) {
388 if (hd->config_ids[i] == mode.id())
394 static int hwc_set_active_config(struct hwc_composer_device_1 *dev, int display,
396 struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
397 hwc_drm_display_t *hd = &ctx->displays[display];
398 if (index >= (int)hd->config_ids.size()) {
399 ALOGE("Invalid config index %d passed in", index);
404 ctx->drm.SetDisplayActiveMode(display, hd->config_ids[index]);
406 ALOGE("Failed to set config for display %d", display);
413 static int hwc_device_close(struct hw_device_t *dev) {
414 struct hwc_context_t *ctx = (struct hwc_context_t *)dev;
420 * TODO: This function sets the active config to the first one in the list. This
421 * should be fixed such that it selects the preferred mode for the display, or
422 * some other, saner, method of choosing the config.
424 static int hwc_set_initial_config(hwc_drm_display_t *hd) {
426 size_t num_configs = 1;
427 int ret = hwc_get_display_configs(&hd->ctx->device, hd->display, &config,
429 if (ret || !num_configs)
432 ret = hwc_set_active_config(&hd->ctx->device, hd->display, 0);
434 ALOGE("Failed to set active config d=%d ret=%d", hd->display, ret);
441 static int hwc_initialize_display(struct hwc_context_t *ctx, int display) {
442 hwc_drm_display_t *hd = &ctx->displays[display];
444 hd->display = display;
446 int ret = hwc_set_initial_config(hd);
448 ALOGE("Failed to set initial config for d=%d ret=%d", display, ret);
452 ret = hd->vsync_worker.Init(&ctx->drm, display);
454 ALOGE("Failed to create event worker for display %d %d\n", display, ret);
461 static int hwc_enumerate_displays(struct hwc_context_t *ctx) {
463 for (DrmResources::ConnectorIter c = ctx->drm.begin_connectors();
464 c != ctx->drm.end_connectors(); ++c) {
465 ret = hwc_initialize_display(ctx, (*c)->display());
467 ALOGE("Failed to initialize display %d", (*c)->display());
475 static int hwc_device_open(const struct hw_module_t *module, const char *name,
476 struct hw_device_t **dev) {
477 if (strcmp(name, HWC_HARDWARE_COMPOSER)) {
478 ALOGE("Invalid module name- %s", name);
482 struct hwc_context_t *ctx = new hwc_context_t();
484 ALOGE("Failed to allocate hwc context");
488 int ret = ctx->drm.Init();
490 ALOGE("Can't initialize Drm object %d", ret);
495 ctx->importer = Importer::CreateInstance(&ctx->drm);
496 if (!ctx->importer) {
497 ALOGE("Failed to create importer instance");
502 ret = hwc_enumerate_displays(ctx);
504 ALOGE("Failed to enumerate displays: %s", strerror(ret));
509 ctx->device.common.tag = HARDWARE_DEVICE_TAG;
510 ctx->device.common.version = HWC_DEVICE_API_VERSION_1_4;
511 ctx->device.common.module = const_cast<hw_module_t *>(module);
512 ctx->device.common.close = hwc_device_close;
514 ctx->device.prepare = hwc_prepare;
515 ctx->device.set = hwc_set;
516 ctx->device.eventControl = hwc_event_control;
517 ctx->device.setPowerMode = hwc_set_power_mode;
518 ctx->device.query = hwc_query;
519 ctx->device.registerProcs = hwc_register_procs;
520 ctx->device.getDisplayConfigs = hwc_get_display_configs;
521 ctx->device.getDisplayAttributes = hwc_get_display_attributes;
522 ctx->device.getActiveConfig = hwc_get_active_config;
523 ctx->device.setActiveConfig = hwc_set_active_config;
524 ctx->device.setCursorPositionAsync = NULL; /* TODO: Add cursor */
526 *dev = &ctx->device.common;
532 static struct hw_module_methods_t hwc_module_methods = {
533 open : android::hwc_device_open
536 hwc_module_t HAL_MODULE_INFO_SYM = {
538 tag : HARDWARE_MODULE_TAG,
541 id : HWC_HARDWARE_MODULE_ID,
542 name : "DRM hwcomposer module",
543 author : "The Android Open Source Project",
544 methods : &hwc_module_methods,