C++程序  |  653行  |  22.75 KB

/*
 * Copyright (C) 2016 ARM Limited. All rights reserved.
 *
 * Copyright (C) 2008 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 <string.h>
#include <dlfcn.h>
#include <hardware/gralloc.h>
#include <inttypes.h>
#include <cutils/log.h>

#include "mali_gralloc_formats.h"
#include "gralloc_priv.h"

static mali_gralloc_format_caps dpu_runtime_caps;
static mali_gralloc_format_caps vpu_runtime_caps;
static mali_gralloc_format_caps gpu_runtime_caps;
static mali_gralloc_format_caps cam_runtime_caps;
static pthread_mutex_t caps_init_mutex = PTHREAD_MUTEX_INITIALIZER;
static bool runtime_caps_read = false;

#define MALI_GRALLOC_GPU_LIB_NAME "libGLES_mali.so"
#if defined(__LP64__)
#define MALI_GRALLOC_GPU_LIBRARY_PATH1 "/vendor/lib64/egl/"
#define MALI_GRALLOC_GPU_LIBRARY_PATH2 "/system/lib64/egl/"
#else
#define MALI_GRALLOC_GPU_LIBRARY_PATH1 "/vendor/lib/egl/"
#define MALI_GRALLOC_GPU_LIBRARY_PATH2 "/system/lib/egl/"
#endif

static bool get_block_capabilities(bool hal_module, const char *name, mali_gralloc_format_caps *block_caps)
{
    void *dso_handle = NULL;
    bool rval = false;

    /* Look for MALI_GRALLOC_FORMATCAPS_SYM_NAME_STR symbol in user-space drivers
     * to determine hw format capabilities.
     */
    if(!hal_module)
    {
        dso_handle = dlopen(name, RTLD_LAZY);
    }
    else
    {
        /* libhardware does some heuristics to find hal modules
         * and then stores the dso handle internally. Use this.
         */
        const struct hw_module_t *module = {NULL};

        if(hw_get_module(name, &module) >= 0)
        {
            dso_handle = module->dso;
        }
    }

    if(dso_handle)
    {
        void *sym = dlsym(dso_handle, MALI_GRALLOC_FORMATCAPS_SYM_NAME_STR);

        if(sym)
        {
            memcpy((void*) block_caps, sym, sizeof(mali_gralloc_format_caps));
            rval = true;
        }

        if(!hal_module)
        {
            dlclose(dso_handle);
        }
    }

    return rval;
}

static int map_flex_formats(int req_format, uint64_t *producer_runtime_mask)
{
    /* Map Android flexible formats to internal base formats */
    if(req_format == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED ||
       req_format == HAL_PIXEL_FORMAT_YCbCr_420_888)
    {
        req_format = MALI_GRALLOC_FORMAT_INTERNAL_NV12;

        /*
         * We disable AFBC for NV12 since neither VPU or DPU DDKs support
         * them currently.
         */
        *producer_runtime_mask &= ~MALI_GRALLOC_FORMAT_CAPABILITY_AFBCENABLE_MASK;
    }
    return req_format;
}

static bool is_afbc_supported(int req_format_mapped)
{
    bool rval = true;

    /* These base formats we currently don't support with compression */
    switch(req_format_mapped)
    {
        case MALI_GRALLOC_FORMAT_INTERNAL_RAW16:
        case MALI_GRALLOC_FORMAT_INTERNAL_RAW12:
        case MALI_GRALLOC_FORMAT_INTERNAL_RAW10:
        case MALI_GRALLOC_FORMAT_INTERNAL_BLOB:
        case MALI_GRALLOC_FORMAT_INTERNAL_P010:
        case MALI_GRALLOC_FORMAT_INTERNAL_P210:
        case MALI_GRALLOC_FORMAT_INTERNAL_Y410:
        case HAL_PIXEL_FORMAT_YCbCr_422_I:
            rval = false;
            break;
    }
    return rval;
}

static bool is_android_yuv_format(int req_format)
{
    bool rval = false;

    switch(req_format)
    {
        case HAL_PIXEL_FORMAT_YV12:
        case HAL_PIXEL_FORMAT_Y8:
        case HAL_PIXEL_FORMAT_Y16:
        case HAL_PIXEL_FORMAT_YCbCr_420_888:
        case HAL_PIXEL_FORMAT_YCbCr_422_888:
        case HAL_PIXEL_FORMAT_YCbCr_444_888:
            rval = true;
            break;
    }
    return rval;
}

