1 // Copyright 2014 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "ui/ozone/platform/dri/dri_wrapper.h" 6 7 #include <fcntl.h> 8 #include <sys/mman.h> 9 #include <unistd.h> 10 #include <xf86drm.h> 11 #include <xf86drmMode.h> 12 13 #include "base/debug/trace_event.h" 14 #include "base/logging.h" 15 #include "base/stl_util.h" 16 #include "third_party/skia/include/core/SkImageInfo.h" 17 #include "ui/ozone/platform/dri/dri_util.h" 18 19 namespace ui { 20 21 namespace { 22 23 uint32_t ToFixedPoint(double v) { 24 // This returns a number in a 16-bit.16-bit fixed point. 25 return v * 65536.0; 26 } 27 28 bool DrmCreateDumbBuffer(int fd, 29 const SkImageInfo& info, 30 uint32_t* handle, 31 uint32_t* stride) { 32 struct drm_mode_create_dumb request; 33 memset(&request, 0, sizeof(request)); 34 request.width = info.width(); 35 request.height = info.height(); 36 request.bpp = info.bytesPerPixel() << 3; 37 request.flags = 0; 38 39 if (drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &request) < 0) { 40 VLOG(2) << "Cannot create dumb buffer (" << errno << ") " 41 << strerror(errno); 42 return false; 43 } 44 45 // The driver may choose to align the last row as well. We don't care about 46 // the last alignment bits since they aren't used for display purposes, so 47 // just check that the expected size is <= to what the driver allocated. 48 DCHECK_LE(info.getSafeSize(request.pitch), request.size); 49 50 *handle = request.handle; 51 *stride = request.pitch; 52 return true; 53 } 54 55 void DrmDestroyDumbBuffer(int fd, uint32_t handle) { 56 struct drm_mode_destroy_dumb destroy_request; 57 memset(&destroy_request, 0, sizeof(destroy_request)); 58 destroy_request.handle = handle; 59 drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_request); 60 } 61 62 } // namespace 63 64 DriWrapper::DriWrapper(const char* device_path) 65 : fd_(-1), device_path_(device_path) { 66 } 67 68 DriWrapper::~DriWrapper() { 69 if (fd_ >= 0) 70 close(fd_); 71 } 72 73 void DriWrapper::Initialize() { 74 fd_ = open(device_path_, O_RDWR | O_CLOEXEC); 75 if (fd_ < 0) 76 PLOG(FATAL) << "open: " << device_path_; 77 } 78 79 ScopedDrmCrtcPtr DriWrapper::GetCrtc(uint32_t crtc_id) { 80 DCHECK(fd_ >= 0); 81 return ScopedDrmCrtcPtr(drmModeGetCrtc(fd_, crtc_id)); 82 } 83 84 bool DriWrapper::SetCrtc(uint32_t crtc_id, 85 uint32_t framebuffer, 86 std::vector<uint32_t> connectors, 87 drmModeModeInfo* mode) { 88 DCHECK(fd_ >= 0); 89 DCHECK(!connectors.empty()); 90 DCHECK(mode); 91 92 TRACE_EVENT2("dri", 93 "DriWrapper::SetCrtc", 94 "crtc", 95 crtc_id, 96 "size", 97 gfx::Size(mode->hdisplay, mode->vdisplay).ToString()); 98 return !drmModeSetCrtc(fd_, 99 crtc_id, 100 framebuffer, 101 0, 102 0, 103 vector_as_array(&connectors), 104 connectors.size(), mode); 105 } 106 107 bool DriWrapper::SetCrtc(drmModeCrtc* crtc, std::vector<uint32_t> connectors) { 108 DCHECK(fd_ >= 0); 109 // If there's no buffer then the CRTC was disabled. 110 if (!crtc->buffer_id) 111 return DisableCrtc(crtc->crtc_id); 112 113 DCHECK(!connectors.empty()); 114 115 TRACE_EVENT1("dri", "DriWrapper::RestoreCrtc", 116 "crtc", crtc->crtc_id); 117 return !drmModeSetCrtc(fd_, 118 crtc->crtc_id, 119 crtc->buffer_id, 120 crtc->x, 121 crtc->y, 122 vector_as_array(&connectors), 123 connectors.size(), 124 &crtc->mode); 125 } 126 127 bool DriWrapper::DisableCrtc(uint32_t crtc_id) { 128 DCHECK(fd_ >= 0); 129 TRACE_EVENT1("dri", "DriWrapper::DisableCrtc", 130 "crtc", crtc_id); 131 return !drmModeSetCrtc(fd_, crtc_id, 0, 0, 0, NULL, 0, NULL); 132 } 133 134 ScopedDrmConnectorPtr DriWrapper::GetConnector(uint32_t connector_id) { 135 DCHECK(fd_ >= 0); 136 TRACE_EVENT1("dri", "DriWrapper::GetConnector", "connector", connector_id); 137 return ScopedDrmConnectorPtr(drmModeGetConnector(fd_, connector_id)); 138 } 139 140 bool DriWrapper::AddFramebuffer(uint32_t width, 141 uint32_t height, 142 uint8_t depth, 143 uint8_t bpp, 144 uint32_t stride, 145 uint32_t handle, 146 uint32_t* framebuffer) { 147 DCHECK(fd_ >= 0); 148 TRACE_EVENT1("dri", "DriWrapper::AddFramebuffer", 149 "handle", handle); 150 return !drmModeAddFB(fd_, 151 width, 152 height, 153 depth, 154 bpp, 155 stride, 156 handle, 157 framebuffer); 158 } 159 160 bool DriWrapper::RemoveFramebuffer(uint32_t framebuffer) { 161 DCHECK(fd_ >= 0); 162 TRACE_EVENT1("dri", "DriWrapper::RemoveFramebuffer", 163 "framebuffer", framebuffer); 164 return !drmModeRmFB(fd_, framebuffer); 165 } 166 167 bool DriWrapper::PageFlip(uint32_t crtc_id, 168 uint32_t framebuffer, 169 void* data) { 170 DCHECK(fd_ >= 0); 171 TRACE_EVENT2("dri", "DriWrapper::PageFlip", 172 "crtc", crtc_id, 173 "framebuffer", framebuffer); 174 return !drmModePageFlip(fd_, 175 crtc_id, 176 framebuffer, 177 DRM_MODE_PAGE_FLIP_EVENT, 178 data); 179 } 180 181 bool DriWrapper::PageFlipOverlay(uint32_t crtc_id, 182 uint32_t framebuffer, 183 const gfx::Rect& location, 184 const gfx::RectF& source, 185 int overlay_plane) { 186 DCHECK(fd_ >= 0); 187 TRACE_EVENT2("dri", "DriWrapper::PageFlipOverlay", 188 "crtc", crtc_id, 189 "framebuffer", framebuffer); 190 return !drmModeSetPlane(fd_, 191 overlay_plane, 192 crtc_id, 193 framebuffer, 194 0, 195 location.x(), 196 location.y(), 197 location.width(), 198 location.height(), 199 ToFixedPoint(source.x()), 200 ToFixedPoint(source.y()), 201 ToFixedPoint(source.width()), 202 ToFixedPoint(source.height())); 203 } 204 205 ScopedDrmFramebufferPtr DriWrapper::GetFramebuffer(uint32_t framebuffer) { 206 DCHECK(fd_ >= 0); 207 TRACE_EVENT1("dri", "DriWrapper::GetFramebuffer", 208 "framebuffer", framebuffer); 209 return ScopedDrmFramebufferPtr(drmModeGetFB(fd_, framebuffer)); 210 } 211 212 ScopedDrmPropertyPtr DriWrapper::GetProperty(drmModeConnector* connector, 213 const char* name) { 214 TRACE_EVENT2("dri", "DriWrapper::GetProperty", 215 "connector", connector->connector_id, 216 "name", name); 217 for (int i = 0; i < connector->count_props; ++i) { 218 ScopedDrmPropertyPtr property(drmModeGetProperty(fd_, connector->props[i])); 219 if (!property) 220 continue; 221 222 if (strcmp(property->name, name) == 0) 223 return property.Pass(); 224 } 225 226 return ScopedDrmPropertyPtr(); 227 } 228 229 bool DriWrapper::SetProperty(uint32_t connector_id, 230 uint32_t property_id, 231 uint64_t value) { 232 DCHECK(fd_ >= 0); 233 return !drmModeConnectorSetProperty(fd_, connector_id, property_id, value); 234 } 235 236 ScopedDrmPropertyBlobPtr DriWrapper::GetPropertyBlob( 237 drmModeConnector* connector, const char* name) { 238 DCHECK(fd_ >= 0); 239 TRACE_EVENT2("dri", "DriWrapper::GetPropertyBlob", 240 "connector", connector->connector_id, 241 "name", name); 242 for (int i = 0; i < connector->count_props; ++i) { 243 ScopedDrmPropertyPtr property(drmModeGetProperty(fd_, connector->props[i])); 244 if (!property) 245 continue; 246 247 if (strcmp(property->name, name) == 0 && 248 property->flags & DRM_MODE_PROP_BLOB) 249 return ScopedDrmPropertyBlobPtr( 250 drmModeGetPropertyBlob(fd_, connector->prop_values[i])); 251 } 252 253 return ScopedDrmPropertyBlobPtr(); 254 } 255 256 bool DriWrapper::SetCursor(uint32_t crtc_id, 257 uint32_t handle, 258 const gfx::Size& size) { 259 DCHECK(fd_ >= 0); 260 TRACE_EVENT1("dri", "DriWrapper::SetCursor", "handle", handle); 261 return !drmModeSetCursor(fd_, crtc_id, handle, size.width(), size.height()); 262 } 263 264 bool DriWrapper::MoveCursor(uint32_t crtc_id, const gfx::Point& point) { 265 DCHECK(fd_ >= 0); 266 return !drmModeMoveCursor(fd_, crtc_id, point.x(), point.y()); 267 } 268 269 void DriWrapper::HandleEvent(drmEventContext& event) { 270 DCHECK(fd_ >= 0); 271 TRACE_EVENT0("dri", "DriWrapper::HandleEvent"); 272 drmHandleEvent(fd_, &event); 273 } 274 275 bool DriWrapper::CreateDumbBuffer(const SkImageInfo& info, 276 uint32_t* handle, 277 uint32_t* stride, 278 void** pixels) { 279 DCHECK(fd_ >= 0); 280 281 TRACE_EVENT0("dri", "DriWrapper::CreateDumbBuffer"); 282 if (!DrmCreateDumbBuffer(fd_, info, handle, stride)) 283 return false; 284 285 if (!MapDumbBuffer(fd_, *handle, info.getSafeSize(*stride), pixels)) { 286 DrmDestroyDumbBuffer(fd_, *handle); 287 return false; 288 } 289 290 return true; 291 } 292 293 void DriWrapper::DestroyDumbBuffer(const SkImageInfo& info, 294 uint32_t handle, 295 uint32_t stride, 296 void* pixels) { 297 DCHECK(fd_ >= 0); 298 TRACE_EVENT1("dri", "DriWrapper::DestroyDumbBuffer", "handle", handle); 299 munmap(pixels, info.getSafeSize(stride)); 300 DrmDestroyDumbBuffer(fd_, handle); 301 } 302 303 304 } // namespace ui 305