Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/third_party/jpeg-xl/lib/jxl/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 8 kB image not shown  

Quelle  dec_group_border.cc   Sprache: C

 
// Copyright (c) the JPEG XL Project Authors. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

#include "lib/jxl/dec_group_border.h"

#include <atomic>
#include <cstddef>
#include <cstdint>
#include <utility>

#include "lib/jxl/base/rect.h"
#include "lib/jxl/base/status.h"
#include "lib/jxl/frame_dimensions.h"

namespace jxl {

void GroupBorderAssigner::Init(const FrameDimensions& frame_dim) {
  frame_dim_ = frame_dim;
  size_t num_corners =
      (frame_dim_.xsize_groups + 1) * (frame_dim_.ysize_groups + 1);
  { std::vector<std::atomic<uint8_t>>(num_corners).swap(counters_); }
  // Initialize counters.
  for (size_t y = 0; y < frame_dim_.ysize_groups + 1; y++) {
    for (size_t x = 0; x < frame_dim_.xsize_groups + 1; x++) {
      // Counters at image borders don't have anything on the other side, we
      // pre-fill their value to have more uniform handling afterwards.
      uint8_t init_value = 0;
      if (x == 0) {
        init_value |= kTopLeft | kBottomLeft;
      }
      if (x == frame_dim_.xsize_groups) {
        init_value |= kTopRight | kBottomRight;
      }
      if (y == 0) {
        init_value |= kTopLeft | kTopRight;
      }
      if (y == frame_dim_.ysize_groups) {
        init_value |= kBottomLeft | kBottomRight;
      }
      counters_[y * (frame_dim_.xsize_groups + 1) + x] = init_value;
    }
  }
}

void GroupBorderAssigner::ClearDone(size_t group_id) {
  size_t x = group_id % frame_dim_.xsize_groups;
  size_t y = group_id / frame_dim_.xsize_groups;
  size_t top_left_idx = y * (frame_dim_.xsize_groups + 1) + x;
  size_t top_right_idx = y * (frame_dim_.xsize_groups + 1) + x + 1;
  size_t bottom_right_idx = (y + 1) * (frame_dim_.xsize_groups + 1) + x + 1;
  size_t bottom_left_idx = (y + 1) * (frame_dim_.xsize_groups + 1) + x;
  counters_[top_left_idx].fetch_and(~kBottomRight);
  counters_[top_right_idx].fetch_and(~kBottomLeft);
  counters_[bottom_left_idx].fetch_and(~kTopRight);
  counters_[bottom_right_idx].fetch_and(~kTopLeft);
}

// Looking at each corner between groups, we can guarantee that the four
// involved groups will agree between each other regarding the order in which
// each of the four groups terminated. Thus, the last of the four groups
// gets the responsibility of handling the corner. For borders, every border
// is assigned to its top corner (for vertical borders) or to its left corner
// (for horizontal borders): the order as seen on those corners will decide who
// handles that border.

void GroupBorderAssigner::GroupDone(size_t group_id, size_t padx, size_t pady,
                                    Rect* rects_to_finalize,
                                    size_t* num_to_finalize) {
  size_t x = group_id % frame_dim_.xsize_groups;
  size_t y = group_id / frame_dim_.xsize_groups;
  Rect block_rect(x * frame_dim_.group_dim / kBlockDim,
                  y * frame_dim_.group_dim / kBlockDim,
                  frame_dim_.group_dim / kBlockDim,
                  frame_dim_.group_dim / kBlockDim, frame_dim_.xsize_blocks,
                  frame_dim_.ysize_blocks);

  size_t top_left_idx = y * (frame_dim_.xsize_groups + 1) + x;
  size_t top_right_idx = y * (frame_dim_.xsize_groups + 1) + x + 1;
  size_t bottom_right_idx = (y + 1) * (frame_dim_.xsize_groups + 1) + x + 1;
  size_t bottom_left_idx = (y + 1) * (frame_dim_.xsize_groups + 1) + x;

  auto fetch_status = [this](size_t idx, uint8_t bit) {
    // Note that the acq-rel semantics of this fetch are actually needed to
    // ensure that the pixel data of the group is already written to memory.
    size_t status = counters_[idx].fetch_or(bit);
    JXL_DASSERT((bit & status) == 0);
    return bit | status;
  };

  size_t top_left_status = fetch_status(top_left_idx, kBottomRight);
  size_t top_right_status = fetch_status(top_right_idx, kBottomLeft);
  size_t bottom_right_status = fetch_status(bottom_right_idx, kTopLeft);
  size_t bottom_left_status = fetch_status(bottom_left_idx, kTopRight);

  size_t x1 = block_rect.x0() + block_rect.xsize();
  size_t y1 = block_rect.y0() + block_rect.ysize();

  bool is_last_group_x = frame_dim_.xsize_groups == x + 1;
  bool is_last_group_y = frame_dim_.ysize_groups == y + 1;

  // Start of border of neighbouring group, end of border of this group, start
  // of border of this group (on the other side), end of border of next group.
  size_t xpos[4] = {
      block_rect.x0() == 0 ? 0 : block_rect.x0() * kBlockDim - padx,
      block_rect.x0() == 0
          ? 0
          : std::min(frame_dim_.xsize, block_rect.x0() * kBlockDim + padx),
      is_last_group_x ? frame_dim_.xsize : x1 * kBlockDim - padx,
      std::min(frame_dim_.xsize, x1 * kBlockDim + padx)};
  size_t ypos[4] = {
      block_rect.y0() == 0 ? 0 : block_rect.y0() * kBlockDim - pady,
      block_rect.y0() == 0
          ? 0
          : std::min(frame_dim_.ysize, block_rect.y0() * kBlockDim + pady),
      is_last_group_y ? frame_dim_.ysize : y1 * kBlockDim - pady,
      std::min(frame_dim_.ysize, y1 * kBlockDim + pady)};

  *num_to_finalize = 0;
  auto append_rect = [&](size_t x0, size_t x1, size_t y0, size_t y1) {
    Rect rect(xpos[x0], ypos[y0], xpos[x1] - xpos[x0], ypos[y1] - ypos[y0]);
    if (rect.xsize() == 0 || rect.ysize() == 0) return;
    JXL_DASSERT(*num_to_finalize < kMaxToFinalize);
    rects_to_finalize[(*num_to_finalize)++] = rect;
  };

  // Because of how group borders are assigned, it is impossible that we need to
  // process the left and right side of some area but not the center area. Thus,
  // we compute the first/last part to process in every horizontal strip and
  // merge them together. We first collect a mask of what parts should be
  // processed.
  // We do this horizontally rather than vertically because horizontal borders
  // are larger.
  bool available_parts_mask[3][3] = {};  // [x][y]
  // Center
  available_parts_mask[1][1] = true;
  // Corners
  if (top_left_status == 0xF) available_parts_mask[0][0] = true;
  if (top_right_status == 0xF) available_parts_mask[2][0] = true;
  if (bottom_right_status == 0xF) available_parts_mask[2][2] = true;
  if (bottom_left_status == 0xF) available_parts_mask[0][2] = true;
  // Other borders
  if (top_left_status & kTopRight) available_parts_mask[1][0] = true;
  if (top_left_status & kBottomLeft) available_parts_mask[0][1] = true;
  if (top_right_status & kBottomRight) available_parts_mask[2][1] = true;
  if (bottom_left_status & kBottomRight) available_parts_mask[1][2] = true;

  // Collect horizontal ranges.
  constexpr size_t kNoSegment = 3;
  std::pair<size_t, size_t> horizontal_segments[3] = {{kNoSegment, kNoSegment},
                                                      {kNoSegment, kNoSegment},
                                                      {kNoSegment, kNoSegment}};
  for (size_t y = 0; y < 3; y++) {
    for (size_t x = 0; x < 3; x++) {
      if (!available_parts_mask[x][y]) continue;
      JXL_DASSERT(horizontal_segments[y].second == kNoSegment ||
                  horizontal_segments[y].second == x);
      JXL_DASSERT((horizontal_segments[y].first == kNoSegment) ==
                  (horizontal_segments[y].second == kNoSegment));
      if (horizontal_segments[y].first == kNoSegment) {
        horizontal_segments[y].first = x;
      }
      horizontal_segments[y].second = x + 1;
    }
  }
  if (horizontal_segments[0] == horizontal_segments[1] &&
      horizontal_segments[0] == horizontal_segments[2]) {
    append_rect(horizontal_segments[0].first, horizontal_segments[0].second, 0,
                3);
  } else if (horizontal_segments[0] == horizontal_segments[1]) {
    append_rect(horizontal_segments[0].first, horizontal_segments[0].second, 0,
                2);
    append_rect(horizontal_segments[2].first, horizontal_segments[2].second, 2,
                3);
  } else if (horizontal_segments[1] == horizontal_segments[2]) {
    append_rect(horizontal_segments[0].first, horizontal_segments[0].second, 0,
                1);
    append_rect(horizontal_segments[1].first, horizontal_segments[1].second, 1,
                3);
  } else {
    append_rect(horizontal_segments[0].first, horizontal_segments[0].second, 0,
                1);
    append_rect(horizontal_segments[1].first, horizontal_segments[1].second, 1,
                2);
    append_rect(horizontal_segments[2].first, horizontal_segments[2].second, 2,
                3);
  }
}

}  // namespace jxl

Messung V0.5
C=84 H=84 G=83

¤ Dauer der Verarbeitung: 0.5 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.