<div dir="ltr">From 591add8daaaafdccb2fcbd09c29147b016f01424 Mon Sep 17 00:00:00 2001<br>From: AnusuyaKumarasamy <<a href="mailto:anusuya.kumarasamy@multicorewareinc.com" target="_blank">anusuya.kumarasamy@multicorewareinc.com</a>><br>Date: Thu, 25 Jul 2024 16:49:08 +0530<br>Subject: [PATCH 6/9] Fix run to run variation issue<br><br>---<br> source/common/cudata.cpp    |   8 ++-<br> source/common/cudata.h      |  11 +++-<br> source/common/frame.cpp     |   3 +-<br> source/encoder/analysis.cpp | 102 +++++++++++++++---------------------<br> source/encoder/analysis.h   |   7 +--<br> source/encoder/search.cpp   |  52 +++++++++---------<br> source/encoder/search.h     |  14 +++--<br> 7 files changed, 96 insertions(+), 101 deletions(-)<br><br>diff --git a/source/common/cudata.cpp b/source/common/cudata.cpp<br>index 23f95288e..395b80fcd 100644<br>--- a/source/common/cudata.cpp<br>+++ b/source/common/cudata.cpp<br>@@ -325,7 +325,7 @@ void CUData::initCTU(const Frame& frame, uint32_t cuAddr, int qp, uint32_t first<br> }<br> <br> // initialize Sub partition<br>-void CUData::initSubCU(const CUData& ctu, const CUGeom& cuGeom, int qp)<br>+void CUData::initSubCU(const CUData& ctu, const CUGeom& cuGeom, int qp, MV lastIntraBCMv[2])<br> {<br>     m_absIdxInCTU   = cuGeom.absPartIdx;<br>     m_encData       = ctu.m_encData;<br>@@ -362,6 +362,12 @@ void CUData::initSubCU(const CUData& ctu, const CUGeom& cuGeom, int qp)<br>     /* initialize the remaining CU data in one memset */<br>     memset(m_predMode, 0, (ctu.m_chromaFormat == X265_CSP_I400 ? BytesPerPartition - 13 : BytesPerPartition - 9) * m_numPartitions);<br>     memset(m_distortion, 0, m_numPartitions * sizeof(sse_t));<br>+<br>+    if (lastIntraBCMv)<br>+    {<br>+        for (int i = 0; i < 2; i++)<br>+            m_lastIntraBCMv[i] = lastIntraBCMv[i];<br>+    }<br> }<br> <br> /* Copy the results of a sub-part (split) CU to the parent CU */<br>diff --git a/source/common/cudata.h b/source/common/cudata.h<br>index 362df5786..69cfb4947 100644<br>--- a/source/common/cudata.h<br>+++ b/source/common/cudata.h<br>@@ -37,6 +37,7 @@ class FrameData;<br> class Slice;<br> struct TUEntropyCodingParameters;<br> struct CUDataMemPool;<br>+struct IBC;<br> <br> enum PartSize<br> {<br>@@ -120,6 +121,14 @@ struct InterNeighbourMV<br>     union { int16_t refIdx[2]; int32_t unifiedRef; };<br> };<br> <br>+struct IBC<br>+{<br>+    int             m_numBVs;<br>+    int             m_numBV16s;<br>+    MV              m_BVs[64];<br>+    MV              m_lastIntraBCMv[2];<br>+};<br>+<br> typedef void(*cucopy_t)(uint8_t* dst, uint8_t* src); // dst and src are aligned to MIN(size, 32)<br> typedef void(*cubcast_t)(uint8_t* dst, uint8_t val); // dst is aligned to MIN(size, 32)<br> <br>@@ -240,7 +249,7 @@ public:<br>     static void calcCTUGeoms(uint32_t ctuWidth, uint32_t ctuHeight, uint32_t maxCUSize, uint32_t minCUSize, CUGeom cuDataArray[CUGeom::MAX_GEOMS]);<br> <br>     void     initCTU(const Frame& frame, uint32_t cuAddr, int qp, uint32_t firstRowInSlice, uint32_t lastRowInSlice, uint32_t lastCUInSlice);<br>-    void     initSubCU(const CUData& ctu, const CUGeom& cuGeom, int qp);<br>+    void     initSubCU(const CUData& ctu, const CUGeom& cuGeom, int qp, MV lastIntraBCMv[2] = 0);<br>     void     initLosslessCU(const CUData& cu, const CUGeom& cuGeom);<br> <br>     void     copyPartFrom(const CUData& cu, const CUGeom& childGeom, uint32_t subPartIdx);<br>diff --git a/source/common/frame.cpp b/source/common/frame.cpp<br>index 6140021aa..b561a67b1 100644<br>--- a/source/common/frame.cpp<br>+++ b/source/common/frame.cpp<br>@@ -315,8 +315,7 @@ void Frame::destroy()<br>         X265_FREE(m_isSubSampled);<br>     }<br> <br>-    int numVersion = !!m_param->bEnableSCC ? 2 : 1;<br>-    for (int i = 0; i < numVersion; i++)<br>+    for (int i = 0; i < !!m_param->bEnableSCC + 1; i++)<br>     {<br>         if (m_reconPic[i])<br>         {<br>diff --git a/source/encoder/analysis.cpp b/source/encoder/analysis.cpp<br>index 789069c4c..033c781a9 100644<br>--- a/source/encoder/analysis.cpp<br>+++ b/source/encoder/analysis.cpp<br>@@ -223,6 +223,9 @@ Mode& Analysis::compressCTU(CUData& ctu, Frame& frame, const CUGeom& cuGeom, con<br>     }<br>     ProfileCUScope(ctu, totalCTUTime, totalCTUs);<br> <br>+    memset(m_ibc.m_BVs, 0, sizeof(m_ibc.m_BVs));<br>+    memset(m_ibc.m_lastIntraBCMv, 0, sizeof(m_ibc.m_lastIntraBCMv));<br>+    m_ibc.m_numBV16s = 0; m_ibc.m_numBVs = 0;<br>     if (m_slice->m_sliceType == I_SLICE || (m_param->bEnableSCC && (m_slice->m_numRefIdx[0] == 1) && m_slice->m_refPOCList[0][0] == m_slice->m_poc))<br>     {<br>         x265_analysis_intra_data* intraDataCTU = m_frame->m_analysisData.intraData;<br>@@ -233,7 +236,7 @@ Mode& Analysis::compressCTU(CUData& ctu, Frame& frame, const CUGeom& cuGeom, con<br>             memcpy(ctu.m_partSize, &intraDataCTU->partSizes[ctu.m_cuAddr * numPartition], sizeof(char) * numPartition);<br>             memcpy(ctu.m_chromaIntraDir, &intraDataCTU->chromaModes[ctu.m_cuAddr * numPartition], sizeof(uint8_t) * numPartition);<br>         }<br>-        compressIntraCU(ctu, cuGeom, qp);<br>+        compressIntraCU(ctu, cuGeom, qp, m_ibc);<br>     }<br>     else<br>     {<br>@@ -266,7 +269,7 @@ Mode& Analysis::compressCTU(CUData& ctu, Frame& frame, const CUGeom& cuGeom, con<br>         if (m_param->bIntraRefresh && m_slice->m_sliceType == P_SLICE &&<br>             ctu.m_cuPelX / m_param->maxCUSize >= frame.m_encData->m_pir.pirStartCol<br>             && ctu.m_cuPelX / m_param->maxCUSize < frame.m_encData->m_pir.pirEndCol)<br>-            compressIntraCU(ctu, cuGeom, qp);<br>+            compressIntraCU(ctu, cuGeom, qp, m_ibc);<br>         else if (!m_param->rdLevel)<br>         {<br>             /* In RD Level 0/1, copy source pixels into the reconstructed block so<br>@@ -304,7 +307,7 @@ Mode& Analysis::compressCTU(CUData& ctu, Frame& frame, const CUGeom& cuGeom, con<br>         else if (m_param->rdLevel <= 4)<br>             compressInterCU_rd0_4(ctu, cuGeom, qp);<br>         else<br>-            compressInterCU_rd5_6(ctu, cuGeom, qp);<br>+            compressInterCU_rd5_6(ctu, cuGeom, qp, m_ibc);<br>     }<br> <br>     if (m_param->bEnableRdRefine || m_param->bOptCUDeltaQP)<br>@@ -511,21 +514,12 @@ void Analysis::qprdRefine(const CUData& parentCTU, const CUGeom& cuGeom, int32_t<br>     md.bestMode->reconYuv.copyToPicYuv(*m_frame->m_reconPic[0], parentCTU.m_cuAddr, cuGeom.absPartIdx);<br> }<br> <br>-uint64_t Analysis::compressIntraCU(const CUData& parentCTU, const CUGeom& cuGeom, int32_t qp)<br>+uint64_t Analysis::compressIntraCU(const CUData& parentCTU, const CUGeom& cuGeom, int32_t qp, IBC& ibc)<br> {<br>     uint32_t depth = cuGeom.depth;<br>     ModeDepth& md = m_modeDepth[depth];<br>     md.bestMode = NULL;<br> <br>-    MV lastIntraBCMv[2];<br>-    for (int i = 0; i < 2; i++)<br>-    {<br>-        if (depth == 0)<br>-            lastIntraBCMv[i] = parentCTU.m_lastIntraBCMv[i];<br>-        else<br>-            lastIntraBCMv[i] = tempLastIntraBCMv[i];<br>-    }<br>-<br>     MV iMVCandList[4][10];<br>     memset(iMVCandList, 0, sizeof(MV) * 4 * 10);<br> <br>@@ -584,13 +578,13 @@ uint64_t Analysis::compressIntraCU(const CUData& parentCTU, const CUGeom& cuGeom<br>         double intracost = MAX_DOUBLE;<br>         if (m_param->bEnableSCC)<br>         {<br>-            md.pred[PRED_MERGE_IBC].cu.initSubCU(parentCTU, cuGeom, qp);<br>+            md.pred[PRED_MERGE_IBC].cu.initSubCU(parentCTU, cuGeom, qp, ibc.m_lastIntraBCMv);<br>             checkRDCostIntraBCMerge2Nx2N(md.pred[PRED_MERGE_IBC], cuGeom);<br> <br>             if (!bSkipIntraBlockCopySearch)<br>             {<br>-                md.pred[PRED_IBC_2Nx2N].cu.initSubCU(parentCTU, cuGeom, qp);<br>-                checkIntraBC_rd5_6(md.pred[PRED_IBC_2Nx2N], cuGeom, SIZE_2Nx2N, false, bUse1DSearchFor8x8, tempLastIntraBCMv, &MV(0, 0));<br>+                md.pred[PRED_IBC_2Nx2N].cu.initSubCU(parentCTU, cuGeom, qp, ibc.m_lastIntraBCMv);<br>+                checkIntraBC_rd5_6(md.pred[PRED_IBC_2Nx2N], cuGeom, SIZE_2Nx2N, false, bUse1DSearchFor8x8, &MV(0, 0), ibc);<br>                 checkBestMode(md.pred[PRED_IBC_2Nx2N], depth);<br> <br>                 if (intraBlockCopyFastSearch)<br>@@ -602,13 +596,13 @@ uint64_t Analysis::compressIntraCU(const CUData& parentCTU, const CUGeom& cuGeom<br>                         double dTH3 = max(66 * m_rdCost.m_lambda, 800.0);<br> <br> <br>-                        md.pred[PRED_IBC_Nx2N].cu.initSubCU(parentCTU, cuGeom, qp);<br>-                        checkIntraBC_rd5_6(md.pred[PRED_IBC_Nx2N], cuGeom, SIZE_Nx2N, false, bUse1DSearchFor8x8, tempLastIntraBCMv, &MV(0, 0));<br>+                        md.pred[PRED_IBC_Nx2N].cu.initSubCU(parentCTU, cuGeom, qp, ibc.m_lastIntraBCMv);<br>+                        checkIntraBC_rd5_6(md.pred[PRED_IBC_Nx2N], cuGeom, SIZE_Nx2N, false, bUse1DSearchFor8x8, &MV(0, 0), ibc);<br>                         checkBestMode(md.pred[PRED_IBC_Nx2N], depth);<br>                         intracost = min(intracost, md.pred[PRED_IBC_Nx2N].rdCost);<br> <br>-                        md.pred[PRED_IBC_2NxN].cu.initSubCU(parentCTU, cuGeom, qp);<br>-                        checkIntraBC_rd5_6(md.pred[PRED_IBC_2NxN], cuGeom, SIZE_2NxN, false, bUse1DSearchFor8x8, tempLastIntraBCMv, &MV(0, 0));<br>+                        md.pred[PRED_IBC_2NxN].cu.initSubCU(parentCTU, cuGeom, qp, ibc.m_lastIntraBCMv);<br>+                        checkIntraBC_rd5_6(md.pred[PRED_IBC_2NxN], cuGeom, SIZE_2NxN, false, bUse1DSearchFor8x8, &MV(0, 0), ibc);<br>                         checkBestMode(md.pred[PRED_IBC_2NxN], depth);<br>                         intracost = min(intracost, md.pred[PRED_IBC_2NxN].rdCost);<br>                     }<br>@@ -616,11 +610,11 @@ uint64_t Analysis::compressIntraCU(const CUData& parentCTU, const CUGeom& cuGeom<br>                 else<br>                 {<br>                     md.pred[PRED_IBC_2NxN].cu.initSubCU(parentCTU, cuGeom, qp);<br>-                    checkIntraBC_rd5_6(md.pred[PRED_IBC_2NxN], cuGeom, SIZE_2NxN, false, bUse1DSearchFor8x8, tempLastIntraBCMv, &MV(0, 0));<br>+                    checkIntraBC_rd5_6(md.pred[PRED_IBC_2NxN], cuGeom, SIZE_2NxN, false, bUse1DSearchFor8x8, &MV(0, 0), ibc);<br>                     checkBestMode(md.pred[PRED_IBC_2NxN], depth);<br> <br>                     md.pred[PRED_IBC_Nx2N].cu.initSubCU(parentCTU, cuGeom, qp);<br>-                    checkIntraBC_rd5_6(md.pred[PRED_IBC_Nx2N], cuGeom, SIZE_Nx2N, false, bUse1DSearchFor8x8, tempLastIntraBCMv, &MV(0, 0));<br>+                    checkIntraBC_rd5_6(md.pred[PRED_IBC_Nx2N], cuGeom, SIZE_Nx2N, false, bUse1DSearchFor8x8, &MV(0, 0), ibc);<br>                     checkBestMode(md.pred[PRED_IBC_Nx2N], depth);<br>                 }<br>             }<br>@@ -746,12 +740,9 @@ uint64_t Analysis::compressIntraCU(const CUData& parentCTU, const CUGeom& cuGeom<br>                 if (m_slice->m_pps->bUseDQP && nextDepth <= m_slice->m_pps->maxCuDQPDepth)<br>                     nextQP = setLambdaFromQP(parentCTU, calculateQpforCuSize(parentCTU, childGeom));<br> <br>-                for (int i = 0; i < 2; i++)<br>-                    tempLastIntraBCMv[i] = lastIntraBCMv[i];<br>-<br>                 if (m_param->bEnableSplitRdSkip)<br>                 {<br>-                    curCost += compressIntraCU(parentCTU, childGeom, nextQP);<br>+                    curCost += compressIntraCU(parentCTU, childGeom, nextQP, ibc);<br>                     if (m_modeDepth[depth].bestMode && curCost > m_modeDepth[depth].bestMode->rdCost)<br>                     {<br>                         skipSplitCheck = 1;<br>@@ -759,13 +750,13 @@ uint64_t Analysis::compressIntraCU(const CUData& parentCTU, const CUGeom& cuGeom<br>                     }<br>                 }<br>                 else<br>-                    compressIntraCU(parentCTU, childGeom, nextQP);<br>+                    compressIntraCU(parentCTU, childGeom, nextQP, ibc);<br> <br>                 if (nd.bestMode->cu.m_lastIntraBCMv[0].x != 0 || nd.bestMode->cu.m_lastIntraBCMv[0].y != 0)<br>                 {<br>                     for (int i = 0; i < 2; i++)<br>                     {<br>-                        lastIntraBCMv[i] = nd.bestMode->cu.m_lastIntraBCMv[i];<br>+                        ibc.m_lastIntraBCMv[i] = nd.bestMode->cu.m_lastIntraBCMv[i];<br>                     }<br>                 }<br> <br>@@ -1303,7 +1294,7 @@ uint32_t Analysis::compressInterCU_dist(const CUData& parentCTU, const CUGeom& c<br> SplitData Analysis::compressInterCU_rd0_4(const CUData& parentCTU, const CUGeom& cuGeom, int32_t qp)<br> {<br>     if (parentCTU.m_vbvAffected && calculateQpforCuSize(parentCTU, cuGeom, 1))<br>-        return compressInterCU_rd5_6(parentCTU, cuGeom, qp);<br>+        return compressInterCU_rd5_6(parentCTU, cuGeom, qp, m_ibc);<br> <br>     uint32_t depth = cuGeom.depth;<br>     uint32_t cuAddr = parentCTU.m_cuAddr;<br>@@ -2004,7 +1995,7 @@ SplitData Analysis::compressInterCU_rd0_4(const CUData& parentCTU, const CUGeom&<br>     return splitCUData;<br> }<br> <br>-SplitData Analysis::compressInterCU_rd5_6(const CUData& parentCTU, const CUGeom& cuGeom, int32_t qp)<br>+SplitData Analysis::compressInterCU_rd5_6(const CUData& parentCTU, const CUGeom& cuGeom, int32_t qp, IBC& ibc)<br> {<br>     if (parentCTU.m_vbvAffected && !calculateQpforCuSize(parentCTU, cuGeom, 1))<br>         return compressInterCU_rd0_4(parentCTU, cuGeom, qp);<br>@@ -2014,14 +2005,6 @@ SplitData Analysis::compressInterCU_rd5_6(const CUData& parentCTU, const CUGeom&<br>     md.bestMode = NULL;<br> <br>     Mode* interBest; // store the best modes in inter prediction<br>-    MV lastIntraBCMv[2];<br>-    for (int i = 0; i < 2; i++)<br>-    {<br>-        if (depth == 0)<br>-            lastIntraBCMv[i] = parentCTU.m_lastIntraBCMv[i];<br>-        else<br>-            lastIntraBCMv[i] = tempLastIntraBCMv[i];<br>-    }<br> <br>     MV iMVCandList[4][10];<br>     memset(iMVCandList, 0, sizeof(MV) * 4 * 10);<br>@@ -2196,7 +2179,7 @@ SplitData Analysis::compressInterCU_rd5_6(const CUData& parentCTU, const CUGeom&<br>             interBest = md.bestMode;<br>             if (m_param->bEnableSCC)<br>             {<br>-                md.pred[PRED_MERGE_IBC].cu.initSubCU(parentCTU, cuGeom, qp);<br>+                md.pred[PRED_MERGE_IBC].cu.initSubCU(parentCTU, cuGeom, qp, ibc.m_lastIntraBCMv);<br>                 checkRDCostIntraBCMerge2Nx2N(md.pred[PRED_MERGE_IBC], cuGeom);<br>             }<br> <br>@@ -2236,15 +2219,12 @@ SplitData Analysis::compressInterCU_rd5_6(const CUData& parentCTU, const CUGeom&<br>                     if (m_slice->m_pps->bUseDQP && nextDepth <= m_slice->m_pps->maxCuDQPDepth)<br>                         nextQP = setLambdaFromQP(parentCTU, calculateQpforCuSize(parentCTU, childGeom));<br> <br>-                    for (int i = 0; i < 2; i++)<br>-                        tempLastIntraBCMv[i] = lastIntraBCMv[i];<br>-<br>-                    splitData[subPartIdx] = compressInterCU_rd5_6(parentCTU, childGeom, nextQP);<br>+                    splitData[subPartIdx] = compressInterCU_rd5_6(parentCTU, childGeom, nextQP, ibc);<br> <br>                     if (nd.bestMode->cu.m_lastIntraBCMv[0].x != 0 || nd.bestMode->cu.m_lastIntraBCMv[0].y != 0)<br>                     {<br>                         for (int i = 0; i < 2; i++)<br>-                            lastIntraBCMv[i] = nd.bestMode->cu.m_lastIntraBCMv[i];<br>+                            ibc.m_lastIntraBCMv[i] = nd.bestMode->cu.m_lastIntraBCMv[i];<br>                     }<br> <br>                     // Save best CU and pred data for this sub CU<br>@@ -2488,8 +2468,8 @@ SplitData Analysis::compressInterCU_rd5_6(const CUData& parentCTU, const CUGeom&<br> <br>                     if (!bSkipIntraBlockCopySearch)<br>                     {<br>-                        md.pred[PRED_IBC_2Nx2N].cu.initSubCU(parentCTU, cuGeom, qp);<br>-                        checkIntraBC_rd5_6(md.pred[PRED_IBC_2Nx2N], cuGeom, SIZE_2Nx2N, false, bUse1DSearchFor8x8, tempLastIntraBCMv, &MV(0, 0));<br>+                        md.pred[PRED_IBC_2Nx2N].cu.initSubCU(parentCTU, cuGeom, qp, ibc.m_lastIntraBCMv);<br>+                        checkIntraBC_rd5_6(md.pred[PRED_IBC_2Nx2N], cuGeom, SIZE_2Nx2N, false, bUse1DSearchFor8x8, &MV(0, 0), ibc);<br>                         checkBestMode(md.pred[PRED_IBC_2Nx2N], depth);<br> <br>                         if (intraBlockCopyFastSearch)<br>@@ -2500,12 +2480,12 @@ SplitData Analysis::compressInterCU_rd5_6(const CUData& parentCTU, const CUGeom&<br>                                 double dTH2 = max(60 * m_rdCost.m_lambda, 56.0);<br>                                 double dTH3 = max(66 * m_rdCost.m_lambda, 800.0);<br> <br>-                                md.pred[PRED_IBC_Nx2N].cu.initSubCU(parentCTU, cuGeom, qp);<br>-                                checkIntraBC_rd5_6(md.pred[PRED_IBC_Nx2N], cuGeom, SIZE_Nx2N, false, bUse1DSearchFor8x8, tempLastIntraBCMv, (iMVCandList[SIZE_Nx2N] + 8));<br>+                                md.pred[PRED_IBC_Nx2N].cu.initSubCU(parentCTU, cuGeom, qp, ibc.m_lastIntraBCMv);<br>+                                checkIntraBC_rd5_6(md.pred[PRED_IBC_Nx2N], cuGeom, SIZE_Nx2N, false, bUse1DSearchFor8x8, (iMVCandList[SIZE_Nx2N] + 8), ibc);<br>                                 checkBestMode(md.pred[PRED_IBC_Nx2N], depth);<br>                                 intracost = min(intracost, md.pred[PRED_IBC_Nx2N].rdCost);<br> <br>-                                md.pred[PRED_MIXED_IBC_NX2N].cu.initSubCU(parentCTU, cuGeom, qp);<br>+                                md.pred[PRED_MIXED_IBC_NX2N].cu.initSubCU(parentCTU, cuGeom, qp, ibc.m_lastIntraBCMv);<br>                                 bValid = predMixedIntraBCInterSearch(md.pred[PRED_MIXED_IBC_NX2N], cuGeom, m_csp != X265_CSP_I400 && m_frame->m_fencPic->m_picCsp != X265_CSP_I400, SIZE_Nx2N, false, iMVCandList[SIZE_Nx2N]);<br>                                 if (bValid)<br>                                     encodeResAndCalcRdInterCU(md.pred[PRED_MIXED_IBC_NX2N], cuGeom);<br>@@ -2513,12 +2493,12 @@ SplitData Analysis::compressInterCU_rd5_6(const CUData& parentCTU, const CUGeom&<br>                                     md.pred[PRED_MIXED_IBC_NX2N].rdCost = UINT64_MAX;<br>                                 checkBestMode(md.pred[PRED_MIXED_IBC_NX2N], depth);<br> <br>-                                md.pred[PRED_IBC_2NxN].cu.initSubCU(parentCTU, cuGeom, qp);<br>-                                checkIntraBC_rd5_6(md.pred[PRED_IBC_2NxN], cuGeom, SIZE_2NxN, false, bUse1DSearchFor8x8, tempLastIntraBCMv, (iMVCandList[SIZE_2NxN] + 8));<br>+                                md.pred[PRED_IBC_2NxN].cu.initSubCU(parentCTU, cuGeom, qp, ibc.m_lastIntraBCMv);<br>+                                checkIntraBC_rd5_6(md.pred[PRED_IBC_2NxN], cuGeom, SIZE_2NxN, false, bUse1DSearchFor8x8, (iMVCandList[SIZE_2NxN] + 8), ibc);<br>                                 checkBestMode(md.pred[PRED_IBC_2NxN], depth);<br>                                 intracost = min(intracost, md.pred[PRED_IBC_2NxN].rdCost);<br> <br>-                                md.pred[PRED_MIXED_IBC_2NXN].cu.initSubCU(parentCTU, cuGeom, qp);<br>+                                md.pred[PRED_MIXED_IBC_2NXN].cu.initSubCU(parentCTU, cuGeom, qp, ibc.m_lastIntraBCMv);<br>                                 bValid = predMixedIntraBCInterSearch(md.pred[PRED_MIXED_IBC_2NXN], cuGeom, m_csp != X265_CSP_I400 && m_frame->m_fencPic->m_picCsp != X265_CSP_I400, SIZE_2NxN, false, iMVCandList[SIZE_2NxN]);<br>                                 if (bValid)<br>                                     encodeResAndCalcRdInterCU(md.pred[PRED_MIXED_IBC_2NXN], cuGeom);<br>@@ -2530,11 +2510,11 @@ SplitData Analysis::compressInterCU_rd5_6(const CUData& parentCTU, const CUGeom&<br>                         else // full search<br>                         {<br>                             md.pred[PRED_IBC_2NxN].cu.initSubCU(parentCTU, cuGeom, qp);<br>-                            checkIntraBC_rd5_6(md.pred[PRED_IBC_2NxN], cuGeom, SIZE_2NxN, false, bUse1DSearchFor8x8, tempLastIntraBCMv, &MV(0, 0));<br>+                            checkIntraBC_rd5_6(md.pred[PRED_IBC_2NxN], cuGeom, SIZE_2NxN, false, bUse1DSearchFor8x8, &MV(0, 0), ibc);<br>                             checkBestMode(md.pred[PRED_IBC_2NxN], depth);<br> <br>                             md.pred[PRED_IBC_Nx2N].cu.initSubCU(parentCTU, cuGeom, qp);<br>-                            checkIntraBC_rd5_6(md.pred[PRED_IBC_Nx2N], cuGeom, SIZE_Nx2N, false, bUse1DSearchFor8x8, tempLastIntraBCMv, &MV(0, 0));<br>+                            checkIntraBC_rd5_6(md.pred[PRED_IBC_Nx2N], cuGeom, SIZE_Nx2N, false, bUse1DSearchFor8x8, &MV(0, 0), ibc);<br>                             checkBestMode(md.pred[PRED_IBC_Nx2N], depth);<br>                         }<br>                     }<br>@@ -2794,7 +2774,7 @@ void Analysis::recodeCU(const CUData& parentCTU, const CUGeom& cuGeom, int32_t q<br>         if (parentCTU.isIntra(cuGeom.absPartIdx) && m_refineLevel < 2)<br>         {<br>             if (m_param->intraRefine == 4)<br>-                compressIntraCU(parentCTU, cuGeom, qp);<br>+                compressIntraCU(parentCTU, cuGeom, qp, m_ibc);<br>             else<br>             {<br>                 bool reuseModes = !((m_param->intraRefine == 3) ||<br>@@ -2913,7 +2893,7 @@ void Analysis::recodeCU(const CUData& parentCTU, const CUGeom& cuGeom, int32_t q<br>                 if (parentCTU.m_skipFlag[list][cuGeom.absPartIdx] == 1 && cuGeom.numPartitions <= 16)<br>                     m_checkMergeAndSkipOnly[list] = true;<br>             }<br>-            m_param->rdLevel > 4 ? compressInterCU_rd5_6(parentCTU, cuGeom, qp) : compressInterCU_rd0_4(parentCTU, cuGeom, qp);<br>+            m_param->rdLevel > 4 ? compressInterCU_rd5_6(parentCTU, cuGeom, qp, m_ibc) : compressInterCU_rd0_4(parentCTU, cuGeom, qp);<br>             for (int list = 0; list < m_slice->isInterB() + 1; list++)<br>             {<br>                 m_modeFlag[list] = false;<br>@@ -2930,7 +2910,7 @@ void Analysis::recodeCU(const CUData& parentCTU, const CUGeom& cuGeom, int32_t q<br>                 m_evaluateInter = 1;<br>             else<br>                 bDecidedDepth = true;<br>-            m_param->rdLevel > 4 ? compressInterCU_rd5_6(parentCTU, cuGeom, qp) : compressInterCU_rd0_4(parentCTU, cuGeom, qp);<br>+            m_param->rdLevel > 4 ? compressInterCU_rd5_6(parentCTU, cuGeom, qp, m_ibc) : compressInterCU_rd0_4(parentCTU, cuGeom, qp);<br>             m_evaluateInter = 0;<br>         }<br>     }<br>@@ -2963,7 +2943,7 @@ void Analysis::recodeCU(const CUData& parentCTU, const CUGeom& cuGeom, int32_t q<br>                 int lamdaQP = (m_param->analysisLoadReuseLevel >= 7) ? nextQP : lqp;<br> <br>                 if (split)<br>-                    m_param->rdLevel > 4 ? compressInterCU_rd5_6(parentCTU, childGeom, nextQP) : compressInterCU_rd0_4(parentCTU, childGeom, nextQP);<br>+                    m_param->rdLevel > 4 ? compressInterCU_rd5_6(parentCTU, childGeom, nextQP, m_ibc) : compressInterCU_rd0_4(parentCTU, childGeom, nextQP);<br>                 else<br>                     qprdRefine(parentCTU, childGeom, nextQP, lamdaQP);<br> <br>@@ -3554,7 +3534,7 @@ void Analysis::checkInter_rd5_6(Mode& interMode, const CUGeom& cuGeom, PartSize<br>     }<br> }<br> <br>-void Analysis::checkIntraBC_rd5_6(Mode& intraBCMode, const CUGeom& cuGeom, PartSize ePartSize, bool testOnlyPred, bool bUse1DSearchFor8x8, MV lastIntraBCMv[2], MV* iMVCandList)<br>+void Analysis::checkIntraBC_rd5_6(Mode& intraBCMode, const CUGeom& cuGeom, PartSize ePartSize, bool testOnlyPred, bool bUse1DSearchFor8x8, MV* iMVCandList, IBC& ibc)<br> {<br>     intraBCMode.initCosts();<br>     intraBCMode.cu.setPartSizeSubParts(ePartSize);<br>@@ -3562,9 +3542,9 @@ void Analysis::checkIntraBC_rd5_6(Mode& intraBCMode, const CUGeom& cuGeom, PartS<br>     intraBCMode.cu.setLumaIntraDirSubParts(DC_IDX, 0, cuGeom.depth);<br>     intraBCMode.cu.setChromIntraDirSubParts(DC_IDX, 0, cuGeom.depth);<br>     for (int i = 0; i < 2; i++)<br>-        intraBCMode.cu.m_lastIntraBCMv[i] = lastIntraBCMv[i];<br>+        intraBCMode.cu.m_lastIntraBCMv[i] = ibc.m_lastIntraBCMv[i];<br> <br>-    bool bValid = predIntraBCSearch(intraBCMode, cuGeom, m_csp != X265_CSP_I400 && m_frame->m_fencPic->m_picCsp != X265_CSP_I400, ePartSize, testOnlyPred, bUse1DSearchFor8x8);<br>+    bool bValid = predIntraBCSearch(intraBCMode, cuGeom, m_csp != X265_CSP_I400 && m_frame->m_fencPic->m_picCsp != X265_CSP_I400, ePartSize, testOnlyPred, bUse1DSearchFor8x8, ibc);<br>     if (bValid)<br>         encodeResAndCalcRdInterCU(intraBCMode, cuGeom);<br>     else<br>diff --git a/source/encoder/analysis.h b/source/encoder/analysis.h<br>index 6f2e4d931..e672d3554 100644<br>--- a/source/encoder/analysis.h<br>+++ b/source/encoder/analysis.h<br>@@ -119,6 +119,7 @@ public:<br>     bool      m_modeFlag[2];<br>     bool      m_checkMergeAndSkipOnly[2];<br> <br>+    IBC       m_ibc;<br>     Analysis();<br> <br>     bool create(ThreadLocalData* tld);<br>@@ -170,12 +171,12 @@ protected:<br>     void qprdRefine(const CUData& parentCTU, const CUGeom& cuGeom, int32_t qp, int32_t lqp);<br> <br>     /* full analysis for an I-slice CU */<br>-    uint64_t compressIntraCU(const CUData& parentCTU, const CUGeom& cuGeom, int32_t qp);<br>+    uint64_t compressIntraCU(const CUData& parentCTU, const CUGeom& cuGeom, int32_t qp, IBC &ibc);<br> <br>     /* full analysis for a P or B slice CU */<br>     uint32_t compressInterCU_dist(const CUData& parentCTU, const CUGeom& cuGeom, int32_t qp);<br>     SplitData compressInterCU_rd0_4(const CUData& parentCTU, const CUGeom& cuGeom, int32_t qp);<br>-    SplitData compressInterCU_rd5_6(const CUData& parentCTU, const CUGeom& cuGeom, int32_t qp);<br>+    SplitData compressInterCU_rd5_6(const CUData& parentCTU, const CUGeom& cuGeom, int32_t qp, IBC& ibc);<br> <br>     void recodeCU(const CUData& parentCTU, const CUGeom& cuGeom, int32_t qp, int32_t origqp = -1);<br> <br>@@ -190,7 +191,7 @@ protected:<br>     void checkBidir2Nx2N(Mode& inter2Nx2N, Mode& bidir2Nx2N, const CUGeom& cuGeom);<br> <br>     void checkRDCostIntraBCMerge2Nx2N(Mode& merge, const CUGeom& cuGeom);<br>-    void checkIntraBC_rd5_6(Mode& intraBCMode, const CUGeom& cuGeom, PartSize ePartSize, bool testOnlyPred, bool bUse1DSearchFor8x8, MV lastIntraBCMv[2], MV* iMVCandList = (0, 0));<br>+    void checkIntraBC_rd5_6(Mode& intraBCMode, const CUGeom& cuGeom, PartSize ePartSize, bool testOnlyPred, bool bUse1DSearchFor8x8, MV* iMVCandList ,IBC& ibc);<br> <br>     /* encode current bestMode losslessly, pick best RD cost */<br>     void tryLossless(const CUGeom& cuGeom);<br>diff --git a/source/encoder/search.cpp b/source/encoder/search.cpp<br>index 3a5c54ffa..f72ea8c9c 100644<br>--- a/source/encoder/search.cpp<br>+++ b/source/encoder/search.cpp<br>@@ -172,6 +172,9 @@ bool Search::initSearch(const x265_param& param, ScalingList& scalingList)<br>     CHECKED_MALLOC(m_tsResidual, int16_t, MAX_TS_SIZE * MAX_TS_SIZE);<br>     CHECKED_MALLOC(m_tsRecon,    pixel,   MAX_TS_SIZE * MAX_TS_SIZE);<br> <br>+    m_numBVs = 0;<br>+    m_numBV16s = 0;<br>+<br>     return ok;<br> <br> fail:<br>@@ -2771,15 +2774,15 @@ int Search::intraBCSearchMVChromaRefine(Mode& intraBCMode,<br>     return bestCandIdx;<br> }<br> <br>-void Search::updateBVMergeCandLists(int roiWidth, int roiHeight, MV* mvCand)<br>+void Search::updateBVMergeCandLists(int roiWidth, int roiHeight, MV* mvCand, IBC& ibc)<br> {<br>     if (roiWidth + roiHeight > 8)<br>     {<br>-        m_numBVs = mergeCandLists(m_BVs, m_numBVs, mvCand, CHROMA_REFINEMENT_CANDIDATES, false);<br>+        ibc.m_numBVs = mergeCandLists(ibc.m_BVs, ibc.m_numBVs, mvCand, CHROMA_REFINEMENT_CANDIDATES, false);<br> <br>         if (roiWidth + roiHeight == 32)<br>         {<br>-            m_numBV16s = m_numBVs;<br>+            ibc.m_numBV16s = ibc.m_numBVs;<br>         }<br>     }<br> }<br>@@ -2954,7 +2957,7 @@ bool Search::isValidIntraBCSearchArea(CUData* cu, int predX, int predY, int roiW<br> }<br> <br> void Search::intraPatternSearch(Mode& intraBCMode, const CUGeom& cuGeom, int puIdx, uint32_t partAddr, pixel* refY, int refStride, MV* searchRangeLT, MV* searchRangeRB,<br>-    MV& mv, uint32_t& cost, int roiWidth, int roiHeight, bool testOnlyPred, bool bUse1DSearchFor8x8)<br>+    MV& mv, uint32_t& cost, int roiWidth, int roiHeight, bool testOnlyPred, bool bUse1DSearchFor8x8, IBC& ibc)<br> {<br>     const int   srchRngHorLeft = searchRangeLT->x;<br>     const int   srchRngHorRight = searchRangeRB->x;<br>@@ -3021,22 +3024,21 @@ void Search::intraPatternSearch(Mode& intraBCMode, const CUGeom& cuGeom, int puI<br>         }<br> <br>         if (roiWidth > 8 || roiHeight > 8)<br>-            m_numBVs = 0;<br>+            ibc.m_numBVs = 0;<br>         else if (roiWidth + roiHeight == 16)<br>-            m_numBVs = m_numBV16s;<br>+            ibc.m_numBVs = ibc.m_numBV16s;<br>         if (testOnlyPred)<br>-            m_numBVs = 0;<br>+            ibc.m_numBVs = 0;<br> <br>         MV  mvPredEncOnly[16];<br>         int nbPreds = 0;<br>-<br>         cu.getIntraBCMVPsEncOnly(partAddr, mvPredEncOnly, nbPreds, puIdx);<br>-        m_numBVs = mergeCandLists(m_BVs, m_numBVs, mvPredEncOnly, nbPreds, true);<br>+        ibc.m_numBVs = mergeCandLists(ibc.m_BVs, ibc.m_numBVs, mvPredEncOnly, nbPreds, true);<br> <br>-        for (uint32_t cand = 0; cand < m_numBVs; cand++)<br>+        for (uint32_t cand = 0; cand < ibc.m_numBVs; cand++)<br>         {<br>-            int xPred = m_BVs[cand].x >> 2;<br>-            int yPred = m_BVs[cand].y >> 2;<br>+            int xPred = ibc.m_BVs[cand].x >> 2;<br>+            int yPred = ibc.m_BVs[cand].y >> 2;<br>             if (!(xPred == 0 && yPred == 0) && !((yPred < srTop) || (yPred > srBottom)) && !((xPred < srLeft) || (xPred > srRight)))<br>             {<br>                 int tempY = yPred + relCUPelY + roiHeight - 1;<br>@@ -3058,7 +3060,7 @@ void Search::intraPatternSearch(Mode& intraBCMode, const CUGeom& cuGeom, int puI<br> <br>                 if (validCand)<br>                 {<br>-                    sad = m_me.mvcost(m_BVs[cand]);<br>+                    sad = m_me.mvcost(ibc.m_BVs[cand]);<br> <br>                     refSrch = refY + yPred * refStride + xPred;<br> <br>@@ -3118,7 +3120,7 @@ void Search::intraPatternSearch(Mode& intraBCMode, const CUGeom& cuGeom, int puI<br>                 mv.set(bestX, bestY);<br>                 cost = sadBest;<br> <br>-                updateBVMergeCandLists(roiWidth, roiHeight, MVCand);<br>+                updateBVMergeCandLists(roiWidth, roiHeight, MVCand, ibc);<br>                 return;<br>             }<br>         }<br>@@ -3155,7 +3157,7 @@ void Search::intraPatternSearch(Mode& intraBCMode, const CUGeom& cuGeom, int puI<br>                 mv.set(bestX, bestY);<br>                 cost = sadBest;<br> <br>-                updateBVMergeCandLists(roiWidth, roiHeight, MVCand);<br>+                updateBVMergeCandLists(roiWidth, roiHeight, MVCand, ibc);<br>                 return;<br>             }<br>         }<br>@@ -3174,7 +3176,7 @@ void Search::intraPatternSearch(Mode& intraBCMode, const CUGeom& cuGeom, int puI<br>             mv.set(bestX, bestY);<br>             cost = sadBest;<br> <br>-            updateBVMergeCandLists(roiWidth, roiHeight, MVCand);<br>+            updateBVMergeCandLists(roiWidth, roiHeight, MVCand, ibc);<br>             return;<br>         }<br> <br>@@ -3238,7 +3240,7 @@ void Search::intraPatternSearch(Mode& intraBCMode, const CUGeom& cuGeom, int puI<br>                 mv.set(bestX, bestY);<br>                 cost = sadBest;<br> <br>-                updateBVMergeCandLists(roiWidth, roiHeight, MVCand);<br>+                updateBVMergeCandLists(roiWidth, roiHeight, MVCand, ibc);<br>                 return;<br>             }<br> <br>@@ -3299,7 +3301,7 @@ void Search::intraPatternSearch(Mode& intraBCMode, const CUGeom& cuGeom, int puI<br>                         mv.set(bestX, bestY);<br>                         cost = sadBest;<br> <br>-                        updateBVMergeCandLists(roiWidth, roiHeight, MVCand);<br>+                        updateBVMergeCandLists(roiWidth, roiHeight, MVCand, ibc);<br>                         return;<br>                     }<br>                 }<br>@@ -3319,7 +3321,7 @@ void Search::intraPatternSearch(Mode& intraBCMode, const CUGeom& cuGeom, int puI<br>                 mv.set(bestX, bestY);<br>                 cost = sadBest;<br> <br>-                updateBVMergeCandLists(roiWidth, roiHeight, MVCand);<br>+                updateBVMergeCandLists(roiWidth, roiHeight, MVCand, ibc);<br>                 return;<br>             }<br> <br>@@ -3383,7 +3385,7 @@ void Search::intraPatternSearch(Mode& intraBCMode, const CUGeom& cuGeom, int puI<br>                         mv.set(bestX, bestY);<br>                         cost = sadBest;<br> <br>-                        updateBVMergeCandLists(roiWidth, roiHeight, MVCand);<br>+                        updateBVMergeCandLists(roiWidth, roiHeight, MVCand, ibc);<br>                         return;<br>                     }<br>                 }<br>@@ -3453,7 +3455,7 @@ void Search::intraPatternSearch(Mode& intraBCMode, const CUGeom& cuGeom, int puI<br>     mv.set(bestX, bestY);<br>     cost = sadBest;<br> <br>-    updateBVMergeCandLists(roiWidth, roiHeight, MVCand);<br>+    updateBVMergeCandLists(roiWidth, roiHeight, MVCand, ibc);<br> <br> }<br> <br>@@ -3518,7 +3520,7 @@ void Search::setIntraSearchRange(Mode& intraBCMode, MV& pred, int puIdx, int roi<br> <br> }<br> <br>-void Search::intraBlockCopyEstimate(Mode& intraBCMode, const CUGeom& cuGeom, int puIdx, MV* pred, MV& mv, uint32_t& cost, bool testOnlyPred, bool bUse1DSearchFor8x8)<br>+void Search::intraBlockCopyEstimate(Mode& intraBCMode, const CUGeom& cuGeom, int puIdx, MV* pred, MV& mv, uint32_t& cost, bool testOnlyPred, bool bUse1DSearchFor8x8, IBC& ibc)<br> {<br>     uint32_t         partAddr;<br>     int              roiWidth;<br>@@ -3558,10 +3560,10 @@ void Search::intraBlockCopyEstimate(Mode& intraBCMode, const CUGeom& cuGeom, int<br> <br>     m_me.setMVP(predictors);<br> <br>-    intraPatternSearch(intraBCMode, cuGeom, puIdx, partAddr, refY, strideY, &searchRangeLT, &searchRangeRB, mv, cost, roiWidth, roiHeight, testOnlyPred, bUse1DSearchFor8x8);<br>+    intraPatternSearch(intraBCMode, cuGeom, puIdx, partAddr, refY, strideY, &searchRangeLT, &searchRangeRB, mv, cost, roiWidth, roiHeight, testOnlyPred, bUse1DSearchFor8x8, ibc);<br> }<br> <br>-bool Search::predIntraBCSearch(Mode& intraBCMode, const CUGeom& cuGeom, bool bChromaMC, PartSize ePartSize, bool testOnlyPred, bool bUse1DSearchFor8x8)<br>+bool Search::predIntraBCSearch(Mode& intraBCMode, const CUGeom& cuGeom, bool bChromaMC, PartSize ePartSize, bool testOnlyPred, bool bUse1DSearchFor8x8, IBC& ibc)<br> {<br>     MV zeroMv(0, 0);<br>     CUData& cu = intraBCMode.cu;<br>@@ -3596,7 +3598,7 @@ bool Search::predIntraBCSearch(Mode& intraBCMode, const CUGeom& cuGeom, bool bCh<br>         MVField mvField;<br>         uint32_t cost;<br>         mv.set(0, 0);<br>-        intraBlockCopyEstimate(intraBCMode, cuGeom, puIdx, mvPred, mv, cost, testOnlyPred, bUse1DSearchFor8x8);<br>+        intraBlockCopyEstimate(intraBCMode, cuGeom, puIdx, mvPred, mv, cost, testOnlyPred, bUse1DSearchFor8x8, ibc);<br> <br>         bestME->mv.set(mv.x << 2, mv.y << 2);<br>         bestME->cost = cost;<br>diff --git a/source/encoder/search.h b/source/encoder/search.h<br>index e05d6ef95..948ea1883 100644<br>--- a/source/encoder/search.h<br>+++ b/source/encoder/search.h<br>@@ -289,12 +289,10 @@ public:<br>     bool            m_vertRestriction;<br> <br>     int             m_ibcEnabled;<br>-<br>-    int             m_numBVs = 0;<br>-    int             m_numBV16s = 0;<br>+    int             m_numBVs;<br>+    int             m_numBV16s;<br>     MV              m_BVs[64];<br>     uint32_t        m_lastCandCost;<br>-    MV              tempLastIntraBCMv[2] = { 0,0 };<br> #if DETAILED_CU_STATS<br>     /* Accumulate CU statistics separately for each frame encoder */<br>     CUStats         m_stats[X265_MAX_FRAME_THREADS];<br>@@ -338,16 +336,16 @@ public:<br> <br>     MV getLowresMV(const CUData& cu, const PredictionUnit& pu, int list, int ref);<br> <br>-    bool      predIntraBCSearch(Mode& intraBCMode, const CUGeom& cuGeom, bool bChromaMC, PartSize ePartSize, bool testOnlyPred, bool bUse1DSearchFor8x8);<br>-    void      intraBlockCopyEstimate(Mode& intraBCMode, const CUGeom& cuGeom, int puIdx, MV* pred, MV& mv, uint32_t& cost, bool testOnlyPred, bool bUse1DSearchFor8x8);<br>+    bool      predIntraBCSearch(Mode& intraBCMode, const CUGeom& cuGeom, bool bChromaMC, PartSize ePartSize, bool testOnlyPred, bool bUse1DSearchFor8x8, IBC& ibc);<br>+    void      intraBlockCopyEstimate(Mode& intraBCMode, const CUGeom& cuGeom, int puIdx, MV* pred, MV& mv, uint32_t& cost, bool testOnlyPred, bool bUse1DSearchFor8x8, IBC& ibc);<br>     void      setIntraSearchRange(Mode& intraBCMode, MV& pred, int puIdx, int roiWidth, int roiHeight, MV& searchRangeLT, MV& searchRangeRB);<br>     void      intraPatternSearch(Mode& intraBCMode, const CUGeom& cuGeom, int puIdx, uint32_t partAddr, pixel* refY, int refStride, MV* searchRangeLT, MV* searchRangeRB,<br>-        MV& mv, uint32_t& cost, int roiwidth, int roiheight, bool testOnlyPred, bool bUse1DSearchFor8x8);<br>+        MV& mv, uint32_t& cost, int roiwidth, int roiheight, bool testOnlyPred, bool bUse1DSearchFor8x8, IBC& ibc);<br>     bool      isValidIntraBCSearchArea(CUData* cu, int predX, int predY, int roiWidth, int roiHeight, int partOffset);<br>     bool      isBlockVectorValid(int xPos, int yPos, int width, int height, CUData* pcCU,<br>         int xStartInCU, int yStartInCU, int xBv, int yBv, int ctuSize);<br>     void      intraBCSearchMVCandUpdate(uint32_t sad, int x, int y, uint32_t* sadBestCand, MV* cMVCand);<br>-    void      updateBVMergeCandLists(int roiWidth, int roiHeight, MV* mvCand);<br>+    void      updateBVMergeCandLists(int roiWidth, int roiHeight, MV* mvCand, IBC& ibc);<br>     int       intraBCSearchMVChromaRefine(Mode& intraBCMode, const CUGeom& cuGeom, int roiWidth, int roiHeight, int cuPelX, int cuPelY, uint32_t* sadBestCand, MV* cMVCand,<br>         uint32_t partOffset, int puIdx);<br>     static    uint32_t mergeCandLists(MV* dst, uint32_t dn, MV* src, uint32_t sn, bool isSrcQuarPel);<br>-- <br>2.36.0.windows.1<br><br></div>