1 /*
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 
25 skc_err
skc_styling_retain(skc_styling_t styling)26 skc_styling_retain(skc_styling_t styling)
27 {
28   styling->ref_count += 1;
29 
30   return SKC_ERR_SUCCESS;
31 }
32 
33 skc_err
skc_styling_release(skc_styling_t styling)34 skc_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 
44 skc_err
skc_styling_seal(skc_styling_t styling)45 skc_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 
55 skc_err
skc_styling_unseal(skc_styling_t styling)56 skc_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 
67 skc_err
skc_styling_reset(skc_styling_t styling)68 skc_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 
87 skc_err
skc_styling_group_alloc(skc_styling_t styling,skc_group_id * group_id)88 skc_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 
98 skc_err
skc_styling_group_enter(skc_styling_t styling,skc_group_id group_id,uint32_t n,skc_styling_cmd_t const * cmds)99 skc_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 
115 skc_err
skc_styling_group_leave(skc_styling_t styling,skc_group_id group_id,uint32_t n,skc_styling_cmd_t const * cmds)116 skc_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 
132 skc_err
skc_styling_group_parents(skc_styling_t styling,skc_group_id group_id,uint32_t n,skc_group_id const * parents)133 skc_styling_group_parents(skc_styling_t        styling,
134                           skc_group_id         group_id,
135                           uint32_t             n,
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 = n, // starts at 0
143       .base  = styling->extras.count
144     };
145 
146   while (n-- > 0)
147     styling->extras.extent[styling->extras.count++].parent = parents[n];
148 
149   return SKC_ERR_SUCCESS;
150 }
151 
152 skc_err
skc_styling_group_range_lo(skc_styling_t styling,skc_group_id group_id,skc_layer_id layer_lo)153 skc_styling_group_range_lo(skc_styling_t styling,
154                            skc_group_id  group_id,
155                            skc_layer_id  layer_lo)
156 {
157   styling->unseal(styling->impl,true);
158 
159   styling->groups.extent[group_id].range.lo = layer_lo;
160 
161   return SKC_ERR_SUCCESS;
162 }
163 
164 skc_err
skc_styling_group_range_hi(skc_styling_t styling,skc_group_id group_id,skc_layer_id layer_hi)165 skc_styling_group_range_hi(skc_styling_t styling,
166                            skc_group_id  group_id,
167                            skc_layer_id  layer_hi)
168 {
169   styling->unseal(styling->impl,true);
170 
171   styling->groups.extent[group_id].range.hi = layer_hi;
172 
173   return SKC_ERR_SUCCESS;
174 }
175 
176 skc_err
skc_styling_group_layer(skc_styling_t styling,skc_group_id group_id,skc_layer_id layer_id,uint32_t n,skc_styling_cmd_t const * cmds)177 skc_styling_group_layer(skc_styling_t             styling,
178                         skc_group_id              group_id,
179                         skc_layer_id              layer_id,
180                         uint32_t                  n,
181                         skc_styling_cmd_t const * cmds)
182 {
183   styling->unseal(styling->impl,true);
184 
185   styling->layers.extent[layer_id] = (union skc_layer_node)
186     {
187       .cmds   = styling->extras.count,
188       .parent = group_id
189     };
190 
191   memcpy(styling->extras.extent + styling->extras.count,cmds,n * sizeof(*cmds));
192 
193   styling->extras.count += n;
194 
195   return SKC_ERR_SUCCESS;
196 }
197 
198 //
199 // FIXME -- get rid of these x86'isms ASAP -- let compiler figure it
200 // out with a vector type
201 //
202 
203 static
204 __m128i
skc_convert_colors_4(float const * const colors)205 skc_convert_colors_4(float const * const colors)
206 {
207   __m128i c;
208 
209   c = _mm_cvtps_ph(*(__m128*)colors,0);
210 
211   return c;
212 }
213 
214 static
215 __m128i
skc_convert_colors_8(float const * const colors)216 skc_convert_colors_8(float const * const colors)
217 {
218   __m128i c;
219 
220   c = _mm256_cvtps_ph(*(__m256*)colors,0);
221 
222   return c;
223 }
224 
225 //
226 //
227 //
228 
229 static
230 void
skc_styling_layer_cmd_rgba_encoder(skc_styling_cmd_t * const cmds,skc_styling_opcode_e const opcode,float const rgba[4])231 skc_styling_layer_cmd_rgba_encoder(skc_styling_cmd_t  * const cmds,
232                                    skc_styling_opcode_e const opcode,
233                                    float                const rgba[4])
234 {
235   __m128i const c = skc_convert_colors_4(rgba);
236 
237   cmds[0] = opcode;
238   cmds[1] = c.m128i_u32[0];
239   cmds[2] = c.m128i_u32[1];
240 }
241 
242 void
skc_styling_background_over_encoder(skc_styling_cmd_t * cmds,float const rgba[4])243 skc_styling_background_over_encoder(skc_styling_cmd_t * cmds, float const rgba[4])
244 {
245   skc_styling_layer_cmd_rgba_encoder(cmds,SKC_STYLING_OPCODE_BACKGROUND_OVER,rgba);
246 }
247 
248 void
skc_styling_layer_fill_rgba_encoder(skc_styling_cmd_t * cmds,float const rgba[4])249 skc_styling_layer_fill_rgba_encoder(skc_styling_cmd_t * cmds, float const rgba[4])
250 {
251   // encode a solid fill
252   skc_styling_layer_cmd_rgba_encoder(cmds,SKC_STYLING_OPCODE_COLOR_FILL_SOLID,rgba);
253 }
254 
255 //
256 //
257 //
258 
259 void
skc_styling_layer_fill_gradient_encoder(skc_styling_cmd_t * cmds,float x0,float y0,float x1,float y1,skc_styling_gradient_type_e type,uint32_t n,float const stops[],float const colors[])260 skc_styling_layer_fill_gradient_encoder(skc_styling_cmd_t         * cmds,
261                                         float                       x0,
262                                         float                       y0,
263                                         float                       x1,
264                                         float                       y1,
265                                         skc_styling_gradient_type_e type,
266                                         uint32_t                    n,
267                                         float                 const stops[],
268                                         float                 const colors[])
269 {
270   union skc_styling_cmd * const cmds_u = (union skc_styling_cmd *)cmds;
271 
272   //
273   // encode a gradient fill
274   //
275   cmds_u[0].opcode = SKC_STYLING_OPCODE_COLOR_FILL_GRADIENT_LINEAR;
276 
277   float const dx = x1 - x0;
278   float const dy = y1 - y0;
279   float const c1 = x0 * dx + y0 * dy;
280   float const c2 = x1 * dx + y1 * dy;
281 
282   cmds_u[1].f32 =  dx;               // dx
283   cmds_u[2].f32 = -c1;               // p0
284   cmds_u[3].f32 =  dy;               // dy
285   cmds_u[4].f32 =  1.0f / (c2 - c1); // denom
286 
287   //
288   // store type
289   //
290   cmds_u[5].gradient_type = type;
291 
292   //
293   // Write out slopes
294   //
295   // Note: make sure that that the first and last stop pairs don't
296   // have a span of zero.  Why?  Because it's meaningless and the
297   // zero-span stops can simply be dropped.
298   //
299   // And obviously the stops need to monotonically increasing.
300   //
301   // These validations can be perfomed elsewhere.
302   //
303   // After a pile of simple algebra the slope necessary to map a stop
304   // percentage on [0,1] to an INDEX.LERP real number from [0.0,N.0]
305   // is simply:
306   //
307   //                delta_stop_prev
308   //   slope_curr = --------------- - 1
309   //                delta_stop_curr
310   //
311   // Each delta stop equal to zero reduces the stop count by 1.
312   //
313   // Note that color pairs are what's stored so this simplified
314   // representation works for both linear gradients with non-zero
315   // delta stops and linear gradients that double-up the stops in
316   // order to produce "stripes".
317   //
318   float                         ds_prev = stops[1] - stops[0];
319   union skc_styling_cmd * const slopes  = cmds_u + 8;
320 
321   slopes[0].f32 = 1.0f / ds_prev;
322 
323   uint32_t ds_count = 1;
324 
325   for (uint32_t ii=1; ii<n-1; ii++)
326     {
327       float const ds_curr = stops[ii+1] - stops[ii];
328 
329       if (ds_curr > 0.0f)
330         {
331           slopes[ds_count++].f32 = ds_prev / ds_curr - 1.0f;
332           ds_prev                = ds_curr;
333         }
334     }
335 
336   //
337   // save a potentially compressed delta slope count
338   //
339   cmds_u[6].u32 = ds_count;
340   cmds_u[7].u32 = n; // REMOVE ME -------------------------------------------- REMOVE
341 
342   //
343   // FIXME -- encode color pair as a single color diff as noted by HERB @ CHAP <------------- FIXME
344   //
345 
346   //
347   // write out color pairs while skipping delta stops equal to zero
348   //
349   uint32_t const color_count = ds_count + 1;
350 
351   union skc_styling_cmd * color_r = cmds_u + 8 + ds_count;
352   union skc_styling_cmd * color_g = color_r + color_count;
353   union skc_styling_cmd * color_b = color_r + color_count * 2;
354   union skc_styling_cmd * color_a = color_r + color_count * 3;
355 
356   for (uint32_t ii=0; ii<n-1; ii++)
357     {
358       if (stops[ii+1] > stops[ii])
359         {
360           __m128i const c = skc_convert_colors_8(colors+ii*4);
361 
362           color_r->u16v2.lo = c.m128i_u16[0];
363           color_r->u16v2.hi = c.m128i_u16[4];
364           color_g->u16v2.lo = c.m128i_u16[1];
365           color_g->u16v2.hi = c.m128i_u16[5];
366           color_b->u16v2.lo = c.m128i_u16[2];
367           color_b->u16v2.hi = c.m128i_u16[6];
368           color_a->u16v2.lo = c.m128i_u16[3];
369           color_a->u16v2.hi = c.m128i_u16[7];
370 
371           ++color_r;
372           ++color_g;
373           ++color_b;
374           ++color_a;
375         }
376     }
377 
378   float laststop[8]; // sentinel to lerp against same color
379 
380   for (int ii=0; ii<4; ii++)
381     laststop[ii+4] = laststop[ii] = colors[(n-1)*4+ii];
382 
383   __m128i const c = skc_convert_colors_8(laststop);
384 
385   color_r->u16v2.lo = c.m128i_u16[0];
386   color_r->u16v2.hi = c.m128i_u16[4];
387   color_g->u16v2.lo = c.m128i_u16[1];
388   color_g->u16v2.hi = c.m128i_u16[5];
389   color_b->u16v2.lo = c.m128i_u16[2];
390   color_b->u16v2.hi = c.m128i_u16[6];
391   color_a->u16v2.lo = c.m128i_u16[3];
392   color_a->u16v2.hi = c.m128i_u16[7];
393 }
394 
395 //
396 //
397 //
398