blob: 4a3a957347aaeb5107ef229def29f45b3380fafe [file] [log] [blame]
Sean Paulda6270d2015-06-01 14:11:52 -04001/*
2 * Copyright (C) 2015 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
Sean Paul0aee6b22016-05-10 04:08:10 -040017#define LOG_TAG "hwc-platform-nv"
Sean Paulda6270d2015-06-01 14:11:52 -040018
19#include "drmresources.h"
Sean Paul63769962016-04-21 16:25:06 -040020#include "platform.h"
Sean Paulea045b72016-04-21 16:39:02 -040021#include "platformnv.h"
Sean Paulda6270d2015-06-01 14:11:52 -040022
Sean Paul5325e102016-03-29 13:55:35 -040023#include <cinttypes>
Sean Paul419b5e02015-06-10 14:30:47 -040024#include <stdatomic.h>
Sean Paulda6270d2015-06-01 14:11:52 -040025#include <xf86drm.h>
26#include <xf86drmMode.h>
27
28#include <cutils/log.h>
29#include <hardware/gralloc.h>
30
Rob Clark90f92d82016-10-19 10:48:14 -040031#ifndef EGL_NATIVE_HANDLE_ANDROID_NVX
32#define EGL_NATIVE_HANDLE_ANDROID_NVX 0x322A
33#endif
34
Sean Paulda6270d2015-06-01 14:11:52 -040035namespace android {
36
37#ifdef USE_NVIDIA_IMPORTER
38// static
39Importer *Importer::CreateInstance(DrmResources *drm) {
40 NvImporter *importer = new NvImporter(drm);
41 if (!importer)
42 return NULL;
43
44 int ret = importer->Init();
45 if (ret) {
46 ALOGE("Failed to initialize the nv importer %d", ret);
47 delete importer;
48 return NULL;
49 }
50 return importer;
51}
52#endif
53
54NvImporter::NvImporter(DrmResources *drm) : drm_(drm) {
55}
56
57NvImporter::~NvImporter() {
58}
59
60int NvImporter::Init() {
61 int ret = hw_get_module(GRALLOC_HARDWARE_MODULE_ID,
62 (const hw_module_t **)&gralloc_);
63 if (ret) {
64 ALOGE("Failed to open gralloc module %d", ret);
65 return ret;
66 }
67
68 if (strcasecmp(gralloc_->common.author, "NVIDIA"))
69 ALOGW("Using non-NVIDIA gralloc module: %s/%s\n", gralloc_->common.name,
70 gralloc_->common.author);
71
72 return 0;
73}
74
Rob Clark90f92d82016-10-19 10:48:14 -040075
76EGLImageKHR NvImporter::ImportImage(EGLDisplay egl_display, buffer_handle_t handle) {
77 return eglCreateImageKHR(
78 egl_display, EGL_NO_CONTEXT, EGL_NATIVE_HANDLE_ANDROID_NVX,
79 (EGLClientBuffer)handle, NULL /* no attribs */);
80}
81
Sean Paulda6270d2015-06-01 14:11:52 -040082int NvImporter::ImportBuffer(buffer_handle_t handle, hwc_drm_bo_t *bo) {
83 memset(bo, 0, sizeof(hwc_drm_bo_t));
84 NvBuffer_t *buf = GrallocGetNvBuffer(handle);
85 if (buf) {
Sean Paul419b5e02015-06-10 14:30:47 -040086 atomic_fetch_add(&buf->ref, 1);
Sean Paulda6270d2015-06-01 14:11:52 -040087 *bo = buf->bo;
88 return 0;
89 }
90
91 buf = new NvBuffer_t();
92 if (!buf) {
93 ALOGE("Failed to allocate new NvBuffer_t");
94 return -ENOMEM;
95 }
Sean Paul419b5e02015-06-10 14:30:47 -040096 buf->bo.priv = buf;
Sean Paulda6270d2015-06-01 14:11:52 -040097 buf->importer = this;
98
Sean Paul419b5e02015-06-10 14:30:47 -040099 // We initialize the reference count to 2 since NvGralloc is still using this
100 // buffer (will be cleared in the NvGrallocRelease), and the other
101 // reference is for HWC (this ImportBuffer call).
102 atomic_init(&buf->ref, 2);
103
Sean Paulda6270d2015-06-01 14:11:52 -0400104 int ret = gralloc_->perform(gralloc_, GRALLOC_MODULE_PERFORM_DRM_IMPORT,
105 drm_->fd(), handle, &buf->bo);
106 if (ret) {
107 ALOGE("GRALLOC_MODULE_PERFORM_DRM_IMPORT failed %d", ret);
108 delete buf;
109 return ret;
110 }
111
112 ret = drmModeAddFB2(drm_->fd(), buf->bo.width, buf->bo.height, buf->bo.format,
113 buf->bo.gem_handles, buf->bo.pitches, buf->bo.offsets,
114 &buf->bo.fb_id, 0);
115 if (ret) {
116 ALOGE("Failed to add fb %d", ret);
117 ReleaseBufferImpl(&buf->bo);
118 delete buf;
119 return ret;
120 }
121
122 ret = GrallocSetNvBuffer(handle, buf);
123 if (ret) {
124 /* This will happen is persist.tegra.gpu_mapping_cache is 0/off,
125 * or if NV gralloc runs out of "priv slots" (currently 3 per buffer,
126 * only one of which should be used by drm_hwcomposer). */
127 ALOGE("Failed to register free callback for imported buffer %d", ret);
128 ReleaseBufferImpl(&buf->bo);
129 delete buf;
130 return ret;
131 }
132 *bo = buf->bo;
133 return 0;
134}
135
Zach Reiznerc6520e42015-08-13 14:32:09 -0700136int NvImporter::ReleaseBuffer(hwc_drm_bo_t *bo) {
Sean Paul419b5e02015-06-10 14:30:47 -0400137 NvBuffer_t *buf = (NvBuffer_t *)bo->priv;
138 if (!buf) {
Sean Paul5325e102016-03-29 13:55:35 -0400139 ALOGE("Freeing bo %" PRIu32 ", buf is NULL!", bo->fb_id);
Sean Paul419b5e02015-06-10 14:30:47 -0400140 return 0;
141 }
142 if (atomic_fetch_sub(&buf->ref, 1) > 1)
143 return 0;
144
145 ReleaseBufferImpl(bo);
146 delete buf;
Sean Paulda6270d2015-06-01 14:11:52 -0400147 return 0;
148}
149
150// static
Sean Paul419b5e02015-06-10 14:30:47 -0400151void NvImporter::NvGrallocRelease(void *nv_buffer) {
152 NvBuffer_t *buf = (NvBuffer *)nv_buffer;
153 buf->importer->ReleaseBuffer(&buf->bo);
Sean Paulda6270d2015-06-01 14:11:52 -0400154}
155
156void NvImporter::ReleaseBufferImpl(hwc_drm_bo_t *bo) {
157 if (bo->fb_id) {
158 int ret = drmModeRmFB(drm_->fd(), bo->fb_id);
159 if (ret)
160 ALOGE("Failed to rm fb %d", ret);
161 }
162
163 struct drm_gem_close gem_close;
164 memset(&gem_close, 0, sizeof(gem_close));
165 int num_gem_handles = sizeof(bo->gem_handles) / sizeof(bo->gem_handles[0]);
166 for (int i = 0; i < num_gem_handles; i++) {
167 if (!bo->gem_handles[i])
168 continue;
169
170 gem_close.handle = bo->gem_handles[i];
171 int ret = drmIoctl(drm_->fd(), DRM_IOCTL_GEM_CLOSE, &gem_close);
Isaac Simha6e02c9d2015-10-14 11:40:29 -0700172 if (ret) {
Sean Paulda6270d2015-06-01 14:11:52 -0400173 ALOGE("Failed to close gem handle %d %d", i, ret);
Isaac Simha6e02c9d2015-10-14 11:40:29 -0700174 } else {
175 /* Clear any duplicate gem handle as well but don't close again */
Haixia Shi479412c2015-10-27 10:40:48 -0700176 for (int j = i + 1; j < num_gem_handles; j++)
177 if (bo->gem_handles[j] == bo->gem_handles[i])
Isaac Simha6e02c9d2015-10-14 11:40:29 -0700178 bo->gem_handles[j] = 0;
Sean Paulda6270d2015-06-01 14:11:52 -0400179 bo->gem_handles[i] = 0;
Isaac Simha6e02c9d2015-10-14 11:40:29 -0700180 }
Sean Paulda6270d2015-06-01 14:11:52 -0400181 }
182}
183
184NvImporter::NvBuffer_t *NvImporter::GrallocGetNvBuffer(buffer_handle_t handle) {
185 void *priv = NULL;
186 int ret =
187 gralloc_->perform(gralloc_, GRALLOC_MODULE_PERFORM_GET_IMPORTER_PRIVATE,
Sean Paul419b5e02015-06-10 14:30:47 -0400188 handle, NvGrallocRelease, &priv);
Sean Paulda6270d2015-06-01 14:11:52 -0400189 return ret ? NULL : (NvBuffer_t *)priv;
190}
191
192int NvImporter::GrallocSetNvBuffer(buffer_handle_t handle, NvBuffer_t *buf) {
193 return gralloc_->perform(gralloc_,
194 GRALLOC_MODULE_PERFORM_SET_IMPORTER_PRIVATE, handle,
Sean Paul419b5e02015-06-10 14:30:47 -0400195 NvGrallocRelease, buf);
Sean Paulda6270d2015-06-01 14:11:52 -0400196}
Sean Paul4c4646e2016-05-10 04:19:24 -0400197
198#ifdef USE_NVIDIA_IMPORTER
199// static
200std::unique_ptr<Planner> Planner::CreateInstance(DrmResources *) {
201 std::unique_ptr<Planner> planner(new Planner);
202 planner->AddStage<PlanStageProtectedRotated>();
203 planner->AddStage<PlanStageProtected>();
Adrian Salido45002322017-04-10 21:44:21 -0700204 planner->AddStage<PlanStagePrecomp>();
Sean Paul4c4646e2016-05-10 04:19:24 -0400205 planner->AddStage<PlanStageGreedy>();
206 return planner;
207}
208#endif
209
210static DrmPlane *GetCrtcPrimaryPlane(DrmCrtc *crtc,
211 std::vector<DrmPlane *> *planes) {
212 for (auto i = planes->begin(); i != planes->end(); ++i) {
213 if ((*i)->GetCrtcSupported(*crtc)) {
214 DrmPlane *plane = *i;
215 planes->erase(i);
216 return plane;
217 }
218 }
219 return NULL;
220}
221
222int PlanStageProtectedRotated::ProvisionPlanes(
223 std::vector<DrmCompositionPlane> *composition,
224 std::map<size_t, DrmHwcLayer *> &layers, DrmCrtc *crtc,
225 std::vector<DrmPlane *> *planes) {
226 int ret;
227 int protected_zorder = -1;
228 for (auto i = layers.begin(); i != layers.end();) {
229 if (!i->second->protected_usage() || !i->second->transform) {
230 ++i;
231 continue;
232 }
233
234 auto primary_iter = planes->begin();
235 for (; primary_iter != planes->end(); ++primary_iter) {
236 if ((*primary_iter)->type() == DRM_PLANE_TYPE_PRIMARY)
237 break;
238 }
239
240 // We cheat a little here. Since there can only be one primary plane per
241 // crtc, we know we'll only hit this case once. So we blindly insert the
242 // protected content at the beginning of the composition, knowing this path
243 // won't be taken a second time during the loop.
244 if (primary_iter != planes->end()) {
245 composition->emplace(composition->begin(),
246 DrmCompositionPlane::Type::kLayer, *primary_iter,
247 crtc, i->first);
248 planes->erase(primary_iter);
249 protected_zorder = i->first;
250 } else {
251 ALOGE("Could not provision primary plane for protected/rotated layer");
252 }
253 i = layers.erase(i);
254 }
255
256 if (protected_zorder == -1)
257 return 0;
258
259 // Add any layers below the protected content to the precomposition since we
260 // need to punch a hole through them.
261 for (auto i = layers.begin(); i != layers.end();) {
262 // Skip layers above the z-order of the protected content
263 if (i->first > static_cast<size_t>(protected_zorder)) {
264 ++i;
265 continue;
266 }
267
268 // If there's no precomp layer already queued, queue one now.
269 DrmCompositionPlane *precomp = GetPrecomp(composition);
270 if (precomp) {
271 precomp->source_layers().emplace_back(i->first);
272 } else {
273 if (planes->size()) {
274 DrmPlane *precomp_plane = planes->back();
275 planes->pop_back();
276 composition->emplace_back(DrmCompositionPlane::Type::kPrecomp,
277 precomp_plane, crtc, i->first);
278 } else {
279 ALOGE("Not enough planes to reserve for precomp fb");
280 }
281 }
282 i = layers.erase(i);
283 }
284 return 0;
285}
Sean Paulda6270d2015-06-01 14:11:52 -0400286}