Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  scaling.c

  Sprache: C
 

#include "config.h"

#include <gtk/gtk.h>

#include "gdk/gdkmemoryformatprivate.h"
#include "gsk/gl/fp16private.h"
#include "testsuite/gdk/gdktestutils.h"

struct {
  const char *name;
  GskRenderer * (*create_func) (void);
  GskRenderer *renderer;
} renderers[] = {
  {
    "vulkan",
    gsk_vulkan_renderer_new,
  },
  {
    "gl",
    gsk_gl_renderer_new,
  },
};

static gpointer
encode_renderer_format (guint           renderer,
                        GdkMemoryFormat format)
{
  return GSIZE_TO_POINTER (format * G_N_ELEMENTS (renderers) + renderer);
}

static void
decode_renderer_format (gconstpointer     data,
                        GskRenderer     **renderer,
                        GdkMemoryFormat  *format)
{
  gsize value = GPOINTER_TO_SIZE (data);

  *renderer = renderers[value % G_N_ELEMENTS (renderers)].renderer;
  value /= G_N_ELEMENTS (renderers);

  *format = value;
}

#if 0
static GdkTexture *
ensure_texture_format (GdkTexture      *texture,
                       GdkMemoryFormat  format)
{
  GdkTextureDownloader *downloader;
  GdkTexture *result;
  GBytes *bytes;
  gsize stride;

  if (gdk_texture_get_format (texture) == format)
    return texture;

  downloader = gdk_texture_downloader_new (texture);
  gdk_texture_downloader_set_format (downloader, format);
  bytes = gdk_texture_downloader_download_bytes (downloader, &stride);
  gdk_texture_downloader_free (downloader);

  result = gdk_memory_texture_new (gdk_texture_get_width (texture),
                                   gdk_texture_get_height (texture),
                                   format,
                                   bytes,
                                   stride);
  g_bytes_unref (bytes);
  g_object_unref (texture);

  return result;
}
#endif

static void
color_make_opaque (GdkRGBA       *result,
                   const GdkRGBA *color)
{
  result->red *= color->alpha;
  result->green *= color->alpha;
  result->blue *= color->alpha;
  result->alpha = 1.0f;
}

static void
color_make_gray (GdkRGBA       *result,
                 const GdkRGBA *color)
{
  result->red = (color->red + color->green + color->blue) / 3.0f;
  result->green = result->red;
  result->blue = result->red;
  result->alpha = color->alpha;
}

static void
color_make_white (GdkRGBA       *result,
                  const GdkRGBA *color)
{
  result->red = 1.0f;
  result->green = 1.0f;
  result->blue = 1.0f;
  result->alpha = color->alpha;
}

/* Generate colors so that premultiplying will result in values in steps of 1/15th.
 * Also make sure that an averaged gray value fits in that range. */

static void
create_random_color (GdkRGBA *color)
{
  int r, g, b;
  do
    {
      r = g_test_rand_int_range (06);
      g = g_test_rand_int_range (06);
      b = g_test_rand_int_range (06);
    }
  while ((r + g + b) % 3 != 0);
  color->red = r / 5.f;
  color->green = g / 5.f;
  color->blue = b / 5.f;
  color->alpha = g_test_rand_int_range (04) / 3.f;
}

static void
create_random_10bit_color (GdkRGBA *color)
{
  int r, g, b;

  r = g_test_rand_int_range (04);
  g = g_test_rand_int_range (04);
  b = g_test_rand_int_range (04);
  color->red = r / 3.f;
  color->green = g / 3.f;
  color->blue = b / 3.f;
  color->alpha = 1.0;
}

static void
create_random_color_for_format (GdkRGBA *color,
                                GdkMemoryFormat format)
{
  /* non-premultiplied can represet GdkRGBA (1, 1, 1, 0)
   * but premultiplied cannot.
   * Premultiplied will always represent this as (0, 0, 0, 0)
   */

  do
    {
      if (gdk_memory_format_get_channel_type (format) == CHANNEL_UINT_10)
        create_random_10bit_color (color);
      else
        create_random_color (color);
    }
  while (color->alpha == 0 &&
         gdk_memory_format_alpha (format) == GDK_MEMORY_ALPHA_PREMULTIPLIED);

  /* If the format can't handle alpha, make things opaque
   */

  if (gdk_memory_format_alpha (format) == GDK_MEMORY_ALPHA_OPAQUE)
    color_make_opaque (color, color);

  /* If the format has fewer color channels than the
   * target, make sure the colors get adjusted.
   */

  if (gdk_memory_format_n_colors (format) == 1)
    color_make_gray (color, color);
  else if (gdk_memory_format_n_colors (format) == 0)
    color_make_white (color, color);
}

