// File: /workspace/github_c_makefile_star2_O2/jonof[P]jftekwar/jfbuild/src/rg_etc1.cpp
// Function: rg_etc1::etc1_optimizer::compute()
bool etc1_optimizer::compute()
   {
      const uint n = m_pParams->m_num_src_pixels;
      const int scan_delta_size = m_pParams->m_scan_delta_size;
      
      // Scan through a subset of the 3D lattice centered around the avg block color trying each 3D (555 or 444) lattice point as a potential block color.
      // Each time a better solution is found try to refine the current solution's block color based of the current selectors and intensity table index.
      for (int zdi = 0; zdi < scan_delta_size; zdi++)
      {
         const int zd = m_pParams->m_pScan_deltas[zdi];
         const int mbb = m_bb + zd;
         if (mbb < 0) continue; else if (mbb > m_limit) break;
         
         for (int ydi = 0; ydi < scan_delta_size; ydi++)
         {
            const int yd = m_pParams->m_pScan_deltas[ydi];
            const int mbg = m_bg + yd;
            if (mbg < 0) continue; else if (mbg > m_limit) break;

            for (int xdi = 0; xdi < scan_delta_size; xdi++)
            {
               const int xd = m_pParams->m_pScan_deltas[xdi];
               const int mbr = m_br + xd;
               if (mbr < 0) continue; else if (mbr > m_limit) break;
      
               etc1_solution_coordinates coords(mbr, mbg, mbb, 0, m_pParams->m_use_color4);
               if (m_pParams->m_quality == cHighQuality)
               {
                  if (!evaluate_solution(coords, m_trial_solution, &m_best_solution))
                     continue;
               }
               else
               {
                  if (!evaluate_solution_fast(coords, m_trial_solution, &m_best_solution))
                     continue;
               }
               
               // Now we have the input block, the avg. color of the input pixels, a set of trial selector indices, and the block color+intensity index.
               // Now, for each component, attempt to refine the current solution by solving a simple linear equation. For example, for 4 colors:
               // The goal is:
               // pixel0 - (block_color+inten_table[selector0]) + pixel1 - (block_color+inten_table[selector1]) + pixel2 - (block_color+inten_table[selector2]) + pixel3 - (block_color+inten_table[selector3]) = 0
               // Rearranging this:
               // (pixel0 + pixel1 + pixel2 + pixel3) - (block_color+inten_table[selector0]) - (block_color+inten_table[selector1]) - (block_color+inten_table[selector2]) - (block_color+inten_table[selector3]) = 0
               // (pixel0 + pixel1 + pixel2 + pixel3) - block_color - inten_table[selector0] - block_color-inten_table[selector1] - block_color-inten_table[selector2] - block_color-inten_table[selector3] = 0
               // (pixel0 + pixel1 + pixel2 + pixel3) - 4*block_color - inten_table[selector0] - inten_table[selector1] - inten_table[selector2] - inten_table[selector3] = 0
               // (pixel0 + pixel1 + pixel2 + pixel3) - 4*block_color - (inten_table[selector0] + inten_table[selector1] + inten_table[selector2] + inten_table[selector3]) = 0
               // (pixel0 + pixel1 + pixel2 + pixel3)/4 - block_color - (inten_table[selector0] + inten_table[selector1] + inten_table[selector2] + inten_table[selector3])/4 = 0
               // block_color = (pixel0 + pixel1 + pixel2 + pixel3)/4 - (inten_table[selector0] + inten_table[selector1] + inten_table[selector2] + inten_table[selector3])/4
               // So what this means:
               // optimal_block_color = avg_input - avg_inten_delta
               // So the optimal block color can be computed by taking the average block color and subtracting the current average of the intensity delta.
               // Unfortunately, optimal_block_color must then be quantized to 555 or 444 so it's not always possible to improve matters using this formula.
               // Also, the above formula is for unclamped intensity deltas. The actual implementation takes into account clamping.

               const uint max_refinement_trials = (m_pParams->m_quality == cLowQuality) ? 2 : (((xd | yd | zd) == 0) ? 4 : 2);
               for (uint refinement_trial = 0; refinement_trial < max_refinement_trials; refinement_trial++)
               {
                  const uint8* pSelectors = m_best_solution.m_selectors;
                  const int* pInten_table = g_etc1_inten_tables[m_best_solution.m_coords.m_inten_table];

                  int delta_sum_r = 0, delta_sum_g = 0, delta_sum_b = 0;
                  const color_quad_u8 base_color(m_best_solution.m_coords.get_scaled_color());
                  for (uint r = 0; r < n; r++)
                  {
                     const uint s = *pSelectors++;
                     const int yd = pInten_table[s];
                     // Compute actual delta being applied to each pixel, taking into account clamping.
                     delta_sum_r += rg_etc1::clamp<int>(base_color.r + yd, 0, 255) - base_color.r;
                     delta_sum_g += rg_etc1::clamp<int>(base_color.g + yd, 0, 255) - base_color.g;
                     delta_sum_b += rg_etc1::clamp<int>(base_color.b + yd, 0, 255) - base_color.b;
                  }
                  if ((!delta_sum_r) && (!delta_sum_g) && (!delta_sum_b))
                     break;
                  const float avg_delta_r_f = static_cast<float>(delta_sum_r) / n;
                  const float avg_delta_g_f = static_cast<float>(delta_sum_g) / n;
                  const float avg_delta_b_f = static_cast<float>(delta_sum_b) / n;
                  const int br1 = rg_etc1::clamp<int>(static_cast<uint>((m_avg_color[0] - avg_delta_r_f) * m_limit / 255.0f + .5f), 0, m_limit);
                  const int bg1 = rg_etc1::clamp<int>(static_cast<uint>((m_avg_color[1] - avg_delta_g_f) * m_limit / 255.0f + .5f), 0, m_limit);
                  const int bb1 = rg_etc1::clamp<int>(static_cast<uint>((m_avg_color[2] - avg_delta_b_f) * m_limit / 255.0f + .5f), 0, m_limit);
                  
                  bool skip = false;
                  
                  if ((mbr == br1) && (mbg == bg1) && (mbb == bb1))
                     skip = true;
                  else if ((br1 == m_best_solution.m_coords.m_unscaled_color.r) && (bg1 == m_best_solution.m_coords.m_unscaled_color.g) && (bb1 == m_best_solution.m_coords.m_unscaled_color.b))
                     skip = true;
                  else if ((m_br == br1) && (m_bg == bg1) && (m_bb == bb1))
                     skip = true;

                  if (skip)
                     break;

                  etc1_solution_coordinates coords1(br1, bg1, bb1, 0, m_pParams->m_use_color4);
                  if (m_pParams->m_quality == cHighQuality)
                  {
                     if (!evaluate_solution(coords1, m_trial_solution, &m_best_solution)) 
                        break;
                  }
                  else
                  {
                     if (!evaluate_solution_fast(coords1, m_trial_solution, &m_best_solution))
                        break;
                  }

               }  // refinement_trial

            } // xdi
         } // ydi
      } // zdi

      if (!m_best_solution.m_valid)
      {
         m_pResult->m_error = cUINT32_MAX;
         return false;
      }
      
      const uint8* pSelectors = m_best_solution.m_selectors;

#ifdef RG_ETC1_BUILD_DEBUG
      {
         color_quad_u8 block_colors[4];
         m_best_solution.m_coords.get_block_colors(block_colors);

         const color_quad_u8* pSrc_pixels = m_pParams->m_pSrc_pixels;
         uint64 actual_error = 0;
         for (uint i = 0; i < n; i++)
            actual_error += pSrc_pixels[i].squared_distance_rgb(block_colors[pSelectors[i]]);
         
         RG_ETC1_ASSERT(actual_error == m_best_solution.m_error);
      }
#endif      
      
      m_pResult->m_error = m_best_solution.m_error;

      m_pResult->m_block_color_unscaled = m_best_solution.m_coords.m_unscaled_color;
      m_pResult->m_block_color4 = m_best_solution.m_coords.m_color4;
      
      m_pResult->m_block_inten_table = m_best_solution.m_coords.m_inten_table;
      memcpy(m_pResult->m_pSelectors, pSelectors, n);
      m_pResult->m_n = n;

      return true;
   }

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0xa8, %rsp
movq %rdi, %rbx
movq (%rdi), %rax
movl 0x8(%rax), %r14d
movl 0x28(%rax), %eax
leaq 0xc8(%rdi), %rcx
movq %rcx, 0x38(%rsp)
leaq 0xa0(%rdi), %rcx
movq %rcx, 0x8(%rsp)
cvtsi2ss %r14, %xmm0
testl %eax, %eax
movl $0x0, %ecx
movq %rax, 0x50(%rsp)
cmovgl %eax, %ecx
movq %rcx, 0x60(%rsp)
leaq 0xac(%rdi), %rax
movq %rax, 0x58(%rsp)
movaps %xmm0, 0x90(%rsp)
shufps $0x0, %xmm0, %xmm0      # xmm0 = xmm0[0,0,0,0]
movaps %xmm0, 0x80(%rsp)
movl $0xff, %ebp
xorl %ecx, %ecx
cmpq 0x60(%rsp), %rcx
je 0x5f74c
movq (%rbx), %rax
movq 0x20(%rax), %rax
movq %rcx, 0x68(%rsp)
movl (%rax,%rcx,4), %eax
movl 0x28(%rbx), %ecx
movl %eax, 0x40(%rsp)
addl %eax, %ecx
movl %ecx, 0x14(%rsp)
js 0x5f73f
movl 0x14(%rsp), %eax
cmpl 0x10(%rbx), %eax
jg 0x5f74c
cmpl %ebp, %eax
movl $0xff, %ecx
cmovbl %eax, %ecx
movl %ecx, 0x44(%rsp)
xorl %ecx, %ecx
cmpq 0x50(%rsp), %rcx
je 0x5f73f
movq (%rbx), %rax
movq 0x20(%rax), %rax
movq %rcx, 0x70(%rsp)
movl (%rax,%rcx,4), %eax
movl 0x24(%rbx), %ecx
movl %eax, 0x4(%rsp)
addl %eax, %ecx
movl %ecx, 0x18(%rsp)
js 0x5f732
movl 0x18(%rsp), %eax
cmpl 0x10(%rbx), %eax
jg 0x5f73f
cmpl %ebp, %eax
movl $0xff, %ecx
cmovbl %eax, %ecx
movl %ecx, 0x48(%rsp)
movl 0x4(%rsp), %eax
orl 0x40(%rsp), %eax
movl %eax, 0x4(%rsp)
xorl %edx, %edx
cmpq 0x50(%rsp), %rdx
je 0x5f732
movq (%rbx), %rax
movq 0x20(%rax), %rcx
movl (%rcx,%rdx,4), %r12d
movl 0x20(%rbx), %r15d
addl %r12d, %r15d
js 0x5f72a
cmpl 0x10(%rbx), %r15d
jg 0x5f732
movq %rdx, 0x78(%rsp)
cmpl %ebp, %r15d
movl $0xff, %ecx
cmovbl %r15d, %ecx
movb 0x18(%rax), %dl
movb %cl, 0x2c(%rsp)
movl 0x48(%rsp), %ecx
movb %cl, 0x2d(%rsp)
movl 0x44(%rsp), %ecx
movb %cl, 0x2e(%rsp)
movb $-0x1, 0x2f(%rsp)
andl $0x0, 0x30(%rsp)
movb %dl, 0x34(%rsp)
cmpl $0x2, (%rax)
jne 0x5f43b
movq %rbx, %rdi
leaq 0x2c(%rsp), %rsi
movq 0x38(%rsp), %rdx
movq 0x8(%rsp), %rcx
callq 0x5f7c0
jmp 0x5f452
movq %rbx, %rdi
leaq 0x2c(%rsp), %rsi
movq 0x38(%rsp), %rdx
movq 0x8(%rsp), %rcx
callq 0x5fb1a
testb %al, %al
je 0x5f725
movq (%rbx), %rax
xorl %ecx, %ecx
orl 0x4(%rsp), %r12d
sete %cl
cmpl $0x0, (%rax)
leal 0x2(%rcx,%rcx), %ecx
pushq $0x2
popq %rax
cmovel %eax, %ecx
movl %ecx, 0x4c(%rsp)
xorl %r13d, %r13d
cmpl 0x4c(%rsp), %r13d
je 0x5f725
movl 0xa4(%rbx), %r12d
shlq $0x4, %r12
leaq 0x12728(%rip), %rax     # 0x71bc0
addq %rax, %r12
leaq 0x1c(%rsp), %rdi
movq 0x8(%rsp), %rsi
callq 0x61150
movd 0x1c(%rsp), %xmm1
xorps %xmm0, %xmm0
punpcklbw %xmm0, %xmm1    # xmm1 = xmm1[0],xmm0[0],xmm1[1],xmm0[1],xmm1[2],xmm0[2],xmm1[3],xmm0[3],xmm1[4],xmm0[4],xmm1[5],xmm0[5],xmm1[6],xmm0[6],xmm1[7],xmm0[7]
pextrw $0x0, %xmm1, %ecx
pextrw $0x1, %xmm1, %edx
punpcklwd %xmm0, %xmm1    # xmm1 = xmm1[0],xmm0[0],xmm1[1],xmm0[1],xmm1[2],xmm0[2],xmm1[3],xmm0[3]
movzbl 0x1e(%rsp), %esi
xorl %edi, %edi
xorl %eax, %eax
cmpl %edi, %r14d
je 0x5f538
movzbl 0xac(%rbx,%rdi), %r8d
movl (%r12,%r8,4), %r8d
leal (%r8,%rcx), %r9d
cmpl %ebp, %r9d
cmovgel %ebp, %r9d
testl %r9d, %r9d
jg 0x5f4f3
xorl %r9d, %r9d
leal (%r8,%rdx), %r10d
cmpl %ebp, %r10d
cmovgel %ebp, %r10d
testl %r10d, %r10d
jg 0x5f506
xorl %r10d, %r10d
addl %esi, %r8d
cmpl %ebp, %r8d
cmovgel %ebp, %r8d
testl %r8d, %r8d
jg 0x5f518
xorl %r8d, %r8d
psubd %xmm1, %xmm0
movd %r10d, %xmm2
movd %r9d, %xmm3
punpckldq %xmm2, %xmm3    # xmm3 = xmm3[0],xmm2[0],xmm3[1],xmm2[1]
paddd %xmm3, %xmm0
subl %esi, %eax
addl %r8d, %eax
incq %rdi
jmp 0x5f4ce
pshufd $0x50, %xmm0, %xmm1     # xmm1 = xmm0[0,0,1,1]
pcmpeqd 0x11e8b(%rip), %xmm1    # 0x713d0
movmskpd %xmm1, %ecx
xorl $0x3, %ecx
testb $0x1, %cl
jne 0x5f55d
shrb %cl
jne 0x5f55d
testl %eax, %eax
je 0x5f725
cvtsi2ss %eax, %xmm1
cvtdq2ps %xmm0, %xmm3
divps 0x80(%rsp), %xmm3
divss 0x90(%rsp), %xmm1
movl 0x10(%rbx), %eax
cvtsi2ss %eax, %xmm2
movsd 0x14(%rbx), %xmm0
subps %xmm3, %xmm0
movss 0x1c(%rbx), %xmm3
subss %xmm1, %xmm3
mulss %xmm2, %xmm3
shufps $0x0, %xmm2, %xmm2      # xmm2 = xmm2[0,0,0,0]
mulps %xmm0, %xmm2
divps 0xff41(%rip), %xmm2     # 0x6f4e0
addps 0x11e0a(%rip), %xmm2    # 0x713b0
cvttps2dq %xmm2, %xmm0
movdqa %xmm0, %xmm1
psrad $0x1f, %xmm1
subps 0x11e06(%rip), %xmm2    # 0x713c0
cvttps2dq %xmm2, %xmm2
pand %xmm1, %xmm2
por %xmm0, %xmm2
movd %eax, %xmm0
pshufd $0x50, %xmm0, %xmm1     # xmm1 = xmm0[0,0,1,1]
movdqa %xmm1, %xmm4
pcmpgtd %xmm2, %xmm4
pxor %xmm0, %xmm0
pcmpgtd %xmm2, %xmm0
pand %xmm4, %xmm2
pandn %xmm1, %xmm4
por %xmm2, %xmm4
pandn %xmm4, %xmm0
pshufd $0x55, %xmm0, %xmm1     # xmm1 = xmm0[1,1,1,1]
movd %xmm1, %ecx
divss 0xfd20(%rip), %xmm3     # 0x6f320
addss 0xfd00(%rip), %xmm3     # 0x6f308
cvttss2si %xmm3, %rsi
movd %xmm0, %edx
cmpl %eax, %esi
cmovll %esi, %eax
testl %esi, %esi
movl $0x0, %esi
cmovsl %esi, %eax
cmpl %edx, %r15d
jne 0x5f635
cmpl %ecx, 0x18(%rsp)
jne 0x5f635
cmpl %eax, 0x14(%rsp)
je 0x5f725
movq 0xa0(%rbx), %xmm1
pxor %xmm2, %xmm2
punpcklbw %xmm2, %xmm1    # xmm1 = xmm1[0],xmm2[0],xmm1[1],xmm2[1],xmm1[2],xmm2[2],xmm1[3],xmm2[3],xmm1[4],xmm2[4],xmm1[5],xmm2[5],xmm1[6],xmm2[6],xmm1[7],xmm2[7]
punpcklwd %xmm2, %xmm1    # xmm1 = xmm1[0],xmm2[0],xmm1[1],xmm2[1],xmm1[2],xmm2[2],xmm1[3],xmm2[3]
pshufd $0x50, %xmm1, %xmm1     # xmm1 = xmm1[0,0,1,1]
pshufd $0x50, %xmm0, %xmm2     # xmm2 = xmm0[0,0,1,1]
pcmpeqd %xmm1, %xmm2
movmskpd %xmm2, %esi
testb $0x1, %sil
je 0x5f675
shrb %sil
je 0x5f675
movzbl 0xa2(%rbx), %esi
cmpl %esi, %eax
je 0x5f725
movq 0x20(%rbx), %xmm1
pcmpeqd %xmm0, %xmm1
pshufd $0x50, %xmm1, %xmm0     # xmm0 = xmm1[0,0,1,1]
movmskpd %xmm0, %esi
testb $0x1, %sil
je 0x5f69b
shrb %sil
je 0x5f69b
cmpl %eax, 0x28(%rbx)
je 0x5f725
testl %edx, %edx
movl $0x0, %r8d
cmovlel %r8d, %edx
movq (%rbx), %rsi
cmpl %ebp, %edx
cmovgel %ebp, %edx
movb 0x18(%rsi), %dil
testl %ecx, %ecx
cmovlel %r8d, %ecx
movb %dl, 0x20(%rsp)
cmpl %ebp, %ecx
cmovgel %ebp, %ecx
movb %cl, 0x21(%rsp)
testl %eax, %eax
cmovlel %r8d, %eax
cmpl %ebp, %eax
cmovgel %ebp, %eax
movb %al, 0x22(%rsp)
movb $-0x1, 0x23(%rsp)
andl $0x0, 0x24(%rsp)
movb %dil, 0x28(%rsp)
cmpl $0x2, (%rsi)
jne 0x5f702
movq %rbx, %rdi
leaq 0x20(%rsp), %rsi
movq 0x38(%rsp), %rdx
movq 0x8(%rsp), %rcx
callq 0x5f7c0
jmp 0x5f719
movq %rbx, %rdi
leaq 0x20(%rsp), %rsi
movq 0x38(%rsp), %rdx
movq 0x8(%rsp), %rcx
callq 0x5fb1a
testb %al, %al
je 0x5f725
incl %r13d
jmp 0x5f47b
movq 0x78(%rsp), %rdx
incq %rdx
jmp 0x5f3ba
movq 0x70(%rsp), %rcx
incq %rcx
jmp 0x5f364
movq 0x68(%rsp), %rcx
incq %rcx
jmp 0x5f31a
movb 0xc0(%rbx), %bpl
testb %bpl, %bpl
je 0x5f7a0
movq 0x8(%rbx), %rax
movq 0xb8(%rbx), %rcx
movq %rcx, (%rax)
movl 0xa0(%rbx), %ecx
movl %ecx, 0x8(%rax)
movb 0xa8(%rbx), %al
movq 0x8(%rbx), %rcx
movb %al, 0x20(%rcx)
movl 0xa4(%rbx), %eax
movl %eax, 0xc(%rcx)
movq 0x18(%rcx), %rdi
movq 0x58(%rsp), %rsi
movq %r14, %rdx
callq 0x60c0
movq 0x8(%rbx), %rax
movl %r14d, 0x10(%rax)
jmp 0x5f7ac
movq 0x8(%rbx), %rax
movl $0xffffffff, %ecx       # imm = 0xFFFFFFFF
movq %rcx, (%rax)
movl %ebp, %eax
addq $0xa8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq