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 <C2AllocatorBlob.h>
21 #include <C2PlatformSupport.h>
22 
23 #include <android/hardware/graphics/common/1.2/types.h>
24 #include <utils/Log.h>
25 
26 namespace android {
27 
28 using ::android::hardware::graphics::common::V1_2::PixelFormat;
29 
30 constexpr uint32_t kLinearBufferHeight = 1u;
31 constexpr uint32_t kLinearBufferFormat = static_cast<uint32_t>(PixelFormat::BLOB);
32 
33 namespace {
34 
GetCapacityFromHandle(const C2Handle * const grallocHandle,size_t * capacity)35 c2_status_t GetCapacityFromHandle(const C2Handle* const grallocHandle, size_t* capacity) {
36     uint32_t width, height, format, stride, generation, igbp_slot;
37     uint64_t usage, igbp_id;
38     _UnwrapNativeCodec2GrallocMetadata(grallocHandle, &width, &height, &format, &usage, &stride,
39                                        &generation, &igbp_id, &igbp_slot);
40 
41     if (height != kLinearBufferHeight || format != kLinearBufferFormat) {
42         return C2_BAD_VALUE;
43     }
44     *capacity = width;
45     return C2_OK;
46 }
47 
48 }  // namespace
49 
50 // C2AllocationBlob is a wrapper for C2AllocationGralloc allocated by C2AllocatorGralloc.
51 // C2AllocationBlob::handle() delegates to the backed C2AllocationGralloc::handle().
52 class C2AllocationBlob : public C2LinearAllocation {
53 public:
54     C2AllocationBlob(std::shared_ptr<C2GraphicAllocation> graphicAllocation, size_t capacity,
55                      C2Allocator::id_t allocatorId);
56     ~C2AllocationBlob() override;
57     c2_status_t map(size_t offset, size_t size, C2MemoryUsage usage, C2Fence* fence,
58                     void** addr /* nonnull */) override;
59     c2_status_t unmap(void* addr, size_t size, C2Fence* fenceFd) override;
60 
getAllocatorId() const61     id_t getAllocatorId() const override { return mAllocatorId; }
handle() const62     const C2Handle* handle() const override { return mGraphicAllocation->handle(); }
equals(const std::shared_ptr<C2LinearAllocation> & other) const63     bool equals(const std::shared_ptr<C2LinearAllocation>& other) const override {
64         return other && other->handle() == handle();
65     }
66 
67 private:
68     const std::shared_ptr<C2GraphicAllocation> mGraphicAllocation;
69     const C2Allocator::id_t mAllocatorId;
70 };
71 
C2AllocationBlob(std::shared_ptr<C2GraphicAllocation> graphicAllocation,size_t capacity,C2Allocator::id_t allocatorId)72 C2AllocationBlob::C2AllocationBlob(
73         std::shared_ptr<C2GraphicAllocation> graphicAllocation, size_t capacity,
74         C2Allocator::id_t allocatorId)
75       : C2LinearAllocation(capacity),
76         mGraphicAllocation(std::move(graphicAllocation)),
77         mAllocatorId(allocatorId) {}
78 
~C2AllocationBlob()79 C2AllocationBlob::~C2AllocationBlob() {}
80 
map(size_t offset,size_t size,C2MemoryUsage usage,C2Fence * fence,void ** addr)81 c2_status_t C2AllocationBlob::map(size_t offset, size_t size, C2MemoryUsage usage,
82                                   C2Fence* fence, void** addr /* nonnull */) {
83     C2PlanarLayout layout;
84     C2Rect rect = C2Rect(size, kLinearBufferHeight).at(offset, 0u);
85     return mGraphicAllocation->map(rect, usage, fence, &layout, reinterpret_cast<uint8_t**>(addr));
86 }
87 
unmap(void * addr,size_t size,C2Fence * fenceFd)88 c2_status_t C2AllocationBlob::unmap(void* addr, size_t size, C2Fence* fenceFd) {
89     C2Rect rect(size, kLinearBufferHeight);
90     return mGraphicAllocation->unmap(reinterpret_cast<uint8_t**>(&addr), rect, fenceFd);
91 }
92 
93 /* ====================================== BLOB ALLOCATOR ====================================== */
C2AllocatorBlob(id_t id)94 C2AllocatorBlob::C2AllocatorBlob(id_t id) {
95     C2MemoryUsage minUsage = {0, 0};
96     C2MemoryUsage maxUsage = {C2MemoryUsage::CPU_READ | C2MemoryUsage::READ_PROTECTED,
97                               C2MemoryUsage::CPU_WRITE};
98     Traits traits = {"android.allocator.blob", id, LINEAR, minUsage, maxUsage};
99     mTraits = std::make_shared<C2Allocator::Traits>(traits);
100     auto allocatorStore = GetCodec2PlatformAllocatorStore();
101     allocatorStore->fetchAllocator(C2PlatformAllocatorStore::GRALLOC, &mC2AllocatorGralloc);
102     if (!mC2AllocatorGralloc) {
103         ALOGE("Failed to obtain C2AllocatorGralloc as backed allocator");
104     }
105 }
106 
~C2AllocatorBlob()107 C2AllocatorBlob::~C2AllocatorBlob() {}
108 
newLinearAllocation(uint32_t capacity,C2MemoryUsage usage,std::shared_ptr<C2LinearAllocation> * allocation)109 c2_status_t C2AllocatorBlob::newLinearAllocation(
110         uint32_t capacity, C2MemoryUsage usage, std::shared_ptr<C2LinearAllocation>* allocation) {
111     if (allocation == nullptr) {
112         return C2_BAD_VALUE;
113     }
114 
115     allocation->reset();
116 
117     if (!mC2AllocatorGralloc) {
118         return C2_CORRUPTED;
119     }
120 
121     std::shared_ptr<C2GraphicAllocation> graphicAllocation;
122     c2_status_t status = mC2AllocatorGralloc->newGraphicAllocation(
123             capacity, kLinearBufferHeight, kLinearBufferFormat, usage, &graphicAllocation);
124     if (status != C2_OK) {
125         ALOGE("Failed newGraphicAllocation");
126         return status;
127     }
128 
129     allocation->reset(new C2AllocationBlob(std::move(graphicAllocation),
130                                            static_cast<size_t>(capacity), mTraits->id));
131     return C2_OK;
132 }
133 
priorLinearAllocation(const C2Handle * handle,std::shared_ptr<C2LinearAllocation> * allocation)134 c2_status_t C2AllocatorBlob::priorLinearAllocation(
135         const C2Handle* handle, std::shared_ptr<C2LinearAllocation>* allocation) {
136     if (allocation == nullptr) {
137         return C2_BAD_VALUE;
138     }
139 
140     allocation->reset();
141 
142     if (!mC2AllocatorGralloc) {
143         return C2_CORRUPTED;
144     }
145 
146     std::shared_ptr<C2GraphicAllocation> graphicAllocation;
147     c2_status_t status = mC2AllocatorGralloc->priorGraphicAllocation(handle, &graphicAllocation);
148     if (status != C2_OK) {
149         ALOGE("Failed priorGraphicAllocation");
150         return status;
151     }
152 
153     const C2Handle* const grallocHandle = graphicAllocation->handle();
154     size_t capacity = 0;
155     status = GetCapacityFromHandle(grallocHandle, &capacity);
156     if (status != C2_OK) {
157         ALOGE("Failed to extract capacity from Handle");
158         return status;
159     }
160 
161     allocation->reset(new C2AllocationBlob(std::move(graphicAllocation), capacity, mTraits->id));
162     return C2_OK;
163 }
164 
getId() const165 id_t C2AllocatorBlob::getId() const {
166     return mTraits->id;
167 }
168 
getName() const169 C2String C2AllocatorBlob::getName() const {
170     return mTraits->name;
171 }
172 
getTraits() const173 std::shared_ptr<const C2Allocator::Traits> C2AllocatorBlob::getTraits() const {
174     return mTraits;
175 }
176 
177 // static
isValid(const C2Handle * const o)178 bool C2AllocatorBlob::isValid(const C2Handle* const o) {
179     size_t capacity;
180     // Distinguish C2Handle purely allocated by C2AllocatorGralloc, or one allocated through
181     // C2AllocatorBlob, by checking the handle's height is 1, and its format is
182     // PixelFormat::BLOB by GetCapacityFromHandle().
183     return C2AllocatorGralloc::isValid(o) && GetCapacityFromHandle(o, &capacity) == C2_OK;
184 }
185 
186 }  // namespace android
187