~elementary-os/ubuntu-package-imports/mutter-bionic

« back to all changes in this revision

Viewing changes to cogl/cogl-pango/cogl-pango-pipeline-cache.c

  • Committer: RabbitBot
  • Date: 2018-04-11 14:49:36 UTC
  • Revision ID: rabbitbot@elementary.io-20180411144936-hgymqa9d8d1xfpbh
Initial import, version 3.28.0-2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Cogl
 
3
 *
 
4
 * A Low Level GPU Graphics and Utilities API
 
5
 *
 
6
 * Copyright (C) 2011 Intel Corporation.
 
7
 *
 
8
 * Permission is hereby granted, free of charge, to any person
 
9
 * obtaining a copy of this software and associated documentation
 
10
 * files (the "Software"), to deal in the Software without
 
11
 * restriction, including without limitation the rights to use, copy,
 
12
 * modify, merge, publish, distribute, sublicense, and/or sell copies
 
13
 * of the Software, and to permit persons to whom the Software is
 
14
 * furnished to do so, subject to the following conditions:
 
15
 *
 
16
 * The above copyright notice and this permission notice shall be
 
17
 * included in all copies or substantial portions of the Software.
 
18
 *
 
19
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 
20
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 
21
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 
22
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 
23
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 
24
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 
25
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 
26
 * SOFTWARE.
 
27
 *
 
28
 *
 
29
 *
 
30
 * Authors:
 
31
 *   Neil Roberts <neil@linux.intel.com>
 
32
 */
 
33
 
 
34
#ifdef HAVE_CONFIG_H
 
35
#include "cogl-config.h"
 
36
#endif
 
37
 
 
38
#include <glib.h>
 
39
#include "cogl-pango-pipeline-cache.h"
 
40
 
 
41
#include "cogl/cogl-context-private.h"
 
42
#include "cogl/cogl-texture-private.h"
 
43
 
 
44
typedef struct _CoglPangoPipelineCacheEntry CoglPangoPipelineCacheEntry;
 
45
 
 
46
struct _CoglPangoPipelineCacheEntry
 
47
{
 
48
  /* This will take a reference or it can be NULL to represent the
 
49
     pipeline used to render colors */
 
50
  CoglTexture *texture;
 
51
 
 
52
  /* This will only take a weak reference */
 
53
  CoglPipeline *pipeline;
 
54
};
 
55
 
 
56
static void
 
57
_cogl_pango_pipeline_cache_key_destroy (void *data)
 
58
{
 
59
  if (data)
 
60
    cogl_object_unref (data);
 
61
}
 
62
 
 
63
static void
 
64
_cogl_pango_pipeline_cache_value_destroy (void *data)
 
65
{
 
66
  CoglPangoPipelineCacheEntry *cache_entry = data;
 
67
 
 
68
  if (cache_entry->texture)
 
69
    cogl_object_unref (cache_entry->texture);
 
70
 
 
71
  /* We don't need to unref the pipeline because it only takes a weak
 
72
     reference */
 
73
 
 
74
  g_slice_free (CoglPangoPipelineCacheEntry, cache_entry);
 
75
}
 
76
 
 
77
CoglPangoPipelineCache *
 
78
_cogl_pango_pipeline_cache_new (CoglContext *ctx,
 
79
                                CoglBool use_mipmapping)
 
80
{
 
81
  CoglPangoPipelineCache *cache = g_new (CoglPangoPipelineCache, 1);
 
82
 
 
83
  cache->ctx = cogl_object_ref (ctx);
 
84
 
 
85
  /* The key is the pipeline pointer. A reference is taken when the
 
86
     pipeline is used as a key so we should unref it again in the
 
87
     destroy function */
 
88
  cache->hash_table =
 
89
    g_hash_table_new_full (g_direct_hash,
 
90
                           g_direct_equal,
 
91
                           _cogl_pango_pipeline_cache_key_destroy,
 
92
                           _cogl_pango_pipeline_cache_value_destroy);
 
93
 
 
94
  cache->base_texture_rgba_pipeline = NULL;
 
95
  cache->base_texture_alpha_pipeline = NULL;
 
96
 
 
97
  cache->use_mipmapping = use_mipmapping;
 
98
 
 
99
  return cache;
 
100
}
 
101
 
 
102
static CoglPipeline *
 
103
get_base_texture_rgba_pipeline (CoglPangoPipelineCache *cache)
 
104
{
 
105
  if (cache->base_texture_rgba_pipeline == NULL)
 
106
    {
 
107
      CoglPipeline *pipeline;
 
108
 
 
109
      pipeline = cache->base_texture_rgba_pipeline =
 
110
        cogl_pipeline_new (cache->ctx);
 
111
 
 
112
      cogl_pipeline_set_layer_wrap_mode (pipeline, 0,
 
113
                                         COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE);
 
114
 
 
115
      if (cache->use_mipmapping)
 
116
        cogl_pipeline_set_layer_filters
 
117
          (pipeline, 0,
 
118
           COGL_PIPELINE_FILTER_LINEAR_MIPMAP_LINEAR,
 
119
           COGL_PIPELINE_FILTER_LINEAR);
 
120
    }
 
121
 
 
122
  return cache->base_texture_rgba_pipeline;
 
123
}
 
