2 // Copyright (c) 2016 Intel Corporation
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
8 // http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include "compositor.h"
19 #include <xf86drmMode.h>
21 #include "disjoint_layers.h"
22 #include "displayplanestate.h"
24 #include "nativegpuresource.h"
25 #include "nativesurface.h"
26 #include "nativesync.h"
27 #include "overlaylayer.h"
29 #include "renderstate.h"
30 #include "scopedrendererstate.h"
32 namespace hwcomposer {
34 Compositor::Compositor() {
37 Compositor::~Compositor() {
40 void Compositor::Init(NativeBufferHandler *buffer_handler, uint32_t width,
41 uint32_t height, uint32_t gpu_fd) {
42 buffer_handler_ = buffer_handler;
44 if (!surfaces_.empty()) {
45 if (width == surfaces_.back()->GetWidth() ||
46 height == surfaces_.back()->GetHeight())
49 for (auto i = surfaces_.begin(); i != surfaces_.end();) {
51 i = surfaces_.erase(i);
55 gpu_resource_handler_.reset(CreateNativeGpuResourceHandler());
61 bool Compositor::BeginFrame() {
63 renderer_.reset(CreateRenderer());
64 if (!renderer_->Init()) {
65 ETRACE("Failed to initialize OpenGL compositor %s", PRINTERROR());
66 renderer_.reset(nullptr);
71 if (!in_flight_surfaces_.empty())
72 std::vector<NativeSurface *>().swap(in_flight_surfaces_);
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.");
88 if (!gpu_resource_handler_->PrepareResources(layers)) {
90 "Failed to prepare GPU resources for compositing the frame, "
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) {
104 std::vector<CompositionRegion> comp_regions;
105 SeparateLayers(dedicated_layers, comp->source_layers(), display_frame,
107 std::vector<size_t>().swap(dedicated_layers);
108 if (comp_regions.empty())
111 if (!PrepareForComposition(plane)) {
112 ETRACE("Failed to initialize resources for composition");
116 if (!Render(layers, plane.GetOffScreenTarget(), comp_regions)) {
117 ETRACE("Failed to Render layer.");
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.");
137 if (!gpu_resource_handler_->PrepareResources(layers)) {
139 "Failed to prepare GPU resources for compositing the frame, "
145 std::vector<CompositionRegion> comp_regions;
146 SeparateLayers(std::vector<size_t>(), source_layers, display_frame,
148 if (comp_regions.empty()) {
150 "Failed to prepare offscreen buffer. "
156 std::unique_ptr<NativeSurface> surface(CreateBackBuffer(width_, height_));
157 surface->InitializeForOffScreenRendering(buffer_handler_, output_handle);
159 if (!Render(layers, surface.get(), comp_regions))
162 *retire_fence = surface->ReleaseNativeFence();
167 void Compositor::EndFrame(bool commit_passed) {
169 for (auto &fb : surfaces_) {
173 for (auto fb : in_flight_surfaces_) {
179 void Compositor::InsertFence(int fence) {
180 renderer_->InsertFence(fence);
183 bool Compositor::PrepareForComposition(DisplayPlaneState &plane) {
184 NativeSurface *surface = NULL;
185 for (auto &fb : surfaces_) {
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();
199 surface->SetPlaneTarget(plane, gpu_fd_);
200 plane.SetOffScreenTarget(surface);
201 in_flight_surfaces_.emplace_back(surface);
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);
212 for (size_t region_index = 0; region_index < num_regions; region_index++) {
213 const CompositionRegion ®ion = comp_regions.at(region_index);
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())
222 states.emplace(it, state);
225 if (!renderer_->Draw(states, surface))
228 surface->GetLayer()->SetAcquireFence(surface->ReleaseNativeFence());
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)
240 out.emplace_back(index_map[i]);
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");
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) {
258 "Exclusion rectangles are being truncated to make the rectangle count "
260 num_exclude_rects = 64 - source_layers.size() - dedicated_layers.size();
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);
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];
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;
284 for (RectSet<int> ®ion : separate_regions) {
285 if (region.id_set.getBits() & exclude_mask)
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
293 uint64_t dedicated_intersect = region.id_set.getBits() & dedicated_mask;
294 for (size_t i = 0; dedicated_intersect && i < dedicated_layers.size();
296 // Only exclude layers if they intersect this particular dedicated layer
297 if (!(dedicated_intersect & (1 << (i + num_exclude_rects))))
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);
305 if (!(region.id_set.getBits() >> layer_offset))
308 comp_regions.emplace_back(CompositionRegion{
309 region.rect, SetBitsToVector(region.id_set.getBits() >> layer_offset,