• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
20 #include <set>
21 
22 #include <C2AllocatorBlob.h>
23 #include <C2PlatformSupport.h>
24 
25 #include <android/hardware/graphics/common/1.2/types.h>
26 #include <utils/Log.h>
27 
28 namespace android {
29 
30 using ::android::hardware::graphics::common::V1_2::PixelFormat;
31 
32 constexpr uint32_t kLinearBufferHeight = 1u;
33 constexpr uint32_t kLinearBufferFormat = static_cast<uint32_t>(PixelFormat::BLOB);
34 
35 namespace {
36 
GetCapacityFromHandle(const C2Handle * const grallocHandle,size_t * capacity)37 c2_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().
54 class C2AllocationBlob : public C2LinearAllocation {
55 public:
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 
getAllocatorId() const63     id_t getAllocatorId() const override { return mAllocatorId; }
handle() const64     const C2Handle* handle() const override { return mGraphicAllocation->handle(); }
equals(const std::shared_ptr<C2LinearAllocation> & other) const65     bool equals(const std::shared_ptr<C2LinearAllocation>& other) const override {
66         return other && other->handle() == handle();
67     }
68 
69 private:
70     const std::shared_ptr<C2GraphicAllocation> mGraphicAllocation;
71     const C2Allocator::id_t mAllocatorId;
72 
73     std::mutex mMapLock;
74     std::multiset<std::pair<size_t, size_t>> mMappedOffsetSize;
75     uint8_t *mMappedAddr;
76 };
77 
C2AllocationBlob(std::shared_ptr<C2GraphicAllocation> graphicAllocation,size_t capacity,C2Allocator::id_t allocatorId)78 C2AllocationBlob::C2AllocationBlob(
79         std::shared_ptr<C2GraphicAllocation> graphicAllocation, size_t capacity,
80         C2Allocator::id_t allocatorId)
81       : C2LinearAllocation(capacity),
82         mGraphicAllocation(std::move(graphicAllocation)),
83         mAllocatorId(allocatorId),
84         mMappedAddr(nullptr) {}
85 
~C2AllocationBlob()86 C2AllocationBlob::~C2AllocationBlob() {
87     if (mMappedAddr) {
88         C2Rect rect(capacity(), kLinearBufferHeight);
89         mGraphicAllocation->unmap(&mMappedAddr, rect, nullptr);
90     }
91 }
92 
map(size_t offset,size_t size,C2MemoryUsage usage,C2Fence * fence,void ** addr)93 c2_status_t C2AllocationBlob::map(size_t offset, size_t size, C2MemoryUsage usage,
94                                   C2Fence* fence, void** addr /* nonnull */) {
95     *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     }
109     C2PlanarLayout layout;
110     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;
123 }
124 
unmap(void * addr,size_t size,C2Fence * fenceFd)125 c2_status_t C2AllocationBlob::unmap(void* addr, size_t size, C2Fence* fenceFd) {
126     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;
151 }
152 
153 /* ====================================== BLOB ALLOCATOR ====================================== */
C2AllocatorBlob(id_t id)154 C2AllocatorBlob::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 
~C2AllocatorBlob()167 C2AllocatorBlob::~C2AllocatorBlob() {}
168 
newLinearAllocation(uint32_t capacity,C2MemoryUsage usage,std::shared_ptr<C2LinearAllocation> * allocation)169 c2_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     // Note: the BLOB allocator does not support padding as this functionality is expected
182     // to be provided by the gralloc implementation.
183     std::shared_ptr<C2GraphicAllocation> graphicAllocation;
184     c2_status_t status = mC2AllocatorGralloc->newGraphicAllocation(
185             capacity, kLinearBufferHeight, kLinearBufferFormat, usage, &graphicAllocation);
186     if (status != C2_OK) {
187         ALOGE("Failed newGraphicAllocation");
188         return status;
189     }
190 
191     allocation->reset(new C2AllocationBlob(std::move(graphicAllocation),
192                                            static_cast<size_t>(capacity), mTraits->id));
193     return C2_OK;
194 }
195 
priorLinearAllocation(const C2Handle * handle,std::shared_ptr<C2LinearAllocation> * allocation)196 c2_status_t C2AllocatorBlob::priorLinearAllocation(
197         const C2Handle* handle, std::shared_ptr<C2LinearAllocation>* allocation) {
198     if (allocation == nullptr) {
199         return C2_BAD_VALUE;
200     }
201 
202     allocation->reset();
203 
204     if (!mC2AllocatorGralloc) {
205         return C2_CORRUPTED;
206     }
207 
208     std::shared_ptr<C2GraphicAllocation> graphicAllocation;
209     c2_status_t status = mC2AllocatorGralloc->priorGraphicAllocation(handle, &graphicAllocation);
210     if (status != C2_OK) {
211         ALOGE("Failed priorGraphicAllocation");
212         return status;
213     }
214 
215     const C2Handle* const grallocHandle = graphicAllocation->handle();
216     size_t capacity = 0;
217     status = GetCapacityFromHandle(grallocHandle, &capacity);
218     if (status != C2_OK) {
219         ALOGE("Failed to extract capacity from Handle");
220         return status;
221     }
222 
223     allocation->reset(new C2AllocationBlob(std::move(graphicAllocation), capacity, mTraits->id));
224     return C2_OK;
225 }
226 
getId() const227 id_t C2AllocatorBlob::getId() const {
228     return mTraits->id;
229 }
230 
getName() const231 C2String C2AllocatorBlob::getName() const {
232     return mTraits->name;
233 }
234 
getTraits() const235 std::shared_ptr<const C2Allocator::Traits> C2AllocatorBlob::getTraits() const {
236     return mTraits;
237 }
238 
239 // static
CheckHandle(const C2Handle * const o)240 bool C2AllocatorBlob::CheckHandle(const C2Handle* const o) {
241     size_t capacity;
242     // Distinguish C2Handle purely allocated by C2AllocatorGralloc, or one allocated through
243     // C2AllocatorBlob, by checking the handle's height is 1, and its format is
244     // PixelFormat::BLOB by GetCapacityFromHandle().
245     return C2AllocatorGralloc::CheckHandle(o) && GetCapacityFromHandle(o, &capacity) == C2_OK;
246 }
247 
248 }  // namespace android
249