blob: ccef8dd97dc29da348dc907b87b38ba578e7b90f [file] [log] [blame]
/*
* Copyright (c) 2009-2017, Intel Corporation
*
* 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, sublicense,
* 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 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 NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS 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.
*/
//!
//! \file media_libva_putsurface_linux.cpp
//! \brief libva(and its extension) putsurface linux implementaion
//!
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <fcntl.h> //open
#include <sys/stat.h> //fstat
#include <unistd.h> //read, lseek
#include <dlfcn.h> //dlopen,dlsym,dlclose
#include <time.h> //get_clocktime
#include <errno.h> //errno
#include <assert.h> //assert
#include <sys/mman.h>
#include <dlfcn.h>
#include <sys/ioctl.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include "media_libva_putsurface_linux.h"
#include "media_libva_util.h"
#include "media_libva_common.h"
#include "media_libva_vp.h"
extern MOS_FORMAT VpGetFormatFromMediaFormat(DDI_MEDIA_FORMAT mf);
extern VPHAL_CSPACE DdiVp_GetColorSpaceFromMediaFormat(DDI_MEDIA_FORMAT mf);
extern MOS_TILE_TYPE VpGetTileTypeFromMediaTileType(uint32_t mediaTileType);
/* Closes and disposed any allocated data */
void dso_close(struct dso_handle *h)
{
if (!h){
return;
}
if (h->handle) {
if (h->handle != RTLD_DEFAULT)
dlclose(h->handle);
h->handle = nullptr;
}
free(h);
}
/* Opens the named shared library */
struct dso_handle * dso_open(const char *path)
{
struct dso_handle *h = nullptr;
h = (dso_handle *)calloc(1, sizeof(*h));
if (!h){
return nullptr;
}
if (path) {
h->handle = dlopen(path, RTLD_LAZY|RTLD_LOCAL);
if (!h->handle)
goto error;
}
else{
h->handle = RTLD_DEFAULT;
}
return h;
error:
dso_close(h);
return nullptr;
}
/* Load function name from one dynamic lib */
static bool get_symbol(struct dso_handle *h, void *func_vptr, const char *name)
{
DDI_CHK_NULL(h, "nullptr h", false);
DDI_CHK_NULL(func_vptr, "nullptr func_vptr", false);
dso_generic_func func;
dso_generic_func * const func_ptr = (dso_generic_func*) func_vptr;
const char *error = nullptr;
dlerror();
func = (dso_generic_func)dlsym(h->handle, name);
error = dlerror();
if (error) {
fprintf(stderr, "error: failed to resolve %s(): %s\n", name, error);
return false;
}
*func_ptr = func;
return true;
}
//!
//! \brief Loads function name from vtable
//!
//! \param [in] h
//! Dso handle
//! \param [in] vtable
//! VA api table
//! \param [in] vtable_length
//! Length of VA api table
//! \param [in] symbols
//! Dso symbol
//!
//! \return bool
//! true if call success, else false
//!
bool
dso_get_symbols(
struct dso_handle *h,
void *vtable,
uint32_t vtable_length,
const struct dso_symbol *symbols
)
{
DDI_CHK_NULL(h, "nullptr h", false);
const struct dso_symbol *s = nullptr;
if (nullptr == symbols)
{
return VA_STATUS_ERROR_INVALID_PARAMETER;
}
for (s = symbols; s->name != nullptr; s++) {
if (s->offset + sizeof(dso_generic_func) > vtable_length)
return false;
if (!get_symbol(h, ((char *)vtable) + s->offset, s->name))
return false;
}
return true;
}
bool output_dri_init(VADriverContextP ctx)
{
DDI_CHK_NULL(ctx, "nullptr ctx", false);
PDDI_MEDIA_CONTEXT mediaDrvCtx = nullptr;
mediaDrvCtx = DdiMedia_GetMediaContext(ctx);
DDI_CHK_NULL(mediaDrvCtx, "nullptr ctx", false);
struct dso_handle *dso_handle = nullptr;
struct dri_vtable *dri_vtable = nullptr;
mediaDrvCtx->dri_output = nullptr;
static const struct dso_symbol symbols[] = {
{ "va_dri_get_drawable",
offsetof(struct dri_vtable, get_drawable) },
{ "va_dri_get_rendering_buffer",
offsetof(struct dri_vtable, get_rendering_buffer) },
{ "va_dri_swap_buffer",
offsetof(struct dri_vtable, swap_buffer) },
{ nullptr, }
};
mediaDrvCtx->dri_output = (va_dri_output*) calloc(1, sizeof(struct va_dri_output));
if (!mediaDrvCtx->dri_output){
goto error;
}
mediaDrvCtx->dri_output->handle = dso_open(LIBVA_X11_NAME);
if (!mediaDrvCtx->dri_output->handle){
free(mediaDrvCtx->dri_output);
mediaDrvCtx->dri_output = nullptr;
goto error;
}
dso_handle = mediaDrvCtx->dri_output->handle;
dri_vtable = &mediaDrvCtx->dri_output->vtable;
if (!dso_get_symbols(dso_handle, dri_vtable, sizeof(*dri_vtable), symbols)){
dso_close(mediaDrvCtx->dri_output->handle);
free(mediaDrvCtx->dri_output);
mediaDrvCtx->dri_output = nullptr;
goto error;
}
return true;
error:
return false;
}
void
inline Rect_init(
RECT *rect,
int16_t destx,
int16_t desty,
uint16_t destw,
uint16_t desth
)
{
if (nullptr == rect)
{
return;
}
rect->left = destx;
rect->top = desty;
rect->right = destx + destw;
rect->bottom = desty + desth;
}
VAStatus DdiCodec_PutSurfaceLinuxVphalExt(
VADriverContextP ctx,
VASurfaceID surface,
void *draw, /* Drawable of window system */
int16_t srcx,
int16_t srcy,
uint16_t srcw,
uint16_t srch,
int16_t destx,
int16_t desty,
uint16_t destw,
uint16_t desth,
VARectangle *cliprects, /* client supplied clip list */
uint32_t number_cliprects, /* number of clip rects in the clip list */
uint32_t flags /* de-interlacing flags */
)
{
GC gc;
int32_t depth;
Visual* visual;
XImage* ximg;
int32_t surf_width;
int32_t surf_height;
PDDI_MEDIA_CONTEXT mediaDrvCtx;
PDDI_MEDIA_SURFACE dstSurfBuffObj;
TypeXCreateGC pfn_XCreateGC = nullptr;
TypeXFreeGC pfn_XFreeGC = nullptr;
TypeXCreateImage pfn_XCreateImage = nullptr;
TypeXDestroyImage pfn_XDestroyImage = nullptr;
TypeXPutImage pfn_XPutImage = nullptr;
if (nullptr == draw)
{
return VA_STATUS_ERROR_UNKNOWN;
}
visual = nullptr;
ximg = nullptr;
mediaDrvCtx = DdiMedia_GetMediaContext(ctx);
dstSurfBuffObj = DdiMedia_GetSurfaceFromVASurfaceID(mediaDrvCtx, surface);
if (nullptr == dstSurfBuffObj)
{
return VA_STATUS_ERROR_UNKNOWN;
}
if (nullptr == mediaDrvCtx->X11FuncTable ||
nullptr == mediaDrvCtx->X11FuncTable->pfnXCreateGC ||
nullptr == mediaDrvCtx->X11FuncTable->pfnXFreeGC ||
nullptr == mediaDrvCtx->X11FuncTable->pfnXCreateImage ||
nullptr == mediaDrvCtx->X11FuncTable->pfnXDestroyImage ||
nullptr == mediaDrvCtx->X11FuncTable->pfnXPutImage)
{
return VA_STATUS_ERROR_UNKNOWN;
}
pfn_XCreateGC = (TypeXCreateGC)(mediaDrvCtx->X11FuncTable->pfnXCreateGC);
pfn_XFreeGC = (TypeXFreeGC)(mediaDrvCtx->X11FuncTable->pfnXFreeGC);
pfn_XCreateImage = (TypeXCreateImage)(mediaDrvCtx->X11FuncTable->pfnXCreateImage);
pfn_XDestroyImage = (TypeXDestroyImage)(mediaDrvCtx->X11FuncTable->pfnXDestroyImage);
pfn_XPutImage = (TypeXPutImage)(mediaDrvCtx->X11FuncTable->pfnXPutImage);
surf_width = dstSurfBuffObj->iWidth;
surf_height = dstSurfBuffObj->iHeight;
visual = DefaultVisual(ctx->native_dpy, ctx->x11_screen);
gc = (*pfn_XCreateGC)((Display*)ctx->native_dpy, (Drawable)draw, 0, nullptr);
depth = DefaultDepth(ctx->native_dpy, ctx->x11_screen);
if (TrueColor != visual->c_class)
{
DDI_ASSERTMESSAGE("Default visual of X display must be TrueColor.");
(*pfn_XFreeGC)((Display*)ctx->native_dpy, gc);
return VA_STATUS_ERROR_UNKNOWN;
}
ximg = (*pfn_XCreateImage)((Display*)ctx->native_dpy, visual, depth, ZPixmap, 0, nullptr,surf_width, surf_height, 32, 0 );
if (nullptr == ximg)
{
return VA_STATUS_ERROR_ALLOCATION_FAILED;
}
if (ximg->bits_per_pixel != 32)
{
DDI_ASSERTMESSAGE("Display uses %d bits/pixel this not supported.",ximg->bits_per_pixel);
(*pfn_XDestroyImage)(ximg);
(*pfn_XFreeGC)((Display*)ctx->native_dpy, gc);
return VA_STATUS_ERROR_UNKNOWN;
}
ximg->data = (char *)DdiMediaUtil_LockSurface(dstSurfBuffObj, (MOS_LOCKFLAG_READONLY | MOS_LOCKFLAG_WRITEONLY));
if (nullptr == ximg->data)
{
DdiMediaUtil_UnlockSurface(dstSurfBuffObj);
(*pfn_XDestroyImage)(ximg);
(*pfn_XFreeGC)((Display*)ctx->native_dpy, gc);
return VA_STATUS_ERROR_ALLOCATION_FAILED;
}
(*pfn_XPutImage)((Display*)ctx->native_dpy, (Drawable)draw, gc, ximg, 0, 0, destx, desty, surf_width, surf_height);
DdiMediaUtil_UnlockSurface(dstSurfBuffObj);
ximg->data = nullptr;
if (nullptr != ximg)
{
(*pfn_XDestroyImage)(ximg);
}
(*pfn_XFreeGC)((Display*)ctx->native_dpy, gc);
return VA_STATUS_SUCCESS;
}
VAStatus DdiCodec_PutSurfaceLinuxHW(
VADriverContextP ctx,
VASurfaceID surface,
void* draw, /* Drawable of window system */
int16_t srcx,
int16_t srcy,
uint16_t srcw,
uint16_t srch,
int16_t destx,
int16_t desty,
uint16_t destw,
uint16_t desth,
VARectangle *cliprects, /* client supplied clip list */
uint32_t number_cliprects, /* number of clip rects in the clip list */
uint32_t flags /* de-interlacing flags */
)
{
VphalState *vpHal = nullptr;
int32_t ovRenderIndex = 0;
VPHAL_SURFACE Surf;
VPHAL_SURFACE target;
VPHAL_RENDER_PARAMS renderParams;
VPHAL_COLORFILL_PARAMS colorFill;
MOS_STATUS eStatus = MOS_STATUS_INVALID_PARAMETER;
RECT srcRect = { 0, 0, 0, 0 };
RECT dstRect = { 0, 0, 0, 0 };
PDDI_MEDIA_CONTEXT mediaCtx;
PDDI_MEDIA_SURFACE bufferObject;
uint32_t width,height,pitch;
uint32_t drawable_tiling_mode;
uint32_t drawable_swizzle_mode;
MOS_ALLOC_GFXRES_PARAMS allocParams;
MOS_TILE_TYPE tileType;
uint32_t ctxType;
PDDI_VP_CONTEXT vpCtx;
struct dri_drawable* dri_drawable = nullptr;
union dri_buffer* buffer = nullptr;
GMM_RESCREATE_PARAMS gmmParams;
mediaCtx = DdiMedia_GetMediaContext(ctx);
DDI_CHK_NULL(mediaCtx, "Null mediaCtx", VA_STATUS_ERROR_INVALID_CONTEXT);
DDI_CHK_NULL(mediaCtx->dri_output, "Null mediaDrvCtx->dri_output", VA_STATUS_ERROR_INVALID_PARAMETER);
DDI_CHK_NULL(mediaCtx->pSurfaceHeap, "Null mediaDrvCtx->pSurfaceHeap", VA_STATUS_ERROR_INVALID_PARAMETER);
DDI_CHK_NULL(mediaCtx->pGmmClientContext, "Null mediaCtx->pGmmClientContext", VA_STATUS_ERROR_INVALID_PARAMETER);
DDI_CHK_LESS((uint32_t)surface, mediaCtx->pSurfaceHeap->uiAllocatedHeapElements, "Invalid surfaceId", VA_STATUS_ERROR_INVALID_SURFACE);
struct dri_vtable * const dri_vtable = &mediaCtx->dri_output->vtable;
DDI_CHK_NULL(dri_vtable, "Null dri_vtable", VA_STATUS_ERROR_INVALID_PARAMETER);
dri_drawable = dri_vtable->get_drawable(ctx, (Drawable)draw);
DDI_CHK_NULL(dri_drawable, "Null dri_drawable", VA_STATUS_ERROR_INVALID_PARAMETER);
buffer = dri_vtable->get_rendering_buffer(ctx, dri_drawable);
DDI_CHK_NULL(buffer, "Null buffer", VA_STATUS_ERROR_INVALID_PARAMETER);
bufferObject = DdiMedia_GetSurfaceFromVASurfaceID(mediaCtx, surface);
DDI_CHK_NULL(bufferObject, "Null bufferObject", VA_STATUS_ERROR_INVALID_SURFACE);
DdiMediaUtil_MediaPrintFps();
pitch = bufferObject->iPitch;
vpCtx = nullptr;
if (nullptr != mediaCtx->pVpCtxHeap->pHeapBase)
{
vpCtx = (PDDI_VP_CONTEXT)DdiMedia_GetContextFromContextID(ctx, (VAContextID)(0 + DDI_MEDIA_VACONTEXTID_OFFSET_VP), &ctxType);
DDI_CHK_NULL(vpCtx, "Null vpCtx", VA_STATUS_ERROR_INVALID_PARAMETER);
vpHal = vpCtx->pVpHal;
DDI_CHK_NULL(vpHal, "Null vpHal", VA_STATUS_ERROR_INVALID_PARAMETER);
}
else
{
return VA_STATUS_ERROR_INVALID_CONTEXT;
}
// Zero memory
MOS_ZeroMemory(&Surf, sizeof(Surf));
MOS_ZeroMemory(&target, sizeof(target));
MOS_ZeroMemory(&renderParams, sizeof(renderParams));
MOS_ZeroMemory(&gmmParams, sizeof(gmmParams));
renderParams.Component = COMPONENT_LibVA;
//Init source rectangle
Rect_init(&srcRect, srcx, srcy, srcw, srch);
Rect_init(&dstRect, destx, desty, destw, desth);
// Source Surface Information
Surf.Format = VpGetFormatFromMediaFormat(bufferObject->format); // Surface format
Surf.SurfType = SURF_IN_PRIMARY; // Surface type (context)
Surf.SampleType = SAMPLE_PROGRESSIVE;
Surf.ScalingMode = VPHAL_SCALING_AVS;
Surf.OsResource.Format = VpGetFormatFromMediaFormat(bufferObject->format);
Surf.OsResource.iWidth = bufferObject->iWidth;
Surf.OsResource.iHeight = bufferObject->iHeight;
Surf.OsResource.iPitch = bufferObject->iPitch;
Surf.OsResource.iCount = 0;
Surf.OsResource.TileType = VpGetTileTypeFromMediaTileType(bufferObject->TileType);
Surf.OsResource.bMapped = bufferObject->bMapped;
Surf.OsResource.bo = bufferObject->bo;
Surf.OsResource.pGmmResInfo = bufferObject->pGmmResourceInfo;
Surf.dwWidth = bufferObject->iWidth;
Surf.dwHeight = bufferObject->iHeight;
Surf.dwPitch = bufferObject->iPitch;
Surf.TileType = VpGetTileTypeFromMediaTileType(bufferObject->TileType);
Surf.ColorSpace = DdiVp_GetColorSpaceFromMediaFormat(bufferObject->format);
Surf.ExtendedGamut = false;
Surf.rcSrc = srcRect;
Surf.rcDst = dstRect;
MOS_LINUX_BO* drawable_bo = mos_bo_gem_create_from_name(mediaCtx->pDrmBufMgr, "rendering buffer", buffer->dri2.name);
if (nullptr == drawable_bo)
{
return VA_STATUS_ERROR_ALLOCATION_FAILED;
}
if (!mos_bo_get_tiling(drawable_bo, &drawable_tiling_mode, &drawable_swizzle_mode))
{
switch (drawable_tiling_mode)
{
case I915_TILING_Y:
tileType = MOS_TILE_Y;
break;
case I915_TILING_X:
tileType = MOS_TILE_X;
gmmParams.Flags.Info.TiledX = true;
break;
case I915_TILING_NONE:
tileType = MOS_TILE_LINEAR;
gmmParams.Flags.Info.Linear = true;
break;
default:
drawable_tiling_mode = I915_TILING_NONE;
tileType = MOS_TILE_LINEAR;
gmmParams.Flags.Info.Linear = true;
break;
target.OsResource.TileType = (MOS_TILE_TYPE)drawable_tiling_mode;
}
}
else
{
target.OsResource.TileType = (MOS_TILE_TYPE)I915_TILING_NONE;
tileType = MOS_TILE_LINEAR;
gmmParams.Flags.Info.Linear = true;
}
gmmParams.Flags.Info.LocalOnly = MEDIA_IS_SKU(&mediaCtx->SkuTable, FtrLocalMemory);
target.Format = Format_A8R8G8B8;
target.SurfType = SURF_OUT_RENDERTARGET;
//init target retangle
Rect_init(&srcRect, dri_drawable->x, dri_drawable->y, dri_drawable->width, dri_drawable->height);
Rect_init(&dstRect, dri_drawable->x, dri_drawable->y, dri_drawable->width, dri_drawable->height);
// Create GmmResourceInfo
gmmParams.Flags.Gpu.Video = true;
gmmParams.BaseWidth = dri_drawable->width;
gmmParams.BaseHeight = dri_drawable->height;
gmmParams.ArraySize = 1;
gmmParams.Type = RESOURCE_2D;
gmmParams.Format = GMM_FORMAT_R8G8B8A8_UNORM_TYPE;
//gmmParams.Format = GMM_FORMAT_B8G8R8A8_UNORM_TYPE;
target.OsResource.pGmmResInfo = mediaCtx->pGmmClientContext->CreateResInfoObject(&gmmParams);
if (nullptr == target.OsResource.pGmmResInfo)
{
mos_bo_unreference(drawable_bo);
return VA_STATUS_ERROR_ALLOCATION_FAILED;
}
target.OsResource.iWidth = dri_drawable->width;
target.OsResource.iHeight = dri_drawable->height;
target.OsResource.iPitch = buffer->dri2.pitch;
target.OsResource.Format = Format_A8R8G8B8;
target.OsResource.iCount = 0;
target.OsResource.bo = drawable_bo;
target.OsResource.pData = (uint8_t *)drawable_bo->virt;
target.OsResource.TileType = tileType;
target.TileType = tileType;
target.dwWidth = dri_drawable->width;
target.dwHeight = dri_drawable->height;
target.dwPitch = target.OsResource.iPitch;
target.ColorSpace = CSpace_sRGB;
target.ExtendedGamut = false;
target.rcSrc = srcRect;
target.rcDst = dstRect;
renderParams.uSrcCount = 1;
renderParams.uDstCount = 1;
renderParams.pSrc[0] = &Surf;
renderParams.pTarget[0] = &target;
renderParams.pColorFillParams = &colorFill;
renderParams.pColorFillParams->Color = 0xFF000000;
renderParams.pColorFillParams->bYCbCr = false;
renderParams.pColorFillParams->CSpace = CSpace_sRGB;
DdiMediaUtil_LockMutex(&mediaCtx->PutSurfaceRenderMutex);
eStatus = vpHal->Render(&renderParams);
if (MOS_FAILED(eStatus))
{
DdiMediaUtil_UnLockMutex(&mediaCtx->PutSurfaceRenderMutex);
mos_bo_unreference(drawable_bo);
return VA_STATUS_ERROR_OPERATION_FAILED;
}
DdiMediaUtil_UnLockMutex(&mediaCtx->PutSurfaceRenderMutex);
mos_bo_unreference(drawable_bo);
target.OsResource.bo = nullptr;
DdiMediaUtil_LockMutex(&mediaCtx->PutSurfaceSwapBufferMutex);
dri_vtable->swap_buffer(ctx, dri_drawable);
DdiMediaUtil_UnLockMutex(&mediaCtx->PutSurfaceSwapBufferMutex);
mediaCtx->pGmmClientContext->DestroyResInfoObject(target.OsResource.pGmmResInfo);
target.OsResource.pGmmResInfo = nullptr;
return VA_STATUS_SUCCESS;
}
#ifndef ANDROID
// move from media_libva_putsurface_linux.c
static unsigned long DdiMedia_mask2shift(unsigned long mask)
{
unsigned long shift = 0;
while((mask & 0x1) == 0)
{
mask = mask >> 1;
shift++;
}
return shift;
}
static void DdiMedia_yuv2pixel(uint32_t *pixel, int32_t y, int32_t u, int32_t v,
unsigned long rshift, unsigned long rmask,
unsigned long gshift, unsigned long gmask,
unsigned long bshift, unsigned long bmask)
{
DDI_CHK_NULL(pixel, "nullptr pixel", );
/* Warning, magic values ahead */
int32_t r = y + ((351 * (v-128)) >> 8);
int32_t g = y - (((179 * (v-128)) + (86 * (u-128))) >> 8);
int32_t b = y + ((444 * (u-128)) >> 8);
if (r > 255) r = 255;
if (g > 255) g = 255;
if (b > 255) b = 255;
if (r < 0) r = 0;
if (g < 0) g = 0;
if (b < 0) b = 0;
*pixel = (uint32_t)(((r << rshift) & rmask) | ((g << gshift) & gmask) |((b << bshift) & bmask));
}
#define YUV_444P_TO_ARGB() \
srcY = umdContextY + pitch * srcy;\
srcU = srcY + pitch * ((mediaSurface->iHeight));\
srcV = srcU + pitch * ((mediaSurface->iHeight));\
\
for(y = srcy; y < (srcy + height); y += 1) \
{\
for(x = srcx; x < (srcx + width); x += 1) \
{\
y1 = *(srcY + x); \
u1 = *(srcU + x);\
v1 = *(srcV + x);\
\
pixel = (uint32_t *)(ximg->data + (y * ximg->bytes_per_line) + (x * (ximg->bits_per_pixel >> 3)));\
DdiMedia_yuv2pixel(pixel, y1, u1, v1, rshift, rmask, gshift, gmask, bshift, bmask);\
\
}\
srcY += pitch;\
srcU += pitch;\
srcV += pitch;\
}
#define YUV_422H_TO_ARGB()\
srcY = umdContextY + pitch * srcy;\
srcU = srcY + pitch * mediaSurface->iHeight;\
srcV = srcU + pitch * mediaSurface->iHeight;\
\
for(y = srcy; y < (srcy + height); y += 1)\
{\
for(x = srcx; x < (srcx + width); x += 2)\
{\
y1 = *(srcY + x);\
y2 = *(srcY + x + 1);\
u1 = *(srcU + x / 2);\
v1 = *(srcV + x / 2);\
\
pixel = (uint32_t *)(ximg->data + (y * ximg->bytes_per_line) + (x * (ximg->bits_per_pixel >> 3)));\
DdiMedia_yuv2pixel(pixel, y1, u1, v1, rshift, rmask, gshift, gmask, bshift, bmask);\
pixel = (uint32_t *)(ximg->data + (y * ximg->bytes_per_line) + ((x + 1) * (ximg->bits_per_pixel >> 3)));\
DdiMedia_yuv2pixel(pixel, y2, u1, v1, rshift, rmask, gshift, gmask, bshift, bmask);\
}\
srcY += pitch;\
srcU += pitch;\
srcV += pitch;\
}
#define YUV_422V_TO_ARGB() \
srcY = umdContextY + pitch * srcy;\
srcU = srcY + pitch * mediaSurface->iHeight;\
srcV = srcU + pitch * mediaSurface->iHeight / 2;\
\
for(y = srcy; y < (srcy + width); y += 1)\
{\
for(x = srcx; x < (srcx + height); x += 2)\
{\
y1 = *(srcY + x * pitch);\
y2 = *(srcY + (x + 1) * pitch);\
u1 = *(srcU + (x / 2) * pitch);\
v1 = *(srcV + (x / 2) * pitch);\
\
pixel = (uint32_t *)(ximg->data + (x * ximg->bytes_per_line) + (y * (ximg->bits_per_pixel >> 3)));\
DdiMedia_yuv2pixel(pixel, y1, u1, v1, rshift, rmask, gshift, gmask, bshift, bmask);\
pixel = (uint32_t *)(ximg->data + (x* ximg->bytes_per_line) + ((y + 1) * (ximg->bits_per_pixel >> 3)));\
DdiMedia_yuv2pixel(pixel, y2, u1, v1, rshift, rmask, gshift, gmask, bshift, bmask);\
\
}\
\
srcY += 1;\
srcU += 1;\
srcV += 1;\
}
#define YUV_IMC3_TO_ARGB() \
srcY = umdContextY + pitch * srcy;\
srcU = srcY + pitch * mediaSurface->iHeight;\
srcV = srcU + pitch * mediaSurface->iHeight / 2;\
\
for(y = srcy; y < (srcy + height); y += 2) \
{\
for(x = srcx; x < (srcx + width); x += 2) \
{\
y1 = *(srcY + x);\
y2 = *(srcY + x + 1);\
y3 = *(srcY + x + pitch);\
y4 = *(srcY + x + pitch + 1);\
\
u1 = *(srcU + x / 2);\
v1 = *(srcV + x / 2);\
\
pixel = (uint32_t *)(ximg->data + (y * ximg->bytes_per_line) + (x * (ximg->bits_per_pixel >> 3)));\
DdiMedia_yuv2pixel(pixel, y1, u1, v1, rshift, rmask, gshift, gmask, bshift, bmask);\
pixel = (uint32_t *)(ximg->data + (y * ximg->bytes_per_line) + ((x + 1) * (ximg->bits_per_pixel >> 3)));\
DdiMedia_yuv2pixel(pixel, y2, u1, v1, rshift, rmask, gshift, gmask, bshift, bmask);\
pixel = (uint32_t *)(ximg->data + ((y + 1) * ximg->bytes_per_line) + (x * (ximg->bits_per_pixel >> 3)));\
DdiMedia_yuv2pixel(pixel, y3, u1, v1, rshift, rmask, gshift, gmask, bshift, bmask);\
pixel = (uint32_t *)(ximg->data + ((y + 1) * ximg->bytes_per_line) + ((x + 1) * (ximg->bits_per_pixel >> 3)));\
DdiMedia_yuv2pixel(pixel, y4, u1, v1, rshift, rmask, gshift, gmask, bshift, bmask); \
}\
srcY += pitch * 2;\
srcU += pitch;\
srcV += pitch;\
}
#define YUV_411P_TO_ARGB() \
srcY = umdContextY + pitch * srcy;\
srcU = srcY + pitch * mediaSurface->iHeight;\
srcV = srcU + pitch * mediaSurface->iHeight;\
\
for(y = srcy; y < (srcy + height); y += 1)\
{\
for(x = srcx; x < (srcx + width); x += 4)\
{\
y1 = *(srcY + x);\
y2 = *(srcY + x + 1);\
y3 = *(srcY + x + 2);\
y4 = *(srcY + x + 3);\
\
u1 = *(srcU + x / 4);\
v1 = *(srcV + x / 4);\
\
pixel = (uint32_t *)(ximg->data + (y * ximg->bytes_per_line) + (x * (ximg->bits_per_pixel >> 3)));\
DdiMedia_yuv2pixel(pixel, y1, u1, v1, rshift, rmask, gshift, gmask, bshift, bmask);\
pixel = (uint32_t *)(ximg->data + (y * ximg->bytes_per_line) + ((x + 1) * (ximg->bits_per_pixel >> 3)));\
DdiMedia_yuv2pixel(pixel, y2, u1, v1, rshift, rmask, gshift, gmask, bshift, bmask);\
pixel = (uint32_t *)(ximg->data + ((y ) * ximg->bytes_per_line) + ((x+2) * (ximg->bits_per_pixel >> 3)));\
DdiMedia_yuv2pixel(pixel, y3, u1, v1, rshift, rmask, gshift, gmask, bshift, bmask);\
pixel = (uint32_t *)(ximg->data + ((y) * ximg->bytes_per_line) + ((x + 3) * (ximg->bits_per_pixel >> 3)));\
DdiMedia_yuv2pixel(pixel, y4, u1, v1, rshift, rmask, gshift, gmask, bshift, bmask);\
}\
srcY += pitch;\
srcU += pitch;\
srcV += pitch;\
}
#define YUV_400P_TO_ARGB()\
srcY = umdContextY + pitch * srcy;\
srcU = srcY;\
srcV = srcY;\
\
for(y = srcy; y < (srcy + height); y += 2)\
{\
for(x = srcx; x < (srcx + width); x += 2)\
{\
y1 = *(srcY + x);\
y2 = *(srcY + x + 1);\
y3 = *(srcY + x + pitch);\
y4 = *(srcY + x + pitch + 1);\
\
u1 = 128;\
v1 = 128;\
pixel = (uint32_t *)(ximg->data + (y * ximg->bytes_per_line) + (x * (ximg->bits_per_pixel >> 3)));\
DdiMedia_yuv2pixel(pixel, y1, u1, v1, rshift, rmask, gshift, gmask, bshift, bmask);\
pixel = (uint32_t *)(ximg->data + (y * ximg->bytes_per_line) + ((x + 1) * (ximg->bits_per_pixel >> 3)));\
DdiMedia_yuv2pixel(pixel, y2, u1, v1, rshift, rmask, gshift, gmask, bshift, bmask);\
pixel = (uint32_t *)(ximg->data + ((y + 1) * ximg->bytes_per_line) + (x * (ximg->bits_per_pixel >> 3)));\
DdiMedia_yuv2pixel(pixel, y3, u1, v1, rshift, rmask, gshift, gmask, bshift, bmask);\
pixel = (uint32_t *)(ximg->data + ((y + 1) * ximg->bytes_per_line) + ((x + 1) * (ximg->bits_per_pixel >> 3)));\
DdiMedia_yuv2pixel(pixel, y4, u1, v1, rshift, rmask, gshift, gmask, bshift, bmask);\
}\
srcY += pitch * 2;\
srcU += pitch;\
srcV += pitch;\
}
#define YUV_NV12_TO_ARGB()\
srcY = umdContextY + pitch * srcy;\
srcU = srcY + pitch * mediaSurface->iHeight;\
srcV = srcU + 1;\
\
for(y = srcy; y < (srcy + height); y += 2)\
{\
for(x = srcx; x < (srcx + width); x += 2)\
{\
y1 = *(srcY + x);\
y2 = *(srcY + x + 1);\
y3 = *(srcY + x + pitch);\
y4 = *(srcY + x + pitch + 1);\
\
u1 = *(srcU + x);\
v1 = *(srcU + x +1);\
pixel = (uint32_t *)(ximg->data + (y * ximg->bytes_per_line) + (x * (ximg->bits_per_pixel >> 3)));\
DdiMedia_yuv2pixel(pixel, y1, u1, v1, rshift, rmask, gshift, gmask, bshift, bmask);\
pixel = (uint32_t *)(ximg->data + (y * ximg->bytes_per_line) + ((x + 1) * (ximg->bits_per_pixel >> 3)));\
DdiMedia_yuv2pixel(pixel, y2, u1, v1, rshift, rmask, gshift, gmask, bshift, bmask);\
pixel = (uint32_t *)(ximg->data + ((y + 1) * ximg->bytes_per_line) + (x * (ximg->bits_per_pixel >> 3)));\
DdiMedia_yuv2pixel(pixel, y3, u1, v1, rshift, rmask, gshift, gmask, bshift, bmask);\
pixel = (uint32_t *)(ximg->data + ((y + 1) * ximg->bytes_per_line) + ((x + 1) * (ximg->bits_per_pixel >> 3)));\
DdiMedia_yuv2pixel(pixel, y4, u1, v1, rshift, rmask, gshift, gmask, bshift, bmask);\
}\
srcY += pitch * 2;\
srcU += pitch;\
}
VAStatus DdiMedia_PutSurfaceLinuxSW(
VADriverContextP ctx,
VASurfaceID surface,
void* draw, /* Drawable of window system */
int16_t srcx,
int16_t srcy,
uint16_t srcw,
uint16_t srch,
int16_t destx,
int16_t desty,
uint16_t destw,
uint16_t desth,
VARectangle *cliprects, /* client supplied clip list */
uint32_t number_cliprects, /* number of clip rects in the clip list */
uint32_t flags /* de-interlacing flags */
)
{
PDDI_MEDIA_CONTEXT mediaCtx = DdiMedia_GetMediaContext(ctx);
DDI_CHK_NULL(mediaCtx, "nullptr mediaCtx.", VA_STATUS_ERROR_INVALID_CONTEXT);
DDI_CHK_NULL(mediaCtx->X11FuncTable, "nullptr X11FuncTable", VA_STATUS_ERROR_INVALID_CONTEXT);
DDI_CHK_NULL(mediaCtx->X11FuncTable->pfnXCreateGC, "nullptr pfnXCreateGC", VA_STATUS_ERROR_INVALID_CONTEXT);
DDI_CHK_NULL(mediaCtx->X11FuncTable->pfnXFreeGC, "nullptr pfnXFreeGC", VA_STATUS_ERROR_INVALID_CONTEXT);
DDI_CHK_NULL(mediaCtx->X11FuncTable->pfnXCreateImage, "nullptr pfnXCreateImage", VA_STATUS_ERROR_INVALID_CONTEXT);
DDI_CHK_NULL(mediaCtx->X11FuncTable->pfnXDestroyImage, "nullptr pfnXDestroyImage", VA_STATUS_ERROR_INVALID_CONTEXT);
DDI_CHK_NULL(mediaCtx->X11FuncTable->pfnXPutImage, "nullptr pfnXPutImage", VA_STATUS_ERROR_INVALID_CONTEXT);
TypeXCreateGC pfn_XCreateGC = (TypeXCreateGC)(mediaCtx->X11FuncTable->pfnXCreateGC);
TypeXFreeGC pfn_XFreeGC = (TypeXFreeGC)(mediaCtx->X11FuncTable->pfnXFreeGC);
TypeXCreateImage pfn_XCreateImage = (TypeXCreateImage)(mediaCtx->X11FuncTable->pfnXCreateImage);
TypeXDestroyImage pfn_XDestroyImage = (TypeXDestroyImage)(mediaCtx->X11FuncTable->pfnXDestroyImage);
TypeXPutImage pfn_XPutImage = (TypeXPutImage)(mediaCtx->X11FuncTable->pfnXPutImage);
DDI_MEDIA_SURFACE *mediaSurface = DdiMedia_GetSurfaceFromVASurfaceID(mediaCtx, surface);
DDI_CHK_NULL(mediaSurface, "nullptr mediaSurface.", VA_STATUS_ERROR_INVALID_SURFACE);
uint16_t width = 0;
if (srcw <= destw)
width = srcw;
else
width = destw;
uint16_t height = 0;
if (srch <= desth)
height = srch;
else
height = desth;
int32_t pitch = mediaSurface->iPitch;
uint32_t adjustU = 1;
uint32_t adjustD = 1;
switch(mediaSurface->format)
{
case Media_Format_422H:
case Media_Format_444P:
case Media_Format_411P:
adjustU = 3;
adjustD = 1;
break;
case Media_Format_400P:
adjustU = 1;
adjustD = 1;
break;
case Media_Format_422V:
case Media_Format_IMC3:
adjustU = 2;
adjustD = 1;
break;
case Media_Format_NV12:
adjustU = 3;
adjustD = 2;
break;
default:
DDI_ASSERTMESSAGE("Color Format is not supported: %d",mediaSurface->format);
return VA_STATUS_ERROR_INVALID_VALUE;
}
uint32_t surfaceSize = pitch * mediaSurface->iHeight * adjustU / adjustD;
uint8_t *dispTempBuffer = (uint8_t *)malloc(surfaceSize);
if (dispTempBuffer == nullptr)
{
DdiMediaUtil_UnlockSurface(mediaSurface);
return VA_STATUS_ERROR_ALLOCATION_FAILED;
}
uint8_t *umdContextY = dispTempBuffer;
uint8_t *ptr = (uint8_t*)DdiMediaUtil_LockSurface(mediaSurface, (MOS_LOCKFLAG_READONLY | MOS_LOCKFLAG_WRITEONLY));
MOS_STATUS eStatus = MOS_SecureMemcpy(umdContextY, surfaceSize, ptr, surfaceSize);
if (eStatus != MOS_STATUS_SUCCESS)
{
MOS_FreeMemory(dispTempBuffer);
DDI_ASSERTMESSAGE("DDI:Failed to copy surface buffer data!");
return VA_STATUS_ERROR_OPERATION_FAILED;
}
Visual *visual = DefaultVisual(ctx->native_dpy, ctx->x11_screen);
GC gc = (*pfn_XCreateGC)((Display*)ctx->native_dpy, (Drawable)draw, 0, nullptr);
if (TrueColor != visual->c_class)
{
(*pfn_XFreeGC)((Display*)ctx->native_dpy, gc);
MOS_FreeMemory(dispTempBuffer);
return VA_STATUS_ERROR_UNKNOWN;
}
unsigned long rmask = visual->red_mask;
unsigned long gmask = visual->green_mask;
unsigned long bmask = visual->blue_mask;
unsigned long rshift = DdiMedia_mask2shift(rmask);
unsigned long gshift = DdiMedia_mask2shift(gmask);
unsigned long bshift = DdiMedia_mask2shift(bmask);
int32_t depth = DefaultDepth(ctx->native_dpy, ctx->x11_screen);
XImage *ximg = (*pfn_XCreateImage)((Display*)ctx->native_dpy, visual, depth, ZPixmap, 0, nullptr,width, height, 32, 0 );
if (ximg == nullptr)
{
MOS_FreeMemory(dispTempBuffer);
return VA_STATUS_ERROR_ALLOCATION_FAILED;
}
if (ximg->bits_per_pixel != 32)
{
(*pfn_XDestroyImage)(ximg);
(*pfn_XFreeGC)((Display*)ctx->native_dpy, gc);
MOS_FreeMemory(dispTempBuffer);
return VA_STATUS_ERROR_UNKNOWN;
}
ximg->data = (char *) malloc(ximg->bytes_per_line * MOS_ALIGN_CEIL(height, 2)); // If height is odd, need to add it by one for we process two lines per iteration
if (nullptr == ximg->data)
{
(*pfn_XDestroyImage)(ximg);
(*pfn_XFreeGC)((Display*)ctx->native_dpy, gc);
MOS_FreeMemory(dispTempBuffer);
return VA_STATUS_ERROR_ALLOCATION_FAILED;
}
int32_t x = 0;
int32_t y = 0;
uint8_t *srcY = nullptr;
uint8_t *srcU = nullptr;
uint8_t *srcV = nullptr;
uint32_t *pixel = nullptr;
int32_t y1 = 0, y2 = 0, y3 = 0, y4 = 0, u1 = 0, v1 = 0;
switch(mediaSurface->format)
{
case Media_Format_444P:
YUV_444P_TO_ARGB();
break;
case Media_Format_422H:
YUV_422H_TO_ARGB();
break;
case Media_Format_422V:
YUV_422V_TO_ARGB();
break;
case Media_Format_IMC3:
YUV_IMC3_TO_ARGB();
break;
case Media_Format_411P:
YUV_411P_TO_ARGB();
break;
case Media_Format_400P:
YUV_400P_TO_ARGB();
break;
case Media_Format_NV12:
YUV_NV12_TO_ARGB();
break;
default:
DDI_ASSERTMESSAGE("Color Format is not supported: %d", mediaSurface->format);
}
DdiMediaUtil_UnlockSurface(mediaSurface);
(*pfn_XPutImage)((Display*)ctx->native_dpy,(Drawable)draw, gc, ximg, 0, 0, destx, desty, destw, desth);
if (ximg != nullptr)
{
(*pfn_XDestroyImage)(ximg);
}
(*pfn_XFreeGC)((Display*)ctx->native_dpy, gc);
MOS_FreeMemory(dispTempBuffer);
return VA_STATUS_SUCCESS;
}
VAStatus DdiMedia_PutSurfaceDummy(
VADriverContextP ctx,
VASurfaceID surface,
void *draw, /* Drawable of window system */
int16_t srcx,
int16_t srcy,
uint16_t srcw,
uint16_t srch,
int16_t destx,
int16_t desty,
uint16_t destw,
uint16_t desth,
VARectangle *cliprects, /* client supplied clip list */
uint32_t number_cliprects, /* number of clip rects in the clip list */
uint32_t flags /* de-interlacing flags */
)
{
return VA_STATUS_ERROR_UNIMPLEMENTED;
}
#endif