text: /*
  * Copyright (c) 2008-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      hal_kerneldll.c 
  //! \brief         Kernel Dynamic Linking / Loading routines 
  //!
  #ifndef VPHAL_LIB
  
  #if IMOLA
  #include <stdlib.h>
  #endif // IMOLA
  #include <math.h> //for sin & cos
  #endif  // VPHAL_LIB
  
  #if EMUL || VPHAL_LIB
  #include <math.h>
  #include "support.h"
  #elif LINUX
  #else  // !(EMUL | VPHAL_LIB) && !LINUX
  
  #endif // EMUL | VPHAL_LIB
  
  #include "hal_kerneldll.h"
  #include "vphal.h"
  
  // Define _DEBUG symbol for KDLL Release build before loading the "vpkrnheader.h" file
  // This is necessary for full kernels names in both Release/Debug versions of KDLL app
  #if EMUL || VPHAL_LIB
  #ifndef _DEBUG
  #define _DEBUG 2
  #endif // _DEBUG
  #endif // EMUL || VPHAL_LIB
  
  // Kernel IDs and Kernel Names
  #include "vpkrnheader.h" // IDR_VP_TOTAL_NUM_KERNELS
  
  // Undefine _DEBUG symbol for the remaining of the KDLL Release build
  #if _DEBUG == 2
  #undef _DEBUG
  #endif // _DEBUG
  
  #ifndef PI
  #define PI 3.1415926535897932f
  #endif // PI
  
  #ifdef __cplusplus
  extern "C" {
  #endif // __cplusplus
  
  const bool g_cIsFormatYUV[Format_Count] =
  {
      false,  // Format_Any
      false,  // Format_A8R8G8B8
      false,  // Format_X8R8G8B8
      false,  // Format_A8B8G8R8
      false,  // Format_X8B8G8R8
      false,  // Format_A16B16G16R16
      false,  // Format_A16R16G16B16
      false,  // Format_R5G6B5
      false,  // Format_R32U
      false,  // Format_R32F
      false,  // Format_R8G8B8
      false,  // Format_RGBP
      false,  // Format_BGRP
      true,   // Format_YUY2
      true,   // Format_YUYV
      true,   // Format_YVYU
      true,   // Format_UYVY
      true,   // Format_VYUY
      true,   // Format_Y216
      true,   // Format_Y210
      true,   // Format_Y416
      true,   // Format_AYUV
      true,   // Format_AUYV
      true,   // Format_Y410
      true,   // Format_400P
      true,   // Format_NV12
      true,   // Format_NV12_UnAligned
      true,   // Format_NV21
      true,   // Format_NV11
      true,   // Format_NV11_UnAligned
      true,   // Format_P208
      true,   // Format_P208_UnAligned
      true,   // Format_IMC1
      true,   // Format_IMC2
      true,   // Format_IMC3
      true,   // Format_IMC4
      true,   // Format_422H
      true,   // Format_422V
      true,   // Format_444P
      true,   // Format_411P
      true,   // Format_411R
      true,   // Format_I420
      true,   // Format_IYUV
      true,   // Format_YV12
      true,   // Format_YVU9
      true,   // Format_AI44    (YUV originally, palette may be converted to RGB)
      true,   // Format_IA44    (same as above)
      false,  // Format_P8      (using RGB since P8 is uncommon in FC)
      false,  // Format_A8P8    (same as above)
      false,  // Format_A8
      false,  // Format_L8
      false,  // Format_A4L4
      false,  // Format_A8L8
      true,   // Format_IRW0
      true,   // Format_IRW1
      true,   // Format_IRW2
      true,   // Format_IRW3
      true,   // Format_IRW4
      true,   // Format_IRW5
      true,   // Format_IRW6
      true,   // Format_IRW7
      false,  // Format_STMM
      false,  // Format_Buffer
      false,  // Format_Buffer_2D
      false,  // Format_V8U8
      false,  // Format_R32S
      false,  // Format_R8U
      false,  // Format_R8G8UN
      false,  // Format_R8G8SN
      false,  // Format_G8R8_G8B8
      false,  // Format_R16U
      false,  // Format_R16S
      false,  // Format_R16UN
      false,  // Format_RAW
      false,  // Format_Y8
      false,  // Format_Y1
      false,  // Format_Y16U
      false,  // Format_Y16S
      false,  // Format_L16
      false,  // Format_D16
      false,  // Format_R10G10B10A2
      false,  // Format_B10G10R10A2
      true,   // Format_P016
      true,   // Format_P010
      true    // Format_YV12_Planar
  };
  
  const float g_cCSC_sRGB_stRGB[12] =
  {
      0.858824f,  0.000000f,  0.000000f,  16.000000f,   // stR = C0 * sR + C1 * sG + C2  * sB + C3
      0.000000f,  0.858824f,  0.000000f,  16.000000f,   // stG = C4 * sR + C5 * sG + C6  * sB + C7
      0.000000f,  0.000000f,  0.858824f,  16.000000f    // stB = C8 * sR + C9 * sG + C10 * sB + C11
  };
  
  const float g_cCSC_stRGB_sRGB[12] =
  {
      1.164384f,  0.000000f,  0.000000f, -18.630137f,   // sR   = C0 * stR + C1 * stG + C2  * stB + C3
      0.000000f,  1.164384f,  0.000000f, -18.630137f,   // sG   = C4 * stR + C5 * stG + C6  * stB + C7
      0.000000f,  0.000000f,  1.164384f, -18.630137f    // sB   = C8 * stR + C9 * stG + C10 * stB + C11
  };
  
  const float g_cCSC_Identity[12] =
  {
      1.0f,  0.0f, 0.0f, 0.0f,
      0.0f,  1.0f, 0.0f, 0.0f,
      0.0f,  0.0f, 1.0f, 0.0f
  };
  
  const float g_cCSC_GrayIdentity[12] =
  {
      1.0f,  0.0f, 0.0f, 0.000f,
      0.0f,  0.0f, 0.0f, 128.0f,
      0.0f,  0.0f, 0.0f, 128.0f
  };
  
  // Generic RGB to YUV conversion matrix from BT.601 standard
  const float g_cCSC_BT601_RGB_YUV[9] =
  {
      0.299000f,  0.587000f,  0.114000f,
     -0.168736f, -0.331264f,  0.500000f,
      0.500000f, -0.418688f, -0.081312f
  };
  
  // Generic RGB to YUV conversion matrix from BT.709 standard
  const float g_cCSC_BT709_RGB_YUV[9] =
  {
      0.212600f,  0.715200f,  0.072200f,
     -0.114572f, -0.385428f,  0.500000f,
      0.500000f, -0.454153f, -0.045847f
  };
  
  // Generic YUV to RGB conversion matrix from BT.601 standard
  const float g_cCSC_BT601_YUV_RGB[9] =
  {
      1.000000f,  0.000000f,  1.402000f,
      1.000000f, -0.344136f, -0.714136f,
      1.000000f,  1.772000f,  0.000000f
  };
  
  // Generic YUV to RGB conversion matrix from BT.709 standard
  const float g_cCSC_BT709_YUV_RGB[9] =
  {
      1.000000f,  0.000000f,  1.574800f,
      1.000000f, -0.187324f, -0.468124f,
      1.000000f,  1.855600f,  0.000000f
  };
  
  // BT2020 RGB to Non-constant YUV conversion matrix from R-REC-BT.2020-1-201406-I!!PDF-E.pdf
  const float g_cCSC_BT2020_RGB_YUV[9] =
  {
      0.262700f,  0.678000f,  0.059300f,     // Y
      -0.139630f, -0.360370f, 0.500000f,     // U
      0.500000f,  -0.459786f, -0.040214f     // V
  };
  
  // BT2020 Non-constant YUV to RGB conversion matrix from R-REC-BT.2020-1-201406-I!!PDF-E.pdf
  const float g_cCSC_BT2020_YUV_RGB[9] =
  {
      1.000000f, 0.000000f,  1.474600f,     //R
      1.000000f, -0.164553f, -0.571353f,    //G
      1.000000f, 1.881400f,  0.000000f      //B
  };
  
  // BT2020 YUV Limited Range to BT2020 RGB full range conversion matrix
  const float g_cCSC_BT2020_LimitedYUV_RGB[9] =
  {
      1.164383f,  0.000000f,  1.678680f,    // R
      1.164383f, -0.187332f, -0.650421f,    // G
      1.164383f,  2.141769f,  0.000000f     // B
  };
  
  // BT2020 RGB full range to BT2020 YUV Limited Range tconversion matrix
  const float g_cCSC_BT2020_RGB_LimitedYUV[9] =
  {
      0.225617f,   0.582275f,  0.050934f,  // Y
      -0.122650f, -0.316559f,  0.439209f,  // U
      0.439209f,  -0.403885f, -0.035324f   // V
  };
  
  const char  *g_cInit_ComponentNames[] =
  {
      IDR_VP_KERNEL_NAMES
  };
  
  #define FOLD_HASH(folded_hash, hash)                                   \
      {                                                                  \
          folded_hash = (((hash) >> 8) ^ (hash)) & 0x00ff00ff;           \
          folded_hash = ((folded_hash >> 16) ^ folded_hash) & 0xff;      \
      }                                                                  \
  
  #if _DEBUG || EMUL || VPHAL_LIB
  
  #ifndef VPHAL_LIB
  #pragma warning( push )
  #pragma warning( disable : 4996 )
  #endif // VPHAL_LIB
  
  const char    *KernelDll_GetLayerString(Kdll_Layer layer)
  {
      switch (layer)
      {
          case Layer_Invalid     : return _T("Invalid");
          case Layer_None        : return _T("None");
          case Layer_Background  : return _T("Background");
          case Layer_MainVideo   : return _T("Main Video");
          case Layer_SubVideo    : return _T("Sub-Video");
          case Layer_SubPicture1 : return _T("Sub-Picture 1");
          case Layer_SubPicture2 : return _T("Sub-Picture 2");
          case Layer_SubPicture3 : return _T("Sub-Picture 3");
          case Layer_SubPicture4 : return _T("Sub-Picture 4");
          case Layer_Graphics    : return _T("Graphics");
          case Layer_RenderTarget: return _T("Render Target");
      }
  
      return nullptr;
  }
  
  const char    *KernelDll_GetFormatString(MOS_FORMAT   format)
  {
      switch (format)
      {
          case Format_Invalid     : return _T("Invalid");
          case Format_Source      : return _T("Current layer");
          case Format_RGB         : return _T("RGB");
          case Format_RGB32       : return _T("RGB32");
          case Format_PA          : return _T("PA");
          case Format_PL2         : return _T("PL2");
          case Format_PL3         : return _T("PL3");
          case Format_PL3_RGB     : return _T("PL3_RGB");
          case Format_PAL         : return _T("PAL");
          case Format_None        : return _T("None");
          case Format_Any         : return _T("Any");
          case Format_A8R8G8B8    : return _T("ARGB");
          case Format_X8R8G8B8    : return _T("RGB");
          case Format_A8B8G8R8    : return _T("ABGR");
          case Format_X8B8G8R8    : return _T("BGR");
          case Format_A16B16G16R16: return _T("A16B16G16R16");
          case Format_A16R16G16B16: return _T("A16R16G16B16");
          case Format_R5G6B5      : return _T("RGB16");
          case Format_R8G8B8      : return _T("RGB24");
          case Format_R32U        : return _T("R32U");
          case Format_R32F        : return _T("R32F");
          case Format_RGBP        : return _T("RGBP");
          case Format_BGRP        : return _T("BGRP");
          case Format_YUY2        : return _T("YUY2");
          case Format_YUYV        : return _T("YUYV");
          case Format_YVYU        : return _T("YVYU");
          case Format_UYVY        : return _T("UYVY");
          case Format_VYUY        : return _T("VYUY");
          case Format_Y416        : return _T("Y416");
          case Format_AYUV        : return _T("AYUV");
          case Format_AUYV        : return _T("AUYV");
          case Format_400P        : return _T("400P");
          case Format_NV12        : return _T("NV12");
          case Format_NV12_UnAligned: return _T("NV12_UnAligned");
          case Format_NV21        : return _T("NV21");
          case Format_NV11        : return _T("NV11");
          case Format_NV11_UnAligned: return _T("NV11_UnAligned");
          case Format_P208        : return _T("P208");
          case Format_P208_UnAligned: return _T("P208_UnAligned");
          case Format_IMC1        : return _T("IMC1");
          case Format_IMC2        : return _T("IMC2");
          case Format_IMC3        : return _T("IMC3");
          case Format_IMC4        : return _T("IMC4");
          case Format_422H        : return _T("422H");
          case Format_422V        : return _T("422V");
          case Format_444P        : return _T("444P");
          case Format_411P        : return _T("411P");
          case Format_411R        : return _T("411R");
          case Format_I420        : return _T("I420");
          case Format_IYUV        : return _T("IYUV");
          case Format_YV12        : return _T("YV12");
          case Format_YVU9        : return _T("YVU9");
          case Format_AI44        : return _T("AI44");
          case Format_IA44        : return _T("IA44");
          case Format_P8          : return _T("P8");
          case Format_A8P8        : return _T("A8P8");
          case Format_A8          : return _T("A8");
          case Format_L8          : return _T("L8");
          case Format_A4L4        : return _T("A4L4");
          case Format_A8L8        : return _T("A8L8");
          case Format_IRW0        : return _T("IRW0");
          case Format_IRW1        : return _T("IRW1");
          case Format_IRW2        : return _T("IRW2");
          case Format_IRW3        : return _T("IRW3");
          case Format_IRW4        : return _T("IRW4");
          case Format_IRW5        : return _T("IRW5");
          case Format_IRW6        : return _T("IRW6");
          case Format_IRW7        : return _T("IRW7");
          case Format_STMM        : return _T("STMM");
          case Format_Buffer      : return _T("Buffer");
          case Format_Buffer_2D   : return _T("Buffer_2D");
          case Format_V8U8        : return _T("V8U8");
          case Format_R32S        : return _T("R32S");
          case Format_R8U         : return _T("RU8");
          case Format_R8G8UN      : return _T("R8G8UN");
          case Format_R8G8SN      : return _T("R8S8UN");
          case Format_G8R8_G8B8   : return _T("G8R8_G8B8");
          case Format_R16U        : return _T("R16U");
          case Format_R16S        : return _T("R16S");
          case Format_R16UN       : return _T("R16UN");
          case Format_RAW         : return _T("RAW");
          case Format_Y8          : return _T("Y8");
          case Format_Y1          : return _T("Y1");
          case Format_Y16U        : return _T("Y16U");
          case Format_Y16S        : return _T("Y16S");
          case Format_L16         : return _T("L16");
          case Format_D16         : return _T("D16");
          case Format_R10G10B10A2 : return _T("R10G10B10A2");
          case Format_B10G10R10A2 : return _T("B10G10R10A2");
          case Format_P016        : return _T("P016");
          case Format_P010        : return _T("P010");
          case Format_YV12_Planar : return _T("YV12_Planar");
          default                 : return _T("Invalid format");
      }
  
      return nullptr;
  }
  
  const char    *KernelDll_GetCSpaceString(VPHAL_CSPACE cspace)
  {
      switch (cspace)
      {
          case CSpace_None                : return _T("None");
          case CSpace_Source              : return _T("Current layer");
          case CSpace_RGB                 : return _T("RGB");
          case CSpace_YUV                 : return _T("YUV");
          case CSpace_Any                 : return _T("Any");
          case CSpace_sRGB                : return _T("sRGB");
          case CSpace_BT601               : return _T("BT.601");
          case CSpace_BT601_FullRange     : return _T("BT.601_FullRange");
          case CSpace_BT709               : return _T("BT.709");
          case CSpace_BT709_FullRange     : return _T("BT.709_FullRange");
          case CSpace_xvYCC601            : return _T("xvYCC.601");
          case CSpace_xvYCC709            : return _T("xvYCC.709");
          case CSpace_BT601Gray           : return _T("BT.601Gray");
          case CSpace_BT601Gray_FullRange : return _T("BT.601Gray_FullRange");
          default                         : return _T("Invalid cspace");
      }
  
      return nullptr;
  }
  
  const char    *KernelDll_GetSamplingString(Kdll_Sampling sampling)
  {
      switch (sampling)
      {
          case Sample_None             : return _T("No Sampling");
          case Sample_Source           : return _T("Current layer");
          case Sample_Any              : return _T("Any Sampling");
          case Sample_Scaling_Any      : return _T("Any Scale");
          case Sample_Scaling          : return _T("Scale");
          case Sample_Scaling_034x     : return _T("0.34x");
          case Sample_Scaling_AVS      : return _T("AVS");
          case Sample_iScaling         : return _T("iScale");
          case Sample_iScaling_034x    : return _T("0.34x iScaling");
          case Sample_iScaling_AVS     : return _T("iAVS");
      }
  
      return nullptr;
  }
  
  const char    *KernelDll_GetRotationString(VPHAL_ROTATION rotation)
  {
      switch (rotation)
      {
          case VPHAL_ROTATION_IDENTITY            : return _T("0");
          case VPHAL_ROTATION_90                  : return _T("90");
          case VPHAL_ROTATION_180                 : return _T("180");
          case VPHAL_ROTATION_270                 : return _T("270");
          case VPHAL_MIRROR_HORIZONTAL            : return _T("Horizontal");
          case VPHAL_MIRROR_VERTICAL              : return _T("Vertical");
          case VPHAL_ROTATE_90_MIRROR_VERTICAL    : return _T("90 Mirror Vertical");
          case VPHAL_ROTATE_90_MIRROR_HORIZONTAL  : return _T("90 Mirror Horizontal");
      }
  
      return nullptr;
  }
  
  const char    *KernelDll_GetProcessString(Kdll_Processing process)
  {
      switch (process)
      {
          case Process_None        : return _T("No processing");
          case Process_Source      : return _T("Current layer");
          case Process_Any         : return _T("Any processing");
          case Process_Composite   : return _T("Composite");
          case Process_XORComposite: return _T("XOR Mono Composite");
          case Process_CBlend      : return _T("Const Blend");
          case Process_SBlend      : return _T("Source Blend");
          case Process_SBlend_4bits: return _T("Source Blend 4-bits");
          case Process_PBlend      : return _T("Part Blend");
          case Process_CSBlend     : return _T("ConstSource Blend");
          case Process_CPBlend     : return _T("ConstPart Blend");
          case Process_DI          : return _T("DI");
          case Process_DN          : return _T("DN");
          case Process_DNDI        : return _T("DNDI");
      }
  
      return nullptr;
  }
  
  
  const char    *KernelDll_GetParserStateString(Kdll_ParserState state)
  {
      switch (state)
      {
          case Parser_Invalid                 : return _T("Invalid");
          case Parser_Begin                   : return _T("Begin");
          case Parser_SetRenderMethod         : return _T("SetRenderMethod");
          case Parser_SetupLayer0             : return _T("SetupLayer0");
          case Parser_SetupLayer1             : return _T("SetupLayer1");
          case Parser_SetParamsLayer0         : return _T("SetParamsLayer0");
          case Parser_SetParamsLayer1         : return _T("SetParamsLayer1");
          case Parser_SetParamsTarget         : return _T("SetParamsTarget");
          case Parser_SampleLayer0            : return _T("SampleLayer0");
          case Parser_SampleLayer0Mix         : return _T("SampleLayer0Mix");
          case Parser_SampleLayer0ColorFill   : return _T("SampleLayer0ColorFill");
          case Parser_RotateLayer0Check       : return _T("SampleRotateLayer0Check");
          case Parser_RotateLayer0            : return _T("SampleRotateLayer0");
          case Parser_SampleLayer0Done        : return _T("SampleLayer0Done");
          case Parser_ShuffleLayer0           : return _T("ShuffleLayer0");
          case Parser_SampleLayer1            : return _T("SampleLayer1");
          case Parser_SampleLayer1Done        : return _T("SampleLayer1Done");
          case Parser_ShuffleLayer1           : return _T("ShuffleLayer1");
          case Parser_SampleLayer0SelectCSC   : return _T("SampleLayer0SelectCSC");
          case Parser_SetupCSC0               : return _T("SetupCSC0");
          case Parser_ExecuteCSC0             : return _T("ExecuteCSC0");
          case Parser_ExecuteCSC0Done         : return _T("ExecuteCSC0Done");
          case Parser_SetupCSC1               : return _T("SetupCSC1");
          case Parser_ExecuteCSC1             : return _T("ExecuteCSC1");
          case Parser_ExecuteCSC1Done         : return _T("ExecuteCSC1Done");
          case Parser_Lumakey                 : return _T("LumaKey");
          case Parser_ProcessLayer            : return _T("ProcessLayer");
          case Parser_ProcessLayerDone        : return _T("ProcessLayerDone");
          case Parser_DualOutput              : return _T("DualOutput");
          case Parser_Rotation                : return _T("Rotation");
          case Parser_DestSurfIndex           : return _T("DestSurfIndex");
          case Parser_Colorfill               : return _T("Colorfill");
          case Parser_WriteOutput             : return _T("WriteOutput");
          case Parser_End                     : return _T("End");
          default                             : return _T("Invalid parser state");
      }
  
      return nullptr;
  }
  
  const char    *KernelDll_GetRuleIDString(Kdll_RuleID RID)
  {
      switch (RID)
      {
          case RID_Op_EOF             : return _T("EOF");
          case RID_Op_NewEntry        : return _T("NewEntry");
          case RID_IsTargetCspace     : return _T("IsTargetCspace");
          case RID_IsLayerID          : return _T("IsLayerID");
          case RID_IsLayerFormat      : return _T("IsLayerFormat");
          case RID_IsParserState      : return _T("IsParserState");
          case RID_IsRenderMethod     : return _T("IsRenderMethod");
          case RID_IsShuffling        : return _T("IsShuffling");
          case RID_IsLayerRotation    : return _T("IsLayerRotation");
          case RID_IsSrc0Format       : return _T("IsSrc0Format");
          case RID_IsSrc0Sampling     : return _T("IsSrc0Sampling");
          case RID_IsSrc0ColorFill    : return _T("IsSrc0ColorFill");
          case RID_IsSrc0LumaKey      : return _T("IsSrc0LumaKey");
          case RID_IsSrc0Procamp      : return _T("IsSrc0Procamp");
          case RID_IsSrc0Rotation     : return _T("IsSrc0Rotation");
          case RID_IsSrc0Coeff        : return _T("IsSrc0Coeff");
          case RID_IsSrc0Processing   : return _T("IsSrc0Processing");
          case RID_IsSrc1Format       : return _T("IsSrc1Format");
          case RID_IsSrc1Sampling     : return _T("IsSrc1Sampling");
          case RID_IsSrc1LumaKey      : return _T("IsSrc1LumaKey");
          case RID_IsSrc1SamplerLumaKey: return _T("IsSrc1SamplerLumaKey");
          case RID_IsSrc1Coeff        : return _T("IsSrc1Coeff");
          case RID_IsSrc1Processing   : return _T("IsSrc1Processing");
          case RID_IsLayerNumber      : return _T("IsLayerNumber");
          case RID_IsQuadrant         : return _T("IsQuadrant");
          case RID_IsCSCBeforeMix     : return _T("IsCSCBeforeMix");
          case RID_IsDualOutput       : return _T("IsDualOutput");
          case RID_IsRTRotate         : return _T("IsRTRotate");
          case RID_IsTargetFormat     : return _T("IsTargetFormat");
          case RID_Is64BSaveEnabled   : return _T("Is64BSaveEnabled");
          case RID_IsTargetTileType   : return _T("IsTargetTileType");
          case RID_IsProcampEnabled   : return _T("IsProcampEnabled");
          case RID_SetTargetCspace    : return _T("SetTargetCspace");
          case RID_SetParserState     : return _T("SetParserState");
          case RID_SetSrc0Format      : return _T("SetSrc0Format");
          case RID_SetSrc0Sampling    : return _T("SetSrc0Sampling");
          case RID_SetSrc0ColorFill   : return _T("SetSrc0ColorFill");
          case RID_SetSrc0LumaKey     : return _T("SetSrc0LumaKey");
          case RID_SetSrc0Rotation    : return _T("SetSrc0Rotation");
          case RID_SetSrc0Coeff       : return _T("SetSrc0Coeff");
          case RID_SetSrc0Processing  : return _T("SetSrc0Processing");
          case RID_SetSrc1Format      : return _T("SetSrc1Format");
          case RID_SetSrc1Sampling    : return _T("SetSrc1Sampling");
          case RID_SetSrc1Rotation    : return _T("SetSrc1Rotation");
          case RID_SetSrc1LumaKey     : return _T("SetSrc1LumaKey");
          case RID_SetSrc1SamplerLumaKey: return _T("SetSrc1SamplerLumaKey");
          case RID_SetSrc1Procamp     : return _T("SetSrc1Procamp");
          case RID_SetSrc1Coeff       : return _T("SetSrc1Coeff");
          case RID_SetSrc1Processing  : return _T("SetSrc1Processing");
          case RID_SetKernel          : return _T("SetKernel");
          case RID_SetNextLayer       : return _T("SetNextLayer");
          case RID_SetPatchData       : return _T("SetPatchData");
          case RID_SetQuadrant        : return _T("SetQuadrant");
          case RID_SetCSCBeforeMix    : return _T("SetCSCBeforeMix");
          case RID_SetPatch           : return _T("SetPatch");
          case RID_IsSrc0Chromasiting : return _T("IsSrc0Chromasiting");
          case RID_IsSrc1Procamp      : return _T("IsSrc1Procamp");
          case RID_IsSrc1Chromasiting : return _T("IsSrc1Chromasiting");
          case RID_IsSetCoeffMode     : return _T("IsSetCoeffMode");
          case RID_IsConstOutAlpha    : return _T("IsConstOutAlpha");
          case RID_IsDitherNeeded     : return _T("IsDitherNeeded");
          case RID_IsScalingRatio     : return _T("IsScalingRatio");
          case RID_SetSrc0Procamp     : return _T("SetSrc0Procamp");
      }
  
      return nullptr;
  }
  
  const char    *KernelDll_GetCoeffIDString(Kdll_CoeffID CID)
  {
      switch (CID)
      {
          case CoeffID_Src0   : return _T("Src0 coeff");
          case CoeffID_Src1   : return _T("Src1 coeff");
          case CoeffID_Source : return _T("Current layer");
          case CoeffID_Any    : return _T("Any coeff");
          case CoeffID_None   : return _T("No coeff");
          case CoeffID_0      : return _T("Coeff 0");
          case CoeffID_1      : return _T("Coeff 1");
          case CoeffID_2      : return _T("Coeff 2");
          case CoeffID_3      : return _T("Coeff 3");
          case CoeffID_4      : return _T("Coeff 4");
          case CoeffID_5      : return _T("Coeff 5");
      }
  
      return nullptr;
  }
  
  const char    *KernelDll_GetShuffleString(Kdll_Shuffling shuffling)
  {
      switch (shuffling)
      {
          case Shuffle_None          : return _T("None");
          case Shuffle_Any           : return _T("Any");
          case Shuffle_All_8x8_Layer : return _T("All 8x8 Layer");
          case Shuffle_RenderTarget  : return _T("Render Target");
      }
  
      return nullptr;
  }
  
  int32_t KernelDll_PrintRule(
      char                    *szOut,
      int32_t                 iSize,
      const Kdll_RuleEntry    *pEntry,
      Kdll_KernelCache        *pCache)
  {
      char    data[32];
      int32_t increment   = 1;
      const char *szRID   = KernelDll_GetRuleIDString(pEntry->id);
      const char *szValue = nullptr;
  
      switch (pEntry->id)
      {
          case RID_IsParserState     :
          case RID_SetParserState    :
              szValue = KernelDll_GetParserStateString((Kdll_ParserState) pEntry->value);
              break;
  
          case RID_IsLayerID         :
              szValue = KernelDll_GetLayerString((Kdll_Layer) pEntry->value);
              break;
  
          case RID_Op_NewEntry       :
          case RID_Op_EOF            :
          case RID_IsLayerNumber     :
          case RID_IsQuadrant        :
          case RID_SetQuadrant       :
          case RID_SetPatchData      :
              _stprintf(data, _T("%d"), pEntry->value);
              szValue = data;
              break;
  
          case RID_IsSrc0ColorFill   :
          case RID_SetSrc0ColorFill  :
              if (pEntry->value == ColorFill_Source)
              {
                  szValue = _T("Current Layer");
              }
              else if (pEntry->value)
              {
                  szValue = _T("TRUE");
              }
              else
              {
                  szValue = _T("FALSE");
              }
              break;
  
          case RID_IsSrc0LumaKey          :
          case RID_IsSrc1LumaKey          :
          case RID_SetSrc0LumaKey         :
          case RID_SetSrc1LumaKey         :
          case RID_IsSrc1SamplerLumaKey   :
          case RID_SetSrc1SamplerLumaKey  :
              if (pEntry->value == LumaKey_Source)
              {
                  szValue = _T("Current Layer");
              }
              else if (pEntry->value)
              {
                  szValue = _T("TRUE");
              }
              else
              {
                  szValue = _T("FALSE");
              }
              break;
  
          case RID_IsSrc0Procamp    :
          case RID_IsSrc1Procamp    :
          case RID_SetSrc0Procamp   :
          case RID_SetSrc1Procamp   :
              if (pEntry->value == Procamp_Source)
              {
                  szValue = _T("Current Layer");
              }
              else if (pEntry->value == DL_PROCAMP_DISABLED)
              {
                  szValue = _T("FALSE");
              }
              else
              {
                  szValue = _T("TRUE");
              }
              break;
  
          case RID_IsSrc0Chromasiting :
          case RID_IsSrc1Chromasiting :
              if (pEntry->value == DL_CHROMASITING_DISABLE)
              {
                  szValue = _T("FALSE");
              }
              else
              {
                  szValue = _T("TRUE");
              }
              break;
  
          case RID_SetKernel:
              if (pCache && (pEntry->value < pCache->iCacheEntries))
              {
                  szValue = pCache->pCacheEntries[pEntry->value].szName;
              }
              else
              {
                  _stprintf(data, _T("%d"), pEntry->value);
                  szValue = data;
              }
              break;
  
          case RID_SetNextLayer:
              if (pEntry->value == 0)
              {
                  szValue = _T("Next Layer");
              }
              else if (pEntry->value == -1)
              {
                  szValue = _T("Previous Layer");
              }
              else if (pEntry->value == 2)
              {
                  szValue = _T("Target Layer");
              }
              else if (pEntry->value == -2)
              {
                  szValue = _T("Main Layer");
              }
              break;
  
          case RID_SetPatch          :
              _stprintf(data, _T("%d patch entries"), pEntry->value);
              increment += pEntry->value;
              szValue = data;
              break;
  
          case RID_IsLayerFormat     :
          case RID_IsSrc0Format      :
          case RID_IsSrc1Format      :
          case RID_SetSrc0Format     :
          case RID_SetSrc1Format     :
          case RID_IsTargetFormat    :
              szValue = KernelDll_GetFormatString((MOS_FORMAT  ) pEntry->value);
              break;
  
          case RID_IsTargetCspace    :
          case RID_SetTargetCspace   :
              szValue = KernelDll_GetCSpaceString((VPHAL_CSPACE) pEntry->value);
              break;
  
          case RID_IsSrc0Sampling    :
          case RID_IsSrc1Sampling    :
          case RID_SetSrc0Sampling   :
          case RID_SetSrc1Sampling   :
              szValue = KernelDll_GetSamplingString((Kdll_Sampling) pEntry->value);
              break;
  
          case RID_IsSrc0Rotation   :
              szValue = KernelDll_GetRotationString((VPHAL_ROTATION) pEntry->value);
              break;
  
          case RID_IsShuffling       :
              szValue = KernelDll_GetShuffleString((Kdll_Shuffling) pEntry->value);
              break;
  
          case RID_IsSrc0Coeff       :
          case RID_IsSrc1Coeff       :
          case RID_SetSrc0Coeff      :
          case RID_SetSrc1Coeff      :
              szValue = KernelDll_GetCoeffIDString((Kdll_CoeffID) pEntry->value);
              break;
  
          case RID_IsSrc1Processing  :
          case RID_SetSrc1Processing :
              szValue = KernelDll_GetProcessString((Kdll_Processing) pEntry->value);
              break;
  
          case RID_IsCSCBeforeMix    :
          case RID_SetCSCBeforeMix   :
              if (pEntry->value)
              {
                  szValue = _T("TRUE");
              }
              else
              {
                  szValue = _T("FALSE");
              }
              break;
  
          case RID_Is64BSaveEnabled  :
              if (pEntry->value)
              {
                  szValue = _T("TRUE");
              }
              else
              {
                  szValue = _T("FALSE");
              }
              break;
  
          default:
              break;
      }
  
      if (szRID && szValue)
      {
          _sntprintf(szOut, iSize, _T("%-22s %s"), szRID, szValue);
      }
      else if (szRID)
      {
          _sntprintf(szOut, iSize, _T("%-22s"), szRID);
      }
  
      return increment;
  }
  
  #ifndef VPHAL_LIB
  #pragma warning( pop )
  #endif // !VPHAL_LIB
  
  #endif // _DEBUG || EMUL || VPHAL_LIB
  
  /*----------------------------------------------------------------------------
  | Name      : KernelDll_IsSameFormatType
  | Purpose   : Check if 2 formats are similar
  |
  | Input     : Internal Format
  |
  | Return    : FourCC format
  \---------------------------------------------------------------------------*/
  bool KernelDll_IsSameFormatType(MOS_FORMAT   format1, MOS_FORMAT   format2)
  {
      int32_t group1, group2;
  
      switch (format1)
      {
          CASE_PA_FORMAT:
              group1 = 1;
              break;
  
          CASE_PL2_FORMAT:
              group1 = 2;
              break;
  
          CASE_PL3_FORMAT:
              group1 = 3;
              break;
  
          CASE_RGB_FORMAT:
              group1 = 4;
              break;
  
          default:
              group1 = 0;
              break;
      }
  
      switch (format2)
      {
          CASE_PA_FORMAT:
              group2 = 1;
              break;
  
          CASE_PL2_FORMAT:
              group2 = 2;
              break;
  
          CASE_PL3_FORMAT:
              group2 = 3;
              break;
  
          CASE_RGB_FORMAT:
              group2 = 4;
              break;
  
          default:
              group2 = 0;
              break;
      }
  
      if (group1 == group2)
      {
          return true;
      }
      else
      {
          return false;
      }
  }
  
  bool KernelDll_IsYUVFormat(MOS_FORMAT   format)
  {
      if (format >= Format_Any && format < Format_Count)
      {
          return g_cIsFormatYUV[format];
      }
      else
      {
          return false;
      }
  }
  
  bool KernelDll_IsCspace(VPHAL_CSPACE cspace, VPHAL_CSPACE match)
  {
      switch (match)
      {
          case CSpace_RGB:
              return (cspace == CSpace_sRGB            ||
                      cspace == CSpace_stRGB);
  
          case CSpace_YUV:
              return (cspace == CSpace_BT709           ||
                      cspace == CSpace_BT601           ||
                      cspace == CSpace_BT601_FullRange ||
                      cspace == CSpace_BT709_FullRange ||
                      cspace == CSpace_xvYCC709        ||
                      cspace == CSpace_xvYCC601);
  
          case CSpace_Gray:
              return (cspace == CSpace_BT601Gray       ||
                      cspace == CSpace_BT601Gray_FullRange);
  
          case CSpace_Any:
              return (cspace != CSpace_None);
  
          case CSpace_BT2020:
              return (cspace == CSpace_BT2020    ||
                      cspace == CSpace_BT2020_FullRange);
  
          case CSpace_BT2020_RGB:
              return (cspace == CSpace_BT2020_RGB ||
                      cspace == CSpace_BT2020_stRGB);
  
          default:
              return (cspace == match);
      }
  
      return false;
  }
  
  bool KernelDll_IsFormat(
      MOS_FORMAT      format,
      VPHAL_CSPACE    cspace,
      MOS_FORMAT      match)
  {
      switch (match)
      {
          case Format_Any:
              return (format != Format_None);
              break;
  
          case Format_RGB_Swap:
              return (IS_RGB_SWAP(format));
  
          case Format_RGB_No_Swap:
              return (IS_RGB_NO_SWAP(format));
  
          case Format_RGB:
              if (IS_PAL_FORMAT(format))
              {
                  return (KernelDll_IsCspace(cspace, CSpace_RGB));
              }
              else
              {
                  return (IS_RGB_FORMAT(format) && !IS_PL3_RGB_FORMAT(format));
              }
  
          case Format_RGB32:
              return (IS_RGB32_FORMAT(format));
  
          case Format_PA:
              if (IS_PAL_FORMAT(format))
              {
                  return (KernelDll_IsCspace(cspace, CSpace_YUV));
              }
              else
              {
                  return (IS_PA_FORMAT(format) ||
                          format == Format_AUYV);
              }
  
          case Format_PL2:
              return (IS_PL2_FORMAT(format));
  
          case Format_PL2_UnAligned:
              return (IS_PL2_FORMAT_UnAligned(format));
  
          case Format_PL3:
              return (IS_PL3_FORMAT(format));
  
          case Format_PL3_RGB:
              return (IS_PL3_RGB_FORMAT(format));
  
          case Format_AYUV:
              return (format == Format_AYUV);
  
          case Format_PAL:
              return (IS_PAL_FORMAT(format));
  
          default:
              return (format == match);
      }
  
      return false;
  }
  
  /*----------------------------------------------------------------------------
  | Purpose   : Group common color spaces into one
  | Returns   : Return the representative color space of the group
  \---------------------------------------------------------------------------*/
  VPHAL_CSPACE KernelDll_TranslateCspace(VPHAL_CSPACE cspace)
  {
      switch (cspace)
      {
          case CSpace_BT709:
          case CSpace_xvYCC709:
              return CSpace_BT709;
  
          case CSpace_BT601:
          case CSpace_xvYCC601:
              return CSpace_BT601;
  
          case CSpace_BT601_FullRange:
              return CSpace_BT601_FullRange;
  
          case CSpace_BT709_FullRange:
              return CSpace_BT709_FullRange;
  
          case CSpace_RGB:
          case CSpace_sRGB:
              return CSpace_sRGB;
  
          case CSpace_stRGB:
              return CSpace_stRGB;
  
          case CSpace_Gray:
          case CSpace_BT601Gray:
              return CSpace_BT601Gray;
  
          case CSpace_BT601Gray_FullRange:
              return CSpace_BT601Gray_FullRange;
  
          case CSpace_BT2020:
              return CSpace_BT2020;
  
          case CSpace_BT2020_FullRange:
              return CSpace_BT2020_FullRange;
  
          case CSpace_BT2020_RGB:
              return CSpace_BT2020_RGB;
  
          case CSpace_BT2020_stRGB:
              return CSpace_BT2020_stRGB;
  
          default:
              return CSpace_None;
      }
  }
  
  /*----------------------------------------------------------------------------
  | Name      : KernelDll_GetYuvRangeAndOffset
  | Purpose   : Get the YUV offset and excursion for the input color space
  | Return    : true if success else false
  \---------------------------------------------------------------------------*/
  bool KernelDll_GetYuvRangeAndOffset(
      Kdll_CSpace cspace,
      float       *pLumaOffset,
      float       *pLumaExcursion,
      float       *pChromaZero,
      float       *pChromaExcursion)
  {
      bool res = true;
  
      switch (cspace)
      {
          case CSpace_BT601_FullRange:
          case CSpace_BT709_FullRange:
          case CSpace_BT601Gray_FullRange:
          case CSpace_BT2020_FullRange:
              *pLumaOffset      =   0.0f;
              *pLumaExcursion   = 255.0f;
              *pChromaZero      = 128.0f;
              *pChromaExcursion = 255.0f;
              break;
  
          case CSpace_BT601:
          case CSpace_BT709:
          case CSpace_xvYCC601: // since matrix is the same as 601, use the same range
          case CSpace_xvYCC709: // since matrix is the same as 709, use the same range
          case CSpace_BT601Gray:
          case CSpace_BT2020:
              *pLumaOffset      =  16.0f;
              *pLumaExcursion   = 219.0f;
              *pChromaZero      = 128.0f;
              *pChromaExcursion = 224.0f;
              break;
  
          default:
              res = false;
              break;
      }
  
      return res;
  }
  
  /*----------------------------------------------------------------------------
  | Name      : KernelDll_GetRgbRangeAndOffset
  | Purpose   : Get the RGB offset and excursion for the input color space
  | Return    : true if success else false
  \---------------------------------------------------------------------------*/
  bool KernelDll_GetRgbRangeAndOffset(
      Kdll_CSpace cspace,
      float       *pRgbOffset,
      float       *pRgbExcursion)
  {
      bool res = true;
  
      switch (cspace)
      {
          case CSpace_sRGB:
          case CSpace_BT2020_RGB:
              *pRgbOffset    =   0.0f;
              *pRgbExcursion = 255.0f;
              break;
  
          case CSpace_stRGB:
          case CSpace_BT2020_stRGB:
              *pRgbOffset    =  16.0f;
              *pRgbExcursion = 219.0f;
              break;
  
          default:
              res = false;
              break;
      }
  
      return res;
  }
  
  /*----------------------------------------------------------------------------
  | Name      : KernelDll_CalcYuvToRgbMatrix
  | Purpose   : Given the YUV->RGB transfer matrix, get the final matrix after
  |             applying offsets and excursions.
  |
  | [R']     [R_o]                                 [R_e/Y_e    0       0   ]  [Y'  - Y_o]
  | [G']  =  [R_o] + [YUVtoRGBCoeff (3x3 matrix)]. [   0    R_e/C_e    0   ]. [Cb' - C_z]
  | [B']     [R_o]                                 [   0       0    R_e/C_e]. [Cr' - C_z]
  |
  | [R']  = [C0  C1   C2] [Y' ]   [C3]      {Out pMatrix}
  | [G']  = [C4  C5   C6].[Cb'] + [C7]
  | [B']  = [C8  C9  C10] [Cr'] + [C11]
  |
  | Return    : true if success else false
  \---------------------------------------------------------------------------*/
  bool KernelDll_CalcYuvToRgbMatrix(
      Kdll_CSpace     src,                        // [in] YUV Color space
      Kdll_CSpace     dst,                        // [in] RGB Color space
      float           *pTransferMatrix,             // [in] Transfer matrix (3x3)
      float           *pOutMatrix)                  // [out] Conversion matrix (3x4)
  {
      bool    res;
      float   Y_o, Y_e, C_z, C_e;
      float   R_o, R_e;
  
      res = true;
  
      res = KernelDll_GetRgbRangeAndOffset(dst, &R_o, &R_e);
      if (res == false)
      {
          goto finish;
      }
  
      res = KernelDll_GetYuvRangeAndOffset(src, &Y_o, &Y_e, &C_z, &C_e);
      if (res == false)
      {
          goto finish;
      }
  
      // after + (3x3)(3x3)
      pOutMatrix[0]  = pTransferMatrix[0] * R_e / Y_e;
      pOutMatrix[4]  = pTransferMatrix[3] * R_e / Y_e;
      pOutMatrix[8]  = pTransferMatrix[6] * R_e / Y_e;
      pOutMatrix[1]  = pTransferMatrix[1] * R_e / C_e;
      pOutMatrix[5]  = pTransferMatrix[4] * R_e / C_e;
      pOutMatrix[9]  = pTransferMatrix[7] * R_e / C_e;
      pOutMatrix[2]  = pTransferMatrix[2] * R_e / C_e;
      pOutMatrix[6]  = pTransferMatrix[5] * R_e / C_e;
      pOutMatrix[10] = pTransferMatrix[8] * R_e / C_e;
  
      // (3x1) - (3x3)(3x3)(3x1)
      pOutMatrix[3]  = R_o - (pOutMatrix[0] * Y_o + pOutMatrix[1] * C_z + pOutMatrix[2]  * C_z);
      pOutMatrix[7]  = R_o - (pOutMatrix[4] * Y_o + pOutMatrix[5] * C_z + pOutMatrix[6]  * C_z);
      pOutMatrix[11] = R_o - (pOutMatrix[8] * Y_o + pOutMatrix[9] * C_z + pOutMatrix[10] * C_z);
  
  finish:
      return res;
  }
  
  /*----------------------------------------------------------------------------
  | Name      : KernelDll_CalcRgbToYuvMatrix
  | Purpose   : Given the RGB->YUV transfer matrix, get the final matrix after
  |             applying offsets and excursions.
  |
  | [Y' ]     [Y_o - Y_e.R_o/R_e]   [Y_e/R_e    0       0   ]  [   RGB to YUV  ]  [R']
  | [Cb']  =  [C_z]               + [   0    C_e/R_e    0   ]. [Transfer matrix]. [G']
  | [Cr']     [C_z]                 [   0       0    C_e/R_e]  [   3x3 matrix  ]  [B']
  |
  | [Y' ]  = [C0  C1   C2] [R']   [C3]      {Out pMatrix}
  | [Cb']  = [C4  C5   C6].[G'] + [C7]
  | [Cr']  = [C8  C9  C10] [B'] + [C11]
  |
  | Return    : true if success else false
  \---------------------------------------------------------------------------*/
  bool KernelDll_CalcRgbToYuvMatrix(
      Kdll_CSpace     src,                        // [in] RGB Color space
      Kdll_CSpace     dst,                        // [in] YUV Color space
      float           *pTransferMatrix,             // [in] Transfer matrix (3x3)
      float           *pOutMatrix)                  // [out] Conversion matrix (3x4)
  {
      bool    res;
      float   Y_o, Y_e, C_z, C_e;
      float   R_o, R_e;
  
      res = true;
  
      res = KernelDll_GetRgbRangeAndOffset(src, &R_o, &R_e);
      if (res == false)
      {
          goto finish;
      }
  
      res = KernelDll_GetYuvRangeAndOffset(dst, &Y_o, &Y_e, &C_z, &C_e);
      if (res == false)
      {
          goto finish;
      }
  
      // multiplication of + onwards
      pOutMatrix[0]  = pTransferMatrix[0] * Y_e / R_e;
      pOutMatrix[1]  = pTransferMatrix[1] * Y_e / R_e;
      pOutMatrix[2]  = pTransferMatrix[2] * Y_e / R_e;
      pOutMatrix[4]  = pTransferMatrix[3] * C_e / R_e;
      pOutMatrix[5]  = pTransferMatrix[4] * C_e / R_e;
      pOutMatrix[6]  = pTransferMatrix[5] * C_e / R_e;
      pOutMatrix[8]  = pTransferMatrix[6] * C_e / R_e;
      pOutMatrix[9]  = pTransferMatrix[7] * C_e / R_e;
      pOutMatrix[10] = pTransferMatrix[8] * C_e / R_e;
  
      // before +
      pOutMatrix[3]  = Y_o - Y_e * R_o / R_e;
      pOutMatrix[7]  = C_z;
      pOutMatrix[11] = C_z;
  
  finish:
      return res;
  }
  
  /*----------------------------------------------------------------------------
  | Name      : KernelDll_CalcGrayCoeffs
  | Purpose   : Given CSC matrix, calculate the new matrix making Chroma zero.
  |             Chroma will be read from the surface, but we need to factor in C_z
  |             by adjusting this in the constant.
  |
  | [R']  = [C0  C1   C2] [Y' ]   [C3]      {Out pMatrix}
  | [G']  = [C4  C5   C6].[C_z] + [C7]
  | [B']  = [C8  C9  C10] [C_z]   [C11]
  |
  | New C3 = C1 * C_z + C2 * C_z + C3
  |
  | Return    : true if success else false
  \---------------------------------------------------------------------------*/
  bool KernelDll_CalcGrayCoeffs(
      Kdll_CSpace     src,                       // [in] YUV source Color space
      float           *pMatrix)                   // [in/out] Conversion matrix (3x4)
  {
      float   Y_o, Y_e, C_z, C_e;
      bool    res;
  
      res = true;
  
      res = KernelDll_GetYuvRangeAndOffset(src, &Y_o, &Y_e, &C_z, &C_e);
      if (res == false)
      {
          goto finish;
      }
  
      // Calculate the constant offset by factoring in C_z
      pMatrix[3]  = pMatrix[1] * C_z + pMatrix[2]  * C_z + pMatrix[3];
      pMatrix[7]  = pMatrix[5] * C_z + pMatrix[6]  * C_z + pMatrix[7];
      pMatrix[11] = pMatrix[9] * C_z + pMatrix[10] * C_z + pMatrix[11];
  
      // Nullify the effect of chroma read
      pMatrix[1] = pMatrix[2]  = 0;
      pMatrix[5] = pMatrix[6]  = 0;
      pMatrix[9] = pMatrix[10] = 0;
  
  finish:
      return res;
  }
  
  /*----------------------------------------------------------------------------
  | Name      : KernelDll_3x3MatrixProduct
  | Purpose   : Given two [3x4] input matrices, calculate [3x3]x[3x3] ignoring
  |             the last column in both inputs
  | Return    : none
  \---------------------------------------------------------------------------*/
  void KernelDll_3x3MatrixProduct(
      float       *dest,
      const float *m1,
      const float *m2)
  {
      dest[ 0] = m1[0] * m2[0] + m1[1] * m2[4] + m1[ 2] * m2[ 8];
      dest[ 1] = m1[0] * m2[1] + m1[1] * m2[5] + m1[ 2] * m2[ 9];
      dest[ 2] = m1[0] * m2[2] + m1[1] * m2[6] + m1[ 2] * m2[10];
  
      dest[ 4] = m1[4] * m2[0] + m1[5] * m2[4] + m1[ 6] * m2[ 8];
      dest[ 5] = m1[4] * m2[1] + m1[5] * m2[5] + m1[ 6] * m2[ 9];
      dest[ 6] = m1[4] * m2[2] + m1[5] * m2[6] + m1[ 6] * m2[10];
  
      dest[ 8] = m1[8] * m2[0] + m1[9] * m2[4] + m1[10] * m2[ 8];
      dest[ 9] = m1[8] * m2[1] + m1[9] * m2[5] + m1[10] * m2[ 9];
      dest[10] = m1[8] * m2[2] + m1[9] * m2[6] + m1[10] * m2[10];
  }
  
  /*----------------------------------------------------------------------------
  | Name      : KernelDll_CalcYuvToYuvMatrix
  | Purpose   : Calculate the matrix equation for converting b/w YUV color spaces.
  |             1. Get conversion matrix from Source YUV to sRGB
  |             2. Get conversion matrix from sRGB to Destination YUV
  |             3. Apply the transformation below to get the final matrix
  |
  | [Y'dst]  = [C0  C1   C2] [C0  C1   C2][Y'src] [C0  C1   C2] [C3]    [C3]
  | [U']     = [C4  C5   C6].[C4  C5   C6][C_z] + [C4  C5   C6].[C7]  + [C7]
  | [V']     = [C8  C9  C10] [C8  C9  C10][C_z]   [C8  C9  C10] [C11]   [C11]
  |             dst matrix    src matrix           dst matrix    src     dst
  |
  | [Y'dst]  = [C0  C1   C2] [Y'src]   [C3]      {Out pMatrix}
  | [U']     = [C4  C5   C6].[C_z] +   [C7]
  | [V']     = [C8  C9  C10] [C_z]     [C11]
  |
  | Return    : true if success else false
  \---------------------------------------------------------------------------*/
  bool KernelDll_CalcYuvToYuvMatrix(
      Kdll_CSpace     src,                        // [in] RGB Color space
      Kdll_CSpace     dst,                        // [in] YUV Color space
      float           *pOutMatrix)                 // [out] Conversion matrix (3x4)
  {
      float   fYuvToRgb[12]  = {0};
      float   fRgbToYuv[12]  = {0};
      bool    res;
  
      res = true;
  
      // 1. Get conversion matrix from Source YUV to sRGB
      if (IS_BT601_CSPACE(src))
      {
          res = KernelDll_CalcYuvToRgbMatrix(src, CSpace_sRGB, (float *) g_cCSC_BT601_YUV_RGB, fYuvToRgb);
      }
      else
      {
          res = KernelDll_CalcYuvToRgbMatrix(src, CSpace_sRGB, (float *) g_cCSC_BT709_YUV_RGB, fYuvToRgb);
      }
      if (res == false)
      {
          goto finish;
      }
  
      // 2. Get conversion matrix from sRGB to Destination YUV
      if (IS_BT601_CSPACE(dst))
      {
          res = KernelDll_CalcRgbToYuvMatrix(CSpace_sRGB, dst, (float *) g_cCSC_BT601_RGB_YUV, fRgbToYuv);
      }
      else
      {
          res = KernelDll_CalcRgbToYuvMatrix(CSpace_sRGB, dst, (float *) g_cCSC_BT709_RGB_YUV, fRgbToYuv);
      }
      if (res == false)
      {
          goto finish;
      }
  
      // 3. Multiply the 2 matrices above
      KernelDll_3x3MatrixProduct(pOutMatrix, fRgbToYuv, fYuvToRgb);
  
      // Perform [3x3][3x1] matrix multiply + [3x1] matrix
      pOutMatrix[3]  = fRgbToYuv[0] * fYuvToRgb[3]  + fRgbToYuv[1] * fYuvToRgb[7] +
                       fRgbToYuv[2] * fYuvToRgb[11] +                fRgbToYuv[3];
      pOutMatrix[7]  = fRgbToYuv[4] * fYuvToRgb[3]  + fRgbToYuv[5] * fYuvToRgb[7] +
                       fRgbToYuv[6] * fYuvToRgb[11] +                fRgbToYuv[7];
      pOutMatrix[11] = fRgbToYuv[8] * fYuvToRgb[3]  + fRgbToYuv[9] * fYuvToRgb[7] +
                       fRgbToYuv[10]* fYuvToRgb[11] +                fRgbToYuv[11];
  
  finish:
      return res;
  }
  
  /*----------------------------------------------------------------------------
  | Name      : KernelDll_GetCSCMatrix
  | Purpose   : Get the required matrix for the given CSC conversion
  | Return    :
  \---------------------------------------------------------------------------*/
  void KernelDll_GetCSCMatrix(
      Kdll_CSpace     src,                        // [in] Source Color space
      Kdll_CSpace     dst,                        // [in] Destination Color space
      float           *pCSC_Matrix)                // [out] CSC matrix to use
  {
      bool        bMatrix;
      bool        bSrcGray;
      Kdll_CSpace temp;
      int32_t     i;
  
      bMatrix  = false;
      bSrcGray = KernelDll_IsCspace(src, CSpace_Gray);
  
      // convert gray color spaces to its equivalent non-gray cpsace
      switch(src)
      {
          case CSpace_BT601Gray:
              temp = CSpace_BT601;
              break;
          case CSpace_BT601Gray_FullRange:
              temp = CSpace_BT601_FullRange;
              break;
          default:
              temp = src;
              break;
      }
  
      // BT601/709 YUV to sRGB/stRGB conversion
      if (KernelDll_IsCspace(temp, CSpace_YUV) || KernelDll_IsCspace(temp, CSpace_Gray))
      {
          if(KernelDll_IsCspace(dst, CSpace_RGB))
          {
              if (IS_BT601_CSPACE(temp))
              {
                  KernelDll_CalcYuvToRgbMatrix(temp, dst, (float *) g_cCSC_BT601_YUV_RGB, pCSC_Matrix);
                  bMatrix = true;
              }
              else // if (IS_BT709_CSPACE(temp))
              {
                  KernelDll_CalcYuvToRgbMatrix(temp, dst, (float *) g_cCSC_BT709_YUV_RGB, pCSC_Matrix);
                  bMatrix = true;
              }
          }
      }
      // sRGB/stRGB to BT601/709 YUV conversion
      else if (KernelDll_IsCspace(temp, CSpace_RGB))
      {
          if (KernelDll_IsCspace(dst, CSpace_YUV))
          {
              if (IS_BT601_CSPACE(dst))
              {
                  KernelDll_CalcRgbToYuvMatrix(temp, dst, (float *) g_cCSC_BT601_RGB_YUV, pCSC_Matrix);
                  bMatrix = true;
              }
              else // if (IS_BT709_CSPACE(temp))
              {
                  KernelDll_CalcRgbToYuvMatrix(temp, dst, (float *) g_cCSC_BT709_RGB_YUV, pCSC_Matrix);
                  bMatrix = true;
              }
          }
      }
      // BT2020 YUV to RGB conversion
      else if (KernelDll_IsCspace(temp, CSpace_BT2020))
      {
          if (KernelDll_IsCspace(dst, CSpace_BT2020_RGB))
          {
              KernelDll_CalcYuvToRgbMatrix(temp, dst, (float *)g_cCSC_BT2020_YUV_RGB, pCSC_Matrix);
              bMatrix = true;
          }
      }
      // BT2020 RGB to YUV conversion
      else if (KernelDll_IsCspace(temp, CSpace_BT2020_RGB))
      {
          if (KernelDll_IsCspace(dst, CSpace_BT2020))
          {
              KernelDll_CalcRgbToYuvMatrix(temp, dst, (float *)g_cCSC_BT2020_RGB_YUV, pCSC_Matrix);
              bMatrix = true;
          }
      }
  
      // If matrix has not been derived yet, its one of the below special cases
      if (!bMatrix)
      {
          if (temp == dst) // Check if its identity matrix
          {
              MOS_SecureMemcpy(pCSC_Matrix, sizeof(g_cCSC_Identity), (void *)g_cCSC_Identity, sizeof(g_cCSC_Identity));
          }
          else if (KernelDll_IsCspace(temp, CSpace_RGB)) // sRGB to stRGB inter-conversions
          {
              if (temp == CSpace_sRGB)
              {
                  MOS_SecureMemcpy(pCSC_Matrix, sizeof(g_cCSC_sRGB_stRGB), (void *)g_cCSC_sRGB_stRGB, sizeof(g_cCSC_sRGB_stRGB));
              }
              else //temp == CSpace_stRGB
              {
                  MOS_SecureMemcpy(pCSC_Matrix, sizeof(g_cCSC_stRGB_sRGB), (void *)g_cCSC_stRGB_sRGB, sizeof(g_cCSC_stRGB_sRGB));
              }
          }
          else if (KernelDll_IsCspace(temp, CSpace_YUV)) // 601 to 709 inter-conversions
          {
              KernelDll_CalcYuvToYuvMatrix(temp, dst, pCSC_Matrix);
          }
          else
          {
              VPHAL_RENDER_ASSERTMESSAGE("Not supported color space conversion(from %d to %d)", src, dst);
          }
      }
  
      // Calculate the Gray transformation matrix now
      if (bSrcGray)
      {
          KernelDll_CalcGrayCoeffs(src, pCSC_Matrix);
      }
  
      VPHAL_RENDER_NORMALMESSAGE("");
      for(i = 0; i < 3; i++)
      {
          VPHAL_RENDER_NORMALMESSAGE("%f\t%f\t%f\t%f",
                              pCSC_Matrix[4 * i],
                              pCSC_Matrix[4 * i + 1],
                              pCSC_Matrix[4 * i + 2],
                              pCSC_Matrix[4 * i + 3]);
      }
  }
  
  void KernelDll_MatrixProduct(
      float       *dest,
      const float *m1,
      const float *m2)
  {
      bool  save;
      float temp[12];
  
      // setup temp matrix to allow the following operations:
      //   dest = dest * m2
      //   dest = m1 * dest
      //   dest = dest * dest
      save = (m1 == dest) || (m2 == dest);
      m1   = (m1 == dest) ? temp : m1;
      m2   = (m2 == dest) ? temp : m2;
      if (save) MOS_SecureMemcpy(temp, sizeof(temp), (void *)dest, sizeof(temp));
  
      // Multiply the matrices
      dest[ 0] = m1[0] * m2[0] + m1[1] * m2[4] + m1[ 2] * m2[ 8];
      dest[ 1] = m1[0] * m2[1] + m1[1] * m2[5] + m1[ 2] * m2[ 9];
      dest[ 2] = m1[0] * m2[2] + m1[1] * m2[6] + m1[ 2] * m2[10];
      dest[ 3] = m1[0] * m2[3] + m1[1] * m2[7] + m1[ 2] * m2[11] + m1[3];
      dest[ 4] = m1[4] * m2[0] + m1[5] * m2[4] + m1[ 6] * m2[ 8];
      dest[ 5] = m1[4] * m2[1] + m1[5] * m2[5] + m1[ 6] * m2[ 9];
      dest[ 6] = m1[4] * m2[2] + m1[5] * m2[6] + m1[ 6] * m2[10];
      dest[ 7] = m1[4] * m2[3] + m1[5] * m2[7] + m1[ 6] * m2[11] + m1[7];
      dest[ 8] = m1[8] * m2[0] + m1[9] * m2[4] + m1[10] * m2[ 8];
      dest[ 9] = m1[8] * m2[1] + m1[9] * m2[5] + m1[10] * m2[ 9];
      dest[10] = m1[8] * m2[2] + m1[9] * m2[6] + m1[10] * m2[10];
      dest[11] = m1[8] * m2[3] + m1[9] * m2[7] + m1[10] * m2[11] + m1[11];
  }
  
  bool KernelDll_MapCSCMatrix(
                              Kdll_CSCType    csctype,
                              const float    *matrix,
                              short          *coeff)
  {
      // Unified kernel architecture requires that the color space
      // conversion coefficients programmed in specific orders, depends on the
      // type of the color space conversion.
      //
      // M (matrix)  ---> C (coeff)
  
      switch (csctype)
      {
          case CSC_YUV_RGB:
              // direct mapping from matrix to coeff
              coeff[ 0] = FLOAT_TO_SHORT(matrix[0] );      // M0  --> C0
              coeff[ 1] = FLOAT_TO_SHORT(matrix[1] );      // M1  --> C1
              coeff[ 2] = FLOAT_TO_SHORT(matrix[2] );      // M2  --> C2
              coeff[ 3] = FLOAT_TO_SHORT(matrix[3] );      // M3  --> C3
              coeff[ 4] = FLOAT_TO_SHORT(matrix[4] );      // M4  --> C4
              coeff[ 5] = FLOAT_TO_SHORT(matrix[5] );      // M5  --> C5
              coeff[ 6] = FLOAT_TO_SHORT(matrix[6] );      // M6  --> C6
              coeff[ 7] = FLOAT_TO_SHORT(matrix[7] );      // M7  --> C7
              coeff[ 8] = FLOAT_TO_SHORT(matrix[8] );      // M8  --> C8
              coeff[ 9] = FLOAT_TO_SHORT(matrix[9] );      // M9  --> C9
              coeff[10] = FLOAT_TO_SHORT(matrix[10]);      // M10 --> C10
              coeff[11] = FLOAT_TO_SHORT(matrix[11]);      // M11 --> C11
              break;
  
          case CSC_RGB_YUV:
              coeff[ 6] = FLOAT_TO_SHORT(matrix[0] );      // M0   --> C6
              coeff[ 4] = FLOAT_TO_SHORT(matrix[1] );      // M1   --> C4
              coeff[ 5] = FLOAT_TO_SHORT(matrix[2] );      // M2   --> C5
              coeff[ 7] = FLOAT_TO_SHORT(matrix[3] );      // M3   --> C7
              coeff[10] = FLOAT_TO_SHORT(matrix[4] );      // M4   --> C10
              coeff[ 8] = FLOAT_TO_SHORT(matrix[5] );      // M5   --> C8
              coeff[ 9] = FLOAT_TO_SHORT(matrix[6] );      // M6   --> C9
              coeff[11] = FLOAT_TO_SHORT(matrix[7] );      // M7   --> C11
              coeff[ 2] = FLOAT_TO_SHORT(matrix[8] );      // M8   --> C2
              coeff[ 0] = FLOAT_TO_SHORT(matrix[9] );      // M9   --> C0
              coeff[ 1] = FLOAT_TO_SHORT(matrix[10]);      // M10  --> C1
              coeff[ 3] = FLOAT_TO_SHORT(matrix[11]);      // M11  --> C3
              break;
  
          case CSC_YUV_YUV:
              coeff[ 4] = FLOAT_TO_SHORT(matrix[0] );      // M0   --> C4
              coeff[ 5] = FLOAT_TO_SHORT(matrix[1] );      // M1   --> C5
              coeff[ 6] = FLOAT_TO_SHORT(matrix[2] );      // M2   --> C6
              coeff[ 7] = FLOAT_TO_SHORT(matrix[3] );      // M3   --> C7
              coeff[ 8] = FLOAT_TO_SHORT(matrix[4] );      // M4   --> C8
              coeff[ 9] = FLOAT_TO_SHORT(matrix[5] );      // M5   --> C9
              coeff[10] = FLOAT_TO_SHORT(matrix[6] );      // M6   --> C10
              coeff[11] = FLOAT_TO_SHORT(matrix[7] );      // M7   --> C11
              coeff[ 0] = FLOAT_TO_SHORT(matrix[8] );      // M8   --> C0
              coeff[ 1] = FLOAT_TO_SHORT(matrix[9] );      // M9   --> C1
              coeff[ 2] = FLOAT_TO_SHORT(matrix[10]);      // M10  --> C2
              coeff[ 3] = FLOAT_TO_SHORT(matrix[11]);      // M11  --> C3
              break;
  
          default:
              //CSC_RGB_RGB
              coeff[ 2] = FLOAT_TO_SHORT(matrix[0] );      // M0   --> C2
              coeff[ 0] = FLOAT_TO_SHORT(matrix[1] );      // M1   --> C0
              coeff[ 1] = FLOAT_TO_SHORT(matrix[2] );      // M2   --> C1
              coeff[ 3] = FLOAT_TO_SHORT(matrix[3] );      // M3   --> C3
              coeff[ 6] = FLOAT_TO_SHORT(matrix[4] );      // M4   --> C6
              coeff[ 4] = FLOAT_TO_SHORT(matrix[5] );      // M5   --> C4
              coeff[ 5] = FLOAT_TO_SHORT(matrix[6] );      // M6   --> C5
              coeff[ 7] = FLOAT_TO_SHORT(matrix[7] );      // M7   --> C7
              coeff[10] = FLOAT_TO_SHORT(matrix[8] );      // M8   --> C10
              coeff[ 8] = FLOAT_TO_SHORT(matrix[9] );      // M9   --> C8
              coeff[ 9] = FLOAT_TO_SHORT(matrix[10]);      // M10  --> C9
              coeff[11] = FLOAT_TO_SHORT(matrix[11]);      // M11  --> C11
              break;
      }
  
      return true;
  }
  
  void KernelDll_UpdateCscCoefficients(Kdll_State      *pState,
                                       Kdll_CSC_Matrix *pMatrix)
  {
      float csc[12];    // CSC  matrix (YUV->RGB)
      float icsc[12];   // ICSC matrix (RGB->YUV), (YUV->YUV)
      float m[12];      // auxiliary matrix
      float matrix[12];    // final matrix
      Kdll_CSCType csctype;
      Kdll_Procamp *pProcamp = nullptr;
      VPHAL_CSPACE  src = pMatrix->SrcSpace;
      VPHAL_CSPACE  dst = pMatrix->DstSpace;
      bool bCSC, bICSC;
  
      bCSC = bICSC = false;
      MOS_ZeroMemory(m, sizeof(m));
      MOS_ZeroMemory(csc, sizeof(csc));
      MOS_ZeroMemory(icsc, sizeof(icsc));
  
      // Select procamp parameters
      if (pMatrix->iProcampID > DL_PROCAMP_DISABLED &&
          pMatrix->iProcampID < pState->iProcampSize &&
          pState->pProcamp != nullptr)
      {
          pProcamp = pState->pProcamp + pMatrix->iProcampID;
      }
  
      // Setup CSC matrix
      if (src != dst)
      {
          if ((dst == CSpace_sRGB) && (src != CSpace_stRGB))
          {
              KernelDll_GetCSCMatrix(src, dst, csc);
              MOS_SecureMemcpy(m, sizeof(csc), (void *)csc, sizeof(csc));
              bCSC = true;
              csctype = CSC_YUV_RGB;
          }
          else if ((dst == CSpace_stRGB) && (src != CSpace_sRGB))
          {
              KernelDll_GetCSCMatrix(src, dst, csc);
              MOS_SecureMemcpy(m, sizeof(csc), (void *)csc, sizeof(csc));
              bCSC = true;
              csctype = CSC_YUV_RGB;
          }
          else
          {
              KernelDll_GetCSCMatrix(src, dst, icsc);
              MOS_SecureMemcpy(m, sizeof(icsc), (void *)icsc, sizeof(icsc));
              bICSC = true;
              if (KernelDll_IsCspace(src, CSpace_RGB) && !KernelDll_IsCspace(dst, CSpace_RGB))
              {
                  csctype = CSC_RGB_YUV;
              }
              else if (KernelDll_IsCspace(src, CSpace_BT2020_RGB) && KernelDll_IsCspace(dst, CSpace_BT2020))
              {
                  csctype = CSC_RGB_YUV;
              }
              else if (KernelDll_IsCspace(src, CSpace_BT2020) && KernelDll_IsCspace(dst, CSpace_BT2020_RGB))
              {
                  csctype = CSC_YUV_RGB;
              }
              else
              {
                  csctype = CSC_YUV_YUV;
              }
          }
      }
      // Setup CSC matrix for procamp in sRGB space
      else if ((dst == CSpace_sRGB) && (pProcamp))
      {
          KernelDll_GetCSCMatrix(CSpace_sRGB, CSpace_BT709, icsc);
          KernelDll_GetCSCMatrix(CSpace_BT709, CSpace_sRGB, csc);
          bICSC = bCSC = true;
          csctype = CSC_RGB_RGB;
      }
      // Setup CSC matrix for procamp in stRGB space
      else if ((dst == CSpace_stRGB) && (pProcamp))
      {
          KernelDll_GetCSCMatrix(CSpace_stRGB, CSpace_BT709, icsc);
          KernelDll_GetCSCMatrix(CSpace_BT709, CSpace_stRGB, csc);
          bICSC = bCSC = true;
          csctype = CSC_RGB_RGB;
      }
      else
      {
          MOS_SecureMemcpy(m, sizeof(g_cCSC_Identity), (void *)g_cCSC_Identity, sizeof(g_cCSC_Identity));
          csctype = CSC_YUV_YUV;
      }
  
      // Product only happens if Procamp is present
      // Otherwise use the original matrix
      if (pProcamp)
      {
          float b,c,h,s;
  
          // Calculate procamp parameters
          b = pProcamp->fBrightness;
          c = pProcamp->fContrast;
          h = pProcamp->fHue * (PI / 180.0f);
          s = pProcamp->fSaturation;
  
          // procamp matrix
          //
          // [Y']   [ c            0          0  ] [Y]   [ 16  - 16 * c + b              ]
          // [U'] = [ 0   c*s*cos(h)  c*s*sin(h) ] [U] + [ 128 - 128*c*s*(cos(h)+sin(h)) ]
          // [V']   [ 0  -c*s*sin(h)  c*s*cos(h) ] [V]   [ 128 - 128*c*s*(cos(h)-sin(h)) ]
  
          matrix[0]  = c;
          matrix[1]  = 0.0f;
          matrix[2]  = 0.0f;
          matrix[3]  = 16.0f - 16.0f * c + b;
          matrix[4]  = 0.0f;
          matrix[5]  = (float)cos(h) * c * s;
          matrix[6]  = (float)sin(h) * c * s;
          matrix[7]  = 128.0f * (1.0f - matrix[5] - matrix[6]);
          matrix[8]  = 0.0f;
          matrix[9]  = -matrix[6];
          matrix[10] =  matrix[5];
          matrix[11] = 128.0f * (1.0f - matrix[5] + matrix[6]);
  
          // Calculate final CSC matrix (csc * pa * icsc)
          if (bICSC)
          {   // Calculate [pa] * [icsc]
              KernelDll_MatrixProduct(matrix, matrix, icsc);
          }
  
          if (bCSC)
          {   // Calculate [csc] * [pa]     (if no icsc)
              //        or [csc] * [pa] * [icsc]
              KernelDll_MatrixProduct(matrix, csc, matrix);
          }
  
          // Update procamp version
          pMatrix->iProcampVersion = pProcamp->iProcampVersion;
  
          // Use the output matrix to generate kernel CSC parameters
          MOS_SecureMemcpy(m, sizeof(m), (void *)matrix, sizeof(m));
      }
  
      // normalize for kernel use
      matrix[0]  = ROUND_FLOAT(m[ 0], 128.0f);  // 9.7
      matrix[1]  = ROUND_FLOAT(m[ 1], 128.0f);  // 9.7
      matrix[2]  = ROUND_FLOAT(m[ 2], 128.0f);  // 9.7
      matrix[3]  = ROUND_FLOAT(m[ 3],   0.5f);  // 16.0 (value/2)
      matrix[4]  = ROUND_FLOAT(m[ 4], 128.0f);  // 9.7
      matrix[5]  = ROUND_FLOAT(m[ 5], 128.0f);  // 9.7
      matrix[6]  = ROUND_FLOAT(m[ 6], 128.0f);  // 9.7
      matrix[7]  = ROUND_FLOAT(m[ 7],   0.5f);  // 16.0 (value/2)
      matrix[8]  = ROUND_FLOAT(m[ 8], 128.0f);  // 9.7
      matrix[9]  = ROUND_FLOAT(m[ 9], 128.0f);  // 9.7
      matrix[10] = ROUND_FLOAT(m[10], 128.0f);  // 9.7
      matrix[11] = ROUND_FLOAT(m[11],   0.5f);  // 16.0 (value/2)
  
      // Save matrix as kernel CSC coefficients
      pState->pfnMapCSCMatrix(csctype, matrix, pMatrix->Coeff);
  }
  
  /*----------------------------------------------------------------------------
  | Name      : KernelDll_FindRule
  | Purpose   : Find a rule that matches the current search/input state
  |
  | Input     : pState       - Kernel Dll state
  |             pSearchState - current DL search state
  |
  | Return    :
  \---------------------------------------------------------------------------*/
  bool KernelDll_FindRule(
      Kdll_State       *pState,
      Kdll_SearchState *pSearchState)
  {
      uint32_t parser_state = (uint32_t)pSearchState->state;
      Kdll_RuleEntrySet    *pRuleSet;
      const Kdll_RuleEntry *pRuleEntry;
      int32_t              iRuleCount;
      int32_t              iMatchCount;
      bool                 bLayerFormatMatched;
      bool                 bSrc0FormatMatched;
      bool                 bSrc1FormatMatched;
      bool                 bTargetFormatMatched;
      bool                 bSrc0SampingMatched;
  
      VPHAL_RENDER_FUNCTION_ENTER;
  
      // All Custom states are handled as a single group
      if (parser_state >= Parser_Custom)
      {
          parser_state = Parser_Custom;
      }
  
      pRuleSet   = pState->pDllRuleTable[parser_state];
      iRuleCount = pState->iDllRuleCount[parser_state];
  
      if (pRuleSet == nullptr || iRuleCount == 0)
      {
          VPHAL_RENDER_NORMALMESSAGE("Search rules undefined.");
          pSearchState->pMatchingRuleSet = nullptr;
          return false;
      }
  
      // Search matching entry
      for ( ; iRuleCount > 0; iRuleCount--, pRuleSet++)
      {
          // Points to the first rule, get number of matches
          pRuleEntry  = pRuleSet->pRuleEntry;
          iMatchCount = pRuleSet->iMatchCount;
  
          // Initialize for each Ruleset
          bLayerFormatMatched  = false;
          bSrc0FormatMatched   = false;
          bSrc1FormatMatched   = false;
          bTargetFormatMatched = false;
          bSrc0SampingMatched  = false;
  
          // Match all rules within the same RuleSet
          for (; iMatchCount > 0; iMatchCount--, pRuleEntry++)
          {
              switch (pRuleEntry->id)
              {
                  // Match current Parser State
                  case RID_IsParserState:
                      if (pSearchState->state == (Kdll_ParserState) pRuleEntry->value)
                      {
                          continue;
                      }
                      else
                      {
                          break;
                      }
  
                  // Match render method
                  case RID_IsRenderMethod:
                      if (pSearchState->pFilter->RenderMethod == (Kdll_RenderMethod)pRuleEntry->value)
                      {
                          continue;
                      }
                      else
                      {
                          break;
                      }
  
                  // Match target color space
                  case RID_IsTargetCspace:
                      if (KernelDll_IsCspace(pSearchState->cspace, (VPHAL_CSPACE) pRuleEntry->value))
                      {
                          continue;
                      }
                      else
                      {
                          break;
                      }
  
                  // Match current layer ID
                  case RID_IsLayerID:
                      if (pSearchState->pFilter->layer == (Kdll_Layer) pRuleEntry->value)
                      {
                          continue;
                      }
                      else
                      {
                          break;
                      }
  
                  // Match current layer format
                  case RID_IsLayerFormat:
                      if (pRuleEntry->logic == Kdll_Or && bLayerFormatMatched)
                      {
                          // Already found matching format in the ruleset
                          continue;
                      }
                      else
                      {
                          // Check if the layer format matches the rule
                          if (KernelDll_IsFormat(pSearchState->pFilter->format,
                                                  pSearchState->pFilter->cspace,
                                                  (MOS_FORMAT  ) pRuleEntry->value))
                          {
                              bLayerFormatMatched = true;
                          }
  
                          if (pRuleEntry->logic == Kdll_None && !bLayerFormatMatched)
                          {
                              // Last entry and No matching format was found
                              break;
                          }
                          else
                          {
                              continue;
                          }
                      }
  
                  // Match shuffling requirement
                  case RID_IsShuffling:
                      if (pSearchState->ShuffleSamplerData == (Kdll_Shuffling) pRuleEntry->value)
                      {
                          continue;
                      }
                      else
                      {
                          break;
                      }
  
                  // Check if RT rotates
                  case RID_IsRTRotate:
                      if (pSearchState->bRTRotate == (pRuleEntry->value ? true : false) )
                      {
                          continue;
                      }
                      else
                      {
                          break;
                      }
  
                  // Match current layer rotation
                  case RID_IsLayerRotation:
                      if (pSearchState->pFilter->rotation == (VPHAL_ROTATION) pRuleEntry->value)
                      {
                          continue;
                      }
                      else
                      {
                          break;
                      }
  
                  // Match Src0 source format (surface)
                  case RID_IsSrc0Format:
                      if (pRuleEntry->logic == Kdll_Or && bSrc0FormatMatched)
                      {
                          // Already found matching format in the ruleset
                          continue;
                      }
                      else
                      {
                          // Check if the source 0 format matches the rule
                          // The intermediate colorspace is used to determine
                          // if palettized input is given in RGB or YUV format.
                          if (KernelDll_IsFormat(pSearchState->src0_format,
                                                  pSearchState->cspace,
                                                  (MOS_FORMAT  ) pRuleEntry->value))
                          {
                              bSrc0FormatMatched = true;
                          }
  
                          if (pRuleEntry->logic == Kdll_None && !bSrc0FormatMatched)
                          {
                              // Last entry and No matching format was found
                              break;
                          }
                          else
                          {
                              continue;
                          }
                      }
  
                  // Match Src0 sampling mode
                  case RID_IsSrc0Sampling:
                      // Check if the layer format matches the rule
                      if (pSearchState->src0_sampling == (Kdll_Sampling) pRuleEntry->value)
                      {
                          bSrc0SampingMatched = true;
                          continue;
                      }
                      else if (bSrc0SampingMatched || pRuleEntry->logic == Kdll_Or)
                      {
                          continue;
                      }
                      else if ((Kdll_Sampling) pRuleEntry->value == Sample_Any &&
                              pSearchState->src0_sampling != Sample_None)
                      {
                          continue;
                      }
                      else
                      {
                          break;
                      }
  
                  // Match Src0 rotation
                  case RID_IsSrc0Rotation:
                      if (pSearchState->src0_rotation == (VPHAL_ROTATION) pRuleEntry->value)
                      {
                          continue;
                      }
                      else
                      {
                          break;
                      }
  
                  // Match Src0 Colorfill
                  case RID_IsSrc0ColorFill:
                      if (pSearchState->src0_colorfill == (int32_t)pRuleEntry->value)
                      {
                          continue;
                      }
                      else
                      {
                          break;
                      }
  
                  // Match Src0 Luma Key
                  case RID_IsSrc0LumaKey:
                      if (pSearchState->src0_lumakey == (int32_t)pRuleEntry->value)
                      {
                          continue;
                      }
                      else
                      {
                          break;
                      }
  
                  // Match Src0 Procamp
                  case RID_IsSrc0Procamp:
                      if (pSearchState->pFilter->procamp == (int32_t)pRuleEntry->value)
                      {
                          continue;
                      }
                      else
                      {
                          break;
                      }
  
                  // Match Src0 CSC coefficients
                  case RID_IsSrc0Coeff:
                      if (pSearchState->src0_coeff == (Kdll_CoeffID) pRuleEntry->value)
                      {
                          continue;
                      }
                      else if ((Kdll_CoeffID) pRuleEntry->value == CoeffID_Any &&
                              pSearchState->src0_coeff != CoeffID_None)
                      {
                          continue;
                      }
                      else
                      {
                          break;
                      }
  
                  // Match Src0 CSC coefficients setting mode
                  case RID_IsSetCoeffMode:
                      if (pSearchState->pFilter->SetCSCCoeffMode == (Kdll_SetCSCCoeffMethod) pRuleEntry->value)
                      {
                          continue;
                      }
                      else
                      {
                          break;
                      }
  
                  // Match Src0 processing mode
                  case RID_IsSrc0Processing:
                      if (pSearchState->src0_process == (Kdll_Processing) pRuleEntry->value)
                      {
                          continue;
                      }
                      if ((Kdll_Processing) pRuleEntry->value == Process_Any &&
                          pSearchState->src0_process != Process_None)
                      {
                          continue;
                      }
                      else
                      {
                          break;
                      }
  
                  // Match Src0 chromasiting mode
                  case RID_IsSrc0Chromasiting:
                      if (pSearchState->Filter->chromasiting == (int32_t)pRuleEntry->value)
                      {
                          continue;
                      }
                      else
                      {
                          break;
                      }
  
                  // Match Src1 source format (surface)
                  case RID_IsSrc1Format:
                      if (pRuleEntry->logic == Kdll_Or && bSrc1FormatMatched)
                      {
                          // Already found matching format in the ruleset
                          continue;
                      }
                      else
                      {
                          // Check if the source 1 format matches the rule
                          // The intermediate colorspace is used to determine
                          // if palettized input is given in RGB or YUV format.
                          if (KernelDll_IsFormat(pSearchState->src1_format,
                                                  pSearchState->cspace,
                                                  (MOS_FORMAT) pRuleEntry->value))
                          {
                              bSrc1FormatMatched = true;
                          }
  
                          if (pRuleEntry->logic == Kdll_None && !bSrc1FormatMatched)
                          {
                              // Last entry and No matching format was found
                              break;
                          }
                          else
                          {
                              continue;
                          }
                      }
                  // Match Src1 sampling mode
                  case RID_IsSrc1Sampling:
                      if (pSearchState->src1_sampling == (Kdll_Sampling) pRuleEntry->value)
                      {
                          continue;
                      }
                      else if ((Kdll_Sampling) pRuleEntry->value == Sample_Any &&
                              pSearchState->src1_sampling != Sample_None)
                      {
                          continue;
                      }
                      else
                      {
                          break;
                      }
  
                  // Match Src1 Luma Key
                  case RID_IsSrc1LumaKey:
                      if (pSearchState->src1_lumakey == (int32_t)pRuleEntry->value)
                      {
                          continue;
                      }
                      else
                      {
                          break;
                      }
                      
                  // Match Src1 Sampler LumaKey
                  case RID_IsSrc1SamplerLumaKey:
                      if (pSearchState->src1_samplerlumakey == (int32_t)pRuleEntry->value)
                      {
                          continue;
                      }
                      else
                      {
                          break;
                      }
  
                  // Match Src1 Procamp
                  case RID_IsSrc1Procamp:
                      if (pSearchState->pFilter->procamp == (int32_t)pRuleEntry->value)
                      {
                          continue;
                      }
                      else
                      {
                          break;
                      }
  
                  // Match Src1 CSC coefficients
                  case RID_IsSrc1Coeff:
                      if (pSearchState->src1_coeff == (Kdll_CoeffID) pRuleEntry->value)
                      {
                          continue;
                      }
                      else if ((Kdll_CoeffID) pRuleEntry->value == CoeffID_Any &&
                              pSearchState->src1_coeff != CoeffID_None)
                      {
                          continue;
                      }
                      else
                      {
                          break;
                      }
  
                  // Match Src1 processing mode
                  case RID_IsSrc1Processing:
                      if (pSearchState->src1_process == (Kdll_Processing) pRuleEntry->value)
                      {
                          continue;
                      }
                      if ((Kdll_Processing) pRuleEntry->value == Process_Any &&
                          pSearchState->src1_process != Process_None)
                      {
                          continue;
                      }
                      else
                      {
                          break;
                      }
  
                  // Match Src1 chromasiting mode
                  case RID_IsSrc1Chromasiting:
                      //pSearchState->pFilter is pointed to the real sub layer
                      if (pSearchState->pFilter->chromasiting == (int32_t)pRuleEntry->value)
                      {
                          continue;
                      }
                      else
                      {
                          break;
                      }
  
                  // Match Layer number
                  case RID_IsLayerNumber:
                      if (pSearchState->layer_number == (int32_t) pRuleEntry->value)
                      {
                          continue;
                      }
                      else
                      {
                          break;
                      }
  
                  // Match quadrant
                  case RID_IsQuadrant:
                      if (pSearchState->quadrant == (int32_t) pRuleEntry->value)
                      {
                          continue;
                      }
                      else
                      {
                          break;
                      }
  
                  // Set CSC flag before Mix
                  case RID_IsCSCBeforeMix:
                      if (pSearchState->bCscBeforeMix == (pRuleEntry->value ? true : false))
                      {
                          continue;
                      }
                      else
                      {
                          break;
                      }
  
                  case RID_IsDualOutput:
                      if (pSearchState->pFilter->dualout == (pRuleEntry->value ? true : false))
                      {
                          continue;
                      }
                      else
                      {
                          break;
                      }
  
                  case RID_IsTargetFormat:
                      if (pRuleEntry->logic == Kdll_Or && bTargetFormatMatched)
                      {
                          // Already found matching format in the ruleset
                          continue;
                      }
                      else
                      {
                          if (pSearchState->target_format == (MOS_FORMAT) pRuleEntry->value)
                          {
                              bTargetFormatMatched = true;
                          }
  
                          if (pRuleEntry->logic == Kdll_None && !bTargetFormatMatched)
                          {
                              // Last entry and No matching format was found
                              break;
                          }
                          else
                          {
                              continue;
                          }
                      }
  
                  case RID_Is64BSaveEnabled:
                      if (pSearchState->b64BSaveEnabled == (pRuleEntry->value ? true : false))
                      {
                          continue;
                      }
                      else
                      {
                          break;
                      }
  
                  case RID_IsTargetTileType:
                      if (pRuleEntry->logic == Kdll_None &&
                          pSearchState->target_tiletype == (MOS_TILE_TYPE) pRuleEntry->value)
                      {
                          continue;
                      }
                      else if (pRuleEntry->logic == Kdll_Not &&
                               pSearchState->target_tiletype != (MOS_TILE_TYPE) pRuleEntry->value)
                      {
                          continue;
                      }
                      else
                      {
                          break;
                      }
  
                  case RID_IsProcampEnabled:
                      if (pSearchState->bProcamp == (pRuleEntry->value ? true : false))
                      {
                          continue;
                      }
                      else
                      {
                          break;
                      }
  
                  case RID_IsConstOutAlpha:
                      if (pSearchState->pFilter->bFillOutputAlphaWithConstant == (pRuleEntry->value ? true : false))
                      {
                          continue;
                      }
                      else
                      {
                          break;
                      }
  
                  case RID_IsDitherNeeded:
                      if (pSearchState->pFilter->bIsDitherNeeded == (pRuleEntry->value ? true : false))
                      {
                          continue;
                      }
                      else
                      {
                          break;
                      }
                  // Undefined search rule will fail
                  default:
                      VPHAL_RENDER_ASSERTMESSAGE("Invalid rule %d @ layer %d, state %d.", pRuleEntry->id, pSearchState->layer_number, pSearchState->state);
                      break;
              }  // End of switch to deal with all matching rule IDs
  
              // Rule didn't match - try another RuleSet
              break;
          } // End of file loop to test all rules for the current RuleSet
  
          // Match
          if (iMatchCount == 0)
          {
              pSearchState->pMatchingRuleSet = pRuleSet;
              return true;
          }
      }   // End of for loop to test all RuleSets for the current parser state
  
      // Failed to find a matching rule -> kernel search will fail
      VPHAL_RENDER_NORMALMESSAGE("Fail to find a matching rule @ layer %d, state %d.", pSearchState->layer_number, pSearchState->state);
  
      // No match -> return
      pSearchState->pMatchingRuleSet = nullptr;
      return false;
  }
  
  /*----------------------------------------------------------------------------
  | Name      : KernelDll_GetPatchData
  | Purpose   : Get binary data block to be used for kernel patching
  |
  | Input     : pState       - [in]  Current DL state
  |             pSearchState - [in]  Current DL search state
  |             iPatchKind   - [in]  Patch kind
  |             pSize        - [out] Data block Size
  |
  | Return    : nullptr - Unsupported patch data kind
  |             <>nullptr - Pointer to data block
  \---------------------------------------------------------------------------*/
  static uint8_t *KernelDll_GetPatchData(
      Kdll_State          *pState,
      Kdll_SearchState    *pSearchState,
      int32_t             iPatchKind,
      int32_t             *pSize)
  {
      MOS_UNUSED(pState);
  
      VPHAL_RENDER_FUNCTION_ENTER;
  
      if (iPatchKind == PatchKind_CSC_Coeff_Src0 ||
          iPatchKind == PatchKind_CSC_Coeff_Src1)
      {
          Kdll_CoeffID  coeffID  = CoeffID_None;
          uint8_t       matrixID = DL_CSC_DISABLED;
  
          // Get matrix id
          if (iPatchKind == PatchKind_CSC_Coeff_Src0)
          {
              coeffID = pSearchState->src0_coeff;
          }
          else
          {
              coeffID = pSearchState->src1_coeff;
          }
  
          // Get matrix associated with the coefficient ID
          if (coeffID > CoeffID_None)
          {
              matrixID = pSearchState->CscParams.MatrixID[coeffID];
          }
  
          // Found matrix
          if (matrixID < DL_CSC_MAX)
          {
              Kdll_CSC_Matrix *pMatrix = &(pSearchState->CscParams.Matrix[matrixID]);
  
              *pSize = 12 * sizeof(uint16_t);
  
              if (pState->bEnableCMFC)
              {
                  if (pSearchState->CscParams.PatchMatrixNum < DL_CSC_MAX)
                  {
                      pSearchState->CscParams.PatchMatrixID[pSearchState->CscParams.PatchMatrixNum] = matrixID;
                      pSearchState->CscParams.PatchMatrixNum ++;
                  }
                  else
                  {
                      VPHAL_RENDER_NORMALMESSAGE("Patch CSC coefficient exceed limitation");
                  }
              }
  
              return ((uint8_t *)pMatrix->Coeff);
          }
      }
      else
      {
          VPHAL_RENDER_NORMALMESSAGE("Invalid patch kind %d.", iPatchKind);
      }
  
      return nullptr;
  }
  
  /*----------------------------------------------------------------------------
  | Name      : KernelDll_UpdateState
  | Purpose   : Update search state using current matching rule
  |
  | Input     : pState       - Kernel Dll state
  |             pSearchState - current DL search state
  |
  | Return    :
  \---------------------------------------------------------------------------*/
  bool KernelDll_UpdateState(
      Kdll_State       *pState,
      Kdll_SearchState *pSearchState)
  {
      Kdll_RuleEntrySet    *pRuleSet   = pSearchState->pMatchingRuleSet;
      const Kdll_RuleEntry *pRuleEntry;
      int32_t               iSetCount;
  
      VPHAL_RENDER_FUNCTION_ENTER;
  
      // Ensures that we have a matching rule
      if (pRuleSet == nullptr)
      {
          return false;
      }
  
      // Get rule entry and number of state update ("Set") rules; validate
      pRuleEntry = pRuleSet->pRuleEntry;
      iSetCount  = pRuleSet->iSetCount;
      if (pRuleEntry == nullptr || iSetCount < 1)
      {
          VPHAL_RENDER_NORMALMESSAGE("Invalid rule set.");
          return false;
      }
  
      // Jump to set rules (skip match rules)
      pRuleEntry += pRuleSet->iMatchCount;
  
      // Apply state update rules
      for (; iSetCount > 0; iSetCount--, pRuleEntry++)
      {
          switch (pRuleEntry->id)
          {
              // Add kernel to the Dynamic Linking array
              case RID_SetKernel:
                  if (pSearchState->KernelCount < DL_MAX_KERNELS)
                  {
                      int32_t i = pSearchState->KernelCount++;
                      pSearchState->KernelID [i] = pRuleEntry->value;
                      pSearchState->KernelGrp[i] = pRuleSet->iGroup;  // Group associated with the kernel ID
                  }
                  else
                  {
                      VPHAL_RENDER_ASSERTMESSAGE("reached maximum number of component kernels.");
                      return false;
                  }
                  break;
  
              // Set Parser State
              case RID_SetParserState:
                  pSearchState->state = (Kdll_ParserState) pRuleEntry->value;
                  break;
  
              // Move to Next/Prev Layer
              case RID_SetNextLayer:
                  if (pRuleEntry->value == -1)
                  {
                      pSearchState->layer_number--;
                      pSearchState->pFilter--;
                  }
                  else if (pRuleEntry->value == -2) // jump to layer main video
                  {
                     do
                     {
                          pSearchState->layer_number--;
                          pSearchState->pFilter--;
                          if (pSearchState->pFilter == nullptr || pSearchState->layer_number < 0 )
                          {
                               return false;
                          }
                      }
                      while (pSearchState->pFilter->layer != Layer_MainVideo);
                  }
                  else if (pRuleEntry->value == 2) // jump to target layer
                  {
                      while (pSearchState->pFilter->layer < Layer_RenderTarget )
                      {
                          pSearchState->layer_number++;
                          pSearchState->pFilter++;
                      }
                  }
                  else
                  {
                      pSearchState->layer_number++;
                      pSearchState->pFilter++;
                  }
                  break;
  
              // Set patch data
              case RID_SetPatchData:
                  {
                      uint8_t *pData = nullptr;
                      int32_t iSize = 0;
                      int32_t iKernelIndex = pSearchState->KernelCount - 1;
                      int32_t iPatchIndex;
                      Kdll_PatchData *pPatch;
  
                      // Get block of data for patching
                      pData = KernelDll_GetPatchData(pState, pSearchState, (Kdll_PatchKind)pRuleEntry->value, &iSize);
                      if (pData == nullptr || iSize == 0)
                      {
                          VPHAL_RENDER_ASSERTMESSAGE("invalid patch.");
                          return false;
                      }
  
                      // Append to the existing patch data block
                      iPatchIndex = pSearchState->PatchID[iKernelIndex];
  
                      // Allocate new patch structure
                      if (iPatchIndex < 0)
                      {
                          // Fail to allocate
                          if (pSearchState->PatchCount >= DL_MAX_PATCHES)
                          {
                              VPHAL_RENDER_ASSERTMESSAGE("reached maximum number of patches.");
                              return false;
                          }
  
                          // Get new patch block
                          iPatchIndex = pSearchState->PatchCount++;
                          pSearchState->PatchID[iKernelIndex] = iPatchIndex;
  
                          // Reset new patch entry
                          pPatch = &(pSearchState->Patches[iPatchIndex]);
                          MOS_ZeroMemory(pPatch, sizeof(Kdll_PatchData));
                      }
                      else
                      {
                          // Get Patch entry already in use
                          pPatch = &(pSearchState->Patches[iPatchIndex]);
                      }
  
                      // Check if data can be appended
                      if (pPatch->iPatchDataSize + iSize > DL_MAX_PATCH_DATA_SIZE)
                      {
                          VPHAL_RENDER_ASSERTMESSAGE("exceeded maximum patch size.");
                          return false;
                      }
  
                      // Append patch data
                      MOS_SecureMemcpy(pPatch->Data + pPatch->iPatchDataSize, iSize, (void *)pData, iSize);
                      pPatch->iPatchDataSize += iSize;
                  }
                  break;
  
              // Set patch operation
              case RID_SetPatch:
                  {
                      int32_t iKernelIndex = pSearchState->KernelCount - 1;
                      int32_t iPatchIndex  = pSearchState->PatchID[iKernelIndex];
                      Kdll_PatchData      *pPatch;
                      uint8_t             *pPatchRule;
                      Kdll_PatchBlock     *pPatchBlock;
                      int32_t              nPatches;
  
                      // No patch associated with the current kernel
                      if (iPatchIndex < 0)
                      {
                          return false;
                      }
  
                      // Get Patch entry
                      pPatch = &(pSearchState->Patches[iPatchIndex]);
  
                      // Get number of patches and pointer to first rule extension (patch rule)
                      nPatches   = pRuleEntry->value;
                      pPatchRule = (uint8_t*) (pRuleEntry + 1);
  
                      // Check if rules can be applied
                      if (nPatches + pPatch->nPatches > DL_MAX_PATCH_BLOCKS)
                      {
                          VPHAL_RENDER_ASSERTMESSAGE("exceeded number of patch blocks.");
                          return false;
                      }
  
                      // Set Patches
                      pPatchBlock = &(pPatch->Patch[pPatch->nPatches]);
                      for (; nPatches > 0; nPatches--, pPatchBlock++, pPatch->nPatches++)
                      {
                          pPatchBlock->BlockSize = ((Kdll_PatchRuleEntry *)pPatchRule)->Size;
                          pPatchBlock->SrcOffset = ((Kdll_PatchRuleEntry *)pPatchRule)->Source;
                          pPatchBlock->DstOffset = ((Kdll_PatchRuleEntry *)pPatchRule)->Dest;
                          pPatchRule += sizeof(Kdll_RuleEntry);
                      }
  
                      // Skip rule extensions
                      iSetCount  -= pRuleEntry->value;
                      pRuleEntry += pRuleEntry->value;
                  }
                  break;
  
              // Set destination colorspace
              case RID_SetTargetCspace:
                  if ((VPHAL_CSPACE)pRuleEntry->value == CSpace_Source)
                  {
                      pSearchState->cspace = pSearchState->pFilter->cspace;
                  }
                  else
                  {
                      pSearchState->cspace = (VPHAL_CSPACE)pRuleEntry->value;
                  }
                  break;
  
              // Set Src0 source format
              case RID_SetSrc0Format:
                  if ((MOS_FORMAT  )pRuleEntry->value == Format_Source)
                  {
                      pSearchState->src0_format = pSearchState->pFilter->format;
                  }
                  else
                  {
                      pSearchState->src0_format = (MOS_FORMAT  ) pRuleEntry->value;
                  }
                  break;
  
              // Set Src0 sampling mode
              case RID_SetSrc0Sampling:
                  if ((Kdll_Sampling)pRuleEntry->value == Sample_Source)
                  {
                      pSearchState->src0_sampling = pSearchState->pFilter->sampler;
                  }
                  else
                  {
                      pSearchState->src0_sampling = (Kdll_Sampling) pRuleEntry->value;
                  }
                  break;
  
              // Set Src0 Rotation
              case RID_SetSrc0Rotation:
                  pSearchState->src0_rotation = pSearchState->pFilter->rotation;
                  break;
  
              // Set Src0 Colorfill
              case RID_SetSrc0ColorFill:
                  if ((int32_t)pRuleEntry->value == ColorFill_Source)
                  {
                      pSearchState->src0_colorfill = pSearchState->pFilter->colorfill;
                  }
                  else
                  {
                      pSearchState->src0_colorfill = (int32_t)pRuleEntry->value;
                  }
                  break;
  
              // Set Src0 luma key
              case RID_SetSrc0LumaKey:
                  if (pRuleEntry->value == LumaKey_Source)
                  {
                      pSearchState->src0_lumakey = pSearchState->pFilter->lumakey;
                  }
                  else
                  {
                      pSearchState->src0_lumakey = (int32_t)pRuleEntry->value;
                  }
                  break;
  
              // Set Src0 Procamp
              case RID_SetSrc0Procamp:
                  if (pRuleEntry->value == Procamp_Source)
                  {
                      pSearchState->src0_procamp = pSearchState->pFilter->procamp;
                  }
                  else
                  {
                      pSearchState->src0_procamp = (int32_t)pRuleEntry->value;
                  }
                  break;
  
              // Set Src0 CSC coefficients
              case RID_SetSrc0Coeff:
                  if ((Kdll_CoeffID)pRuleEntry->value == CoeffID_Source)
                  {
                      if (pSearchState->pFilter->matrix == DL_CSC_DISABLED)
                      {
                          pSearchState->src0_coeff = CoeffID_None;
                      }
                      else
                      {
                          Kdll_CSC_Matrix *matrix = pSearchState->CscParams.Matrix;
                          matrix += pSearchState->pFilter->matrix;
  
                          pSearchState->src0_coeff = matrix->iCoeffID;
                      }
                  }
                  else
                  {
                      pSearchState->src0_coeff = (Kdll_CoeffID) pRuleEntry->value;
                  }
                  break;
  
              case RID_SetSrc0Processing:
                  if ((Kdll_Processing)pRuleEntry->value == Process_Source)
                  {
                      pSearchState->src0_process = pSearchState->pFilter->process;
                  }
                  else
                  {
                      pSearchState->src0_process = (Kdll_Processing) pRuleEntry->value;
                  }
                  break;
  
              // Set Src1 source format
              case RID_SetSrc1Format:
                  if ((MOS_FORMAT  )pRuleEntry->value == Format_Source)
                  {
                      pSearchState->src1_format = pSearchState->pFilter->format;
                  }
                  else
                  {
                      pSearchState->src1_format = (MOS_FORMAT  ) pRuleEntry->value;
                  }
                  break;
  
              // Set Src1 sampling mode
              case RID_SetSrc1Sampling:
                  if ((Kdll_Sampling)pRuleEntry->value == Sample_Source)
                  {
                      pSearchState->src1_sampling = pSearchState->pFilter->sampler;
                  }
                  else
                  {
                      pSearchState->src1_sampling = (Kdll_Sampling) pRuleEntry->value;
                  }
                  break;
  
              // Set Src1 Rotation
              case RID_SetSrc1Rotation:
                  pSearchState->src1_rotation = pSearchState->pFilter->rotation;
                  break;
  
              // Set Src1 luma key
              case RID_SetSrc1LumaKey:
                  if (pRuleEntry->value == LumaKey_Source)
                  {
                      pSearchState->src1_lumakey = pSearchState->pFilter->lumakey;
                  }
                  else
                  {
                      pSearchState->src1_lumakey = (int32_t)pRuleEntry->value;
                  }
                  break;
  
              // Set Src1 Sampler LumaKey
              case RID_SetSrc1SamplerLumaKey:
                  if (pRuleEntry->value == LumaKey_Source)
                  {
                      pSearchState->src1_samplerlumakey = pSearchState->pFilter->samplerlumakey;
                  }
                  else
                  {
                      pSearchState->src1_samplerlumakey = (int32_t)pRuleEntry->value;
                  }
                  break;
  
              // Set Src1 Procamp
              case RID_SetSrc1Procamp:
                  if (pRuleEntry->value == Procamp_Source)
                  {
                      pSearchState->src1_procamp = pSearchState->pFilter->procamp;
                  }
                  else
                  {
                      pSearchState->src1_procamp = (int32_t)pRuleEntry->value;
                  }
                  break;
  
              // Set Src1 CSC coefficients
              case RID_SetSrc1Coeff:
                  if ((Kdll_CoeffID)pRuleEntry->value == CoeffID_Source)
                  {
                      if (pSearchState->pFilter->matrix == DL_CSC_DISABLED)
                      {
                          pSearchState->src1_coeff = CoeffID_None;
                      }
                      else
                      {
                          Kdll_CSC_Matrix *matrix = pSearchState->CscParams.Matrix;
                          matrix += pSearchState->pFilter->matrix;
  
                          pSearchState->src1_coeff = matrix->iCoeffID;
                      }
                  }
                  else
                  {
                      pSearchState->src1_coeff = (Kdll_CoeffID) pRuleEntry->value;
                  }
                  break;
  
              // Set Src1 processing mode
              case RID_SetSrc1Processing:
                  if ((Kdll_Processing)pRuleEntry->value == Process_Source)
                  {
                      pSearchState->src1_process = pSearchState->pFilter->process;
                  }
                  else
                  {
                      pSearchState->src1_process = (Kdll_Processing) pRuleEntry->value;
                  }
                  break;
  
              // Set current quadrant
              case RID_SetQuadrant:
                  pSearchState->quadrant = (int32_t) pRuleEntry->value;
                  break;
  
              // Set CSC flag before Mix
              case RID_SetCSCBeforeMix:
                  pSearchState->bCscBeforeMix = pRuleEntry->value ? true : false;
                  break;
  
              // Unsupported "Set" rule
              default:
                  // Failed to find a matching rule -> kernel search will fail
                  VPHAL_RENDER_ASSERTMESSAGE("Invalid rule %d @ layer %d, state %d.", pRuleEntry->id, pSearchState->layer_number, pSearchState->state);
                  return false;
          }
      }
  
      // Reset matching rule
      pSearchState->pMatchingRuleSet = nullptr;
      return true;
  }
  
  //-----------------------------------------------------------------------------------------
  // KernelDll_SortRuleTable - Sort master dynamic linking rule table
  //
  // Parameters:
  //    char  *pState    - [in] Kernel Dll state
  //
  // Output: true  - Master rule table (and acceleration table) successfully created
  //         false - Failed to setup master rule table
  //-----------------------------------------------------------------------------------------
  bool KernelDll_SortRuleTable(Kdll_State *pState)
  {
      uint8_t group;
      int32_t state;
      const Kdll_RuleEntry *pRule = nullptr;
      Kdll_RuleEntrySet    *pRuleSet;
      int32_t i, j;
  
      int32_t iTotal = 0;
      int32_t iNoOverr[Parser_Count];    // Non-overridable (enforced) rules
      int32_t iDefault[Parser_Count];    // Default rules
      int32_t iCustom [Parser_Count];    // Custom rules
  
      VPHAL_RENDER_FUNCTION_ENTER;
  
      // Release previous table (rule table update)
      if (pState->pSortedRules)
      {
          MOS_FreeMemory(pState->pSortedRules);
          pState->pSortedRules = nullptr;
  
          MOS_ZeroMemory(pState->pDllRuleTable, sizeof(pState->pDllRuleTable));
          MOS_ZeroMemory(pState->iDllRuleCount, sizeof(pState->iDllRuleCount));
      }
  
      // Zero counters
      MOS_ZeroMemory(iNoOverr, sizeof(iNoOverr));
      MOS_ZeroMemory(iDefault, sizeof(iDefault));
      MOS_ZeroMemory(iCustom , sizeof(iCustom));
  
      // Count number of entries for each state
      for (i = 0; i < 2; i++)
      {
          if (i == 0)
          {
              pRule = pState->pRuleTableDefault;
          }
          else if (i == 1)
          {
              pRule = pState->pRuleTableCustom;
          }
  
          // Table not set - continue
          if (!pRule) continue;
  
          for (; pRule->id != RID_Op_EOF; pRule++)
          {
              // Skip extended rules (variable lenght)
              if (RID_IS_EXTENDED(pRule->id))
              {   // value contains number of entries
                  pRule += pRule->value;
              }
              else if (pRule->id == RID_Op_NewEntry)
              {
                  // Save Rule Group
                  if (i == 0)
                  {
                      group = pRule->value;
                  }
                  else
                  {
                      group = RULE_CUSTOM;
                  }
  
                  // Second rule must always be RID_IsParserState
                  pRule++;
                  if (pRule->id != RID_IsParserState)
                  {
                      VPHAL_RENDER_ASSERTMESSAGE("Rule does not start with State.");
                      return false;
                  }
  
                  // Get Parser State -> validate value
                  state = pRule->value;
                  if (state <  Parser_Begin)
                  {
                      VPHAL_RENDER_ASSERTMESSAGE("Invalid State %d.", state);
                      return false;
                  }
                  else if (state >= Parser_Custom)
                  {   // Custom states are set together in the same entry
                      state = Parser_Custom;
                  }
  
                  if (group == RULE_NO_OVERRIDE)
                  {
                      iNoOverr[state]++;
                  }
                  else if (group == RULE_DEFAULT)
                  {
                      iDefault[state]++;
                  }
                  else
                  {
                      iCustom[state]++;
                  }
  
                  iTotal++;
              }
          }
      }
  
      // Allocate rules
      pState->pSortedRules = (Kdll_RuleEntrySet *)MOS_AllocAndZeroMemory(iTotal * sizeof(Kdll_RuleEntrySet));
      if (!pState->pSortedRules)
      {
          VPHAL_RENDER_ASSERTMESSAGE("Failed to allocate rule table.");
          return false;
      }
  
      // Setup pointers to sorted rules
      pState->pDllRuleTable[0] = pState->pSortedRules;
      for (j = 0, i = 0; i < Parser_Count; i++)
      {
          // Setup start pointer and number of entries to search for each state
          pState->pDllRuleTable[i] = pState->pDllRuleTable[j] + pState->iDllRuleCount[j];
          pState->iDllRuleCount[i] = iNoOverr[i] + iCustom[i] + iDefault[i];
  
          // Setup offsets to rules for sorting
          iDefault[i] = iNoOverr[i] + iCustom[i];   // Last set of rules
          iCustom [i] = iNoOverr[i];                // 2nd set of rules
          iNoOverr[i] = 0;                          // 1st set of rules
  
          j = i;
      }
  
      // Sort rules for fast access
      // Integrate enforced, custom, default rules into one single access table
      for (i = 0; i < 2; i++)
      {
          if (i == 0)
          {
              pRule = pState->pRuleTableDefault;
          }
          else if (i == 1)
          {
              pRule = pState->pRuleTableCustom;
          }
  
          // Table not set - continue
          if (!pRule) continue;
  
          while (pRule->id != RID_Op_EOF)
          {
              if (pRule->id != RID_Op_NewEntry)
              {
                  VPHAL_RENDER_ASSERTMESSAGE("New rule entry expected.");
                  return false;
              }
  
              // Save Rule Group
              if (i == 0)
              {
                  group = pRule->value;
              }
              else
              {
                  group = RULE_CUSTOM;
              }
  
              // Get Parser State -> validate value
              pRule++;
              state = pRule->value;
              if (state >= Parser_Custom)
              {   // Custom states are set together in the same entry
                  state = Parser_Custom;
              }
              else
              {   // Skip state check - already handled by acceleration table
                  pRule++;
              }
  
              // Point to sorted rule set entry
              if (group == RULE_NO_OVERRIDE)
              {
                  j = iNoOverr[state]++;
              }
              else if (group == RULE_DEFAULT)
              {
                  j = iDefault[state]++;
              }
              else
              {
                  j = iCustom[state]++;
              }
  
              // Point to sorted ruleset for the current parser state
              pRuleSet = pState->pDllRuleTable[state] + j;
  
              // Fill RuleSet
              pRuleSet->pRuleEntry = pRule;
              pRuleSet->iGroup     = group;
  
              // Count number of match rules, including extended rules
              while (RID_IS_MATCH(pRule->id))
              {
                  if (RID_IS_EXTENDED(pRule->id))
                  {
                      pRuleSet->iMatchCount += pRule->value;
                      pRule += pRule->value;
                  }
  
                  pRuleSet->iMatchCount++;
                  pRule++;
              }
  
              // Count number of set rules, including extended rules
              while (RID_IS_SET(pRule->id))
              {
                  if (RID_IS_EXTENDED(pRule->id))
                  {
                      pRuleSet->iSetCount += pRule->value;
                      pRule += pRule->value;
                  }
  
                  pRuleSet->iSetCount++;
                  pRule++;
              }
  
              // Rule must have at least one "Set" rule
              if (pRuleSet->iSetCount < 1)
              {
                  VPHAL_RENDER_ASSERTMESSAGE("Ruleset must have at least one set rule.");
                  return false;
              }
          }
      }
  
      // Rule table is now sorted and integrated with custom rules
      return true;
  }
  
  //---------------------------------------------------------------------------------------
  // KernelDll_AllocateStates - Allocate Kernel Dynamic Linking/Loading (Dll) States
  //
  //    - Allocate DL states
  //    - Setup export/import list for linking
  //    - Prepare pool of search nodes
  //    - Load component kernels from binary file
  //    - Setup kernel cache
  //    - Setup kernel dynamic linking rules
  //
  // Parameters: [in] pKernelBin        - Pointer to Kernel binary file loaded in sys memory
  //             [in] uKernelSize       - Kernel file size
  //             [in] pFcPatchBin       - Pointer to FC patch binary file loaded in sys memory
  //             [in] uFcPatchCacheSize - FC patch binary file size
  //             [in] platform          - Gfx platform
  //             [in] pDefaultRules     - Dynamic Linking Rules Table
  //
  // Output: Pointer to allocated Kernel dll state
  //         nullptr - Failed to allocate Kernel dll state
  //-----------------------------------------------------------------------------------------
  Kdll_State *KernelDll_AllocateStates(
      void                    *pKernelBin,
      uint32_t                uKernelSize,
      void                    *pFcPatchCache,
      uint32_t                uFcPatchCacheSize,
      const Kdll_RuleEntry    *pDefaultRules,
      void(*ModifyFunctionPointers)(PKdll_State))
  {
      Kdll_State            *pState;
      Kdll_CacheEntry       *pCacheEntry;
      Kdll_KernelCache      *pKernelCache;
      Kdll_KernelHashTable  *pHashTable;
      Kdll_KernelHashEntry  *pHashEntries;
  
      int32_t                iSize;
      int32_t                nExports    = 0;
      int32_t                nImports    = 0;
      uint32_t              *pLinkOffset = nullptr;
      Kdll_LinkData         *pLinkSort   = nullptr;
      Kdll_LinkData         *pLinkData;
      Kdll_LinkData         *pExports;
      Kdll_LinkFileHeader   *pLinkHeader;
  
      int32_t i, j;
      uint32_t *pOffsets;
      uint8_t *pBase;
  
      VPHAL_RENDER_FUNCTION_ENTER;
  
      // Allocate dynamic linking states
      i     = sizeof(Kdll_State);                                    // Dynamic linking states
      i    += sizeof(Kdll_CacheEntry) * IDR_VP_TOTAL_NUM_KERNELS;    // Component kernel cache entries
      i    += sizeof(Kdll_CacheEntry) * IDR_VP_TOTAL_NUM_KERNELS;    // CMFC kernel patch cache entries
      i    += sizeof(Kdll_CacheEntry) * DL_DEFAULT_COMBINED_KERNELS; // Combined kernel cache entries
      i    += DL_COMBINED_KERNEL_CACHE_SIZE;                         // Combined kernel buffer
      i    += sizeof(Kdll_LinkData)   * DL_MAX_EXPORT_COUNT;         // Kernel Export table
  
      pState = (Kdll_State *)MOS_AllocAndZeroMemory(i);
      if (!pState)
      {
          VPHAL_RENDER_ASSERTMESSAGE("Failed to allocate kernel dll states.");
          goto cleanup;
      }
      pState->iSize        = i;
      pState->dwRefresh    = 0;
      pState->pProcamp     = nullptr;
      pState->iProcampSize = 0;
      pState->pSortedRules = nullptr;
  
      if ((pFcPatchCache != nullptr) && (uFcPatchCacheSize != 0))
      {
          pState->bEnableCMFC = true;
      }
  
      // Initialize platform specific function pointers
      if (!KernelDll_SetupFunctionPointers(pState, ModifyFunctionPointers))
      {
          VPHAL_RENDER_ASSERTMESSAGE("Failed to setup function pointers.");
          goto cleanup;
      }
  
      pKernelCache = &pState->ComponentKernelCache;
  
      // No custom kernels/rules
      pState->pRuleTableCustom   = nullptr;
      pState->pCustomKernelCache = nullptr;
  
      // Set Kernel DLL Rules
      pState->pRuleTableDefault  = pDefaultRules;
  
      // Integrate and sort rule tables
      KernelDll_SortRuleTable(pState);
  
      // Setup component kernel cache
      pKernelCache->pCache           = (uint8_t*)pKernelBin;
      pKernelCache->iCacheSize       = (int32_t)  uKernelSize;
      pKernelCache->iCacheFree       = 0;
      pKernelCache->iCacheMaxEntries = IDR_VP_TOTAL_NUM_KERNELS;
      pKernelCache->iCacheEntries    = IDR_VP_TOTAL_NUM_KERNELS;
      pKernelCache->pCacheEntries    = (Kdll_CacheEntry *)(pState + 1);
  
      pOffsets    = (uint32_t *) pKernelCache->pCache;
      pBase       = (uint8_t *)(pOffsets + IDR_VP_TOTAL_NUM_KERNELS + 1);
      pCacheEntry = pKernelCache->pCacheEntries;
      for (i = 0; i < IDR_VP_TOTAL_NUM_KERNELS; i++, pCacheEntry++)
      {
          pCacheEntry->iKUID      = i;
          pCacheEntry->iKCID      = -1;
          pCacheEntry->dwLoaded   = 0;
          pCacheEntry->dwRefresh  = 0;
          pCacheEntry->wHashEntry = 0;
          pCacheEntry->szName     = g_cInit_ComponentNames[i];
          pCacheEntry->iSize      = pOffsets[i + 1] - pOffsets[i];
          pCacheEntry->pBinary    = (pCacheEntry->iSize > 0) ? (pBase + pOffsets[i]) : nullptr;
      }
  
      // Setup CMFC kernel patch cache
      pKernelCache = &pState->CmFcPatchCache;
  
      if (pState->bEnableCMFC && pFcPatchCache)
      {
          pKernelCache->pCache           = (uint8_t*)pFcPatchCache;
          pKernelCache->iCacheSize       = (int32_t)uFcPatchCacheSize;
          pKernelCache->iCacheFree       = 0;
          pKernelCache->iCacheMaxEntries = IDR_VP_TOTAL_NUM_KERNELS;
          pKernelCache->iCacheEntries    = IDR_VP_TOTAL_NUM_KERNELS;
          pKernelCache->pCacheEntries    = pCacheEntry;
  
          pOffsets = (uint32_t *)pKernelCache->pCache;
          pBase = (uint8_t *)(pOffsets + IDR_VP_TOTAL_NUM_KERNELS + 1);
          for (i = 0; i < IDR_VP_TOTAL_NUM_KERNELS; i++, pCacheEntry++)
          {
              pCacheEntry->iKUID      = i;
              pCacheEntry->iKCID      = -1;
              pCacheEntry->dwLoaded   = 0;
              pCacheEntry->dwRefresh  = 0;
              pCacheEntry->wHashEntry = 0;
              pCacheEntry->szName     = g_cInit_ComponentNames[i];
              pCacheEntry->iSize      = pOffsets[i + 1] - pOffsets[i];
              pCacheEntry->pBinary    = (pCacheEntry->iSize > 0) ? (pBase + pOffsets[i]) : nullptr;
          }
      }
      else
      {
          pCacheEntry += IDR_VP_TOTAL_NUM_KERNELS;
      }
  
      // Setup combined kernel cache
      pKernelCache = &pState->KernelCache;
      pKernelCache->iCacheMaxEntries = DL_DEFAULT_COMBINED_KERNELS;
      pKernelCache->iCacheEntries    = 0;
      pKernelCache->iCacheSize       = DL_COMBINED_KERNEL_CACHE_SIZE;     // Size of kernel cache
      pKernelCache->iCacheFree       = DL_COMBINED_KERNEL_CACHE_SIZE;     // Free cache size
      pKernelCache->iCacheID         = 0x00010000;                        // Cache ID
      pKernelCache->pCacheEntries    = pCacheEntry;                       // Cached kernel entries
      pKernelCache->pCache           = (uint8_t *)(pCacheEntry + DL_DEFAULT_COMBINED_KERNELS); // kernels
  
      // reset cache entries
      for (i = 0; i < DL_DEFAULT_COMBINED_KERNELS; i++, pCacheEntry++)
      {
          pCacheEntry->iKUID      = -1;
          pCacheEntry->iKCID      = -1;
          pCacheEntry->pBinary    = pKernelCache->pCache + i * DL_CACHE_BLOCK_SIZE;
          if(i != DL_DEFAULT_COMBINED_KERNELS - 1)
          {
              pCacheEntry->pNextEntry = pCacheEntry + 1;
          }
          else
          {
              pCacheEntry->pNextEntry = nullptr;
          }
      }
  
      //------------------------------------
      // Setup hash table
      //------------------------------------
      pHashTable   = &pState->KernelHashTable;
      pHashEntries = pState->KernelHashTable.HashEntry - 1;
  
      pHashTable->pool    = 1;                          // first in pool (1 based index)
      pHashTable->last    = DL_MAX_COMBINED_KERNELS;    // last in pool (for releasing)
  
      for (i = 1; i <= DL_MAX_COMBINED_KERNELS; i++)
      {
          pHashEntries[i].next = i + 1;
      }
      pHashEntries[i - 1].next = 0;  // last entry
  
      //------------------------------------
      // Setup dynamic linking import/export array
      //------------------------------------
      pCacheEntry = pState->ComponentKernelCache.pCacheEntries;
      iSize       = pCacheEntry[IDR_VP_LinkFile].iSize;
      if (iSize == 0)
      {
          VPHAL_RENDER_NORMALMESSAGE("Link file is missing.");
          goto cleanup;
      }
  
      // Get link file binary data
      pLinkHeader = (Kdll_LinkFileHeader *) pCacheEntry[IDR_VP_LinkFile].pBinary;
      if (pLinkHeader == nullptr ||
          pLinkHeader->dwVersion != IDR_VP_LINKFILE_VERSION ||
          sizeof(Kdll_LinkFileHeader) != IDR_VP_LINKFILE_HEADER)
      {
          VPHAL_RENDER_ASSERTMESSAGE("Invalid link file version.");
          goto cleanup;
      }
      iSize = (iSize - IDR_VP_LINKFILE_HEADER) / sizeof(Kdll_LinkData);
  
      // Create temporary list of sorted link data and offsets
      pLinkSort   = (Kdll_LinkData *)MOS_AllocAndZeroMemory(iSize * sizeof(Kdll_LinkData));
      pLinkOffset = (uint32_t *)MOS_AllocAndZeroMemory((IDR_VP_TOTAL_NUM_KERNELS + 1) * sizeof(uint32_t));
      if (!pLinkSort || !pLinkOffset)
      {
          VPHAL_RENDER_ASSERTMESSAGE("Failed to allocate temporary buffers.");
          goto cleanup;
      }
  
      // Count number of imports for each component kernel
      pCacheEntry[0].pLink = pLinkData = (Kdll_LinkData *)(pLinkHeader + 1);
      for (i = iSize; i > 0; i--, pLinkData++)
      {
          if (pLinkData->iKUID < IDR_VP_TOTAL_NUM_KERNELS)
          {
              pCacheEntry[pLinkData->iKUID].nLink++;
          }
  
          nExports += pLinkData->bExport;
          nImports += !pLinkData->bExport;
      }
  
      // Sanity check
      if (nExports != (int32_t)pLinkHeader->dwExports ||
          nImports != (int32_t)pLinkHeader->dwImports)
      {
          VPHAL_RENDER_ASSERTMESSAGE("Inconsistent header data.");
          goto cleanup;
      }
  
      if (nExports > DL_MAX_EXPORT_COUNT)
      {
          VPHAL_RENDER_ASSERTMESSAGE("Unsupported number of exports %d > %d.", nExports, DL_MAX_EXPORT_COUNT);
          goto cleanup;
      }
  
      pState->ComponentKernelCache.pExports = pExports = (Kdll_LinkData *)(pKernelCache->pCache + pKernelCache->iCacheSize);
      pState->ComponentKernelCache.nExports = nExports;
  
      // Calculate offsets for sorting
      pLinkOffset[0] = 0;
      pLinkData = pCacheEntry[0].pLink;
      for (i = 1; i < IDR_VP_TOTAL_NUM_KERNELS; i++)
      {
          pLinkOffset[i] = pLinkOffset[i-1] + pCacheEntry[i-1].nLink;
          pCacheEntry[i].pLink = (pCacheEntry[i].nLink) ? (pLinkData + pLinkOffset[i]) : nullptr;
      }
      pLinkOffset[i] = pLinkOffset[i-1] + pCacheEntry[i-1].nLink;
  
      // Sort link data
      for (i = iSize; i > 0; i--, pLinkData++)
      {
          j = pLinkOffset[MOS_MIN(pLinkData->iKUID, IDR_VP_TOTAL_NUM_KERNELS)]++;
          pLinkSort[j] = *pLinkData;
  
          // Add to export table
          if (pLinkData->bExport &&
              pLinkData->iLabelID < DL_MAX_EXPORT_COUNT)
          {
              pExports[pLinkData->iLabelID] = *pLinkData;
          }
      }
  
      // Copy sort data
      pLinkData = pCacheEntry[0].pLink;
      MOS_SecureMemcpy(pLinkData, iSize * sizeof(Kdll_LinkData), (void *)pLinkSort, iSize * sizeof(Kdll_LinkData));
  
      // Release sort buffers
      MOS_FreeMemory(pLinkOffset);
      MOS_FreeMemory(pLinkSort);
  
      // Return
      return pState;
  
  cleanup:
      if (pState)
      {
          MOS_FreeMemory(pState->pSortedRules);
          pState->pSortedRules = nullptr;
      }
  
      // Free DL States and temporary sort buffers
      MOS_FreeMemory(pState);
      MOS_FreeMemory(pLinkSort);
      MOS_FreeMemory(pLinkOffset);
  
      return nullptr;
  }
  
  //---------------------------------------------------------------------------------------
  // KernelDll_ReleaseStates - Release Kernel Dynamic Linking/Loading (Dll) States
  //
  // Parameters:
  //    Kdll_State *pState - [in] Kernel dll State to release
  //
  // Output: Pointer to allocated Kernel dll state
  //         nullptr - Failed to allocate Kernel dll state
  //-----------------------------------------------------------------------------------------
  void KernelDll_ReleaseStates(Kdll_State *pState)
  {
      VPHAL_RENDER_FUNCTION_ENTER;
  
      if (!pState) return;
      KernelDll_ReleaseAdditionalCacheEntries(&pState->KernelCache);
      MOS_FreeMemory(pState->ComponentKernelCache.pCache);
      MOS_FreeMemory(pState->CmFcPatchCache.pCache);
      MOS_FreeMemory(pState->pSortedRules);
      MOS_FreeMemory(pState);
  }
  
  //---------------------------------------------------------------------------------------
  // KernelDll_SetupProcampParameters - Setup Kernel Procamp Parameters
  //
  // Parameters:
  //    Kdll_State   *pState       - [in] Kernel dll State to release
  //    Kdll_Procamp *pProcamp     - [in] Pointer to array of Procamp Parameters
  //    int32_t       iProcampSize - [in] Size of the array
  //
  // Output: Pointer to allocated Kernel dll state
  //         nullptr - Failed to allocate Kernel dll state
  //-----------------------------------------------------------------------------------------
  void KernelDll_SetupProcampParameters(Kdll_State    *pState,
                                        Kdll_Procamp  *pProcamp,
                                        int32_t        iProcampSize)
  {
      VPHAL_RENDER_FUNCTION_ENTER;
  
      // Setup pointer to procamp parameters
      pState->pProcamp     = pProcamp;
      pState->iProcampSize = iProcampSize;
  }
  
  //---------------------------------------------------------------------------------------
  // Kdll_SearchKernel - Performs full kernel search, including selection of best match
  //                     Search state must be initialized by KernelDll_StartKernelSearch
  //
  // Parameters:
  //    Kdll_State       *pState       - [in]     Dynamic Linking state
  //    Kdll_SearchState *pSearchState - [in/out] Kernel search state
  //
  // Output: true if suceeded, false otherwise
  //---------------------------------------------------------------------------------------
  bool KernelDll_SearchKernel(Kdll_State       *pState,
                              Kdll_SearchState *pSearchState)
  {
      VPHAL_RENDER_FUNCTION_ENTER;
  
      // Check parameters
      if ((!pSearchState) || pSearchState->iFilterSize < 1)
      {
          VPHAL_RENDER_NORMALMESSAGE("Search is empty, must contain 2 or more layers.");
          return false;
      }
  
      // Setup CSC; allocate and calculate CSC matrices
      if (!pState->pfnSetupCSC(pState, pSearchState))
      {
          VPHAL_RENDER_NORMALMESSAGE("CSC setup failed.");
          return false;
      }
  
      // Initial search states
      pSearchState->bCscBeforeMix = false;
      pSearchState->state        = Parser_Begin;
      pSearchState->cspace       = pSearchState->CscParams.ColorSpace;
      pSearchState->quadrant     = 0;
      pSearchState->layer_number = 0;
  
      pSearchState->pMatchingRuleSet = nullptr;
  
      // Reset Src0 state
      pSearchState->src0_format   = Format_None;
      pSearchState->src0_sampling = Sample_None;
      pSearchState->src0_colorfill = false;
      pSearchState->src0_lumakey   = LumaKey_False;
      pSearchState->src0_coeff    = CoeffID_None;
  
      // Reset Src1 state
      pSearchState->src1_format   = Format_None;
      pSearchState->src1_sampling = Sample_None;
      pSearchState->src1_lumakey   = LumaKey_False;
      pSearchState->src1_samplerlumakey = LumaKey_False;
      pSearchState->src1_coeff    = CoeffID_None;
      pSearchState->src1_process  = Process_None;
  
      // Search loop
      while (pSearchState->state != Parser_End)
      {
  #if EMUL || VPHAL_LIB
          if (pState->pfnCbSearchSate)
          {
              pState->pfnCbSearchSate(pState->pToken, CB_REASON_BEGIN_SEARCH, pSearchState);
          }
  #endif
          // Find rule that matches
          if (!pState->pfnFindRule(pState, pSearchState))
          {
  #if EMUL || VPHAL_LIB
              if (pState->pfnCbSearchSate)
              {
                  pState->pfnCbSearchSate(pState->pToken, CB_REASON_SEARCH_FAILED, pSearchState);
              }
  #endif
              return false;
          }
  
  #if EMUL || VPHAL_LIB
          if (pState->pfnCbSearchSate)
          {
              pState->pfnCbSearchSate(pState->pToken, CB_REASON_BEGIN_UPDATE, pSearchState);
          }
  #endif
          // Update state
          if (!pState->pfnUpdateState(pState, pSearchState))
          {
  #if EMUL || VPHAL_LIB
              if (pState->pfnCbSearchSate)
              {
                  pState->pfnCbSearchSate(pState->pToken, CB_REASON_UPDATE_FAILED, pSearchState);
              }
  #endif
              return false;
          }
      }
  
  #if EMUL || VPHAL_LIB
      if (pState->pfnCbSearchSate)
      {
          pState->pfnCbSearchSate(pState->pToken, CB_REASON_END_SEARCH, pSearchState);
      }
  #endif
  
      VPHAL_RENDER_VERBOSEMESSAGE("Search completed successfully.");
      return true;
  }
  
  //--------------------------------------------------------------
  // Append kernel, include symbols to resolve
  //--------------------------------------------------------------
  bool Kdll_AppendKernel(Kdll_KernelCache *pKernelCache,
                         Kdll_SearchState *pSearchState,
                         int32_t           iKUID,
                         Kdll_PatchData   *pKernelPatch)
  {
      Kdll_State      *pState;
      Kdll_Symbol     *pSymbols;
      Kdll_CacheEntry *kernels;
      Kdll_LinkData   *link;
      Kdll_LinkData   *liSearch_reloc;
      uint8_t         *kernel;
      int             *size;
      int             *left;
      int dwSize;
      int i;
      int             base;
      bool            bInline;
      bool            res;
  
      VPHAL_RENDER_FUNCTION_ENTER;
  
      res = false;
  
      // Check if Kernel ID is valid
      if (iKUID >= pKernelCache->iCacheEntries)
      {
          VPHAL_RENDER_NORMALMESSAGE("invalid Kernel ID %d.", iKUID);
          goto cleanup;
      }
  
      // Get KDLL state
      pState   = pSearchState->pKdllState;
  
      // Get current combined kernel
      kernel   = pSearchState->Kernel;
      size     = &pSearchState->KernelSize;
      left     = &pSearchState->KernelLeft;
      pSymbols = &pSearchState->KernelLink;
      base     = (*size) >> 2;
  
      // Find selected kernel and kernel size; check if there is enough space
      kernels  = &pKernelCache->pCacheEntries[iKUID];
      dwSize = kernels->iSize;
      if (*left < dwSize)
      {
          VPHAL_RENDER_NORMALMESSAGE("exceeded maximum kernel size.");
          goto cleanup;
      }
  
      // Check if there is enough space for symbols
      if (pSymbols->dwCount + kernels->nLink >= pSymbols->dwSize)
      {
          VPHAL_RENDER_NORMALMESSAGE("exceeded maximum numbers of symbols to resolve.");
          goto cleanup;
      }
  
  #if EMUL || VPHAL_LIB
      VPHAL_RENDER_NORMALMESSAGE("%s.", kernels->szName);
  
      if (pState->pfnCbListKernel)
      {
          pState->pfnCbListKernel(pState->pToken, kernels->szName);
      }
  #elif _DEBUG // EMUL || VPHAL_LIB
      VPHAL_RENDER_NORMALMESSAGE("%s.", kernels->szName);
  #endif // _DEBUG
  
      // Append symbols to resolve, relocate symbols
      link = kernels->pLink;
      liSearch_reloc = pSymbols->pLink + pSymbols->dwCount;
  
      bInline = false;
      if (link)
      {
          for (i = kernels->nLink; i > 0; i--, link++)
          {
              if (link->bInline)
              {
                  // Inline code included
                  if (!link->bExport)
                  {
                      bInline = true;
                  }
              }
              else
              {
                  *liSearch_reloc = *link;
                  liSearch_reloc->dwOffset += base;
                  liSearch_reloc++;
  
                  pSymbols->dwCount++;
              }
          }
      }
  
      // Append kernel
      MOS_SecureMemcpy(&kernel[*size], dwSize, (void *)kernels->pBinary, dwSize);
  
      // Patch kernel
      if (pKernelPatch)
      {
          uint8_t *pSource      = pKernelPatch->Data;
          uint8_t *pDestination = kernel + (*size);
          int32_t i;
  
          Kdll_PatchBlock *pBlock = pKernelPatch->Patch;
          for (i = pKernelPatch->nPatches; i > 0; i--, pBlock++)
          {
              MOS_SecureMemcpy(pDestination + pBlock->DstOffset, pBlock->BlockSize, (void *)(pSource + pBlock->SrcOffset), pBlock->BlockSize);
          }
      }
  
      res = true;
      *size += dwSize;
      *left -= dwSize;
  
      // Insert inline code
      if (bInline)
      {
          for (link = kernels->pLink, i = kernels->nLink; (i > 0) && (res); i--, link++)
          {
              if (link->bInline && (!link->bExport))
              {
                  iKUID = pKernelCache->pExports[link->iLabelID].iKUID;
                  res &= Kdll_AppendKernel(pKernelCache, pSearchState, iKUID, pKernelPatch);
              }
          }
      }
  
  cleanup:
      return res;
  }
  
  //--------------------------------------------------------------
  // Resolve kernel dependencies and perform patching
  //--------------------------------------------------------------
  bool Kdll_ResolveKernelDependencies(
      Kdll_State         *pState,
      Kdll_SearchState   *pSearchState)
  {
      Kdll_KernelCache *cache    = &pState->ComponentKernelCache;
      uint8_t          *kernel   =  pSearchState->Kernel;
      Kdll_Symbol      *pSymbols = &pSearchState->KernelLink;
      uint32_t          nExports = cache->nExports;
      Kdll_LinkData    *pExports = cache->pExports;
      Kdll_LinkData    *pLink;
      int32_t           iKUID;
      int32_t           iOffset;
      uint32_t          dwResolveOffset[DL_MAX_EXPORT_COUNT];
      bool              bResolveDone;
      int32_t           i;
      uint32_t         *d;
  
      VPHAL_RENDER_FUNCTION_ENTER;
  
      MOS_ZeroMemory(dwResolveOffset, sizeof(dwResolveOffset));
  
      do
      {
          // Update exports
          for (pLink = pSymbols->pLink, i = pSymbols->dwCount; i > 0; i--, pLink++)
          {
              if (pLink->bExport)
              {
                  dwResolveOffset[pLink->iLabelID] = pLink->dwOffset;
              }
          }
  
          bResolveDone = true;
          for (pLink = pSymbols->pLink, i = pSymbols->dwCount; i > 0; i--, pLink++)
          {
              // validate label
              if (pLink->iLabelID > nExports ||              // invalid label
                  pExports[pLink->iLabelID].bExport == 0)    // label not in the export table
              {
                  VPHAL_RENDER_ASSERTMESSAGE("Invalid/unresolved label %d.", pLink->iLabelID);
                  return false;
              }
  
              // load dependencies
              if (!pLink->bExport && !dwResolveOffset[pLink->iLabelID])
              {
                  // set flag for another pass as newly loaded
                  // kernels may contain dependencies of their own
                  bResolveDone = false;
  
                  // Load dependencies
                  iKUID = pExports[pLink->iLabelID].iKUID;
                  Kdll_AppendKernel(cache, pSearchState, iKUID, nullptr);
  
                  // Restart
                  break;
              }
          } // for
      } while (!bResolveDone);
  
      // All modules must be loaded by now, start patching
      for (pLink = pSymbols->pLink, i = pSymbols->dwCount; i > 0; i--, pLink++)
      {
          iOffset  = (int32_t)dwResolveOffset[pLink->iLabelID] - 4;
          iOffset -= pLink->dwOffset;
  
          d = ((uint32_t *)kernel) + pLink->dwOffset;
  
          // Patch offset
          if (!pLink->bExport && !pLink->bInline)
          {
              d[3] = iOffset << 2; // jmpi - index * 8 bits
          }
      }
  
      return true;
  }
  
  //--------------------------------------------------------------
  // Fowler/Noll/Vo FNV-1a hash algorithm - public domain
  //--------------------------------------------------------------
  uint32_t KernelDll_SimpleHash(void *pData, int32_t iSize)
  {
     static const uint32_t k = 0x1000193;
     uint32_t hash = 0x811c9dc5;
     char *p = (char *)pData;
  
     for(; iSize > 0; iSize--)
     {
        hash ^= (*p++);
        hash *= k;
     }
  
     return hash;
  }
  
  //--------------------------------------------------------------
  // KernelDll_GetCombinedKernel - Search combined kernel
  //--------------------------------------------------------------
  Kdll_CacheEntry *KernelDll_GetCombinedKernel(
      Kdll_State          *pState,
      Kdll_FilterEntry    *pFilter,
      int32_t             iFilterSize,
      uint32_t            dwHash)
  {
      Kdll_KernelHashTable *pHashTable;
      Kdll_KernelHashEntry *entries, *curr, *next;
      uint32_t folded_hash;
      uint16_t entry;
  
      VPHAL_RENDER_FUNCTION_ENTER;
  
      // Get hash table
      pHashTable = &pState->KernelHashTable;
  
      // fold hash from 32 to 8 bit :-)
      FOLD_HASH(folded_hash, dwHash)
  
      // No entries
      entry = pHashTable->wHashTable[folded_hash];
      if (entry == 0 || entry > DL_MAX_COMBINED_KERNELS ) return nullptr;
  
      entries = (&pHashTable->HashEntry[0]) - 1;  // all indices are 1 based (0 means null)
      curr    = &entries[entry];
      for (; (curr != nullptr); curr = next)
      {
          // match 32-bit hash, then compare filter
          if (curr->dwHash  == dwHash &&
              curr->iFilter == iFilterSize)
          {
              if (memcmp(curr->pFilter, pFilter, iFilterSize * sizeof(Kdll_FilterEntry)) == 0)
              {
                  break;
              }
          }
  
          // Next entry with the same 8-bit folded hash
          next = (curr->next) ? (&entries[curr->next]) : nullptr;
      }
  
      if (curr)
      {   // Kernel already cached
          curr->pCacheEntry->dwRefresh = pState->dwRefresh++;
          return (curr->pCacheEntry);
      }
      else
      {   // Kernel must be built
          return nullptr;
      }
  }
  
  //--------------------------------------------------------------
  // KernelDll_AllocateHashEntry - Allocate hash entry
  //--------------------------------------------------------------
  uint16_t KernelDll_AllocateHashEntry(Kdll_KernelHashTable *pHashTable,
                                   uint32_t              hash)
  {
      Kdll_KernelHashEntry *pHashEntry = &pHashTable->HashEntry[0] - 1;
      Kdll_KernelHashEntry *pNewEntry;
      uint32_t folded_hash;
      uint16_t entry;
  
      VPHAL_RENDER_FUNCTION_ENTER;
  
      entry = pHashTable->pool;
      if (!entry)
      {
          return 0;
      }
  
      // Get entry from pool
      pNewEntry = &pHashEntry[entry];
      pHashTable->pool = pNewEntry->next;
      if (pHashTable->last == entry)
      {
          pHashTable->last = 0;
      }
  
      // Initialize entry, attach to the hash table
      FOLD_HASH(folded_hash, hash);
      pNewEntry->dwHash      = hash;
      pNewEntry->next        = pHashTable->wHashTable[folded_hash];
      pNewEntry->iFilter     = 0;
      pNewEntry->pFilter     = nullptr;
      pNewEntry->pCacheEntry = nullptr;
      pHashTable->wHashTable[folded_hash] = entry;
      return entry;
  }
  
  //--------------------------------------------------------------
  // KernelDll_ReleaseHashEntry - Release hash table entry
  //--------------------------------------------------------------
  void KernelDll_ReleaseHashEntry(Kdll_KernelHashTable *pHashTable, uint16_t entry)
  {
      Kdll_KernelHashEntry *pHashEntry = &pHashTable->HashEntry[0] - 1;
      uint32_t folded_hash;
      uint16_t next;
  
      VPHAL_RENDER_FUNCTION_ENTER;
  
      if (entry == 0)
      {
          return;
      }
  
      // unlink entry
      next = pHashEntry[entry].next;
      pHashEntry[entry].next = 0;
  
      // remove references to entry from hash table
      FOLD_HASH(folded_hash, pHashEntry[entry].dwHash);
      if (pHashTable->wHashTable[folded_hash] == entry)
      {
          pHashTable->wHashTable[folded_hash] = next;
      }
      else
      {
          uint16_t prev = pHashTable->wHashTable[folded_hash];
  
          while (prev != 0 &&
                 pHashEntry[prev].next != entry)
          {
              prev = pHashEntry[prev].next;
          }
  
          if (prev)
          {
              pHashEntry[prev].next = next;
          }
      }
  
      // return entry to pool
      if (pHashTable->pool == 0)
      {
          pHashTable->pool = entry;
      }
      else
      {
          pHashEntry[pHashTable->last].next = entry;
      }
      pHashTable->last = entry;
  }
  
  //--------------------------------------------------------------
  // KernelDll_ReleaseCacheEntry - Release cache entry
  //--------------------------------------------------------------
  void KernelDll_ReleaseCacheEntry(Kdll_KernelCache *pCache,
                                   Kdll_CacheEntry  *pEntry)
  {
      pEntry->iKUID = -1;
      pEntry->iKCID = -1;
      pCache->iCacheEntries--;
  }
  
  //--------------------------------------------------------------
  // KernelDll_CacheGarbageCollection - performs garbage collection
  //--------------------------------------------------------------
  bool KernelDll_GarbageCollection(Kdll_State *pState, int32_t size)
  {
      Kdll_KernelCache     *pCache     = &pState->KernelCache;
      Kdll_CacheEntry      *pEntry     = pCache->pCacheEntries;
      Kdll_CacheEntry      *pOldest    = nullptr;
      Kdll_KernelHashTable *pHashTable = &pState->KernelHashTable;
      Kdll_KernelHashEntry *pHashEntry = &pHashTable->HashEntry[0] - 1;
      uint32_t              dwOldest   = (uint32_t)-1;
      uint16_t              wEntry     = 0;
      int32_t i;
  
      MOS_UNUSED(size);
  
      VPHAL_RENDER_FUNCTION_ENTER;
  
      // Adjust refresh values to avoid overflow
      if (pState->dwRefresh > 0xffff0000)
      {
          pState->dwRefresh -= 0x80000000;
          for (i = pCache->iCacheMaxEntries; i > 0; i--)
          {
              if (pEntry->dwRefresh < 0x80000000)
                  pEntry->dwRefresh = 0;
              else
                  pEntry->dwRefresh -= 0x80000000;
              pEntry = pEntry->pNextEntry;
          }
      }
  
      // No need to deallocate old entries
      if (pCache->iCacheEntries < DL_MAX_COMBINED_KERNELS)
      {
          return true;
      }
  
      for (i = pCache->iCacheMaxEntries; i > 0; i--)
      {
          // deallocate old unreferenced entries
          if (pEntry->iKCID != -1 && pEntry->dwLoaded == 0)
          {
              if (pEntry->dwRefresh < dwOldest)
              {
                  pOldest  = pEntry;
                  dwOldest = pEntry->dwRefresh;
                  wEntry   = pEntry->wHashEntry;
              }
          }
          pEntry = pEntry->pNextEntry;
      }
  
      // No entry to release, sanity checks
      pHashEntry += wEntry;
      if (!pOldest ||
          wEntry == 0 ||
          pHashEntry->pCacheEntry != pOldest)
      {
          VPHAL_RENDER_ASSERT(false);
          return false;
      }
  
      // Release hash and cache entries
      KernelDll_ReleaseHashEntry(pHashTable, wEntry);
      KernelDll_ReleaseCacheEntry(pCache, pOldest);
  
      return true;
  }
  
  //--------------------------------------------------------------
  // KernelDll_AllocateAdditionalCacheEntries - Allocate more kernel cache entries
  //--------------------------------------------------------------
  Kdll_CacheEntry *
  KernelDll_AllocateAdditionalCacheEntries(Kdll_KernelCache *pCache)
  {
      Kdll_CacheEntry *pNewEntry = nullptr;
      Kdll_CacheEntry *pChcheEntry;
      int i, j;
  
      VPHAL_RENDER_FUNCTION_ENTER;
  
      // Check num
      if (pCache->iCacheEntries + DL_NEW_COMBINED_KERNELS > DL_MAX_COMBINED_KERNELS)
      {
          VPHAL_RENDER_ASSERTMESSAGE("KernelDll_AllocateAdditionalCacheEntries: Can't allocate more kernel cache entries\n");
          return nullptr;
      }
  
      // Allocate the new entires
      i = (sizeof(Kdll_CacheEntry) + DL_CACHE_BLOCK_SIZE) * DL_NEW_COMBINED_KERNELS;
      pNewEntry = (Kdll_CacheEntry *)MOS_AllocAndZeroMemory(i);
      if (!pNewEntry)
      {
          VPHAL_RENDER_ASSERTMESSAGE("KernelDll_AllocateAdditionalCacheEntries: Failed to allocate kernel cache entries\n");
          return nullptr;
      }
  
      // Update the cache entires
      pChcheEntry = pCache->pCacheEntries;
      for(j = 0; j < pCache->iCacheMaxEntries - 1; j++)
      {
          pChcheEntry = pChcheEntry->pNextEntry;
      }
      pChcheEntry->pNextEntry = pNewEntry;
      for(j = 0; j < DL_NEW_COMBINED_KERNELS; j++, pNewEntry++)
      {
          pNewEntry->iKUID   = -1;
          pNewEntry->iKCID   = -1;
          pNewEntry->pBinary = (uint8_t *)(pNewEntry + DL_NEW_COMBINED_KERNELS - j) + j * DL_CACHE_BLOCK_SIZE;
          if(j != DL_NEW_COMBINED_KERNELS - 1)
          {
              pNewEntry->pNextEntry = pNewEntry + 1;
          }
          else
          {
              pNewEntry->pNextEntry = nullptr;
          }
      }
  
      pCache->iCacheMaxEntries += DL_NEW_COMBINED_KERNELS;
      pCache->iCacheSize       += DL_NEW_COMBINED_KERNELS * DL_CACHE_BLOCK_SIZE;
      pCache->iCacheFree       += DL_NEW_COMBINED_KERNELS * DL_CACHE_BLOCK_SIZE;
      return (Kdll_CacheEntry *)(pNewEntry - DL_NEW_COMBINED_KERNELS);
  }
  
  //--------------------------------------------------------------
  // KernelDll_ReleaseAdditionalCacheEntries - Release the additional kernel cache entries
  //--------------------------------------------------------------
  void KernelDll_ReleaseAdditionalCacheEntries(Kdll_KernelCache *pCache)
  {
      VPHAL_RENDER_FUNCTION_ENTER;
      if(pCache->iCacheMaxEntries > DL_DEFAULT_COMBINED_KERNELS)
      {
          Kdll_CacheEntry *pNewEntries, *pEntries;
          pNewEntries = (pCache->pCacheEntries + DL_DEFAULT_COMBINED_KERNELS - 1)->pNextEntry;
          for(int i = 0; i < (pCache->iCacheMaxEntries - DL_DEFAULT_COMBINED_KERNELS) / DL_NEW_COMBINED_KERNELS; i++)
          {
              pEntries = (pNewEntries + DL_NEW_COMBINED_KERNELS - 1)->pNextEntry;
              MOS_FreeMemory(pNewEntries);
              pNewEntries = pEntries;
          }
      }
  }
  
  //--------------------------------------------------------------
  // KernelDll_AllocateCacheEntry - Allocate cache entry for a given size
  //--------------------------------------------------------------
  Kdll_CacheEntry *
  KernelDll_AllocateCacheEntry(Kdll_KernelCache *pCache, int32_t iSize)
  {
      Kdll_CacheEntry *pEntry          = pCache->pCacheEntries;
      uint8_t *pCacheBinary               = nullptr;
      Kdll_CacheEntry *pCacheNextEntry = nullptr;
      int32_t i, j;
  
      VPHAL_RENDER_FUNCTION_ENTER;
  
      // Check size
      if (iSize > DL_CACHE_BLOCK_SIZE)
      {
          return nullptr;
      }
  
      // Search empty entry
      j = pCache->iCacheMaxEntries;
      for (i = 0; i < j; i++)
      {
          if (pEntry->iKCID == -1)
          {
              break;
          }
          pEntry = pEntry->pNextEntry;
      }
      if (i == j)
      {
          // Try to allocate more cache entries
          pEntry = KernelDll_AllocateAdditionalCacheEntries(pCache);
          if(! pEntry)
          {
              return nullptr;
          }
      }
  
      // Reset entry
      pCacheBinary    = pEntry->pBinary;
      pCacheNextEntry = pEntry->pNextEntry;
      MOS_ZeroMemory(pEntry, sizeof(Kdll_CacheEntry));
      pEntry->iSize   = iSize;
      pEntry->pBinary    = pCacheBinary;
      pEntry->pNextEntry = pCacheNextEntry;
  
      // Increment entries
      pCache->iCacheEntries++;
      return pEntry;
  }
  
  //--------------------------------------------------------------
  // Kerneldll_GetComponentKernel - Get component/static kernel
  //                                entry from cache
  //--------------------------------------------------------------
  Kdll_CacheEntry *
  KernelDll_GetComponentKernel(Kdll_State *pState,
                               int32_t     iKUID)
  {
      Kdll_CacheEntry *pEntry = nullptr;
  
      if (iKUID < pState->ComponentKernelCache.iCacheMaxEntries)
      {
          pEntry = &(pState->ComponentKernelCache.pCacheEntries[iKUID]);
          if (pEntry->iKUID != iKUID ||
              pEntry->pBinary == nullptr ||
              pEntry->iSize == 0)
          {
              pEntry = nullptr;
          }
      }
  
      return pEntry;
  }
  
  //--------------------------------------------------------------
  // KernelDll_AddKernel - Add kernel into hash table and kernel cache
  //--------------------------------------------------------------
  Kdll_CacheEntry *
  KernelDll_AddKernel(Kdll_State       *pState,           // Kernel Dll state
                      Kdll_SearchState *pSearchState,     // Search state
                      Kdll_FilterEntry *pFilter,          // Original filter
                      int32_t           iFilterSize,      // Original filter size
                      uint32_t          dwHash)
  {
      Kdll_CacheEntry      *pCacheEntry;
      Kdll_KernelHashTable *pHashTable;
      Kdll_KernelHashEntry *pHashEntry;
      uint16_t entry;
      int32_t size;
      uint8_t *ptr;
  
      VPHAL_RENDER_FUNCTION_ENTER;
  
      // Check kernel
      if (pSearchState->KernelSize <= 0)
      {
          return nullptr;
      }
  
      // Get hash table
      pHashTable = &pState->KernelHashTable;
      pHashEntry = &pHashTable->HashEntry[0] - 1;  // all indices are 1 based (0 = null)
  
      // allocate space in kernel cache to store the kernel, filter, CSC parameters
      size  = pSearchState->KernelSize +                                  // Kernel
              pSearchState->iFilterSize * sizeof(Kdll_FilterEntry) * 2 +  // Original + Modified Filter
              sizeof(Kdll_CSC_Params) +                                   // CSC parameters
              sizeof(VPHAL_CSPACE);                                       // Intermediate Color Space for colorfill
  
      // Run garbage collection, create space for new kernel and metadata
      KernelDll_GarbageCollection(pState, size);
  
      // Get new kernel cache entry
      pCacheEntry = KernelDll_AllocateCacheEntry(&pState->KernelCache, size);
      if (!pCacheEntry)
      {
          VPHAL_RENDER_ASSERTMESSAGE("Failed to allocate cache space for new kernel.");
          return nullptr;
      }
  
      // Get hash entry
      entry = KernelDll_AllocateHashEntry(pHashTable, dwHash);
      if (!entry)
      {
          VPHAL_RENDER_ASSERTMESSAGE("Failed to allocate hash entry for new kernel.");
          KernelDll_ReleaseCacheEntry(&pState->KernelCache, pCacheEntry);
          return nullptr;
      }
  
      // Setup cache entry, copy kernel
      pCacheEntry->iKUID       = -1;
      pCacheEntry->iKCID       = pState->KernelCache.iCacheID;  // Create new kernel cache id (KCID)
      pCacheEntry->dwRefresh   = pState->dwRefresh++;
      pCacheEntry->wHashEntry  = entry;
  
      // Save kernel
      pCacheEntry->iSize = pSearchState->KernelSize;
      MOS_SecureMemcpy(pCacheEntry->pBinary, pSearchState->KernelSize, (void *)pSearchState->Kernel, pSearchState->KernelSize);
      ptr = pCacheEntry->pBinary + pSearchState->KernelSize;
  
      // Save modified filter
      pCacheEntry->iFilterSize = pSearchState->iFilterSize;
      pCacheEntry->pFilter     = (Kdll_FilterEntry *) (ptr);
      MOS_SecureMemcpy(ptr, pSearchState->iFilterSize * sizeof(Kdll_FilterEntry), (void *)pSearchState->Filter, pSearchState->iFilterSize * sizeof(Kdll_FilterEntry));
      ptr += pSearchState->iFilterSize * sizeof(Kdll_FilterEntry);
  
      // Save CSC parameters associated with the kernel
      pCacheEntry->pCscParams = (Kdll_CSC_Params *) (ptr);
      MOS_SecureMemcpy(ptr, sizeof(Kdll_CSC_Params), (void *)&pSearchState->CscParams, sizeof(Kdll_CSC_Params));
      ptr += sizeof(Kdll_CSC_Params);
      // Save intermediate color space for colorfill
      pCacheEntry->colorfill_cspace = pState->colorfill_cspace;
      ptr += sizeof(VPHAL_CSPACE);
  
      // increment KCID (Range = 0x00010000 - 0x7fffffff)
      pState->KernelCache.iCacheID = 0x00010000 + (pState->KernelCache.iCacheID - 0x0000ffff) % 0x7fff0000;
  
      // Setup hash entry, copy filter
      pHashEntry += entry;
      pHashEntry->pCacheEntry = pCacheEntry;
  
      // Save original filter for search purposes - modified filter is used for rendering
      pHashEntry->iFilter     = iFilterSize;
      pHashEntry->pFilter     = (Kdll_FilterEntry *) (ptr);
      MOS_SecureMemcpy(ptr, iFilterSize * sizeof(Kdll_FilterEntry), (void *)pFilter, iFilterSize * sizeof(Kdll_FilterEntry));
  
      return pCacheEntry;
  }
  
  //--------------------------------------------------------------
  // KernelDll_BuildKernel - build kernel
  //--------------------------------------------------------------
  bool KernelDll_BuildKernel(Kdll_State *pState, Kdll_SearchState *pSearchState)
  {
      Kdll_KernelCache *pKernelCache = &pState->ComponentKernelCache;
      Kdll_KernelCache *pCustomCache =  pState->pCustomKernelCache;
      Kdll_PatchData   *pKernelPatch;
      bool              res;
      int32_t           offset = 0;
      int32_t           *pKernelID, *pGroupID, *pPatchID;
  
      VPHAL_RENDER_FUNCTION_ENTER;
  
      pSearchState->KernelLink.dwSize  = DL_MAX_SYMBOLS;
      pSearchState->KernelLink.dwCount = 0;
      pSearchState->KernelLink.pLink   = pSearchState->LinkArray;
      pSearchState->KernelSize         = 0;
      pSearchState->KernelLeft         = sizeof(pSearchState->Kernel);
      pSearchState->KernelLink.dwCount = 0;
  
  #if EMUL || VPHAL_LIB || _DEBUG || _RELEASE_INTERNAL
      VPHAL_RENDER_NORMALMESSAGE("Component Kernels:");
  #endif // EMUL || VPHAL_LIB || _DEBUG
  
      pKernelID = pSearchState->KernelID;
      pGroupID  = pSearchState->KernelGrp;
      pPatchID  = pSearchState->PatchID;
  
      for (offset = 0; offset < pSearchState->KernelCount; offset++, pKernelID++, pGroupID++, pPatchID++)
      {
          // Get patch information associated with the kernel
          pKernelPatch = (*pPatchID >= 0) ? &(pSearchState->Patches[*pPatchID]) : nullptr;
  
          // Append/Patch kernel from custom cache
          if (*pGroupID == GROUP_CUSTOM)
          {
              res = Kdll_AppendKernel(pCustomCache, pSearchState, *pKernelID, pKernelPatch);
          }
          // Append/Patch kernel from internal cache
          else
          {
              res = Kdll_AppendKernel(pKernelCache, pSearchState, *pKernelID, pKernelPatch);
          }
  
          if (!res)
          {
              VPHAL_RENDER_ASSERTMESSAGE("Failed to build kernel ID %d.", pSearchState->KernelID[offset]);
              return false;
          }
          else
          {
              Kdll_CacheEntry *kernels = (*pGroupID == GROUP_CUSTOM) ? &pCustomCache->pCacheEntries[*pKernelID] : &pKernelCache->pCacheEntries[*pKernelID];
              VPHAL_RENDER_NORMALMESSAGE("Component kernels [%d]: %s", *pKernelID, kernels->szName);
          }
      }
  
      // Resolve kernel dependencies
      res = Kdll_ResolveKernelDependencies(pState, pSearchState);
      if (!res)
      {
          VPHAL_RENDER_ASSERTMESSAGE("Failed to resolve symbols.");
          return false;
      }
  
      return true;
  }
  
  //---------------------------------------------------------------------------------------
  // KernelDll_StartKernelSearch - Starts kernel search
  //
  // Parameters:
  //    Kdll_State       *pState       - [in]     Dynamic Linking State
  //    Kdll_FilterEntry *pFilter      - [in]     Search filter (array of search entries)
  //    int               iFilterSize  - [in]     Search filter size
  //    Kdll_SearchState *pSearchState - [in/out] Kernel search state
  //
  // Output: none
  //---------------------------------------------------------------------------------------
  void KernelDll_StartKernelSearch(
      Kdll_State       *pState,
      Kdll_SearchState *pSearchState,
      Kdll_FilterEntry *pFilter,
      int32_t          iFilterSize,
      uint32_t         uiIs64BInstrEnabled)
  {
      int32_t nLayer;
  
      VPHAL_RENDER_FUNCTION_ENTER;
  
      // Reset all states
      MOS_ZeroMemory(pSearchState, sizeof(Kdll_SearchState));
  
      // Setup KDLL state
      pSearchState->pKdllState    = pState;     // KDLL state
  
      // Cleanup kernel table
      pSearchState->KernelCount   = 0;          // # of kernels
  
      // Cleanup patch data
      memset(pSearchState->Patches ,  0, sizeof(pSearchState->Patches));
      memset(pSearchState->PatchID , -1, sizeof(pSearchState->PatchID));
      pSearchState->PatchCount = 0;
  
      // Copy original filter; filter will be modified as part of the search
      if (pFilter && iFilterSize > 0)
      {
          MOS_SecureMemcpy(pSearchState->Filter, iFilterSize * sizeof(Kdll_FilterEntry), pFilter, iFilterSize * sizeof(Kdll_FilterEntry));
          pSearchState->pFilter      = pSearchState->Filter;
          pSearchState->iFilterSize  = iFilterSize;
  
          for (nLayer = 0; nLayer < iFilterSize; nLayer++)
          {
              // DScale Kernels are enabled for all gen9 stepping.
              //For Gen9+, kernel don't support sublayer DScale+rotation
              //Sampler_unorm does not support Y410/RGB10, we need to use sampler_16 to support Y410/RGB10
              if (!pFilter[nLayer].bEnableDscale &&
                  (!pFilter[nLayer].bWaEnableDscale ||
                  (pFilter[nLayer].layer == Layer_SubVideo &&
                   pFilter[nLayer].rotation != VPHAL_ROTATION_IDENTITY)))
              {
                  if (pFilter[nLayer].sampler == Sample_Scaling_034x)
                  {
                      pSearchState->pFilter[nLayer].sampler = Sample_Scaling;
                  }
                  else if (pFilter[nLayer].sampler == Sample_iScaling_034x)
                  {
                      pSearchState->pFilter[nLayer].sampler = Sample_iScaling;
                  }
                  else if (pFilter[nLayer].sampler == Sample_iScaling_AVS)
                  {
                      pSearchState->pFilter[nLayer].sampler = Sample_iScaling_AVS;
                  }
              }
          }
  
          // Copy the render target format
          pSearchState->target_format = pSearchState->pFilter[iFilterSize - 1].format;
  
          // Copy the render target tile type
          pSearchState->target_tiletype = pSearchState->pFilter[iFilterSize - 1].tiletype;
  
          // Indicate whether to use 64B save kernel for render target surface
          if (uiIs64BInstrEnabled                               &&
              ((pSearchState->target_tiletype == MOS_TILE_X)    ||
              (pSearchState->target_tiletype  == MOS_TILE_LINEAR)))
          {
              pSearchState->b64BSaveEnabled = true;
          }
      }
  }
  
  //---------------------------------------------------------------------------------------
  // KernelDll_SetupFunctionPointers - Setup Function pointers based on platform
  //
  // Parameters:
  //    char  *pState    - [in/out] Kernel Dll state
  //           platform  - [in] platform
  //
  // Output: true  - Function pointers are set
  //         false - Failed to setup function pointers (invalid platform)
  //-----------------------------------------------------------------------------------------
  static bool KernelDll_SetupFunctionPointers(
      Kdll_State  *pState,
      void        (*ModifyFunctionPointers)(PKdll_State))
  {
      VPHAL_RENDER_FUNCTION_ENTER;
  
      pState->pfnSetupCSC          = KernelDll_SetupCSC;
      pState->pfnMapCSCMatrix      = KernelDll_MapCSCMatrix;
      pState->pfnFindRule          = KernelDll_FindRule;
      pState->pfnUpdateState       = KernelDll_UpdateState;
      pState->pfnSearchKernel      = KernelDll_SearchKernel;
      pState->pfnBuildKernel       = KernelDll_BuildKernel;
      pState->pfnStartKernelSearch = KernelDll_StartKernelSearch;
  
      if (ModifyFunctionPointers != nullptr)
      {
          (*ModifyFunctionPointers)(pState);
      }
  
  #if EMUL || VPHAL_LIB
      // Disable callbacks
      pState->pToken = nullptr;
      pState->pfnCbListKernel = nullptr;
      pState->pfnCbSearchSate = nullptr;
  #endif // EMUL || VPHAL_LIB
  
      return true;
  }
  
  /*----------------------------------------------------------------------------
  | Name      : KernelDll_SetupCSC
  | Purpose   : Defines CSC conversions necessary for a given filter
  |
  | Input     : pState       - Kernel Dll state
  |             pSearchState - current DL search state
  |
  | Return    :
  \---------------------------------------------------------------------------*/
  bool KernelDll_SetupCSC(
      Kdll_State       *pState,
      Kdll_SearchState *pSearchState)
  {
      int i, m;                                       // Integer iterators
  
      bool bCoeffID_0_Used = false;
  
      VPHAL_CSPACE     cspace      = CSpace_None;      // Current ColorSpace
      VPHAL_CSPACE     out_cspace  = CSpace_None;      // Render Target CS
      VPHAL_CSPACE     main_cspace = CSpace_None;      // Main video CS
      VPHAL_CSPACE     sel_cspace  = CSpace_Any;       // Selected CS
  
      Kdll_FilterEntry *pFilter;                      // Current Filter information
      int               iFilterSize = pSearchState->iFilterSize;
      Kdll_CSC_Params  *pCSC        = &pSearchState->CscParams;
  
      int             csc_count;                      // Number of CSC operations
      int             matrix_count;                   // Number of Matrices in use
      int             procamp_count = 0;              // Number of PA operations
      int             sel_csc_count = -1;             // Minimum number of CSC operations
      int             iCoeffID;                       // coeffID for layers other than main video
      uint8_t         cspace_in_use[CSpace_Count];    // Color Spaces in use
  
      Kdll_CSC_Matrix   curr_matrix;
      Kdll_CSC_Matrix  *matrix   = pCSC->Matrix;      // Color Space conversion matrix
      uint8_t          *matrixID = pCSC->MatrixID;    // CSC coefficient allocation table
  
      // Clear all CSC matrices
      MOS_ZeroMemory(matrix, sizeof(pCSC->Matrix));
      memset(matrixID, DL_CSC_DISABLED, sizeof(pCSC->MatrixID));
      memset(pCSC->PatchMatrixID, DL_CSC_DISABLED, sizeof(pCSC->PatchMatrixID));
      pCSC->PatchMatrixNum = 0;
  
      // Clear array of color spaces in use
      MOS_ZeroMemory(cspace_in_use, sizeof(cspace_in_use));
  
      //---------------------------------------------------------------//
      // Collect information about Color Spaces in use
      // Get Primary Video and Render Target Color Spaces
      // Force xvYCC passthrough if enabled
      //---------------------------------------------------------------//
      for (i = iFilterSize, pFilter = pSearchState->Filter; i > 0; i--, pFilter++)
      {
          // Disable Procamp for all layers except Main Video
          // Disable Procamp if source is RGB
          if (pFilter->layer  != Layer_MainVideo ||
              pFilter->cspace == CSpace_sRGB     ||
              pFilter->cspace == CSpace_stRGB)
          {
              pFilter->procamp = DL_PROCAMP_DISABLED;
          }
  
          // Count number of procamp operations (limited by number of independent coefficients)
          // Ignore layers with palletized/constant colors
          if (pFilter->procamp != DL_PROCAMP_DISABLED &&
              pFilter->cspace  != CSpace_Any)
          {
              procamp_count++;
          }
  
          // Set xvYCC passthrough mode
          if (pFilter->cspace == CSpace_xvYCC709 ||
              pFilter->cspace == CSpace_xvYCC601)
          {
              sel_cspace = pFilter->cspace;
          }
  
          // Get Main Video color space
          if (pFilter->layer == Layer_MainVideo)
          {
              main_cspace = pFilter->cspace;
          }
  
          // Get Render Target color space
          if (pFilter->layer == Layer_RenderTarget)
          {
              // Target is sRGB/stRGB
              if (!KernelDll_IsYUVFormat(pFilter->format))
              {
                  // Disable xvYCC passthrough (sRGB cannot have extended gamut)
                  sel_cspace      = CSpace_Any;
              }
              out_cspace = pFilter->cspace;
          }
  
          // Mark color spaces in use for search that follows
          if (pFilter->cspace > CSpace_Any && pFilter->cspace < CSpace_Count)
          {
              cspace_in_use[pFilter->cspace] = 1;
          }
      }
  
      // Check max number of procamp operations
      if (procamp_count > DL_PROCAMP_MAX)
      {
          return false;
      }
  
      //---------------------------------------------------------------//
      // Search Color Space that provides minimum number of CSC conversions
      // If there are multiple solutions, select main video cspace (quality)
      //---------------------------------------------------------------//
      if (sel_cspace == CSpace_Any)
      {
          int cs;
          for (cs = (CSpace_Any + 1); cs < CSpace_Count; cs++)
          {
              // Skip color spaces not in use
              cspace = (VPHAL_CSPACE) cs;
              if (!cspace_in_use[cspace])
              {
                  continue;
              }
  
              // xvYCC and BT are treated as same for CSC considerations (BT.x to xvYCC.x matrix is I)
              cspace = KernelDll_TranslateCspace(cspace);
  
              // Count # of CS conversions and matrices
              csc_count = 0;
              for (i = iFilterSize, pFilter = pSearchState->Filter; i > 0; i--, pFilter++)
              {
                  // Ignore layers where the Color Space may be set in software (colorfill, palletized)
                  if (pFilter->cspace == CSpace_Any)
                  {
                      continue;
                  }
  
                  // Check if CSC/PA is required
                  if (KernelDll_TranslateCspace(pFilter->cspace) != cspace ||
                      pFilter->procamp != DL_PROCAMP_DISABLED)
                  {
                      csc_count++;
                  }
              }
  
              // Save best choice as requiring minimum number of CSC operations
              if ((sel_csc_count < 0) ||                                     // Initial value
                  (csc_count <  sel_csc_count) ||                            // Minimum number of CSC operations
                  (csc_count == sel_csc_count && cs == main_cspace) )        // Use main cspace as default if same CSC count
              {
                  sel_cspace    = cspace;
                  sel_csc_count = csc_count;
              }
          }
      }
  
      // Due to put the colorfill behind CSC, so Src0 cspace needs to change
      // to selspace in order to fill colorfill values correctly.
      pState->colorfill_cspace = sel_cspace;
  
      // color space is selected by now... setup CSC matrices
      matrix_count  = 0;
      iCoeffID = 1;
      for (i = iFilterSize, pFilter = pSearchState->Filter; i > 0; i--, pFilter++)
      {
          // Setup CSC for palettized/colorfill layers
          if (pFilter->cspace == CSpace_Any)
          {
              // Set Color Space and format (for software)
              if (pFilter->format == Format_Any)
              {
                  pFilter->format = KernelDll_IsCspace(sel_cspace, CSpace_YUV) ? Format_AYUV : Format_A8R8G8B8;
              }
  
              pFilter->cspace = sel_cspace;
              pFilter->matrix = DL_CSC_DISABLED;
          }
          else
          {
              // Setup CSC parameters: SrcSpace is the layer color space,
              //                       DstSpace is the internal color space selected
              curr_matrix.SrcSpace   = KernelDll_TranslateCspace(pFilter->cspace);
              curr_matrix.DstSpace   = KernelDll_TranslateCspace(sel_cspace);
              curr_matrix.iProcampID = pFilter->procamp;
  
              // Check if CSC is necessary
              if (curr_matrix.SrcSpace   == curr_matrix.DstSpace &&
                  curr_matrix.iProcampID == DL_PROCAMP_DISABLED)
              {
                  pFilter->matrix = DL_CSC_DISABLED;
                  curr_matrix.iCoeffID = CoeffID_None;
                  continue;
              }
  
              // Reserve CoeffID_0 for main video - CoeffID_0 gets CSC coeff from static parameters
              // If main video doesn't use CoeffID_0, assign to RT
              if ( (pFilter->layer == Layer_MainVideo) ||
                   (pFilter->layer == Layer_RenderTarget))
              {
                  if (bCoeffID_0_Used)
                  {
                      curr_matrix.iCoeffID = (Kdll_CoeffID)iCoeffID++;
                  }
                  else
                  {
                      curr_matrix.iCoeffID = CoeffID_0;
                      bCoeffID_0_Used = true;
                  }
              }
              else
              {
                  curr_matrix.iCoeffID = (Kdll_CoeffID)iCoeffID++;
              }
  
              // CSC at the target layer is from internal cspace (SrcSpace)
              //                              to external cspace (DstCspace)
              if (pFilter->layer == Layer_RenderTarget)
              {
                  VPHAL_CSPACE      aux = curr_matrix.SrcSpace;
                  curr_matrix.SrcSpace = curr_matrix.DstSpace;
                  curr_matrix.DstSpace = aux;
              }
  
              // Search CSC matrix - avoid duplicated CSC matrices
              for (m = 0; m < matrix_count; m++)
              {
                  if (curr_matrix.SrcSpace   == matrix[m].SrcSpace &&
                      curr_matrix.DstSpace   == matrix[m].DstSpace &&
                      curr_matrix.iProcampID == matrix[m].iProcampID)
                  {
                      break;
                  }
              }
  
              // Check limit
              if (m == matrix_count)
              {
                  // Exceeded number of CSC matrices allowed
                  if (matrix_count == DL_CSC_MAX)
                  {
                      return false;
                  }
  
                  matrix[m].bInUse     = true;
                  matrix[m].SrcSpace   = curr_matrix.SrcSpace;
                  matrix[m].DstSpace   = curr_matrix.DstSpace;
                  matrix[m].iProcampID = curr_matrix.iProcampID;
                  matrix[m].iCoeffID   = curr_matrix.iCoeffID;
  
                  // Calculate coefficients for the first time
                  KernelDll_UpdateCscCoefficients(pState, &matrix[m]);
  
                  // Next matrix
                  matrix_count++;
              }
  
              // point to the matrix
              pFilter->matrix = m;
          }
      }
  
      // Link matrices to kernel coefficients (and vice-versa)
      matrix        = pCSC->Matrix;
      for (m = 0; m < matrix_count; m++, matrix++)
      {
          // Coefficient table points to matrix index
          matrixID[matrix->iCoeffID] = (uint8_t)m;
      }
  
      // Save selected color space
      pCSC->ColorSpace = sel_cspace;
  
      return true;
  }
  
  //---------------------------------------------------------------------------------------
  // Kdll_AddKernelList - Add kernel to CM FC kernel list
  //
  // Parameters:
  //    Kdll_KernelCache *pKernelCache     - [in]     Component kernel cache
  //    Kdll_KernelCache *pCmFcPatchCache  - [in]     Component kernel patch data cache
  //    Kdll_SearchState *pSearchState     - [in/out] Kernel search state
  //    Kdll_PatchData   *pKernelPatch     - [in]     Kernel Patch data
  //    void             *pPatchDst         - [in]     Patch data Dst address
  //    int32_t          iKUID             - [in]     Kernel Unique ID
  //    cm_fc_kernel_t   *Cm_Fc_Kernels    - [in/out] CM FC Kernels
  //
  // Output: true if suceeded, false otherwise
  //---------------------------------------------------------------------------------------
  bool Kdll_AddKernelList(Kdll_KernelCache *pKernelCache,
                          Kdll_KernelCache *pCmFcPatchCache,
                          Kdll_SearchState *pSearchState,
                          int32_t           iKUID,
                          Kdll_PatchData   *pKernelPatch,
                          void             *pPatchDst,
                          cm_fc_kernel_t   *Cm_Fc_Kernels)
  {
      Kdll_State      *pState;
      Kdll_Symbol     *pSymbols;
      Kdll_CacheEntry *kernels;
      Kdll_CacheEntry *pPatch;
      Kdll_LinkData   *link;
      Kdll_LinkData   *liSearch_reloc;
      int             *size;
      int             *left;
      int             dwSize;
      int             i;
      int             base;
      bool            bInline;
      bool            res;
  
      VPHAL_RENDER_FUNCTION_ENTER;
  
      res = false;
  
      // Check if Kernel ID is valid
      if (iKUID >= pKernelCache->iCacheEntries)
      {
          VPHAL_RENDER_NORMALMESSAGE("invalid Kernel ID %d.", iKUID);
          goto finish;
      }
  
      // Get KDLL state
      pState = pSearchState->pKdllState;
  
      // Get current combined kernel
      size = &pSearchState->KernelSize;
      left = &pSearchState->KernelLeft;
      pSymbols = &pSearchState->KernelLink;
      base = (*size) >> 2;
  
      // Find selected kernel/patch and kernel size; check if there is enough space 
      kernels = &pKernelCache->pCacheEntries[iKUID];
      pPatch = &pCmFcPatchCache->pCacheEntries[iKUID];
      dwSize = kernels->iSize;
      if (*left < dwSize)
      {
          VPHAL_RENDER_NORMALMESSAGE("exceeded maximum kernel size.");
          goto finish;
      }
  
      // Check if there is enough space for symbols
      if (pSymbols->dwCount + kernels->nLink >= pSymbols->dwSize)
      {
          VPHAL_RENDER_NORMALMESSAGE("exceeded maximum numbers of symbols to resolve.");
          goto finish;
      }
  
  #if EMUL || VPHAL_LIB
      VPHAL_RENDER_NORMALMESSAGE("%s.", kernels->szName);
  
      if (pState->pfnCbListKernel)
      {
          pState->pfnCbListKernel(pState->pToken, kernels->szName);
      }
  #elif _DEBUG || _RELEASE_INTERNAL // EMUL || VPHAL_LIB
      VPHAL_RENDER_NORMALMESSAGE("%s.", kernels->szName);
  #endif // _DEBUG
  
      // Append symbols to resolve, relocate symbols
      link = kernels->pLink;
      liSearch_reloc = pSymbols->pLink + pSymbols->dwCount;
  
      bInline = false;
      if (link)
      {
          for (i = kernels->nLink; i > 0; i--, link++)
          {
              if (link->bInline)
              {
                  // Inline code included
                  if (!link->bExport)
                  {
                      bInline = true;
                  }
              }
              else
              {
                  *liSearch_reloc = *link;
                  liSearch_reloc->dwOffset += base;
                  liSearch_reloc++;
  
                  pSymbols->dwCount++;
              }
          }
      }
  
      *size += dwSize;
      *left -= dwSize;
      Cm_Fc_Kernels->binary_buf = (const char *)kernels->pBinary;
      Cm_Fc_Kernels->binary_size = kernels->iSize;
      Cm_Fc_Kernels->patch_buf = (const char *)pPatch->pBinary;
      Cm_Fc_Kernels->patch_size = pPatch->iSize;
      res = true;
  
  finish:
      return res;
  }
  
  //---------------------------------------------------------------------------------------
  // KernelDll_BuildKernel_CmFc - Build CM based FC combine Kernel
  //
  // Parameters: [in/out] pState        - Pointer to Kernel binary file loaded in sys memory
  //             [in/out] pSearchState       - Kernel file size
  //
  // Output: bool
  //         TRUE - Successful FALSE - Failed
  //-----------------------------------------------------------------------------------------
  bool KernelDll_BuildKernel_CmFc(Kdll_State *pState, Kdll_SearchState *pSearchState)
  {
      Kdll_KernelCache *pKernelCache = &pState->ComponentKernelCache;
      Kdll_KernelCache *pPatchCache = &pState->CmFcPatchCache;
      Kdll_KernelCache *pCustomCache = pState->pCustomKernelCache;
      bool              res;
      int32_t           offset = 0;
      int32_t           *pKernelID, *pPatchID;
      uint8_t           *pPatchData;
      Kdll_PatchData   *pKernelPatch;
      uint8_t          *kernel = pSearchState->Kernel;
      Kdll_Symbol      *pSymbols = &pSearchState->KernelLink;
      uint32_t          nExports = pKernelCache->nExports;
      Kdll_LinkData    *pExports = pKernelCache->pExports;
      Kdll_LinkData    *pLink;
      int32_t           iOffset;
      uint32_t          dwResolveOffset[DL_MAX_EXPORT_COUNT];
      uint32_t          dwTotalKernelCount;
      size_t            stEstimatedKernelSize;
      int32_t           iKUID;
      bool              bResolveDone;
      int32_t           i;
      cm_fc_kernel_t    Cm_Fc_kernels[DL_MAX_KERNELS];
  
      VPHAL_RENDER_FUNCTION_ENTER;
  
      // Disable pop-up box window for STL assertion to avoid VM hang in auto test.
  #if (!LINUX)
      ::SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX);
  #if defined(_MSC_VER)
      ::_set_error_mode(_OUT_TO_STDERR);
      _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
      _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
      _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
      _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
      _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
      _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
  #endif
  #endif
  
      pSearchState->KernelLink.dwSize = DL_MAX_SYMBOLS;
      pSearchState->KernelLink.dwCount = 0;
      pSearchState->KernelLink.pLink = pSearchState->LinkArray;
      pSearchState->KernelSize = 0;
      pSearchState->KernelLeft = sizeof(pSearchState->Kernel);
      pSearchState->KernelLink.dwCount = 0;
  
      MOS_ZeroMemory(Cm_Fc_kernels, sizeof(Cm_Fc_kernels));
      dwTotalKernelCount = 0;
      stEstimatedKernelSize = 0;
  
  #if EMUL || VPHAL_LIB || _DEBUG
      VPHAL_RENDER_NORMALMESSAGE("Component Kernels:");
  #endif // EMUL || VPHAL_LIB || _DEBUG
  
      pKernelID = pSearchState->KernelID;
      pPatchID = pSearchState->PatchID;
      pPatchData = nullptr;
  
      for (offset = 0; offset < pSearchState->KernelCount; offset++, pKernelID++, pPatchID++, dwTotalKernelCount++)
      {
          // Get patch information associated with the kernel
          pKernelPatch = (*pPatchID >= 0) ? &(pSearchState->Patches[*pPatchID]) : nullptr;
  
          // Append/Patch kernel from internal cache
          res = Kdll_AddKernelList(pKernelCache, pPatchCache, pSearchState, *pKernelID, pKernelPatch, pPatchData, &Cm_Fc_kernels[dwTotalKernelCount]);
  
          stEstimatedKernelSize += Cm_Fc_kernels[dwTotalKernelCount].binary_size;
  
          if (*pKernelID == IDR_VP_EOT)
          {
              dwTotalKernelCount--;
          }
  
          if (!res)
          {
              VPHAL_RENDER_NORMALMESSAGE("Failed to build kernel ID %d.", pSearchState->KernelID[offset]);
              res = false;
              goto finish;
          }
      }
  
      // Resolve kernel dependencies
      MOS_ZeroMemory(dwResolveOffset, sizeof(dwResolveOffset));
  
      do
      {
          // Update exports
          for (pLink = pSymbols->pLink, i = pSymbols->dwCount; i > 0; i--, pLink++)
          {
              if (pLink->bExport)
              {
                  dwResolveOffset[pLink->iLabelID] = pLink->dwOffset;
              }
          }
  
          bResolveDone = true;
          for (pLink = pSymbols->pLink, i = pSymbols->dwCount; i > 0; i--, pLink++)
          {
              // validate label
              if (pLink->iLabelID > nExports ||              // invalid label
                  pExports[pLink->iLabelID].bExport == 0)    // label not in the export table
              {
                  VPHAL_RENDER_NORMALMESSAGE("Invalid/unresolved label %d.", pLink->iLabelID);
                  res = false;
                  goto finish;
              }
  
              // load dependencies
              if (!pLink->bExport && !dwResolveOffset[pLink->iLabelID])
              {
                  // set flag for another pass as newly loaded 
                  // kernels may contain dependencies of their own
                  bResolveDone = false;
  
                  // Add dependencies to kernel list
                  iKUID = pExports[pLink->iLabelID].iKUID;
                  res = Kdll_AddKernelList(pKernelCache, pPatchCache, pSearchState, iKUID, nullptr, nullptr, &Cm_Fc_kernels[dwTotalKernelCount]);
  
                  if (!res)
                  {
                      VPHAL_RENDER_NORMALMESSAGE("Failed to build kernel ID %d.", pSearchState->KernelID[offset]);
                      res = false;
                      goto finish;
                  }
  
                  dwTotalKernelCount++;
  
                  // Restart
                  break;
              }
          } // for
      } while (!bResolveDone);
  
      if (stEstimatedKernelSize > DL_MAX_KERNEL_SIZE)
      {
          res = false;
          VPHAL_RENDER_NORMALMESSAGE("Kernel size exceeded kdll limitatin.");
          goto finish;
      }
  
      stEstimatedKernelSize = DL_MAX_KERNEL_SIZE;
  
      // Get combine kernel binary from CMFC lib
      if (CM_FC_OK != cm_fc_combine_kernels(dwTotalKernelCount, Cm_Fc_kernels, (char *)pSearchState->Kernel, &stEstimatedKernelSize, nullptr))
      {
          res = false;
          VPHAL_RENDER_NORMALMESSAGE("cm_fc_combine_kernels() function call failed.");
          goto finish;
      }
  
      // Get combine kernel binary size from CMFC lib
      pSearchState->KernelSize = (int) stEstimatedKernelSize;
  
      res = true;
  
  finish:
      return res;
  }
  
  //---------------------------------------------------------------------------------------
  // KernelDll_SetupFunctionPointers - Setup Function pointers based on platform
  //
  // Parameters:
  //    KdllState  *pState    - [in/out] Kernel Dll state
  //
  // Output: true  - Function pointers are set
  //         false - Failed to setup function pointers (invalid platform)
  //-----------------------------------------------------------------------------------------
  bool KernelDll_SetupFunctionPointers_Ext(
      Kdll_State  *pState)
  {
      VPHAL_RENDER_FUNCTION_ENTER;
  
      if (pState->bEnableCMFC)
      {
          pState->pfnBuildKernel      = KernelDll_BuildKernel_CmFc;
      }
  
      return true;
  }
  
  #ifdef __cplusplus
  }
  #endif // __cplusplus
  