static bool is_afbc_allowed(int buffer_size)
{
    bool afbc_allowed = false;

    (void) buffer_size;

#if GRALLOC_DISP_W != 0 && GRALLOC_DISP_H != 0
    afbc_allowed = ((buffer_size*100) / (GRALLOC_DISP_W*GRALLOC_DISP_H)) >= GRALLOC_AFBC_MIN_SIZE;

#else
    /* If display size is not valid then always allow AFBC */
    afbc_allowed = true;

#endif

    return afbc_allowed;
}

static bool is_afbc_format(uint64_t internal_format)
{
    return (internal_format & MALI_GRALLOC_FORMAT_CAPABILITY_AFBCENABLE_MASK) != 0;
}

static uint64_t determine_best_format(int req_format, mali_gralloc_producer_type producer, mali_gralloc_consumer_type consumer,
                                      uint64_t producer_runtime_mask, uint64_t consumer_runtime_mask)
{
    /* Default is to return the requested format */
    uint64_t internal_format = req_format;
    uint64_t dpu_mask = dpu_runtime_caps.caps_mask;
    uint64_t gpu_mask = gpu_runtime_caps.caps_mask;
    uint64_t vpu_mask = vpu_runtime_caps.caps_mask;
    uint64_t cam_mask = cam_runtime_caps.caps_mask;

    if(producer == MALI_GRALLOC_PRODUCER_GPU && gpu_runtime_caps.caps_mask & MALI_GRALLOC_FORMAT_CAPABILITY_OPTIONS_PRESENT)
    {
        gpu_mask &= producer_runtime_mask;

        if(consumer == MALI_GRALLOC_CONSUMER_GPU_OR_DISPLAY)
        {
            gpu_mask &= consumer_runtime_mask;
            dpu_mask &= consumer_runtime_mask;

            if(gpu_mask & MALI_GRALLOC_FORMAT_CAPABILITY_AFBC_SPLITBLK &&
               dpu_mask & MALI_GRALLOC_FORMAT_CAPABILITY_AFBC_SPLITBLK)
            {
                internal_format |= MALI_GRALLOC_INTFMT_AFBC_SPLITBLK;
            }
            else if(gpu_mask & MALI_GRALLOC_FORMAT_CAPABILITY_AFBC_BASIC &&
                    dpu_mask & MALI_GRALLOC_FORMAT_CAPABILITY_AFBC_BASIC)
            {
                internal_format |= MALI_GRALLOC_INTFMT_AFBC_BASIC;

                if(gpu_mask & MALI_GRALLOC_FORMAT_CAPABILITY_AFBC_TILED_HEADERS &&
                   dpu_mask & MALI_GRALLOC_FORMAT_CAPABILITY_AFBC_TILED_HEADERS)
                {
                    internal_format |= MALI_GRALLOC_INTFMT_AFBC_TILED_HEADERS;
                }
            }
        }
        else if(consumer == MALI_GRALLOC_CONSUMER_GPU_EXCL)
        {
            gpu_mask &= consumer_runtime_mask;

            /* When GPU acts as both producer and consumer it prefers 16x16 superblocks */
            if(gpu_mask & MALI_GRALLOC_FORMAT_CAPABILITY_AFBC_BASIC)
            {
                internal_format |= MALI_GRALLOC_INTFMT_AFBC_BASIC;
            }

            if(gpu_mask & MALI_GRALLOC_FORMAT_CAPABILITY_AFBC_TILED_HEADERS)
            {
                internal_format |= MALI_GRALLOC_INTFMT_AFBC_TILED_HEADERS;
            }
        }
        else if(consumer == MALI_GRALLOC_CONSUMER_VIDEO_ENCODER)
        {
            vpu_mask &= consumer_runtime_mask;

            if(req_format == HAL_PIXEL_FORMAT_YV12)
            {
                if(gpu_mask & MALI_GRALLOC_FORMAT_CAPABILITY_AFBC_BASIC &&
                   vpu_mask & MALI_GRALLOC_FORMAT_CAPABILITY_AFBC_BASIC)
                {
                    internal_format |= MALI_GRALLOC_INTFMT_AFBC_BASIC;
                }

                if(gpu_mask & MALI_GRALLOC_FORMAT_CAPABILITY_AFBC_TILED_HEADERS &&
                   vpu_mask & MALI_GRALLOC_FORMAT_CAPABILITY_AFBC_TILED_HEADERS)
                {
                    internal_format |= MALI_GRALLOC_INTFMT_AFBC_TILED_HEADERS;
                }
            }
        }
    }
    else if(producer == MALI_GRALLOC_PRODUCER_VIDEO_DECODER && vpu_runtime_caps.caps_mask & MALI_GRALLOC_FORMAT_CAPABILITY_OPTIONS_PRESENT)
    {
        vpu_mask &= producer_runtime_mask;

        if(consumer == MALI_GRALLOC_CONSUMER_GPU_OR_DISPLAY)
        {
            gpu_mask &= consumer_runtime_mask;
            dpu_mask &= consumer_runtime_mask;

            if(internal_format == HAL_PIXEL_FORMAT_YV12)
            {
                if(vpu_mask & MALI_GRALLOC_FORMAT_CAPABILITY_AFBC_BASIC &&
                   gpu_mask & MALI_GRALLOC_FORMAT_CAPABILITY_AFBC_BASIC &&
                   dpu_mask & MALI_GRALLOC_FORMAT_CAPABILITY_AFBC_BASIC)
                {
                    internal_format |= MALI_GRALLOC_INTFMT_AFBC_BASIC;
                }

                if(vpu_mask & MALI_GRALLOC_FORMAT_CAPABILITY_AFBC_TILED_HEADERS &&
                   gpu_mask & MALI_GRALLOC_FORMAT_CAPABILITY_AFBC_TILED_HEADERS &&
                   dpu_mask & MALI_GRALLOC_FORMAT_CAPABILITY_AFBC_TILED_HEADERS)
                {
                    internal_format |= MALI_GRALLOC_INTFMT_AFBC_TILED_HEADERS;
                }
            }
        }
        else if(consumer == MALI_GRALLOC_CONSUMER_GPU_EXCL)
        {
            gpu_mask &= consumer_runtime_mask;

            if(internal_format == HAL_PIXEL_FORMAT_YV12)
            {
                if(gpu_mask & MALI_GRALLOC_FORMAT_CAPABILITY_AFBC_BASIC &&
                   vpu_mask & MALI_GRALLOC_FORMAT_CAPABILITY_AFBC_BASIC)
                {
                    internal_format |= MALI_GRALLOC_INTFMT_AFBC_BASIC;
                }

                if(gpu_mask & MALI_GRALLOC_FORMAT_CAPABILITY_AFBC_TILED_HEADERS &&
                   vpu_mask & MALI_GRALLOC_FORMAT_CAPABILITY_AFBC_TILED_HEADERS)
                {
                    internal_format |= MALI_GRALLOC_INTFMT_AFBC_TILED_HEADERS;
                }
            }
        }
        else if(consumer == MALI_GRALLOC_CONSUMER_VIDEO_ENCODER)
        {
            /* Fall-through. To be decided.*/
        }
  }
  else if(producer == MALI_GRALLOC_PRODUCER_CAMERA && cam_runtime_caps.caps_mask & MALI_GRALLOC_FORMAT_CAPABILITY_OPTIONS_PRESENT)
  {
        if(consumer == MALI_GRALLOC_CONSUMER_GPU_OR_DISPLAY)
        {
            /* Fall-through. To be decided.*/
        }
        else if(consumer == MALI_GRALLOC_CONSUMER_GPU_EXCL)
        {
            /* Fall-through. To be decided.*/
        }
        else if(consumer == MALI_GRALLOC_CONSUMER_VIDEO_ENCODER)
        {
            /* Fall-through. To be decided.*/
        }
  }
  return internal_format;
}

