Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Linux/drivers/video/fbdev/core/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 11 kB image not shown  

Quelle  fb_copyarea.h   Sprache: C

 
/* SPDX-License-Identifier: GPL-2.0-only
 *
 *  Generic bit area copy and twister engine for packed pixel framebuffers
 *
 *      Rewritten by:
 * Copyright (C)  2025 Zsolt Kajtar (soci@c64.rulez.org)
 *
 * Based on previous work of:
 * Copyright (C)  1999-2005 James Simmons <jsimmons@www.infradead.org>
 * Anton Vorontsov <avorontsov@ru.mvista.com>
 * Pavel Pisa <pisa@cmp.felk.cvut.cz>
 * Antonino Daplas <adaplas@hotpop.com>
 * Geert Uytterhoeven
 * and others
 *
 * NOTES:
 *
 * Handles native and foreign byte order on both endians, standard and
 * reverse pixel order in a byte (<8 BPP), word length of 32/64 bits,
 * bits per pixel from 1 to the word length. Handles line lengths at byte
 * granularity while maintaining aligned accesses.
 *
 * Optimized routines for word aligned copying and byte aligned copying
 * on reverse pixel framebuffers.
 */

#include "fb_draw.h"

/* used when no reversing is necessary */
static inline unsigned long fb_no_reverse(unsigned long val, struct fb_reverse reverse)
{
 return val;
}

/* modifies the masked area in a word */
static inline void fb_copy_offset_masked(unsigned long mask, int offset,
      const struct fb_address *dst,
      const struct fb_address *src)
{
 fb_modify_offset(fb_read_offset(offset, src), mask, offset, dst);
}

/* copies the whole word */
static inline void fb_copy_offset(int offset, const struct fb_address *dst,
      const struct fb_address *src)
{
 fb_write_offset(fb_read_offset(offset, src), offset, dst);
}

/* forward aligned copy */
static inline void fb_copy_aligned_fwd(const struct fb_address *dst,
           const struct fb_address *src,
           int end, struct fb_reverse reverse)
{
 unsigned long first, last;

 first = fb_pixel_mask(dst->bits, reverse);
 last = ~fb_pixel_mask(end & (BITS_PER_LONG-1), reverse);

 /* Same alignment for source and dest */
 if (end <= BITS_PER_LONG) {
  /* Single word */
  last = last ? (last & first) : first;

  /* Trailing bits */
  if (last == ~0UL)
   fb_copy_offset(0, dst, src);
  else
   fb_copy_offset_masked(last, 0, dst, src);
 } else {
  /* Multiple destination words */
  int offset = first != ~0UL;

  /* Leading bits */
  if (offset)
   fb_copy_offset_masked(first, 0, dst, src);

  /* Main chunk */
  end /= BITS_PER_LONG;
  while (offset + 4 <= end) {
   fb_copy_offset(offset + 0, dst, src);
   fb_copy_offset(offset + 1, dst, src);
   fb_copy_offset(offset + 2, dst, src);
   fb_copy_offset(offset + 3, dst, src);
   offset += 4;
  }
  while (offset < end)
   fb_copy_offset(offset++, dst, src);

  /* Trailing bits */
  if (last)
   fb_copy_offset_masked(last, offset, dst, src);
 }
}

/* reverse aligned copy */
static inline void fb_copy_aligned_rev(const struct fb_address *dst,
           const struct fb_address *src,
           int end, struct fb_reverse reverse)
{
 unsigned long first, last;

 first = fb_pixel_mask(dst->bits, reverse);
 last = ~fb_pixel_mask(end & (BITS_PER_LONG-1), reverse);

 if (end <= BITS_PER_LONG) {
  /* Single word */
  if (last)
   first &= last;
  if (first == ~0UL)
   fb_copy_offset(0, dst, src);
  else
   fb_copy_offset_masked(first, 0, dst, src);
 } else {
  /* Multiple destination words */
  int offset = first != ~0UL;

  /* Trailing bits */
  end /= BITS_PER_LONG;

  if (last)
   fb_copy_offset_masked(last, end, dst, src);

  /* Main chunk */
  while (end >= offset + 4) {
   fb_copy_offset(end - 1, dst, src);
   fb_copy_offset(end - 2, dst, src);
   fb_copy_offset(end - 3, dst, src);
   fb_copy_offset(end - 4, dst, src);
   end -= 4;
  }
  while (end > offset)
   fb_copy_offset(--end, dst, src);

  /* Leading bits */
  if (offset)
   fb_copy_offset_masked(first, 0, dst, src);
 }
}

static inline void fb_copy_aligned(struct fb_address *dst, struct fb_address *src,
       int width, u32 height, unsigned int bits_per_line,
       struct fb_reverse reverse, bool rev_copy)
{
 if (rev_copy)
  while (height--) {
   fb_copy_aligned_rev(dst, src, width + dst->bits, reverse);
   fb_address_backward(dst, bits_per_line);
   fb_address_backward(src, bits_per_line);
  }
 else
  while (height--) {
   fb_copy_aligned_fwd(dst, src, width + dst->bits, reverse);
   fb_address_forward(dst, bits_per_line);
   fb_address_forward(src, bits_per_line);
  }
}

