1 /*
2 * Copyright (C) 2020 ARM Limited. All rights reserved.
3 *
4 * Copyright 2016 The Android Open Source Project
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18
19 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
20
21 #include <array>
22 #include <atomic>
23 #include <chrono>
24 #include <utils/Trace.h>
25 #include <shared_mutex>
26 #include <sstream>
27 #include <sys/stat.h>
28
29 #include "Allocator.h"
30 #include "core/mali_gralloc_bufferallocation.h"
31 #include "core/mali_gralloc_bufferdescriptor.h"
32 #include "core/format_info.h"
33 #include "allocator/mali_gralloc_ion.h"
34 #include "gralloc_priv.h"
35 #include "SharedMetadata.h"
36
37 namespace arm
38 {
39 namespace allocator
40 {
41 namespace common
42 {
43
44 struct BufferDetails {
45 std::string name;
46 uint64_t buffer_id;
47 std::vector<ino_t> inodes;
48 uint64_t format;
49 uint64_t usage;
50 uint32_t width;
51 uint32_t height;
52 };
53
54 uint64_t total_allocated = 0;
55 std::atomic<uint16_t> next_idx = 0;
56
57 // There is no atomic rounding off for atomics so next_idx can overflow. allocated_buffers should be
58 // a power of 2.
59 std::array<BufferDetails, 2048> allocated_buffers;
60 std::shared_timed_mutex allocated_buffers_mutex;
61 static_assert((allocated_buffers.size() & (allocated_buffers.size() - 1)) == 0);
62
get_inode(int fd)63 ino_t get_inode(int fd) {
64 struct stat fd_info;
65 int error = fstat(fd, &fd_info);
66 if (error != 0) {
67 return error;
68 }
69
70 return fd_info.st_ino;
71 }
72
allocate(const buffer_descriptor_t & bufferDescriptor,uint32_t count,IAllocator::allocate_cb hidl_cb,std::function<int (const buffer_descriptor_t *,buffer_handle_t *)> fb_allocator)73 void allocate(const buffer_descriptor_t &bufferDescriptor, uint32_t count, IAllocator::allocate_cb hidl_cb,
74 std::function<int(const buffer_descriptor_t *, buffer_handle_t *)> fb_allocator)
75 {
76 #if DISABLE_FRAMEBUFFER_HAL
77 GRALLOC_UNUSED(fb_allocator);
78 #endif
79 ATRACE_CALL();
80
81 Error error = Error::NONE;
82 int stride = 0;
83 bool use_placeholder = bufferDescriptor.producer_usage & GRALLOC_USAGE_PLACEHOLDER_BUFFER;
84 std::vector<hidl_handle> grallocBuffers;
85 gralloc_buffer_descriptor_t grallocBufferDescriptor[1];
86
87 grallocBufferDescriptor[0] = (gralloc_buffer_descriptor_t)(&bufferDescriptor);
88 grallocBuffers.reserve(count);
89
90 for (uint32_t i = 0; i < count; i++)
91 {
92 buffer_handle_t tmpBuffer = nullptr;
93
94 int allocResult;
95 #if (DISABLE_FRAMEBUFFER_HAL != 1)
96 if (((bufferDescriptor.producer_usage & GRALLOC_USAGE_HW_FB) ||
97 (bufferDescriptor.consumer_usage & GRALLOC_USAGE_HW_FB)) &&
98 fb_allocator)
99 {
100 allocResult = fb_allocator(&bufferDescriptor, &tmpBuffer);
101 }
102 else
103 #endif
104 {
105 allocResult = mali_gralloc_buffer_allocate(grallocBufferDescriptor, 1, &tmpBuffer, nullptr, use_placeholder);
106 if (allocResult != 0)
107 {
108 MALI_GRALLOC_LOGE("%s, buffer allocation failed with %d", __func__, allocResult);
109 error = Error::NO_RESOURCES;
110 break;
111 }
112 auto hnd = const_cast<private_handle_t *>(reinterpret_cast<const private_handle_t *>(tmpBuffer));
113 hnd->imapper_version = HIDL_MAPPER_VERSION_SCALED;
114
115 // 4k is rougly 7.9 MB with one byte per pixel. We are
116 // assuming that the reserved region might be needed for
117 // dynamic HDR and that represents the largest size.
118 uint64_t max_reserved_region_size = 8ull * 1024 * 1024;
119 hnd->reserved_region_size = bufferDescriptor.reserved_size;
120 if (hnd->reserved_region_size > max_reserved_region_size) {
121 MALI_GRALLOC_LOGE("%s, Requested reserved region size (%" PRIu64 ") is larger than allowed (%" PRIu64 ")",
122 __func__, hnd->reserved_region_size, max_reserved_region_size);
123 error = Error::BAD_VALUE;
124 break;
125 }
126 hnd->attr_size = mapper::common::shared_metadata_size() + hnd->reserved_region_size;
127
128 if (hnd->get_usage() & GRALLOC_USAGE_ROIINFO)
129 {
130 hnd->attr_size += 32768;
131 }
132
133 /* TODO: must do error checking */
134 mali_gralloc_ion_allocate_attr(hnd);
135
136 /* TODO: error check for failure */
137 void* metadata_vaddr = mmap(nullptr, hnd->attr_size, PROT_READ | PROT_WRITE,
138 MAP_SHARED, hnd->get_share_attr_fd(), 0);
139
140 memset(metadata_vaddr, 0, hnd->attr_size);
141
142 mapper::common::shared_metadata_init(metadata_vaddr, bufferDescriptor.name);
143
144 const uint32_t base_format = bufferDescriptor.alloc_format & MALI_GRALLOC_INTFMT_FMT_MASK;
145 const uint64_t usage = bufferDescriptor.consumer_usage | bufferDescriptor.producer_usage;
146 android_dataspace_t dataspace;
147 get_format_dataspace(base_format, usage, hnd->width, hnd->height, &dataspace);
148
149 // TODO: set_dataspace API in mapper expects a buffer to be first imported before it can set the dataspace
150 {
151 using mapper::common::shared_metadata;
152 using mapper::common::aligned_optional;
153 using mapper::common::Dataspace;
154 (static_cast<shared_metadata*>(metadata_vaddr))->dataspace = aligned_optional(static_cast<Dataspace>(dataspace));
155 }
156
157 {
158 ATRACE_NAME("Update dump details");
159 const auto fd_count = hnd->fd_count + 1 /* metadata fd */;
160 std::vector<ino_t> inodes(fd_count);
161 for (size_t idx = 0; idx < fd_count; idx++) {
162 inodes[idx] = get_inode(hnd->fds[idx]);
163 }
164
165 auto idx = next_idx.fetch_add(1);
166 idx %= allocated_buffers.size();
167
168 allocated_buffers_mutex.lock_shared();
169 allocated_buffers[idx] =
170 BufferDetails{bufferDescriptor.name,
171 hnd->backing_store_id,
172 inodes,
173 bufferDescriptor.hal_format,
174 bufferDescriptor.producer_usage,
175 bufferDescriptor.width,
176 bufferDescriptor.height};
177 allocated_buffers_mutex.unlock_shared();
178
179 total_allocated++;
180 }
181
182 munmap(metadata_vaddr, hnd->attr_size);
183 }
184
185 int tmpStride = 0;
186 tmpStride = bufferDescriptor.pixel_stride;
187
188 if (stride == 0)
189 {
190 stride = tmpStride;
191 }
192 else if (stride != tmpStride)
193 {
194 /* Stride must be the same for all allocations */
195 mali_gralloc_buffer_free(tmpBuffer);
196 stride = 0;
197 error = Error::UNSUPPORTED;
198 break;
199 }
200
201 grallocBuffers.emplace_back(hidl_handle(tmpBuffer));
202 }
203
204 /* Populate the array of buffers for application consumption */
205 hidl_vec<hidl_handle> hidlBuffers;
206 if (error == Error::NONE)
207 {
208 hidlBuffers.setToExternal(grallocBuffers.data(), grallocBuffers.size());
209 }
210 hidl_cb(error, stride, hidlBuffers);
211
212 /* The application should import the Gralloc buffers using IMapper for
213 * further usage. Free the allocated buffers in IAllocator context
214 */
215 for (const auto &buffer : grallocBuffers)
216 {
217 mali_gralloc_buffer_free(buffer.getNativeHandle());
218 }
219 }
220
dump()221 const std::string dump() {
222 using namespace std::chrono_literals;
223 if (!allocated_buffers_mutex.try_lock_for(100ms)) {
224 return "";
225 }
226
227 std::stringstream ss;
228 // TODO: Add logs to indicate overflow
229 for (int i = 0; i < std::min(total_allocated, static_cast<uint64_t>(allocated_buffers.size())); i++) {
230 const auto& [name, buffer_id, inodes, format, usage, width, height] = allocated_buffers[i];
231 ss << "buffer_id: " << buffer_id << ", inodes: ";
232 for (auto it = inodes.begin(); it != inodes.end(); it++) {
233 if (it != inodes.begin()) {
234 ss << ",";
235 }
236 ss << static_cast<int>(*it);
237 }
238 ss << ", format: 0x" << std::hex << format << std::dec;
239 ss << ", usage: 0x" << std::hex << usage << std::dec;
240 ss << ", width: " << width << ", height: " << height;
241 ss << ", name: " << name << std::endl;
242 }
243
244 allocated_buffers_mutex.unlock();
245 return ss.str();
246 }
247
isSupported(buffer_descriptor_t * const bufDescriptor)248 bool isSupported(buffer_descriptor_t *const bufDescriptor) {
249 // this is used as the criteria to determine which allocations succeed.
250 return (mali_gralloc_derive_format_and_size(bufDescriptor) == 0);
251 }
252
253 } // namespace common
254 } // namespace allocator
255 } // namespace arm
256