static GdkTexture *
create_solid_color_texture (GdkMemoryFormat  format,
                            int              width,
                            int              height,
                            const GdkRGBA   *color)
{
  TextureBuilder builder;

  texture_builder_init (&builder, format, width, height);
  texture_builder_fill (&builder, color);

  return texture_builder_finish (&builder);
}

/* randomly creates 4 colors with values that are multiples
 * of 8, so that averaging the colors works without rounding
 * errors, and then creates a stipple pattern like this:
 *
 * 1 2 1 2 1 2 ...
 * 3 4 3 4 3 4
 * 1 2 1 2 1 2
 * 3 4 3 4 3 4
 * 1 2 1 2 1 2
 * 3 4 3 4 3 4
 * 
 */

static GdkTexture *
create_stipple_texture (GdkMemoryFormat  format,
                        gsize            width,
                        gsize            height,
                        GdkRGBA          colors[2][2],
                        GdkRGBA         *average)
{
  TextureBuilder builder;
  GdkTexture *texture;
  int x, y;
  /* large enough */
  float data[4 * 4 * 4];
  GdkMemoryLayout layout;
  float adjust_color, adjust_alpha;

  *average = (GdkRGBA) { 0000 };

  if (gdk_memory_format_get_channel_type (format) == CHANNEL_UINT_10)
    {
      adjust_color = 16.f / 31.f;
      adjust_alpha = 1.f;
    }
  else if (gdk_memory_format_alpha (format) == GDK_MEMORY_ALPHA_OPAQUE)
    {
      adjust_color = 16.f / 17.f;
      adjust_alpha = 1.f;
    }
  else
    {
      adjust_color = 1.f;
      adjust_alpha = 16.f / 17.f;
    }

  for (y = 0; y < 2; y++)
    {
      for (x = 0; x < 2; x++)
        {
          create_random_color_for_format (&colors[x][y], format);
          if (gdk_memory_format_alpha (format) != GDK_MEMORY_ALPHA_OPAQUE)
            colors[x][y].alpha *= adjust_alpha;
          else
            {
              colors[x][y].red *= adjust_color;
              colors[x][y].green *= adjust_color;
              colors[x][y].blue *= adjust_color;
            }

          average->red += colors[x][y].red * colors[x][y].alpha;
          average->green += colors[x][y].green * colors[x][y].alpha;
          average->blue += colors[x][y].blue * colors[x][y].alpha;
          average->alpha += colors[x][y].alpha;
        }
    }

  if (average->alpha != 0.0f)
    {
      average->red /= average->alpha;
      average->green /= average->alpha;
      average->blue /= average->alpha;
      average->alpha /= 4.0f;
    }
  else
    {
      /* Each component of the average has been multiplied by the alpha
       * already, so if the alpha is zero, all components should also
       * be zero */

      g_assert_cmpfloat (average->red, ==, 0.0f);
      g_assert_cmpfloat (average->green, ==, 0.0f);
      g_assert_cmpfloat (average->blue, ==, 0.0f);
    }

  for (y = 0; y < 4; y++)
    {
      for (x = 0; x < 4; x++)
        {
          data[4 * (4 * y + x) + 0] = colors[x % 2][y % 2].red;
          data[4 * (4 * y + x) + 1] = colors[x % 2][y % 2].green;
          data[4 * (4 * y + x) + 2] = colors[x % 2][y % 2].blue;
          data[4 * (4 * y + x) + 3] = colors[x % 2][y % 2].alpha;
        }
    }
  gdk_memory_layout_init (&layout,
                          GDK_MEMORY_R32G32B32A32_FLOAT,
                          4,
                          4,
                          1);
  layout.width = MIN (width, layout.width);
  layout.height = MIN (height, layout.height);

  texture_builder_init (&builder, format, width, height);
  for (y = 0; y < height; y += layout.height)
    {
      for (x = 0; x < width; x += layout.width)
        {
          texture_builder_draw_data (&builder,
                                     x, y,
                                     (guchar *) data,
                                     &layout);
        }
    }
  texture = texture_builder_finish (&builder);

  return texture;
}

static void
dump_scaling_input (const GdkRGBA  colors[2][2],
                    const GdkRGBA *average)
{
  int x, y;

  for (y = 0; y < 2; y++)
    {
      for (x = 0; x < 2; x++)
        g_test_message ("input stipple texture (%d,%d) r=%f g=%f b=%f a=%f",
                        x, y,
                        colors[x][y].red,
                        colors[x][y].green,
                        colors[x][y].blue,
                        colors[x][y].alpha);
    }

  g_test_message ("expected average r=%f g=%f b=%f a=%f",
                  average->red, average->green, average->blue, average->alpha);
}

