This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

OMAP 3530 vertical sync problem

Other Parts Discussed in Thread: OMAP3530

Hi All!

I'm working with video and graphics for OMAP 3530.
Video screen (O3530_VID) is working well, but I've got a problem with the OSD screen (O3530_OSD).
OSD screen is flickering, it looks like a problem with the vertical sync. Anyone got this problem?

I tried to use ioctl and FBIO_WAITFORVSYNC but the compiler complains about the FBIO_WAITFORVSYNC not being defined.

Please advice.

Thanks

RamOn

  • Though FBIO_WAITFORVSYNC is not given in the documentation, the PSP migration guide mentions that the OMAPFB_WAIT_FOR_VSYNC ioctl should be supported, so it may be worth trying that instead.

  • One thing to be careful about is that I think this interrupt occurs at the START of active video and not the end, so if you use this interrupt to start rendering to the currently displayed buffer you will likely get tearing.

    There is a subtle but important difference between the display controller and the processing pipes. The waitforvsync interrupt is display controller related, i.e. final output image. (See http://wiki.omap.com/index.php/Display_Subsystem which might help understand the importance of the difference)

    Your options are to either use this interrupt to indicate that it is OK to display the previously rendered buffer, or use a different interrupt.

    We did some quick test code a while back for another customer and changed the interrupt source for waitforvsync to be the end of the graphics buffer read. Below is the code we changed.

    As a quick test we modified "drivers/video/omap24xxfb.c" from

    ---------------------------------------------------------------
            if(omap2_disp_get_output_dev(OMAP2_GRAPHICS) == OMAP2_OUTPUT_TV)
                    mask = DISPC_IRQSTATUS_EVSYNC_ODD |
                            DISPC_IRQSTATUS_EVSYNC_EVEN;
            else
                    mask = DISPC_IRQSTATUS_VSYNC;
    ---------------------------------------------------------------

    to
     
    ---------------------------------------------------------------
            mask = DISPC_IRQSTATUS_GFXENDWINDOW;  // Using this interrupt now
    ---------------------------------------------------------------
    With the above code, if you wait for the interrupt then do your buffer rendering during the blanking period you should not get tearing or flickering. This does require your rendering to complete entirely during the blanking period though. If your rendering takes longer than the blanking period then you must use multiple buffers.

    The original mask waits for the start of the display controller output to start whereas the new mask waits for the end of the specific processing pipe access. Note, "GFX" can be replaced with "VID1" or "VID2" I believe depending on which processing pipe you are interested in.

    Be aware that this is a quick test and may have additional side effects. The correct way is to add additional IOCTLs for these new sync interrupts.

    Kind regards,

    Steve

  • Thank you for pointing out about OMAPFB_WAIT_FOR_VSYNC.

    Unfortunately I got the same problem :(

    Anyway, thanks for it.

    RamOn

  • Steve, thank you very much for your help. Now I understand better how it works.

    I forgot to mention something in my first post. I'm using Dmai. When I saw the flickering effect I tried to use the ioctl call with fbio_waitforsync without luck.

    Looking at the Dmai code, I see that it is already using waitforvsync and that it works the same as you explain, it waits for vsync on Display_get() when I expected it to do it on Display_put().

    Currently I'm doing something like this:

    ...

    Display_create with 2 buffers. (dAttrs.numBufs=2)

    Display_get();

    I do my render here, I'm painting on the hDispBuf returned by Display_get.

    Display_put();

    The flickering appears.

    ...

     

    After reading your post and looking at the Dmai source, I tried the follow:

    ...

    Display_create with 1 buffers. (dAttrs.numBufs=1)

    Create a new buftab with a new buffer with the same properties as the display buffer.

    I do my render here, I'm painting on the new buffer (not the display one)

    Display_get();

    Copy the new buffer contents to the display buffer. (I'm just trying to be "fast" enough)

    Display_put();

    This time the program crash due to a CMEM error: CMEM Error: getPool: Failed to get a pool fitting a size 225888 When trying to play a sound.

    It looks like the system doesn't likes me reserving memory for my buffer.

    ...

    Is there any way to force Dmai to use GFXENDWINDOW? I really prefer to avoid writing code in the driver source.

    Again , thank you very much for your help.

    Regards.

    RamOn

     

     

     


  • Ramon,

    Unfortunately I am going to have to defer to people who know more about the software side of things for questions on what is exposed in Linux.

    Regarding the buffers though, there are some things you can do to avoid expensive memory copies if your buffers are already declared.

    Each of the processing pipes has a base address register which tells it where to read its data from. It is much quicker to change this register to simply point to the newly rendered buffer for display than to copy it. Note, like all other display related registers this is only updated in the hardware at a frame start so as to eliminate tearing when changing it. I am not sure how the drivers interact with these pointers when you are using features such as FBDEV, V4L2 etc... but if you are doing all your rendering yourself to the frame buffer then handling the buffer management in your application might be an option?

    Next, regarding the actual frame buffer allocation, I believe that the amount of contiguous memory allocated for frame buffers is specified at boot time in the boot args. This is usually significantly higher than is necessary for a single/double buffer, so you could potentially manage this memory yourself and allocate to your front and back buffers yourself purely based on the size and color depth.

    I have some example code which handles all the configuration of multiple single frame buffers, their position, size and scaling which may be useful as a starting point for you if you want to consider handling things entirely by yourself. The code was really written to try and help people working on drivers, and does not cover all use cases but it might be useful?

    As I say, I don't really know too much about what is exposed under Linux so perhaps better folks with more knowledge can give you cleaner solutions?

    Kind regards,

    Steve

  • Ramon Rabaso said:
    Copy the new buffer contents to the display buffer. (I'm just trying to be "fast" enough)

    Just a small comment on this, copying the data may work and is fine for testing but is somewhat inefficient, if possible you want to just swap around the pointers to the image data. As Steve suggests there may be additional ways of optimizing this even further using the video hardware.

    Ramon Rabaso said:

    This time the program crash due to a CMEM error: CMEM Error: getPool: Failed to get a pool fitting a size 225888 When trying to play a sound.

    It looks like the system doesn't likes me reserving memory for my buffer.

    This is something you can fix fairly easily, to understand deeper how to fix it and why you may want to look at the CMEM Overview wiki article. As to actually fixing this you simply need to give more memory to CMEM so that it has a pool available for you to allocate at run time, a two step process. 

    The first step is to configure CMEM to take more memory. In a typical DVSDK context the CMEM configuration and insertion is done when you run ./loadmodules.sh, so you will want to edit loadmodules.sh to add an extra buffer that is large enough (>225888), details on the syntax are given in the wiki article mentioned above. 

    The second step is to make sure that the memory you are now taking exists and is not being used by something else, namely the Linux kernel. You define how much memory the Linux kernel uses in the bootargs value from U-Boot, in particular the mem= option in the bootargs.

    For an example lets take the existing insmod cmem.ko command from the DVSDK loadmodules.sh.

    DVSDK 3.00.00.12 OMAP3530 loadmodules.sh said:

    #
    # Default Memory Map
    #
    # Start Addr    Size    Description
    # -------------------------------------------
    # 0x80000000    88 MB   Linux
    # 0x85800000    08 MB   CMEM (Bernie EDIT: this should say 16MB, it is a bug in the comment)
    # 0x86800000    24 MB   DDRALGHEAP
    # 0x87800000     6 MB   DDR2 (BIOS, Codecs, Applications)
    # 0x87E00000     1 MB   DSPLINK (MEM)
    # 0x87F00000     4 KB   DSPLINK (RESET)
    # 0x87F01000  1020 KB   unused

    insmod cmemk.ko phys_start=0x85800000 phys_end=0x86800000 pools=20x4096,8x131072,5x1048576,1x1429440,1x256000,1x3600000,5x829440

    In your case you only need another 226k but to make this easier we can just grab another MB from the Linux kernel (in this case I am assuming DDRALGHEAP  and beyond need to be unchanged to run your codecs).

    To add another buffer we simply need to edit the insmod cmemk.ko line, in particular the pools segment. Since the error said we needed a pool of at least size 225888 we can add ",1x226000" to the end of the insmod cmemk.ko line, this will tell CMEM we want to reserve one more pool of 226k bytes.

    Having added in this new pool there is a problem, if you were to sum up all the pools CMEM is being tasked with creating they no longer fit in the 16MB that CMEM had been allocated (we look to be over by about 32k), so we need to get more memory and the easiest place to take it here is from Linux. To do so we need to adjust the phys_start value we are inserting with to step it back by 1 MB, so phys_start=0x85700000, and we will need to change the bootargs in U-Boot to tell the kernel to only use 87 MB of memory, so mem=87M.

    At this point you should be all set, and by making these minor adjustments you should be able to allocate that extra buffer without CMEM throwing up that error. Below is the completed loadmodules.sh modification (comments also changed for clarity, but not necessary).

    DVSDK 3.00.00.12 OMAP3530 loadmodules.sh MODIFIED said:

    #
    # Default Memory Map
    #
    # Start Addr    Size    Description
    # -------------------------------------------
    # 0x80000000    87 MB   Linux
    # 0x85700000    17 MB   CMEM
    # 0x86800000    24 MB   DDRALGHEAP
    # 0x87800000     6 MB   DDR2 (BIOS, Codecs, Applications)
    # 0x87E00000     1 MB   DSPLINK (MEM)
    # 0x87F00000     4 KB   DSPLINK (RESET)
    # 0x87F01000  1020 KB   unused

    insmod cmemk.ko phys_start=0x85700000 phys_end=0x86800000 pools=20x4096,8x131072,5x1048576,1x1429440,1x256000,1x3600000,5x829440,1x226000

     

     

  • Hello Steve and Bernie,

    Many Thanks for your detailed description about CMEM, unfortunately it will
    not be useful for us. Because we do not intend to create any additional
    buffer for display .

    Our original problem is that we wish insert text and still pictures over a
    video , in order to do so we are using the DMAI facilities and when using
    such DMAI a severe flicker appears , that we assume is produced by a problem
    with the vsync .

    Regarding the buffer issues, yes, I understand that the correct way to
    do the render is swapping buffers instead of copy them. In fact, I
    understand that Dmai is doing this and it looks like working well except
    for the vertical sync problem.

    We asume that Dmai should have a solution for the flickering even today
    looking in the source of Dmai we did not find

    Looking at the Dmai source code I see that it works as you explain, it
    do a swapping instead of copy buffers and it tried to wait for vertical
    sync when FBIO_WAITFORVSYNC is defined (and it looks like this is not
    the case when working with the evm3530)

    We are using basically;

    ...
    display_get()
    we do some render here
    display_put()
    ...


    Dmai functions display_get and display_put are defined like this on
    Display_fbdev.c:

    Int Display_fbdev_get(Display_Handle hDisplay, Buffer_Handle *hBufPtr)
    {
    #if defined(FBIO_WAITFORVSYNC)
    Int dummy;
    #endif
    BufTab_Handle hBufTab = hDisplay->hBufTab;

    assert(hDisplay);
    assert(hBufPtr);

    #if defined(FBIO_WAITFORVSYNC)
    /* Wait for vertical sync */
    if (ioctl(hDisplay->fd, FBIO_WAITFORVSYNC, &dummy) == -1) {
    Dmai_err1("Failed FBIO_WAITFORVSYNC (%s)\n", strerror(errno));
    return Dmai_EFAIL;
    }
    #endif
    *hBufPtr = BufTab_getBuf(hBufTab, hDisplay->workingIdx);

    return Dmai_EOK;
    }

    /***************************************************************************
    ***
    * Display_fbdev_put

    ****************************************************************************
    **/
    Int Display_fbdev_put(Display_Handle hDisplay, Buffer_Handle hBuf)
    {
    BufTab_Handle hBufTab = hDisplay->hBufTab;
    Int32 numBufs;

    assert(hDisplay);
    assert(hBuf);

    numBufs = BufTab_getNumBufs(hBufTab);

    hDisplay->displayIdx = (hDisplay->displayIdx + 1) % numBufs;
    hDisplay->workingIdx = (hDisplay->workingIdx + 1) % numBufs;

    return setDisplayBuffer(hDisplay, hDisplay->displayIdx);
    }


    As you can see, display_fbdev_get is trying to wait for vertical sync
    only if FBIO_WAITFORVSYNC is defined, and Display_fbdev_put rotates the
    available buffers avoiding to copy the contents. So, I understand that
    Dmai is working as you suggested.

    But the flickering problem remains, so my questions are:

    Why FBIO_WAITFORVSYNC is not defined in my host system? is this a
    problem with EVM3530? maybe it works with other targets?
    Do I need to forget about Dmai and implement this by myself?


    Thanks again for your support.


    RamOn
  • RamOn,

    Unfortunately I do not really know too much about the software side, so can't be much more help.

    Could you send me a sample application so that I can see the flickering since this may help me determine exactly where the issue is?

    BR,

    Steve

  • Steve,

     

    Thanks again for your help.

    I wrote a simple example program that shows the flickering effect, I paste it here. Also I can send it to you by email if you preffer, or maybe I can upload it here somewhere?

    Thanks again for your time.

    Best Regards

    RamOn

     

    #include <stdio.h>
    #include <stdlib.h>
    #include <getopt.h>
    #include <string.h>
    #include <unistd.h>
    #include <pthread.h>
    #include <signal.h>

    #include <errno.h>

    #include <sys/types.h>
    #include <sys/time.h>
    #include <sys/resource.h>
    #include <sys/ioctl.h>
    #include <sys/mman.h>
    #include <sys/time.h>


    #include <linux/videodev.h>
    #include <linux/videodev2.h>
    #include <linux/fb.h>

    #include <fcntl.h>



    #include <xdc/std.h>
    #include <ti/sdo/ce/trace/gt.h>
    #include <ti/sdo/ce/CERuntime.h>
    #include <ti/sdo/ce/Engine.h>
    #include <ti/sdo/ce/osal/Memory.h>
    #include <ti/sdo/dmai/Ccv.h>
    #include <ti/sdo/dmai/Cpu.h>
    #include <ti/sdo/dmai/Dmai.h>
    #include <ti/sdo/dmai/Time.h>
    #include <ti/sdo/dmai/BufTab.h>
    #include <ti/sdo/dmai/Display.h>
    #include <ti/sdo/dmai/Sound.h>
    #include <ti/sdo/dmai/Buffer.h>
    #include <ti/sdo/dmai/BufferGfx.h>
    #include <ti/sdo/dmai/Loader.h>
    #include <ti/sdo/dmai/VideoStd.h>
    #include <ti/sdo/dmai/ce/Vdec2.h>
    #include <ti/sdo/dmai/ce/Adec1.h>
    #include <ti/sdo/dmai/ColorSpace.h>
    #include <ti/sdo/dmai/Framecopy.h>
    #include <ti/sdo/dmai/Fifo.h>
    #include <ti/sdo/dmai/Pause.h>
    #include <ti/sdo/dmai/Rendezvous.h>
    #include <ti/sdo/dmai/Blend.h>


    #include <ti/sdo/simplewidget/Font.h>
    #include <ti/sdo/simplewidget/Png.h>
    #include <ti/sdo/simplewidget/Jpeg.h>
    #include <ti/sdo/simplewidget/Text.h>
    #include <ti/sdo/simplewidget/Screen.h>


    #include <xdc/runtime/System.h>



    typedef struct{
        Display_Attrs             dAttrs;
        Display_Handle             hDisplay;
        Display_Output          videoOutput;
        Buffer_Handle             hDispBuf;
        BufferGfx_Dimensions     dim;
        }SPLAYER_DISPLAY;

    SPLAYER_DISPLAY display[2];

    __u32 colorkey;




    int main(Int argc, char *argv[])
        {
        Int16    *userPtr;
        struct v4l2_capability capability;
        struct v4l2_framebuffer framebuffer;
        struct v4l2_format fmt;
        int d,error,ret;
        int px,py;
        Png_Handle    hPng;
        /* Initialize Codec Engine runtime */
        CERuntime_init();
        /* Initialize Davinci Multimedia Application Interface */
        Dmai_init();


        /* CREATE THE VID DISPLAY */
        display[1].dAttrs   = Display_Attrs_O3530_VID_DEFAULT;
        display[1].hDispBuf = NULL;
        /* Detect what configuration is used */
        display[1].videoOutput = display[1].dAttrs.videoOutput = Display_Output_SYSTEM;
        display[1].dAttrs.videoStd = VideoStd_AUTO;
        /* The rotation will be updated in the case that AUTO is use for the Video std */
        display[1].dAttrs.rotation = display[1].dAttrs.videoOutput == Display_Output_LCD ? 90 : 0;
       /* We want double buffering, so lets create 2 buffers for the display */
        display[1].dAttrs.numBufs=2;
        /* Create the display */      
        display[1].hDisplay = Display_create(NULL, &display[1].dAttrs);  
        if (display[1].hDisplay == NULL) { printf("Error creating display VID\n"); return 1; }
       
        /* CREATE THE OSD DISPLAY */
        display[0].dAttrs   = Display_Attrs_O3530_OSD_DEFAULT;
        display[0].hDispBuf = NULL;
        /* Detect what configuration is used */
        display[0].videoOutput = display[0].dAttrs.videoOutput = Display_Output_SYSTEM;
        display[0].dAttrs.videoStd = VideoStd_AUTO;
        /* The rotation will be updated in the case that AUTO is use for the Video std */
        display[0].dAttrs.rotation = display[0].dAttrs.videoOutput == Display_Output_LCD ? 90 : 0;
        /* We want double buffering, so lets create 2 buffers for the display */
        display[0].dAttrs.numBufs=2;
        /* Create the display */  
        display[0].hDisplay = Display_create(NULL, &display[0].dAttrs);  
        if (display[0].hDisplay == NULL) { printf("Error creating display OSD\n"); return 1; }
       
        /* define the color key */
        colorkey=(__u32)((255 >> 3)|((0>>2)<<5)|((255>>3)<<(5+6)));

        d=1;

        /* Check if the device is capable of streaming */
        if (ioctl(Display_getHandle(display[d].hDisplay), VIDIOC_QUERYCAP, &capability) < 0) { printf("Error VIDIOC_QUERYCAP\n"); return 1; }
       


        /* set the buffer parameters */
        fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
        ret = ioctl(Display_getHandle(display[d].hDisplay), VIDIOC_G_FMT, &fmt);
        if (ret < 0) { printf("error V4L2_BUF_TYPE_VIDEO_OUTPUT\n"); return 1; };
           
        /* set the buffer parameters */
        fmt.type = V4L2_BUF_TYPE_VIDEO_OVERLAY;
        ret = ioctl(Display_getHandle(display[d].hDisplay), VIDIOC_G_FMT, &fmt);
        if (ret < 0) { printf("error V4L2_BUF_TYPE_VIDEO_OVERLAY\n"); return 1; };
           
        /* Set the window size and chromakey */
        fmt.fmt.win.w.left = 0;
        fmt.fmt.win.w.top = 0;
        fmt.fmt.win.w.width = 640;
        fmt.fmt.win.w.height = 480;
        /* Make red black color transperent */
        fmt.fmt.win.chromakey = colorkey;
        ret = ioctl(Display_getHandle(display[d].hDisplay), VIDIOC_S_FMT, &fmt);
        if (ret < 0) { printf("error chromakey\n"); return 1; };
           
        /* Get the flags related to overlay parameters like alpha blending, color keying.
           Enabled color keying after setting the chroma key as chormakey set is used
           while enabling of the color keying  */
        ret = ioctl (Display_getHandle(display[d].hDisplay), VIDIOC_G_FBUF, &framebuffer);
        if (ret < 0) { printf("error VIDIOC_G_FBUF\n"); return 1; };
           
        /* Check if device supports color keying */
        if(!(framebuffer.capability & V4L2_FBUF_CAP_CHROMAKEY)) { printf("error V4L2_FBUF_CAP_CHROMAKEY\n"); return 1; };

        /* Set SRC_COLOR_KEYING */
        framebuffer.flags &= ~V4L2_FBUF_FLAG_SRC_CHROMAKEY;
        framebuffer.flags |= V4L2_FBUF_FLAG_CHROMAKEY;

        ret = ioctl (Display_getHandle(display[d].hDisplay), VIDIOC_S_FBUF, &framebuffer);
        if (ret < 0) { printf("error VIDIOC_S_FBUF\n"); return 1; };
       

        hPng=Png_create("test.png");

        printf("init success\n");


        while (1)
            {
            usleep(1000);

            Display_get(display[0].hDisplay, &display[0].hDispBuf);

            /* paint all the background with the key color */
            userPtr = (Int16 *)Buffer_getUserPtr(display[0].hDispBuf);

            for (py=0; py<480; py++)
                {
                for (px=0; px<640; px++)
                    {
                    *(userPtr+px)=(Int16)colorkey;
                    }
                userPtr+=4096/2;
                }

            Png_show(hPng,10,19,display[0].hDispBuf);


            Display_put(display[0].hDisplay, display[0].hDispBuf);
            }

        return 0;
        }

     

  • I did a modification in the omap3530 default example.

    I modified the file /home/<user>/dvsdk_#_##_##_ ##/dvsdk_demos_#_##_##_##/omap3530/interface/menu.c, so now it shows my flickering problem.

    I attached the modified file here.

    Thanks

    1205.menu.zip

  • Hi all,

    Thanks for all your time and help with the flickering problem.

    It was a problem with the Dmai source code and it was solved with a patch that TI sent me.

    Thanks again for your help.

    Regards.

    RamOn


  • Hi Ramon,

    Could  you please  share the patch which you got from TI to solve Flickering Problem.

    Thanks & Regards,

    Ganesh

  • Hi,

    I also need this patch. If a TI employee can post the patch here or somewhere on web, I think it would be useful for a lot of people.

    Regards,

    Fatih