OSDN Git Service

Ensure GL resources are initlialized before MakeCurrent.
[android-x86/external-IA-Hardware-Composer.git] / common / compositor / compositor.cpp
1 /*
2 // Copyright (c) 2016 Intel Corporation
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 #include "compositor.h"
18
19 #include <xf86drmMode.h>
20
21 #include "disjoint_layers.h"
22 #include "displayplanestate.h"
23 #include "hwctrace.h"
24 #include "nativegpuresource.h"
25 #include "nativesurface.h"
26 #include "nativesync.h"
27 #include "overlaylayer.h"
28 #include "renderer.h"
29 #include "renderstate.h"
30 #include "scopedrendererstate.h"
31
32 namespace hwcomposer {
33
34 Compositor::Compositor() {
35 }
36
37 Compositor::~Compositor() {
38 }
39
40 void Compositor::Init(NativeBufferHandler *buffer_handler, uint32_t width,
41                       uint32_t height, uint32_t gpu_fd) {
42   buffer_handler_ = buffer_handler;
43   gpu_fd_ = gpu_fd;
44   if (!surfaces_.empty()) {
45     if (width == surfaces_.back()->GetWidth() ||
46         height == surfaces_.back()->GetHeight())
47       return;
48
49     for (auto i = surfaces_.begin(); i != surfaces_.end();) {
50       i->reset(nullptr);
51       i = surfaces_.erase(i);
52     }
53   }
54
55   gpu_resource_handler_.reset(CreateNativeGpuResourceHandler());
56
57   width_ = width;
58   height_ = height;
59 }
60
61 bool Compositor::BeginFrame() {
62   if (!renderer_) {
63     renderer_.reset(CreateRenderer());
64     if (!renderer_->Init()) {
65       ETRACE("Failed to initialize OpenGL compositor %s", PRINTERROR());
66       renderer_.reset(nullptr);
67       return false;
68     }
69   }
70
71   if (!in_flight_surfaces_.empty())
72     std::vector<NativeSurface *>().swap(in_flight_surfaces_);
73
74   return true;
75 }
76
77 bool Compositor::Draw(DisplayPlaneStateList &comp_planes,
78                       std::vector<OverlayLayer> &layers,
79                       const std::vector<HwcRect<int>> &display_frame) {
80   const DisplayPlaneState *comp = NULL;
81   std::vector<size_t> dedicated_layers;
82   ScopedRendererState state(renderer_.get());
83   if (!state.IsValid()) {
84     ETRACE("Failed to draw as Renderer doesnt have a valid context.");
85     return false;
86   }
87
88   if (!gpu_resource_handler_->PrepareResources(layers)) {
89     ETRACE(
90         "Failed to prepare GPU resources for compositing the frame, "
91         "error: %s",
92         PRINTERROR());
93     return false;
94   }
95
96   for (DisplayPlaneState &plane : comp_planes) {
97     if (plane.GetCompositionState() == DisplayPlaneState::State::kScanout) {
98       dedicated_layers.insert(dedicated_layers.end(),
99                               plane.source_layers().begin(),
100                               plane.source_layers().end());
101     } else if (plane.GetCompositionState() ==
102                DisplayPlaneState::State::kRender) {
103       comp = &plane;
104       std::vector<CompositionRegion> comp_regions;
105       SeparateLayers(dedicated_layers, comp->source_layers(), display_frame,
106                      comp_regions);
107       std::vector<size_t>().swap(dedicated_layers);
108       if (comp_regions.empty())
109         continue;
110
111       if (!PrepareForComposition(plane)) {
112         ETRACE("Failed to initialize resources for composition");
113         return false;
114       }
115
116       if (!Render(layers, plane.GetOffScreenTarget(), comp_regions)) {
117         ETRACE("Failed to Render layer.");
118         return false;
119       }
120     }
121   }
122
123   return true;
124 }
125
126 bool Compositor::DrawOffscreen(std::vector<OverlayLayer> &layers,
127                                const std::vector<HwcRect<int>> &display_frame,
128                                const std::vector<size_t> &source_layers,
129                                HWCNativeHandle output_handle,
130                                int32_t *retire_fence) {
131   ScopedRendererState state(renderer_.get());
132   if (!state.IsValid()) {
133     ETRACE("Failed to draw as Renderer doesnt have a valid context.");
134     return false;
135   }
136
137   if (!gpu_resource_handler_->PrepareResources(layers)) {
138     ETRACE(
139         "Failed to prepare GPU resources for compositing the frame, "
140         "error: %s",
141         PRINTERROR());
142     return false;
143   }
144
145   std::vector<CompositionRegion> comp_regions;
146   SeparateLayers(std::vector<size_t>(), source_layers, display_frame,
147                  comp_regions);
148   if (comp_regions.empty()) {
149     ETRACE(
150         "Failed to prepare offscreen buffer. "
151         "error: %s",
152         PRINTERROR());
153     return false;
154   }
155
156   std::unique_ptr<NativeSurface> surface(CreateBackBuffer(width_, height_));
157   surface->InitializeForOffScreenRendering(buffer_handler_, output_handle);
158
159   if (!Render(layers, surface.get(), comp_regions))
160     return false;
161
162   *retire_fence = surface->ReleaseNativeFence();
163
164   return true;
165 }
166
167 void Compositor::EndFrame(bool commit_passed) {
168   if (commit_passed) {
169     for (auto &fb : surfaces_) {
170       fb->SetInUse(false);
171     }
172
173     for (auto fb : in_flight_surfaces_) {
174       fb->SetInUse(true);
175     }
176   }
177 }
178
179 void Compositor::InsertFence(int fence) {
180   renderer_->InsertFence(fence);
181 }
182
183 bool Compositor::PrepareForComposition(DisplayPlaneState &plane) {
184   NativeSurface *surface = NULL;
185   for (auto &fb : surfaces_) {
186     if (!fb->InUse()) {
187       surface = fb.get();
188       break;
189     }
190   }
191
192   if (!surface) {
193     NativeSurface *new_surface = CreateBackBuffer(width_, height_);
194     new_surface->Init(buffer_handler_);
195     surfaces_.emplace_back(std::move(new_surface));
196     surface = surfaces_.back().get();
197   }
198
199   surface->SetPlaneTarget(plane, gpu_fd_);
200   plane.SetOffScreenTarget(surface);
201   in_flight_surfaces_.emplace_back(surface);
202   return true;
203 }
204
205 bool Compositor::Render(std::vector<OverlayLayer> &layers,
206                         NativeSurface *surface,
207                         const std::vector<CompositionRegion> &comp_regions) {
208   std::vector<RenderState> states;
209   size_t num_regions = comp_regions.size();
210   states.reserve(num_regions);
211
212   for (size_t region_index = 0; region_index < num_regions; region_index++) {
213     const CompositionRegion &region = comp_regions.at(region_index);
214     RenderState state;
215     state.ConstructState(layers, region, gpu_resource_handler_.get());
216     auto it = states.begin();
217     for (; it != states.end(); ++it) {
218       if (state.layer_state_.size() > it->layer_state_.size())
219         break;
220     }
221
222     states.emplace(it, state);
223   }
224
225   if (!renderer_->Draw(states, surface))
226     return false;
227
228   surface->GetLayer()->SetAcquireFence(surface->ReleaseNativeFence());
229   return true;
230 }
231
232 // Below code is taken from drm_hwcomposer adopted to our needs.
233 static std::vector<size_t> SetBitsToVector(
234     uint64_t in, const std::vector<size_t> &index_map) {
235   std::vector<size_t> out;
236   size_t msb = sizeof(in) * 8 - 1;
237   uint64_t mask = (uint64_t)1 << msb;
238   for (size_t i = msb; mask != (uint64_t)0; i--, mask >>= 1)
239     if (in & mask)
240       out.emplace_back(index_map[i]);
241   return out;
242 }
243
244 void Compositor::SeparateLayers(const std::vector<size_t> &dedicated_layers,
245                                 const std::vector<size_t> &source_layers,
246                                 const std::vector<HwcRect<int>> &display_frame,
247                                 std::vector<CompositionRegion> &comp_regions) {
248   if (source_layers.size() > 64) {
249     ETRACE("Failed to separate layers because there are more than 64");
250     return;
251   }
252
253   size_t num_exclude_rects = 0;
254   // Index at which the actual layers begin
255   size_t layer_offset = dedicated_layers.size();
256   if (source_layers.size() + layer_offset > 64) {
257     WTRACE(
258         "Exclusion rectangles are being truncated to make the rectangle count "
259         "fit into 64");
260     num_exclude_rects = 64 - source_layers.size() - dedicated_layers.size();
261   }
262
263   // We inject all the exclude rects into the rects list. Any resulting rect
264   // that includes ANY of the first num_exclude_rects is rejected. After the
265   // exclude rects, we add the lower layers. The rects that intersect with
266   // these layers will be inspected and only those which are to be composited
267   // above the layer will be included in the composition regions.
268   std::vector<HwcRect<int>> layer_rects(source_layers.size() + layer_offset);
269   std::transform(
270       dedicated_layers.begin(), dedicated_layers.end(),
271       layer_rects.begin() + num_exclude_rects,
272       [=](size_t layer_index) { return display_frame[layer_index]; });
273   std::transform(source_layers.begin(), source_layers.end(),
274                  layer_rects.begin() + layer_offset, [=](size_t layer_index) {
275     return display_frame[layer_index];
276   });
277
278   std::vector<RectSet<int>> separate_regions;
279   get_draw_regions(layer_rects, &separate_regions);
280   uint64_t exclude_mask = ((uint64_t)1 << num_exclude_rects) - 1;
281   uint64_t dedicated_mask = (((uint64_t)1 << dedicated_layers.size()) - 1)
282                             << num_exclude_rects;
283
284   for (RectSet<int> &region : separate_regions) {
285     if (region.id_set.getBits() & exclude_mask)
286       continue;
287
288     // If a rect intersects one of the dedicated layers, we need to remove the
289     // layers from the composition region which appear *below* the dedicated
290     // layer. This effectively punches a hole through the composition layer such
291     // that the dedicated layer can be placed below the composition and not
292     // be occluded.
293     uint64_t dedicated_intersect = region.id_set.getBits() & dedicated_mask;
294     for (size_t i = 0; dedicated_intersect && i < dedicated_layers.size();
295          ++i) {
296       // Only exclude layers if they intersect this particular dedicated layer
297       if (!(dedicated_intersect & (1 << (i + num_exclude_rects))))
298         continue;
299
300       for (size_t j = 0; j < source_layers.size(); ++j) {
301         if (source_layers[j] < dedicated_layers[i])
302           region.id_set.subtract(j + layer_offset);
303       }
304     }
305     if (!(region.id_set.getBits() >> layer_offset))
306       continue;
307
308     comp_regions.emplace_back(CompositionRegion{
309         region.rect, SetBitsToVector(region.id_set.getBits() >> layer_offset,
310                                      source_layers)});
311   }
312 }
313 }