blob: 6340cbabc6bec5deedc6e810ecc7e2e1c199e7fb [file] [log] [blame]
Pin-chih Linf72774b2019-11-19 18:26:47 +08001/*
2 * Copyright (C) 2019 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// #define LOG_NDEBUG 0
18#define LOG_TAG "C2AllocatorBlob"
19
Wonsik Kimd04f34c2020-11-25 10:12:32 -080020#include <set>
21
Pin-chih Linf72774b2019-11-19 18:26:47 +080022#include <C2AllocatorBlob.h>
23#include <C2PlatformSupport.h>
24
25#include <android/hardware/graphics/common/1.2/types.h>
26#include <utils/Log.h>
27
28namespace android {
29
30using ::android::hardware::graphics::common::V1_2::PixelFormat;
31
32constexpr uint32_t kLinearBufferHeight = 1u;
33constexpr uint32_t kLinearBufferFormat = static_cast<uint32_t>(PixelFormat::BLOB);
34
35namespace {
36
37c2_status_t GetCapacityFromHandle(const C2Handle* const grallocHandle, size_t* capacity) {
38 uint32_t width, height, format, stride, generation, igbp_slot;
39 uint64_t usage, igbp_id;
40 _UnwrapNativeCodec2GrallocMetadata(grallocHandle, &width, &height, &format, &usage, &stride,
41 &generation, &igbp_id, &igbp_slot);
42
43 if (height != kLinearBufferHeight || format != kLinearBufferFormat) {
44 return C2_BAD_VALUE;
45 }
46 *capacity = width;
47 return C2_OK;
48}
49
50} // namespace
51
52// C2AllocationBlob is a wrapper for C2AllocationGralloc allocated by C2AllocatorGralloc.
53// C2AllocationBlob::handle() delegates to the backed C2AllocationGralloc::handle().
54class C2AllocationBlob : public C2LinearAllocation {
55public:
56 C2AllocationBlob(std::shared_ptr<C2GraphicAllocation> graphicAllocation, size_t capacity,
57 C2Allocator::id_t allocatorId);
58 ~C2AllocationBlob() override;
59 c2_status_t map(size_t offset, size_t size, C2MemoryUsage usage, C2Fence* fence,
60 void** addr /* nonnull */) override;
61 c2_status_t unmap(void* addr, size_t size, C2Fence* fenceFd) override;
62
63 id_t getAllocatorId() const override { return mAllocatorId; }
64 const C2Handle* handle() const override { return mGraphicAllocation->handle(); }
65 bool equals(const std::shared_ptr<C2LinearAllocation>& other) const override {
66 return other && other->handle() == handle();
67 }
68
69private:
70 const std::shared_ptr<C2GraphicAllocation> mGraphicAllocation;
71 const C2Allocator::id_t mAllocatorId;
Wonsik Kimd04f34c2020-11-25 10:12:32 -080072
73 std::mutex mMapLock;
74 std::multiset<std::pair<size_t, size_t>> mMappedOffsetSize;
75 uint8_t *mMappedAddr;
Pin-chih Linf72774b2019-11-19 18:26:47 +080076};
77
78C2AllocationBlob::C2AllocationBlob(
79 std::shared_ptr<C2GraphicAllocation> graphicAllocation, size_t capacity,
80 C2Allocator::id_t allocatorId)
81 : C2LinearAllocation(capacity),
82 mGraphicAllocation(std::move(graphicAllocation)),
Wonsik Kimd04f34c2020-11-25 10:12:32 -080083 mAllocatorId(allocatorId),
84 mMappedAddr(nullptr) {}
Pin-chih Linf72774b2019-11-19 18:26:47 +080085
Wonsik Kimd04f34c2020-11-25 10:12:32 -080086C2AllocationBlob::~C2AllocationBlob() {
87 if (mMappedAddr) {
88 C2Rect rect(capacity(), kLinearBufferHeight);
89 mGraphicAllocation->unmap(&mMappedAddr, rect, nullptr);
90 }
91}
Pin-chih Linf72774b2019-11-19 18:26:47 +080092
93c2_status_t C2AllocationBlob::map(size_t offset, size_t size, C2MemoryUsage usage,
94 C2Fence* fence, void** addr /* nonnull */) {
Wonsik Kimd04f34c2020-11-25 10:12:32 -080095 *addr = nullptr;
96 if (size > capacity() || offset > capacity() || offset > capacity() - size) {
97 ALOGV("C2AllocationBlob: map: bad offset / size: offset=%zu size=%zu capacity=%u",
98 offset, size, capacity());
99 return C2_BAD_VALUE;
100 }
101 std::unique_lock<std::mutex> lock(mMapLock);
102 if (mMappedAddr) {
103 *addr = mMappedAddr + offset;
104 mMappedOffsetSize.insert({offset, size});
105 ALOGV("C2AllocationBlob: mapped from existing mapping: offset=%zu size=%zu capacity=%u",
106 offset, size, capacity());
107 return C2_OK;
108 }
Pin-chih Linf72774b2019-11-19 18:26:47 +0800109 C2PlanarLayout layout;
Wonsik Kimd04f34c2020-11-25 10:12:32 -0800110 C2Rect rect = C2Rect(capacity(), kLinearBufferHeight);
111 c2_status_t err = mGraphicAllocation->map(rect, usage, fence, &layout, &mMappedAddr);
112 if (err != C2_OK) {
113 ALOGV("C2AllocationBlob: map failed: offset=%zu size=%zu capacity=%u err=%d",
114 offset, size, capacity(), err);
115 mMappedAddr = nullptr;
116 return err;
117 }
118 *addr = mMappedAddr + offset;
119 mMappedOffsetSize.insert({offset, size});
120 ALOGV("C2AllocationBlob: new map succeeded: offset=%zu size=%zu capacity=%u",
121 offset, size, capacity());
122 return C2_OK;
Pin-chih Linf72774b2019-11-19 18:26:47 +0800123}
124
125c2_status_t C2AllocationBlob::unmap(void* addr, size_t size, C2Fence* fenceFd) {
Wonsik Kimd04f34c2020-11-25 10:12:32 -0800126 std::unique_lock<std::mutex> lock(mMapLock);
127 uint8_t *u8Addr = static_cast<uint8_t *>(addr);
128 if (u8Addr < mMappedAddr || mMappedAddr + capacity() < u8Addr + size) {
129 ALOGV("C2AllocationBlob: unmap: Bad addr / size: addr=%p size=%zu capacity=%u",
130 addr, size, capacity());
131 return C2_BAD_VALUE;
132 }
133 auto it = mMappedOffsetSize.find(std::make_pair(u8Addr - mMappedAddr, size));
134 if (it == mMappedOffsetSize.end()) {
135 ALOGV("C2AllocationBlob: unrecognized map: addr=%p size=%zu capacity=%u",
136 addr, size, capacity());
137 return C2_BAD_VALUE;
138 }
139 mMappedOffsetSize.erase(it);
140 if (!mMappedOffsetSize.empty()) {
141 ALOGV("C2AllocationBlob: still maintain mapping: addr=%p size=%zu capacity=%u",
142 addr, size, capacity());
143 return C2_OK;
144 }
145 C2Rect rect(capacity(), kLinearBufferHeight);
146 c2_status_t err = mGraphicAllocation->unmap(&mMappedAddr, rect, fenceFd);
147 ALOGV("C2AllocationBlob: last unmap: addr=%p size=%zu capacity=%u err=%d",
148 addr, size, capacity(), err);
149 mMappedAddr = nullptr;
150 return err;
Pin-chih Linf72774b2019-11-19 18:26:47 +0800151}
152
153/* ====================================== BLOB ALLOCATOR ====================================== */
154C2AllocatorBlob::C2AllocatorBlob(id_t id) {
155 C2MemoryUsage minUsage = {0, 0};
156 C2MemoryUsage maxUsage = {C2MemoryUsage::CPU_READ | C2MemoryUsage::READ_PROTECTED,
157 C2MemoryUsage::CPU_WRITE};
158 Traits traits = {"android.allocator.blob", id, LINEAR, minUsage, maxUsage};
159 mTraits = std::make_shared<C2Allocator::Traits>(traits);
160 auto allocatorStore = GetCodec2PlatformAllocatorStore();
161 allocatorStore->fetchAllocator(C2PlatformAllocatorStore::GRALLOC, &mC2AllocatorGralloc);
162 if (!mC2AllocatorGralloc) {
163 ALOGE("Failed to obtain C2AllocatorGralloc as backed allocator");
164 }
165}
166
167C2AllocatorBlob::~C2AllocatorBlob() {}
168
169c2_status_t C2AllocatorBlob::newLinearAllocation(
170 uint32_t capacity, C2MemoryUsage usage, std::shared_ptr<C2LinearAllocation>* allocation) {
171 if (allocation == nullptr) {
172 return C2_BAD_VALUE;
173 }
174
175 allocation->reset();
176
177 if (!mC2AllocatorGralloc) {
178 return C2_CORRUPTED;
179 }
180
181 std::shared_ptr<C2GraphicAllocation> graphicAllocation;
182 c2_status_t status = mC2AllocatorGralloc->newGraphicAllocation(
183 capacity, kLinearBufferHeight, kLinearBufferFormat, usage, &graphicAllocation);
184 if (status != C2_OK) {
185 ALOGE("Failed newGraphicAllocation");
186 return status;
187 }
188
189 allocation->reset(new C2AllocationBlob(std::move(graphicAllocation),
190 static_cast<size_t>(capacity), mTraits->id));
191 return C2_OK;
192}
193
194c2_status_t C2AllocatorBlob::priorLinearAllocation(
195 const C2Handle* handle, std::shared_ptr<C2LinearAllocation>* allocation) {
196 if (allocation == nullptr) {
197 return C2_BAD_VALUE;
198 }
199
200 allocation->reset();
201
202 if (!mC2AllocatorGralloc) {
203 return C2_CORRUPTED;
204 }
205
206 std::shared_ptr<C2GraphicAllocation> graphicAllocation;
207 c2_status_t status = mC2AllocatorGralloc->priorGraphicAllocation(handle, &graphicAllocation);
208 if (status != C2_OK) {
209 ALOGE("Failed priorGraphicAllocation");
210 return status;
211 }
212
213 const C2Handle* const grallocHandle = graphicAllocation->handle();
214 size_t capacity = 0;
215 status = GetCapacityFromHandle(grallocHandle, &capacity);
216 if (status != C2_OK) {
217 ALOGE("Failed to extract capacity from Handle");
218 return status;
219 }
220
221 allocation->reset(new C2AllocationBlob(std::move(graphicAllocation), capacity, mTraits->id));
222 return C2_OK;
223}
224
225id_t C2AllocatorBlob::getId() const {
226 return mTraits->id;
227}
228
229C2String C2AllocatorBlob::getName() const {
230 return mTraits->name;
231}
232
233std::shared_ptr<const C2Allocator::Traits> C2AllocatorBlob::getTraits() const {
234 return mTraits;
235}
236
237// static
John Stultz653ddd12020-09-19 05:26:24 +0000238bool C2AllocatorBlob::CheckHandle(const C2Handle* const o) {
Pin-chih Linf72774b2019-11-19 18:26:47 +0800239 size_t capacity;
240 // Distinguish C2Handle purely allocated by C2AllocatorGralloc, or one allocated through
241 // C2AllocatorBlob, by checking the handle's height is 1, and its format is
242 // PixelFormat::BLOB by GetCapacityFromHandle().
John Stultz653ddd12020-09-19 05:26:24 +0000243 return C2AllocatorGralloc::CheckHandle(o) && GetCapacityFromHandle(o, &capacity) == C2_OK;
Pin-chih Linf72774b2019-11-19 18:26:47 +0800244}
245
246} // namespace android