124
 
 
125
static CoglPipeline *
 
126
get_base_texture_alpha_pipeline (CoglPangoPipelineCache *cache)
 
127
{
 
128
  if (cache->base_texture_alpha_pipeline == NULL)
 
129
    {
 
130
      CoglPipeline *pipeline;
 
131
 
 
132
      pipeline = cogl_pipeline_copy (get_base_texture_rgba_pipeline (cache));
 
133
      cache->base_texture_alpha_pipeline = pipeline;
 
134
 
 
135
      /* The default combine mode of materials is to modulate (A x B)
 
136
       * the texture RGBA channels with the RGBA channels of the
 
137
       * previous layer (which in our case is just the font color)
 
138
       *
 
139
       * Since the RGB for an alpha texture is defined as 0, this gives us:
 
140
       *
 
141
       *  result.rgb = color.rgb * 0
 
142
       *  result.a = color.a * texture.a
 
143
       *
 
144
       * What we want is premultiplied rgba values:
 
145
       *
 
146
       *  result.rgba = color.rgb * texture.a
 
147
       *  result.a = color.a * texture.a
 
148
       */
 
149
      cogl_pipeline_set_layer_combine (pipeline, 0, /* layer */
 
150
                                       "RGBA = MODULATE (PREVIOUS, TEXTURE[A])",
 
151
                                       NULL);
 
152
    }
 
153
 
 
154
  return cache->base_texture_alpha_pipeline;
 
155
}
 
156
 
 
157
typedef struct
 
158
{
 
159
  CoglPangoPipelineCache *cache;
 
160
  CoglTexture *texture;
 
161
} PipelineDestroyNotifyData;
 
162
 
 
163
static void
 
164
pipeline_destroy_notify_cb (void *user_data)
 
165
{
 
166
  PipelineDestroyNotifyData *data = user_data;
 
167
 
 
168
  g_hash_table_remove (data->cache->hash_table, data->texture);
 
169
  g_slice_free (PipelineDestroyNotifyData, data);
 
170
}
 
171
 
 
172
CoglPipeline *
 
173
_cogl_pango_pipeline_cache_get (CoglPangoPipelineCache *cache,
 
174
                                CoglTexture *texture)
 
175
{
 
176
  CoglPangoPipelineCacheEntry *entry;
 
177
  PipelineDestroyNotifyData *destroy_data;
 
178
  static CoglUserDataKey pipeline_destroy_notify_key;
 
179
 
 
180
  /* Look for an existing entry */
 
181
  entry = g_hash_table_lookup (cache->hash_table, texture);
 
182
 
 
183
  if (entry)
 
184
    return cogl_object_ref (entry->pipeline);
 
185
 
 
186
  /* No existing pipeline was found so let's create another */
 
187
  entry = g_slice_new (CoglPangoPipelineCacheEntry);
 
188
 
 
189
  if (texture)
 
190
    {
 
191
      CoglPipeline *base;
 
192
 
 
193
      entry->texture = cogl_object_ref (texture);
 
194
 
 
195
      if (_cogl_texture_get_format (entry->texture) == COGL_PIXEL_FORMAT_A_8)
 
196
        base = get_base_texture_alpha_pipeline (cache);
 
197
      else
 
198
        base = get_base_texture_rgba_pipeline (cache);
 
199
 
 
200
      entry->pipeline = cogl_pipeline_copy (base);
 
201
 
 
202
      cogl_pipeline_set_layer_texture (entry->pipeline, 0 /* layer */, texture);
 
203
    }
 
204
  else
 
205
    {
 
206
      entry->texture = NULL;
 
207
      entry->pipeline = cogl_pipeline_new (cache->ctx);
 
208
    }
 
209
 
 
210
  /* Add a weak reference to the pipeline so we can remove it from the
 
211
     hash table when it is destroyed */
 
212
  destroy_data = g_slice_new (PipelineDestroyNotifyData);
 
213
  destroy_data->cache = cache;
 
214
  destroy_data->texture = texture;
 
215
  cogl_object_set_user_data (COGL_OBJECT (entry->pipeline),
 
216
                             &pipeline_destroy_notify_key,
 
217
                             destroy_data,
 
218
                             pipeline_destroy_notify_cb);
 
219
 
 
220
  g_hash_table_insert (cache->hash_table,
 
221
                       texture ? cogl_object_ref (texture) : NULL,
 
222
                       entry);
 
223
 
 
224
  /* This doesn't take a reference on the pipeline so that it will use
 
225
     the newly created reference */
 
226
  return entry->pipeline;
 
227
}
 
228
 
 
229
void
 
230
_cogl_pango_pipeline_cache_free (CoglPangoPipelineCache *cache)
 
231
{
 
232
  if (cache->base_texture_rgba_pipeline)
 
233
    cogl_object_unref (cache->base_texture_rgba_pipeline);
 
234
  if (cache->base_texture_alpha_pipeline)
 
235
    cogl_object_unref (cache->base_texture_alpha_pipeline);
 
236
 
 
237
  g_hash_table_destroy (cache->hash_table);
 
238
 
 
239
  cogl_object_unref (cache->ctx);
 
240
 
 
241
  g_free (cache);
 
242
}