| /* |
| * Copyright 2017 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include <gtest/gtest.h> |
| |
| #include <C2AllocatorGralloc.h> |
| #include <C2Buffer.h> |
| #include <C2BufferPriv.h> |
| #include <C2Config.h> |
| #include <C2ParamDef.h> |
| #include <C2PlatformSupport.h> |
| |
| #include <system/graphics.h> |
| |
| namespace android { |
| |
| class C2BufferUtilsTest : public ::testing::Test { |
| static void StaticSegmentTest() { |
| // constructor |
| static_assert(C2Segment(123u, 456u).offset == 123, ""); |
| static_assert(C2Segment(123u, 456u).size == 456, ""); |
| |
| // empty |
| static_assert(!C2Segment(123u, 456u).isEmpty(), ""); |
| static_assert(C2Segment(123u, 0u).isEmpty(), ""); |
| |
| // valid |
| static_assert(C2Segment(123u, 456u).isValid(), ""); |
| static_assert(C2Segment(123u, ~123u).isValid(), ""); |
| static_assert(!C2Segment(123u, 1 + ~123u).isValid(), ""); |
| |
| // bool() |
| static_assert(C2Segment(123u, 456u), ""); |
| static_assert((bool)C2Segment(123u, ~123u), ""); |
| static_assert(!bool(C2Segment(123u, 1 + ~123u)), ""); |
| static_assert(!bool(C2Segment(123u, 0)), ""); |
| |
| // ! |
| static_assert(!!C2Segment(123u, 456u), ""); |
| static_assert(!!C2Segment(123u, ~123u), ""); |
| static_assert(!C2Segment(123u, 1 + ~123u), ""); |
| static_assert(!C2Segment(123u, 0), ""); |
| |
| // contains |
| static_assert(C2Segment(123u, ~123u).contains(C2Segment(123u, 0)), ""); |
| static_assert(!C2Segment(123u, 1 + ~123u).contains(C2Segment(123u, 0)), ""); |
| static_assert(C2Segment(123u, ~123u).contains(C2Segment(123u, ~123u)), ""); |
| static_assert(!C2Segment(123u, ~123u).contains(C2Segment(123u, 1 + ~123u)), ""); |
| static_assert(!C2Segment(123u, 1 + ~123u).contains(C2Segment(123u, 1 + ~123u)), ""); |
| static_assert(!C2Segment(123u, ~123u).contains(C2Segment(122u, 2u)), ""); |
| static_assert(C2Segment(123u, ~123u).contains(C2Segment(123u, 2u)), ""); |
| static_assert(C2Segment(123u, 3u).contains(C2Segment(124u, 2u)), ""); |
| static_assert(!C2Segment(123u, 3u).contains(C2Segment(125u, 2u)), ""); |
| |
| // == |
| static_assert(C2Segment(123u, 456u) == C2Segment(123u, 456u), ""); |
| static_assert(!(C2Segment(123u, 456u) == C2Segment(123u, 457u)), ""); |
| static_assert(!(C2Segment(123u, 456u) == C2Segment(123u, 455u)), ""); |
| static_assert(!(C2Segment(123u, 456u) == C2Segment(122u, 456u)), ""); |
| static_assert(!(C2Segment(123u, 456u) == C2Segment(124u, 456u)), ""); |
| static_assert(!(C2Segment(123u, 0u) == C2Segment(124u, 0u)), ""); |
| static_assert(C2Segment(123u, 0u) == C2Segment(123u, 0u), ""); |
| static_assert(C2Segment(123u, 1 + ~123u) == C2Segment(124u, 1 + ~124u), ""); |
| |
| // != |
| static_assert(!(C2Segment(123u, 456u) != C2Segment(123u, 456u)), ""); |
| static_assert(C2Segment(123u, 456u) != C2Segment(123u, 457u), ""); |
| static_assert(C2Segment(123u, 456u) != C2Segment(123u, 455u), ""); |
| static_assert(C2Segment(123u, 456u) != C2Segment(122u, 456u), ""); |
| static_assert(C2Segment(123u, 456u) != C2Segment(124u, 456u), ""); |
| static_assert(C2Segment(123u, 0u) != C2Segment(124u, 0u), ""); |
| static_assert(!(C2Segment(123u, 0u) != C2Segment(123u, 0u)), ""); |
| static_assert(!(C2Segment(123u, 1 + ~123u) != C2Segment(124u, 1 + ~124u)), ""); |
| |
| // <= |
| static_assert(C2Segment(123u, 456u) <= C2Segment(123u, 456u), ""); |
| static_assert(C2Segment(123u, 456u) <= C2Segment(123u, 457u), ""); |
| static_assert(C2Segment(123u, 456u) <= C2Segment(122u, 457u), ""); |
| static_assert(!(C2Segment(123u, 457u) <= C2Segment(123u, 456u)), ""); |
| static_assert(!(C2Segment(122u, 457u) <= C2Segment(123u, 456u)), ""); |
| static_assert(!(C2Segment(123u, 457u) <= C2Segment(124u, 457u)), ""); |
| static_assert(!(C2Segment(122u, 457u) <= C2Segment(123u, 457u)), ""); |
| static_assert(!(C2Segment(122u, 0u) <= C2Segment(123u, 0u)), ""); |
| static_assert(C2Segment(123u, 0u) <= C2Segment(122u, 1u), ""); |
| static_assert(C2Segment(122u, 0u) <= C2Segment(122u, 1u), ""); |
| static_assert(!(C2Segment(122u, ~122u) <= C2Segment(122u, 1 + ~122u)), ""); |
| static_assert(!(C2Segment(122u, 1 + ~122u) <= C2Segment(122u, ~122u)), ""); |
| static_assert(!(C2Segment(122u, 1 + ~122u) <= C2Segment(122u, 1 + ~122u)), ""); |
| |
| // < |
| static_assert(!(C2Segment(123u, 456u) < C2Segment(123u, 456u)), ""); |
| static_assert(C2Segment(123u, 456u) < C2Segment(123u, 457u), ""); |
| static_assert(C2Segment(123u, 456u) < C2Segment(122u, 457u), ""); |
| static_assert(!(C2Segment(123u, 457u) < C2Segment(123u, 456u)), ""); |
| static_assert(!(C2Segment(122u, 457u) < C2Segment(123u, 456u)), ""); |
| static_assert(!(C2Segment(123u, 457u) < C2Segment(124u, 457u)), ""); |
| static_assert(!(C2Segment(122u, 457u) < C2Segment(123u, 457u)), ""); |
| static_assert(!(C2Segment(122u, 0u) < C2Segment(123u, 0u)), ""); |
| static_assert(C2Segment(123u, 0u) < C2Segment(122u, 1u), ""); |
| static_assert(C2Segment(122u, 0u) < C2Segment(122u, 1u), ""); |
| static_assert(!(C2Segment(122u, ~122u) < C2Segment(122u, 1 + ~122u)), ""); |
| static_assert(!(C2Segment(122u, 1 + ~122u) < C2Segment(122u, ~122u)), ""); |
| static_assert(!(C2Segment(122u, 1 + ~122u) < C2Segment(122u, 1 + ~122u)), ""); |
| |
| // <= |
| static_assert(C2Segment(123u, 456u) >= C2Segment(123u, 456u), ""); |
| static_assert(C2Segment(123u, 457u) >= C2Segment(123u, 456u), ""); |
| static_assert(C2Segment(122u, 457u) >= C2Segment(123u, 456u), ""); |
| static_assert(!(C2Segment(123u, 456u) >= C2Segment(123u, 457u)), ""); |
| static_assert(!(C2Segment(123u, 456u) >= C2Segment(122u, 457u)), ""); |
| static_assert(!(C2Segment(124u, 457u) >= C2Segment(123u, 457u)), ""); |
| static_assert(!(C2Segment(123u, 457u) >= C2Segment(122u, 457u)), ""); |
| static_assert(!(C2Segment(123u, 0u) >= C2Segment(122u, 0u)), ""); |
| static_assert(C2Segment(122u, 1u) >= C2Segment(123u, 0u), ""); |
| static_assert(C2Segment(122u, 1u) >= C2Segment(122u, 0u), ""); |
| static_assert(!(C2Segment(122u, 1 + ~122u) >= C2Segment(122u, ~122u)), ""); |
| static_assert(!(C2Segment(122u, ~122u) >= C2Segment(122u, 1 + ~122u)), ""); |
| static_assert(!(C2Segment(122u, 1 + ~122u) >= C2Segment(122u, 1 + ~122u)), ""); |
| |
| // < |
| static_assert(!(C2Segment(123u, 456u) > C2Segment(123u, 456u)), ""); |
| static_assert(C2Segment(123u, 457u) > C2Segment(123u, 456u), ""); |
| static_assert(C2Segment(122u, 457u) > C2Segment(123u, 456u), ""); |
| static_assert(!(C2Segment(123u, 456u) > C2Segment(123u, 457u)), ""); |
| static_assert(!(C2Segment(123u, 456u) > C2Segment(122u, 457u)), ""); |
| static_assert(!(C2Segment(124u, 457u) > C2Segment(123u, 457u)), ""); |
| static_assert(!(C2Segment(123u, 457u) > C2Segment(122u, 457u)), ""); |
| static_assert(!(C2Segment(123u, 0u) > C2Segment(122u, 0u)), ""); |
| static_assert(C2Segment(122u, 1u) > C2Segment(123u, 0u), ""); |
| static_assert(C2Segment(122u, 1u) > C2Segment(122u, 0u), ""); |
| static_assert(!(C2Segment(122u, 1 + ~122u) > C2Segment(122u, ~122u)), ""); |
| static_assert(!(C2Segment(122u, ~122u) > C2Segment(122u, 1 + ~122u)), ""); |
| static_assert(!(C2Segment(122u, 1 + ~122u) > C2Segment(122u, 1 + ~122u)), ""); |
| |
| // end |
| static_assert(C2Segment(123u, 456u).end() == 579u, ""); |
| static_assert(C2Segment(123u, 0u).end() == 123u, ""); |
| static_assert(C2Segment(123u, ~123u).end() == 0xffffffffu, ""); |
| static_assert(C2Segment(123u, 1 + ~123u).end() == 0u, ""); |
| |
| // intersect |
| static_assert(C2Segment(123u, 456u).intersect(C2Segment(123u, 456u)) == C2Segment(123u, 456u), ""); |
| static_assert(C2Segment(123u, 456u).intersect(C2Segment(123u, 460u)) == C2Segment(123u, 456u), ""); |
| static_assert(C2Segment(123u, 456u).intersect(C2Segment(124u, 460u)) == C2Segment(124u, 455u), ""); |
| static_assert(C2Segment(123u, 456u).intersect(C2Segment(579u, 460u)) == C2Segment(579u, 0u), ""); |
| static_assert(C2Segment(123u, 456u).intersect(C2Segment(589u, 460u)) == C2Segment(589u, ~9u /* -10 */), ""); |
| static_assert(C2Segment(123u, 456u).intersect(C2Segment(123u, 455u)) == C2Segment(123u, 455u), ""); |
| static_assert(C2Segment(123u, 456u).intersect(C2Segment(122u, 456u)) == C2Segment(123u, 455u), ""); |
| static_assert(C2Segment(123u, 456u).intersect(C2Segment(0u, 123u)) == C2Segment(123u, 0u), ""); |
| static_assert(C2Segment(123u, 456u).intersect(C2Segment(0u, 0u)) == C2Segment(123u, ~122u /* -123 */), ""); |
| |
| // normalize (change invalid segments to empty segments) |
| static_assert(C2Segment(123u, 456u).normalize() == C2Segment(123u, 456u), ""); |
| static_assert(C2Segment(123u, ~123u).normalize() == C2Segment(123u, ~123u), ""); |
| static_assert(C2Segment(123u, 1 + ~123u).normalize() == C2Segment(123u, 0u), ""); |
| |
| // note: normalize cannot be used to make this work |
| static_assert(C2Segment(123u, 456u).intersect(C2Segment(150u, ~150u)).normalize() == C2Segment(150u, 429u), ""); |
| static_assert(C2Segment(123u, 456u).intersect(C2Segment(150u, 1 + ~150u)).normalize() != C2Segment(150u, 429u), ""); |
| static_assert(C2Segment(123u, 456u).intersect(C2Segment(150u, 1 + ~150u)).normalize() == C2Segment(150u, 0u), ""); |
| |
| // saturate (change invalid segments to full segments up to max) |
| static_assert(C2Segment(123u, 456u).saturate() == C2Segment(123u, 456u), ""); |
| static_assert(C2Segment(123u, ~123u).saturate() == C2Segment(123u, ~123u), ""); |
| static_assert(C2Segment(123u, 1 + ~123u).saturate() == C2Segment(123u, ~123u), ""); |
| |
| // note: saturate can be used to make this work but only partially |
| static_assert(C2Segment(123u, 456u).intersect(C2Segment(150u, 1 + ~150u).saturate()).normalize() == C2Segment(150u, 429u), ""); |
| static_assert(C2Segment(123u, 456u).intersect(C2Segment(0u, 100u).saturate()).normalize() == C2Segment(123u, 0u), ""); |
| static_assert(C2Segment(123u, 456u).intersect(C2Segment(1000u, 100u).saturate()).normalize() != C2Segment(579u, 0u), ""); |
| static_assert(C2Segment(123u, 456u).intersect(C2Segment(1000u, 100u).saturate()).normalize() == C2Segment(1000u, 0u), ""); |
| |
| } |
| |
| static void StaticLinearRangeAndCapacityTest() { |
| class TestCapacity : public _C2LinearCapacityAspect { |
| using _C2LinearCapacityAspect::_C2LinearCapacityAspect; |
| friend class C2BufferUtilsTest; |
| }; |
| |
| class TestRange : public _C2LinearRangeAspect { |
| using _C2LinearRangeAspect::_C2LinearRangeAspect; |
| friend class C2BufferUtilsTest; |
| }; |
| |
| // _C2LinearCapacityAspect |
| static_assert(TestCapacity(0u).capacity() == 0u, ""); |
| constexpr TestCapacity cap(123u); |
| static_assert(TestCapacity(&cap).capacity() == 123u, ""); |
| static_assert(TestCapacity(nullptr).capacity() == 0u, ""); |
| |
| // _C2LinearCapacityRange |
| static_assert(TestRange(&cap).capacity() == 123u, ""); |
| static_assert(TestRange(&cap).offset() == 0u, ""); |
| static_assert(TestRange(&cap).size() == 123u, ""); |
| static_assert(TestRange(&cap).endOffset() == 123u, ""); |
| |
| constexpr TestRange range(&cap, 50u, 100u); |
| |
| static_assert(range.capacity() == 123u, ""); |
| static_assert(range.offset() == 50u, ""); |
| static_assert(range.size() == 73u, ""); |
| static_assert(range.endOffset() == 123u, ""); |
| |
| static_assert(TestRange(&cap, 20u, 30u).capacity() == 123u, ""); |
| static_assert(TestRange(&cap, 20u, 30u).offset() == 20u, ""); |
| static_assert(TestRange(&cap, 20u, 30u).size() == 30u, ""); |
| static_assert(TestRange(&cap, 20u, 30u).endOffset() == 50u, ""); |
| |
| static_assert(TestRange(&cap, 200u, 30u).capacity() == 123u, ""); |
| static_assert(TestRange(&cap, 200u, 30u).offset() == 123u, ""); |
| static_assert(TestRange(&cap, 200u, 30u).size() == 0u, ""); |
| static_assert(TestRange(&cap, 200u, 30u).endOffset() == 123u, ""); |
| |
| } |
| |
| }; |
| |
| |
| class C2BufferTest : public ::testing::Test { |
| public: |
| C2BufferTest() |
| : mBlockPoolId(C2BlockPool::PLATFORM_START), |
| mSize(0u), |
| mAddr(nullptr), |
| mGraphicAllocator(std::make_shared<C2AllocatorGralloc>('g')) { |
| getLinearAllocator(&mLinearAllocator); |
| } |
| |
| ~C2BufferTest() = default; |
| |
| void allocateLinear(size_t capacity) { |
| c2_status_t err = mLinearAllocator->newLinearAllocation( |
| capacity, |
| { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE }, |
| &mLinearAllocation); |
| if (err != C2_OK) { |
| mLinearAllocation.reset(); |
| FAIL() << "C2Allocator::newLinearAllocation() failed: " << err; |
| } |
| } |
| |
| void mapLinear(size_t offset, size_t size, uint8_t **addr) { |
| ASSERT_TRUE(mLinearAllocation); |
| c2_status_t err = mLinearAllocation->map( |
| offset, |
| size, |
| { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE }, |
| // TODO: fence |
| nullptr, |
| &mAddr); |
| if (err != C2_OK) { |
| mAddr = nullptr; |
| FAIL() << "C2LinearAllocation::map() failed: " << err; |
| } |
| ASSERT_NE(nullptr, mAddr); |
| mSize = size; |
| *addr = (uint8_t *)mAddr; |
| } |
| |
| void unmapLinear() { |
| ASSERT_TRUE(mLinearAllocation); |
| ASSERT_NE(nullptr, mAddr); |
| ASSERT_NE(0u, mSize); |
| |
| // TODO: fence |
| ASSERT_EQ(C2_OK, mLinearAllocation->unmap(mAddr, mSize, nullptr)); |
| mSize = 0u; |
| mAddr = nullptr; |
| } |
| |
| std::shared_ptr<C2BlockPool> makeLinearBlockPool() { |
| return std::make_shared<C2PooledBlockPool>(mLinearAllocator, mBlockPoolId++); |
| } |
| |
| void allocateGraphic(uint32_t width, uint32_t height) { |
| c2_status_t err = mGraphicAllocator->newGraphicAllocation( |
| width, |
| height, |
| HAL_PIXEL_FORMAT_YCBCR_420_888, |
| { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE }, |
| &mGraphicAllocation); |
| if (err != C2_OK) { |
| mGraphicAllocation.reset(); |
| FAIL() << "C2Allocator::newGraphicAllocation() failed: " << err; |
| } |
| } |
| |
| void mapGraphic(C2Rect rect, C2PlanarLayout *layout, uint8_t **addr) { |
| ASSERT_TRUE(mGraphicAllocation); |
| c2_status_t err = mGraphicAllocation->map( |
| rect, |
| { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE }, |
| // TODO: fence |
| nullptr, |
| layout, |
| addr); |
| if (err != C2_OK) { |
| addr[C2PlanarLayout::PLANE_Y] = nullptr; |
| addr[C2PlanarLayout::PLANE_U] = nullptr; |
| addr[C2PlanarLayout::PLANE_V] = nullptr; |
| FAIL() << "C2GraphicAllocation::map() failed: " << err; |
| } |
| mMappedRect = rect; |
| memcpy(mAddrGraphic, addr, sizeof(uint8_t*) * C2PlanarLayout::MAX_NUM_PLANES); |
| } |
| |
| void unmapGraphic() { |
| ASSERT_TRUE(mGraphicAllocation); |
| |
| // TODO: fence |
| ASSERT_EQ(C2_OK, mGraphicAllocation->unmap(mAddrGraphic, mMappedRect, nullptr)); |
| } |
| |
| std::shared_ptr<C2BlockPool> makeGraphicBlockPool() { |
| return std::make_shared<C2BasicGraphicBlockPool>(mGraphicAllocator); |
| } |
| |
| private: |
| void getLinearAllocator(std::shared_ptr<C2Allocator>* mLinearAllocator) { |
| std::shared_ptr<C2AllocatorStore> store = android::GetCodec2PlatformAllocatorStore(); |
| ASSERT_EQ(store->fetchAllocator(C2AllocatorStore::DEFAULT_LINEAR, mLinearAllocator), C2_OK); |
| } |
| |
| C2BlockPool::local_id_t mBlockPoolId; |
| std::shared_ptr<C2Allocator> mLinearAllocator; |
| std::shared_ptr<C2LinearAllocation> mLinearAllocation; |
| size_t mSize; |
| void *mAddr; |
| C2Rect mMappedRect; |
| uint8_t* mAddrGraphic[C2PlanarLayout::MAX_NUM_PLANES]; |
| |
| std::shared_ptr<C2Allocator> mGraphicAllocator; |
| std::shared_ptr<C2GraphicAllocation> mGraphicAllocation; |
| }; |
| |
| TEST_F(C2BufferTest, LinearAllocationTest) { |
| constexpr size_t kCapacity = 1024u * 1024u; |
| |
| allocateLinear(kCapacity); |
| |
| uint8_t *addr = nullptr; |
| mapLinear(0u, kCapacity, &addr); |
| ASSERT_NE(nullptr, addr); |
| |
| for (size_t i = 0; i < kCapacity; ++i) { |
| addr[i] = i % 100u; |
| } |
| |
| unmapLinear(); |
| addr = nullptr; |
| |
| mapLinear(kCapacity / 3, kCapacity / 3, &addr); |
| ASSERT_NE(nullptr, addr); |
| for (size_t i = 0; i < kCapacity / 3; ++i) { |
| ASSERT_EQ((i + kCapacity / 3) % 100, addr[i]) << " at i = " << i; |
| } |
| } |
| |
| TEST_F(C2BufferTest, BlockPoolTest) { |
| constexpr size_t kCapacity = 1024u * 1024u; |
| |
| std::shared_ptr<C2BlockPool> blockPool(makeLinearBlockPool()); |
| |
| std::shared_ptr<C2LinearBlock> block; |
| ASSERT_EQ(C2_OK, blockPool->fetchLinearBlock( |
| kCapacity, |
| { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE }, |
| &block)); |
| ASSERT_TRUE(block); |
| |
| C2Acquirable<C2WriteView> writeViewHolder = block->map(); |
| C2WriteView writeView = writeViewHolder.get(); |
| ASSERT_EQ(C2_OK, writeView.error()); |
| ASSERT_EQ(kCapacity, writeView.capacity()); |
| ASSERT_EQ(0u, writeView.offset()); |
| ASSERT_EQ(kCapacity, writeView.size()); |
| |
| uint8_t *data = writeView.data(); |
| ASSERT_NE(nullptr, data); |
| for (size_t i = 0; i < writeView.size(); ++i) { |
| data[i] = i % 100u; |
| } |
| |
| writeView.setOffset(kCapacity / 3); |
| data = writeView.data(); |
| ASSERT_NE(nullptr, data); |
| for (size_t i = 0; i < writeView.size(); ++i) { |
| ASSERT_EQ((i + kCapacity / 3) % 100u, data[i]) << " at i = " << i |
| << "; data = " << static_cast<void *>(data); |
| } |
| |
| C2Fence fence; |
| C2ConstLinearBlock constBlock = block->share( |
| kCapacity / 3, kCapacity / 3, fence); |
| |
| C2Acquirable<C2ReadView> readViewHolder = constBlock.map(); |
| C2ReadView readView = readViewHolder.get(); |
| ASSERT_EQ(C2_OK, readView.error()); |
| ASSERT_EQ(kCapacity / 3, readView.capacity()); |
| |
| // TODO: fence |
| const uint8_t *constData = readView.data(); |
| ASSERT_NE(nullptr, constData); |
| for (size_t i = 0; i < readView.capacity(); ++i) { |
| ASSERT_EQ((i + kCapacity / 3) % 100u, constData[i]) << " at i = " << i |
| << "; data = " << static_cast<void *>(data) |
| << "; constData = " << static_cast<const void *>(constData); |
| } |
| |
| readView = readView.subView(333u, 100u); |
| ASSERT_EQ(C2_OK, readView.error()); |
| ASSERT_EQ(100u, readView.capacity()); |
| |
| constData = readView.data(); |
| ASSERT_NE(nullptr, constData); |
| for (size_t i = 0; i < readView.capacity(); ++i) { |
| ASSERT_EQ((i + 333u + kCapacity / 3) % 100u, constData[i]) << " at i = " << i; |
| } |
| } |
| |
| void fillPlane(const C2Rect rect, const C2PlaneInfo info, uint8_t *addr, uint8_t value) { |
| for (uint32_t row = 0; row < rect.height / info.rowSampling; ++row) { |
| int32_t rowOffset = (row + rect.top / info.rowSampling) * info.rowInc; |
| for (uint32_t col = 0; col < rect.width / info.colSampling; ++col) { |
| int32_t colOffset = (col + rect.left / info.colSampling) * info.colInc; |
| addr[rowOffset + colOffset] = value; |
| } |
| } |
| } |
| |
| bool verifyPlane(const C2Rect rect, const C2PlaneInfo info, const uint8_t *addr, uint8_t value) { |
| for (uint32_t row = 0; row < rect.height / info.rowSampling; ++row) { |
| int32_t rowOffset = (row + rect.top / info.rowSampling) * info.rowInc; |
| for (uint32_t col = 0; col < rect.width / info.colSampling; ++col) { |
| int32_t colOffset = (col + rect.left / info.colSampling) * info.colInc; |
| if (addr[rowOffset + colOffset] != value) { |
| return false; |
| } |
| } |
| } |
| return true; |
| } |
| |
| TEST_F(C2BufferTest, GraphicAllocationTest) { |
| constexpr uint32_t kWidth = 320; |
| constexpr uint32_t kHeight = 240; |
| |
| allocateGraphic(kWidth, kHeight); |
| |
| uint8_t *addr[C2PlanarLayout::MAX_NUM_PLANES]; |
| C2Rect rect(kWidth, kHeight); |
| C2PlanarLayout layout; |
| mapGraphic(rect, &layout, addr); |
| ASSERT_NE(nullptr, addr[C2PlanarLayout::PLANE_Y]); |
| ASSERT_NE(nullptr, addr[C2PlanarLayout::PLANE_U]); |
| ASSERT_NE(nullptr, addr[C2PlanarLayout::PLANE_V]); |
| |
| uint8_t *y = addr[C2PlanarLayout::PLANE_Y]; |
| C2PlaneInfo yInfo = layout.planes[C2PlanarLayout::PLANE_Y]; |
| uint8_t *u = addr[C2PlanarLayout::PLANE_U]; |
| C2PlaneInfo uInfo = layout.planes[C2PlanarLayout::PLANE_U]; |
| uint8_t *v = addr[C2PlanarLayout::PLANE_V]; |
| C2PlaneInfo vInfo = layout.planes[C2PlanarLayout::PLANE_V]; |
| |
| fillPlane(rect, yInfo, y, 0); |
| fillPlane(rect, uInfo, u, 0); |
| fillPlane(rect, vInfo, v, 0); |
| fillPlane(C2Rect(kWidth / 2, kHeight / 2).at(kWidth / 4, kHeight / 4), yInfo, y, 0x12); |
| fillPlane(C2Rect(kWidth / 2, kHeight / 2).at(kWidth / 4, kHeight / 4), uInfo, u, 0x34); |
| fillPlane(C2Rect(kWidth / 2, kHeight / 2).at(kWidth / 4, kHeight / 4), vInfo, v, 0x56); |
| |
| unmapGraphic(); |
| |
| mapGraphic(rect, &layout, addr); |
| ASSERT_NE(nullptr, addr[C2PlanarLayout::PLANE_Y]); |
| ASSERT_NE(nullptr, addr[C2PlanarLayout::PLANE_U]); |
| ASSERT_NE(nullptr, addr[C2PlanarLayout::PLANE_V]); |
| |
| y = addr[C2PlanarLayout::PLANE_Y]; |
| yInfo = layout.planes[C2PlanarLayout::PLANE_Y]; |
| u = addr[C2PlanarLayout::PLANE_U]; |
| uInfo = layout.planes[C2PlanarLayout::PLANE_U]; |
| v = addr[C2PlanarLayout::PLANE_V]; |
| vInfo = layout.planes[C2PlanarLayout::PLANE_V]; |
| |
| ASSERT_TRUE(verifyPlane(C2Rect(kWidth / 2, kHeight / 2).at(kWidth / 4, kHeight / 4), yInfo, y, 0x12)); |
| ASSERT_TRUE(verifyPlane(C2Rect(kWidth / 2, kHeight / 2).at(kWidth / 4, kHeight / 4), uInfo, u, 0x34)); |
| ASSERT_TRUE(verifyPlane(C2Rect(kWidth / 2, kHeight / 2).at(kWidth / 4, kHeight / 4), vInfo, v, 0x56)); |
| ASSERT_TRUE(verifyPlane({ kWidth, kHeight / 4 }, yInfo, y, 0)); |
| ASSERT_TRUE(verifyPlane({ kWidth, kHeight / 4 }, uInfo, u, 0)); |
| ASSERT_TRUE(verifyPlane({ kWidth, kHeight / 4 }, vInfo, v, 0)); |
| ASSERT_TRUE(verifyPlane({ kWidth / 4, kHeight }, yInfo, y, 0)); |
| ASSERT_TRUE(verifyPlane({ kWidth / 4, kHeight }, uInfo, u, 0)); |
| ASSERT_TRUE(verifyPlane({ kWidth / 4, kHeight }, vInfo, v, 0)); |
| } |
| |
| TEST_F(C2BufferTest, GraphicBlockPoolTest) { |
| constexpr uint32_t kWidth = 320; |
| constexpr uint32_t kHeight = 240; |
| |
| std::shared_ptr<C2BlockPool> blockPool(makeGraphicBlockPool()); |
| |
| std::shared_ptr<C2GraphicBlock> block; |
| ASSERT_EQ(C2_OK, blockPool->fetchGraphicBlock( |
| kWidth, |
| kHeight, |
| HAL_PIXEL_FORMAT_YCBCR_420_888, |
| { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE }, |
| &block)); |
| ASSERT_TRUE(block); |
| |
| C2Acquirable<C2GraphicView> graphicViewHolder = block->map(); |
| C2GraphicView graphicView = graphicViewHolder.get(); |
| ASSERT_EQ(C2_OK, graphicView.error()); |
| ASSERT_EQ(kWidth, graphicView.width()); |
| ASSERT_EQ(kHeight, graphicView.height()); |
| |
| uint8_t *const *data = graphicView.data(); |
| C2PlanarLayout layout = graphicView.layout(); |
| ASSERT_NE(nullptr, data); |
| |
| uint8_t *y = data[C2PlanarLayout::PLANE_Y]; |
| C2PlaneInfo yInfo = layout.planes[C2PlanarLayout::PLANE_Y]; |
| uint8_t *u = data[C2PlanarLayout::PLANE_U]; |
| C2PlaneInfo uInfo = layout.planes[C2PlanarLayout::PLANE_U]; |
| uint8_t *v = data[C2PlanarLayout::PLANE_V]; |
| C2PlaneInfo vInfo = layout.planes[C2PlanarLayout::PLANE_V]; |
| |
| fillPlane({ kWidth, kHeight }, yInfo, y, 0); |
| fillPlane({ kWidth, kHeight }, uInfo, u, 0); |
| fillPlane({ kWidth, kHeight }, vInfo, v, 0); |
| fillPlane(C2Rect(kWidth / 2, kHeight / 2).at(kWidth / 4, kHeight / 4), yInfo, y, 0x12); |
| fillPlane(C2Rect(kWidth / 2, kHeight / 2).at(kWidth / 4, kHeight / 4), uInfo, u, 0x34); |
| fillPlane(C2Rect(kWidth / 2, kHeight / 2).at(kWidth / 4, kHeight / 4), vInfo, v, 0x56); |
| |
| C2Fence fence; |
| C2ConstGraphicBlock constBlock = block->share(C2Rect(kWidth, kHeight), fence); |
| block.reset(); |
| |
| C2Acquirable<const C2GraphicView> constViewHolder = constBlock.map(); |
| const C2GraphicView constGraphicView = constViewHolder.get(); |
| ASSERT_EQ(C2_OK, constGraphicView.error()); |
| ASSERT_EQ(kWidth, constGraphicView.width()); |
| ASSERT_EQ(kHeight, constGraphicView.height()); |
| |
| const uint8_t *const *constData = constGraphicView.data(); |
| layout = graphicView.layout(); |
| ASSERT_NE(nullptr, constData); |
| |
| const uint8_t *cy = constData[C2PlanarLayout::PLANE_Y]; |
| yInfo = layout.planes[C2PlanarLayout::PLANE_Y]; |
| const uint8_t *cu = constData[C2PlanarLayout::PLANE_U]; |
| uInfo = layout.planes[C2PlanarLayout::PLANE_U]; |
| const uint8_t *cv = constData[C2PlanarLayout::PLANE_V]; |
| vInfo = layout.planes[C2PlanarLayout::PLANE_V]; |
| |
| ASSERT_TRUE(verifyPlane(C2Rect(kWidth / 2, kHeight / 2).at(kWidth / 4, kHeight / 4), yInfo, cy, 0x12)); |
| ASSERT_TRUE(verifyPlane(C2Rect(kWidth / 2, kHeight / 2).at(kWidth / 4, kHeight / 4), uInfo, cu, 0x34)); |
| ASSERT_TRUE(verifyPlane(C2Rect(kWidth / 2, kHeight / 2).at(kWidth / 4, kHeight / 4), vInfo, cv, 0x56)); |
| ASSERT_TRUE(verifyPlane({ kWidth, kHeight / 4 }, yInfo, cy, 0)); |
| ASSERT_TRUE(verifyPlane({ kWidth, kHeight / 4 }, uInfo, cu, 0)); |
| ASSERT_TRUE(verifyPlane({ kWidth, kHeight / 4 }, vInfo, cv, 0)); |
| ASSERT_TRUE(verifyPlane({ kWidth / 4, kHeight }, yInfo, cy, 0)); |
| ASSERT_TRUE(verifyPlane({ kWidth / 4, kHeight }, uInfo, cu, 0)); |
| ASSERT_TRUE(verifyPlane({ kWidth / 4, kHeight }, vInfo, cv, 0)); |
| } |
| |
| class BufferData : public C2BufferData { |
| public: |
| explicit BufferData(const std::vector<C2ConstLinearBlock> &blocks) : C2BufferData(blocks) {} |
| explicit BufferData(const std::vector<C2ConstGraphicBlock> &blocks) : C2BufferData(blocks) {} |
| }; |
| |
| class Buffer : public C2Buffer { |
| public: |
| explicit Buffer(const std::vector<C2ConstLinearBlock> &blocks) : C2Buffer(blocks) {} |
| explicit Buffer(const std::vector<C2ConstGraphicBlock> &blocks) : C2Buffer(blocks) {} |
| }; |
| |
| TEST_F(C2BufferTest, BufferDataTest) { |
| std::shared_ptr<C2BlockPool> linearBlockPool(makeLinearBlockPool()); |
| std::shared_ptr<C2BlockPool> graphicBlockPool(makeGraphicBlockPool()); |
| |
| constexpr uint32_t kWidth1 = 320; |
| constexpr uint32_t kHeight1 = 240; |
| constexpr C2Rect kCrop1(kWidth1, kHeight1); |
| constexpr uint32_t kWidth2 = 176; |
| constexpr uint32_t kHeight2 = 144; |
| constexpr C2Rect kCrop2(kWidth2, kHeight2); |
| constexpr size_t kCapacity1 = 1024u; |
| constexpr size_t kCapacity2 = 2048u; |
| |
| std::shared_ptr<C2LinearBlock> linearBlock1; |
| std::shared_ptr<C2LinearBlock> linearBlock2; |
| ASSERT_EQ(C2_OK, linearBlockPool->fetchLinearBlock( |
| kCapacity1, |
| { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE }, |
| &linearBlock1)); |
| ASSERT_EQ(C2_OK, linearBlockPool->fetchLinearBlock( |
| kCapacity2, |
| { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE }, |
| &linearBlock2)); |
| std::shared_ptr<C2GraphicBlock> graphicBlock1; |
| std::shared_ptr<C2GraphicBlock> graphicBlock2; |
| ASSERT_EQ(C2_OK, graphicBlockPool->fetchGraphicBlock( |
| kWidth1, |
| kHeight1, |
| HAL_PIXEL_FORMAT_YCBCR_420_888, |
| { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE }, |
| &graphicBlock1)); |
| ASSERT_EQ(C2_OK, graphicBlockPool->fetchGraphicBlock( |
| kWidth2, |
| kHeight2, |
| HAL_PIXEL_FORMAT_YCBCR_420_888, |
| { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE }, |
| &graphicBlock2)); |
| |
| std::shared_ptr<C2BufferData> data(new BufferData({ linearBlock1->share(0, kCapacity1, C2Fence()) })); |
| EXPECT_EQ(C2BufferData::LINEAR, data->type()); |
| ASSERT_EQ(1u, data->linearBlocks().size()); |
| EXPECT_EQ(linearBlock1->handle(), data->linearBlocks().front().handle()); |
| EXPECT_TRUE(data->graphicBlocks().empty()); |
| |
| data.reset(new BufferData({ |
| linearBlock1->share(0, kCapacity1, C2Fence()), |
| linearBlock2->share(0, kCapacity2, C2Fence()), |
| })); |
| EXPECT_EQ(C2BufferData::LINEAR_CHUNKS, data->type()); |
| ASSERT_EQ(2u, data->linearBlocks().size()); |
| EXPECT_EQ(linearBlock1->handle(), data->linearBlocks().front().handle()); |
| EXPECT_EQ(linearBlock2->handle(), data->linearBlocks().back().handle()); |
| EXPECT_TRUE(data->graphicBlocks().empty()); |
| |
| data.reset(new BufferData({ graphicBlock1->share(kCrop1, C2Fence()) })); |
| EXPECT_EQ(C2BufferData::GRAPHIC, data->type()); |
| ASSERT_EQ(1u, data->graphicBlocks().size()); |
| EXPECT_EQ(graphicBlock1->handle(), data->graphicBlocks().front().handle()); |
| EXPECT_TRUE(data->linearBlocks().empty()); |
| |
| data.reset(new BufferData({ |
| graphicBlock1->share(kCrop1, C2Fence()), |
| graphicBlock2->share(kCrop2, C2Fence()), |
| })); |
| EXPECT_EQ(C2BufferData::GRAPHIC_CHUNKS, data->type()); |
| ASSERT_EQ(2u, data->graphicBlocks().size()); |
| EXPECT_EQ(graphicBlock1->handle(), data->graphicBlocks().front().handle()); |
| EXPECT_EQ(graphicBlock2->handle(), data->graphicBlocks().back().handle()); |
| EXPECT_TRUE(data->linearBlocks().empty()); |
| } |
| |
| void DestroyCallback(const C2Buffer * /* buf */, void *arg) { |
| std::function<void(void)> *cb = (std::function<void(void)> *)arg; |
| (*cb)(); |
| } |
| |
| enum : uint32_t { |
| kParamIndexNumber1, |
| kParamIndexNumber2, |
| }; |
| |
| typedef C2GlobalParam<C2Info, C2Int32Value, kParamIndexNumber1> C2Number1Info; |
| typedef C2GlobalParam<C2Info, C2Int32Value, kParamIndexNumber2> C2Number2Info; |
| |
| TEST_F(C2BufferTest, BufferTest) { |
| std::shared_ptr<C2BlockPool> alloc(makeLinearBlockPool()); |
| constexpr size_t kCapacity = 1024u; |
| std::shared_ptr<C2LinearBlock> block; |
| |
| ASSERT_EQ(C2_OK, alloc->fetchLinearBlock( |
| kCapacity, |
| { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE }, |
| &block)); |
| |
| std::atomic_bool destroyed(false); |
| std::function<void(void)> arg = [&destroyed](){ destroyed = true; }; |
| |
| std::shared_ptr<C2Buffer> buffer(new Buffer( { block->share(0, kCapacity, C2Fence()) })); |
| ASSERT_EQ(C2_OK, buffer->registerOnDestroyNotify(&DestroyCallback, &arg)); |
| EXPECT_FALSE(destroyed); |
| ASSERT_EQ(C2_DUPLICATE, buffer->registerOnDestroyNotify(&DestroyCallback, &arg)); |
| buffer.reset(); |
| EXPECT_TRUE(destroyed); |
| |
| buffer.reset(new Buffer( { block->share(0, kCapacity, C2Fence()) })); |
| destroyed = false; |
| ASSERT_EQ(C2_OK, buffer->registerOnDestroyNotify(&DestroyCallback, &arg)); |
| EXPECT_FALSE(destroyed); |
| ASSERT_EQ(C2_NOT_FOUND, buffer->unregisterOnDestroyNotify(&DestroyCallback, nullptr)); |
| ASSERT_EQ(C2_OK, buffer->unregisterOnDestroyNotify(&DestroyCallback, &arg)); |
| EXPECT_FALSE(destroyed); |
| ASSERT_EQ(C2_NOT_FOUND, buffer->unregisterOnDestroyNotify(&DestroyCallback, &arg)); |
| buffer.reset(); |
| EXPECT_FALSE(destroyed); |
| |
| std::shared_ptr<C2Info> info1(new C2Number1Info(1)); |
| std::shared_ptr<C2Info> info2(new C2Number2Info(2)); |
| buffer.reset(new Buffer( { block->share(0, kCapacity, C2Fence()) })); |
| EXPECT_TRUE(buffer->info().empty()); |
| EXPECT_FALSE(buffer->hasInfo(info1->type())); |
| EXPECT_FALSE(buffer->hasInfo(info2->type())); |
| |
| ASSERT_EQ(C2_OK, buffer->setInfo(info1)); |
| EXPECT_EQ(1u, buffer->info().size()); |
| EXPECT_EQ(*info1, *buffer->info().front()); |
| EXPECT_TRUE(buffer->hasInfo(info1->type())); |
| EXPECT_FALSE(buffer->hasInfo(info2->type())); |
| |
| ASSERT_EQ(C2_OK, buffer->setInfo(info2)); |
| EXPECT_EQ(2u, buffer->info().size()); |
| EXPECT_TRUE(buffer->hasInfo(info1->type())); |
| EXPECT_TRUE(buffer->hasInfo(info2->type())); |
| |
| std::shared_ptr<C2Info> removed = buffer->removeInfo(info1->type()); |
| ASSERT_TRUE(removed); |
| EXPECT_EQ(*removed, *info1); |
| EXPECT_EQ(1u, buffer->info().size()); |
| EXPECT_EQ(*info2, *buffer->info().front()); |
| EXPECT_FALSE(buffer->hasInfo(info1->type())); |
| EXPECT_TRUE(buffer->hasInfo(info2->type())); |
| |
| removed = buffer->removeInfo(info1->type()); |
| ASSERT_FALSE(removed); |
| EXPECT_EQ(1u, buffer->info().size()); |
| EXPECT_FALSE(buffer->hasInfo(info1->type())); |
| EXPECT_TRUE(buffer->hasInfo(info2->type())); |
| |
| std::shared_ptr<C2Info> info3(new C2Number2Info(3)); |
| ASSERT_EQ(C2_OK, buffer->setInfo(info3)); |
| EXPECT_EQ(1u, buffer->info().size()); |
| EXPECT_FALSE(buffer->hasInfo(info1->type())); |
| EXPECT_TRUE(buffer->hasInfo(info2->type())); |
| |
| removed = buffer->removeInfo(info2->type()); |
| ASSERT_TRUE(removed); |
| EXPECT_EQ(*info3, *removed); |
| EXPECT_TRUE(buffer->info().empty()); |
| EXPECT_FALSE(buffer->hasInfo(info1->type())); |
| EXPECT_FALSE(buffer->hasInfo(info2->type())); |
| } |
| |
| TEST_F(C2BufferTest, MultipleLinearMapTest) { |
| std::shared_ptr<C2BlockPool> pool(makeLinearBlockPool()); |
| constexpr size_t kCapacity = 524288u; |
| for (int i = 0; i < 100; ++i) { |
| std::vector<C2WriteView> wViews; |
| std::vector<C2ReadView> rViews; |
| for (int j = 0; j < 16; ++j) { |
| std::shared_ptr<C2LinearBlock> block; |
| ASSERT_EQ(C2_OK, pool->fetchLinearBlock( |
| kCapacity, |
| { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE }, |
| &block)); |
| wViews.push_back(block->map().get()); |
| C2ConstLinearBlock cBlock = block->share(0, kCapacity / 2, C2Fence()); |
| rViews.push_back(cBlock.map().get()); |
| } |
| } |
| } |
| |
| TEST_F(C2BufferTest, InfoBufferTest) { |
| constexpr size_t kCapacity = 524288u; |
| |
| // allocate a linear block |
| std::shared_ptr<C2BlockPool> linearPool(makeLinearBlockPool()); |
| std::shared_ptr<C2LinearBlock> linearBlock; |
| ASSERT_EQ(C2_OK, linearPool->fetchLinearBlock( |
| kCapacity, |
| { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE }, |
| &linearBlock)); |
| |
| C2InfoBuffer info = C2InfoBuffer::CreateLinearBuffer( |
| kParamIndexNumber1, linearBlock->share(1024, kCapacity / 2, C2Fence())); |
| std::shared_ptr<C2InfoBuffer> spInfo(new C2InfoBuffer(info)); |
| ASSERT_EQ(kParamIndexNumber1, spInfo->index().coreIndex()); |
| ASSERT_TRUE(spInfo->index().isGlobal()); |
| ASSERT_EQ(C2Param::INFO, spInfo->index().kind()); |
| ASSERT_EQ(C2BufferData::LINEAR, spInfo->data().type()); |
| ASSERT_EQ(1024, spInfo->data().linearBlocks()[0].offset()); |
| ASSERT_EQ(kCapacity / 2, spInfo->data().linearBlocks()[0].size()); |
| // handles must actually be identical after sharing into an info buffer |
| ASSERT_EQ(linearBlock->handle(), spInfo->data().linearBlocks()[0].handle()); |
| ASSERT_EQ(linearPool->getAllocatorId(), spInfo->data().linearBlocks()[0].getAllocatorId()); |
| |
| C2InfoBuffer streamInfo = info.asStream(false /* output */, 1u); |
| ASSERT_EQ(kParamIndexNumber1, streamInfo.index().coreIndex()); |
| ASSERT_TRUE(streamInfo.index().forStream()); |
| ASSERT_TRUE(streamInfo.index().forInput()); |
| ASSERT_EQ(1u, streamInfo.index().stream()); |
| ASSERT_EQ(C2Param::INFO, streamInfo.index().kind()); |
| ASSERT_EQ(C2BufferData::LINEAR, streamInfo.data().type()); |
| ASSERT_EQ(1024, streamInfo.data().linearBlocks()[0].offset()); |
| ASSERT_EQ(kCapacity / 2, streamInfo.data().linearBlocks()[0].size()); |
| // handles must actually be identical after sharing into an info buffer |
| ASSERT_EQ(linearBlock->handle(), streamInfo.data().linearBlocks()[0].handle()); |
| ASSERT_EQ(linearPool->getAllocatorId(), streamInfo.data().linearBlocks()[0].getAllocatorId()); |
| |
| C2InfoBuffer portInfo = streamInfo.asPort(true /* output */); |
| ASSERT_EQ(kParamIndexNumber1, portInfo.index().coreIndex()); |
| ASSERT_TRUE(portInfo.index().forPort()); |
| ASSERT_TRUE(portInfo.index().forOutput()); |
| ASSERT_EQ(C2Param::INFO, portInfo.index().kind()); |
| ASSERT_EQ(C2BufferData::LINEAR, portInfo.data().type()); |
| ASSERT_EQ(1024, portInfo.data().linearBlocks()[0].offset()); |
| ASSERT_EQ(kCapacity / 2, portInfo.data().linearBlocks()[0].size()); |
| // handles must actually be identical after sharing into an info buffer |
| ASSERT_EQ(linearBlock->handle(), portInfo.data().linearBlocks()[0].handle()); |
| ASSERT_EQ(linearPool->getAllocatorId(), portInfo.data().linearBlocks()[0].getAllocatorId()); |
| } |
| |
| } // namespace android |