OSDN Git Service

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