/* * Copyright 2016 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. */ #define LOG_TAG "GrallocPassthrough" #include #include #include #include #include #include #include #include "Gralloc.h" namespace android { namespace hardware { namespace graphics { namespace allocator { namespace V2_0 { namespace implementation { class GrallocHal : public IAllocator { public: GrallocHal(const hw_module_t* module); virtual ~GrallocHal(); // IAllocator interface Return getCapabilities(getCapabilities_cb hidl_cb) override; Return dumpDebugInfo(dumpDebugInfo_cb hidl_cb) override; Return createClient(createClient_cb hidl_cb) override; Error createDescriptor( const IAllocatorClient::BufferDescriptorInfo& descriptorInfo, BufferDescriptor& outDescriptor); Error destroyDescriptor(BufferDescriptor descriptor); Error testAllocate(const hidl_vec& descriptors); Error allocate(const hidl_vec& descriptors, hidl_vec& outBuffers); Error free(Buffer buffer); Error exportHandle(Buffer buffer, const native_handle_t*& outHandle); private: void initCapabilities(); template void initDispatch(T& func, gralloc1_function_descriptor_t desc); void initDispatch(); bool hasCapability(Capability capability) const; gralloc1_device_t* mDevice; std::unordered_set mCapabilities; struct { GRALLOC1_PFN_DUMP dump; GRALLOC1_PFN_CREATE_DESCRIPTOR createDescriptor; GRALLOC1_PFN_DESTROY_DESCRIPTOR destroyDescriptor; GRALLOC1_PFN_SET_DIMENSIONS setDimensions; GRALLOC1_PFN_SET_FORMAT setFormat; GRALLOC1_PFN_SET_LAYER_COUNT setLayerCount; GRALLOC1_PFN_SET_CONSUMER_USAGE setConsumerUsage; GRALLOC1_PFN_SET_PRODUCER_USAGE setProducerUsage; GRALLOC1_PFN_ALLOCATE allocate; GRALLOC1_PFN_RELEASE release; } mDispatch; }; class GrallocClient : public IAllocatorClient { public: GrallocClient(GrallocHal& hal); virtual ~GrallocClient(); // IAllocatorClient interface Return createDescriptor(const BufferDescriptorInfo& descriptorInfo, createDescriptor_cb hidl_cb) override; Return destroyDescriptor(BufferDescriptor descriptor) override; Return testAllocate( const hidl_vec& descriptors) override; Return allocate(const hidl_vec& descriptors, allocate_cb hidl_cb) override; Return free(Buffer buffer) override; Return exportHandle(BufferDescriptor descriptor, Buffer buffer, exportHandle_cb hidl_cb) override; private: GrallocHal& mHal; std::mutex mMutex; std::unordered_set mDescriptors; std::unordered_set mBuffers; }; GrallocHal::GrallocHal(const hw_module_t* module) : mDevice(nullptr), mDispatch() { int status = gralloc1_open(module, &mDevice); if (status) { LOG_ALWAYS_FATAL("failed to open gralloc1 device: %s", strerror(-status)); } initCapabilities(); initDispatch(); } GrallocHal::~GrallocHal() { gralloc1_close(mDevice); } void GrallocHal::initCapabilities() { uint32_t count; mDevice->getCapabilities(mDevice, &count, nullptr); std::vector caps(count); mDevice->getCapabilities(mDevice, &count, reinterpret_cast< std::underlying_type::type*>(caps.data())); caps.resize(count); mCapabilities.insert(caps.cbegin(), caps.cend()); } template void GrallocHal::initDispatch(T& func, gralloc1_function_descriptor_t desc) { auto pfn = mDevice->getFunction(mDevice, desc); if (!pfn) { LOG_ALWAYS_FATAL("failed to get gralloc1 function %d", desc); } func = reinterpret_cast(pfn); } void GrallocHal::initDispatch() { initDispatch(mDispatch.dump, GRALLOC1_FUNCTION_DUMP); initDispatch(mDispatch.createDescriptor, GRALLOC1_FUNCTION_CREATE_DESCRIPTOR); initDispatch(mDispatch.destroyDescriptor, GRALLOC1_FUNCTION_DESTROY_DESCRIPTOR); initDispatch(mDispatch.setDimensions, GRALLOC1_FUNCTION_SET_DIMENSIONS); initDispatch(mDispatch.setFormat, GRALLOC1_FUNCTION_SET_FORMAT); if (hasCapability(Capability::LAYERED_BUFFERS)) { initDispatch( mDispatch.setLayerCount, GRALLOC1_FUNCTION_SET_LAYER_COUNT); } initDispatch(mDispatch.setConsumerUsage, GRALLOC1_FUNCTION_SET_CONSUMER_USAGE); initDispatch(mDispatch.setProducerUsage, GRALLOC1_FUNCTION_SET_PRODUCER_USAGE); initDispatch(mDispatch.allocate, GRALLOC1_FUNCTION_ALLOCATE); initDispatch(mDispatch.release, GRALLOC1_FUNCTION_RELEASE); } bool GrallocHal::hasCapability(Capability capability) const { return (mCapabilities.count(capability) > 0); } Return GrallocHal::getCapabilities(getCapabilities_cb hidl_cb) { std::vector caps( mCapabilities.cbegin(), mCapabilities.cend()); hidl_vec reply; reply.setToExternal(caps.data(), caps.size()); hidl_cb(reply); return Void(); } Return GrallocHal::dumpDebugInfo(dumpDebugInfo_cb hidl_cb) { uint32_t len = 0; mDispatch.dump(mDevice, &len, nullptr); std::vector buf(len + 1); mDispatch.dump(mDevice, &len, buf.data()); buf.resize(len + 1); buf[len] = '\0'; hidl_string reply; reply.setToExternal(buf.data(), len); hidl_cb(reply); return Void(); } Return GrallocHal::createClient(createClient_cb hidl_cb) { sp client = new GrallocClient(*this); hidl_cb(Error::NONE, client); return Void(); } Error GrallocHal::createDescriptor( const IAllocatorClient::BufferDescriptorInfo& descriptorInfo, BufferDescriptor& outDescriptor) { gralloc1_buffer_descriptor_t descriptor; int32_t err = mDispatch.createDescriptor(mDevice, &descriptor); if (err != GRALLOC1_ERROR_NONE) { return static_cast(err); } err = mDispatch.setDimensions(mDevice, descriptor, descriptorInfo.width, descriptorInfo.height); if (err == GRALLOC1_ERROR_NONE) { err = mDispatch.setFormat(mDevice, descriptor, static_cast(descriptorInfo.format)); } if (err == GRALLOC1_ERROR_NONE) { if (hasCapability(Capability::LAYERED_BUFFERS)) { err = mDispatch.setLayerCount(mDevice, descriptor, descriptorInfo.layerCount); } else if (descriptorInfo.layerCount != 1) { err = GRALLOC1_ERROR_BAD_VALUE; } } if (err == GRALLOC1_ERROR_NONE) { uint64_t producerUsageMask = descriptorInfo.producerUsageMask; if (producerUsageMask & GRALLOC1_PRODUCER_USAGE_CPU_READ_OFTEN) { producerUsageMask |= GRALLOC1_PRODUCER_USAGE_CPU_READ; } if (producerUsageMask & GRALLOC1_PRODUCER_USAGE_CPU_WRITE_OFTEN) { producerUsageMask |= GRALLOC1_PRODUCER_USAGE_CPU_WRITE; } err = mDispatch.setProducerUsage(mDevice, descriptor, descriptorInfo.producerUsageMask); } if (err == GRALLOC1_ERROR_NONE) { uint64_t consumerUsageMask = descriptorInfo.consumerUsageMask; if (consumerUsageMask & GRALLOC1_CONSUMER_USAGE_CPU_READ_OFTEN) { consumerUsageMask |= GRALLOC1_CONSUMER_USAGE_CPU_READ; } err = mDispatch.setConsumerUsage(mDevice, descriptor, consumerUsageMask); } if (err == GRALLOC1_ERROR_NONE) { outDescriptor = descriptor; } else { mDispatch.destroyDescriptor(mDevice, descriptor); } return static_cast(err); } Error GrallocHal::destroyDescriptor(BufferDescriptor descriptor) { int32_t err = mDispatch.destroyDescriptor(mDevice, descriptor); return static_cast(err); } Error GrallocHal::testAllocate(const hidl_vec& descriptors) { if (!hasCapability(Capability::TEST_ALLOCATE)) { return Error::UNDEFINED; } int32_t err = mDispatch.allocate(mDevice, descriptors.size(), descriptors.data(), nullptr); return static_cast(err); } Error GrallocHal::allocate(const hidl_vec& descriptors, hidl_vec& outBuffers) { std::vector buffers(descriptors.size()); int32_t err = mDispatch.allocate(mDevice, descriptors.size(), descriptors.data(), buffers.data()); if (err == GRALLOC1_ERROR_NONE || err == GRALLOC1_ERROR_NOT_SHARED) { outBuffers.resize(buffers.size()); for (size_t i = 0; i < outBuffers.size(); i++) { outBuffers[i] = static_cast( reinterpret_cast(buffers[i])); } } return static_cast(err); } Error GrallocHal::free(Buffer buffer) { buffer_handle_t handle = reinterpret_cast( static_cast(buffer)); int32_t err = mDispatch.release(mDevice, handle); return static_cast(err); } Error GrallocHal::exportHandle(Buffer buffer, const native_handle_t*& outHandle) { // we rely on the caller to validate buffer here outHandle = reinterpret_cast( static_cast(buffer)); return Error::NONE; } GrallocClient::GrallocClient(GrallocHal& hal) : mHal(hal) { } GrallocClient::~GrallocClient() { if (!mBuffers.empty()) { ALOGW("client destroyed with valid buffers"); for (auto buf : mBuffers) { mHal.free(buf); } } if (!mDescriptors.empty()) { ALOGW("client destroyed with valid buffer descriptors"); for (auto desc : mDescriptors) { mHal.destroyDescriptor(desc); } } } Return GrallocClient::createDescriptor( const BufferDescriptorInfo& descriptorInfo, createDescriptor_cb hidl_cb) { BufferDescriptor descriptor; Error err = mHal.createDescriptor(descriptorInfo, descriptor); if (err == Error::NONE) { std::lock_guard lock(mMutex); auto result = mDescriptors.insert(descriptor); if (!result.second) { ALOGW("duplicated buffer descriptor id returned"); mHal.destroyDescriptor(descriptor); err = Error::NO_RESOURCES; } } hidl_cb(err, descriptor); return Void(); } Return GrallocClient::destroyDescriptor(BufferDescriptor descriptor) { { std::lock_guard lock(mMutex); if (!mDescriptors.erase(descriptor)) { return Error::BAD_DESCRIPTOR; } } return mHal.destroyDescriptor(descriptor); } Return GrallocClient::testAllocate( const hidl_vec& descriptors) { return mHal.testAllocate(descriptors); } Return GrallocClient::allocate( const hidl_vec& descriptors, allocate_cb hidl_cb) { hidl_vec buffers; Error err = mHal.allocate(descriptors, buffers); if (err == Error::NONE || err == Error::NOT_SHARED) { std::lock_guard lock(mMutex); for (size_t i = 0; i < buffers.size(); i++) { auto result = mBuffers.insert(buffers[i]); if (!result.second) { ALOGW("duplicated buffer id returned"); for (size_t j = 0; j < buffers.size(); j++) { if (j < i) { mBuffers.erase(buffers[i]); } mHal.free(buffers[i]); } buffers = hidl_vec(); err = Error::NO_RESOURCES; break; } } } hidl_cb(err, buffers); return Void(); } Return GrallocClient::free(Buffer buffer) { { std::lock_guard lock(mMutex); if (!mBuffers.erase(buffer)) { return Error::BAD_BUFFER; } } return mHal.free(buffer); } Return GrallocClient::exportHandle(BufferDescriptor /*descriptor*/, Buffer buffer, exportHandle_cb hidl_cb) { const native_handle_t* handle = nullptr; { std::lock_guard lock(mMutex); if (mBuffers.count(buffer) == 0) { hidl_cb(Error::BAD_BUFFER, handle); return Void(); } } Error err = mHal.exportHandle(buffer, handle); hidl_cb(err, handle); return Void(); } IAllocator* HIDL_FETCH_IAllocator(const char* /* name */) { const hw_module_t* module; int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module); if (err) { ALOGE("failed to get gralloc module"); return nullptr; } uint8_t major = (module->module_api_version >> 8) & 0xff; if (major != 1) { ALOGE("unknown gralloc module major version %d", major); return nullptr; } return new GrallocHal(module); } } // namespace implementation } // namespace V2_0 } // namespace allocator } // namespace graphics } // namespace hardware } // namespace android