Home | History | Annotate | Download | only in va
      1 /*
      2  * Copyright (c) 2009 Intel Corporation. All Rights Reserved.
      3  *
      4  * Permission is hereby granted, free of charge, to any person obtaining a
      5  * copy of this software and associated documentation files (the
      6  * "Software"), to deal in the Software without restriction, including
      7  * without limitation the rights to use, copy, modify, merge, publish,
      8  * distribute, sub license, and/or sell copies of the Software, and to
      9  * permit persons to whom the Software is furnished to do so, subject to
     10  * the following conditions:
     11  *
     12  * The above copyright notice and this permission notice (including the
     13  * next paragraph) shall be included in all copies or substantial portions
     14  * of the Software.
     15  *
     16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     17  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
     19  * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
     20  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
     21  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
     22  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     23  */
     24 
     25 #define _GNU_SOURCE 1
     26 #include "va.h"
     27 #include "va_backend.h"
     28 #include "va_trace.h"
     29 #include "va_fool.h"
     30 
     31 #include <assert.h>
     32 #include <stdarg.h>
     33 #include <stdlib.h>
     34 #include <stdio.h>
     35 #include <errno.h>
     36 #include <string.h>
     37 #include <dlfcn.h>
     38 #include <unistd.h>
     39 #include <sys/types.h>
     40 #include <sys/stat.h>
     41 #include <unistd.h>
     42 #include <time.h>
     43 #include <fcntl.h>
     44 
     45 /*
     46  * Do dummy decode/encode, ignore the input data
     47  * In order to debug memory leak or low performance issues, we need to isolate driver problems
     48  * We export env "VA_FOOL", with which, we can do fake decode/encode:
     49  *
     50  * LIBVA_FOOL_DECODE:
     51  * . if set, decode does nothing
     52  * LIBVA_FOOL_ENCODE=<framename>:
     53  * . if set, encode does nothing, but fill in the coded buffer from the content of files with
     54  *   name framename.0,framename.1,..., framename.N, framename.0,..., framename.N,...repeatly
     55  *   Use file name to determine h264 or vp8
     56  * LIBVA_FOOL_JPEG=<framename>:fill the content of filename to codedbuf for jpeg encoding
     57  * LIBVA_FOOL_POSTP:
     58  * . if set, do nothing for vaPutSurface
     59  */
     60 
     61 
     62 /* global settings */
     63 int fool_codec = 0;
     64 int fool_postp  = 0;
     65 
     66 #define FOOL_BUFID_MAGIC   0x12345600
     67 #define FOOL_BUFID_MASK    0xffffff00
     68 
     69 struct fool_context {
     70     int enabled; /* fool_codec is global, and it is for concurent encode/decode */
     71     char *fn_enc;/* file pattern with codedbuf content for encode */
     72     char *segbuf_enc; /* the segment buffer of coded buffer, load frome fn_enc */
     73     int file_count;
     74 
     75     char *fn_jpg;/* file name of JPEG fool with codedbuf content */
     76     char *segbuf_jpg; /* the segment buffer of coded buffer, load frome fn_jpg */
     77 
     78     VAEntrypoint entrypoint; /* current entrypoint */
     79 
     80     /* all buffers with same type share one malloc-ed memory
     81      * bufferID = (buffer numbers with the same type << 8) || type
     82      * the malloc-ed memory can be find by fool_buf[bufferID & 0xff]
     83      * the size is ignored here
     84      */
     85     char *fool_buf[VABufferTypeMax]; /* memory of fool buffers */
     86     unsigned int fool_buf_size[VABufferTypeMax]; /* size of memory of fool buffers */
     87     unsigned int fool_buf_element[VABufferTypeMax]; /* element count of created buffers */
     88     unsigned int fool_buf_count[VABufferTypeMax]; /* count of created buffers */
     89     VAContextID context;
     90 };
     91 
     92 #define FOOL_CTX(dpy) ((struct fool_context *)((VADisplayContextP)dpy)->vafool)
     93 
     94 #define DPY2FOOLCTX(dpy)                                 \
     95     struct fool_context *fool_ctx = FOOL_CTX(dpy);       \
     96     if (fool_ctx == NULL)                                \
     97         return 0; /* no fool for the context */          \
     98 
     99 #define DPY2FOOLCTX_CHK(dpy)                             \
    100     struct fool_context *fool_ctx = FOOL_CTX(dpy);       \
    101     if ((fool_ctx == NULL) || (fool_ctx->enabled == 0))  \
    102         return 0; /* no fool for the context */          \
    103 
    104 /* Prototype declarations (functions defined in va.c) */
    105 
    106 void va_errorMessage(const char *msg, ...);
    107 void va_infoMessage(const char *msg, ...);
    108 
    109 int  va_parseConfig(char *env, char *env_value);
    110 
    111 void va_FoolInit(VADisplay dpy)
    112 {
    113     char env_value[1024];
    114 
    115     struct fool_context *fool_ctx = calloc(sizeof(struct fool_context), 1);
    116 
    117     if (fool_ctx == NULL)
    118         return;
    119 
    120     if (va_parseConfig("LIBVA_FOOL_POSTP", NULL) == 0) {
    121         fool_postp = 1;
    122         va_infoMessage("LIBVA_FOOL_POSTP is on, dummy vaPutSurface\n");
    123     }
    124 
    125     if (va_parseConfig("LIBVA_FOOL_DECODE", NULL) == 0) {
    126         fool_codec  |= VA_FOOL_FLAG_DECODE;
    127         va_infoMessage("LIBVA_FOOL_DECODE is on, dummy decode\n");
    128     }
    129     if (va_parseConfig("LIBVA_FOOL_ENCODE", &env_value[0]) == 0) {
    130         fool_codec  |= VA_FOOL_FLAG_ENCODE;
    131         fool_ctx->fn_enc = strdup(env_value);
    132         va_infoMessage("LIBVA_FOOL_ENCODE is on, load encode data from file with patten %s\n",
    133                        fool_ctx->fn_enc);
    134     }
    135     if (va_parseConfig("LIBVA_FOOL_JPEG", &env_value[0]) == 0) {
    136         fool_codec  |= VA_FOOL_FLAG_JPEG;
    137         fool_ctx->fn_jpg = strdup(env_value);
    138         va_infoMessage("LIBVA_FOOL_JPEG is on, load encode data from file with patten %s\n",
    139                        fool_ctx->fn_jpg);
    140     }
    141 
    142     ((VADisplayContextP)dpy)->vafool = fool_ctx;
    143 }
    144 
    145 
    146 int va_FoolEnd(VADisplay dpy)
    147 {
    148     int i;
    149     DPY2FOOLCTX(dpy);
    150 
    151     for (i = 0; i < VABufferTypeMax; i++) {/* free memory */
    152         if (fool_ctx->fool_buf[i])
    153             free(fool_ctx->fool_buf[i]);
    154     }
    155     if (fool_ctx->segbuf_enc)
    156         free(fool_ctx->segbuf_enc);
    157     if (fool_ctx->segbuf_jpg)
    158         free(fool_ctx->segbuf_jpg);
    159     if (fool_ctx->fn_enc)
    160         free(fool_ctx->fn_enc);
    161     if (fool_ctx->fn_jpg)
    162         free(fool_ctx->fn_jpg);
    163 
    164     free(fool_ctx);
    165     ((VADisplayContextP)dpy)->vafool = NULL;
    166 
    167     return 0;
    168 }
    169 
    170 int va_FoolCreateConfig(
    171         VADisplay dpy,
    172         VAProfile profile,
    173         VAEntrypoint entrypoint,
    174         VAConfigAttrib __maybe_unused *attrib_list,
    175         int __maybe_unused num_attribs,
    176         VAConfigID __maybe_unused *config_id /* out */
    177 )
    178 {
    179     DPY2FOOLCTX(dpy);
    180 
    181     fool_ctx->entrypoint = entrypoint;
    182 
    183     /*
    184      * check fool_codec to align with current context
    185      * e.g. fool_codec = decode then for encode, the
    186      * vaBegin/vaRender/vaEnd also run into fool path
    187      * which is not desired
    188      */
    189     if (((fool_codec & VA_FOOL_FLAG_DECODE) && (entrypoint == VAEntrypointVLD)) ||
    190         ((fool_codec & VA_FOOL_FLAG_JPEG) && (entrypoint == VAEntrypointEncPicture)))
    191         fool_ctx->enabled = 1;
    192     else if ((fool_codec & VA_FOOL_FLAG_ENCODE) && (entrypoint == VAEntrypointEncSlice)) {
    193         /* H264 is desired */
    194         if (((profile == VAProfileH264Baseline ||
    195               profile == VAProfileH264Main ||
    196               profile == VAProfileH264High ||
    197               profile == VAProfileH264ConstrainedBaseline)) &&
    198             strstr(fool_ctx->fn_enc, "h264"))
    199             fool_ctx->enabled = 1;
    200 
    201         /* vp8 is desired */
    202         if ((profile == VAProfileVP8Version0_3) &&
    203             strstr(fool_ctx->fn_enc, "vp8"))
    204             fool_ctx->enabled = 1;
    205     }
    206     if (fool_ctx->enabled)
    207         va_infoMessage("FOOL is enabled for this context\n");
    208     else
    209         va_infoMessage("FOOL is not enabled for this context\n");
    210 
    211     return 0; /* continue */
    212 }
    213 
    214 
    215 VAStatus va_FoolCreateBuffer(
    216     VADisplay dpy,
    217     VAContextID __maybe_unused context,	/* in */
    218     VABufferType type,		/* in */
    219     unsigned int size,		/* in */
    220     unsigned int num_elements,	/* in */
    221     void __maybe_unused *data,			/* in */
    222     VABufferID *buf_id		/* out */
    223 )
    224 {
    225     unsigned int new_size = size * num_elements;
    226     unsigned int old_size;
    227     DPY2FOOLCTX_CHK(dpy);
    228 
    229     old_size = fool_ctx->fool_buf_size[type] * fool_ctx->fool_buf_element[type];
    230 
    231     if (old_size < new_size)
    232         fool_ctx->fool_buf[type] = realloc(fool_ctx->fool_buf[type], new_size);
    233 
    234     fool_ctx->fool_buf_size[type] = size;
    235     fool_ctx->fool_buf_element[type] = num_elements;
    236     fool_ctx->fool_buf_count[type]++;
    237     /* because we ignore the vaRenderPicture,
    238      * all buffers with same type share same real memory
    239      * bufferID = (magic number) | type
    240      */
    241     *buf_id = FOOL_BUFID_MAGIC | type;
    242 
    243     return 1; /* don't call into driver */
    244 }
    245 
    246 VAStatus va_FoolBufferInfo(
    247     VADisplay dpy,
    248     VABufferID buf_id,  /* in */
    249     VABufferType *type, /* out */
    250     unsigned int *size,         /* out */
    251     unsigned int *num_elements /* out */
    252 )
    253 {
    254     unsigned int magic;
    255 
    256     DPY2FOOLCTX_CHK(dpy);
    257 
    258     magic = buf_id & FOOL_BUFID_MASK;
    259     if (magic != FOOL_BUFID_MAGIC)
    260         return 0; /* could be VAImageBufferType from vaDeriveImage */
    261 
    262     *type = buf_id & 0xff;
    263     *size = fool_ctx->fool_buf_size[*type];
    264     *num_elements = fool_ctx->fool_buf_element[*type];;
    265 
    266     return 1; /* fool is valid */
    267 }
    268 
    269 static int va_FoolFillCodedBufEnc(struct fool_context *fool_ctx)
    270 {
    271     char file_name[1024];
    272     struct stat file_stat = {0};
    273     VACodedBufferSegment *codedbuf;
    274     int i, fd = -1;
    275 
    276     /* try file_name.file_count, if fail, try file_name.file_count-- */
    277     for (i=0; i<=1; i++) {
    278         snprintf(file_name, 1024, "%s.%d",
    279                  fool_ctx->fn_enc,
    280                  fool_ctx->file_count);
    281 
    282         if ((fd = open(file_name, O_RDONLY)) != -1) {
    283             fstat(fd, &file_stat);
    284             fool_ctx->file_count++; /* open next file */
    285             break;
    286         } else /* fall back to the first file file */
    287             fool_ctx->file_count = 0;
    288     }
    289     if (fd != -1) {
    290         fool_ctx->segbuf_enc = realloc(fool_ctx->segbuf_enc, file_stat.st_size);
    291         read(fd, fool_ctx->segbuf_enc, file_stat.st_size);
    292         close(fd);
    293     } else
    294         va_errorMessage("Open file %s failed:%s\n", file_name, strerror(errno));
    295 
    296     codedbuf = (VACodedBufferSegment *)fool_ctx->fool_buf[VAEncCodedBufferType];
    297     codedbuf->size = file_stat.st_size;
    298     codedbuf->bit_offset = 0;
    299     codedbuf->status = 0;
    300     codedbuf->reserved = 0;
    301     codedbuf->buf = fool_ctx->segbuf_enc;
    302     codedbuf->next = NULL;
    303 
    304     return 0;
    305 }
    306 
    307 static int va_FoolFillCodedBufJPG(struct fool_context *fool_ctx)
    308 {
    309     struct stat file_stat = {0};
    310     VACodedBufferSegment *codedbuf;
    311     int fd = -1;
    312 
    313     if ((fd = open(fool_ctx->fn_jpg, O_RDONLY)) != -1) {
    314         fstat(fd, &file_stat);
    315         fool_ctx->segbuf_jpg = realloc(fool_ctx->segbuf_jpg, file_stat.st_size);
    316         read(fd, fool_ctx->segbuf_jpg, file_stat.st_size);
    317         close(fd);
    318     } else
    319         va_errorMessage("Open file %s failed:%s\n", fool_ctx->fn_jpg, strerror(errno));
    320 
    321     codedbuf = (VACodedBufferSegment *)fool_ctx->fool_buf[VAEncCodedBufferType];
    322     codedbuf->size = file_stat.st_size;
    323     codedbuf->bit_offset = 0;
    324     codedbuf->status = 0;
    325     codedbuf->reserved = 0;
    326     codedbuf->buf = fool_ctx->segbuf_jpg;
    327     codedbuf->next = NULL;
    328 
    329     return 0;
    330 }
    331 
    332 
    333 static int va_FoolFillCodedBuf(struct fool_context *fool_ctx)
    334 {
    335     if (fool_ctx->entrypoint == VAEntrypointEncSlice)
    336         va_FoolFillCodedBufEnc(fool_ctx);
    337     else if (fool_ctx->entrypoint == VAEntrypointEncPicture)
    338         va_FoolFillCodedBufJPG(fool_ctx);
    339 
    340     return 0;
    341 }
    342 
    343 
    344 VAStatus va_FoolMapBuffer(
    345     VADisplay dpy,
    346     VABufferID buf_id,	/* in */
    347     void **pbuf 	/* out */
    348 )
    349 {
    350     unsigned int magic, buftype;
    351     DPY2FOOLCTX_CHK(dpy);
    352 
    353     magic = buf_id & FOOL_BUFID_MASK;
    354     if (magic != FOOL_BUFID_MAGIC)
    355         return 0; /* could be VAImageBufferType from vaDeriveImage */
    356 
    357     buftype = buf_id & 0xff;
    358     *pbuf = fool_ctx->fool_buf[buftype];
    359 
    360     /* it is coded buffer, fill coded segment from file */
    361     if (*pbuf && (buftype == VAEncCodedBufferType))
    362         va_FoolFillCodedBuf(fool_ctx);
    363 
    364     return 1; /* fool is valid */
    365 }
    366 
    367 VAStatus va_FoolCheckContinuity(VADisplay dpy)
    368 {
    369     DPY2FOOLCTX_CHK(dpy);
    370 
    371     return 1; /* fool is valid */
    372 }
    373 
    374