1054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin/* 2054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin * Copyright (C) 2008 The Android Open Source Project 3054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin * Copyright (c) 2011-2015, The Linux Foundation. All rights reserved. 4054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin * 5054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin * Licensed under the Apache License, Version 2.0 (the "License"); 6054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin * you may not use this file except in compliance with the License. 7054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin * You may obtain a copy of the License at 8054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin * 9054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin * http://www.apache.org/licenses/LICENSE-2.0 10054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin * 11054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin * Unless required by applicable law or agreed to in writing, software 12054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin * distributed under the License is distributed on an "AS IS" BASIS, 13054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin * See the License for the specific language governing permissions and 15054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin * limitations under the License. 16054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin */ 17054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin 18054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin#define ATRACE_TAG (ATRACE_TAG_GRAPHICS | ATRACE_TAG_HAL) 19054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin#include <limits.h> 20054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin#include <errno.h> 21054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin#include <pthread.h> 22054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin#include <unistd.h> 23054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin#include <string.h> 24054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin#include <stdarg.h> 25054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin 26054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin#include <sys/mman.h> 27054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin#include <sys/stat.h> 28054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin#include <sys/types.h> 29054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin#include <sys/ioctl.h> 30054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin 31054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin#include <cutils/log.h> 32054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin#include <cutils/atomic.h> 33054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin#include <utils/Trace.h> 34054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin 35054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin#include <hardware/hardware.h> 36054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin#include <hardware/gralloc.h> 37054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin 38054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin#include "gralloc_priv.h" 39054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin#include "gr.h" 40054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin#include "alloc_controller.h" 41054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin#include "memalloc.h" 42054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin#include <qdMetaData.h> 43054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin 44054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin 45054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjinusing namespace gralloc; 46054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin/*****************************************************************************/ 47054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin 48054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin// Return the type of allocator - 49054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin// these are used for mapping/unmapping 50054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjinstatic IMemAlloc* getAllocator(int flags) 51054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin{ 52054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin IMemAlloc* memalloc; 53054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin IAllocController* alloc_ctrl = IAllocController::getInstance(); 54054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin memalloc = alloc_ctrl->getAllocator(flags); 55054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin return memalloc; 56054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin} 57054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin 58b7d1a389b00370fc9d2a7db1268ce26271ead7e2Naseer Ahmedstatic int gralloc_map_metadata(buffer_handle_t handle) { 59b7d1a389b00370fc9d2a7db1268ce26271ead7e2Naseer Ahmed private_handle_t* hnd = (private_handle_t*)handle; 60b7d1a389b00370fc9d2a7db1268ce26271ead7e2Naseer Ahmed hnd->base_metadata = 0; 61b7d1a389b00370fc9d2a7db1268ce26271ead7e2Naseer Ahmed IMemAlloc* memalloc = getAllocator(hnd->flags) ; 62b7d1a389b00370fc9d2a7db1268ce26271ead7e2Naseer Ahmed void *mappedAddress = MAP_FAILED; 63b7d1a389b00370fc9d2a7db1268ce26271ead7e2Naseer Ahmed unsigned int size = 0; 64b7d1a389b00370fc9d2a7db1268ce26271ead7e2Naseer Ahmed if (!(hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER)) { 65b7d1a389b00370fc9d2a7db1268ce26271ead7e2Naseer Ahmed mappedAddress = MAP_FAILED; 66b7d1a389b00370fc9d2a7db1268ce26271ead7e2Naseer Ahmed size = ROUND_UP_PAGESIZE(sizeof(MetaData_t)); 67b7d1a389b00370fc9d2a7db1268ce26271ead7e2Naseer Ahmed int ret = memalloc->map_buffer(&mappedAddress, size, 68b7d1a389b00370fc9d2a7db1268ce26271ead7e2Naseer Ahmed hnd->offset_metadata, hnd->fd_metadata); 69b7d1a389b00370fc9d2a7db1268ce26271ead7e2Naseer Ahmed if(ret || mappedAddress == MAP_FAILED) { 70b7d1a389b00370fc9d2a7db1268ce26271ead7e2Naseer Ahmed ALOGE("Could not mmap metadata for handle %p, fd=%d (%s)", 71b7d1a389b00370fc9d2a7db1268ce26271ead7e2Naseer Ahmed hnd, hnd->fd_metadata, strerror(errno)); 72b7d1a389b00370fc9d2a7db1268ce26271ead7e2Naseer Ahmed return -errno; 73b7d1a389b00370fc9d2a7db1268ce26271ead7e2Naseer Ahmed } 74b7d1a389b00370fc9d2a7db1268ce26271ead7e2Naseer Ahmed hnd->base_metadata = uint64_t(mappedAddress) + hnd->offset_metadata; 75b7d1a389b00370fc9d2a7db1268ce26271ead7e2Naseer Ahmed } 76b7d1a389b00370fc9d2a7db1268ce26271ead7e2Naseer Ahmed return 0; 77b7d1a389b00370fc9d2a7db1268ce26271ead7e2Naseer Ahmed} 78b7d1a389b00370fc9d2a7db1268ce26271ead7e2Naseer Ahmed 79054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjinstatic int gralloc_map(gralloc_module_t const* module, 80054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin buffer_handle_t handle) 81054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin{ 82054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin ATRACE_CALL(); 83054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin if(!module) 84054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin return -EINVAL; 85054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin 86054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin private_handle_t* hnd = (private_handle_t*)handle; 87054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin unsigned int size = 0; 88054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin int err = 0; 89054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin IMemAlloc* memalloc = getAllocator(hnd->flags) ; 9005d37027d2422f070136f2117e9a4a6464714f25Naseer Ahmed void *mappedAddress = MAP_FAILED; 9105d37027d2422f070136f2117e9a4a6464714f25Naseer Ahmed hnd->base = 0; 9205d37027d2422f070136f2117e9a4a6464714f25Naseer Ahmed 9305d37027d2422f070136f2117e9a4a6464714f25Naseer Ahmed // Dont map framebuffer and secure buffers 94054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin if (!(hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER) && 95054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin !(hnd->flags & private_handle_t::PRIV_FLAGS_SECURE_BUFFER)) { 96054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin size = hnd->size; 97054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin err = memalloc->map_buffer(&mappedAddress, size, 98054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin hnd->offset, hnd->fd); 99054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin if(err || mappedAddress == MAP_FAILED) { 100054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin ALOGE("Could not mmap handle %p, fd=%d (%s)", 101054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin handle, hnd->fd, strerror(errno)); 102054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin return -errno; 103054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin } 104054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin 105054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin hnd->base = uint64_t(mappedAddress) + hnd->offset; 106b7d1a389b00370fc9d2a7db1268ce26271ead7e2Naseer Ahmed } else { 107b7d1a389b00370fc9d2a7db1268ce26271ead7e2Naseer Ahmed // Cannot map secure buffers or framebuffers, but still need to map 108b7d1a389b00370fc9d2a7db1268ce26271ead7e2Naseer Ahmed // metadata for secure buffers. 109b7d1a389b00370fc9d2a7db1268ce26271ead7e2Naseer Ahmed // If mapping a secure buffers fails, the framework needs to get 110b7d1a389b00370fc9d2a7db1268ce26271ead7e2Naseer Ahmed // an error code. 111b7d1a389b00370fc9d2a7db1268ce26271ead7e2Naseer Ahmed err = -EINVAL; 112054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin } 113054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin 11405d37027d2422f070136f2117e9a4a6464714f25Naseer Ahmed //Allow mapping of metadata for all buffers including secure ones, but not 11505d37027d2422f070136f2117e9a4a6464714f25Naseer Ahmed //of framebuffer 116b7d1a389b00370fc9d2a7db1268ce26271ead7e2Naseer Ahmed int metadata_err = gralloc_map_metadata(handle); 117b7d1a389b00370fc9d2a7db1268ce26271ead7e2Naseer Ahmed if(!err) { 118b7d1a389b00370fc9d2a7db1268ce26271ead7e2Naseer Ahmed err = metadata_err; 119f026d04dde743a0524235ae57e2ce8ac5364d44bSteve Pfetsch } 120b7d1a389b00370fc9d2a7db1268ce26271ead7e2Naseer Ahmed return err; 121054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin} 122054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin 123054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjinstatic int gralloc_unmap(gralloc_module_t const* module, 124054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin buffer_handle_t handle) 125054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin{ 126054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin ATRACE_CALL(); 12705d37027d2422f070136f2117e9a4a6464714f25Naseer Ahmed int err = -EINVAL; 128054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin if(!module) 12905d37027d2422f070136f2117e9a4a6464714f25Naseer Ahmed return err; 130054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin 131054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin private_handle_t* hnd = (private_handle_t*)handle; 13205d37027d2422f070136f2117e9a4a6464714f25Naseer Ahmed IMemAlloc* memalloc = getAllocator(hnd->flags) ; 13305d37027d2422f070136f2117e9a4a6464714f25Naseer Ahmed if(!memalloc) 13405d37027d2422f070136f2117e9a4a6464714f25Naseer Ahmed return err; 13505d37027d2422f070136f2117e9a4a6464714f25Naseer Ahmed 13605d37027d2422f070136f2117e9a4a6464714f25Naseer Ahmed if(hnd->base) { 13705d37027d2422f070136f2117e9a4a6464714f25Naseer Ahmed err = memalloc->unmap_buffer((void*)hnd->base, hnd->size, hnd->offset); 13805d37027d2422f070136f2117e9a4a6464714f25Naseer Ahmed if (err) { 13905d37027d2422f070136f2117e9a4a6464714f25Naseer Ahmed ALOGE("Could not unmap memory at address %p, %s", hnd->base, 14005d37027d2422f070136f2117e9a4a6464714f25Naseer Ahmed strerror(errno)); 14105d37027d2422f070136f2117e9a4a6464714f25Naseer Ahmed return -errno; 142054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin } 14305d37027d2422f070136f2117e9a4a6464714f25Naseer Ahmed hnd->base = 0; 144054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin } 14505d37027d2422f070136f2117e9a4a6464714f25Naseer Ahmed 14605d37027d2422f070136f2117e9a4a6464714f25Naseer Ahmed if(hnd->base_metadata) { 14705d37027d2422f070136f2117e9a4a6464714f25Naseer Ahmed unsigned int size = ROUND_UP_PAGESIZE(sizeof(MetaData_t)); 14805d37027d2422f070136f2117e9a4a6464714f25Naseer Ahmed err = memalloc->unmap_buffer((void*)hnd->base_metadata, 14905d37027d2422f070136f2117e9a4a6464714f25Naseer Ahmed size, hnd->offset_metadata); 15005d37027d2422f070136f2117e9a4a6464714f25Naseer Ahmed if (err) { 15105d37027d2422f070136f2117e9a4a6464714f25Naseer Ahmed ALOGE("Could not unmap memory at address %p, %s", 15205d37027d2422f070136f2117e9a4a6464714f25Naseer Ahmed hnd->base_metadata, strerror(errno)); 15305d37027d2422f070136f2117e9a4a6464714f25Naseer Ahmed return -errno; 15405d37027d2422f070136f2117e9a4a6464714f25Naseer Ahmed } 15505d37027d2422f070136f2117e9a4a6464714f25Naseer Ahmed hnd->base_metadata = 0; 15605d37027d2422f070136f2117e9a4a6464714f25Naseer Ahmed } 15705d37027d2422f070136f2117e9a4a6464714f25Naseer Ahmed 158054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin return 0; 159054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin} 160054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin 161054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin/*****************************************************************************/ 162054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin 163054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjinstatic pthread_mutex_t sMapLock = PTHREAD_MUTEX_INITIALIZER; 164054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin 165054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin/*****************************************************************************/ 166054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin 167054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjinint gralloc_register_buffer(gralloc_module_t const* module, 168054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin buffer_handle_t handle) 169054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin{ 170054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin ATRACE_CALL(); 171054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin if (!module || private_handle_t::validate(handle) < 0) 172054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin return -EINVAL; 173b7d1a389b00370fc9d2a7db1268ce26271ead7e2Naseer Ahmed // The base address received via IPC is invalid in this process 174b7d1a389b00370fc9d2a7db1268ce26271ead7e2Naseer Ahmed // Reset it to 0 here since it will be mapped in lock() 175b7d1a389b00370fc9d2a7db1268ce26271ead7e2Naseer Ahmed private_handle_t* hnd = (private_handle_t*)handle; 176b7d1a389b00370fc9d2a7db1268ce26271ead7e2Naseer Ahmed hnd->base = 0; 177b7d1a389b00370fc9d2a7db1268ce26271ead7e2Naseer Ahmed return gralloc_map_metadata(handle); 178054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin} 179054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin 180054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjinint gralloc_unregister_buffer(gralloc_module_t const* module, 181054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin buffer_handle_t handle) 182054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin{ 183054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin ATRACE_CALL(); 184054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin if (!module || private_handle_t::validate(handle) < 0) 185054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin return -EINVAL; 186054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin 187054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin /* 188054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin * If the buffer has been mapped during a lock operation, it's time 189054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin * to un-map it. It's an error to be here with a locked buffer. 190054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin * NOTE: the framebuffer is handled differently and is never unmapped. 19105d37027d2422f070136f2117e9a4a6464714f25Naseer Ahmed * Also base and base_metadata are reset. 192054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin */ 19305d37027d2422f070136f2117e9a4a6464714f25Naseer Ahmed return gralloc_unmap(module, handle); 194054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin} 195054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin 196054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjinint terminateBuffer(gralloc_module_t const* module, 197054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin private_handle_t* hnd) 198054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin{ 199054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin ATRACE_CALL(); 200054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin if(!module) 201054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin return -EINVAL; 202054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin 203054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin /* 204054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin * If the buffer has been mapped during a lock operation, it's time 205054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin * to un-map it. It's an error to be here with a locked buffer. 20605d37027d2422f070136f2117e9a4a6464714f25Naseer Ahmed * NOTE: the framebuffer is handled differently and is never unmapped. 20705d37027d2422f070136f2117e9a4a6464714f25Naseer Ahmed * Also base and base_metadata are reset. 208054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin */ 20905d37027d2422f070136f2117e9a4a6464714f25Naseer Ahmed return gralloc_unmap(module, hnd); 210054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin} 211054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin 212054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjinstatic int gralloc_map_and_invalidate (gralloc_module_t const* module, 213054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin buffer_handle_t handle, int usage) 214054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin{ 215054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin ATRACE_CALL(); 216054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin if (!module || private_handle_t::validate(handle) < 0) 217054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin return -EINVAL; 218054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin 219054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin int err = 0; 220054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin private_handle_t* hnd = (private_handle_t*)handle; 221054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin if (usage & (GRALLOC_USAGE_SW_READ_MASK | GRALLOC_USAGE_SW_WRITE_MASK)) { 222054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin if (hnd->base == 0) { 223054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin // we need to map for real 224054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin pthread_mutex_t* const lock = &sMapLock; 225054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin pthread_mutex_lock(lock); 226054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin err = gralloc_map(module, handle); 227054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin pthread_mutex_unlock(lock); 228054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin } 229054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin if (hnd->flags & private_handle_t::PRIV_FLAGS_USES_ION and 230054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin hnd->flags & private_handle_t::PRIV_FLAGS_CACHED) { 231054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin //Invalidate if CPU reads in software and there are non-CPU 232054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin //writers. No need to do this for the metadata buffer as it is 233054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin //only read/written in software. 234054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin if ((usage & GRALLOC_USAGE_SW_READ_MASK) and 235054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin (hnd->flags & private_handle_t::PRIV_FLAGS_NON_CPU_WRITER)) 236054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin { 237054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin IMemAlloc* memalloc = getAllocator(hnd->flags) ; 238054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin err = memalloc->clean_buffer((void*)hnd->base, 239054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin hnd->size, hnd->offset, hnd->fd, 240054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin CACHE_INVALIDATE); 241054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin } 242054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin //Mark the buffer to be flushed after CPU write. 243054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin if (usage & GRALLOC_USAGE_SW_WRITE_MASK) { 244054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin hnd->flags |= private_handle_t::PRIV_FLAGS_NEEDS_FLUSH; 245054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin } 246054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin } 247054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin } 248054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin 249054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin return err; 250054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin} 251054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin 252054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjinint gralloc_lock(gralloc_module_t const* module, 253054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin buffer_handle_t handle, int usage, 254054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin int /*l*/, int /*t*/, int /*w*/, int /*h*/, 255054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin void** vaddr) 256054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin{ 257054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin ATRACE_CALL(); 258054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin private_handle_t* hnd = (private_handle_t*)handle; 259054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin int err = gralloc_map_and_invalidate(module, handle, usage); 260054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin if(!err) 261054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin *vaddr = (void*)hnd->base; 262054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin return err; 263054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin} 264054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin 265054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjinint gralloc_lock_ycbcr(gralloc_module_t const* module, 266054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin buffer_handle_t handle, int usage, 267054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin int /*l*/, int /*t*/, int /*w*/, int /*h*/, 268054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin struct android_ycbcr *ycbcr) 269054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin{ 270054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin ATRACE_CALL(); 271054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin private_handle_t* hnd = (private_handle_t*)handle; 272054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin int err = gralloc_map_and_invalidate(module, handle, usage); 273054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin if(!err) 274054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin err = getYUVPlaneInfo(hnd, ycbcr); 275054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin return err; 276054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin} 277054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin 278054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjinint gralloc_unlock(gralloc_module_t const* module, 279054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin buffer_handle_t handle) 280054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin{ 281054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin ATRACE_CALL(); 282054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin if (!module || private_handle_t::validate(handle) < 0) 283054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin return -EINVAL; 284054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin 285054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin int err = 0; 286054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin private_handle_t* hnd = (private_handle_t*)handle; 287054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin 288054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin IMemAlloc* memalloc = getAllocator(hnd->flags); 289054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin if (hnd->flags & private_handle_t::PRIV_FLAGS_NEEDS_FLUSH) { 290054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin err = memalloc->clean_buffer((void*)hnd->base, 291054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin hnd->size, hnd->offset, hnd->fd, 292054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin CACHE_CLEAN); 293054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin hnd->flags &= ~private_handle_t::PRIV_FLAGS_NEEDS_FLUSH; 294054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin } 295054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin 296054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin return err; 297054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin} 298054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin 299054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin/*****************************************************************************/ 300054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin 301054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjinint gralloc_perform(struct gralloc_module_t const* module, 302054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin int operation, ... ) 303054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin{ 304054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin int res = -EINVAL; 305054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin va_list args; 306054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin if(!module) 307054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin return res; 308054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin 309054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin va_start(args, operation); 310054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin switch (operation) { 311054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin case GRALLOC_MODULE_PERFORM_CREATE_HANDLE_FROM_BUFFER: 312054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin { 313054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin int fd = va_arg(args, int); 314054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin unsigned int size = va_arg(args, unsigned int); 315054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin unsigned int offset = va_arg(args, unsigned int); 316054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin void* base = va_arg(args, void*); 317054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin int width = va_arg(args, int); 318054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin int height = va_arg(args, int); 319054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin int format = va_arg(args, int); 320054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin 321054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin native_handle_t** handle = va_arg(args, native_handle_t**); 322054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin private_handle_t* hnd = (private_handle_t*)native_handle_create( 323054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin private_handle_t::sNumFds, private_handle_t::sNumInts()); 324054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin hnd->magic = private_handle_t::sMagic; 325054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin hnd->fd = fd; 326054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin hnd->flags = private_handle_t::PRIV_FLAGS_USES_ION; 327054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin hnd->size = size; 328054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin hnd->offset = offset; 329054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin hnd->base = uint64_t(base) + offset; 330054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin hnd->gpuaddr = 0; 331054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin hnd->width = width; 332054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin hnd->height = height; 333054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin hnd->format = format; 334054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin *handle = (native_handle_t *)hnd; 335054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin res = 0; 336054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin break; 337054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin 338054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin } 339054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin case GRALLOC_MODULE_PERFORM_GET_STRIDE: 340054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin { 341054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin int width = va_arg(args, int); 342054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin int format = va_arg(args, int); 343054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin int *stride = va_arg(args, int *); 344054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin int alignedw = 0, alignedh = 0; 345054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin AdrenoMemInfo::getInstance().getAlignedWidthAndHeight(width, 346054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin 0, format, 0, alignedw, alignedh); 347054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin *stride = alignedw; 348054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin res = 0; 349054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin } break; 350054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin 351054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin case GRALLOC_MODULE_PERFORM_GET_CUSTOM_STRIDE_FROM_HANDLE: 352054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin { 353054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin private_handle_t* hnd = va_arg(args, private_handle_t*); 354054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin int *stride = va_arg(args, int *); 355054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin if (private_handle_t::validate(hnd)) { 356054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin return res; 357054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin } 358054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin MetaData_t *metadata = (MetaData_t *)hnd->base_metadata; 359054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin if(metadata && metadata->operation & UPDATE_BUFFER_GEOMETRY) { 360054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin *stride = metadata->bufferDim.sliceWidth; 361054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin } else { 362054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin *stride = hnd->width; 363054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin } 364054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin res = 0; 365054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin } break; 366054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin 367054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin case GRALLOC_MODULE_PERFORM_GET_CUSTOM_STRIDE_AND_HEIGHT_FROM_HANDLE: 368054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin { 369054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin private_handle_t* hnd = va_arg(args, private_handle_t*); 370054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin int *stride = va_arg(args, int *); 371054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin int *height = va_arg(args, int *); 372054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin if (private_handle_t::validate(hnd)) { 373054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin return res; 374054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin } 375054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin MetaData_t *metadata = (MetaData_t *)hnd->base_metadata; 376054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin if(metadata && metadata->operation & UPDATE_BUFFER_GEOMETRY) { 377054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin *stride = metadata->bufferDim.sliceWidth; 378054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin *height = metadata->bufferDim.sliceHeight; 379054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin } else { 380054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin *stride = hnd->width; 381054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin *height = hnd->height; 382054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin } 383054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin res = 0; 384054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin } break; 385054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin 386054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin case GRALLOC_MODULE_PERFORM_GET_ATTRIBUTES: 387054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin { 388054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin int width = va_arg(args, int); 389054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin int height = va_arg(args, int); 390054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin int format = va_arg(args, int); 391054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin int usage = va_arg(args, int); 392054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin int *alignedWidth = va_arg(args, int *); 393054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin int *alignedHeight = va_arg(args, int *); 394054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin int *tileEnabled = va_arg(args,int *); 395054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin *tileEnabled = isMacroTileEnabled(format, usage); 396054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin AdrenoMemInfo::getInstance().getAlignedWidthAndHeight(width, 397054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin height, format, usage, *alignedWidth, *alignedHeight); 398054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin res = 0; 399054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin } break; 400054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin 401054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin case GRALLOC_MODULE_PERFORM_GET_COLOR_SPACE_FROM_HANDLE: 402054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin { 403054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin private_handle_t* hnd = va_arg(args, private_handle_t*); 404054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin int *color_space = va_arg(args, int *); 405054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin if (private_handle_t::validate(hnd)) { 406054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin return res; 407054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin } 408054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin MetaData_t *metadata = (MetaData_t *)hnd->base_metadata; 409054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin if(metadata && metadata->operation & UPDATE_COLOR_SPACE) { 410054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin *color_space = metadata->colorSpace; 411054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin res = 0; 412054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin } 413054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin } break; 414054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin 415054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin case GRALLOC_MODULE_PERFORM_GET_YUV_PLANE_INFO: 416054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin { 417054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin private_handle_t* hnd = va_arg(args, private_handle_t*); 418054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin android_ycbcr* ycbcr = va_arg(args, struct android_ycbcr *); 419054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin if (!private_handle_t::validate(hnd)) { 420054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin res = getYUVPlaneInfo(hnd, ycbcr); 421054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin } 422054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin } break; 423054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin 424054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin case GRALLOC_MODULE_PERFORM_GET_MAP_SECURE_BUFFER_INFO: 425054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin { 426054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin private_handle_t* hnd = va_arg(args, private_handle_t*); 427054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin int *map_secure_buffer = va_arg(args, int *); 428054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin if (private_handle_t::validate(hnd)) { 429054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin return res; 430054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin } 431054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin MetaData_t *metadata = (MetaData_t *)hnd->base_metadata; 432054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin if(metadata && metadata->operation & MAP_SECURE_BUFFER) { 433054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin *map_secure_buffer = metadata->mapSecureBuffer; 434054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin res = 0; 435054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin } else { 436054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin *map_secure_buffer = 0; 437054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin } 438054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin } break; 439054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin 440054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin default: 441054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin break; 442054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin } 443054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin va_end(args); 444054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin return res; 445054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin} 446