• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) Texas Instruments Incorporated - http://www.ti.com/
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 <algorithm>
18 
19 #include <cstdint>
20 
21 #include <log/log.h>
22 #include <cutils/properties.h>
23 
24 #include "display.h"
25 #include "format.h"
26 #include "hwc_dev.h"
27 
HWCDisplay(enum disp_role role)28 HWCDisplay::HWCDisplay(enum disp_role role) :
29     active_config(0),
30     role(role),
31     cb_procs(NULL),
32     is_dummy(false),
33     vsync_on(false),
34     blanked(true),
35     is_flip_pending(false)
36 {
37 }
38 
setup_composition_pipes()39 void HWCDisplay::setup_composition_pipes()
40 {
41     std::unique_lock<std::mutex> lock(this->mutex);
42 
43     KMSDisplay* kdisp = &this->disp_link;
44 
45     int count = 0;
46     for (auto plane : kdisp->card->get_planes()) {
47         auto possible_crtcs = plane->get_possible_crtcs();
48         if (std::find(possible_crtcs.begin(), possible_crtcs.end(), kdisp->crtc) != possible_crtcs.end()) {
49             planeProps[count].plane = plane;
50             ALOGI("Overlay %d: plane_id: %d", count, planeProps[count].plane->id());
51             count++;
52         }
53     }
54 }
55 
56 /* Page flip handler callback */
page_flip_handler(int fd,unsigned int frame,unsigned int sec,unsigned int usec,void * data)57 void HWCDisplay::page_flip_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec, void* data)
58 {
59     HWCDisplay* display = static_cast<HWCDisplay*>(data);
60 
61     std::unique_lock<std::mutex> lock(display->mutex);
62 
63     if (display->is_flip_pending == false) {
64         ALOGW("Spurious page flip?");
65         return;
66     }
67 
68     /* release the old buffers */
69     for (auto current_fb_info : display->current_fb_infos)
70         delete current_fb_info;
71     display->current_fb_infos.clear();
72 
73     /* pending are now current */
74     for (auto pending_fb_info : display->pending_fb_infos)
75         display->current_fb_infos.push_back(pending_fb_info);
76     display->pending_fb_infos.clear();
77 
78     display->is_flip_pending = false;
79     lock.unlock();
80     display->cond_flip.notify_one();
81 }
82 
vblank_kick(HWCDisplay * display)83 static int vblank_kick(HWCDisplay* display)
84 {
85     drmVBlank vblank;
86     memset(&vblank, 0, sizeof(vblank));
87     vblank.request.type = (drmVBlankSeqType)(DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT |
88                 display->role == DISP_ROLE_SECONDARY ? DRM_VBLANK_SECONDARY : 0);
89     vblank.request.sequence = 1;
90     vblank.request.signal = (unsigned long)display;
91     int err = drmWaitVBlank(display->disp_link.card->fd(), &vblank);
92     if (err < 0) {
93         /* FIXME: error in drmWaitVBlank() use SW vsync instead? */
94         ALOGE("drmWaitVBlank error %d (%s)", err, strerror(errno));
95         return -1;
96     }
97 
98     return 0;
99 }
100 
101 /* Callback function that gets triggered on vsync */
vblank_handler(int fd,unsigned int frame,unsigned int sec,unsigned int usec,void * data)102 void HWCDisplay::vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec, void* data)
103 {
104     HWCDisplay* display = static_cast<HWCDisplay*>(data);
105 
106     std::unique_lock<std::mutex> lock(display->mutex);
107 
108     if (display->vsync_on) {
109         int64_t ts = sec * (int64_t)1000000000 + usec * (int64_t)1000;
110 
111 //        ALOGD("Sending VBLANK at %lld for display %d", ts, display->role);
112         display->cb_procs->vsync(display->cb_procs, display->role, ts);
113 
114         vblank_kick(display);
115     }
116 }
117 
set_vsync_state(bool state)118 int HWCDisplay::set_vsync_state(bool state)
119 {
120     std::unique_lock<std::mutex> lock(this->mutex);
121 
122     if (this->is_dummy)
123         return 0;
124 
125     this->vsync_on = state;
126 
127     if (this->vsync_on)
128         return vblank_kick(this);
129 
130     return 0;
131 }
132 
set_plane_properties(kms::AtomicReq & req,drm_plane_props_t * plane_props)133 static void set_plane_properties(kms::AtomicReq& req, drm_plane_props_t* plane_props)
134 {
135     kms::Plane* plane = plane_props->plane;
136 
137     req.add(plane, "FB_ID", plane_props->fb_info->fb_id);
138 
139     req.add(plane, "IN_FENCE_FD", plane_props->layer->acquireFenceFd);
140 
141     req.add(plane, {
142             { "CRTC_ID", plane_props->crtc_id },
143             { "SRC_X", (plane_props->src_x) << 16 },
144             { "SRC_Y", (plane_props->src_y) << 16 },
145             { "SRC_W", (plane_props->src_w) << 16 },
146             { "SRC_H", (plane_props->src_h) << 16 },
147             { "CRTC_X", plane_props->crtc_x },
148             { "CRTC_Y", plane_props->crtc_y },
149             { "CRTC_W", plane_props->crtc_w },
150             { "CRTC_H", plane_props->crtc_h },
151     });
152 
153     /* optional props */
154     req.add(plane, {
155             { "zorder", plane_props->zorder },
156             { "pre_mult_alpha", plane_props->pre_mult_alpha },
157     });
158 }
159 
update_display(drm_plane_props_t * planeProp)160 int HWCDisplay::update_display(drm_plane_props_t* planeProp)
161 {
162     std::unique_lock<std::mutex> lock(this->mutex);
163 
164     this->cond_flip.wait(lock, [this]{return !this->is_flip_pending;});
165 
166     buffer_handle_t handle = planeProp->layer->handle;
167     if (!handle) {
168         ALOGW("Got empty handle, nothing to display");
169         return 0;
170     }
171 
172     KMSDisplay* kdisp = &this->disp_link;
173 
174     planeProp->fb_info = new DRMFramebuffer(kdisp->card->fd(), handle, false);
175     this->pending_fb_infos.push_back(planeProp->fb_info);
176 
177     planeProp->crtc_id = kdisp->crtc->id();
178 
179     // Atomic display update
180     kms::AtomicReq req(*kdisp->card);
181     set_plane_properties(req, planeProp);
182     int ret = req.commit(this, true);
183     if (ret) {
184         ALOGE("cannot do atomic commit/page flip: %d (%s)", ret, strerror(errno));
185         for (auto pending_fb_info : this->pending_fb_infos)
186             delete pending_fb_info;
187         this->pending_fb_infos.clear();
188         return ret;
189     }
190 
191 //    ALOGD("Scheduled page flip on display %d", this->role);
192     this->is_flip_pending = true;
193 
194     return 0;
195 }
196 
blank(int blank)197 void HWCDisplay::blank(int blank)
198 {
199     std::unique_lock<std::mutex> lock(this->mutex);
200 
201     if (this->is_dummy)
202         return;
203 
204     KMSDisplay* kdisp = &this->disp_link;
205 
206     ALOGI("Linking connector %d to crtc %d", kdisp->con->id(), kdisp->crtc->id());
207 
208     int ret = kdisp->crtc->set_mode(kdisp->con, kdisp->mode);
209     if (ret) {
210         ALOGE("Failed to set crtc mode (%s)", strerror(-ret));
211         return;
212     }
213 
214     // FIXME: This should actually blank the screen
215     this->blanked = blank;
216 }
217 
get_display_configs(uint32_t * configs,size_t * numConfigs)218 int HWCDisplay::get_display_configs(uint32_t* configs, size_t* numConfigs)
219 {
220     if (!configs || !numConfigs)
221         return -EINVAL;
222 
223     if (*numConfigs == 0)
224         return 0;
225 
226     std::unique_lock<std::mutex> lock(this->mutex);
227 
228     size_t num = this->configs.size();
229     if (num > *numConfigs)
230         num = *numConfigs;
231 
232     for (size_t i = 0; i < num; i++)
233         configs[i] = i;
234 
235     *numConfigs = num;
236 
237     return 0;
238 }
239 
get_display_attributes(uint32_t cfg,const uint32_t * attributes,int32_t * values)240 int HWCDisplay::get_display_attributes(uint32_t cfg, const uint32_t* attributes, int32_t* values)
241 {
242     if (!attributes || !values)
243         return 0;
244 
245     std::unique_lock<std::mutex> lock(this->mutex);
246 
247     if (cfg >= this->configs.size())
248         return -EINVAL;
249 
250     display_config_t* config = &this->configs[cfg];
251 
252     for (size_t i = 0; attributes[i] != HWC_DISPLAY_NO_ATTRIBUTE; i++) {
253         switch (attributes[i]) {
254         case HWC_DISPLAY_VSYNC_PERIOD:
255             values[i] = 1000000000 / config->fps;
256             break;
257         case HWC_DISPLAY_WIDTH:
258             values[i] = config->xres;
259             break;
260         case HWC_DISPLAY_HEIGHT:
261             values[i] = config->yres;
262             break;
263         case HWC_DISPLAY_DPI_X:
264             values[i] = 1000 * config->xdpi;
265             break;
266         case HWC_DISPLAY_DPI_Y:
267             values[i] = 1000 * config->ydpi;
268             break;
269         }
270     }
271 
272     return 0;
273 }
274