OSDN Git Service

drm_hwcomposer: Split the drm compositor into per-display threads
[android-x86/external-drm_hwcomposer.git] / gl_compositor.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 "GLCompositor"
19
20 #include <vector>
21
22 #include <cutils/log.h>
23
24 #include <ui/GraphicBuffer.h>
25 #include <utils/Trace.h>
26
27 #include <sync/sync.h>
28 #include <sw_sync.h>
29
30 #include "drm_hwcomposer.h"
31
32 #include "gl_compositor.h"
33 #include "glworker.h"
34
35 namespace android {
36
37 static const char *get_gl_error(void);
38 static const char *get_egl_error(void);
39 static bool has_extension(const char *extension, const char *extensions);
40
41 template <typename T>
42 int AllocResource(std::vector<T> &array) {
43   for (typename std::vector<T>::iterator it = array.begin(); it != array.end();
44        ++it) {
45     if (!it->is_some()) {
46       return std::distance(array.begin(), it);
47     }
48   }
49
50   array.push_back(T());
51   return array.size() - 1;
52 }
53
54 template <typename T>
55 void FreeResource(std::vector<T> &array, int index) {
56   if (index == (int)array.size() - 1) {
57     array.pop_back();
58   } else if (index >= 0 && (unsigned)index < array.size()) {
59     array[index].Reset();
60   }
61 }
62
63 struct GLTarget {
64   sp<GraphicBuffer> fb;
65   bool forgotten;
66   unsigned composition_count;
67
68   GLTarget() : forgotten(true), composition_count(0) {
69   }
70
71   void Reset() {
72     fb.clear();
73     forgotten = true;
74     composition_count = 0;
75   }
76
77   bool is_some() const {
78     return fb != NULL;
79   }
80 };
81
82 struct GLCompositor::priv_data {
83   int current_target;
84   std::vector<GLTarget> targets;
85   std::vector<GLComposition *> compositions;
86
87   GLWorker worker;
88
89   priv_data() : current_target(-1) {
90   }
91 };
92
93 class GLComposition : public Composition {
94  public:
95   struct LayerData {
96     hwc_layer_1 layer;
97     hwc_drm_bo bo;
98   };
99
100   GLComposition(GLCompositor *owner, Importer *imp)
101       : compositor(owner), importer(imp), target_handle(-1), timeline_fd(-1) {
102     int ret = sw_sync_timeline_create();
103     if (ret < 0) {
104       ALOGE("Failed to create sw sync timeline %d", ret);
105     }
106     timeline_fd = ret;
107   }
108
109   virtual ~GLComposition() {
110     if (timeline_fd >= 0)
111       close(timeline_fd);
112
113     if (compositor == NULL) {
114       return;
115     }
116
117     // Removes this composition from the owning compositor automatically.
118     std::vector<GLComposition *> &compositions =
119         compositor->priv_->compositions;
120     std::vector<GLComposition *>::iterator it =
121         std::find(compositions.begin(), compositions.end(), this);
122     if (it != compositions.end()) {
123       compositions.erase(it);
124     }
125
126     GLTarget *target = &compositor->priv_->targets[target_handle];
127     target->composition_count--;
128     compositor->CheckAndDestroyTarget(target_handle);
129   }
130
131   virtual int AddLayer(int display, hwc_layer_1 *layer, hwc_drm_bo *bo) {
132     (void)display;
133     if (layer->compositionType != HWC_OVERLAY) {
134       ALOGE("Must add layers with compositionType == HWC_OVERLAY");
135       return 1;
136     }
137
138     if (layer->handle == 0) {
139       ALOGE("Must add layers with valid buffer handle");
140       return 1;
141     }
142
143     layer->releaseFenceFd = sw_sync_fence_create(
144         timeline_fd, "GLComposition release fence", layers.size() + 1);
145
146     layers.push_back(*layer);
147
148     return importer->ReleaseBuffer(bo);
149   }
150
151   virtual unsigned GetRemainingLayers(int display, unsigned num_needed) const {
152     (void)display;
153     return num_needed;
154   }
155
156   GLCompositor *compositor;
157   Importer *importer;
158   int target_handle;
159   int timeline_fd;
160   std::vector<hwc_layer_1> layers;
161 };
162
163 GLCompositor::GLCompositor() {
164   priv_ = new priv_data;
165 }
166
167 GLCompositor::~GLCompositor() {
168   for (std::vector<GLComposition *>::iterator it = priv_->compositions.end();
169        it != priv_->compositions.begin(); it = priv_->compositions.end()) {
170     --it;
171
172     // Prevents compositor from trying to erase itself
173     (*it)->compositor = NULL;
174     delete *it;
175     priv_->compositions.erase(it);
176   }
177
178   delete priv_;
179 }
180
181 int GLCompositor::Init() {
182   return priv_->worker.Init();
183 }
184
185 Targeting *GLCompositor::targeting() {
186   return (Targeting *)this;
187 }
188
189 int GLCompositor::CreateTarget(sp<GraphicBuffer> &buffer) {
190   int ret;
191
192   int target_handle = AllocResource(priv_->targets);
193   GLTarget *target = &priv_->targets[target_handle];
194
195   target->fb = buffer;
196   target->forgotten = false;
197
198   return target_handle;
199 }
200
201 void GLCompositor::SetTarget(int target_handle) {
202   if (target_handle >= 0 && (unsigned)target_handle < priv_->targets.size()) {
203     GLTarget *target = &priv_->targets[target_handle];
204     if (target->is_some()) {
205       priv_->current_target = target_handle;
206       return;
207     }
208   }
209
210   priv_->current_target = -1;
211 }
212
213 void GLCompositor::ForgetTarget(int target_handle) {
214   if (target_handle >= 0 && (unsigned)target_handle < priv_->targets.size()) {
215     if (target_handle == priv_->current_target) {
216       priv_->current_target = -1;
217     }
218
219     GLTarget *target = &priv_->targets[target_handle];
220     if (target->is_some()) {
221       target->forgotten = true;
222       CheckAndDestroyTarget(target_handle);
223       return;
224     }
225   }
226
227   ALOGE("Failed to forget target because of invalid handle");
228 }
229
230 void GLCompositor::CheckAndDestroyTarget(int target_handle) {
231   GLTarget *target = &priv_->targets[target_handle];
232   if (target->composition_count == 0 && target->forgotten) {
233     FreeResource(priv_->targets, target_handle);
234   }
235 }
236
237 Composition *GLCompositor::CreateComposition(Importer *importer) {
238   if (priv_->current_target >= 0 &&
239       (unsigned)priv_->current_target < priv_->targets.size()) {
240     GLTarget *target = &priv_->targets[priv_->current_target];
241     if (target->is_some()) {
242       GLComposition *composition = new GLComposition(this, importer);
243       composition->target_handle = priv_->current_target;
244       target->composition_count++;
245       priv_->compositions.push_back(composition);
246       return composition;
247     }
248   }
249
250   ALOGE("Failed to create composition because of invalid target handle %d",
251         priv_->current_target);
252
253   return NULL;
254 }
255
256 int GLCompositor::QueueComposition(Composition *composition) {
257   if (composition) {
258     GLComposition *gl_composition = (GLComposition *)composition;
259     int ret = DoComposition(gl_composition);
260     gl_composition->timeline_fd = -1;
261     delete composition;
262     return ret;
263   }
264
265   ALOGE("Failed to queue composition because of invalid composition handle");
266
267   return -EINVAL;
268 }
269
270 int GLCompositor::Composite() {
271   return 0;
272 }
273
274 int GLCompositor::DoComposition(GLComposition *composition) {
275   ATRACE_CALL();
276   int ret = 0;
277
278   GLTarget *target = &priv_->targets[composition->target_handle];
279   GLWorker::Work work;
280   work.layers = composition->layers.data();
281   work.num_layers = composition->layers.size();
282   work.timeline_fd = composition->timeline_fd;
283   work.framebuffer = target->fb;
284
285   ret = priv_->worker.DoWork(&work);
286
287   if (work.timeline_fd >= 0) {
288     sw_sync_timeline_inc(work.timeline_fd, work.num_layers + 1);
289     close(work.timeline_fd);
290   }
291
292   return ret;
293 }
294
295 }  // namespace android