blob: 5653e203a7935dbcff1678cec2fd6d9a96c355db [file] [log] [blame]
Allan MacKinnon4359d522018-06-19 13:57:04 -07001/*
2 * Copyright 2016 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can
5 * be found in the LICENSE file.
6 *
7 */
8
9#include <memory.h>
10
11#include "styling.h"
12#include "styling_types.h"
13#include "skc.h"
14
15//
16// FIXME -- x86'isms are temporary
17//
18
19#include <immintrin.h>
20
21//
22//
23//
24
25skc_err
26skc_styling_retain(skc_styling_t styling)
27{
28 styling->ref_count += 1;
29
30 return SKC_ERR_SUCCESS;
31}
32
33skc_err
34skc_styling_release(skc_styling_t styling)
35{
36 //
37 // blocks and waits if grid is active
38 //
39 styling->release(styling->impl);
40
41 return SKC_ERR_SUCCESS;
42}
43
44skc_err
45skc_styling_seal(skc_styling_t styling)
46{
47 //
48 // no-op if sealed
49 //
50 styling->seal(styling->impl);
51
52 return SKC_ERR_SUCCESS;
53}
54
55skc_err
56skc_styling_unseal(skc_styling_t styling)
57{
58 //
59 // no-op if unsealed
60 // blocks and waits if sealed and grid is active
61 //
62 styling->unseal(styling->impl,false);
63
64 return SKC_ERR_SUCCESS;
65}
66
67skc_err
68skc_styling_reset(skc_styling_t styling)
69{
70 styling->unseal(styling->impl,true);
71
72 styling->layers.count = 0;
73 styling->groups.count = 0;
74 styling->extras.count = 0;
75
76 return SKC_ERR_SUCCESS;
77}
78
79//
80// FIXME -- various robustifications can be made to this builder but
81// we don't want to make this heavyweight too soon
82//
83// - out of range layer_id is an error
84// - extras[] overflow is an error
85//
86
87skc_err
88skc_styling_group_alloc(skc_styling_t styling,
89 skc_group_id * group_id)
90{
91 styling->unseal(styling->impl,true);
92
93 *group_id = styling->groups.count++;
94
95 return SKC_ERR_SUCCESS;
96}
97
98skc_err
99skc_styling_group_enter(skc_styling_t styling,
100 skc_group_id group_id,
101 uint32_t n,
102 skc_styling_cmd_t const * cmds)
103{
104 styling->unseal(styling->impl,true);
105
106 styling->groups.extent[group_id].cmds.enter = styling->extras.count;
107
108 memcpy(styling->extras.extent + styling->extras.count,cmds,n * sizeof(*cmds));
109
110 styling->extras.count += n;
111
112 return SKC_ERR_SUCCESS;
113}
114
115skc_err
116skc_styling_group_leave(skc_styling_t styling,
117 skc_group_id group_id,
118 uint32_t n,
119 skc_styling_cmd_t const * cmds)
120{
121 styling->unseal(styling->impl,true);
122
123 styling->groups.extent[group_id].cmds.leave = styling->extras.count;
124
125 memcpy(styling->extras.extent + styling->extras.count,cmds,n * sizeof(*cmds));
126
127 styling->extras.count += n;
128
129 return SKC_ERR_SUCCESS;
130}
131
132skc_err
133skc_styling_group_parents(skc_styling_t styling,
134 skc_group_id group_id,
135 uint32_t depth,
136 skc_group_id const * parents)
137{
138 styling->unseal(styling->impl,true);
139
140 styling->groups.extent[group_id].parents = (union skc_group_parents)
141 {
142 .depth = depth,
143 .base = styling->extras.count
144 };
145
146 memcpy(styling->extras.extent + styling->extras.count,parents,depth * sizeof(*parents));
147
148 styling->extras.count += depth;
149
150 return SKC_ERR_SUCCESS;
151}
152
153skc_err
154skc_styling_group_range_lo(skc_styling_t styling,
155 skc_group_id group_id,
156 skc_layer_id layer_lo)
157{
158 styling->unseal(styling->impl,true);
159
160 styling->groups.extent[group_id].range.lo = layer_lo;
161
162 return SKC_ERR_SUCCESS;
163}
164
165skc_err
166skc_styling_group_range_hi(skc_styling_t styling,
167 skc_group_id group_id,
168 skc_layer_id layer_hi)
169{
170 styling->unseal(styling->impl,true);
171
172 styling->groups.extent[group_id].range.hi = layer_hi;
173
174 return SKC_ERR_SUCCESS;
175}
176
177skc_err
178skc_styling_group_layer(skc_styling_t styling,
179 skc_group_id group_id,
180 skc_layer_id layer_id,
181 uint32_t n,
182 skc_styling_cmd_t const * cmds)
183{
184 styling->unseal(styling->impl,true);
185
186 styling->layers.extent[layer_id] = (union skc_layer_node)
187 {
188 .cmds = styling->extras.count,
189 .parent = group_id
190 };
191
192 memcpy(styling->extras.extent + styling->extras.count,cmds,n * sizeof(*cmds));
193
194 styling->extras.count += n;
195
196 return SKC_ERR_SUCCESS;
197}
198
199//
200// FIXME -- get rid of these x86'isms ASAP -- let compiler figure it
201// out with a vector type
202//
203
204static
205__m128i
206skc_convert_colors_4(float const * const colors)
207{
208 __m128i c;
209
210 c = _mm_cvtps_ph(*(__m128*)colors,0);
211
212 return c;
213}
214
215static
216__m128i
217skc_convert_colors_8(float const * const colors)
218{
219 __m128i c;
220
221 c = _mm256_cvtps_ph(*(__m256*)colors,0);
222
223 return c;
224}
225
226//
227//
228//
229
230static
231void
232skc_styling_layer_cmd_rgba_encoder(skc_styling_cmd_t * const cmds,
233 skc_styling_opcode_e const opcode,
234 float const rgba[4])
235{
236 __m128i const c = skc_convert_colors_4(rgba);
237
238 cmds[0] = opcode;
239 cmds[1] = c.m128i_u32[0];
240 cmds[2] = c.m128i_u32[1];
241}
242
243void
244skc_styling_background_over_encoder(skc_styling_cmd_t * cmds, float const rgba[4])
245{
246 skc_styling_layer_cmd_rgba_encoder(cmds,SKC_STYLING_OPCODE_BACKGROUND_OVER,rgba);
247}
248
249void
250skc_styling_layer_fill_rgba_encoder(skc_styling_cmd_t * cmds, float const rgba[4])
251{
252 // encode a solid fill
253 skc_styling_layer_cmd_rgba_encoder(cmds,SKC_STYLING_OPCODE_COLOR_FILL_SOLID,rgba);
254}
255
256//
257//
258//
259
260void
261skc_styling_layer_fill_gradient_encoder(skc_styling_cmd_t * cmds,
262 float x0,
263 float y0,
264 float x1,
265 float y1,
266 skc_styling_gradient_type_e type,
267 uint32_t n,
268 float const stops[],
269 float const colors[])
270{
271 union skc_styling_cmd * const cmds_u = (union skc_styling_cmd *)cmds;
272
273 //
274 // encode a gradient fill
275 //
276 cmds_u[0].opcode = SKC_STYLING_OPCODE_COLOR_FILL_GRADIENT_LINEAR;
277
278 float const dx = x1 - x0;
279 float const dy = y1 - y0;
280 float const c1 = x0 * dx + y0 * dy;
281 float const c2 = x1 * dx + y1 * dy;
282
283 cmds_u[1].f32 = dx; // dx
284 cmds_u[2].f32 = -c1; // p0
285 cmds_u[3].f32 = dy; // dy
286 cmds_u[4].f32 = 1.0f / (c2 - c1); // denom
287
288 //
289 // store type
290 //
291 cmds_u[5].gradient_type = type;
292
293 //
294 // Write out slopes
295 //
296 // Note: make sure that that the first and last stop pairs don't
297 // have a span of zero. Why? Because it's meaningless and the
298 // zero-span stops can simply be dropped.
299 //
300 // And obviously the stops need to monotonically increasing.
301 //
302 // These validations can be perfomed elsewhere.
303 //
304 // After a pile of simple algebra the slope necessary to map a stop
305 // percentage on [0,1] to an INDEX.LERP real number from [0.0,N.0]
306 // is simply:
307 //
308 // delta_stop_prev
309 // slope_curr = --------------- - 1
310 // delta_stop_curr
311 //
312 // Each delta stop equal to zero reduces the stop count by 1.
313 //
314 // Note that color pairs are what's stored so this simplified
315 // representation works for both linear gradients with non-zero
316 // delta stops and linear gradients that double-up the stops in
317 // order to produce "stripes".
318 //
319 float ds_prev = stops[1] - stops[0];
320 union skc_styling_cmd * const slopes = cmds_u + 8;
321
322 slopes[0].f32 = 1.0f / ds_prev;
323
324 uint32_t ds_count = 1;
325
326 for (uint32_t ii=1; ii<n-1; ii++)
327 {
328 float const ds_curr = stops[ii+1] - stops[ii];
329
330 if (ds_curr > 0.0f)
331 {
332 slopes[ds_count++].f32 = ds_prev / ds_curr - 1.0f;
333 ds_prev = ds_curr;
334 }
335 }
336
337 //
338 // save a potentially compressed delta slope count
339 //
340 cmds_u[6].u32 = ds_count;
341 cmds_u[7].u32 = n; // REMOVE ME -------------------------------------------- REMOVE
342
343 //
344 // FIXME -- encode color pair as a single color diff as noted by HERB @ CHAP <------------- FIXME
345 //
346
347 //
348 // write out color pairs while skipping delta stops equal to zero
349 //
350 uint32_t const color_count = ds_count + 1;
351
352 union skc_styling_cmd * color_r = cmds_u + 8 + ds_count;
353 union skc_styling_cmd * color_g = color_r + color_count;
354 union skc_styling_cmd * color_b = color_r + color_count * 2;
355 union skc_styling_cmd * color_a = color_r + color_count * 3;
356
357 for (uint32_t ii=0; ii<n-1; ii++)
358 {
359 if (stops[ii+1] > stops[ii])
360 {
361 __m128i const c = skc_convert_colors_8(colors+ii*4);
362
363 color_r->u16v2.lo = c.m128i_u16[0];
364 color_r->u16v2.hi = c.m128i_u16[4];
365 color_g->u16v2.lo = c.m128i_u16[1];
366 color_g->u16v2.hi = c.m128i_u16[5];
367 color_b->u16v2.lo = c.m128i_u16[2];
368 color_b->u16v2.hi = c.m128i_u16[6];
369 color_a->u16v2.lo = c.m128i_u16[3];
370 color_a->u16v2.hi = c.m128i_u16[7];
371
372 ++color_r;
373 ++color_g;
374 ++color_b;
375 ++color_a;
376 }
377 }
378
379 float laststop[8]; // sentinel to lerp against same color
380
381 for (int ii=0; ii<4; ii++)
382 laststop[ii+4] = laststop[ii] = colors[(n-1)*4+ii];
383
384 __m128i const c = skc_convert_colors_8(laststop);
385
386 color_r->u16v2.lo = c.m128i_u16[0];
387 color_r->u16v2.hi = c.m128i_u16[4];
388 color_g->u16v2.lo = c.m128i_u16[1];
389 color_g->u16v2.hi = c.m128i_u16[5];
390 color_b->u16v2.lo = c.m128i_u16[2];
391 color_b->u16v2.hi = c.m128i_u16[6];
392 color_a->u16v2.lo = c.m128i_u16[3];
393 color_a->u16v2.hi = c.m128i_u16[7];
394}
395
396//
397//
398//