static __always_inline void fb_copy_fwd(const struct fb_address *dst,
     const struct fb_address *src, int width,
     unsigned long (*reorder)(unsigned long val,
         struct fb_reverse reverse),
     struct fb_reverse reverse)
{
 unsigned long first, last;
 unsigned long d0, d1;
 int end = dst->bits + width;
 int shift, left, right;

 first = fb_pixel_mask(dst->bits, reverse);
 last = ~fb_pixel_mask(end & (BITS_PER_LONG-1), reverse);

 shift = dst->bits - src->bits;
 right = shift & (BITS_PER_LONG - 1);
 left = -shift & (BITS_PER_LONG - 1);

 if (end <= BITS_PER_LONG) {
  /* Single destination word */
  last = last ? (last & first) : first;
  if (shift < 0) {
   d0 = fb_left(reorder(fb_read_offset(-1, src), reverse), left);
   if (src->bits + width > BITS_PER_LONG)
    d0 |= fb_right(reorder(fb_read_offset(0, src), reverse), right);

   if (last == ~0UL)
    fb_write_offset(reorder(d0, reverse), 0, dst);
   else
    fb_modify_offset(reorder(d0, reverse), last, 0, dst);
  } else {
   d0 = fb_right(reorder(fb_read_offset(0, src), reverse), right);
   fb_modify_offset(reorder(d0, reverse), last, 0, dst);
  }
 } else {
  /* Multiple destination words */
  int offset = first != ~0UL;

  /* Leading bits */
  if (shift < 0)
   d0 = reorder(fb_read_offset(-1, src), reverse);
  else
   d0 = 0;

  /* 2 source words */
  if (offset) {
   d1 = reorder(fb_read_offset(0, src), reverse);
   d0 = fb_left(d0, left) | fb_right(d1, right);
   fb_modify_offset(reorder(d0, reverse), first, 0, dst);
   d0 = d1;
  }

  /* Main chunk */
  end /= BITS_PER_LONG;
  if (reorder == fb_no_reverse)
   while (offset + 4 <= end) {
    d1 = fb_read_offset(offset + 0, src);
    d0 = fb_left(d0, left) | fb_right(d1, right);
    fb_write_offset(d0, offset + 0, dst);
    d0 = d1;
    d1 = fb_read_offset(offset + 1, src);
    d0 = fb_left(d0, left) | fb_right(d1, right);
    fb_write_offset(d0, offset + 1, dst);
    d0 = d1;
    d1 = fb_read_offset(offset + 2, src);
    d0 = fb_left(d0, left) | fb_right(d1, right);
    fb_write_offset(d0, offset + 2, dst);
    d0 = d1;
    d1 = fb_read_offset(offset + 3, src);
    d0 = fb_left(d0, left) | fb_right(d1, right);
    fb_write_offset(d0, offset + 3, dst);
    d0 = d1;
    offset += 4;
   }

  while (offset < end) {
   d1 = reorder(fb_read_offset(offset, src), reverse);
   d0 = fb_left(d0, left) | fb_right(d1, right);
   fb_write_offset(reorder(d0, reverse), offset, dst);
   d0 = d1;
   offset++;
  }

  /* Trailing bits */
  if (last) {
   d0 = fb_left(d0, left);
   if (src->bits + width
       > offset * BITS_PER_LONG + ((shift < 0) ? BITS_PER_LONG : 0))
    d0 |= fb_right(reorder(fb_read_offset(offset, src), reverse),
            right);
   fb_modify_offset(reorder(d0, reverse), last, offset, dst);
  }
 }
}

static __always_inline void fb_copy_rev(const struct fb_address *dst,
     const struct fb_address *src, int end,
     unsigned long (*reorder)(unsigned long val,
         struct fb_reverse reverse),
     struct fb_reverse reverse)
{
 unsigned long first, last;
 unsigned long d0, d1;
 int shift, left, right;

 first = fb_pixel_mask(dst->bits, reverse);
 last = ~fb_pixel_mask(end & (BITS_PER_LONG-1), reverse);

 shift = dst->bits - src->bits;
 right = shift & (BITS_PER_LONG-1);
 left = -shift & (BITS_PER_LONG-1);

