/******************************************************************************/
/*
 * File name: FdkAddConstantMain.cpp
 * Location:  ...\Matrox Imaging\MILxxx\Examples\BoardSpecific\solios\C++\SoliosFDK
 *             \AddConstantPrimitive
 *
 * Synopsis:  This example shows how to test and benchmark a custom FPGA
 *            accelerated processing function that adds a constant to 
 *            an image. 
 */

/* Headers. */
#include <mil.h>

#define CONSTANT_TO_ADD    50
#define NB_LOOP            100
#define IMAGE_FILE         M_IMAGE_PATH MIL_TEXT("Board.mim")

/* Master MIL functions declaration. */
void FpgaAddConstant(MIL_ID SrcImageId, MIL_ID DstImageId, MIL_INT ConstantToAdd,
                                                            MIL_INT ControlFlag);

/* Main test and benchmark function. */
/* --------------------------------- */

int MosMain(void)
   {
   MIL_ID   MilApplication;
   MIL_ID   MilSystem     ;
   MIL_ID   MilDisplay    ;
   MIL_ID   MilImageSrc   ;
   MIL_ID   MilImageDst   ;
   MIL_ID   MilImageDisp  ;
   MIL_INT  SizeX, SizeY, n, BoardType;
   MIL_DOUBLE Time;

   /* Allocate defaults. */
   MappAllocDefault(M_DEFAULT, &MilApplication, &MilSystem, &MilDisplay, M_NULL, M_NULL);

   /* Verify for FPGA offload support on the target system.*/
   MsysInquire(MilSystem, M_BOARD_TYPE, &BoardType);
   if(!(BoardType & M_PF))
      {
      MosPrintf(MIL_TEXT("Error: This example needs a processing FPGA installed on your\n"));
      MosPrintf(MIL_TEXT("system to continue.\n"));
      MosPrintf(MIL_TEXT("Press <Enter> to quit.\n"));
      MosGetch();
      MdispFree(MilDisplay);
      MsysFree(MilSystem);
      MappFree(MilApplication);
      return(0);
      }
   
   /* Allocate buffers and clear them.*/
   /* For FPGA acceleration, all source buffers must be in FPGA accessible and 
      destination buffers can be in host FPGA accessible memory or in FPGA memory. */
   SizeX = MbufDiskInquire(IMAGE_FILE, M_SIZE_X, M_NULL);
   SizeY = MbufDiskInquire(IMAGE_FILE, M_SIZE_Y, M_NULL);
   MbufAlloc2d(MilSystem, SizeX, SizeY,8+M_UNSIGNED,
               M_IMAGE+M_PROC+M_GRAB+M_FPGA_ACCESSIBLE, &MilImageSrc);
   MbufAlloc2d(MilSystem, SizeX, SizeY,8+M_UNSIGNED, 
               M_IMAGE+M_PROC+M_HOST_MEMORY+M_FPGA_ACCESSIBLE, &MilImageDst);
   MbufAlloc2d(MilSystem, SizeX, SizeY,8+M_UNSIGNED,
               M_IMAGE+M_DISP+M_NON_PAGED, &MilImageDisp);
   MbufClear(MilImageSrc, 0);
   MbufClear(MilImageDst, 0);
   MbufClear(MilImageDisp, 0);

   /* Load the source image and display it. */
   MbufLoad(IMAGE_FILE, MilImageSrc);
   MbufLoad(IMAGE_FILE, MilImageDisp);
   MdispSelect(MilDisplay, MilImageDisp);

   MosPrintf(MIL_TEXT("This example demonstrates how to create and use an \n"));
   MosPrintf(MIL_TEXT("FPGA accelerated Add Constant processing primitive.\n"));
   MosPrintf(MIL_TEXT("Press <Enter> to continue.\n"));
   MosGetchar();

   /* Do a first iteration to load the Mfpga library. */
   FpgaAddConstant(MilImageSrc, MilImageDst, CONSTANT_TO_ADD, M_SATURATION);

   /* Benchmark the FPGA accelerated function. */
   MappTimer(M_DEFAULT, M_TIMER_RESET+M_SYNCHRONOUS, M_NULL);
   for(n = 0; n < NB_LOOP; n++)
      {
      FpgaAddConstant(MilImageSrc, MilImageDst, CONSTANT_TO_ADD, M_SATURATION);
      }
   MappTimer(M_DEFAULT, M_TIMER_READ+M_SYNCHRONOUS, &Time);
   MosPrintf(MIL_TEXT("Add constant time: %.3f ms.\n"), (Time*1000.0)/NB_LOOP);

   /* Update the display buffer with the result of the last processing operation. */
   MbufCopy(MilImageDst, MilImageDisp);
   MosPrintf(MIL_TEXT("Press <Enter> to terminate.\n"));
   MosGetchar();

   /* Free the MIL objects. */
   MbufFree(MilImageSrc);
   MbufFree(MilImageDst);
   MappFreeDefault(MilApplication, MilSystem, MilDisplay, M_NULL, MilImageDisp);

   return 0;
   }