• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
18 #define LOG_TAG "hwc-platform-drm-generic"
19 
20 #include "DrmFbImporter.h"
21 
22 #include <hardware/gralloc.h>
23 #include <xf86drm.h>
24 #include <xf86drmMode.h>
25 
26 #include <cinttypes>
27 #include <system_error>
28 
29 #include "utils/log.h"
30 #include "utils/properties.h"
31 
32 namespace android {
33 
CreateInstance(hwc_drm_bo_t * bo,GemHandle first_gem_handle,DrmDevice & drm)34 auto DrmFbIdHandle::CreateInstance(hwc_drm_bo_t *bo, GemHandle first_gem_handle,
35                                    DrmDevice &drm)
36     -> std::shared_ptr<DrmFbIdHandle> {
37   // NOLINTNEXTLINE(cppcoreguidelines-owning-memory): priv. constructor usage
38   std::shared_ptr<DrmFbIdHandle> local(new DrmFbIdHandle(drm));
39 
40   local->gem_handles_[0] = first_gem_handle;
41   int32_t err = 0;
42 
43   /* Framebuffer object creation require gem handle for every used plane */
44   for (size_t i = 1; i < local->gem_handles_.size(); i++) {
45     if (bo->prime_fds[i] > 0) {
46       if (bo->prime_fds[i] != bo->prime_fds[0]) {
47         err = drmPrimeFDToHandle(drm.GetFd(), bo->prime_fds[i],
48                                  &local->gem_handles_.at(i));
49         if (err != 0) {
50           ALOGE("failed to import prime fd %d errno=%d", bo->prime_fds[i],
51                 errno);
52         }
53       } else {
54         local->gem_handles_.at(i) = local->gem_handles_[0];
55       }
56     }
57   }
58 
59   bool has_modifiers = bo->modifiers[0] != DRM_FORMAT_MOD_NONE &&
60                        bo->modifiers[0] != DRM_FORMAT_MOD_INVALID;
61 
62   if (!drm.HasAddFb2ModifiersSupport() && has_modifiers) {
63     ALOGE("No ADDFB2 with modifier support. Can't import modifier %" PRIu64,
64           bo->modifiers[0]);
65     local.reset();
66     return local;
67   }
68 
69   /* Create framebuffer object */
70   if (!has_modifiers) {
71     err = drmModeAddFB2(drm.GetFd(), bo->width, bo->height, bo->format,
72                         &local->gem_handles_[0], &bo->pitches[0],
73                         &bo->offsets[0], &local->fb_id_, 0);
74   } else {
75     err = drmModeAddFB2WithModifiers(drm.GetFd(), bo->width, bo->height,
76                                      bo->format, &local->gem_handles_[0],
77                                      &bo->pitches[0], &bo->offsets[0],
78                                      &bo->modifiers[0], &local->fb_id_,
79                                      DRM_MODE_FB_MODIFIERS);
80   }
81   if (err != 0) {
82     ALOGE("could not create drm fb %d", err);
83     local.reset();
84   }
85 
86   return local;
87 }
88 
~DrmFbIdHandle()89 DrmFbIdHandle::~DrmFbIdHandle() {
90   /* Destroy framebuffer object */
91   if (drmModeRmFB(drm_->GetFd(), fb_id_) != 0) {
92     ALOGE("Failed to rm fb");
93   }
94 
95   /* Close GEM handles.
96    *
97    * WARNING: TODO(nobody):
98    * From Linux side libweston relies on libgbm to get KMS handle and never
99    * closes it (handle is closed by libgbm on buffer destruction)
100    * Probably we should offer similar approach to users (at least on user
101    * request via system properties)
102    */
103   struct drm_gem_close gem_close {};
104   for (size_t i = 0; i < gem_handles_.size(); i++) {
105     /* Don't close invalid handle. Close handle only once in cases
106      * where several YUV planes located in the single buffer. */
107     if (gem_handles_[i] == 0 ||
108         (i != 0 && gem_handles_[i] == gem_handles_[0])) {
109       continue;
110     }
111     gem_close.handle = gem_handles_[i];
112     int32_t err = drmIoctl(drm_->GetFd(), DRM_IOCTL_GEM_CLOSE, &gem_close);
113     if (err != 0) {
114       ALOGE("Failed to close gem handle %d, errno: %d", gem_handles_[i], errno);
115     }
116   }
117 }
118 
GetOrCreateFbId(hwc_drm_bo_t * bo)119 auto DrmFbImporter::GetOrCreateFbId(hwc_drm_bo_t *bo)
120     -> std::shared_ptr<DrmFbIdHandle> {
121   /* Lookup DrmFbIdHandle in cache first. First handle serves as a cache key. */
122   GemHandle first_handle = 0;
123   int32_t err = drmPrimeFDToHandle(drm_->GetFd(), bo->prime_fds[0],
124                                    &first_handle);
125 
126   if (err != 0) {
127     ALOGE("Failed to import prime fd %d ret=%d", bo->prime_fds[0], err);
128     return {};
129   }
130 
131   auto drm_fb_id_cached = drm_fb_id_handle_cache_.find(first_handle);
132 
133   if (drm_fb_id_cached != drm_fb_id_handle_cache_.end()) {
134     if (auto drm_fb_id_handle_shared = drm_fb_id_cached->second.lock()) {
135       return drm_fb_id_handle_shared;
136     }
137     drm_fb_id_handle_cache_.erase(drm_fb_id_cached);
138   }
139 
140   /* Cleanup cached empty weak pointers */
141   const int minimal_cleanup_size = 128;
142   if (drm_fb_id_handle_cache_.size() > minimal_cleanup_size) {
143     CleanupEmptyCacheElements();
144   }
145 
146   /* No DrmFbIdHandle found in cache, create framebuffer object */
147   auto fb_id_handle = DrmFbIdHandle::CreateInstance(bo, first_handle, *drm_);
148   if (fb_id_handle) {
149     drm_fb_id_handle_cache_[first_handle] = fb_id_handle;
150   }
151 
152   return fb_id_handle;
153 }
154 
155 }  // namespace android
156