static void
test_linear_filtering (gconstpointer data,
                       gsize         width,
                       gsize         height)
{
  GdkMemoryFormat format;
  GskRenderer *renderer;
  GdkTexture *input, *output, *expected;
  GskRenderNode *node;
  GdkRGBA colors[2][2];
  GdkRGBA average_color;

  decode_renderer_format (data, &renderer, &format);

  width = MAX (width, gdk_memory_format_get_block_width (format));
  height = MAX (height, gdk_memory_format_get_block_height (format));

  input = create_stipple_texture (format, width, height, colors, &average_color);
  node = gsk_texture_scale_node_new (input, &GRAPHENE_RECT_INIT (00, width / 2, height / 2), GSK_SCALING_FILTER_LINEAR);
  output = gsk_renderer_render_texture (renderer, node, NULL);
  expected = create_solid_color_texture (gdk_texture_get_format (output), width / 2, height / 2, &average_color);

  compare_textures (expected, output, FALSE);

  if (g_test_failed ())
    dump_scaling_input (colors, &average_color);

  g_object_unref (expected);
  g_object_unref (output);
  gsk_render_node_unref (node);
  g_object_unref (input);
}

static void
test_mipmaps (gconstpointer data)
{
  GdkMemoryFormat format;
  GskRenderer *renderer;
  GdkTexture *input, *output, *expected;
  GskRenderNode *node;
  GdkRGBA colors[2][2];
  GdkRGBA average_color;
  gsize width, height;

  decode_renderer_format (data, &renderer, &format);

  width = MAX (2, gdk_memory_format_get_block_width (format));
  height = MAX (2, gdk_memory_format_get_block_height (format));

  input = create_stipple_texture (format, width, height, colors, &average_color);
  node = gsk_texture_scale_node_new (input, &GRAPHENE_RECT_INIT (0011), GSK_SCALING_FILTER_TRILINEAR);
  output = gsk_renderer_render_texture (renderer, node, NULL);
  expected = create_solid_color_texture (gdk_texture_get_format (output), 11, &average_color);

  compare_textures (expected, output, FALSE);

  if (g_test_failed ())
    dump_scaling_input (colors, &average_color);

  g_object_unref (expected);
  g_object_unref (output);
  gsk_render_node_unref (node);
  g_object_unref (input);
}

static void
test_linear_filtering_2x2 (gconstpointer data)
{
  test_linear_filtering (data, 22);
}

static void
test_linear_filtering_512x512 (gconstpointer data)
{
  test_linear_filtering (data, 512512);
}

static void
add_format_test (const char    *name,
                 GTestDataFunc  func)
{
  GdkMemoryFormat format;
  gsize renderer;
  GEnumClass *enum_class;

  enum_class = g_type_class_ref (GDK_TYPE_MEMORY_FORMAT);

  for (renderer = 0; renderer < G_N_ELEMENTS (renderers); renderer++)
    {
      if (renderers[renderer].renderer == NULL)
        continue;

      for (format = 0; format < GDK_MEMORY_N_FORMATS; format++)
        {
          char *test_name = g_strdup_printf ("%s/%s/%s",
                                             name,
                                             renderers[renderer].name,
                                             g_enum_get_value (enum_class, format)->value_nick);
          g_test_add_data_func_full (test_name, encode_renderer_format (renderer, format), func, NULL);
          g_free (test_name);
        }
    }
}

static void
create_renderers (void)
{
  GError *error = NULL;
  gsize i;

  for (i = 0; i < G_N_ELEMENTS (renderers); i++)
    {
      renderers[i].renderer = renderers[i].create_func ();
      if (!gsk_renderer_realize_for_display (renderers[i].renderer, gdk_display_get_default (), &error))
        {
          g_test_message ("Could not realize %s renderer: %s", renderers[i].name, error->message);
          g_clear_error (&error);
          g_clear_object (&renderers[i].renderer);
        }
    }
}

static void
destroy_renderers (void)
{
  gsize i;

  for (i = 0; i < G_N_ELEMENTS (renderers); i++)
    {
      if (renderers[i].renderer == NULL)
        continue;

      gsk_renderer_unrealize (renderers[i].renderer);
      g_clear_object (&renderers[i].renderer);
    }
}

int
main (int argc, char *argv[])
{
  int result;

  gtk_test_init (&argc, &argv, NULL);
  create_renderers ();

  add_format_test ("/scaling/linear-filtering", test_linear_filtering_2x2);
  add_format_test ("/scaling/linear-filtering-large", test_linear_filtering_512x512);
  add_format_test ("/scaling/mipmap", test_mipmaps);

  result = g_test_run ();

  /* So the context gets actually destroyed */
  gdk_gl_context_clear_current ();

  destroy_renderers ();

  return result;
}

Messung V0.5 in Prozent
C=98 H=90 G=94

¤ Dauer der Verarbeitung: 0.11 Sekunden  (vorverarbeitet am  2026-07-03) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

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.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik