OSDN Git Service

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