From 955c0f423a203c7a043a36aca58c2b83067b99ec Mon Sep 17 00:00:00 2001
From: analci <analci@qti.qualcomm.com>
Date: Tue, 31 Mar 2020 18:05:41 -0700
Subject: [PATCH] Fixes for handling proper RDOQTS and BDPCM RDOQ for
 slice_ts_residual_coding_disabled_flag.

---
 source/Lib/CommonLib/QuantRDOQ.cpp | 420 ++++++++++++++++++++++++++++-
 source/Lib/CommonLib/QuantRDOQ.h   |   7 +
 source/Lib/CommonLib/TypeDef.h     |   3 +
 source/Lib/EncoderLib/EncSlice.cpp |   4 +
 4 files changed, 432 insertions(+), 2 deletions(-)

diff --git a/source/Lib/CommonLib/QuantRDOQ.cpp b/source/Lib/CommonLib/QuantRDOQ.cpp
index c9d12955..b12133bf 100644
--- a/source/Lib/CommonLib/QuantRDOQ.cpp
+++ b/source/Lib/CommonLib/QuantRDOQ.cpp
@@ -537,7 +537,18 @@ void QuantRDOQ::quant(TransformUnit &tu, const ComponentID &compID, const CCoeff
       {
         if( (tu.cu->bdpcmMode && isLuma(compID)) || (isChroma(compID) && tu.cu->bdpcmModeChroma ) )
         {
+#if QC_TS_RRC_RDOQ
+          if( tu.cs->slice->getTSResidualCodingDisabledFlag() )
+          {
+            forwardRRCRDPCM( tu, compID, pSrc, uiAbsSum, cQP, ctx );
+          }
+          else
+          {
+            forwardRDPCM( tu, compID, pSrc, uiAbsSum, cQP, ctx );
+          }
+#else
           forwardRDPCM( tu, compID, pSrc, uiAbsSum, cQP, ctx );
+#endif
         }
         else
         {
@@ -635,9 +646,13 @@ void QuantRDOQ::xRateDistOptQuant(TransformUnit &tu, const ComponentID &compID,
   memset( m_sigRateDelta, 0, sizeof( int    ) *  uiMaxNumCoeff );
   memset( m_deltaU,       0, sizeof( TCoeff ) *  uiMaxNumCoeff );
 
-
+#if QC_TS_RRC_RDOQ
+  const bool   isTransformSkip  = (tu.mtsIdx[compID] == MTS_SKIP);
+  const bool needSqrtAdjustment = isTransformSkip ? false : ( TU::needsBlockSizeTrafoScale( tu, compID ) );
+#else
   const bool needSqrtAdjustment= TU::needsBlockSizeTrafoScale( tu, compID );
   const bool   isTransformSkip = (tu.mtsIdx[compID] == MTS_SKIP);
+#endif
   const double *const pdErrScale = xGetErrScaleCoeffSL(scalingListType, uiLog2BlockWidth, uiLog2BlockHeight, cQP.rem(isTransformSkip));
   const int    *const piQCoef    = getQuantCoeff(scalingListType, cQP.rem(isTransformSkip), uiLog2BlockWidth, uiLog2BlockHeight);
 #if JVET_Q0346_SCALING_LIST_USED_IN_SH
@@ -652,9 +667,21 @@ void QuantRDOQ::xRateDistOptQuant(TransformUnit &tu, const ComponentID &compID,
   const bool   enableScalingLists = getUseScalingList(uiWidth, uiHeight, isTransformSkip, tu.cu->lfnstIdx > 0, disableSMForLFNST);
 #endif
   const int    defaultQuantisationCoefficient = g_quantScales[ needSqrtAdjustment ?1:0][cQP.rem(isTransformSkip)];
+#if QC_TS_RRC_RDOQ
+  double defaultErrorScale;
+  if( isTransformSkip )
+  {
+    defaultErrorScale = xGetErrScaleCoeff(needSqrtAdjustment, uiLog2BlockWidth, uiLog2BlockHeight, cQP.rem(isTransformSkip), maxLog2TrDynamicRange, channelBitDepth, isTransformSkip);
+  }
+  else
+  {
+    defaultErrorScale = xGetErrScaleCoeffNoScalingList(scalingListType, uiLog2BlockWidth, uiLog2BlockHeight, cQP.rem(isTransformSkip));
+  }
+  const int iQBits    = QUANT_SHIFT + cQP.per(isTransformSkip) + (isTransformSkip ? 0 : iTransformShift) + (needSqrtAdjustment ? -1 : 0);
+#else
   const double defaultErrorScale              = xGetErrScaleCoeffNoScalingList(scalingListType, uiLog2BlockWidth, uiLog2BlockHeight, cQP.rem(isTransformSkip));
   const int iQBits = QUANT_SHIFT + cQP.per(isTransformSkip) + iTransformShift + (needSqrtAdjustment?-1:0);                   // Right shift of non-RDOQ quantizer;  level = (coeff*uiQ + offset)>>q_bits
-
+#endif
 
   const TCoeff entropyCodingMinimum = -(1 << maxLog2TrDynamicRange);
   const TCoeff entropyCodingMaximum =  (1 << maxLog2TrDynamicRange) - 1;
@@ -1413,6 +1440,395 @@ void QuantRDOQ::xRateDistOptQuantTS( TransformUnit &tu, const ComponentID &compI
   }
 }
 
+#if QC_TS_RRC_RDOQ
+void QuantRDOQ::forwardRRCRDPCM(TransformUnit &tu, const ComponentID &compID, const CCoeffBuf &pSrc, TCoeff &uiAbsSum, const QpParam &cQP, const Ctx &ctx)
+{
+  const FracBitsAccess& fracBits = ctx.getFracBitsAcess();
+
+  const SPS &sps            = *tu.cs->sps;
+  const CompArea &rect      = tu.blocks[compID];
+  const uint32_t uiWidth    = rect.width;
+  const uint32_t uiHeight   = rect.height;
+  const ChannelType chType  = toChannelType(compID);
+  const int channelBitDepth = sps.getBitDepth( chType );
+
+  const bool extendedPrecision     = sps.getSpsRangeExtension().getExtendedPrecisionProcessingFlag();
+  const int  maxLog2TrDynamicRange = sps.getMaxLog2TrDynamicRange(chType);
+
+  const int  dirMode = isLuma(compID) ? tu.cu->bdpcmMode : tu.cu->bdpcmModeChroma;
+
+  // Represents scaling through forward transform
+  int iTransformShift = getTransformShift(channelBitDepth, rect.size(), maxLog2TrDynamicRange);
+
+  if (tu.mtsIdx[compID] == MTS_SKIP && extendedPrecision)
+  {
+    iTransformShift = std::max<int>(0, iTransformShift);
+  }
+
+  double     d64BlockUncodedCost               = 0;
+  const uint32_t uiLog2BlockWidth                  = floorLog2(uiWidth);
+  const uint32_t uiLog2BlockHeight                 = floorLog2(uiHeight);
+  const uint32_t uiMaxNumCoeff                     = rect.area();
+
+  CHECK(compID >= MAX_NUM_TBLOCKS, "Invalid component ID");
+
+  int scalingListType = getScalingListType(tu.cu->predMode, compID);
+
+  CHECK(scalingListType >= SCALING_LIST_NUM, "Invalid scaling list");
+
+// Rotate block
+  const uint32_t  numSamplesInBlock = uiWidth * uiHeight;
+
+  memset(m_srcCoeffTemp, 0, sizeof(TCoeff) * numSamplesInBlock);
+  memset(m_dstCoeffTemp, 0, sizeof(TCoeff) * numSamplesInBlock);
+
+  const uint32_t uiSizeMinus1 = (numSamplesInBlock)-1;
+  for (uint32_t y = 0, coefficientIndex = 0; y < uiHeight; y++)
+  {
+	  for (uint32_t x = 0; x < uiWidth; x++, coefficientIndex++)
+	  {
+		  m_srcCoeffTemp[coefficientIndex] = pSrc.buf[uiSizeMinus1 - coefficientIndex];
+	  }
+  }
+  const TCoeff *plSrcCoeff = m_srcCoeffTemp;
+        TCoeff *piDstCoeff = tu.getCoeffs(compID).buf;
+
+  double *pdCostCoeff  = m_pdCostCoeff;
+  double *pdCostSig    = m_pdCostSig;
+  double *pdCostCoeff0 = m_pdCostCoeff0;
+  int    *rateIncUp    = m_rateIncUp;
+  int    *rateIncDown  = m_rateIncDown;
+  int    *sigRateDelta = m_sigRateDelta;
+  TCoeff *deltaU       = m_deltaU;
+
+  memset(piDstCoeff, 0, sizeof(*piDstCoeff) * uiMaxNumCoeff);
+  memset( m_pdCostCoeff,  0, sizeof( double ) *  uiMaxNumCoeff );
+  memset( m_pdCostSig,    0, sizeof( double ) *  uiMaxNumCoeff );
+  memset( m_rateIncUp,    0, sizeof( int    ) *  uiMaxNumCoeff );
+  memset( m_rateIncDown,  0, sizeof( int    ) *  uiMaxNumCoeff );
+  memset( m_sigRateDelta, 0, sizeof( int    ) *  uiMaxNumCoeff );
+  memset( m_deltaU,       0, sizeof( TCoeff ) *  uiMaxNumCoeff );
+  memset( m_fullCoeff,    0, sizeof(TCoeff)   *  uiMaxNumCoeff );
+
+  m_bdpcm = dirMode;
+
+  const bool   isTransformSkip  = (tu.mtsIdx[compID] == MTS_SKIP);
+  const bool needSqrtAdjustment = isTransformSkip ? false : ( TU::needsBlockSizeTrafoScale( tu, compID ) );
+
+  const int    defaultQuantisationCoefficient = g_quantScales[ needSqrtAdjustment ?1:0][cQP.rem(isTransformSkip)];
+
+ double defaultErrorScale;
+ if( isTransformSkip )
+ {
+   defaultErrorScale = xGetErrScaleCoeff(needSqrtAdjustment, uiLog2BlockWidth, uiLog2BlockHeight, cQP.rem(isTransformSkip), maxLog2TrDynamicRange, channelBitDepth, isTransformSkip);
+ }
+ else
+ {
+   defaultErrorScale = xGetErrScaleCoeffNoScalingList(scalingListType, uiLog2BlockWidth, uiLog2BlockHeight, cQP.rem(isTransformSkip));
+ }
+
+ const int iQBits    = QUANT_SHIFT + cQP.per(isTransformSkip) + (isTransformSkip ? 0 : iTransformShift) + (needSqrtAdjustment ? -1 : 0);
+
+  TrQuantParams trQuantParams;
+  trQuantParams.rightShift = (IQUANT_SHIFT - ((isTransformSkip ? 0 : iTransformShift) + cQP.per(isTransformSkip)));
+  trQuantParams.qScale     = g_invQuantScales[needSqrtAdjustment ? 1 : 0][cQP.rem(isTransformSkip)];
+
+  const TCoeff entropyCodingMaximum =  (1 << maxLog2TrDynamicRange) - 1;
+
+  CoeffCodingContext cctx(tu, compID, tu.cs->picHeader->getSignDataHidingEnabledFlag());
+
+  const int    iCGSizeM1      = (1 << cctx.log2CGSize()) - 1;
+
+  int     iCGLastScanPos      = -1;
+  double  d64BaseCost         = 0;
+  int     iLastScanPos        = -1;
+
+
+  int ctxBinSampleRatio   = (compID == COMPONENT_Y) ? MAX_TU_LEVEL_CTX_CODED_BIN_CONSTRAINT_LUMA : MAX_TU_LEVEL_CTX_CODED_BIN_CONSTRAINT_CHROMA;
+  int remRegBins          = (uiWidth * uiHeight * ctxBinSampleRatio) >> 4;
+
+  uint32_t  goRiceParam   = 0;
+
+  double *pdCostCoeffGroupSig = m_pdCostCoeffGroupSig;
+  memset( pdCostCoeffGroupSig, 0, ( uiMaxNumCoeff >> cctx.log2CGSize() ) * sizeof( double ) );
+  int iScanPos;
+  coeffGroupRDStats rdStats;
+
+#if ENABLE_TRACING
+  DTRACE( g_trace_ctx, D_RDOQ, "%d: %3d, %3d, %dx%d, comp=%d\n", DTRACE_GET_COUNTER( g_trace_ctx, D_RDOQ ), rect.x, rect.y, rect.width, rect.height, compID );
+#endif
+
+  const uint32_t lfnstIdx = tu.cu->lfnstIdx;
+
+  const int iCGNum = lfnstIdx > 0 ? 1 : std::min<int>(JVET_C0024_ZERO_OUT_TH, uiWidth) * std::min<int>(JVET_C0024_ZERO_OUT_TH, uiHeight) >> cctx.log2CGSize();
+
+  for (int subSetId = iCGNum - 1; subSetId >= 0; subSetId--)
+  {
+    cctx.initSubblock( subSetId );
+
+    uint32_t maxNonZeroPosInCG = iCGSizeM1;
+    if( lfnstIdx > 0 && ( ( uiWidth == 4 && uiHeight == 4 ) || ( uiWidth == 8 && uiHeight == 8 && cctx.cgPosX() == 0 && cctx.cgPosY() == 0 ) ) )
+    {
+      maxNonZeroPosInCG = 7;
+    }
+
+    memset( &rdStats, 0, sizeof (coeffGroupRDStats));
+
+
+    for( int iScanPosinCG = iCGSizeM1; iScanPosinCG > maxNonZeroPosInCG; iScanPosinCG-- )
+    {
+      iScanPos = cctx.minSubPos() + iScanPosinCG;
+      uint32_t    blkPos = cctx.blockPos( iScanPos );
+      piDstCoeff[ blkPos ] = 0;
+    }
+
+
+    for( int iScanPosinCG = maxNonZeroPosInCG; iScanPosinCG >= 0; iScanPosinCG-- )
+    {
+      iScanPos = cctx.minSubPos() + iScanPosinCG;
+      //===== quantization =====
+      uint32_t    uiBlkPos          = cctx.blockPos(iScanPos);
+
+	    const int posX        = cctx.posX(iScanPos);
+      const int posY        = cctx.posY(iScanPos);
+      const int posS        = (1 == dirMode) ? posX : posY;
+	    const int boundaryLim = (1 == dirMode) ? uiWidth-1 : uiHeight-1;
+	    const int posNb       = (1 == dirMode) ? (posX + 1) + posY * pSrc.stride : posX + (posY + 1) * pSrc.stride;
+      TCoeff predCoeff      = (boundaryLim != posS) ? m_fullCoeff[posNb] : 0;
+
+      // set coeff
+      const int    quantisationCoefficient = defaultQuantisationCoefficient;
+      const double errorScale              = defaultErrorScale;
+
+	    const int64_t  tmpLevel              = int64_t(abs(plSrcCoeff[ uiBlkPos ] - predCoeff)) * quantisationCoefficient;
+
+      const Intermediate_Int lLevelDouble  = (Intermediate_Int)std::min<int64_t>(tmpLevel, std::numeric_limits<Intermediate_Int>::max() - (Intermediate_Int(1) << (iQBits - 1)));
+
+      uint32_t uiMaxAbsLevel        = std::min<uint32_t>(uint32_t(entropyCodingMaximum), uint32_t((lLevelDouble + (Intermediate_Int(1) << (iQBits - 1))) >> iQBits));
+
+      const double dErr         = double( lLevelDouble );
+      pdCostCoeff0[ iScanPos ]  = dErr * dErr * errorScale;
+      d64BlockUncodedCost      += pdCostCoeff0[ iScanPos ];
+      piDstCoeff[ uiBlkPos ]    = uiMaxAbsLevel;
+
+
+      if ( uiMaxAbsLevel > 0 && iLastScanPos < 0 )
+      {
+        iLastScanPos            = iScanPos;
+        iCGLastScanPos          = cctx.subSetId();
+      }
+
+      if ( iLastScanPos >= 0 )
+      {
+#if ENABLE_TRACING
+        uint32_t uiCGPosY = cctx.cgPosX();
+        uint32_t uiCGPosX = cctx.cgPosY();
+        uint32_t uiPosY = cctx.posY( iScanPos );
+        uint32_t uiPosX = cctx.posX( iScanPos );
+        DTRACE( g_trace_ctx, D_RDOQ, "%d [%d][%d][%2d:%2d][%2d:%2d]", DTRACE_GET_COUNTER( g_trace_ctx, D_RDOQ ), iScanPos, uiBlkPos, uiCGPosX, uiCGPosY, uiPosX, uiPosY );
+#endif
+        //===== coefficient level estimation =====
+        unsigned ctxIdSig = 0;
+        if( iScanPos != iLastScanPos )
+        {
+          ctxIdSig = cctx.sigCtxIdAbs( iScanPos, piDstCoeff, 0 );
+        }
+
+
+    		const uint8_t  sign = (plSrcCoeff[uiBlkPos] - predCoeff) < 0 ? 1 : 0;
+
+        uint32_t    uiLevel;
+        uint8_t ctxOffset     = cctx.ctxOffsetAbs     ();
+        uint32_t    uiParCtx      = cctx.parityCtxIdAbs   ( ctxOffset );
+        uint32_t    uiGt1Ctx      = cctx.greater1CtxIdAbs ( ctxOffset );
+        uint32_t    uiGt2Ctx      = cctx.greater2CtxIdAbs ( ctxOffset );
+        uint32_t    goRiceZero    = 0;
+        if( remRegBins < 4 )
+        {
+          unsigned  sumAbs = cctx.templateAbsSum( iScanPos, piDstCoeff, 0 );
+          goRiceParam             = g_auiGoRiceParsCoeff   [ sumAbs ];
+          goRiceZero              = g_auiGoRicePosCoeff0(0, goRiceParam);
+        }
+
+        const BinFracBits fracBitsPar = fracBits.getFracBitsArray( uiParCtx );
+        const BinFracBits fracBitsGt1 = fracBits.getFracBitsArray( uiGt1Ctx );
+        const BinFracBits fracBitsGt2 = fracBits.getFracBitsArray( uiGt2Ctx );
+
+        if( iScanPos == iLastScanPos )
+        {
+          uiLevel = xGetCodedLevel( pdCostCoeff[ iScanPos ], pdCostCoeff0[ iScanPos ], pdCostSig[ iScanPos ],
+                                    lLevelDouble, uiMaxAbsLevel, nullptr, fracBitsPar, fracBitsGt1, fracBitsGt2, remRegBins, goRiceZero, goRiceParam, iQBits, errorScale, 1, extendedPrecision, maxLog2TrDynamicRange );
+        }
+        else
+        {
+          DTRACE_COND( ( uiMaxAbsLevel != 0 ), g_trace_ctx, D_RDOQ_MORE, " uiCtxSig=%d", ctxIdSig );
+
+          const BinFracBits fracBitsSig = fracBits.getFracBitsArray( ctxIdSig );
+          uiLevel = xGetCodedLevel( pdCostCoeff[ iScanPos ], pdCostCoeff0[ iScanPos ], pdCostSig[ iScanPos ],
+                                    lLevelDouble, uiMaxAbsLevel, &fracBitsSig, fracBitsPar, fracBitsGt1, fracBitsGt2, remRegBins, goRiceZero, goRiceParam, iQBits, errorScale, 0, extendedPrecision, maxLog2TrDynamicRange );
+          sigRateDelta[ uiBlkPos ] = ( remRegBins < 4 ? 0 : fracBitsSig.intBits[1] - fracBitsSig.intBits[0] );
+        }
+
+        DTRACE( g_trace_ctx, D_RDOQ, " Lev=%d \n", uiLevel );
+        DTRACE_COND( ( uiMaxAbsLevel != 0 ), g_trace_ctx, D_RDOQ, " CostC0=%d\n", (int64_t)( pdCostCoeff0[iScanPos] ) );
+        DTRACE_COND( ( uiMaxAbsLevel != 0 ), g_trace_ctx, D_RDOQ, " CostC =%d\n", (int64_t)( pdCostCoeff[iScanPos] ) );
+
+        deltaU[ uiBlkPos ]        = TCoeff((lLevelDouble - (Intermediate_Int(uiLevel) << iQBits)) >> (iQBits-8));
+
+        if( uiLevel > 0 )
+        {
+          int rateNow              = xGetICRate( uiLevel,   fracBitsPar, fracBitsGt1, fracBitsGt2, remRegBins, goRiceZero, goRiceParam, extendedPrecision, maxLog2TrDynamicRange );
+          rateIncUp   [ uiBlkPos ] = xGetICRate( uiLevel+1, fracBitsPar, fracBitsGt1, fracBitsGt2, remRegBins, goRiceZero, goRiceParam, extendedPrecision, maxLog2TrDynamicRange ) - rateNow;
+          rateIncDown [ uiBlkPos ] = xGetICRate( uiLevel-1, fracBitsPar, fracBitsGt1, fracBitsGt2, remRegBins, goRiceZero, goRiceParam, extendedPrecision, maxLog2TrDynamicRange ) - rateNow;
+        }
+        else // uiLevel == 0
+        {
+          if( remRegBins < 4 )
+          {
+            int rateNow            = xGetICRate( uiLevel,   fracBitsPar, fracBitsGt1, fracBitsGt2, remRegBins, goRiceZero, goRiceParam, extendedPrecision, maxLog2TrDynamicRange );
+            rateIncUp [ uiBlkPos ] = xGetICRate( uiLevel+1, fracBitsPar, fracBitsGt1, fracBitsGt2, remRegBins, goRiceZero, goRiceParam, extendedPrecision, maxLog2TrDynamicRange ) - rateNow;
+          }
+          else
+          {
+            rateIncUp [ uiBlkPos ] = fracBitsGt1.intBits[ 0 ];
+          }
+        }
+        piDstCoeff[ uiBlkPos ] = uiLevel;
+
+		    if( sign )
+        {
+		      piDstCoeff[uiBlkPos] = -piDstCoeff[uiBlkPos];
+        }
+
+		    xDequantSample( m_fullCoeff[uiBlkPos], piDstCoeff[uiBlkPos], trQuantParams );
+        m_fullCoeff[uiBlkPos] += predCoeff;
+
+        d64BaseCost           += pdCostCoeff [ iScanPos ];
+
+        if( ( (iScanPos & iCGSizeM1) == 0 ) && ( iScanPos > 0 ) )
+        {
+          goRiceParam   = 0;
+        }
+        else if( remRegBins >= 4 )
+        {
+          int  sumAll = cctx.templateAbsSum(iScanPos, piDstCoeff, 4);
+          goRiceParam = g_auiGoRiceParsCoeff[sumAll];
+          remRegBins -= (uiLevel < 2 ? uiLevel : 3) + (iScanPos != iLastScanPos);
+        }
+      }
+      else
+      {
+        d64BaseCost    += pdCostCoeff0[ iScanPos ];
+      }
+      rdStats.d64SigCost += pdCostSig[ iScanPos ];
+      if (iScanPosinCG == 0 )
+      {
+        rdStats.d64SigCost_0 = pdCostSig[ iScanPos ];
+      }
+      if (piDstCoeff[ uiBlkPos ] )
+      {
+        cctx.setSigGroup();
+        rdStats.d64CodedLevelandDist += pdCostCoeff[ iScanPos ] - pdCostSig[ iScanPos ];
+        rdStats.d64UncodedDist += pdCostCoeff0[ iScanPos ];
+        if ( iScanPosinCG != 0 )
+        {
+          rdStats.iNNZbeforePos0++;
+        }
+      }
+    } //end for (iScanPosinCG)
+
+    if (iCGLastScanPos >= 0)
+    {
+      if( cctx.subSetId() )
+      {
+        if( !cctx.isSigGroup() )
+        {
+          const BinFracBits fracBitsSigGroup = fracBits.getFracBitsArray( cctx.sigGroupCtxId() );
+          d64BaseCost += xGetRateSigCoeffGroup(fracBitsSigGroup, 0) - rdStats.d64SigCost;
+          pdCostCoeffGroupSig[ cctx.subSetId() ] = xGetRateSigCoeffGroup(fracBitsSigGroup, 0);
+        }
+        else
+        {
+          {
+            if ( rdStats.iNNZbeforePos0 == 0 )
+            {
+              d64BaseCost -= rdStats.d64SigCost_0;
+              rdStats.d64SigCost -= rdStats.d64SigCost_0;
+            }
+            // rd-cost if SigCoeffGroupFlag = 0, initialization
+            double d64CostZeroCG = d64BaseCost;
+
+            const BinFracBits fracBitsSigGroup = fracBits.getFracBitsArray( cctx.sigGroupCtxId() );
+
+
+            d64BaseCost  += xGetRateSigCoeffGroup(fracBitsSigGroup,1);
+            d64CostZeroCG += xGetRateSigCoeffGroup(fracBitsSigGroup,0);
+            pdCostCoeffGroupSig[ cctx.subSetId() ] = xGetRateSigCoeffGroup(fracBitsSigGroup,1);
+
+            // try to convert the current coeff group from non-zero to all-zero
+            d64CostZeroCG += rdStats.d64UncodedDist;  // distortion for resetting non-zero levels to zero levels
+            d64CostZeroCG -= rdStats.d64CodedLevelandDist;   // distortion and level cost for keeping all non-zero levels
+            d64CostZeroCG -= rdStats.d64SigCost;     // sig cost for all coeffs, including zero levels and non-zerl levels
+
+                                                     // if we can save cost, change this block to all-zero block
+            if ( d64CostZeroCG < d64BaseCost )
+            {
+              cctx.resetSigGroup();
+              d64BaseCost = d64CostZeroCG;
+
+              pdCostCoeffGroupSig[ cctx.subSetId() ] = xGetRateSigCoeffGroup(fracBitsSigGroup,0);
+
+              // reset coeffs to 0 in this block
+              for( int iScanPosinCG = maxNonZeroPosInCG; iScanPosinCG >= 0; iScanPosinCG-- )
+              {
+                iScanPos      = cctx.minSubPos() + iScanPosinCG;
+                uint32_t uiBlkPos = cctx.blockPos( iScanPos );
+  	            const int posX        = cctx.posX(iScanPos);
+                const int posY        = cctx.posY(iScanPos);
+                const int posS        = (1 == dirMode) ? posX : posY;
+  	            const int boundaryLim = (1 == dirMode) ? uiWidth-1 : uiHeight-1;
+  	            const int posNb       = (1 == dirMode) ? (posX + 1) + posY * pSrc.stride : posX + (posY + 1) * pSrc.stride;
+  	            m_fullCoeff[uiBlkPos] = (boundaryLim != posS) ? m_fullCoeff[posNb] : 0;	
+
+                if (piDstCoeff[ uiBlkPos ])
+                {
+                  piDstCoeff [ uiBlkPos ] = 0;
+                  pdCostCoeff[ iScanPos ] = pdCostCoeff0[ iScanPos ];
+                  pdCostSig  [ iScanPos ] = 0;
+                }
+              }
+            }
+          }
+        } // end if if (uiSigCoeffGroupFlag[ uiCGBlkPos ] == 0)
+      }
+      else
+      {
+        cctx.setSigGroup();
+      }
+    }
+  } //end for (cctx.subSetId)
+
+
+  //===== estimate last position =====
+  for ( int scanPos = 0; scanPos < uiMaxNumCoeff; scanPos++ )
+  {
+    int blkPos   = cctx.blockPos( scanPos );
+    TCoeff level = piDstCoeff[ blkPos ];
+	uiAbsSum    += abs(level);
+  }
+
+  // rotate block
+  for (uint32_t y = 0, coefficientIndex = 0; y < uiHeight; y++)
+  {
+    for (uint32_t x = 0; x < uiWidth; x++, coefficientIndex++)
+    {
+  		m_dstCoeffTemp[coefficientIndex] = tu.getCoeffs(compID).buf[uiSizeMinus1 - coefficientIndex];
+    }
+  }
+  memcpy( tu.getCoeffs(compID).buf, m_dstCoeffTemp, sizeof(TCoeff) * numSamplesInBlock );
+}
+#endif
+
 void QuantRDOQ::forwardRDPCM( TransformUnit &tu, const ComponentID &compID, const CCoeffBuf &coeffs, TCoeff &absSum, const QpParam &qp, const Ctx &ctx )
 {
   const FracBitsAccess& fracBits = ctx.getFracBitsAcess();
diff --git a/source/Lib/CommonLib/QuantRDOQ.h b/source/Lib/CommonLib/QuantRDOQ.h
index ec3ca1c6..f41828f6 100644
--- a/source/Lib/CommonLib/QuantRDOQ.h
+++ b/source/Lib/CommonLib/QuantRDOQ.h
@@ -66,6 +66,9 @@ public:
   // quantization
   void quant                ( TransformUnit &tu, const ComponentID &compID, const CCoeffBuf &pSrc, TCoeff &uiAbsSum, const QpParam &cQP, const Ctx& ctx );
   void forwardRDPCM         ( TransformUnit &tu, const ComponentID &compID, const CCoeffBuf &pSrc, TCoeff &uiAbsSum, const QpParam &cQP, const Ctx &ctx );
+#if QC_TS_RRC_RDOQ
+  void forwardRRCRDPCM        ( TransformUnit &tu, const ComponentID &compID, const CCoeffBuf &pSrc, TCoeff &uiAbsSum, const QpParam &cQP, const Ctx &ctx );
+#endif
 
 private:
   double* xGetErrScaleCoeffSL            ( uint32_t list, uint32_t sizeX, uint32_t sizeY, int qp ) { return m_errScale[sizeX][sizeY][list][qp]; };  //!< get Error Scale Coefficent
@@ -166,6 +169,10 @@ private:
   int    m_sigRateDelta       [MAX_TB_SIZEY * MAX_TB_SIZEY];
   TCoeff m_deltaU             [MAX_TB_SIZEY * MAX_TB_SIZEY];
   TCoeff m_fullCoeff          [MAX_TB_SIZEY * MAX_TB_SIZEY];
+#if QC_TS_RRC_RDOQ
+  TCoeff m_srcCoeffTemp       [MAX_TB_SIZEY * MAX_TB_SIZEY];
+  TCoeff m_dstCoeffTemp       [MAX_TB_SIZEY * MAX_TB_SIZEY];
+#endif
   int   m_bdpcm;
   int   m_testedLevels;
 };// END CLASS DEFINITION QuantRDOQ
diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h
index 2d4c84c3..6c57352f 100644
--- a/source/Lib/CommonLib/TypeDef.h
+++ b/source/Lib/CommonLib/TypeDef.h
@@ -50,6 +50,9 @@
 #include <assert.h>
 #include <cassert>
 
+#define QC_TEST_TS_RRC                                    1
+#define QC_TS_RRC_RDOQ                                    1
+
 #define JVET_Q0237_STSA_TID_ZERO_DEPLAYER                 1 // JVET-Q0237: STSA picture with TemporalId equal to 0 in a dependent layer
 
 #define JVET_Q0798_SPS_NUMBER_MERGE_CANDIDATE             1 // JVET-Q0798: signal the number of merge candidates in SPS
diff --git a/source/Lib/EncoderLib/EncSlice.cpp b/source/Lib/EncoderLib/EncSlice.cpp
index a7d4ff10..e6a4d2b9 100644
--- a/source/Lib/EncoderLib/EncSlice.cpp
+++ b/source/Lib/EncoderLib/EncSlice.cpp
@@ -350,7 +350,11 @@ void EncSlice::initEncSlice(Picture* pcPic, const int pocLast, const int pocCurr
   }
   else
   {
+#if QC_TEST_TS_RRC
+    rpcSlice->setTSResidualCodingDisabledFlag(true);
+#else
     rpcSlice->setTSResidualCodingDisabledFlag(false);
+#endif
   }
 #endif
 
-- 
2.21.0.windows.1

