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