static uint64_t decode_internal_format(int req_format)
{
    uint64_t internal_format, me_mask, base_format, mapped_base_format;
    uint64_t ignore_mask;

    internal_format = GRALLOC_PRIVATE_FORMAT_UNWRAP(req_format);

    me_mask = internal_format & MALI_GRALLOC_INTFMT_ME_EXT_MASK;
    if(me_mask > 0 && ((me_mask - 1) & me_mask) != 0)
    {
        ALOGE("Internal format contains multiple mutually exclusive modifier bits: %" PRIx64, internal_format);
        internal_format = 0;
        goto out;
    }

    base_format = internal_format & MALI_GRALLOC_INTFMT_FMT_MASK;

    /* Even though private format allocations are intended to be for specific
     * formats, certain test cases uses the flexible formats that needs to be mapped
     * to internal ones.
     */
    mapped_base_format = map_flex_formats((uint32_t ) base_format, &ignore_mask);

    /* Validate the internal base format passed in */
    switch(mapped_base_format)
    {
        case MALI_GRALLOC_FORMAT_INTERNAL_RGBA_8888:
        case MALI_GRALLOC_FORMAT_INTERNAL_RGBX_8888:
        case MALI_GRALLOC_FORMAT_INTERNAL_RGB_888:
        case MALI_GRALLOC_FORMAT_INTERNAL_RGB_565:
        case MALI_GRALLOC_FORMAT_INTERNAL_BGRA_8888:
        case MALI_GRALLOC_FORMAT_INTERNAL_YV12:
        case MALI_GRALLOC_FORMAT_INTERNAL_Y8:
        case MALI_GRALLOC_FORMAT_INTERNAL_Y16:
        case MALI_GRALLOC_FORMAT_INTERNAL_RAW16:
        case MALI_GRALLOC_FORMAT_INTERNAL_RAW12:
        case MALI_GRALLOC_FORMAT_INTERNAL_RAW10:
        case MALI_GRALLOC_FORMAT_INTERNAL_BLOB:
        case MALI_GRALLOC_FORMAT_INTERNAL_NV12:
        case MALI_GRALLOC_FORMAT_INTERNAL_NV21:
        case MALI_GRALLOC_FORMAT_INTERNAL_YUV422_8BIT:
        case MALI_GRALLOC_FORMAT_INTERNAL_Y0L2:
        case MALI_GRALLOC_FORMAT_INTERNAL_P010:
        case MALI_GRALLOC_FORMAT_INTERNAL_P210:
        case MALI_GRALLOC_FORMAT_INTERNAL_Y210:
        case MALI_GRALLOC_FORMAT_INTERNAL_Y410:
            if(mapped_base_format != base_format)
            {
                internal_format = (internal_format & MALI_GRALLOC_INTFMT_EXT_MASK) | mapped_base_format;
            }
            break;

        default:
            ALOGE("Internal base format requested is unrecognized: %" PRIx64 ,internal_format);
            internal_format = 0;
            break;
    }
out:
    return internal_format;
}

