blob: 5f994ee05534df2074fac61b31abfdb871e8f2db [file] [log] [blame]
/*
* Copyright (c) 2011 Intel Corporation. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
* IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#include <sys/mman.h>
#include <va/va_tpi.h>
#include "psb_drv_video.h"
#include "psb_drv_debug.h"
#include "psb_surface.h"
#include "psb_surface_attrib.h"
#include <gralloc.h>
#include "android/psb_gralloc.h"
#include "android/psb_android_glue.h"
#ifndef BAYTRAIL
#include <hal/hal_public.h>
#endif
#include <wsbm/wsbm_manager.h>
#define INIT_DRIVER_DATA psb_driver_data_p driver_data = (psb_driver_data_p) ctx->pDriverData;
#define CONFIG(id) ((object_config_p) object_heap_lookup( &driver_data->config_heap, id ))
#define CONTEXT(id) ((object_context_p) object_heap_lookup( &driver_data->context_heap, id ))
#define SURFACE(id) ((object_surface_p) object_heap_lookup( &driver_data->surface_heap, id ))
#define BUFFER(id) ((object_buffer_p) object_heap_lookup( &driver_data->buffer_heap, id ))
#define SHARE_INFO_INIT_VALUE 0x12345678
static pthread_mutex_t gralloc_mutex = PTHREAD_MUTEX_INITIALIZER;
/*FIXME: include hal_public.h instead of define it here*/
enum {
GRALLOC_SUB_BUFFER0 = 0,
GRALLOC_SUB_BUFFER1,
GRALLOC_SUB_BUFFER2,
GRALLOC_SUB_BUFFER_MAX,
};
VAStatus psb_DestroySurfaceGralloc(object_surface_p obj_surface)
{
void *vaddr[GRALLOC_SUB_BUFFER_MAX];
int usage = GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_COMPOSER;
buffer_handle_t handle = obj_surface->psb_surface->buf.handle;
VAStatus vaStatus = VA_STATUS_SUCCESS;
#ifdef PSBVIDEO_MRFL
usage |= GRALLOC_USAGE_SW_WRITE_OFTEN;
#endif
pthread_mutex_lock(&gralloc_mutex);
if (!gralloc_lock(handle, usage, 0, 0,
obj_surface->width, obj_surface->height, (void **)&vaddr[GRALLOC_SUB_BUFFER0])){
if (obj_surface->share_info && vaddr[GRALLOC_SUB_BUFFER1] == obj_surface->share_info) {
int metadata_rotate = obj_surface->share_info->metadata_rotate;
int surface_protected = obj_surface->share_info->surface_protected;
int force_output_method = obj_surface->share_info->force_output_method;
int bob_deinterlace = obj_surface->share_info->bob_deinterlace;
memset(obj_surface->share_info, 0, sizeof(struct psb_surface_share_info_s));
/* Still need to keep these info so that hwc can get them after suspend/resume cycle */
obj_surface->share_info->metadata_rotate = metadata_rotate;
obj_surface->share_info->surface_protected = surface_protected;
obj_surface->share_info->force_output_method = force_output_method;
obj_surface->share_info->bob_deinterlace = bob_deinterlace;
}
gralloc_unlock(handle);
if (gralloc_unregister(handle))
vaStatus = VA_STATUS_ERROR_UNKNOWN;
}
pthread_mutex_unlock(&gralloc_mutex);
return vaStatus;
}
#ifdef BAYTRAIL
VAStatus psb_CreateSurfacesFromGralloc(
VADriverContextP ctx,
int width,
int height,
int format,
int num_surfaces,
VASurfaceID *surface_list, /* out */
PsbSurfaceAttributeTPI *attribute_tpi
)
{
INIT_DRIVER_DATA
VAStatus vaStatus = VA_STATUS_SUCCESS;
int i, height_origin, usage, buffer_stride = 0;
int protected = (VA_RT_FORMAT_PROTECTED & format);
unsigned long fourcc;
VASurfaceAttributeTPI *external_buffers = NULL;
unsigned long handle;
int size = num_surfaces * sizeof(unsigned int);
void *vaddr;
/* follow are gralloc-buffers */
format = format & (~VA_RT_FORMAT_PROTECTED);
driver_data->protected = protected;
CHECK_INVALID_PARAM(num_surfaces <= 0);
CHECK_SURFACE(surface_list);
external_buffers = attribute_tpi;
ALOGD("format is 0x%x, width is %d, height is %d, num_surfaces is %d.\n", format, width, height, num_surfaces);
/* We only support one format */
if ((VA_RT_FORMAT_YUV420 != format)
&& (VA_RT_FORMAT_YUV422 != format)) {
vaStatus = VA_STATUS_ERROR_UNSUPPORTED_RT_FORMAT;
DEBUG_FAILURE;
return vaStatus;
}
CHECK_INVALID_PARAM(external_buffers == NULL);
/*
vaStatus = psb__checkSurfaceDimensions(driver_data, width, height);
CHECK_VASTATUS();
*/
/* Adjust height to be a multiple of 32 (height of macroblock in interlaced mode) */
height_origin = height;
height = (height + 0x1f) & ~0x1f;
ALOGD("external_buffers->pixel_format is 0x%x.\n", external_buffers->pixel_format);
/* get native window from the reserved field */
driver_data->native_window = (void *)external_buffers->reserved[0];
for (i = 0; i < num_surfaces; i++) {
int surfaceID;
object_surface_p obj_surface;
psb_surface_p psb_surface;
surfaceID = object_heap_allocate(&driver_data->surface_heap);
obj_surface = SURFACE(surfaceID);
if (NULL == obj_surface) {
vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
DEBUG_FAILURE;
break;
}
MEMSET_OBJECT(obj_surface, struct object_surface_s);
obj_surface->surface_id = surfaceID;
surface_list[i] = surfaceID;
obj_surface->context_id = -1;
obj_surface->width = width;
obj_surface->height = height;
obj_surface->width_r = width;
obj_surface->height_r = height;
obj_surface->height_origin = height_origin;
obj_surface->is_ref_surface = 0;
psb_surface = (psb_surface_p) calloc(1, sizeof(struct psb_surface_s));
if (NULL == psb_surface) {
object_heap_free(&driver_data->surface_heap, (object_base_p) obj_surface);
obj_surface->surface_id = VA_INVALID_SURFACE;
vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
DEBUG_FAILURE;
break;
}
switch (format) {
case VA_RT_FORMAT_YUV422:
fourcc = VA_FOURCC_YV16;
break;
case VA_RT_FORMAT_YUV420:
default:
fourcc = VA_FOURCC_NV12;
break;
}
/*hard code the gralloc buffer usage*/
usage = GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_COMPOSER;
/* usage hack for byt */
usage |= GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN;
/* usage hack to force pages alloc and CPU/GPU cache flush */
usage |= GRALLOC_USAGE_HW_VIDEO_ENCODER;
handle = (unsigned long)external_buffers->buffers[i];
pthread_mutex_lock(&gralloc_mutex);
if (gralloc_lock(handle, usage, 0, 0, width, height, (void **)&vaddr)) {
vaStatus = VA_STATUS_ERROR_UNKNOWN;
} else {
int cache_flag = PSB_USER_BUFFER_UNCACHED;
int buf_fd = gralloc_getbuffd(handle);
vaStatus = psb_surface_create_from_ub(driver_data, width, height, fourcc,
external_buffers, psb_surface, vaddr, buf_fd,
cache_flag);
psb_surface->buf.handle = handle;
obj_surface->share_info = NULL;
gralloc_unlock(handle);
}
pthread_mutex_unlock(&gralloc_mutex);
if (VA_STATUS_SUCCESS != vaStatus) {
free(psb_surface);
object_heap_free(&driver_data->surface_heap, (object_base_p) obj_surface);
obj_surface->surface_id = VA_INVALID_SURFACE;
DEBUG_FAILURE;
break;
}
buffer_stride = psb_surface->stride;
#ifdef PSBVIDEO_MSVDX_DEC_TILING
psb_surface->extra_info[7] = external_buffers->tiling;
#endif
/* by default, surface fourcc is NV12 */
psb_surface->extra_info[4] = fourcc;
obj_surface->psb_surface = psb_surface;
}
/* Error recovery */
if (VA_STATUS_SUCCESS != vaStatus) {
/* surface_list[i-1] was the last successful allocation */
for (; i--;) {
object_surface_p obj_surface = SURFACE(surface_list[i]);
psb__destroy_surface(driver_data, obj_surface);
surface_list[i] = VA_INVALID_SURFACE;
}
drv_debug_msg(VIDEO_DEBUG_ERROR, "CreateSurfaces failed\n");
return vaStatus;
}
return vaStatus;
}
#else
VAStatus psb_CreateSurfacesFromGralloc(
VADriverContextP ctx,
int width,
int height,
int format,
int num_surfaces,
VASurfaceID *surface_list, /* out */
PsbSurfaceAttributeTPI *attribute_tpi
)
{
INIT_DRIVER_DATA
VAStatus vaStatus = VA_STATUS_SUCCESS;
int i, height_origin, usage, buffer_stride = 0;
int protected = (VA_RT_FORMAT_PROTECTED & format);
unsigned long fourcc;
PsbSurfaceAttributeTPI *external_buffers = NULL;
unsigned long handle;
int size = num_surfaces * sizeof(unsigned int);
void *vaddr[GRALLOC_SUB_BUFFER_MAX];
/* follow are gralloc-buffers */
format = format & (~VA_RT_FORMAT_PROTECTED);
driver_data->protected = protected;
CHECK_INVALID_PARAM(num_surfaces <= 0);
CHECK_SURFACE(surface_list);
external_buffers = attribute_tpi;
/* We only support one format */
if ((VA_RT_FORMAT_YUV420 != format)
&& (VA_RT_FORMAT_YUV422 != format)
&& (VA_RT_FORMAT_RGB32 != format)) {
vaStatus = VA_STATUS_ERROR_UNSUPPORTED_RT_FORMAT;
DEBUG_FAILURE;
return vaStatus;
}
CHECK_INVALID_PARAM(external_buffers == NULL);
/*
vaStatus = psb__checkSurfaceDimensions(driver_data, width, height);
CHECK_VASTATUS();
*/
/* Adjust height to be a multiple of 32 (height of macroblock in interlaced mode) */
height_origin = height;
IMG_native_handle_t* h = (IMG_native_handle_t*)external_buffers->buffers[0];
int gfx_colorformat = h->iFormat;
if (gfx_colorformat != HAL_PIXEL_FORMAT_NV12 && format != VA_RT_FORMAT_RGB32)
height = (height + 0x1f) & ~0x1f;
/* get native window from the reserved field */
driver_data->native_window = (void *)external_buffers->reserved[0];
for (i = 0; i < num_surfaces; i++) {
int surfaceID;
object_surface_p obj_surface;
psb_surface_p psb_surface;
surfaceID = object_heap_allocate(&driver_data->surface_heap);
obj_surface = SURFACE(surfaceID);
if (NULL == obj_surface) {
vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
DEBUG_FAILURE;
break;
}
MEMSET_OBJECT(obj_surface, struct object_surface_s);
obj_surface->surface_id = surfaceID;
surface_list[i] = surfaceID;
obj_surface->context_id = -1;
obj_surface->width = width;
obj_surface->height = height;
obj_surface->width_r = width;
obj_surface->height_r = height;
obj_surface->height_origin = height_origin;
psb_surface = (psb_surface_p) calloc(1, sizeof(struct psb_surface_s));
if (NULL == psb_surface) {
object_heap_free(&driver_data->surface_heap, (object_base_p) obj_surface);
obj_surface->surface_id = VA_INVALID_SURFACE;
vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
DEBUG_FAILURE;
break;
}
switch (format) {
case VA_RT_FORMAT_YUV422:
fourcc = VA_FOURCC_YV16;
break;
case VA_RT_FORMAT_RGB32:
fourcc = VA_FOURCC_RGBA;
break;
case VA_RT_FORMAT_YUV420:
default:
fourcc = VA_FOURCC_NV12;
break;
}
#ifndef PSBVIDEO_MSVDX_DEC_TILING
external_buffers->tiling = 0;
#endif
/*hard code the gralloc buffer usage*/
usage = GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_COMPOSER;
if (gfx_colorformat == HAL_PIXEL_FORMAT_NV12)
usage |= GRALLOC_USAGE_SW_READ_OFTEN;
else {
// video decoder allows app to read/write the buffer
usage |= GRALLOC_USAGE_SW_WRITE_RARELY | GRALLOC_USAGE_SW_READ_RARELY;
}
handle = (unsigned long)external_buffers->buffers[i];
pthread_mutex_lock(&gralloc_mutex);
if (gralloc_register((buffer_handle_t)handle)) {
vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
} else {
if (gralloc_lock((buffer_handle_t)handle, usage, 0, 0, width, height, (void **)&vaddr[GRALLOC_SUB_BUFFER0])) {
vaStatus = VA_STATUS_ERROR_UNKNOWN;
gralloc_unregister((buffer_handle_t)handle);
} else {
int cache_flag = PSB_USER_BUFFER_UNCACHED;
int buf_fd = gralloc_getbuffd((buffer_handle_t)handle);
#ifdef PSBVIDEO_MRFL
//cache_flag = 0;
#endif
vaStatus = psb_surface_create_from_ub(driver_data, width, height, fourcc,
(VASurfaceAttributeTPI *)external_buffers, psb_surface,
vaddr[GRALLOC_SUB_BUFFER0], buf_fd, cache_flag);
psb_surface->buf.handle = (void *)handle;
obj_surface->share_info = NULL;
if ((gfx_colorformat != HAL_PIXEL_FORMAT_NV12) &&
(gfx_colorformat != HAL_PIXEL_FORMAT_YV12) &&
(format != VA_RT_FORMAT_RGB32)) {
unsigned int decoder_share_info = (unsigned int)external_buffers->reserved[2];
drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s : Create graphic buffer initialized share info %d", __FUNCTION__, decoder_share_info);
obj_surface->share_info = (psb_surface_share_info_t *)vaddr[GRALLOC_SUB_BUFFER1];
if (obj_surface->share_info->initialized != SHARE_INFO_INIT_VALUE) {
memset(obj_surface->share_info, 0, sizeof(struct psb_surface_share_info_s));
// Set clear video the default output method as OUTPUT_FORCE_OVERLAY_FOR_SW_DECODE
// if the video can be decoded by HW, will reset the output method as 0 in psb_BeginPicture
#ifdef PSBVIDEO_MSVDX_DEC_TILING
obj_surface->share_info->tiling = external_buffers->tiling;
#endif
obj_surface->share_info->width = obj_surface->width;
obj_surface->share_info->height = obj_surface->height_origin;
obj_surface->share_info->luma_stride = psb_surface->stride;
obj_surface->share_info->chroma_u_stride = psb_surface->stride;
obj_surface->share_info->chroma_v_stride = psb_surface->stride;
obj_surface->share_info->format = VA_FOURCC_NV12;
obj_surface->share_info->khandle = (uint32_t)(wsbmKBufHandle(wsbmKBuf(psb_surface->buf.drm_buf)));
obj_surface->share_info->initialized = SHARE_INFO_INIT_VALUE;
}
if (decoder_share_info) {
obj_surface->share_info->force_output_method = protected ? OUTPUT_FORCE_OVERLAY : OUTPUT_FORCE_OVERLAY_FOR_SW_DECODE;
obj_surface->share_info->native_window = (void *)external_buffers->reserved[0];
attribute_tpi->reserved[1] = (unsigned long)obj_surface->share_info;
if (vaddr[GRALLOC_SUB_BUFFER0] == NULL) {
drv_debug_msg(VIDEO_DEBUG_ERROR, "Failed to lock graphic buffer in psb_video");
} else {
size = psb_surface->chroma_offset;
// the following memset was used to work-around Bug 19197299 on L.
// on DDK-1.5 we didn't observe the problem so comment it out.
// memset((char *)vaddr[GRALLOC_SUB_BUFFER0], 0, size);
// memset((char *)vaddr[GRALLOC_SUB_BUFFER0] + size, 0x80, psb_surface->size - size);
}
// overlay only support BT.601 and BT.709
if (driver_data->load_csc_matrix == 1) {
obj_surface->share_info->csc_mode = (driver_data->is_BT601 == 1) ? 0 : 1;
} else {
// if csc matrix is not set, use BT601 by default
obj_surface->share_info->csc_mode = 0;
}
if (driver_data->set_video_range == 1) {
obj_surface->share_info->video_range = driver_data->video_range;
} else {
// if video range is not set, use limited range by default
obj_surface->share_info->video_range = 0;
}
obj_surface->share_info->surface_protected = driver_data->protected;
if (driver_data->render_rect.width == 0 || driver_data->render_rect.height == 0) {
obj_surface->share_info->crop_width = obj_surface->share_info->width;
obj_surface->share_info->crop_height = obj_surface->share_info->height;
} else {
obj_surface->share_info->crop_width = driver_data->render_rect.width;
obj_surface->share_info->crop_height = driver_data->render_rect.height;
}
if (obj_surface->share_info->coded_width == 0 || obj_surface->share_info->coded_height == 0) {
obj_surface->share_info->coded_width = (obj_surface->share_info->width + 0xf) & ~0xf;
obj_surface->share_info->coded_height = (obj_surface->share_info->height + 0xf) & ~0xf;
}
drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s : Create graphic buffer success"
"surface_id= 0x%x, vaddr[0] (0x%x), vaddr[1] (0x%x)\n",
__FUNCTION__, surfaceID, vaddr[GRALLOC_SUB_BUFFER0], vaddr[GRALLOC_SUB_BUFFER1]);
}
}
gralloc_unlock((buffer_handle_t)handle);
psb_surface->buf.user_ptr = NULL;
}
}
pthread_mutex_unlock(&gralloc_mutex);
if (VA_STATUS_SUCCESS != vaStatus) {
free(psb_surface);
object_heap_free(&driver_data->surface_heap, (object_base_p) obj_surface);
obj_surface->surface_id = VA_INVALID_SURFACE;
DEBUG_FAILURE;
break;
}
buffer_stride = psb_surface->stride;
/* by default, surface fourcc is NV12 */
psb_surface->extra_info[4] = fourcc;
/* save the pixel format set by application */
psb_surface->extra_info[8] = external_buffers->pixel_format;
#ifdef PSBVIDEO_MSVDX_DEC_TILING
psb_surface->extra_info[7] = external_buffers->tiling;
#endif
obj_surface->psb_surface = psb_surface;
}
/* Error recovery */
if (VA_STATUS_SUCCESS != vaStatus) {
/* surface_list[i-1] was the last successful allocation */
for (; i--;) {
object_surface_p obj_surface = SURFACE(surface_list[i]);
psb__destroy_surface(driver_data, obj_surface);
surface_list[i] = VA_INVALID_SURFACE;
}
drv_debug_msg(VIDEO_DEBUG_ERROR, "CreateSurfaces failed\n");
return vaStatus;
}
return vaStatus;
}
#endif