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>
AllocResource(std::vector<T> & array)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>
FreeResource(std::vector<T> & array,int index)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
GLTargetandroid::GLTarget68 GLTarget() : forgotten(true), composition_count(0) {
69 }
70
Resetandroid::GLTarget71 void Reset() {
72 fb.clear();
73 forgotten = true;
74 composition_count = 0;
75 }
76
is_someandroid::GLTarget77 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
priv_dataandroid::GLCompositor::priv_data89 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
GLComposition(GLCompositor * owner,Importer * imp)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
~GLComposition()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
AddLayer(int display,hwc_layer_1 * layer,hwc_drm_bo * bo)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
GetRemainingLayers(int display,unsigned num_needed) const151 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
GLCompositor()163 GLCompositor::GLCompositor() {
164 priv_ = new priv_data;
165 }
166
~GLCompositor()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
Init()181 int GLCompositor::Init() {
182 return priv_->worker.Init();
183 }
184
targeting()185 Targeting *GLCompositor::targeting() {
186 return (Targeting *)this;
187 }
188
CreateTarget(sp<GraphicBuffer> & buffer)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
SetTarget(int target_handle)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
ForgetTarget(int target_handle)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
CheckAndDestroyTarget(int target_handle)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
CreateComposition(Importer * importer)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
QueueComposition(Composition * composition)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
Composite()270 int GLCompositor::Composite() {
271 return 0;
272 }
273
DoComposition(GLComposition * composition)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
296