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 "hwc-virtual-compositor-worker"
18 
19 #include "virtualcompositorworker.h"
20 #include "worker.h"
21 
22 #include <errno.h>
23 #include <stdlib.h>
24 
25 #include <cutils/log.h>
26 #include <hardware/hardware.h>
27 #include <hardware/hwcomposer.h>
28 #include <sched.h>
29 #include <sw_sync.h>
30 #include <sync/sync.h>
31 
32 namespace android {
33 
34 static const int kMaxQueueDepth = 3;
35 static const int kAcquireWaitTimeoutMs = 3000;
36 
VirtualCompositorWorker()37 VirtualCompositorWorker::VirtualCompositorWorker()
38     : Worker("virtual-compositor", HAL_PRIORITY_URGENT_DISPLAY),
39       timeline_fd_(-1),
40       timeline_(0),
41       timeline_current_(0) {
42 }
43 
~VirtualCompositorWorker()44 VirtualCompositorWorker::~VirtualCompositorWorker() {
45   if (timeline_fd_ >= 0) {
46     FinishComposition(timeline_);
47     close(timeline_fd_);
48     timeline_fd_ = -1;
49   }
50 }
51 
Init()52 int VirtualCompositorWorker::Init() {
53   int ret = sw_sync_timeline_create();
54   if (ret < 0) {
55     ALOGE("Failed to create sw sync timeline %d", ret);
56     return ret;
57   }
58   timeline_fd_ = ret;
59   return InitWorker();
60 }
61 
QueueComposite(hwc_display_contents_1_t * dc)62 void VirtualCompositorWorker::QueueComposite(hwc_display_contents_1_t *dc) {
63   std::unique_ptr<VirtualComposition> composition(new VirtualComposition);
64 
65   composition->outbuf_acquire_fence.Set(dc->outbufAcquireFenceFd);
66   dc->outbufAcquireFenceFd = -1;
67   if (dc->retireFenceFd >= 0)
68     close(dc->retireFenceFd);
69   dc->retireFenceFd = CreateNextTimelineFence();
70 
71   for (size_t i = 0; i < dc->numHwLayers; ++i) {
72     hwc_layer_1_t *layer = &dc->hwLayers[i];
73     if (layer->flags & HWC_SKIP_LAYER)
74       continue;
75     composition->layer_acquire_fences.emplace_back(layer->acquireFenceFd);
76     layer->acquireFenceFd = -1;
77     if (layer->releaseFenceFd >= 0)
78       close(layer->releaseFenceFd);
79     layer->releaseFenceFd = CreateNextTimelineFence();
80   }
81 
82   composition->release_timeline = timeline_;
83 
84   Lock();
85   while (composite_queue_.size() >= kMaxQueueDepth) {
86     Unlock();
87     sched_yield();
88     Lock();
89   }
90 
91   composite_queue_.push(std::move(composition));
92   SignalLocked();
93   Unlock();
94 }
95 
Routine()96 void VirtualCompositorWorker::Routine() {
97   int ret = Lock();
98   if (ret) {
99     ALOGE("Failed to lock worker, %d", ret);
100     return;
101   }
102 
103   int wait_ret = 0;
104   if (composite_queue_.empty()) {
105     wait_ret = WaitForSignalOrExitLocked();
106   }
107 
108   std::unique_ptr<VirtualComposition> composition;
109   if (!composite_queue_.empty()) {
110     composition = std::move(composite_queue_.front());
111     composite_queue_.pop();
112   }
113 
114   ret = Unlock();
115   if (ret) {
116     ALOGE("Failed to unlock worker, %d", ret);
117     return;
118   }
119 
120   if (wait_ret == -EINTR) {
121     return;
122   } else if (wait_ret) {
123     ALOGE("Failed to wait for signal, %d", wait_ret);
124     return;
125   }
126 
127   Compose(std::move(composition));
128 }
129 
CreateNextTimelineFence()130 int VirtualCompositorWorker::CreateNextTimelineFence() {
131   ++timeline_;
132   return sw_sync_fence_create(timeline_fd_, "drm_fence", timeline_);
133 }
134 
FinishComposition(int point)135 int VirtualCompositorWorker::FinishComposition(int point) {
136   int timeline_increase = point - timeline_current_;
137   if (timeline_increase <= 0)
138     return 0;
139   int ret = sw_sync_timeline_inc(timeline_fd_, timeline_increase);
140   if (ret)
141     ALOGE("Failed to increment sync timeline %d", ret);
142   else
143     timeline_current_ = point;
144   return ret;
145 }
146 
Compose(std::unique_ptr<VirtualComposition> composition)147 void VirtualCompositorWorker::Compose(
148     std::unique_ptr<VirtualComposition> composition) {
149   if (!composition.get())
150     return;
151 
152   int ret;
153   int outbuf_acquire_fence = composition->outbuf_acquire_fence.get();
154   if (outbuf_acquire_fence >= 0) {
155     ret = sync_wait(outbuf_acquire_fence, kAcquireWaitTimeoutMs);
156     if (ret) {
157       ALOGE("Failed to wait for outbuf acquire %d/%d", outbuf_acquire_fence,
158             ret);
159       return;
160     }
161     composition->outbuf_acquire_fence.Close();
162   }
163   for (size_t i = 0; i < composition->layer_acquire_fences.size(); ++i) {
164     int layer_acquire_fence = composition->layer_acquire_fences[i].get();
165     if (layer_acquire_fence >= 0) {
166       ret = sync_wait(layer_acquire_fence, kAcquireWaitTimeoutMs);
167       if (ret) {
168         ALOGE("Failed to wait for layer acquire %d/%d", layer_acquire_fence,
169               ret);
170         return;
171       }
172       composition->layer_acquire_fences[i].Close();
173     }
174   }
175   FinishComposition(composition->release_timeline);
176 }
177 }
178