Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a2215293 authored by Nick Deakin's avatar Nick Deakin
Browse files

libjpegrecoverymap: Update min/max boost determination.

Fix min/max content boost to 1 / 10 for HLG and 1 / 100 for PQ.
Determining these values based on both input images can be problematic
due to jpeg encoding artifacts. Additionally, min of 1 seems justified
since attentuation during map application has not come up in a
meaningful way in practice with HLG and PQ input.

This also has the nice benefit of improving encode performance
significantly; generate map numbers for 12MP on Pixel 7 Pro are now
around 45ms, down from ~150ms!

Bug: 264715926
Test: tests pass
Change-Id: Ia016b68de5900cb263d383b1ae64f7c39cc499cd
parent 3f89a3ee
Loading
Loading
Loading
Loading
+4 −60
Original line number Diff line number Diff line
@@ -554,6 +554,9 @@ status_t JpegR::generateRecoveryMap(jr_uncompressed_ptr uncompressed_yuv_420_ima
      return ERROR_JPEGR_INVALID_TRANS_FUNC;
  }

  metadata->maxContentBoost = hdr_white_nits / kSdrWhiteNits;
  metadata->minContentBoost = 1.0f;

  ColorTransformFn hdrGamutConversionFn = getHdrConversionFn(
      uncompressed_yuv_420_image->colorGamut, uncompressed_p010_image->colorGamut);

@@ -574,50 +577,10 @@ status_t JpegR::generateRecoveryMap(jr_uncompressed_ptr uncompressed_yuv_420_ima
  }

  std::mutex mutex;
  float max_gain = 0.0f;
  float min_gain = 1.0f;
  const int threads = std::clamp(GetCPUCoreCount(), 1, 4);
  size_t rowStep = threads == 1 ? image_height : kJobSzInRows;
  JobQueue jobQueue;

  std::function<void()> computeMetadata = [uncompressed_p010_image, uncompressed_yuv_420_image,
                                           hdrInvOetf, hdrGamutConversionFn, luminanceFn,
                                           hdr_white_nits, threads, &mutex, &max_gain, &min_gain,
                                           &jobQueue]() -> void {
    size_t rowStart, rowEnd;
    float max_gain_th = 0.0f;
    float min_gain_th = 1.0f;

    while (jobQueue.dequeueJob(rowStart, rowEnd)) {
      for (size_t y = rowStart; y < rowEnd; ++y) {
        for (size_t x = 0; x < uncompressed_p010_image->width; ++x) {
          Color hdr_yuv_gamma = getP010Pixel(uncompressed_p010_image, x, y);
          Color hdr_rgb_gamma = bt2100YuvToRgb(hdr_yuv_gamma);
          Color hdr_rgb = hdrInvOetf(hdr_rgb_gamma);
          hdr_rgb = hdrGamutConversionFn(hdr_rgb);
          float hdr_y_nits = luminanceFn(hdr_rgb) * hdr_white_nits;

          Color sdr_yuv_gamma =
              getYuv420Pixel(uncompressed_yuv_420_image, x, y);
          Color sdr_rgb_gamma = srgbYuvToRgb(sdr_yuv_gamma);
#if USE_SRGB_INVOETF_LUT
          Color sdr_rgb = srgbInvOetfLUT(sdr_rgb_gamma);
#else
          Color sdr_rgb = srgbInvOetf(sdr_rgb_gamma);
#endif
          float sdr_y_nits = luminanceFn(sdr_rgb) * kSdrWhiteNits;

          float gain = hdr_y_nits / sdr_y_nits;
          max_gain_th = std::max(max_gain_th, gain);
          min_gain_th = std::min(min_gain_th, gain);
        }
      }
    }
    std::unique_lock<std::mutex> lock{mutex};
    max_gain = std::max(max_gain, max_gain_th);
    min_gain = std::min(min_gain, min_gain_th);
  };

  std::function<void()> generateMap = [uncompressed_yuv_420_image, uncompressed_p010_image,
                                       metadata, dest, hdrInvOetf, hdrGamutConversionFn,
                                       luminanceFn, hdr_white_nits, &jobQueue]() -> void {
@@ -651,27 +614,8 @@ status_t JpegR::generateRecoveryMap(jr_uncompressed_ptr uncompressed_yuv_420_ima
    }
  };

  std::vector<std::thread> workers;
  for (int th = 0; th < threads - 1; th++) {
    workers.push_back(std::thread(computeMetadata));
  }

  // compute metadata
  for (size_t rowStart = 0; rowStart < image_height;) {
    size_t rowEnd = std::min(rowStart + rowStep, image_height);
    jobQueue.enqueueJob(rowStart, rowEnd);
    rowStart = rowEnd;
  }
  jobQueue.markQueueForEnd();
  computeMetadata();
  std::for_each(workers.begin(), workers.end(), [](std::thread& t) { t.join(); });
  workers.clear();

  metadata->maxContentBoost = max_gain;
  metadata->minContentBoost = min_gain;

  // generate map
  jobQueue.reset();
  std::vector<std::thread> workers;
  for (int th = 0; th < threads - 1; th++) {
    workers.push_back(std::thread(generateMap));
  }