 if (end <= BITS_PER_LONG) {
  /* Single destination word */
  if (last)
   first &= last;

  if (shift > 0) {
   d0 = fb_right(reorder(fb_read_offset(1, src), reverse), right);
   if (src->bits > left)
    d0 |= fb_left(reorder(fb_read_offset(0, src), reverse), left);
   fb_modify_offset(reorder(d0, reverse), first, 0, dst);
  } else {
   d0 = fb_left(reorder(fb_read_offset(0, src), reverse), left);
   if (src->bits + end - dst->bits > BITS_PER_LONG)
    d0 |= fb_right(reorder(fb_read_offset(1, src), reverse), right);
   if (first == ~0UL)
    fb_write_offset(reorder(d0, reverse), 0, dst);
   else
    fb_modify_offset(reorder(d0, reverse), first, 0, dst);
  }
 } else {
  /* Multiple destination words */
  int offset = first != ~0UL;

  end /= BITS_PER_LONG;

  /* 2 source words */
  if (fb_right(~0UL, right) & last)
   d0 = fb_right(reorder(fb_read_offset(end + 1, src), reverse), right);
  else
   d0 = 0;

  /* Trailing bits */
  d1 = reorder(fb_read_offset(end, src), reverse);
  if (last)
   fb_modify_offset(reorder(fb_left(d1, left) | d0, reverse),
      last, end, dst);
  d0 = d1;

  /* Main chunk */
  if (reorder == fb_no_reverse)
   while (end >= offset + 4) {
    d1 = fb_read_offset(end - 1, src);
    d0 = fb_left(d1, left) | fb_right(d0, right);
    fb_write_offset(d0, end - 1, dst);
    d0 = d1;
    d1 = fb_read_offset(end - 2, src);
    d0 = fb_left(d1, left) | fb_right(d0, right);
    fb_write_offset(d0, end - 2, dst);
    d0 = d1;
    d1 = fb_read_offset(end - 3, src);
    d0 = fb_left(d1, left) | fb_right(d0, right);
    fb_write_offset(d0, end - 3, dst);
    d0 = d1;
    d1 = fb_read_offset(end - 4, src);
    d0 = fb_left(d1, left) | fb_right(d0, right);
    fb_write_offset(d0, end - 4, dst);
    d0 = d1;
    end -= 4;
   }

  while (end > offset) {
   end--;
   d1 = reorder(fb_read_offset(end, src), reverse);
   d0 = fb_left(d1, left) | fb_right(d0, right);
   fb_write_offset(reorder(d0, reverse), end, dst);
   d0 = d1;
  }

  /* Leading bits */
  if (offset) {
   d0 = fb_right(d0, right);
   if (src->bits > left)
    d0 |= fb_left(reorder(fb_read_offset(0, src), reverse), left);
   fb_modify_offset(reorder(d0, reverse), first, 0, dst);
  }
 }
}

static __always_inline void fb_copy(struct fb_address *dst, struct fb_address *src,
        int width, u32 height, unsigned int bits_per_line,
        unsigned long (*reorder)(unsigned long val,
            struct fb_reverse reverse),
        struct fb_reverse reverse, bool rev_copy)
{
 if (rev_copy)
  while (height--) {
   int move = src->bits < dst->bits ? -1 : 0;

   fb_address_move_long(src, move);
   fb_copy_rev(dst, src, width + dst->bits, reorder, reverse);
   fb_address_backward(dst, bits_per_line);
   fb_address_backward(src, bits_per_line);
   fb_address_move_long(src, -move);
  }
 else
  while (height--) {
   int move = src->bits > dst->bits ? 1 : 0;

   fb_address_move_long(src, move);
   fb_copy_fwd(dst, src, width, reorder, reverse);
   fb_address_forward(dst, bits_per_line);
   fb_address_forward(src, bits_per_line);
   fb_address_move_long(src, -move);
  }
}

static inline void fb_copyarea(struct fb_info *p, const struct fb_copyarea *area)
{
 int bpp = p->var.bits_per_pixel;
 u32 dy = area->dy;
 u32 sy = area->sy;
 u32 height = area->height;
 int width = area->width * bpp;
 unsigned int bits_per_line = BYTES_TO_BITS(p->fix.line_length);
 struct fb_reverse reverse = fb_reverse_init(p);
 struct fb_address dst = fb_address_init(p);
 struct fb_address src = dst;
 bool rev_copy = (dy > sy) || (dy == sy && area->dx > area->sx);

 if (rev_copy) {
  dy += height - 1;
  sy += height - 1;
 }
 fb_address_forward(&dst, dy*bits_per_line + area->dx*bpp);
 fb_address_forward(&src, sy*bits_per_line + area->sx*bpp);

 if (src.bits == dst.bits)
  fb_copy_aligned(&dst, &src, width, height, bits_per_line, reverse, rev_copy);
 else if (!reverse.byte && (!reverse.pixel ||
         !((src.bits ^ dst.bits) & (BITS_PER_BYTE-1)))) {
  fb_copy(&dst, &src, width, height, bits_per_line,
   fb_no_reverse, reverse, rev_copy);
 } else
  fb_copy(&dst, &src, width, height, bits_per_line,
   fb_reverse_long, reverse, rev_copy);
}

Messung V0.5
C=98 H=94 G=95

¤ Dauer der Verarbeitung: 0.4 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.