static bool determine_producer(mali_gralloc_producer_type *producer, uint64_t *producer_runtime_mask, int req_format, int usage)
{
    bool rval = true;

    /* Default to GPU */
    *producer = MALI_GRALLOC_PRODUCER_GPU;

    if(usage & (GRALLOC_USAGE_SW_READ_MASK | GRALLOC_USAGE_SW_WRITE_MASK))
    {
        rval = false;
    }
    else if(usage & GRALLOC_USAGE_HW_RENDER)
    {
        if(is_android_yuv_format(req_format))
        {
            if(gpu_runtime_caps.caps_mask & MALI_GRALLOC_FORMAT_CAPABILITY_AFBC_YUV_NOWRITE)
            {
                *producer_runtime_mask &= ~MALI_GRALLOC_FORMAT_CAPABILITY_AFBCENABLE_MASK;
            }
            else
            {
                /* All GPUs that can write YUV AFBC can only do it in 16x16, optionally with tiled */
                *producer_runtime_mask &= ~(MALI_GRALLOC_FORMAT_CAPABILITY_AFBC_SPLITBLK | MALI_GRALLOC_FORMAT_CAPABILITY_AFBC_WIDEBLK);
            }
        }
        *producer = MALI_GRALLOC_PRODUCER_GPU;
    }
    else if(usage & GRALLOC_USAGE_HW_CAMERA_MASK)
    {
        *producer = MALI_GRALLOC_PRODUCER_CAMERA;
    }
    /* HW_TEXTURE+HW_COMPOSER+EXTERNAL_DISP is a definition set by
     * stagefright for "video decoder". We check for it here.
     */
    else if((usage & (GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_EXTERNAL_DISP)) ==
                    (GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_EXTERNAL_DISP))
    {
        *producer = MALI_GRALLOC_PRODUCER_VIDEO_DECODER;
    }

   return rval;
}

