xref: /aosp_15_r20/external/drm_hwcomposer/drm/DrmFbImporter.cpp (revision 0a9764fe0a15e71ebbeb85e87e10990c23aab47f)
1*0a9764feSAndroid Build Coastguard Worker /*
2*0a9764feSAndroid Build Coastguard Worker  * Copyright (C) 2021 The Android Open Source Project
3*0a9764feSAndroid Build Coastguard Worker  *
4*0a9764feSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*0a9764feSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*0a9764feSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*0a9764feSAndroid Build Coastguard Worker  *
8*0a9764feSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*0a9764feSAndroid Build Coastguard Worker  *
10*0a9764feSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*0a9764feSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*0a9764feSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*0a9764feSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*0a9764feSAndroid Build Coastguard Worker  * limitations under the License.
15*0a9764feSAndroid Build Coastguard Worker  */
16*0a9764feSAndroid Build Coastguard Worker 
17*0a9764feSAndroid Build Coastguard Worker // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
18*0a9764feSAndroid Build Coastguard Worker #define ATRACE_TAG ATRACE_TAG_GRAPHICS
19*0a9764feSAndroid Build Coastguard Worker // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
20*0a9764feSAndroid Build Coastguard Worker #define LOG_TAG "drmhwc"
21*0a9764feSAndroid Build Coastguard Worker 
22*0a9764feSAndroid Build Coastguard Worker #include "DrmFbImporter.h"
23*0a9764feSAndroid Build Coastguard Worker 
24*0a9764feSAndroid Build Coastguard Worker #include <hardware/gralloc.h>
25*0a9764feSAndroid Build Coastguard Worker #include <utils/Trace.h>
26*0a9764feSAndroid Build Coastguard Worker #include <xf86drm.h>
27*0a9764feSAndroid Build Coastguard Worker #include <xf86drmMode.h>
28*0a9764feSAndroid Build Coastguard Worker 
29*0a9764feSAndroid Build Coastguard Worker #include <cinttypes>
30*0a9764feSAndroid Build Coastguard Worker #include <system_error>
31*0a9764feSAndroid Build Coastguard Worker 
32*0a9764feSAndroid Build Coastguard Worker #include "utils/log.h"
33*0a9764feSAndroid Build Coastguard Worker #include "utils/properties.h"
34*0a9764feSAndroid Build Coastguard Worker 
35*0a9764feSAndroid Build Coastguard Worker namespace android {
36*0a9764feSAndroid Build Coastguard Worker 
CreateInstance(BufferInfo * bo,GemHandle first_gem_handle,DrmDevice & drm)37*0a9764feSAndroid Build Coastguard Worker auto DrmFbIdHandle::CreateInstance(BufferInfo *bo, GemHandle first_gem_handle,
38*0a9764feSAndroid Build Coastguard Worker                                    DrmDevice &drm)
39*0a9764feSAndroid Build Coastguard Worker     -> std::shared_ptr<DrmFbIdHandle> {
40*0a9764feSAndroid Build Coastguard Worker   // NOLINTNEXTLINE(misc-const-correctness)
41*0a9764feSAndroid Build Coastguard Worker   ATRACE_NAME("Import dmabufs and register FB");
42*0a9764feSAndroid Build Coastguard Worker 
43*0a9764feSAndroid Build Coastguard Worker   // NOLINTNEXTLINE(cppcoreguidelines-owning-memory): priv. constructor usage
44*0a9764feSAndroid Build Coastguard Worker   std::shared_ptr<DrmFbIdHandle> local(new DrmFbIdHandle(drm));
45*0a9764feSAndroid Build Coastguard Worker 
46*0a9764feSAndroid Build Coastguard Worker   local->gem_handles_[0] = first_gem_handle;
47*0a9764feSAndroid Build Coastguard Worker   int32_t err = 0;
48*0a9764feSAndroid Build Coastguard Worker 
49*0a9764feSAndroid Build Coastguard Worker   /* Framebuffer object creation require gem handle for every used plane */
50*0a9764feSAndroid Build Coastguard Worker   for (size_t i = 1; i < local->gem_handles_.size(); i++) {
51*0a9764feSAndroid Build Coastguard Worker     if (bo->prime_fds[i] > 0) {
52*0a9764feSAndroid Build Coastguard Worker       if (bo->prime_fds[i] != bo->prime_fds[0]) {
53*0a9764feSAndroid Build Coastguard Worker         err = drmPrimeFDToHandle(*drm.GetFd(), bo->prime_fds[i],
54*0a9764feSAndroid Build Coastguard Worker                                  &local->gem_handles_.at(i));
55*0a9764feSAndroid Build Coastguard Worker         if (err != 0) {
56*0a9764feSAndroid Build Coastguard Worker           ALOGE("failed to import prime fd %d errno=%d", bo->prime_fds[i],
57*0a9764feSAndroid Build Coastguard Worker                 errno);
58*0a9764feSAndroid Build Coastguard Worker         }
59*0a9764feSAndroid Build Coastguard Worker       } else {
60*0a9764feSAndroid Build Coastguard Worker         local->gem_handles_.at(i) = local->gem_handles_[0];
61*0a9764feSAndroid Build Coastguard Worker       }
62*0a9764feSAndroid Build Coastguard Worker     }
63*0a9764feSAndroid Build Coastguard Worker   }
64*0a9764feSAndroid Build Coastguard Worker 
65*0a9764feSAndroid Build Coastguard Worker   auto has_modifiers = bo->modifiers[0] != DRM_FORMAT_MOD_NONE &&
66*0a9764feSAndroid Build Coastguard Worker                        bo->modifiers[0] != DRM_FORMAT_MOD_INVALID;
67*0a9764feSAndroid Build Coastguard Worker 
68*0a9764feSAndroid Build Coastguard Worker   if (!drm.HasAddFb2ModifiersSupport() && has_modifiers) {
69*0a9764feSAndroid Build Coastguard Worker     ALOGE("No ADDFB2 with modifier support. Can't import modifier %" PRIu64,
70*0a9764feSAndroid Build Coastguard Worker           bo->modifiers[0]);
71*0a9764feSAndroid Build Coastguard Worker     local.reset();
72*0a9764feSAndroid Build Coastguard Worker     return local;
73*0a9764feSAndroid Build Coastguard Worker   }
74*0a9764feSAndroid Build Coastguard Worker 
75*0a9764feSAndroid Build Coastguard Worker   /* Create framebuffer object */
76*0a9764feSAndroid Build Coastguard Worker   if (!has_modifiers) {
77*0a9764feSAndroid Build Coastguard Worker     err = drmModeAddFB2(*drm.GetFd(), bo->width, bo->height, bo->format,
78*0a9764feSAndroid Build Coastguard Worker                         local->gem_handles_.data(), &bo->pitches[0],
79*0a9764feSAndroid Build Coastguard Worker                         &bo->offsets[0], &local->fb_id_, 0);
80*0a9764feSAndroid Build Coastguard Worker   } else {
81*0a9764feSAndroid Build Coastguard Worker     err = drmModeAddFB2WithModifiers(*drm.GetFd(), bo->width, bo->height,
82*0a9764feSAndroid Build Coastguard Worker                                      bo->format, local->gem_handles_.data(),
83*0a9764feSAndroid Build Coastguard Worker                                      &bo->pitches[0], &bo->offsets[0],
84*0a9764feSAndroid Build Coastguard Worker                                      &bo->modifiers[0], &local->fb_id_,
85*0a9764feSAndroid Build Coastguard Worker                                      DRM_MODE_FB_MODIFIERS);
86*0a9764feSAndroid Build Coastguard Worker   }
87*0a9764feSAndroid Build Coastguard Worker   if (err != 0) {
88*0a9764feSAndroid Build Coastguard Worker     ALOGE("could not create drm fb %d", err);
89*0a9764feSAndroid Build Coastguard Worker     local.reset();
90*0a9764feSAndroid Build Coastguard Worker   }
91*0a9764feSAndroid Build Coastguard Worker 
92*0a9764feSAndroid Build Coastguard Worker   return local;
93*0a9764feSAndroid Build Coastguard Worker }
94*0a9764feSAndroid Build Coastguard Worker 
~DrmFbIdHandle()95*0a9764feSAndroid Build Coastguard Worker DrmFbIdHandle::~DrmFbIdHandle() {
96*0a9764feSAndroid Build Coastguard Worker   // NOLINTNEXTLINE(misc-const-correctness)
97*0a9764feSAndroid Build Coastguard Worker   ATRACE_NAME("Close FB and dmabufs");
98*0a9764feSAndroid Build Coastguard Worker 
99*0a9764feSAndroid Build Coastguard Worker   /* Destroy framebuffer object */
100*0a9764feSAndroid Build Coastguard Worker   if (drmModeRmFB(*drm_fd_, fb_id_) != 0) {
101*0a9764feSAndroid Build Coastguard Worker     ALOGE("Failed to rm fb");
102*0a9764feSAndroid Build Coastguard Worker   }
103*0a9764feSAndroid Build Coastguard Worker 
104*0a9764feSAndroid Build Coastguard Worker   /* Close GEM handles.
105*0a9764feSAndroid Build Coastguard Worker    *
106*0a9764feSAndroid Build Coastguard Worker    * WARNING: TODO(nobody):
107*0a9764feSAndroid Build Coastguard Worker    * From Linux side libweston relies on libgbm to get KMS handle and never
108*0a9764feSAndroid Build Coastguard Worker    * closes it (handle is closed by libgbm on buffer destruction)
109*0a9764feSAndroid Build Coastguard Worker    * Probably we should offer similar approach to users (at least on user
110*0a9764feSAndroid Build Coastguard Worker    * request via system properties)
111*0a9764feSAndroid Build Coastguard Worker    */
112*0a9764feSAndroid Build Coastguard Worker   struct drm_gem_close gem_close {};
113*0a9764feSAndroid Build Coastguard Worker   for (size_t i = 0; i < gem_handles_.size(); i++) {
114*0a9764feSAndroid Build Coastguard Worker     /* Don't close invalid handle. Close handle only once in cases
115*0a9764feSAndroid Build Coastguard Worker      * where several YUV planes located in the single buffer. */
116*0a9764feSAndroid Build Coastguard Worker     if (gem_handles_[i] == 0 ||
117*0a9764feSAndroid Build Coastguard Worker         (i != 0 && gem_handles_[i] == gem_handles_[0])) {
118*0a9764feSAndroid Build Coastguard Worker       continue;
119*0a9764feSAndroid Build Coastguard Worker     }
120*0a9764feSAndroid Build Coastguard Worker     gem_close.handle = gem_handles_[i];
121*0a9764feSAndroid Build Coastguard Worker     auto err = drmIoctl(*drm_fd_, DRM_IOCTL_GEM_CLOSE, &gem_close);
122*0a9764feSAndroid Build Coastguard Worker     if (err != 0) {
123*0a9764feSAndroid Build Coastguard Worker       ALOGE("Failed to close gem handle %d, errno: %d", gem_handles_[i], errno);
124*0a9764feSAndroid Build Coastguard Worker     }
125*0a9764feSAndroid Build Coastguard Worker   }
126*0a9764feSAndroid Build Coastguard Worker }
127*0a9764feSAndroid Build Coastguard Worker 
GetOrCreateFbId(BufferInfo * bo)128*0a9764feSAndroid Build Coastguard Worker auto DrmFbImporter::GetOrCreateFbId(BufferInfo *bo)
129*0a9764feSAndroid Build Coastguard Worker     -> std::shared_ptr<DrmFbIdHandle> {
130*0a9764feSAndroid Build Coastguard Worker   /* TODO: Clean up DrmDevices and DrmFbImporter inter-dependency.
131*0a9764feSAndroid Build Coastguard Worker    *
132*0a9764feSAndroid Build Coastguard Worker    * DrmFbImporter can outlive DrmDevice which will cause issues when resources
133*0a9764feSAndroid Build Coastguard Worker    * are released. Addressing this would require a restructure on how
134*0a9764feSAndroid Build Coastguard Worker    * ResourceManager stores DrmDevices and DrmFbImporter to make sure they
135*0a9764feSAndroid Build Coastguard Worker    * depend on each other. For now, just acquire the DRM fd from the DrmDevice
136*0a9764feSAndroid Build Coastguard Worker    * to make sure it is not closed.
137*0a9764feSAndroid Build Coastguard Worker    */
138*0a9764feSAndroid Build Coastguard Worker   if (drm_fd_ == nullptr) {
139*0a9764feSAndroid Build Coastguard Worker     drm_fd_ = drm_->GetFd();
140*0a9764feSAndroid Build Coastguard Worker   }
141*0a9764feSAndroid Build Coastguard Worker 
142*0a9764feSAndroid Build Coastguard Worker   /* Lookup DrmFbIdHandle in cache first. First handle serves as a cache key. */
143*0a9764feSAndroid Build Coastguard Worker   GemHandle first_handle = 0;
144*0a9764feSAndroid Build Coastguard Worker   auto err = drmPrimeFDToHandle(*drm_fd_, bo->prime_fds[0], &first_handle);
145*0a9764feSAndroid Build Coastguard Worker 
146*0a9764feSAndroid Build Coastguard Worker   if (err != 0) {
147*0a9764feSAndroid Build Coastguard Worker     ALOGE("Failed to import prime fd %d ret=%d", bo->prime_fds[0], err);
148*0a9764feSAndroid Build Coastguard Worker     return {};
149*0a9764feSAndroid Build Coastguard Worker   }
150*0a9764feSAndroid Build Coastguard Worker 
151*0a9764feSAndroid Build Coastguard Worker   auto drm_fb_id_cached = drm_fb_id_handle_cache_.find(first_handle);
152*0a9764feSAndroid Build Coastguard Worker 
153*0a9764feSAndroid Build Coastguard Worker   if (drm_fb_id_cached != drm_fb_id_handle_cache_.end()) {
154*0a9764feSAndroid Build Coastguard Worker     if (auto drm_fb_id_handle_shared = drm_fb_id_cached->second.lock()) {
155*0a9764feSAndroid Build Coastguard Worker       return drm_fb_id_handle_shared;
156*0a9764feSAndroid Build Coastguard Worker     }
157*0a9764feSAndroid Build Coastguard Worker     drm_fb_id_handle_cache_.erase(drm_fb_id_cached);
158*0a9764feSAndroid Build Coastguard Worker   }
159*0a9764feSAndroid Build Coastguard Worker 
160*0a9764feSAndroid Build Coastguard Worker   /* Cleanup cached empty weak pointers */
161*0a9764feSAndroid Build Coastguard Worker   const int minimal_cleanup_size = 128;
162*0a9764feSAndroid Build Coastguard Worker   if (drm_fb_id_handle_cache_.size() > minimal_cleanup_size) {
163*0a9764feSAndroid Build Coastguard Worker     CleanupEmptyCacheElements();
164*0a9764feSAndroid Build Coastguard Worker   }
165*0a9764feSAndroid Build Coastguard Worker 
166*0a9764feSAndroid Build Coastguard Worker   /* No DrmFbIdHandle found in cache, create framebuffer object */
167*0a9764feSAndroid Build Coastguard Worker   auto fb_id_handle = DrmFbIdHandle::CreateInstance(bo, first_handle, *drm_);
168*0a9764feSAndroid Build Coastguard Worker   if (fb_id_handle) {
169*0a9764feSAndroid Build Coastguard Worker     drm_fb_id_handle_cache_[first_handle] = fb_id_handle;
170*0a9764feSAndroid Build Coastguard Worker   }
171*0a9764feSAndroid Build Coastguard Worker 
172*0a9764feSAndroid Build Coastguard Worker   return fb_id_handle;
173*0a9764feSAndroid Build Coastguard Worker }
174*0a9764feSAndroid Build Coastguard Worker 
175*0a9764feSAndroid Build Coastguard Worker }  // namespace android
176