summaryrefslogtreecommitdiff
path: root/gsk/gl/opbuffer.c
blob: 806b8f7ca4f11dae5bef136747736311bb777544 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#include "opbuffer.h"

#include <string.h>

static guint op_sizes[OP_LAST] = {
  0,
  sizeof (OpOpacity),
  sizeof (OpColor),
  sizeof (OpMatrix),
  sizeof (OpMatrix),
  sizeof (OpProgram),
  sizeof (OpRenderTarget),
  sizeof (OpClip),
  sizeof (OpViewport),
  sizeof (OpTexture),
  sizeof (OpRepeat),
  sizeof (OpLinearGradient),
  sizeof (OpRadialGradient),
  sizeof (OpColorMatrix),
  sizeof (OpBlur),
  sizeof (OpShadow),
  sizeof (OpOutsetShadow),
  sizeof (OpBorder),
  sizeof (OpBorder),
  sizeof (OpBorder),
  sizeof (OpCrossFade),
  sizeof (OpShadow),
  0,
  sizeof (OpDraw),
  sizeof (OpDumpFrameBuffer),
  sizeof (OpDebugGroup),
  0,
  sizeof (OpBlend),
  sizeof (OpGLShader),
  sizeof (OpExtraTexture),
  sizeof (OpConicGradient),
};

void
op_buffer_init (OpBuffer *buffer)
{
  static gsize initialized = FALSE;

  if (g_once_init_enter (&initialized))
    {
      guint i;

      for (i = 0; i < G_N_ELEMENTS (op_sizes); i++)
        {
          guint size = op_sizes[i];

          if (size > 0)
            {
              /* Round all op entry sizes to the nearest 16 to ensure
               * that we guarantee proper alignments for all op entries.
               * This is only done once on first use.
               */
#define CHECK_SIZE(s) else if (size < (s)) { size = s; }
              if (0) {}
              CHECK_SIZE (16)
              CHECK_SIZE (32)
              CHECK_SIZE (48)
              CHECK_SIZE (64)
              CHECK_SIZE (80)
              CHECK_SIZE (96)
              CHECK_SIZE (112)
              CHECK_SIZE (128)
              CHECK_SIZE (144)
              CHECK_SIZE (160)
              CHECK_SIZE (176)
              CHECK_SIZE (192)
              else g_assert_not_reached ();
#undef CHECK_SIZE

              op_sizes[i] = size;
            }
        }

      g_once_init_leave (&initialized, TRUE);
    }

  memset (buffer, 0, sizeof *buffer);

  buffer->buflen = 4096;
  buffer->bufpos = 0;
  buffer->buf = g_malloc (buffer->buflen);
  buffer->index = g_array_new (FALSE, FALSE, sizeof (OpBufferEntry));

  /* Add dummy entry to guarantee non-empty index */
  op_buffer_add (buffer, OP_NONE);
}

void
op_buffer_destroy (OpBuffer *buffer)
{
  g_free (buffer->buf);
  g_array_unref (buffer->index);
}

void
op_buffer_clear (OpBuffer *buffer)
{
  if (buffer->index->len > 1)
    g_array_remove_range (buffer->index, 1, buffer->index->len - 1);
  buffer->bufpos = 0;
}

static inline void
ensure_buffer_space_for (OpBuffer *buffer,
                         guint     size)
{
  if G_UNLIKELY (buffer->bufpos + size >= buffer->buflen)
    {
      buffer->buflen *= 2;
      buffer->buf = g_realloc (buffer->buf, buffer->buflen);
    }
}

gpointer
op_buffer_add (OpBuffer *buffer,
               OpKind    kind)
{
  guint size = op_sizes[kind];
  OpBufferEntry entry;

  entry.pos = buffer->bufpos;
  entry.kind = kind;

  if (size > 0)
    ensure_buffer_space_for (buffer, size);

  g_array_append_val (buffer->index, entry);

  buffer->bufpos += size;

  return &buffer->buf[entry.pos];
}