static bool determine_consumer(mali_gralloc_consumer_type *consumer, uint64_t *consumer_runtime_mask, int req_format, int usage)
{
    bool rval = true;

    /* Default to GPU */
    *consumer = MALI_GRALLOC_CONSUMER_GPU_EXCL;

    if(usage & (GRALLOC_USAGE_SW_READ_MASK | GRALLOC_USAGE_SW_WRITE_MASK))
    {
        rval = false;
    }
    /* When usage explicitly targets a consumer, as it does with GRALLOC_USAGE_HW_FB,
     * we pick DPU even if there are no runtime capabilities present.
     */
    else if( usage & GRALLOC_USAGE_HW_FB )
    {
        *consumer = MALI_GRALLOC_CONSUMER_GPU_OR_DISPLAY;
    }
    else if(usage & GRALLOC_USAGE_HW_VIDEO_ENCODER)
    {
        if((vpu_runtime_caps.caps_mask & MALI_GRALLOC_FORMAT_CAPABILITY_AFBC_YUV_NOREAD) &&
           is_android_yuv_format(req_format))
        {
            *consumer_runtime_mask &= ~MALI_GRALLOC_FORMAT_CAPABILITY_AFBCENABLE_MASK;
        }
        *consumer = MALI_GRALLOC_CONSUMER_VIDEO_ENCODER;
    }
    /* GRALLOC_USAGE_HW_COMPOSER is by default applied by SurfaceFlinger so we can't exclusively rely on it
     * to determine consumer. When a buffer is targeted for either we reject the DPU when it lacks
     * runtime capabilities, in favor of the more capable GPU.
     */
    else if((usage & (GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_COMPOSER )) == (GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_COMPOSER ) &&
            dpu_runtime_caps.caps_mask & MALI_GRALLOC_FORMAT_CAPABILITY_OPTIONS_PRESENT)
    {
        *consumer = MALI_GRALLOC_CONSUMER_GPU_OR_DISPLAY;
    }
    else if(usage & GRALLOC_USAGE_HW_TEXTURE)
    {
        *consumer = MALI_GRALLOC_CONSUMER_GPU_EXCL;
    }
    return rval;
}

/*
 * Here we determine format capabilities for the 4 IPs we support.
 * For now these are controlled by build defines, but in the future
 * they should be read out from each user-space driver.
 */
static void determine_format_capabilities()
{
    /* Loading libraries can take some time and
     * we may see many allocations at boot.
     */
    pthread_mutex_lock(&caps_init_mutex);

    if(runtime_caps_read)
    {
        goto already_init;
    }

    memset((void*) &dpu_runtime_caps,0,sizeof(dpu_runtime_caps));
    memset((void*) &vpu_runtime_caps,0,sizeof(vpu_runtime_caps));
    memset((void*) &gpu_runtime_caps,0,sizeof(gpu_runtime_caps));
    memset((void*) &cam_runtime_caps,0,sizeof(cam_runtime_caps));

    /* Determine DPU format capabilities */
    if(!get_block_capabilities(true, "hwcomposer", &dpu_runtime_caps))
    {
#if MALI_DISPLAY_VERSION >= 500
        dpu_runtime_caps.caps_mask |= MALI_GRALLOC_FORMAT_CAPABILITY_OPTIONS_PRESENT;
        dpu_runtime_caps.caps_mask |=  MALI_GRALLOC_FORMAT_CAPABILITY_AFBC_BASIC;

#if MALI_DISPLAY_VERSION >= 550
        dpu_runtime_caps.caps_mask |=  MALI_GRALLOC_FORMAT_CAPABILITY_AFBC_SPLITBLK;
#endif
#endif
    }

    /* Determine GPU format capabilities */
    if(access(MALI_GRALLOC_GPU_LIBRARY_PATH1 MALI_GRALLOC_GPU_LIB_NAME,R_OK) == 0)
    {
        get_block_capabilities(false, MALI_GRALLOC_GPU_LIBRARY_PATH1 MALI_GRALLOC_GPU_LIB_NAME, &gpu_runtime_caps);
    }
    else if(access(MALI_GRALLOC_GPU_LIBRARY_PATH2 MALI_GRALLOC_GPU_LIB_NAME,R_OK) == 0)
    {
        get_block_capabilities(false, MALI_GRALLOC_GPU_LIBRARY_PATH2 MALI_GRALLOC_GPU_LIB_NAME, &gpu_runtime_caps);
    }

    if((gpu_runtime_caps.caps_mask & MALI_GRALLOC_FORMAT_CAPABILITY_OPTIONS_PRESENT) == 0)
    {
        ALOGW("Failed to find GPU block configuration in %s. Using static build configuration.", MALI_GRALLOC_GPU_LIB_NAME);

#if MALI_GPU_SUPPORT_AFBC_BASIC == 1
        gpu_runtime_caps.caps_mask |= MALI_GRALLOC_FORMAT_CAPABILITY_OPTIONS_PRESENT;
        gpu_runtime_caps.caps_mask |= MALI_GRALLOC_FORMAT_CAPABILITY_AFBC_BASIC;

        /* Need to verify when to remove this */
        gpu_runtime_caps.caps_mask |= MALI_GRALLOC_FORMAT_CAPABILITY_AFBC_YUV_NOWRITE;

#if MALI_SUPPORT_AFBC_SPLITBLK == 1
        gpu_runtime_caps.caps_mask |= MALI_GRALLOC_FORMAT_CAPABILITY_AFBC_SPLITBLK;
#endif

#if MALI_SUPPORT_AFBC_WIDEBLK == 1
        gpu_runtime_caps.caps_mask |= MALI_GRALLOC_FORMAT_CAPABILITY_AFBC_SPLITBLK;
        gpu_runtime_caps.caps_mask |= MALI_GRALLOC_FORMAT_CAPABILITY_AFBC_WIDEBLK;
#endif

#if MALI_USE_YUV_AFBC_WIDEBLK != 1
        gpu_runtime_caps.caps_mask |= MALI_GRALLOC_FORMAT_CAPABILITY_AFBC_WIDEBLK_YUV_DISABLE;
#endif

#if MALI_SUPPORT_AFBC_TILED_HEADERS == 1
        gpu_runtime_caps.caps_mask |= MALI_GRALLOC_FORMAT_CAPABILITY_AFBC_SPLITBLK;
        gpu_runtime_caps.caps_mask |= MALI_GRALLOC_FORMAT_CAPABILITY_AFBC_WIDEBLK;
        gpu_runtime_caps.caps_mask |= MALI_GRALLOC_FORMAT_CAPABILITY_AFBC_TILED_HEADERS;
#endif
#endif /* MALI_GPU_SUPPORT_AFBC_BASIC == 1 */
    }

    /* Determine VPU format capabilities */
#if MALI_VIDEO_VERSION == 500 || MALI_VIDEO_VERSION == 550
    vpu_runtime_caps.caps_mask |= MALI_GRALLOC_FORMAT_CAPABILITY_OPTIONS_PRESENT;
    vpu_runtime_caps.caps_mask |= MALI_GRALLOC_FORMAT_CAPABILITY_AFBC_BASIC;
    vpu_runtime_caps.caps_mask |= MALI_GRALLOC_FORMAT_CAPABILITY_AFBC_YUV_NOREAD;
#endif

#if MALI_VIDEO_VERSION == 61
    vpu_runtime_caps.caps_mask |= MALI_GRALLOC_FORMAT_CAPABILITY_OPTIONS_PRESENT;
    vpu_runtime_caps.caps_mask |= MALI_GRALLOC_FORMAT_CAPABILITY_AFBC_BASIC;
    vpu_runtime_caps.caps_mask |= MALI_GRALLOC_FORMAT_CAPABILITY_AFBC_TILED_HEADERS;
#endif


    /* Build specific capability changes */
#if GRALLOC_ARM_NO_EXTERNAL_AFBC == 1
    {
        dpu_runtime_caps.caps_mask &= ~MALI_GRALLOC_FORMAT_CAPABILITY_AFBCENABLE_MASK;
        gpu_runtime_caps.caps_mask &= ~MALI_GRALLOC_FORMAT_CAPABILITY_AFBCENABLE_MASK;
        vpu_runtime_caps.caps_mask &= ~MALI_GRALLOC_FORMAT_CAPABILITY_AFBCENABLE_MASK;
        cam_runtime_caps.caps_mask &= ~MALI_GRALLOC_FORMAT_CAPABILITY_AFBCENABLE_MASK;
    }
#endif

    runtime_caps_read = true;

already_init:
    pthread_mutex_unlock(&caps_init_mutex);

    ALOGV("GPU format capabilities 0x%" PRIx64 , gpu_runtime_caps.caps_mask);
    ALOGV("DPU format capabilities 0x%" PRIx64 , dpu_runtime_caps.caps_mask);
    ALOGV("VPU format capabilities 0x%" PRIx64 , vpu_runtime_caps.caps_mask);
    ALOGV("CAM format capabilities 0x%" PRIx64 , cam_runtime_caps.caps_mask);
}

