OSDN Git Service

Merge "drm_hwcomposer: Add Dump() to the Compositor interface" into mnc-dev
[android-x86/external-drm_hwcomposer.git] / hwcomposer.cpp
1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
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
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 #define LOG_TAG "hwcomposer-drm"
18
19 #include "drm_hwcomposer.h"
20 #include "drmresources.h"
21 #include "importer.h"
22 #include "vsyncworker.h"
23
24 #include <errno.h>
25 #include <fcntl.h>
26 #include <list>
27 #include <map>
28 #include <pthread.h>
29 #include <stdlib.h>
30 #include <sys/param.h>
31 #include <sys/resource.h>
32 #include <xf86drm.h>
33 #include <xf86drmMode.h>
34
35 #include <cutils/log.h>
36 #include <cutils/properties.h>
37 #include <hardware/hardware.h>
38 #include <hardware/hwcomposer.h>
39 #include <sw_sync.h>
40 #include <sync/sync.h>
41
42 #define UM_PER_INCH 25400
43
44 namespace android {
45
46 typedef struct hwc_drm_display {
47   struct hwc_context_t *ctx;
48   int display;
49
50   std::vector<uint32_t> config_ids;
51
52   VSyncWorker vsync_worker;
53 } hwc_drm_display_t;
54
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;
59
60   hwc_context_t() : procs(NULL), importer(NULL) {
61   }
62
63   ~hwc_context_t() {
64     delete importer;
65   }
66
67   hwc_composer_device_1_t device;
68   hwc_procs_t const *procs;
69
70   DisplayMap displays;
71   DrmResources drm;
72   Importer *importer;
73 };
74
75 static void hwc_dump(struct hwc_composer_device_1* dev, char *buff,
76                      int buff_len) {
77   struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
78   std::ostringstream out;
79
80   ctx->drm.compositor()->Dump(&out);
81   std::string out_str = out.str();
82   strncpy(buff, out_str.c_str(), std::min((size_t)buff_len, out_str.length()));
83 }
84
85 static int hwc_prepare(hwc_composer_device_1_t *dev, size_t num_displays,
86                        hwc_display_contents_1_t **display_contents) {
87   // XXX: Once we have a GL compositor, just make everything HWC_OVERLAY
88   struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
89   Composition *composition =
90       ctx->drm.compositor()->CreateComposition(ctx->importer);
91   if (!composition) {
92     ALOGE("Drm composition init failed");
93     return -EINVAL;
94   }
95
96   for (int i = 0; i < (int)num_displays; ++i) {
97     if (!display_contents[i])
98       continue;
99
100     int num_layers = display_contents[i]->numHwLayers;
101     int num_planes = composition->GetRemainingLayers(i, num_layers);
102
103     // XXX: Should go away with atomic modeset
104     DrmCrtc *crtc = ctx->drm.GetCrtcForDisplay(i);
105     if (!crtc) {
106       ALOGE("No crtc for display %d", i);
107       delete composition;
108       return -ENODEV;
109     }
110     if (crtc->requires_modeset())
111       num_planes = 0;
112
113     for (int j = std::max(0, num_layers - num_planes); j < num_layers; j++) {
114       if (j >= num_planes)
115         break;
116
117       hwc_layer_1_t *layer = &display_contents[i]->hwLayers[j];
118       if (layer->compositionType == HWC_FRAMEBUFFER)
119         layer->compositionType = HWC_OVERLAY;
120     }
121   }
122
123   delete composition;
124   return 0;
125 }
126
127 static void hwc_set_cleanup(size_t num_displays,
128                             hwc_display_contents_1_t **display_contents,
129                             Composition *composition) {
130   for (int i = 0; i < (int)num_displays; ++i) {
131     if (!display_contents[i])
132       continue;
133
134     hwc_display_contents_1_t *dc = display_contents[i];
135     for (size_t j = 0; j < dc->numHwLayers; ++j) {
136       hwc_layer_1_t *layer = &dc->hwLayers[j];
137       if (layer->acquireFenceFd >= 0) {
138         close(layer->acquireFenceFd);
139         layer->acquireFenceFd = -1;
140       }
141     }
142     if (dc->outbufAcquireFenceFd >= 0) {
143       close(dc->outbufAcquireFenceFd);
144       dc->outbufAcquireFenceFd = -1;
145     }
146   }
147
148   delete composition;
149 }
150
151 static int hwc_add_layer(int display, hwc_context_t *ctx, hwc_layer_1_t *layer,
152                          Composition *composition) {
153   hwc_drm_bo_t bo;
154   int ret = ctx->importer->ImportBuffer(layer->handle, &bo);
155   if (ret) {
156     ALOGE("Failed to import handle to bo %d", ret);
157     return ret;
158   }
159
160   ret = composition->AddLayer(display, layer, &bo);
161   if (!ret)
162     return 0;
163
164   int destroy_ret = ctx->importer->ReleaseBuffer(&bo);
165   if (destroy_ret)
166     ALOGE("Failed to destroy buffer %d", destroy_ret);
167
168   return ret;
169 }
170
171 static int hwc_set(hwc_composer_device_1_t *dev, size_t num_displays,
172                    hwc_display_contents_1_t **display_contents) {
173   struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
174   Composition *composition =
175       ctx->drm.compositor()->CreateComposition(ctx->importer);
176   if (!composition) {
177     ALOGE("Drm composition init failed");
178     hwc_set_cleanup(num_displays, display_contents, NULL);
179     return -EINVAL;
180   }
181
182   int ret;
183   for (int i = 0; i < (int)num_displays; ++i) {
184     if (!display_contents[i])
185       continue;
186
187     DrmCrtc *crtc = ctx->drm.GetCrtcForDisplay(i);
188     if (!crtc) {
189       ALOGE("No crtc for display %d", i);
190       hwc_set_cleanup(num_displays, display_contents, composition);
191       return -ENODEV;
192     }
193
194     hwc_display_contents_1_t *dc = display_contents[i];
195     unsigned num_layers = dc->numHwLayers;
196     unsigned num_planes = composition->GetRemainingLayers(i, num_layers);
197     bool use_target = false;
198     // XXX: We don't need to check for modeset required with atomic modeset
199     if (crtc->requires_modeset() || num_layers > num_planes)
200       use_target = true;
201
202     // XXX: Won't need to worry about FB_TARGET with GL Compositor
203     for (int j = 0; use_target && j < (int)num_layers; ++j) {
204       hwc_layer_1_t *layer = &dc->hwLayers[j];
205       if (layer->compositionType != HWC_FRAMEBUFFER_TARGET)
206         continue;
207
208       ret = hwc_add_layer(i, ctx, layer, composition);
209       if (ret) {
210         ALOGE("Add layer failed %d", ret);
211         hwc_set_cleanup(num_displays, display_contents, composition);
212         return ret;
213       }
214       --num_planes;
215       break;
216     }
217
218     for (int j = 0; num_planes && j < (int)num_layers; ++j) {
219       hwc_layer_1_t *layer = &dc->hwLayers[j];
220       if (layer->compositionType != HWC_OVERLAY)
221         continue;
222
223       ret = hwc_add_layer(i, ctx, layer, composition);
224       if (ret) {
225         ALOGE("Add layer failed %d", ret);
226         hwc_set_cleanup(num_displays, display_contents, composition);
227         return ret;
228       }
229       --num_planes;
230     }
231   }
232
233   ret = ctx->drm.compositor()->QueueComposition(composition);
234   if (ret) {
235     ALOGE("Failed to queue the composition");
236     hwc_set_cleanup(num_displays, display_contents, composition);
237     return ret;
238   }
239   hwc_set_cleanup(num_displays, display_contents, NULL);
240   return ret;
241 }
242
243 static int hwc_event_control(struct hwc_composer_device_1 *dev, int display,
244                              int event, int enabled) {
245   if (event != HWC_EVENT_VSYNC || (enabled != 0 && enabled != 1))
246     return -EINVAL;
247
248   struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
249   hwc_drm_display_t *hd = &ctx->displays[display];
250   return hd->vsync_worker.VSyncControl(enabled);
251 }
252
253 static int hwc_set_power_mode(struct hwc_composer_device_1 *dev, int display,
254                               int mode) {
255   struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
256
257   uint64_t dpmsValue = 0;
258   switch (mode) {
259     case HWC_POWER_MODE_OFF:
260       dpmsValue = DRM_MODE_DPMS_OFF;
261       break;
262
263     /* We can't support dozing right now, so go full on */
264     case HWC_POWER_MODE_DOZE:
265     case HWC_POWER_MODE_DOZE_SUSPEND:
266     case HWC_POWER_MODE_NORMAL:
267       dpmsValue = DRM_MODE_DPMS_ON;
268       break;
269   };
270   return ctx->drm.SetDpmsMode(display, dpmsValue);
271 }
272
273 static int hwc_query(struct hwc_composer_device_1 * /* dev */, int what,
274                      int *value) {
275   switch (what) {
276     case HWC_BACKGROUND_LAYER_SUPPORTED:
277       *value = 0; /* TODO: We should do this */
278       break;
279     case HWC_VSYNC_PERIOD:
280       ALOGW("Query for deprecated vsync value, returning 60Hz");
281       *value = 1000 * 1000 * 1000 / 60;
282       break;
283     case HWC_DISPLAY_TYPES_SUPPORTED:
284       *value = HWC_DISPLAY_PRIMARY | HWC_DISPLAY_EXTERNAL;
285       break;
286   }
287   return 0;
288 }
289
290 static void hwc_register_procs(struct hwc_composer_device_1 *dev,
291                                hwc_procs_t const *procs) {
292   struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
293
294   ctx->procs = procs;
295
296   for (hwc_context_t::DisplayMapIter iter = ctx->displays.begin();
297        iter != ctx->displays.end(); ++iter) {
298     iter->second.vsync_worker.SetProcs(procs);
299   }
300 }
301
302 static int hwc_get_display_configs(struct hwc_composer_device_1 *dev,
303                                    int display, uint32_t *configs,
304                                    size_t *num_configs) {
305   if (!*num_configs)
306     return 0;
307
308   struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
309   hwc_drm_display_t *hd = &ctx->displays[display];
310   hd->config_ids.clear();
311
312   DrmConnector *connector = ctx->drm.GetConnectorForDisplay(display);
313   if (!connector) {
314     ALOGE("Failed to get connector for display %d", display);
315     return -ENODEV;
316   }
317
318   int ret = connector->UpdateModes();
319   if (ret) {
320     ALOGE("Failed to update display modes %d", ret);
321     return ret;
322   }
323
324   for (DrmConnector::ModeIter iter = connector->begin_modes();
325        iter != connector->end_modes(); ++iter) {
326     size_t idx = hd->config_ids.size();
327     if (idx == *num_configs)
328       break;
329     hd->config_ids.push_back(iter->id());
330     configs[idx] = iter->id();
331   }
332   *num_configs = hd->config_ids.size();
333   return *num_configs == 0 ? -1 : 0;
334 }
335
336 static int hwc_get_display_attributes(struct hwc_composer_device_1 *dev,
337                                       int display, uint32_t config,
338                                       const uint32_t *attributes,
339                                       int32_t *values) {
340   struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
341   DrmConnector *c = ctx->drm.GetConnectorForDisplay(display);
342   if (!c) {
343     ALOGE("Failed to get DrmConnector for display %d", display);
344     return -ENODEV;
345   }
346   DrmMode mode;
347   for (DrmConnector::ModeIter iter = c->begin_modes(); iter != c->end_modes();
348        ++iter) {
349     if (iter->id() == config) {
350       mode = *iter;
351       break;
352     }
353   }
354   if (mode.id() == 0) {
355     ALOGE("Failed to find active mode for display %d", display);
356     return -ENOENT;
357   }
358
359   uint32_t mm_width = c->mm_width();
360   uint32_t mm_height = c->mm_height();
361   for (int i = 0; attributes[i] != HWC_DISPLAY_NO_ATTRIBUTE; ++i) {
362     switch (attributes[i]) {
363       case HWC_DISPLAY_VSYNC_PERIOD:
364         values[i] = 1000 * 1000 * 1000 / mode.v_refresh();
365         break;
366       case HWC_DISPLAY_WIDTH:
367         values[i] = mode.h_display();
368         break;
369       case HWC_DISPLAY_HEIGHT:
370         values[i] = mode.v_display();
371         break;
372       case HWC_DISPLAY_DPI_X:
373         /* Dots per 1000 inches */
374         values[i] = mm_width ? (mode.h_display() * UM_PER_INCH) / mm_width : 0;
375         break;
376       case HWC_DISPLAY_DPI_Y:
377         /* Dots per 1000 inches */
378         values[i] =
379             mm_height ? (mode.v_display() * UM_PER_INCH) / mm_height : 0;
380         break;
381     }
382   }
383   return 0;
384 }
385
386 static int hwc_get_active_config(struct hwc_composer_device_1 *dev,
387                                  int display) {
388   struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
389   DrmConnector *c = ctx->drm.GetConnectorForDisplay(display);
390   if (!c) {
391     ALOGE("Failed to get DrmConnector for display %d", display);
392     return -ENODEV;
393   }
394
395   DrmMode mode = c->active_mode();
396   hwc_drm_display_t *hd = &ctx->displays[display];
397   for (size_t i = 0; i < hd->config_ids.size(); ++i) {
398     if (hd->config_ids[i] == mode.id())
399       return i;
400   }
401   return -1;
402 }
403
404 static int hwc_set_active_config(struct hwc_composer_device_1 *dev, int display,
405                                  int index) {
406   struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
407   hwc_drm_display_t *hd = &ctx->displays[display];
408   if (index >= (int)hd->config_ids.size()) {
409     ALOGE("Invalid config index %d passed in", index);
410     return -EINVAL;
411   }
412
413   int ret =
414       ctx->drm.SetDisplayActiveMode(display, hd->config_ids[index]);
415   if (ret) {
416     ALOGE("Failed to set config for display %d", display);
417     return ret;
418   }
419
420   return ret;
421 }
422
423 static int hwc_device_close(struct hw_device_t *dev) {
424   struct hwc_context_t *ctx = (struct hwc_context_t *)dev;
425   delete ctx;
426   return 0;
427 }
428
429 /*
430  * TODO: This function sets the active config to the first one in the list. This
431  * should be fixed such that it selects the preferred mode for the display, or
432  * some other, saner, method of choosing the config.
433  */
434 static int hwc_set_initial_config(hwc_drm_display_t *hd) {
435   uint32_t config;
436   size_t num_configs = 1;
437   int ret = hwc_get_display_configs(&hd->ctx->device, hd->display, &config,
438                                     &num_configs);
439   if (ret || !num_configs)
440     return 0;
441
442   ret = hwc_set_active_config(&hd->ctx->device, hd->display, 0);
443   if (ret) {
444     ALOGE("Failed to set active config d=%d ret=%d", hd->display, ret);
445     return ret;
446   }
447
448   return ret;
449 }
450
451 static int hwc_initialize_display(struct hwc_context_t *ctx, int display) {
452   hwc_drm_display_t *hd = &ctx->displays[display];
453   hd->ctx = ctx;
454   hd->display = display;
455
456   int ret = hwc_set_initial_config(hd);
457   if (ret) {
458     ALOGE("Failed to set initial config for d=%d ret=%d", display, ret);
459     return ret;
460   }
461
462   ret = hd->vsync_worker.Init(&ctx->drm, display);
463   if (ret) {
464     ALOGE("Failed to create event worker for display %d %d\n", display, ret);
465     return ret;
466   }
467
468   return 0;
469 }
470
471 static int hwc_enumerate_displays(struct hwc_context_t *ctx) {
472   int ret;
473   for (DrmResources::ConnectorIter c = ctx->drm.begin_connectors();
474        c != ctx->drm.end_connectors(); ++c) {
475     ret = hwc_initialize_display(ctx, (*c)->display());
476     if (ret) {
477       ALOGE("Failed to initialize display %d", (*c)->display());
478       return ret;
479     }
480   }
481
482   return 0;
483 }
484
485 static int hwc_device_open(const struct hw_module_t *module, const char *name,
486                            struct hw_device_t **dev) {
487   if (strcmp(name, HWC_HARDWARE_COMPOSER)) {
488     ALOGE("Invalid module name- %s", name);
489     return -EINVAL;
490   }
491
492   struct hwc_context_t *ctx = new hwc_context_t();
493   if (!ctx) {
494     ALOGE("Failed to allocate hwc context");
495     return -ENOMEM;
496   }
497
498   int ret = ctx->drm.Init();
499   if (ret) {
500     ALOGE("Can't initialize Drm object %d", ret);
501     delete ctx;
502     return ret;
503   }
504
505   ctx->importer = Importer::CreateInstance(&ctx->drm);
506   if (!ctx->importer) {
507     ALOGE("Failed to create importer instance");
508     delete ctx;
509     return ret;
510   }
511
512   ret = hwc_enumerate_displays(ctx);
513   if (ret) {
514     ALOGE("Failed to enumerate displays: %s", strerror(ret));
515     delete ctx;
516     return ret;
517   }
518
519   ctx->device.common.tag = HARDWARE_DEVICE_TAG;
520   ctx->device.common.version = HWC_DEVICE_API_VERSION_1_4;
521   ctx->device.common.module = const_cast<hw_module_t *>(module);
522   ctx->device.common.close = hwc_device_close;
523
524   ctx->device.dump = hwc_dump;
525   ctx->device.prepare = hwc_prepare;
526   ctx->device.set = hwc_set;
527   ctx->device.eventControl = hwc_event_control;
528   ctx->device.setPowerMode = hwc_set_power_mode;
529   ctx->device.query = hwc_query;
530   ctx->device.registerProcs = hwc_register_procs;
531   ctx->device.getDisplayConfigs = hwc_get_display_configs;
532   ctx->device.getDisplayAttributes = hwc_get_display_attributes;
533   ctx->device.getActiveConfig = hwc_get_active_config;
534   ctx->device.setActiveConfig = hwc_set_active_config;
535   ctx->device.setCursorPositionAsync = NULL; /* TODO: Add cursor */
536
537   *dev = &ctx->device.common;
538
539   return 0;
540 }
541 }
542
543 static struct hw_module_methods_t hwc_module_methods = {
544   open : android::hwc_device_open
545 };
546
547 hwc_module_t HAL_MODULE_INFO_SYM = {
548   common : {
549     tag : HARDWARE_MODULE_TAG,
550     version_major : 1,
551     version_minor : 0,
552     id : HWC_HARDWARE_MODULE_ID,
553     name : "DRM hwcomposer module",
554     author : "The Android Open Source Project",
555     methods : &hwc_module_methods,
556     dso : NULL,
557     reserved : {0},
558   }
559 };