uint64_t mali_gralloc_select_format(int req_format, int usage, int buffer_size)
{
    uint64_t internal_format = 0;
    mali_gralloc_consumer_type consumer;
    mali_gralloc_producer_type producer;
    uint64_t producer_runtime_mask = ~(0ULL);
    uint64_t consumer_runtime_mask = ~(0ULL);
    int req_format_mapped=0;

    if(!runtime_caps_read)
    {
        /*
         * It is better to initialize these when needed because
         * not all processes allocates memory.
         */
        determine_format_capabilities();
    }

    /* A unique usage specifies that an internal format is in req_format */
    if(usage & MALI_GRALLOC_USAGE_PRIVATE_FORMAT)
    {
        internal_format = decode_internal_format(req_format);
        goto out;
    }

    /* Re-map special Android formats */
    req_format_mapped = map_flex_formats(req_format, &producer_runtime_mask);

    /* Determine producer/consumer */
    if(!determine_producer(&producer, &producer_runtime_mask, req_format, usage) ||
       !determine_consumer(&consumer, &consumer_runtime_mask, req_format, usage))
    {
        /* Failing to determine producer/consumer usually means
         * client has requested sw rendering.
         */
        internal_format = req_format_mapped;
        goto out;
    }

    /*
     * Determine runtime capability limitations
     */

    /* Disable AFBC based on unique usage */
    if ((usage & MALI_GRALLOC_USAGE_NO_AFBC) == MALI_GRALLOC_USAGE_NO_AFBC)
    {
        if(is_android_yuv_format(req_format_mapped))
        {
            ALOGE("It is invalid to specify NO_AFBC usage flags when allocating YUV formats.\
                   Requested fmt: 0x%08X Re-Mapped fmt: 0x%08X",req_format,req_format_mapped);
            internal_format = 0;
            goto out;
        }
        producer_runtime_mask &= ~MALI_GRALLOC_FORMAT_CAPABILITY_AFBCENABLE_MASK;
    }
    /* Disable AFBC based on buffer dimensions */
    else if(!is_afbc_allowed(buffer_size))
    {
        producer_runtime_mask &= ~MALI_GRALLOC_FORMAT_CAPABILITY_AFBCENABLE_MASK;
    }
    else if(!is_afbc_supported(req_format_mapped))
    {
        producer_runtime_mask &= ~MALI_GRALLOC_FORMAT_CAPABILITY_AFBCENABLE_MASK;
    }

    /* Automatically select format in case producer/consumer identified */
    internal_format = determine_best_format(req_format_mapped, producer, consumer, producer_runtime_mask, consumer_runtime_mask);

out:
    ALOGV("mali_gralloc_select_format: req_format=0x%08X req_fmt_mapped=0x%08X internal_format=0x%" PRIx64 " usage=0x%08X",req_format, req_format_mapped, internal_format, usage);

    return internal_format;
}

extern "C"
{
void mali_gralloc_get_gpu_caps(struct mali_gralloc_format_caps *gpu_caps)
{
    if(gpu_caps != NULL)
    {
        if(!runtime_caps_read)
        {
            determine_format_capabilities();
        }
        memcpy(gpu_caps,(void*) &gpu_runtime_caps,sizeof(struct mali_gralloc_format_caps));
    }
}
}